cmake_minimum_required(VERSION 4.1)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND NOT DEFINED CMAKE_CXX_COMPILER)
    if(EXISTS "/opt/homebrew/opt/llvm/bin/clang++")
        set(CMAKE_CXX_COMPILER "/opt/homebrew/opt/llvm/bin/clang++")
    endif()
endif()

if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux" AND NOT DEFINED CMAKE_CXX_COMPILER AND "$ENV{CXX}" STREQUAL "")
    find_program(_linux_clangxx NAMES clang++-21 clang++-20 clang++-19 clang++-18 clang++)
    if(_linux_clangxx)
        set(CMAKE_CXX_COMPILER "${_linux_clangxx}")
    endif()
endif()

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_SCAN_FOR_MODULES ON)

if(APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET)
    set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum macOS version" FORCE)
endif()

project(ProjectA)

if(APPLE)
    execute_process(COMMAND xcrun --show-sdk-path
                    OUTPUT_VARIABLE MACOS_SDK_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)
    if(NOT MACOS_SDK_PATH OR NOT IS_DIRECTORY "${MACOS_SDK_PATH}/usr/include/c++/v1")
        message(FATAL_ERROR "Could not locate the macOS SDK's libc++ headers via xcrun "
                            "(got '${MACOS_SDK_PATH}'). Install the Xcode command line tools.")
    endif()
    add_compile_options(
        "$<$<COMPILE_LANGUAGE:CXX>:-nostdinc++>"
        "$<$<COMPILE_LANGUAGE:CXX>:-isystem${MACOS_SDK_PATH}/usr/include/c++/v1>")
    add_link_options(-nostdlib++ -lc++)
endif()

if(NOT MSVC)
    add_compile_options(
        "-ffile-prefix-map=${CMAKE_BINARY_DIR}=."
        "-ffile-prefix-map=${CMAKE_SOURCE_DIR}=.")
else()
    file(TO_NATIVE_PATH "${CMAKE_SOURCE_DIR}" PROJECA_NATIVE_SOURCE_DIR)
    add_compile_options("/d1trimfile:${PROJECA_NATIVE_SOURCE_DIR}")

    add_link_options("/PDBALTPATH:%_PDB%")
endif()

set(CMAKE_POLICY_VERSION_MINIMUM 3.5)

if(MSVC)
    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
    set(SDL_FORCE_STATIC_VCRT ON CACHE BOOL "" FORCE)
endif()

include(FetchContent)

set(_offline_deps_complete TRUE)
foreach(_dep IN ITEMS bgfx SDL3 glm zlib assimp)
    string(TOUPPER "${_dep}" _DEP)
    if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/deps/${_dep}/CMakeLists.txt")
        set(FETCHCONTENT_SOURCE_DIR_${_DEP} "${CMAKE_CURRENT_SOURCE_DIR}/deps/${_dep}" CACHE PATH "" FORCE)
    else()
        set(_offline_deps_complete FALSE)
    endif()
endforeach()
if(_offline_deps_complete)
    set(FETCHCONTENT_FULLY_DISCONNECTED ON)
    message(STATUS "Bundled deps/ found, building fully offline")
endif()

find_package(Git QUIET)

set(BGFX_CMAKE_COMMIT de08a6080b39994ab8a9eddb82e79e18bc3df7bd)
set(BGFX_COMMIT 81d81fba72c42d348c589514c774bbfe01e110fa)
set(BX_COMMIT   25315498841259323e18f549d1ad9d9aba6632cc)
set(BIMG_COMMIT 87aaad3ac882e741889fdd4263224e5d12c26f99)
FetchContent_Declare(
    bgfx
    GIT_REPOSITORY https://github.com/bkaradzic/bgfx.cmake.git
    GIT_TAG ${BGFX_CMAKE_COMMIT}
    GIT_PROGRESS TRUE
    GIT_SUBMODULES ""
    PATCH_COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive --progress
          COMMAND ${GIT_EXECUTABLE} -C bgfx fetch --quiet origin master
          COMMAND ${GIT_EXECUTABLE} -C bgfx checkout --quiet --detach ${BGFX_COMMIT}
          COMMAND ${GIT_EXECUTABLE} -C bx   fetch --quiet origin master
          COMMAND ${GIT_EXECUTABLE} -C bx   checkout --quiet --detach ${BX_COMMIT}
          COMMAND ${GIT_EXECUTABLE} -C bimg fetch --quiet origin master
          COMMAND ${GIT_EXECUTABLE} -C bimg checkout --quiet --detach ${BIMG_COMMIT}
    USES_TERMINAL_PATCH TRUE
)
set(BGFX_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(BGFX_BUILD_TOOLS ON CACHE BOOL "" FORCE)
set(BGFX_BUILD_TOOLS_GEOMETRY OFF CACHE BOOL "" FORCE)
set(BGFX_BUILD_TOOLS_TEXTURE ON CACHE BOOL "" FORCE)
set(BGFX_INSTALL OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(bgfx)

if(TARGET bgfx)
    target_compile_definitions(bgfx PRIVATE
        BGFX_CONFIG_MAX_DYNAMIC_VERTEX_BUFFERS=32768
        BGFX_CONFIG_MAX_DYNAMIC_INDEX_BUFFERS=32768)
endif()

if(WIN32 AND TARGET bgfx)
    target_compile_definitions(bgfx PRIVATE BGFX_CONFIG_RENDERER_DIRECT3D11_USE_STAGING_BUFFER=1)
endif()

string(REPLACE "-ObjC++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")

set(BGFX_SHADER_INCLUDE_PATH "${BGFX_DIR}/src")
include(${bgfx_SOURCE_DIR}/cmake/bgfxToolUtils.cmake)

if(TARGET bgfx::shaderc)
    function(bgfx_compile_shaders)
        set(options AS_HEADERS)
        set(oneValueArgs TYPE VARYING_DEF OUTPUT_DIR OUT_FILES_VAR)
        set(multiValueArgs SHADERS INCLUDE_DIRS)
        cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")

        set(PROFILES 300_es spirv)
        if(IOS)
            set(PLATFORM IOS)
            list(APPEND PROFILES metal)
        elseif(ANDROID)
            set(PLATFORM ANDROID)
        elseif(UNIX AND NOT APPLE)
            set(PLATFORM LINUX)
        elseif(EMSCRIPTEN)
            set(PLATFORM ASM_JS)
        elseif(APPLE)
            set(PLATFORM OSX)
            list(APPEND PROFILES metal)
        elseif(WIN32 OR MINGW OR MSYS OR CYGWIN)
            set(PLATFORM WINDOWS)
            list(APPEND PROFILES s_5_0)
        elseif(ORBIS)
            set(PLATFORM ORBIS)
            list(APPEND PROFILES pssl)
        else()
            message(error "shaderc: Unsupported platform")
        endif()

        if(ARGS_TYPE STREQUAL "COMPUTE")
            list(REMOVE_ITEM PROFILES 300_es)
            list(APPEND PROFILES 310_es)
        endif()

        set(ALL_OUTPUTS "")

        set(SHADER_INCLUDE_DEPS "")
        foreach(INC_DIR ${ARGS_INCLUDE_DIRS})
            file(GLOB _shInc CONFIGURE_DEPENDS "${INC_DIR}/*.sh")
            list(APPEND SHADER_INCLUDE_DEPS ${_shInc})
        endforeach()

        foreach(SHADER_FILE ${ARGS_SHADERS})
            source_group("Shaders" FILES "${SHADER}")
            get_filename_component(SHADER_FILE_BASENAME ${SHADER_FILE} NAME)
            get_filename_component(SHADER_FILE_NAME_WE ${SHADER_FILE} NAME_WE)
            get_filename_component(SHADER_FILE_ABSOLUTE ${SHADER_FILE} ABSOLUTE)

            set(OUTPUTS "")
            set(COMMANDS "")
            set(MKDIR_COMMANDS "")
            foreach(PROFILE ${PROFILES})
                _bgfx_get_profile_path_ext(${PROFILE} PROFILE_PATH_EXT)
                _bgfx_get_profile_ext(${PROFILE} PROFILE_EXT)
                if(ARGS_AS_HEADERS)
                    set(HEADER_PREFIX .h)
                endif()
                set(OUTPUT ${ARGS_OUTPUT_DIR}/${PROFILE_PATH_EXT}/${SHADER_FILE_BASENAME}.bin${HEADER_PREFIX})
                set(PLATFORM_I ${PLATFORM})
                if(PROFILE STREQUAL "spirv")
                    set(PLATFORM_I LINUX)
                endif()
                set(BIN2C_PART "")
                if(ARGS_AS_HEADERS)
                    set(BIN2C_PART BIN2C ${SHADER_FILE_NAME_WE}_${PROFILE_EXT})
                endif()
                _bgfx_shaderc_parse(
                    CLI
                    ${BIN2C_PART}
                    ${ARGS_TYPE} ${PLATFORM_I} WERROR "$<$<CONFIG:debug>:DEBUG>$<$<CONFIG:relwithdebinfo>:DEBUG>"
                    FILE ${SHADER_FILE_ABSOLUTE}
                    OUTPUT ${OUTPUT}
                    PROFILE ${PROFILE}
                    O "$<$<CONFIG:debug>:0>$<$<CONFIG:release>:3>$<$<CONFIG:relwithdebinfo>:3>$<$<CONFIG:minsizerel>:3>"
                    VARYINGDEF ${ARGS_VARYING_DEF}
                    INCLUDES ${BGFX_SHADER_INCLUDE_PATH} ${ARGS_INCLUDE_DIRS}
                )
                list(APPEND OUTPUTS ${OUTPUT})
                list(APPEND ALL_OUTPUTS ${OUTPUT})
                list(
                    APPEND
                    MKDIR_COMMANDS
                    COMMAND
                    ${CMAKE_COMMAND}
                    -E
                    make_directory
                    ${ARGS_OUTPUT_DIR}/${PROFILE_PATH_EXT}
                )
                list(APPEND COMMANDS COMMAND bgfx::shaderc ${CLI})
            endforeach()

            add_custom_command(
                OUTPUT ${OUTPUTS}
                COMMAND ${MKDIR_COMMANDS} ${COMMANDS}
                MAIN_DEPENDENCY ${SHADER_FILE_ABSOLUTE}
                DEPENDS ${ARGS_VARYING_DEF} ${SHADER_INCLUDE_DEPS} $<TARGET_FILE:bgfx::shaderc>
            )
        endforeach()

        if(DEFINED ARGS_OUT_FILES_VAR)
            set(${ARGS_OUT_FILES_VAR} ${ALL_OUTPUTS} PARENT_SCOPE)
        endif()
    endfunction()
endif()

set(SDL_SHARED OFF CACHE BOOL "" FORCE)
set(SDL_STATIC ON CACHE BOOL "" FORCE)
FetchContent_Declare(
    SDL3
    GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
    GIT_TAG main
    GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(SDL3)
set(GLM_BUILD_LIBRARY OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
    glm
    GIT_REPOSITORY https://github.com/g-truc/glm.git
    GIT_TAG master
    GIT_SHALLOW TRUE
    GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(glm)

set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(ASSIMP_INSTALL OFF CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_ASSIMP_TOOLS OFF CACHE BOOL "" FORCE)
set(ASSIMP_NO_EXPORT ON CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT OFF CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT OFF CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_OBJ_IMPORTER ON CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_GLTF_IMPORTER ON CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_ZLIB OFF CACHE BOOL "" FORCE)
set(ASSIMP_WARNINGS_AS_ERRORS OFF CACHE BOOL "" FORCE)

set(ASSIMP_BUILD_MINIZIP ON CACHE BOOL "" FORCE)

set(ZLIB_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
    zlib
    GIT_REPOSITORY https://github.com/madler/zlib.git
    GIT_TAG v1.3.1
    GIT_SHALLOW TRUE
    GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(zlib)
set(ZLIB_INCLUDE_DIR "${zlib_SOURCE_DIR};${zlib_BINARY_DIR}" CACHE PATH "" FORCE)
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
add_definitions(-DASSIMP_BUILD_NO_OWN_ZLIB)

FetchContent_Declare(
    assimp
    GIT_REPOSITORY https://github.com/assimp/assimp.git
    GIT_TAG v5.4.3
    GIT_SHALLOW TRUE
    GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(assimp)

set(TRACY_ENABLE OFF CACHE BOOL "Enable Tracy profiling")
set(TRACY_ON_DEMAND ON CACHE BOOL "Tracy records only while the profiler GUI is connected")
FetchContent_Declare(
    tracy
    GIT_REPOSITORY https://github.com/wolfpld/tracy.git
    GIT_TAG v0.11.1
    GIT_SHALLOW TRUE
    GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(tracy)

file(GLOB_RECURSE CXX_MODULE_FILES CONFIGURE_DEPENDS "src/*.cppm")
list(FILTER CXX_MODULE_FILES EXCLUDE REGEX "/src/mod_example/")

add_executable(Client "src/main.cpp" "src/light_impl.cpp" "src/enet/monocypher.c")

if(CXX_MODULE_FILES)
    target_sources(Client
        PUBLIC
        FILE_SET cxx_modules TYPE CXX_MODULES
        FILES ${CXX_MODULE_FILES}
    )
endif()

file(GLOB MOD_SOURCES CONFIGURE_DEPENDS "mod/*.cppm")
target_sources(Client PUBLIC FILE_SET mod_modules TYPE CXX_MODULES FILES ${MOD_SOURCES})

target_compile_definitions(Client PRIVATE CLIENT)

if(MSVC)
    target_compile_definitions(Client PRIVATE NOMINMAX)
endif()

if(WIN32)
    set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE)
    set(CURL_USE_SCHANNEL ON CACHE BOOL "" FORCE)
    set(CURL_USE_OPENSSL OFF CACHE BOOL "" FORCE)
    set(CURL_USE_LIBPSL OFF CACHE BOOL "" FORCE)
    set(CURL_USE_LIBSSH2 OFF CACHE BOOL "" FORCE)
    set(CURL_ZLIB OFF CACHE BOOL "" FORCE)
    set(CURL_BROTLI OFF CACHE BOOL "" FORCE)
    set(CURL_ZSTD OFF CACHE BOOL "" FORCE)
    set(HTTP_ONLY ON CACHE BOOL "" FORCE)
    set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
    FetchContent_Declare(
        curl
        GIT_REPOSITORY https://github.com/curl/curl.git
        GIT_TAG curl-8_11_1
        GIT_SHALLOW TRUE
        GIT_PROGRESS TRUE
    )
    FetchContent_MakeAvailable(curl)
    set(PROJECA_CURL CURL::libcurl)
else()
    set(PROJECA_CURL curl)
endif()

target_link_libraries(Client PRIVATE SDL3::SDL3-static glm::glm bgfx bx bimg bimg_decode assimp zlibstatic ${PROJECA_CURL})

target_link_libraries(Client PRIVATE TracyClient)

if(MSVC)
    target_compile_options(Client PRIVATE /Z7)
    target_link_options(Client PRIVATE /DEBUG /OPT:REF /OPT:ICF)
else()
    target_compile_options(Client PRIVATE -g)
endif()

set(SHADER_DIR "${CMAKE_CURRENT_SOURCE_DIR}/shaders")
set(SHADER_OUTPUT_DIR "${CMAKE_BINARY_DIR}/shaders")
set(VARYING_DEF "${SHADER_DIR}/varying.def.sc")

file(GLOB VS_SHADERS CONFIGURE_DEPENDS "${SHADER_DIR}/vs_*.sc")
file(GLOB FS_SHADERS CONFIGURE_DEPENDS "${SHADER_DIR}/fs_*.sc" "${CMAKE_CURRENT_SOURCE_DIR}/mod/fs_*.sc")
file(GLOB CS_SHADERS CONFIGURE_DEPENDS "${SHADER_DIR}/cs_*.sc")

set(ALL_SHADER_OUTPUTS "")

if(VS_SHADERS)
    bgfx_compile_shaders(
        TYPE VERTEX
        SHADERS ${VS_SHADERS}
        VARYING_DEF ${VARYING_DEF}
        OUTPUT_DIR ${SHADER_OUTPUT_DIR}
        OUT_FILES_VAR VS_OUTPUTS
        INCLUDE_DIRS ${SHADER_DIR}
        AS_HEADERS
    )
    list(APPEND ALL_SHADER_OUTPUTS ${VS_OUTPUTS})
endif()

if(FS_SHADERS)
    bgfx_compile_shaders(
        TYPE FRAGMENT
        SHADERS ${FS_SHADERS}
        VARYING_DEF ${VARYING_DEF}
        OUTPUT_DIR ${SHADER_OUTPUT_DIR}
        OUT_FILES_VAR FS_OUTPUTS
        INCLUDE_DIRS ${SHADER_DIR}
        AS_HEADERS
    )
    list(APPEND ALL_SHADER_OUTPUTS ${FS_OUTPUTS})
endif()

if(CS_SHADERS)
    bgfx_compile_shaders(
        TYPE COMPUTE
        SHADERS ${CS_SHADERS}
        VARYING_DEF ${VARYING_DEF}
        OUTPUT_DIR ${SHADER_OUTPUT_DIR}
        OUT_FILES_VAR CS_OUTPUTS
        INCLUDE_DIRS ${SHADER_DIR}
        AS_HEADERS
    )
    list(APPEND ALL_SHADER_OUTPUTS ${CS_OUTPUTS})
endif()

add_custom_target(compile_shaders ALL DEPENDS ${ALL_SHADER_OUTPUTS})

add_dependencies(Client compile_shaders)
target_include_directories(Client PRIVATE ${SHADER_OUTPUT_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src)

set(TEXTURE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/textures")
file(GLOB TEXTURE_SOURCES CONFIGURE_DEPENDS "${TEXTURE_DIR}/*.tga")
list(REMOVE_ITEM TEXTURE_SOURCES "${TEXTURE_DIR}/red.tga")

if(TARGET bgfx::texturec)
    set(ALL_TEXTURE_OUTPUTS "")
    foreach(TEX_SRC ${TEXTURE_SOURCES})
        get_filename_component(TEX_NAME_WE ${TEX_SRC} NAME_WE)
        set(TEX_OUT "${TEXTURE_DIR}/${TEX_NAME_WE}.ktx")
        if(TEX_NAME_WE MATCHES "-n$")
            bgfx_compile_texture(FILE ${TEX_SRC} OUTPUT ${TEX_OUT} FORMAT BC5 MIPS NORMALMAP LINEAR)
        else()
            bgfx_compile_texture(FILE ${TEX_SRC} OUTPUT ${TEX_OUT} FORMAT BC1 MIPS)
        endif()
        list(APPEND ALL_TEXTURE_OUTPUTS ${TEX_OUT})
    endforeach()

    add_custom_target(compile_textures ALL DEPENDS ${ALL_TEXTURE_OUTPUTS})
    add_dependencies(Client compile_textures)
endif()
