cmake_minimum_required(VERSION 3.24)

project(openxr_simulator VERSION 0.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

option(XRSIM_BUILD_COMPOSITOR "Build the GLFW + Dear ImGui display window" ON)

find_package(Vulkan REQUIRED)

include(FetchContent)

# ---------------------------------------------------------------------------
# GLFW
# ---------------------------------------------------------------------------
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(GLFW_INSTALL OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
    glfw
    GIT_REPOSITORY https://github.com/glfw/glfw.git
    GIT_TAG 3.4
)
FetchContent_MakeAvailable(glfw)

# ---------------------------------------------------------------------------
# Dear ImGui (docking branch, matches the engine's 1.91.4-docking)
# ---------------------------------------------------------------------------
FetchContent_Declare(
    imgui
    GIT_REPOSITORY https://github.com/ocornut/imgui.git
    GIT_TAG v1.91.4-docking
)
# imgui has no CMakeLists.txt, so this only downloads it.
FetchContent_MakeAvailable(imgui)

add_library(imgui STATIC
    ${imgui_SOURCE_DIR}/imgui.cpp
    ${imgui_SOURCE_DIR}/imgui_draw.cpp
    ${imgui_SOURCE_DIR}/imgui_tables.cpp
    ${imgui_SOURCE_DIR}/imgui_widgets.cpp
    ${imgui_SOURCE_DIR}/imgui_demo.cpp
    ${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp
    ${imgui_SOURCE_DIR}/backends/imgui_impl_vulkan.cpp
    ${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
)
target_include_directories(imgui SYSTEM PUBLIC
    ${imgui_SOURCE_DIR}
    ${imgui_SOURCE_DIR}/backends
)
target_link_libraries(imgui PUBLIC glfw Vulkan::Vulkan)

# ---------------------------------------------------------------------------
# JSON dependency + shared runtime config
# ---------------------------------------------------------------------------
FetchContent_Declare(
    json
    GIT_REPOSITORY https://github.com/nlohmann/json.git
    GIT_TAG v3.11.3
)
FetchContent_MakeAvailable(json)

add_library(xrsim_config STATIC src/Config.cpp)
target_include_directories(xrsim_config PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(xrsim_config PUBLIC nlohmann_json::nlohmann_json)

# ---------------------------------------------------------------------------
# OpenXR simulator runtime
# ---------------------------------------------------------------------------
add_library(openxr_simulator SHARED
    src/Negotiation.cpp
    src/Runtime.cpp
)

if(XRSIM_BUILD_COMPOSITOR)
    target_sources(openxr_simulator PRIVATE src/Compositor.cpp)
    target_link_libraries(openxr_simulator PRIVATE imgui)
else()
    target_sources(openxr_simulator PRIVATE src/CompositorStub.cpp)
endif()

target_include_directories(openxr_simulator
    PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${CMAKE_CURRENT_SOURCE_DIR}/third_party
)

target_compile_definitions(openxr_simulator
    PRIVATE
        XR_USE_PLATFORM_WIN32
        XR_USE_GRAPHICS_API_VULKAN
        XR_NO_PROTOTYPES
)

target_link_libraries(openxr_simulator PRIVATE Vulkan::Vulkan xrsim_config)

if(MINGW)
    # Statically link the GCC runtime (libstdc++/libgcc/libwinpthread) into the DLL so the OpenXR
    # loader can load it when the app is launched from Explorer (no MinGW bin on PATH).
    target_link_options(openxr_simulator PRIVATE -static-libgcc -static-libstdc++ -static)
endif()

if(MSVC)
    target_compile_options(openxr_simulator PRIVATE /W4)
else()
    # Vulkan structs are routinely zero-initialized with `{ VK_STRUCTURE_TYPE_... }`.
    target_compile_options(openxr_simulator PRIVATE -Wall -Wextra -Wno-missing-field-initializers)
endif()

set_target_properties(openxr_simulator PROPERTIES
    PREFIX ""
    OUTPUT_NAME "openxr_simulator"
)

# Runtime manifest consumed by the OpenXR loader (via XR_RUNTIME_JSON or registry).
set(SIM_RUNTIME_NAME "OpenXR Simulator")
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/manifest/openxr_simulator.json.in
    ${CMAKE_CURRENT_BINARY_DIR}/openxr_simulator.json
    @ONLY
)

# ---------------------------------------------------------------------------
# Configurator application (edits openxr_simulator_config.json)
# ---------------------------------------------------------------------------
if(XRSIM_BUILD_COMPOSITOR)
    find_package(OpenGL REQUIRED)

    add_executable(openxr_simulator_configurator WIN32 tools/configurator/ConfiguratorMain.cpp)
    target_link_libraries(openxr_simulator_configurator PRIVATE xrsim_config imgui glfw OpenGL::GL)

    if(MINGW)
        target_link_options(
            openxr_simulator_configurator PRIVATE -static-libgcc -static-libstdc++ -static
        )
    endif()
endif()
