1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
|
# 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)
|