# n3 - ReXGlue Recompiled Project
#
# SDK boilerplate lives in generated/rexglue.cmake.

cmake_minimum_required(VERSION 3.25)
project(n3 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    add_compile_options("-ffile-prefix-map=${CMAKE_SOURCE_DIR}=." "-fdebug-prefix-map=${CMAKE_SOURCE_DIR}=.")
endif()
if(WIN32)
    add_link_options("LINKER:/Brepro" "LINKER:/PDBALTPATH:%_PDB%")
endif()

option(N3_BUILD_GAME "Build the Windows game and renderer" ON)
include(CTest)

add_library(n3_native STATIC src/native/frame_clock.cpp src/native/shape_bounds.cpp src/native/vector_ops.cpp
    src/native/frame_countdown.cpp src/native/scalar_math.cpp src/native/box_geometry.cpp
    src/native/shape_projection.cpp src/native/delay_block.cpp src/native/feedback_delay.cpp
    src/native/bounded_value.cpp src/native/capped_accumulator.cpp src/native/handle_table.cpp
    src/native/state_payload.cpp src/native/payload_install.cpp src/native/direction_math.cpp
    src/native/direction_accumulation.cpp src/native/direction_basis.cpp src/native/chance_roll.cpp
    src/native/state_queries.cpp)
target_include_directories(n3_native PUBLIC src)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    target_compile_options(n3_native PRIVATE -ffp-model=strict -ffp-contract=off)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    target_compile_options(n3_native PRIVATE -frounding-math -ffp-contract=off)
elseif(MSVC)
    target_compile_options(n3_native PRIVATE /fp:strict)
endif()

add_library(n3_game_data STATIC src/game_data.cpp src/file_hash.cpp src/import_paths.cpp)
target_include_directories(n3_game_data PUBLIC src)
if(WIN32)
    target_compile_definitions(n3_game_data PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
    target_link_libraries(n3_game_data PUBLIC bcrypt)
elseif(NOT APPLE)
    find_package(OpenSSL REQUIRED COMPONENTS Crypto)
    target_link_libraries(n3_game_data PRIVATE OpenSSL::Crypto)
endif()
add_library(n3_menu_assets STATIC src/graphics_menu_assets.cpp)
target_include_directories(n3_menu_assets PUBLIC src)
add_executable(n3_import tools/import_main.cpp)
target_link_libraries(n3_import PRIVATE n3_game_data)
if(BUILD_TESTING)
    add_executable(n3_native_clock_test tests/native_clock_test.cpp)
    target_link_libraries(n3_native_clock_test PRIVATE n3_native)
    add_test(NAME native_frame_clock COMMAND n3_native_clock_test)
    add_executable(n3_native_chance_roll_test tests/native_chance_roll_test.cpp)
    target_link_libraries(n3_native_chance_roll_test PRIVATE n3_native)
    add_test(NAME native_chance_roll COMMAND n3_native_chance_roll_test)
    add_executable(n3_native_state_queries_test tests/native_state_queries_test.cpp)
    target_link_libraries(n3_native_state_queries_test PRIVATE n3_native)
    add_test(NAME native_state_queries COMMAND n3_native_state_queries_test)
    add_executable(n3_native_bounds_test tests/native_bounds_test.cpp)
    target_link_libraries(n3_native_bounds_test PRIVATE n3_native)
    add_test(NAME native_shape_bounds COMMAND n3_native_bounds_test)
    add_executable(n3_native_vector_test tests/native_vector_test.cpp)
    target_link_libraries(n3_native_vector_test PRIVATE n3_native)
    add_test(NAME native_vector_ops COMMAND n3_native_vector_test)
    add_executable(n3_native_primitives_test tests/native_primitives_test.cpp)
    target_link_libraries(n3_native_primitives_test PRIVATE n3_native)
    add_test(NAME native_engine_primitives COMMAND n3_native_primitives_test)
    add_executable(n3_native_box_test tests/native_box_test.cpp)
    target_link_libraries(n3_native_box_test PRIVATE n3_native)
    add_test(NAME native_box_geometry COMMAND n3_native_box_test)
    add_executable(n3_native_projection_test tests/native_projection_test.cpp)
    target_link_libraries(n3_native_projection_test PRIVATE n3_native)
    add_test(NAME native_shape_projection COMMAND n3_native_projection_test)
    add_executable(n3_native_delay_test tests/native_delay_test.cpp)
    target_link_libraries(n3_native_delay_test PRIVATE n3_native)
    add_test(NAME native_delay_block COMMAND n3_native_delay_test)
    add_executable(n3_native_feedback_test tests/native_feedback_test.cpp)
    target_link_libraries(n3_native_feedback_test PRIVATE n3_native)
    add_test(NAME native_feedback_delay COMMAND n3_native_feedback_test)
    add_executable(n3_native_bounded_value_test tests/native_bounded_value_test.cpp)
    target_link_libraries(n3_native_bounded_value_test PRIVATE n3_native)
    add_test(NAME native_bounded_value COMMAND n3_native_bounded_value_test)
    add_executable(n3_native_capped_accumulator_test tests/native_capped_accumulator_test.cpp)
    target_link_libraries(n3_native_capped_accumulator_test PRIVATE n3_native)
    add_test(NAME native_capped_accumulator COMMAND n3_native_capped_accumulator_test)
    add_executable(n3_native_handle_table_test tests/native_handle_table_test.cpp)
    target_link_libraries(n3_native_handle_table_test PRIVATE n3_native)
    add_test(NAME native_handle_table COMMAND n3_native_handle_table_test)
    add_executable(n3_native_state_payload_test tests/native_state_payload_test.cpp)
    target_link_libraries(n3_native_state_payload_test PRIVATE n3_native)
    add_test(NAME native_state_payload COMMAND n3_native_state_payload_test)
    add_executable(n3_native_payload_install_test tests/native_payload_install_test.cpp)
    target_link_libraries(n3_native_payload_install_test PRIVATE n3_native)
    add_test(NAME native_payload_install COMMAND n3_native_payload_install_test)
    add_executable(n3_native_direction_math_test tests/native_direction_math_test.cpp)
    target_link_libraries(n3_native_direction_math_test PRIVATE n3_native)
    add_test(NAME native_direction_math COMMAND n3_native_direction_math_test)
    add_executable(n3_native_direction_accumulation_test tests/native_direction_accumulation_test.cpp)
    target_link_libraries(n3_native_direction_accumulation_test PRIVATE n3_native)
    add_test(NAME native_direction_accumulation COMMAND n3_native_direction_accumulation_test)
    add_executable(n3_native_direction_basis_test tests/native_direction_basis_test.cpp)
    target_link_libraries(n3_native_direction_basis_test PRIVATE n3_native)
    add_test(NAME native_direction_basis COMMAND n3_native_direction_basis_test)
    add_executable(n3_game_data_test tests/game_data_test.cpp)
    target_link_libraries(n3_game_data_test PRIVATE n3_game_data)
    add_test(NAME game_data_import COMMAND n3_game_data_test)
    add_executable(n3_graphics_menu_test tests/graphics_menu_test.cpp)
    target_link_libraries(n3_graphics_menu_test PRIVATE n3_menu_assets)
    add_test(NAME graphics_menu_assets COMMAND n3_graphics_menu_test)
endif()
if(NOT N3_BUILD_GAME)
    message(STATUS "Building portable native components only; no game runtime")
    return()
endif()
if(NOT WIN32)
    message(FATAL_ERROR "The full N3 runtime is Windows-only while platform/GPU adapters are ported. Use -DN3_BUILD_GAME=OFF for portable components.")
endif()
include(generated/rexglue.cmake)

# Sources
set(N3_SOURCES
    src/main.cpp
    src/app_icon.cpp
    src/crash_diagnostics.cpp
    src/runtime_fixes.cpp
    src/shape_bounds_hooks.cpp
    src/vector_ops_hooks.cpp
    src/engine_primitives_hooks.cpp
    src/box_geometry_hooks.cpp
    src/shape_projection_hooks.cpp
    src/delay_block_hooks.cpp
    src/feedback_delay_hooks.cpp
    src/bounded_value_hooks.cpp
    src/capped_accumulator_hooks.cpp
    src/handle_table_hooks.cpp
    src/state_payload_hooks.cpp
    src/state_relation_hooks.cpp
    src/direction_normalization_hooks.cpp
    src/direction_accumulation_hooks.cpp
    src/direction_basis_hooks.cpp
    src/chance_roll_hooks.cpp
    src/state_queries_hooks.cpp
    src/game_setup.cpp
    src/frame_rate.cpp
    src/display_settings.cpp
    src/profile_config.cpp
    src/graphics_menu.cpp
    src/graphics_notification.cpp
    src/graphics_settings.cpp
    src/graphics_audit.cpp
)

if(WIN32)
    enable_language(RC)
    configure_file(resources/n3.rc.in ${CMAKE_CURRENT_BINARY_DIR}/n3.rc @ONLY)
    add_executable(n3 WIN32 ${N3_SOURCES})
    target_sources(n3 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/n3.rc)
else()
    add_executable(n3 ${N3_SOURCES})
endif()

add_subdirectory(tools/gpu)
rexglue_setup_target(n3 GPU_PLUGINS xenos)

target_link_libraries(n3 PRIVATE n3_native n3_game_data n3_menu_assets comdlg32 ole32 uuid shell32)
if(BUILD_TESTING)
    add_executable(n3_fp_policy_test tests/fp_policy_test.cpp)
    target_include_directories(n3_fp_policy_test PRIVATE src)
    target_link_libraries(n3_fp_policy_test PRIVATE rex::runtime)
    add_test(NAME callback_fp_policy COMMAND n3_fp_policy_test)
    add_executable(n3_game_setup_test tests/game_setup_test.cpp src/game_setup.cpp)
    target_link_libraries(n3_game_setup_test PRIVATE n3_game_data rex::runtime comdlg32 ole32 uuid shell32)
    add_test(NAME game_data_setup COMMAND n3_game_setup_test)
    add_executable(n3_crash_diagnostics_test tests/crash_diagnostics_test.cpp src/crash_diagnostics.cpp)
    target_include_directories(n3_crash_diagnostics_test PRIVATE src)
    add_test(NAME crash_diagnostics COMMAND n3_crash_diagnostics_test)
    add_executable(n3_frame_rate_test tests/frame_rate_test.cpp src/frame_rate.cpp)
    target_include_directories(n3_frame_rate_test PRIVATE src)
    target_compile_definitions(n3_frame_rate_test PRIVATE N3_FRAME_RATE_TEST)
    target_link_libraries(n3_frame_rate_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_frame_rate_test)
    add_test(NAME frame_rate_policy COMMAND n3_frame_rate_test)
    add_executable(n3_shape_bounds_test tests/shape_bounds_test.cpp src/shape_bounds_hooks.cpp)
    target_include_directories(n3_shape_bounds_test PRIVATE src)
    target_compile_definitions(n3_shape_bounds_test PRIVATE N3_SHAPE_BOUNDS_TEST)
    target_link_libraries(n3_shape_bounds_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_shape_bounds_test)
    add_test(NAME shape_bounds_equivalence COMMAND n3_shape_bounds_test)
    add_executable(n3_vector_ops_test tests/vector_ops_test.cpp src/vector_ops_hooks.cpp)
    target_include_directories(n3_vector_ops_test PRIVATE src)
    target_compile_definitions(n3_vector_ops_test PRIVATE N3_VECTOR_OPS_TEST)
    target_link_libraries(n3_vector_ops_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_vector_ops_test)
    add_test(NAME vector_ops_equivalence COMMAND n3_vector_ops_test)
    add_executable(n3_engine_primitives_test tests/engine_primitives_test.cpp src/engine_primitives_hooks.cpp)
    target_include_directories(n3_engine_primitives_test PRIVATE src)
    target_compile_definitions(n3_engine_primitives_test PRIVATE N3_ENGINE_PRIMITIVES_TEST)
    target_link_libraries(n3_engine_primitives_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_engine_primitives_test)
    add_test(NAME engine_primitives_equivalence COMMAND n3_engine_primitives_test)
    add_executable(n3_box_geometry_test tests/box_geometry_test.cpp src/box_geometry_hooks.cpp)
    target_include_directories(n3_box_geometry_test PRIVATE src)
    target_compile_definitions(n3_box_geometry_test PRIVATE N3_BOX_GEOMETRY_TEST)
    target_link_libraries(n3_box_geometry_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_box_geometry_test)
    add_test(NAME box_geometry_equivalence COMMAND n3_box_geometry_test)
    add_executable(n3_shape_projection_test tests/shape_projection_test.cpp src/shape_projection_hooks.cpp)
    target_include_directories(n3_shape_projection_test PRIVATE src)
    target_compile_definitions(n3_shape_projection_test PRIVATE N3_SHAPE_PROJECTION_TEST)
    target_link_libraries(n3_shape_projection_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_shape_projection_test)
    add_test(NAME shape_projection_equivalence COMMAND n3_shape_projection_test)
    add_executable(n3_delay_block_test tests/delay_block_test.cpp src/delay_block_hooks.cpp)
    target_include_directories(n3_delay_block_test PRIVATE src)
    target_compile_definitions(n3_delay_block_test PRIVATE N3_DELAY_BLOCK_TEST)
    target_link_libraries(n3_delay_block_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_delay_block_test)
    add_test(NAME delay_block_equivalence COMMAND n3_delay_block_test)
    add_executable(n3_feedback_delay_test tests/feedback_delay_test.cpp src/feedback_delay_hooks.cpp)
    target_include_directories(n3_feedback_delay_test PRIVATE src)
    target_compile_definitions(n3_feedback_delay_test PRIVATE N3_FEEDBACK_DELAY_TEST)
    target_link_libraries(n3_feedback_delay_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_feedback_delay_test)
    add_test(NAME feedback_delay_equivalence COMMAND n3_feedback_delay_test)
    add_executable(n3_bounded_value_test tests/bounded_value_test.cpp src/bounded_value_hooks.cpp)
    target_include_directories(n3_bounded_value_test PRIVATE src)
    target_compile_definitions(n3_bounded_value_test PRIVATE N3_BOUNDED_ORACLE_SWITCH)
    target_link_libraries(n3_bounded_value_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_bounded_value_test)
    add_test(NAME bounded_value_equivalence COMMAND n3_bounded_value_test)
    add_executable(n3_percentage_value_test tests/percentage_value_test.cpp src/bounded_value_hooks.cpp)
    target_include_directories(n3_percentage_value_test PRIVATE src)
    target_compile_definitions(n3_percentage_value_test PRIVATE N3_PERCENTAGE_ORACLE_SWITCH)
    target_link_libraries(n3_percentage_value_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_percentage_value_test)
    add_test(NAME percentage_value_equivalence COMMAND n3_percentage_value_test)
    add_executable(n3_capped_accumulator_test tests/capped_accumulator_test.cpp src/capped_accumulator_hooks.cpp)
    target_include_directories(n3_capped_accumulator_test PRIVATE src)
    target_compile_definitions(n3_capped_accumulator_test PRIVATE N3_CAPPED_ACCUMULATOR_TEST)
    target_link_libraries(n3_capped_accumulator_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_capped_accumulator_test)
    add_test(NAME capped_accumulator_equivalence COMMAND n3_capped_accumulator_test)
    add_executable(n3_chance_roll_test tests/chance_roll_test.cpp src/chance_roll_hooks.cpp)
    target_include_directories(n3_chance_roll_test PRIVATE src)
    target_compile_definitions(n3_chance_roll_test PRIVATE N3_CHANCE_ROLL_TEST)
    target_link_libraries(n3_chance_roll_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_chance_roll_test)
    add_test(NAME chance_roll_equivalence COMMAND n3_chance_roll_test)
    add_executable(n3_state_queries_test tests/state_queries_test.cpp src/state_queries_hooks.cpp)
    target_include_directories(n3_state_queries_test PRIVATE src)
    target_compile_definitions(n3_state_queries_test PRIVATE N3_STATE_QUERIES_TEST)
    target_link_libraries(n3_state_queries_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_state_queries_test)
    add_test(NAME state_queries_equivalence COMMAND n3_state_queries_test)
    add_executable(n3_handle_table_test tests/handle_table_test.cpp src/handle_table_hooks.cpp)
    target_include_directories(n3_handle_table_test PRIVATE src)
    target_compile_definitions(n3_handle_table_test PRIVATE N3_HANDLE_TABLE_TEST)
    target_link_libraries(n3_handle_table_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_handle_table_test)
    add_test(NAME handle_table_equivalence COMMAND n3_handle_table_test)
    add_executable(n3_state_payload_test tests/state_payload_test.cpp src/state_payload_hooks.cpp)
    target_include_directories(n3_state_payload_test PRIVATE src)
    target_compile_definitions(n3_state_payload_test PRIVATE N3_STATE_PAYLOAD_TEST)
    target_link_libraries(n3_state_payload_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_state_payload_test)
    add_test(NAME state_payload_equivalence COMMAND n3_state_payload_test)
    add_executable(n3_state_relation_test tests/state_relation_test.cpp src/state_relation_hooks.cpp
        src/handle_table_hooks.cpp src/state_payload_hooks.cpp)
    target_include_directories(n3_state_relation_test PRIVATE src)
    target_compile_definitions(n3_state_relation_test PRIVATE N3_STATE_RELATION_TEST)
    target_link_libraries(n3_state_relation_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_state_relation_test)
    add_test(NAME state_relation_equivalence COMMAND n3_state_relation_test)
    add_executable(n3_direction_normalization_test tests/direction_normalization_test.cpp src/direction_normalization_hooks.cpp)
    target_include_directories(n3_direction_normalization_test PRIVATE src)
    target_compile_definitions(n3_direction_normalization_test PRIVATE N3_DIRECTION_NORMALIZATION_TEST)
    target_link_libraries(n3_direction_normalization_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_direction_normalization_test)
    add_test(NAME direction_normalization_equivalence COMMAND n3_direction_normalization_test)
    add_executable(n3_direction_accumulation_test tests/direction_accumulation_test.cpp src/direction_accumulation_hooks.cpp)
    target_include_directories(n3_direction_accumulation_test PRIVATE src)
    target_compile_definitions(n3_direction_accumulation_test PRIVATE N3_DIRECTION_ACCUMULATION_TEST)
    target_link_libraries(n3_direction_accumulation_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_direction_accumulation_test)
    add_test(NAME direction_accumulation_equivalence COMMAND n3_direction_accumulation_test)
    add_executable(n3_direction_basis_test tests/direction_basis_test.cpp
        src/direction_basis_hooks.cpp src/direction_normalization_hooks.cpp)
    target_include_directories(n3_direction_basis_test PRIVATE src)
    target_compile_definitions(n3_direction_basis_test PRIVATE N3_DIRECTION_BASIS_TEST)
    target_link_libraries(n3_direction_basis_test PRIVATE n3_native n3_recomp rex::runtime)
    rexglue_apply_target_settings(n3_direction_basis_test)
    add_test(NAME direction_basis_equivalence COMMAND n3_direction_basis_test)
    add_executable(n3_profile_config_test tests/profile_config_test.cpp src/profile_config.cpp)
    target_include_directories(n3_profile_config_test PRIVATE src)
    target_link_libraries(n3_profile_config_test PRIVATE rex::runtime)
    add_test(NAME profile_config COMMAND n3_profile_config_test)
    add_executable(n3_graphics_policy_test tests/graphics_policy_test.cpp)
    target_include_directories(n3_graphics_policy_test PRIVATE src)
    add_test(NAME graphics_policy COMMAND n3_graphics_policy_test)
endif()
