# VulkZample! Your example in Vulkan! # Copyright (C) 2024 Rebekah Rowe # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . cmake_minimum_required(VERSION 3.28) project(vulkzample LANGUAGES CXX VERSION 1.0.0) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS true) if(CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_INTERPROCEDURAL_OPTIMIZATION true) endif() find_package(glm REQUIRED) find_package(SDL2 REQUIRED) find_package(SDL2pp REQUIRED) find_package(Vulkan REQUIRED COMPONENTS glslc) find_package(VulkanMemoryAllocator-Hpp REQUIRED) #find_package(Doxygen) add_executable(${PROJECT_NAME} "") target_include_directories(${PROJECT_NAME} PRIVATE SDL2pp::Headers Vulkan::Headers VulkanMemoryAllocator-Hpp::VulkanMemoryAllocator-Hpp ) target_link_libraries(${PROJECT_NAME} PUBLIC SDL2pp::SDL2pp Vulkan::Vulkan VulkanMemoryAllocator-Hpp::VulkanMemoryAllocator-Hpp ) file(GLOB_RECURSE sources "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") target_sources(${PROJECT_NAME} PRIVATE ${sources}) #if (DOXYGEN_FOUND) # doxygen_add_docs(${PROJECT_NAME}) #endif() if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") target_compile_options(${PROJECT_NAME} PRIVATE -O0 -fno-omit-frame-pointer -ggdb -Wall -Werror -fno-common) target_link_options(${PROJECT_NAME} PRIVATE -O0 -fno-omit-frame-pointer -ggdb -Wall -Werror -fno-common) if (ENABLE_ASAN) target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize=address) target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=address) endif() endif() if (ENABLE_TESTS) message(STATUS "Tests Enabled, Building with Testing!") target_compile_definitions(${PROJECT_NAME} PRIVATE -DENABLE_TESTS=1) endif() # SHADER COMPILATION function(CommandCompileGLSLToSPV file_in) cmake_path(GET file_in FILENAME filename) cmake_path(GET file_in PARENT_PATH filepath) cmake_path(GET file_in STEM LAST_ONLY filepath_without_glsl_ext) cmake_path(GET filepath_without_glsl_ext EXTENSION LAST_ONLY file_shader_type) if(file_shader_type MATCHES "^\\..*") string(REGEX REPLACE "^\\." "" file_shader_type "${file_shader_type}") # Remove the dot: ".vertex" endif() add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${filename}.spv WORKING_DIRECTORY ${filepath} COMMAND Vulkan::glslc ARGS -fshader-stage="${file_shader_type}" ${filename} -o ${CMAKE_CURRENT_BINARY_DIR}/${filename}.spv DEPENDS ${file_in} POST_BUILD) set(FUNC_RET ${CMAKE_CURRENT_BINARY_DIR}/${filename}.spv PARENT_SCOPE) endfunction() function(CommandCompileMassGSGLShaders) set(SHADILER_OBJ_RET "") foreach(file_path ${ARGV}) CommandCompileGLSLToSPV(${file_path}) list(APPEND SHADILER_OBJ_RET "${FUNC_RET}") endforeach() set(SHADILER_OBJ_RET "${SHADILER_OBJ_RET}" PARENT_SCOPE) endfunction() file(GLOB_RECURSE shaders_frag "${CMAKE_CURRENT_SOURCE_DIR}/shader/*.frag.glsl") file(GLOB_RECURSE shaders_vertex "${CMAKE_CURRENT_SOURCE_DIR}/shader/*.vertex.glsl") CommandCompileMassGSGLShaders(${shaders_frag} ${shaders_vertex}) # EMBED CMAKE find_package(ImageMagick REQUIRED COMPONENTS convert identify) function(CommandConvertImageToRgba file_in) cmake_path(GET file_in FILENAME filename) cmake_path(GET file_in PARENT_PATH filepath) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${filename}.rgba WORKING_DIRECTORY ${filepath} COMMAND ${ImageMagick_convert_EXECUTABLE} ARGS ${filename} -depth 8 -format rgba ${CMAKE_CURRENT_BINARY_DIR}/${filename}.rgba DEPENDS ${file_in} POST_BUILD) set(FUNC_RET ${CMAKE_CURRENT_BINARY_DIR}/${filename}.rgba PARENT_SCOPE) endfunction() function(CommandConvertToObjcopy file_in) cmake_path(GET file_in FILENAME filename) cmake_path(GET file_in PARENT_PATH filepath) if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "amd64") set(OBJCOPY_ARCH "elf64-x86-64") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64") set(OBJCOPY_ARCH "elf64-littleaarch64") else() message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}") endif() add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${filename}.o WORKING_DIRECTORY ${filepath} COMMAND ${CMAKE_OBJCOPY} ARGS --input-target binary --output-target "${OBJCOPY_ARCH}" "${filename}" "${CMAKE_CURRENT_BINARY_DIR}/${filename}.o" DEPENDS ${file_in} POST_BUILD) set(FUNC_RET ${CMAKE_CURRENT_BINARY_DIR}/${filename}.o PARENT_SCOPE) endfunction() function(CommandConvertImageToObject file_in) CommandConvertImageToRgba("${file_in}") CommandConvertToObjcopy(${FUNC_RET}) set(FUNC_RET ${FUNC_RET} PARENT_SCOPE) endfunction() function(EmbedResources) set(EMBED_HEADER_DIR "${CMAKE_CURRENT_BINARY_DIR}/") set(EMBED_HEADER_DIR "${EMBED_HEADER_DIR}" PARENT_SCOPE) file(WRITE "${EMBED_HEADER_DIR}/embed_resources.hpp" " /* AUTOGENERATED CMAKE EMBEDED FILE HEADER!!! DO NOT EDIT THIS FILE!!! ALL CHANGES WILL BE WIPED!!! */ #include #include class EmbededResource { public: constexpr EmbededResource(const std::byte* _begin, const std::byte* _end) : begin(_begin), end(_end), size(std::distance(_begin, _end)) { //static_assert(this->begin != nullptr && this->end != nullptr); } const std::byte* const begin; const std::byte* const end; std::size_t size; }; class EmbededImage { public: constexpr EmbededImage(std::size_t _width, std::size_t _height, EmbededResource _data)\ : width(_width), height(_height), data(_data) { //static_assert(this->width != 0 && this->height); } const std::size_t width; const std::size_t height; const EmbededResource data; }; ") set(EMBED_OBJ_RET "") foreach(file_path ${ARGV}) cmake_path(GET file_path EXTENSION LAST_ONLY file_ext) set(type "embed") if (file_ext STREQUAL ".jpg") set(type "image") endif() if (file_ext STREQUAL ".png") set(type "image") endif() if (type STREQUAL "image") CommandConvertImageToObject(${file_path}) elseif (type STREQUAL "embed") CommandConvertToObjcopy(${file_path}) endif() list(APPEND EMBED_OBJ_RET "${FUNC_RET}") cmake_path(GET FUNC_RET STEM LAST_ONLY obj_filestem) string(REPLACE "." "_" obj_cleaned_name "${obj_filestem}") file(APPEND "${EMBED_HEADER_DIR}/embed_resources.hpp" "extern const std::byte _binary_${obj_cleaned_name}_start; extern const std::byte _binary_${obj_cleaned_name}_end; \n") if (type STREQUAL "image") cmake_path(GET file_path PARENT_PATH file_parent) cmake_path(GET file_path FILENAME file_name) execute_process(COMMAND "${ImageMagick_identify_EXECUTABLE}" -format "%[fx:w]" "${file_name}" WORKING_DIRECTORY "${file_parent}" OUTPUT_VARIABLE image_width COMMAND_ERROR_IS_FATAL ANY) execute_process(COMMAND "${ImageMagick_identify_EXECUTABLE}" -format "%[fx:h]" "${file_name}" WORKING_DIRECTORY "${file_parent}" OUTPUT_VARIABLE image_height COMMAND_ERROR_IS_FATAL ANY) file(APPEND "${EMBED_HEADER_DIR}/embed_resources.hpp" "inline EmbededImage embeded_${obj_cleaned_name}(${image_width}, ${image_height}, EmbededResource(&_binary_${obj_cleaned_name}_start, &_binary_${obj_cleaned_name}_end)); \n") elseif (type STREQUAL "embed") file(APPEND "${EMBED_HEADER_DIR}/embed_resources.hpp" "inline EmbededResource embeded_${obj_cleaned_name}(&_binary_${obj_cleaned_name}_start, &_binary_${obj_cleaned_name}_end); \n") endif() endforeach() set(EMBED_OBJ_RET "${EMBED_OBJ_RET}" PARENT_SCOPE) endfunction() EmbedResources(${SHADILER_OBJ_RET} "${CMAKE_CURRENT_SOURCE_DIR}/res/debug_north.png") target_sources(${PROJECT_NAME} PRIVATE ${EMBED_OBJ_RET}) target_include_directories(${PROJECT_NAME} PUBLIC "${EMBED_HEADER_DIR}")