cmake_minimum_required(VERSION 3.28)

project(OpenRA3 VERSION 0.0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 26)
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()

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")

option(OPENRA3_WERROR "Treat warnings as errors" OFF)

function(openra3_target_defaults target)
    target_compile_options(${target} PRIVATE -Wall -Wextra -Wpedantic)
    if(OPENRA3_WERROR)
        target_compile_options(${target} PRIVATE -Werror)
    endif()
endfunction()

# --- engine core: fundamental types, math, strings, random, message stream ---
add_library(ra3_core STATIC)
target_sources(ra3_core
    PUBLIC FILE_SET CXX_MODULES FILES
        src/core/ra3.core.cppm
)
openra3_target_defaults(ra3_core)

# --- game logic: objects, players, teams, spatial partition, game loop ---
add_library(ra3_logic STATIC)
target_sources(ra3_logic
    PUBLIC FILE_SET CXX_MODULES FILES
        src/logic/ra3.logic.cppm
)
target_link_libraries(ra3_logic PUBLIC ra3_core)
openra3_target_defaults(ra3_logic)

# --- client: headless display/input abstraction and the client facade ---
add_library(ra3_client STATIC)
target_sources(ra3_client
    PUBLIC FILE_SET CXX_MODULES FILES
        src/client/ra3.client.cppm
)
target_link_libraries(ra3_client PUBLIC ra3_core ra3_logic)
openra3_target_defaults(ra3_client)

# --- RA3 game definitions: factions, player templates, science, special powers ---
add_library(ra3_game STATIC)
target_sources(ra3_game
    PUBLIC FILE_SET CXX_MODULES FILES
        src/game/ra3.game.cppm
)
target_link_libraries(ra3_game PUBLIC ra3_core ra3_logic)
openra3_target_defaults(ra3_game)

# --- filesystem: BIG4 archives, RefPack codec, local install locator ---
add_library(ra3_fs STATIC)
target_sources(ra3_fs
    PUBLIC FILE_SET CXX_MODULES FILES
        src/fs/ra3.fs.cppm
)
target_link_libraries(ra3_fs PUBLIC ra3_core)
openra3_target_defaults(ra3_fs)

# --- map discovery/loading (real .big data, user's local install) ---
add_library(ra3_map STATIC)
target_sources(ra3_map
    PUBLIC FILE_SET CXX_MODULES FILES
        src/map/ra3.map.cppm
)
target_link_libraries(ra3_map PUBLIC ra3_core ra3_fs)
openra3_target_defaults(ra3_map)

# --- minimal headless skirmish simulation ---
add_library(ra3_skirmish STATIC)
target_sources(ra3_skirmish
    PUBLIC FILE_SET CXX_MODULES FILES
        src/skirmish/ra3.skirmish.cppm
)
target_link_libraries(ra3_skirmish PUBLIC ra3_core ra3_logic ra3_game ra3_map)
openra3_target_defaults(ra3_skirmish)

# --- software renderer: framebuffer, TGA decode, BMP encode, map compositing ---
add_library(ra3_render STATIC)
target_sources(ra3_render
    PUBLIC FILE_SET CXX_MODULES FILES
        src/render/ra3.render.cppm
)
target_link_libraries(ra3_render PUBLIC ra3_core)
openra3_target_defaults(ra3_render)

# --- windowed viewer: SDL3 when available, otherwise a null backend ---
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
    pkg_check_modules(SDL3 QUIET IMPORTED_TARGET sdl3)
endif()
add_library(ra3_ui STATIC)
if(SDL3_FOUND)
    target_sources(ra3_ui
        PUBLIC FILE_SET CXX_MODULES FILES
            src/ui/ra3.ui.sdl.cppm
    )
    target_link_libraries(ra3_ui PUBLIC ra3_core ra3_render PkgConfig::SDL3)
    message(STATUS "OpenRA3: SDL3 ${SDL3_VERSION} found - windowed viewer enabled")
else()
    target_sources(ra3_ui
        PUBLIC FILE_SET CXX_MODULES FILES
            src/ui/ra3.ui.null.cppm
    )
    target_link_libraries(ra3_ui PUBLIC ra3_core ra3_render)
    message(STATUS "OpenRA3: SDL3 not found - offscreen BMP output only")
endif()
openra3_target_defaults(ra3_ui)

# --- umbrella module re-exporting the whole SDK ---
add_library(ra3 STATIC)
target_sources(ra3
    PUBLIC FILE_SET CXX_MODULES FILES
        src/ra3.cppm
)
target_link_libraries(ra3 PUBLIC ra3_core ra3_logic ra3_client ra3_game ra3_fs ra3_map ra3_skirmish ra3_render ra3_ui)
openra3_target_defaults(ra3)

# --- the headless game executable ---
add_executable(openra3 apps/openra3/main.cpp)
target_link_libraries(openra3 PRIVATE ra3)
openra3_target_defaults(openra3)

# --- unit tests ---
enable_testing()
add_executable(ra3_tests tests/ra3_tests.cpp)
target_link_libraries(ra3_tests PRIVATE ra3)
openra3_target_defaults(ra3_tests)
add_test(NAME ra3_tests COMMAND ra3_tests)
