# Code Generation Module # Asset packing, timeline compilation, and music compilation # ============================================================================= # Helper Functions # ============================================================================= # Helper to parse asset list and extract individual file paths function(parse_asset_list INPUT_TXT OUT_FILE_LIST) set(ASSET_FILES "") if(EXISTS ${INPUT_TXT}) # Get directory of INPUT_TXT for relative path resolution get_filename_component(INPUT_DIR ${INPUT_TXT} DIRECTORY) file(STRINGS ${INPUT_TXT} LINES) foreach(LINE ${LINES}) # Skip comments and empty lines string(STRIP "${LINE}" LINE) if(NOT LINE MATCHES "^#" AND NOT LINE STREQUAL "") # Extract filename (third field: ASSET_NAME, COMPRESSION, FILENAME, DESC) string(REGEX REPLACE "^[^,]+,[^,]+,[ ]*([^,]+).*" "\\1" FILENAME "${LINE}") string(STRIP "${FILENAME}" FILENAME) # Use workspace-relative path set(FULL_PATH "${INPUT_DIR}/${FILENAME}") if(EXISTS ${FULL_PATH}) list(APPEND ASSET_FILES ${FULL_PATH}) endif() endif() endforeach() endif() set(${OUT_FILE_LIST} ${ASSET_FILES} PARENT_SCOPE) endfunction() # Pack assets for demo (output to src/generated/) function(pack_assets NAME INPUT_TXT HEADER_VAR DATA_CC_VAR TARGET_NAME) set(OUT_H ${CMAKE_CURRENT_SOURCE_DIR}/src/generated/${NAME}.h) set(OUT_CC ${CMAKE_CURRENT_SOURCE_DIR}/src/generated/${NAME}_data.cc) # Parse asset list to get individual file dependencies parse_asset_list(${INPUT_TXT} ASSET_FILE_DEPS) add_custom_command( OUTPUT ${OUT_H} ${OUT_CC} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/src/generated COMMAND ${ASSET_PACKER_CMD} ${INPUT_TXT} ${OUT_H} ${OUT_CC} DEPENDS ${ASSET_PACKER_DEPENDS} ${INPUT_TXT} ${ASSET_FILE_DEPS} COMMENT "Generating assets for ${NAME}..." ) set(${HEADER_VAR} ${OUT_H} PARENT_SCOPE) set(${DATA_CC_VAR} ${OUT_CC} PARENT_SCOPE) add_custom_target(${TARGET_NAME} DEPENDS ${OUT_H} ${OUT_CC}) endfunction() # Pack assets by category (filters by filename pattern) function(pack_assets_category NAME PATTERN INPUT_TXT HEADER_VAR DATA_CC_VAR TARGET_NAME) set(OUT_H ${CMAKE_CURRENT_SOURCE_DIR}/src/generated/${NAME}.h) set(OUT_CC ${CMAKE_CURRENT_SOURCE_DIR}/src/generated/${NAME}_data.cc) # Get directory of INPUT_TXT for relative path resolution get_filename_component(INPUT_DIR ${INPUT_TXT} DIRECTORY) get_filename_component(INPUT_NAME ${INPUT_TXT} NAME_WE) set(FILTERED_TXT ${INPUT_DIR}/${INPUT_NAME}_${NAME}.txt) # Create filtered asset list file(STRINGS ${INPUT_TXT} ALL_LINES) set(FILTERED_LINES "") foreach(LINE ${ALL_LINES}) string(STRIP "${LINE}" LINE) if(LINE MATCHES "^#" OR LINE STREQUAL "") list(APPEND FILTERED_LINES "${LINE}") else() string(REGEX REPLACE "^[^,]+,[^,]+,[ ]*([^,]+).*" "\\1" FILENAME "${LINE}") if(FILENAME MATCHES "${PATTERN}") list(APPEND FILTERED_LINES "${LINE}") endif() endif() endforeach() string(REPLACE ";" "\n" FILTERED_CONTENT "${FILTERED_LINES}") file(WRITE ${FILTERED_TXT} "${FILTERED_CONTENT}\n") # Parse filtered list for dependencies (now in same directory as INPUT_TXT) parse_asset_list(${FILTERED_TXT} ASSET_FILE_DEPS) add_custom_command( OUTPUT ${OUT_H} ${OUT_CC} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/src/generated COMMAND ${ASSET_PACKER_CMD} ${FILTERED_TXT} ${OUT_H} ${OUT_CC} DEPENDS ${ASSET_PACKER_DEPENDS} ${INPUT_TXT} ${ASSET_FILE_DEPS} COMMENT "Generating ${NAME} assets..." ) set(${HEADER_VAR} ${OUT_H} PARENT_SCOPE) set(${DATA_CC_VAR} ${OUT_CC} PARENT_SCOPE) add_custom_target(${TARGET_NAME} DEPENDS ${OUT_H} ${OUT_CC}) endfunction() # Pack test assets (output to build/src/generated_test/) function(pack_test_assets NAME INPUT_TXT HEADER_VAR DATA_CC_VAR TARGET_NAME) set(OUT_H ${CMAKE_CURRENT_BINARY_DIR}/src/generated_test/${NAME}.h) set(OUT_CC ${CMAKE_CURRENT_BINARY_DIR}/src/generated_test/${NAME}_data.cc) # Parse asset list to get individual file dependencies parse_asset_list(${INPUT_TXT} ASSET_FILE_DEPS) add_custom_command( OUTPUT ${OUT_H} ${OUT_CC} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/src/generated_test COMMAND ${ASSET_PACKER_CMD} ${INPUT_TXT} ${OUT_H} ${OUT_CC} DEPENDS ${ASSET_PACKER_DEPENDS} ${INPUT_TXT} ${ASSET_FILE_DEPS} COMMENT "Generating assets for test ${NAME}..." ) set(${HEADER_VAR} ${OUT_H} PARENT_SCOPE) set(${DATA_CC_VAR} ${OUT_CC} PARENT_SCOPE) add_custom_target(${TARGET_NAME} DEPENDS ${OUT_H} ${OUT_CC}) endfunction() # ============================================================================= # Generation Targets # ============================================================================= # Timeline compilation set(DEMO_SEQ_PATH ${WORKSPACE_TIMELINE}) set(GENERATED_TIMELINE_CC ${CMAKE_CURRENT_SOURCE_DIR}/src/generated/timeline.cc) add_custom_command( OUTPUT ${GENERATED_TIMELINE_CC} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/src/generated COMMAND ${SEQ_COMPILER_CMD} ${DEMO_SEQ_PATH} ${GENERATED_TIMELINE_CC} DEPENDS ${SEQ_COMPILER_DEPENDS} ${DEMO_SEQ_PATH} src/gpu/demo_effects.h COMMENT "Compiling demo sequence from workspace ${DEMO_WORKSPACE}..." ) add_custom_target(generate_timeline ALL DEPENDS ${GENERATED_TIMELINE_CC}) # Music compilation set(TRACKER_MUSIC_PATH ${WORKSPACE_MUSIC}) set(GENERATED_MUSIC_DATA_CC ${CMAKE_CURRENT_SOURCE_DIR}/src/generated/music_data.cc) add_custom_command( OUTPUT ${GENERATED_MUSIC_DATA_CC} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/src/generated COMMAND ${TRACKER_COMPILER_FINAL_CMD} ${TRACKER_MUSIC_PATH} ${GENERATED_MUSIC_DATA_CC} DEPENDS ${TRACKER_COMPILER_FINAL_DEPENDS} ${TRACKER_MUSIC_PATH} tracker_compiler_host COMMENT "Compiling tracker music from workspace ${DEMO_WORKSPACE}..." ) add_custom_target(generate_tracker_music ALL DEPENDS ${GENERATED_MUSIC_DATA_CC}) # Asset packing (split by category for granular rebuild tracking) # Generate filtered asset files per category get_filename_component(ASSETS_DIR ${WORKSPACE_ASSETS} DIRECTORY) set(FILTERED_SHADERS ${ASSETS_DIR}/assets_filtered_shaders.txt) set(FILTERED_AUDIO ${ASSETS_DIR}/assets_filtered_audio.txt) set(FILTERED_MODELS ${ASSETS_DIR}/assets_filtered_models.txt) set(FILTERED_DATA ${ASSETS_DIR}/assets_filtered_data.txt) # Filter assets by category at configure time file(STRINGS ${WORKSPACE_ASSETS} ALL_ASSET_LINES) set(SHADERS_LINES "") set(AUDIO_LINES "") set(MODELS_LINES "") set(DATA_LINES "") foreach(LINE ${ALL_ASSET_LINES}) string(STRIP "${LINE}" LINE) if(LINE MATCHES "^#" OR LINE STREQUAL "") list(APPEND SHADERS_LINES "${LINE}") list(APPEND AUDIO_LINES "${LINE}") list(APPEND MODELS_LINES "${LINE}") list(APPEND DATA_LINES "${LINE}") else() string(REGEX REPLACE "^[^,]+,[^,]+,[ ]*([^,]+).*" "\\1" FILENAME "${LINE}") if(FILENAME MATCHES "\\.wgsl$") list(APPEND SHADERS_LINES "${LINE}") elseif(FILENAME MATCHES "\\.(spec|track)$") list(APPEND AUDIO_LINES "${LINE}") elseif(FILENAME MATCHES "\\.obj$") list(APPEND MODELS_LINES "${LINE}") elseif(FILENAME MATCHES "\\.(bin|png)$" OR FILENAME MATCHES "PROC\\(") list(APPEND DATA_LINES "${LINE}") endif() endif() endforeach() string(REPLACE ";" "\n" SHADERS_CONTENT "${SHADERS_LINES}") string(REPLACE ";" "\n" AUDIO_CONTENT "${AUDIO_LINES}") string(REPLACE ";" "\n" MODELS_CONTENT "${MODELS_LINES}") string(REPLACE ";" "\n" DATA_CONTENT "${DATA_LINES}") file(WRITE ${FILTERED_SHADERS} "${SHADERS_CONTENT}\n") file(WRITE ${FILTERED_AUDIO} "${AUDIO_CONTENT}\n") file(WRITE ${FILTERED_MODELS} "${MODELS_CONTENT}\n") file(WRITE ${FILTERED_DATA} "${DATA_CONTENT}\n") # Parse dependencies per category parse_asset_list(${FILTERED_SHADERS} SHADERS_DEPS) parse_asset_list(${FILTERED_AUDIO} AUDIO_DEPS) parse_asset_list(${FILTERED_MODELS} MODELS_DEPS) parse_asset_list(${FILTERED_DATA} DATA_DEPS) # Single unified output (avoids duplicate symbols) set(GEN_DEMO_H ${CMAKE_CURRENT_SOURCE_DIR}/src/generated/assets.h) set(GEN_DEMO_CC ${CMAKE_CURRENT_SOURCE_DIR}/src/generated/assets_data.cc) # Category-specific targets for granular rebuilds add_custom_command( OUTPUT ${GEN_DEMO_H}.shaders_stamp COMMAND ${CMAKE_COMMAND} -E touch ${GEN_DEMO_H}.shaders_stamp DEPENDS ${ASSET_PACKER_DEPENDS} ${WORKSPACE_ASSETS} ${SHADERS_DEPS} COMMENT "Checking shader assets..." ) add_custom_target(generate_demo_shaders DEPENDS ${GEN_DEMO_H}.shaders_stamp) add_custom_command( OUTPUT ${GEN_DEMO_H}.audio_stamp COMMAND ${CMAKE_COMMAND} -E touch ${GEN_DEMO_H}.audio_stamp DEPENDS ${ASSET_PACKER_DEPENDS} ${WORKSPACE_ASSETS} ${AUDIO_DEPS} COMMENT "Checking audio assets..." ) add_custom_target(generate_demo_audio DEPENDS ${GEN_DEMO_H}.audio_stamp) add_custom_command( OUTPUT ${GEN_DEMO_H}.models_stamp COMMAND ${CMAKE_COMMAND} -E touch ${GEN_DEMO_H}.models_stamp DEPENDS ${ASSET_PACKER_DEPENDS} ${WORKSPACE_ASSETS} ${MODELS_DEPS} COMMENT "Checking model assets..." ) add_custom_target(generate_demo_models DEPENDS ${GEN_DEMO_H}.models_stamp) add_custom_command( OUTPUT ${GEN_DEMO_H}.data_stamp COMMAND ${CMAKE_COMMAND} -E touch ${GEN_DEMO_H}.data_stamp DEPENDS ${ASSET_PACKER_DEPENDS} ${WORKSPACE_ASSETS} ${DATA_DEPS} COMMENT "Checking data assets..." ) add_custom_target(generate_demo_data DEPENDS ${GEN_DEMO_H}.data_stamp) # Unified asset generation (triggered when any category changes) add_custom_command( OUTPUT ${GEN_DEMO_H} ${GEN_DEMO_CC} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/src/generated COMMAND ${ASSET_PACKER_CMD} ${WORKSPACE_ASSETS} ${GEN_DEMO_H} ${GEN_DEMO_CC} DEPENDS ${ASSET_PACKER_DEPENDS} ${WORKSPACE_ASSETS} ${GEN_DEMO_H}.shaders_stamp ${GEN_DEMO_H}.audio_stamp ${GEN_DEMO_H}.models_stamp ${GEN_DEMO_H}.data_stamp COMMENT "Generating unified assets..." ) # Combined target for compatibility add_custom_target(generate_demo_assets DEPENDS ${GEN_DEMO_H} ${GEN_DEMO_CC}) # Test assets (unchanged) pack_test_assets(test_assets ${CMAKE_CURRENT_SOURCE_DIR}/workspaces/test/assets.txt GEN_TEST_H GEN_TEST_CC generate_test_assets) # Mark generated files so CMake always checks if they need rebuilding set_source_files_properties(${GEN_DEMO_H} ${GEN_DEMO_CC} PROPERTIES GENERATED TRUE) set_source_files_properties(${GEN_TEST_H} ${GEN_TEST_CC} PROPERTIES GENERATED TRUE) set_source_files_properties(${GENERATED_TIMELINE_CC} PROPERTIES GENERATED TRUE) set_source_files_properties(${GENERATED_MUSIC_DATA_CC} PROPERTIES GENERATED TRUE)