EmbedShaders.cmake 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. find_program(PYTHON_EXECUTABLE python3 REQUIRED)
  2. # Inline Python script to process a shader
  3. set(SHADER_PROCESSOR_SCRIPT "
  4. import sys
  5. import subprocess
  6. import os
  7. def process_shader(shader_file, shader_name, output_file, r3d_root):
  8. # Minify the shader
  9. result = subprocess.run([
  10. sys.executable,
  11. os.path.join(r3d_root, 'scripts', 'glsl_minifier.py'),
  12. shader_file
  13. ], capture_output=True, text=True)
  14. if result.returncode != 0:
  15. print(f'Error during minification: {result.stderr}', file=sys.stderr)
  16. sys.exit(1)
  17. minified_shader = result.stdout.strip()
  18. # Generate the C header
  19. result = subprocess.run([
  20. sys.executable,
  21. os.path.join(r3d_root, 'scripts', 'bin2c.py'),
  22. '--string', minified_shader,
  23. '--name', shader_name,
  24. output_file
  25. ], capture_output=True, text=True)
  26. if result.returncode != 0:
  27. print(f'Error during header generation: {result.stderr}', file=sys.stderr)
  28. sys.exit(1)
  29. if __name__ == '__main__':
  30. if len(sys.argv) != 5:
  31. print('Usage: python script.py <shader_file> <shader_name> <output_file> <r3d_root>')
  32. sys.exit(1)
  33. process_shader(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
  34. ")
  35. # Inline Python script to generate the main shaders.h header
  36. set(SHADERS_HEADER_GENERATOR_SCRIPT "
  37. import sys
  38. import os
  39. def generate_shaders_header(shader_names, output_file):
  40. with open(output_file, 'w') as f:
  41. f.write('#ifndef SHADERS_H\\n')
  42. f.write('#define SHADERS_H\\n\\n')
  43. f.write('// Auto-generated header that includes all shader headers\\n\\n')
  44. for shader_name in shader_names:
  45. f.write(f'#include \"./shaders/{shader_name}.h\"\\n')
  46. f.write('\\n#endif // SHADERS_H\\n')
  47. if __name__ == '__main__':
  48. if len(sys.argv) < 3:
  49. print('Usage: python script.py <output_file> <shader_name1> [shader_name2] ...')
  50. sys.exit(1)
  51. output_file = sys.argv[1]
  52. shader_names = sys.argv[2:]
  53. generate_shaders_header(shader_names, output_file)
  54. ")
  55. # Create the temporary Python scripts only once
  56. file(WRITE "${CMAKE_BINARY_DIR}/process_shader.py" "${SHADER_PROCESSOR_SCRIPT}")
  57. file(WRITE "${CMAKE_BINARY_DIR}/generate_shaders_header.py" "${SHADERS_HEADER_GENERATOR_SCRIPT}")
  58. function(_add_shader_command shader_file output_file)
  59. get_filename_component(shader_name "${shader_file}" NAME)
  60. add_custom_command(
  61. OUTPUT "${output_file}"
  62. COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/generated/include/shaders"
  63. COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_BINARY_DIR}/process_shader.py"
  64. "${shader_file}" "${shader_name}" "${output_file}" "${R3D_ROOT_PATH}"
  65. DEPENDS "${shader_file}"
  66. COMMENT "Processing shader: ${shader_file}"
  67. VERBATIM
  68. )
  69. endfunction()
  70. function(_add_shaders_header_command shader_names output_file)
  71. add_custom_command(
  72. OUTPUT "${output_file}"
  73. COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/generated/include"
  74. COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_BINARY_DIR}/generate_shaders_header.py"
  75. "${output_file}" ${shader_names}
  76. COMMENT "Generating main shaders header: ${output_file}"
  77. VERBATIM
  78. )
  79. endfunction()
  80. ### Public functions ###
  81. function(ProcessShader shader_file output_file_var)
  82. get_filename_component(shader_name "${shader_file}" NAME)
  83. set(output_file "${CMAKE_BINARY_DIR}/generated/include/shaders/${shader_name}.h")
  84. set("${output_file_var}" "${output_file}" PARENT_SCOPE)
  85. _add_shader_command("${shader_file}" "${output_file}")
  86. endfunction()
  87. function(EmbedShaders target_name)
  88. set(shader_files ${ARGN})
  89. if(NOT shader_files)
  90. message(FATAL_ERROR "EmbedShaders: No shader file specified")
  91. endif()
  92. set(output_files)
  93. set(shader_names)
  94. list(LENGTH shader_files shader_count)
  95. message(STATUS "Configuring processing of ${shader_count} shader(s) for target ${target_name}...")
  96. foreach(shader_file ${shader_files})
  97. if(NOT EXISTS "${shader_file}")
  98. message(FATAL_ERROR "EmbedShaders: Shader file not found: ${shader_file}")
  99. endif()
  100. get_filename_component(shader_name "${shader_file}" NAME)
  101. list(APPEND shader_names "${shader_name}")
  102. ProcessShader("${shader_file}" output_file)
  103. list(APPEND output_files "${output_file}")
  104. message(STATUS " - ${shader_file} -> ${output_file}")
  105. endforeach()
  106. # Generate the main shaders.h header
  107. set(main_shaders_header "${CMAKE_BINARY_DIR}/generated/include/shaders.h")
  108. _add_shaders_header_command("${shader_names}" "${main_shaders_header}")
  109. list(APPEND output_files "${main_shaders_header}")
  110. set(shader_target "${target_name}_shaders")
  111. add_custom_target(${shader_target}
  112. DEPENDS ${output_files}
  113. COMMENT "Generating shader headers for ${target_name}"
  114. )
  115. add_dependencies(${target_name} ${shader_target})
  116. target_include_directories(${target_name} PRIVATE "${CMAKE_BINARY_DIR}/generated/include")
  117. message(STATUS "Target ${shader_target} created with ${shader_count} shader(s)")
  118. message(STATUS "Main shaders header: ${main_shaders_header}")
  119. endfunction()