From fc8d363ee3bc51dbd237b9b6dd0d27d8349cb51d Mon Sep 17 00:00:00 2001 From: Brett Date: Sun, 15 Jun 2025 14:07:54 -0400 Subject: [PATCH] cmake embed --- CMakeLists.txt | 69 ++++++++---------------- {shaders => embed/shaders}/particle.frag | 0 {shaders => embed/shaders}/particle.vert | 0 embed/shaders/silly_test/particle.frag | 19 +++++++ embed/shaders/silly_test/particle.vert | 24 +++++++++ embed_strings.py | 43 +++++++++++++++ 6 files changed, 107 insertions(+), 48 deletions(-) rename {shaders => embed/shaders}/particle.frag (100%) rename {shaders => embed/shaders}/particle.vert (100%) create mode 100644 embed/shaders/silly_test/particle.frag create mode 100644 embed/shaders/silly_test/particle.vert create mode 100644 embed_strings.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 369cb4d..f6741fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(gpu-particles VERSION 0.0.18) +project(gpu-particles VERSION 0.0.19) option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) option(ENABLE_UBSAN "Enable the ub sanitizer" OFF) @@ -12,55 +12,28 @@ add_subdirectory(lib/blt-with-graphics) include_directories(include/) file(GLOB_RECURSE PROJECT_BUILD_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") -function(embed_file_as_raw_string INPUT OUTPUT NAMESPACE VAR_NAME) - file(READ "${INPUT}" CONTENTS) - file(WRITE "${OUTPUT}" "// Generated from ${INPUT}\n") - file(APPEND "${OUTPUT}" "#pragma once\n\n") - file(APPEND "${OUTPUT}" "namespace ${NAMESPACE} {\n\n") - file(APPEND "${OUTPUT}" "static constexpr char ${VAR_NAME}_str[] = R\"(\"${CONTENTS}\")\";\n\n}") -endfunction() - -function(embed_directory INPUT_DIR) - # Get the name of the directory the user is trying to embed - get_filename_component(parent_name "${INPUT_DIR}" NAME) - # make sure directory uses forward slashes - file(TO_CMAKE_PATH "${INPUT_DIR}" INPUT_DIR) - set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/embedded/${parent_name}") - # find all directories within the user folder relative to the input directory - file(GLOB_RECURSE INPUT_FILES RELATIVE "${INPUT_DIR}" "${INPUT_DIR}/*") - - foreach(REL_PATH IN LISTS INPUT_FILES) - set(ABS_INPUT_PATH "${INPUT_DIR}/${REL_PATH}") - set(OUTPUT_HEADER "${OUTPUT_DIR}/${REL_PATH}.h") - - get_filename_component(OUTPUT_HEADER_DIR "${OUTPUT_HEADER}" DIRECTORY) - file(MAKE_DIRECTORY "${OUTPUT_HEADER_DIR}") - - # Get the name, extension and relative directory of the input path + file - get_filename_component(VAR_NAME "${REL_PATH}" NAME_WE) - get_filename_component(VAR_EXT "${REL_PATH}" EXT) - get_filename_component(VAR_DIR "${parent_name}/${REL_PATH}" DIRECTORY) - set(FILE_PATH "${VAR_NAME}_${VAR_EXT}") - # replace non-alphanum chars with "_" for the variable - string(REGEX REPLACE "[^a-zA-Z0-9]" "_" FILE_PATH "${FILE_PATH}") - string(REGEX REPLACE "__+" "_" FILE_PATH "${FILE_PATH}") - - # replace non-alphanum chars with : for the namespace - string(REGEX REPLACE "[^a-zA-Z0-9]" "::" VAR_DIR ${VAR_DIR}) - string(REGEX REPLACE ":::+" "::" VAR_DIR ${VAR_DIR}) - - message(STATUS "Converting file '${REL_PATH}' into variable '${VAR_NAME}' with namespace '${VAR_DIR}'") - - embed_file_as_raw_string("${ABS_INPUT_PATH}" "${OUTPUT_HEADER}" "${VAR_DIR}" "${FILE_PATH}") - endforeach() - - include_directories("${CMAKE_BINARY_DIR}/embedded") -endfunction() - -embed_directory("${CMAKE_SOURCE_DIR}/shaders") - add_executable(gpu-particles ${PROJECT_BUILD_FILES}) +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/embed_strings.py) + find_package( Python3 REQUIRED ) + + set(EMBED_PYTHON_COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/embed_strings.py ${CMAKE_CURRENT_SOURCE_DIR}/embed ${CMAKE_BINARY_DIR}/embed) + + add_custom_target( + embed_strings ALL + COMMAND ${EMBED_PYTHON_COMMAND} + COMMENT "Embedding strings" + ) + + add_dependencies(gpu-particles embed_strings) + + execute_process( + COMMAND ${EMBED_PYTHON_COMMAND} + ) + + target_include_directories(gpu-particles PUBLIC "${CMAKE_BINARY_DIR}/embed") +endif() + target_compile_options(gpu-particles PRIVATE -Wall -Wextra -Wpedantic -Wno-comment) target_link_options(gpu-particles PRIVATE -Wall -Wextra -Wpedantic -Wno-comment) diff --git a/shaders/particle.frag b/embed/shaders/particle.frag similarity index 100% rename from shaders/particle.frag rename to embed/shaders/particle.frag diff --git a/shaders/particle.vert b/embed/shaders/particle.vert similarity index 100% rename from shaders/particle.vert rename to embed/shaders/particle.vert diff --git a/embed/shaders/silly_test/particle.frag b/embed/shaders/silly_test/particle.frag new file mode 100644 index 0000000..f4d9ff1 --- /dev/null +++ b/embed/shaders/silly_test/particle.frag @@ -0,0 +1,19 @@ +#version 300 es +precision mediump float; + +uniform sampler2D tex1; +uniform sampler2D tex2; + +in float silly; + +layout (location = 0) out vec4 FragColor; + +void main() +{ + float x = gl_PointCoord.x; + float y = 1.0f - gl_PointCoord.y; + if (silly > 0.0f) + FragColor = texture(tex1, vec2(x, y)); + else + FragColor = texture(tex2, vec2(x, y)); +} \ No newline at end of file diff --git a/embed/shaders/silly_test/particle.vert b/embed/shaders/silly_test/particle.vert new file mode 100644 index 0000000..b40c57c --- /dev/null +++ b/embed/shaders/silly_test/particle.vert @@ -0,0 +1,24 @@ +#version 300 es +precision mediump float; + +layout (location = 0) in vec2 position; + +out float silly; + +layout (std140) uniform GlobalMatrices +{ + mat4 projection; + mat4 ortho; + mat4 view; + mat4 pvm; + mat4 ovm; +}; + +void main() +{ + if (mod(position.x + position.y, 32.0f) >= 16.0f) + silly = 1.0f; + else + silly = 0.0f; + gl_Position = ovm * vec4(position.x, position.y, 0.0, 1.0); +} \ No newline at end of file diff --git a/embed_strings.py b/embed_strings.py new file mode 100644 index 0000000..cf9593c --- /dev/null +++ b/embed_strings.py @@ -0,0 +1,43 @@ +import os +import sys +import re +from pathlib import Path + +def safe_var_name(path): + return re.sub("__+", "_", ''.join(c if c.isalnum() else '_' for c in str(path))) + +def safe_namespace_name(path): + return re.sub(":::+", "::", ''.join(c if (c.isalnum() or c == '_') else '::' for c in str(path))) + +def embed(input_path, output_path, namespace, var_name): + with open(input_path, "rt") as f: + contents = f.read() + out = ( + f"// Generated from {input_path}\n" + f"#pragma once\n\n" + f"namespace {safe_namespace_name(namespace)}" "\n{\n" + f"\tinline constexpr char {safe_var_name(var_name)}_str[] = R\"(\"{contents}\")\";\n""}" + ) + os.makedirs(os.path.dirname(output_path), exist_ok=True) + with open(output_path.with_suffix(output_path.suffix + ".h"), "w") as f: + f.write(out) + +def main(input_dir, output_dir): + input_path = Path(input_dir) + + for root, _, files in os.walk(input_dir): + for file in files: + print(f"Processing file: %{file}%") + file_path = Path(root) / file + + parent_path = file_path.relative_to(input_dir) + + output_path = Path(output_dir) / parent_path + + embed(file_path, output_path, parent_path, file_path.name) + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Expected two arguments: input_dir output_dir") + exit(1) + main(sys.argv[1], sys.argv[2])