cmake_minimum_required(VERSION 3.20)
project(doa2u_game C)

# Dead or Alive 2 Ultimate - recompiled game executable

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

# Generated by: py -3 -m tools.recomp.regen ..\doa2ugamefiles\DOA2.xbe
file(GLOB RECOMP_GEN_SOURCES
    "${CMAKE_CURRENT_SOURCE_DIR}/recomp/gen/recomp_*.c"
)

# NV2A GPU register emulation + PGRAPH -> D3D11 translator
set(NV2A_DIR "${CMAKE_SOURCE_DIR}/src/nv2a")
set(NV2A_SOURCES
    ${NV2A_DIR}/nv2a_core.c
    ${NV2A_DIR}/nv2a_mmio_hook.c
    ${NV2A_DIR}/nv2a_pb_test.c
    ${NV2A_DIR}/nv2a_pgraph_d3d11.c
    ${NV2A_DIR}/nv2a_vertex_program.c
)

set(GAME_SOURCES
    main.c
    movie_present.c
    xiso_extract.c           # first-run install of the game files from a disc image
    ${CMAKE_SOURCE_DIR}/src/ui/video_settings.c
    ${CMAKE_SOURCE_DIR}/src/ui/log_settings.c
    ${CMAKE_SOURCE_DIR}/src/ui/log_rotate.c
    ${CMAKE_SOURCE_DIR}/src/ui/profile_settings.c
    ${CMAKE_SOURCE_DIR}/src/ui/extras.c
    recomp/recomp_manual.c
    burnout_compat_stubs.c   # inert stubs for burnout-only symbols the nv2a srcs need
    assets/doa2u.rc
    ${NV2A_SOURCES}
    ${RECOMP_GEN_SOURCES}
)

# Deterministic math (third_party/detmath, musl via MK-3D-rollback, MIT): the game code's
# sin/cos/tan/atan2/log/pow give the same bits on every PC, which lockstep online play needs.
set(DETMATH_DIR ${CMAKE_SOURCE_DIR}/third_party/detmath)
file(GLOB DETMATH_SOURCES ${DETMATH_DIR}/*.c)
add_library(detmath STATIC ${DETMATH_SOURCES})
target_include_directories(detmath PUBLIC ${DETMATH_DIR})
if(MSVC)
    target_compile_options(detmath PRIVATE /FI${DETMATH_DIR}/features.h /W0 /fp:precise)
    set_property(TARGET detmath PROPERTY MSVC_RUNTIME_CHECKS "")
endif()
set(DETMATH_REDIRECT ${CMAKE_CURRENT_SOURCE_DIR}/detmath_redirect.h)
set_source_files_properties(${RECOMP_GEN_SOURCES} recomp/recomp_manual.c
    PROPERTIES COMPILE_OPTIONS "/FI${DETMATH_REDIRECT}")

add_executable(doa2u ${GAME_SOURCES})

target_link_libraries(doa2u PRIVATE
    detmath
    xbox_kernel
    d3d8_compat
    dsound_compat
    input_compat
    apu_emu
    doa2u_ui
    doa2u_online
    kernel32
    user32
    gdi32
    d3d11
    dxgi
)

target_include_directories(doa2u PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${CMAKE_CURRENT_SOURCE_DIR}/recomp
    ${CMAKE_CURRENT_SOURCE_DIR}/recomp/gen
    ${CMAKE_SOURCE_DIR}/src
    ${CMAKE_SOURCE_DIR}/third_party
    ${NV2A_DIR}
)

if(MSVC)
    target_compile_options(doa2u PRIVATE
        /W3
        /WX-
        $<$<CONFIG:Debug>:/O2>
        $<$<CONFIG:Debug>:/Ob2>
        $<$<NOT:$<CONFIG:Debug>>:/O2>
    )
    set_property(TARGET doa2u PROPERTY MSVC_RUNTIME_CHECKS "")
    set_source_files_properties(${RECOMP_GEN_SOURCES} recomp/recomp_manual.c
        PROPERTIES COMPILE_FLAGS "/w /bigobj")
    set_source_files_properties(${NV2A_SOURCES} PROPERTIES COMPILE_FLAGS "/w")
    target_compile_definitions(doa2u PRIVATE _CRT_SECURE_NO_WARNINGS)
    # Fixed image base (Xbox memory is mapped at fixed addresses); each guest
    # call/ret is a native call/return, so the stack is large.
    target_link_options(doa2u PRIVATE
        /DYNAMICBASE:NO
        /FIXED:NO
        $<$<CONFIG:Debug>:/MAP>
        $<$<CONFIG:Debug>:/DEBUG>
        $<$<CONFIG:Release>:/SUBSYSTEM:WINDOWS>
        $<$<CONFIG:Release>:/ENTRY:mainCRTStartup>
        /STACK:33554432
        /LARGEADDRESSAWARE
    )
endif()

set_target_properties(doa2u PROPERTIES
    OUTPUT_NAME "DOA2U"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
    RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/debug"
    RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/release"
    PDB_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/debug"
)

# Host-only tests: plain executables built with everything, exit code =
# failures; tests/run_host_tests.sh runs every *_test.exe. Tools such as
# netplay_memdiff sit beside them and are not run.
function(doa2u_host_test name)
    add_executable(${name} ${ARGN})
    target_include_directories(${name} PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests)
    set_target_properties(${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tests")
    if(MSVC)
        target_compile_options(${name} PRIVATE /W3 /WX-)
        target_compile_definitions(${name} PRIVATE _CRT_SECURE_NO_WARNINGS)
    endif()
endfunction()

set(ONLINE_DIR ${CMAKE_SOURCE_DIR}/src/online)
doa2u_host_test(netplay_format_test ${ONLINE_DIR}/netplay_format.c ${CMAKE_SOURCE_DIR}/tests/netplay_format_test.c)
doa2u_host_test(online_settings_test ${ONLINE_DIR}/online_settings.c ${CMAKE_SOURCE_DIR}/tests/online_settings_test.c)
doa2u_host_test(netplay_dump_test ${ONLINE_DIR}/netplay_dump.c ${CMAKE_SOURCE_DIR}/tests/netplay_dump_test.c)
doa2u_host_test(netplay_memdiff ${ONLINE_DIR}/netplay_dump.c ${CMAKE_SOURCE_DIR}/tests/netplay_memdiff.c)
doa2u_host_test(join_code_test ${ONLINE_DIR}/join_code.c ${CMAKE_SOURCE_DIR}/tests/join_code_test.c)
doa2u_host_test(netplay_files_test ${ONLINE_DIR}/netplay_files.c ${CMAKE_SOURCE_DIR}/tests/netplay_files_test.c)
doa2u_host_test(approx_test ${CMAKE_SOURCE_DIR}/tests/approx_test.c)
doa2u_host_test(detmath_test ${CMAKE_SOURCE_DIR}/tests/detmath_test.c)
target_link_libraries(detmath_test PRIVATE detmath)
target_compile_options(detmath_test PRIVATE /FI${DETMATH_REDIRECT})   # compiled like the game code
doa2u_host_test(detmath_pin_gen ${CMAKE_SOURCE_DIR}/tests/detmath_pin_gen.c)   # not a _test: prints the pins
target_link_libraries(detmath_pin_gen PRIVATE detmath)
doa2u_host_test(log_rotate_test ${CMAKE_SOURCE_DIR}/src/ui/log_rotate.c ${CMAKE_SOURCE_DIR}/tests/log_rotate_test.c)
doa2u_host_test(netplay_handoff_test ${ONLINE_DIR}/netplay_handoff.c ${CMAKE_SOURCE_DIR}/tests/netplay_handoff_test.c)
doa2u_host_test(netplay_session_test ${ONLINE_DIR}/netplay_session.c ${ONLINE_DIR}/netplay_format.c
                ${ONLINE_DIR}/online_settings.c ${CMAKE_SOURCE_DIR}/tests/netplay_session_test.c
                ${CMAKE_SOURCE_DIR}/tests/fake_game.c ${CMAKE_SOURCE_DIR}/tests/netplay_stubs.c)
target_include_directories(netplay_session_test PRIVATE ${CMAKE_BINARY_DIR}/src/online/generated)   # np_build_id.h
add_dependencies(netplay_session_test np_build_id)
doa2u_host_test(netplay_sweep_test ${ONLINE_DIR}/netplay_sweep.c ${CMAKE_SOURCE_DIR}/tests/netplay_sweep_test.c)
doa2u_host_test(release_channel_test ${ONLINE_DIR}/release_channel.c ${CMAKE_SOURCE_DIR}/tests/release_channel_test.c)
