add_subdirectory(third_party)

set(SRC_FILES
        "src/App.cpp"
        "src/Event.cpp"

        "src/Components/Animator.cpp"
        "src/Components/MeshRendererComponent.cpp"
        "src/Components/Rotator.cpp"
        "src/Components/Spinner.cpp"
        "src/Components/OrbitAndSpin.cpp"

        "src/Components/Physics/Rigidbody.cpp"
        "src/Components/Physics/BoxCollider.cpp"
        "src/Components/Physics/CapsuleCollider.cpp"
        "src/Components/Physics/Collider.cpp"
        "src/Components/Physics/SphereCollider.cpp"

        "src/Graphics/BindlessSetManager.cpp"
        "src/Graphics/Camera.cpp"
        "src/Graphics/ComputePipeline.cpp"
        "src/Graphics/Frustum.cpp"
        "src/Graphics/GfxDevice.cpp"
        "src/Graphics/Caches/ImageCache.cpp"
        "src/Graphics/ImageLoader.cpp"
        "src/Graphics/ImmediateExecuter.cpp"
        "src/Graphics/Init.cpp"
        "src/Graphics/Caches/MaterialCache.cpp"
        "src/Graphics/MeshCache.cpp"
        "src/Graphics/Pipeline.cpp"
        "src/Graphics/Renderer.cpp"
        "src/Graphics/Swapchain.cpp"
        "src/Graphics/Util.cpp"
        "src/Graphics/RenderResources.cpp"

        "src/Graphics/Managers/VulkanInstanceManager.cpp"
        "src/Graphics/Managers/MemoryManager.cpp"
        "src/Graphics/Managers/FrameManager.cpp"
        "src/Graphics/Managers/ImageManager.cpp"
        "src/Graphics/Managers/LineRenderingManager.cpp"
        "src/Graphics/Managers/QuadRenderingManager.cpp"

        "src/Graphics/Resources/GPUImage.cpp"
        "src/Graphics/Resources/NBuffer.cpp"
        "src/Graphics/Resources/Cubemap.cpp"

        "src/Graphics/Pipelines/MeshPipeline.cpp"
        "src/Graphics/Pipelines/LineRenderingPass.cpp"
        "src/Graphics/Pipelines/QuadRendererPass.cpp"
        "src/Graphics/Pipelines/SkyboxPipeline.cpp"
        "src/Graphics/Pipelines/SkinningPipeline.cpp"
        "src/Graphics/Pipelines/ImguiPass.cpp"

        "src/Input/InputManager.cpp"

        "src/ObjectModel/Component.cpp"
        "src/ObjectModel/GameObject.cpp"
        "src/ObjectModel/Object.cpp"
        "src/ObjectModel/Transform.cpp"

        "src/Scene/Scene.cpp"
        "src/Scene/SceneManager.cpp"

        "src/FS/AssetFS.cpp"
        "src/FS/Manifest.cpp"

        "src/Assets/AssetManager.cpp"

        "src/Serialization/SceneSerializer.cpp"
        "src/Serialization/ComponentRegistry.cpp"

        "src/Util/DeltaTime.cpp"
        "src/Util/ImGuiUtils.cpp"

        "src/Physics/PhysicsWorld.cpp"
        "src/Physics/SimplePhysicsWorld.cpp"
        "src/Physics/PhysicsSceneBridge.cpp"
        "src/Physics/JoltPhysicsWorld.cpp"
)

add_library(destrum ${SRC_FILES})

add_library(destrum::destrum ALIAS destrum)

set_target_properties(destrum PROPERTIES
        CXX_STANDARD 20
        CXX_EXTENSIONS OFF
)

#target_add_extra_warnings(destrum)

target_include_directories(destrum PUBLIC "${CMAKE_CURRENT_LIST_DIR}/include")
target_include_directories(destrum PRIVATE
        "${CMAKE_CURRENT_LIST_DIR}/third_party/jolt"
)

target_link_libraries(destrum
        PUBLIC
        volk::volk_headers
        vk-bootstrap::vk-bootstrap
        GPUOpen::VulkanMemoryAllocator

        glm::glm
        nlohmann_json::nlohmann_json
        spdlog::spdlog
        stb::image
        tinygltf
        assimp
        imgui
        Jolt
        Tracy::TracyClient

        PRIVATE
        freetype::freetype
        tinyexr
)

target_compile_definitions(destrum
        PUBLIC
        VK_NO_PROTOTYPES
        VMA_VULKAN_VERSION=1003000
        TRACY_VK_USE_SYMBOL_TABLE
        # VOLK_DEFAULT_VISIBILITY # FIXME: doesn't work for some reason
)

if (WIN32)
    target_link_libraries(destrum PUBLIC SDL2::SDL2main)
endif ()

if (BUILD_SHARED_LIBS)
    target_link_libraries(destrum PUBLIC SDL2::SDL2)
else ()
    target_link_libraries(destrum PUBLIC SDL2::SDL2-static)
endif ()

target_compile_definitions(destrum
        PUBLIC
        GLM_FORCE_CTOR_INIT
        GLM_FORCE_XYZW_ONLY
        GLM_FORCE_EXPLICIT_CTOR
        GLM_FORCE_DEPTH_ZERO_TO_ONE
        GLM_ENABLE_EXPERIMENTAL
)

set(ASSETS_SRC_DIR     "${CMAKE_CURRENT_LIST_DIR}/assets_src")
set(ASSETS_RUNTIME_DIR "${CMAKE_CURRENT_LIST_DIR}/assets_runtime")
#set(OUTPUT_ENGINE_ASSETS_DIR "${CMAKE_BINARY_DIR}/assets/engine")
#
#add_custom_command(TARGET destrum POST_BUILD
#        COMMAND ${CMAKE_COMMAND} -E rm -rf "${OUTPUT_ENGINE_ASSETS_DIR}"
#        COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/assets"
#        COMMAND ${CMAKE_COMMAND} -E create_symlink "${ASSETS_RUNTIME_DIR}" "${OUTPUT_ENGINE_ASSETS_DIR}"
#        VERBATIM
#)

file(GLOB_RECURSE ENGINE_ASSET_SOURCES CONFIGURE_DEPENDS
        "${ASSETS_SRC_DIR}/*")

add_custom_target(_internal_clean_engine_assets
         COMMAND TheChef
         --input  "${ASSETS_SRC_DIR}"
         --output "${ASSETS_RUNTIME_DIR}"
         --clean
         DEPENDS TheChef
)

add_custom_target(_internal_cook_engine_assets
        COMMAND TheChef
        --input  "${ASSETS_SRC_DIR}"
        --output "${ASSETS_RUNTIME_DIR}"
        --clean
        COMMAND TheChef
        --input  "${ASSETS_SRC_DIR}"
        --output "${ASSETS_RUNTIME_DIR}"
        DEPENDS TheChef ${ENGINE_ASSET_SOURCES}
        VERBATIM
)

find_program(SPIRV_VAL_EXECUTABLE NAMES spirv-val spirv-val.exe)
if (SPIRV_VAL_EXECUTABLE)
    file(GLOB_RECURSE ENGINE_SHADER_SOURCES CONFIGURE_DEPENDS
            "${ASSETS_SRC_DIR}/*.vert"
            "${ASSETS_SRC_DIR}/*.frag"
            "${ASSETS_SRC_DIR}/*.comp")

    set(VALIDATE_SHADER_COMMANDS)
    foreach(shader_source IN LISTS ENGINE_SHADER_SOURCES)
        file(RELATIVE_PATH shader_relative "${ASSETS_SRC_DIR}" "${shader_source}")
        list(APPEND VALIDATE_SHADER_COMMANDS
                COMMAND "${SPIRV_VAL_EXECUTABLE}"
                "${ASSETS_RUNTIME_DIR}/${shader_relative}.spv")
    endforeach()

    add_custom_target(_internal_validate_engine_shaders
            DEPENDS _internal_cook_engine_assets
            ${VALIDATE_SHADER_COMMANDS}
    )
endif()

function(destrum_cook_engine_assets GAME_TARGET GAME_OUTPUT_DIR)
    # This resolves to destrum's own directory at function DEFINITION time
    set(_engine_src     "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/assets_src")
    set(_engine_runtime "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/assets_runtime")
    set(_output_engine  "$<TARGET_FILE_DIR:${GAME_TARGET}>/assets/engine")

    if (WIN32)
        set(_engine_asset_install_commands
                COMMAND ${CMAKE_COMMAND} -E copy_directory
                "${_engine_runtime}" "${_output_engine}")
    else()
        set(_engine_asset_install_commands
                COMMAND ${CMAKE_COMMAND} -E create_symlink
                "${_engine_runtime}" "${_output_engine}")
    endif()

    add_custom_command(TARGET ${GAME_TARGET} POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E make_directory "${_output_engine}/.."
            COMMAND ${CMAKE_COMMAND} -E rm -rf "${_output_engine}"
            ${_engine_asset_install_commands}
            VERBATIM
    )

    add_dependencies(${GAME_TARGET} _internal_cook_engine_assets)

    install(DIRECTORY "${_engine_runtime}/" DESTINATION "bin/assets/engine")
endfunction()

install(TARGETS destrum
        ARCHIVE DESTINATION lib
        LIBRARY DESTINATION lib
        RUNTIME DESTINATION bin)
install(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/" DESTINATION include)
