# Need for Speed: Most Wanted (original Xbox), statically recompiled, as an Android library: libmain.so, loaded by SDL's
# activity; or on Linux as an executable, mostwanted. The x86 code is recompiled first (build.bat, build.sh): this build
# takes generated/game as it is, with the SDK's portable runtime, the game's sources in src and the host in native
# (Android's, main_linux.cpp in place of main.cpp on Linux).

cmake_minimum_required(VERSION 3.22)
project(mostwanted_android LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(REPO ${CMAKE_CURRENT_SOURCE_DIR})
set(NATIVE ${CMAKE_CURRENT_SOURCE_DIR}/native)
set(GAME ${CMAKE_CURRENT_SOURCE_DIR}/src)  # the game's hooks, sound, Direct3D 8 and settings

# the SDK: sdk/ in the repo, a checkout beside it, else downloaded
include(FetchContent)
if(EXISTS ${REPO}/sdk/cmake/XbeRecomp.cmake)
    set(SDK ${REPO}/sdk)
elseif(EXISTS ${REPO}/../XboxXBE-Recomp/cmake/XbeRecomp.cmake)
    get_filename_component(SDK ${REPO}/../XboxXBE-Recomp ABSOLUTE)
else()
    FetchContent_Declare(xbe_sdk GIT_REPOSITORY https://github.com/TGP482/XboxXBE-Recomp.git GIT_TAG main)
    FetchContent_MakeAvailable(xbe_sdk)
    set(SDK ${xbe_sdk_SOURCE_DIR})
endif()

# the recompiled code and the xbe it came from
set(XBE_GENERATED ${REPO}/generated/game CACHE PATH "the recompiled code of default.xbe")
set(XBE_IMAGE ${REPO}/assets/default.xbe CACHE FILEPATH "the xbe it was recompiled from")
set(GEN ${XBE_GENERATED})
set(XBE ${XBE_IMAGE})
if(NOT EXISTS ${GEN}/x86_func_mapping.cpp OR NOT EXISTS ${XBE})
    message(FATAL_ERROR "No recompiled code: put the game in assets/ or iso/ and run build.bat (build.sh on Linux), it writes generated/game")
endif()
file(STRINGS ${REPO}/config/game.toml GAME_PARTITIONS REGEX "^partitions *=")
string(REGEX MATCH "[0-9]+" GAME_PARTITIONS "${GAME_PARTITIONS}")
math(EXPR last "${GAME_PARTITIONS} - 1")
set(GEN_SOURCES ${GEN}/x86_func_mapping.cpp)
foreach(i RANGE ${last})
    list(APPEND GEN_SOURCES ${GEN}/x86_recomp.${i}.cpp)
endforeach()
file(SHA1 ${XBE} xbe_sha1)
file(CONFIGURE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/image_sha1.cpp CONTENT "extern const char kImageSha1[] = \"${xbe_sha1}\";\n")
# the build's version for the log: the commit when the project is in git, else unknown
set(BUILD_COMMIT "unknown")
find_package(Git QUIET)
if(GIT_EXECUTABLE)
    execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD WORKING_DIRECTORY ${REPO}
                    OUTPUT_VARIABLE head OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET RESULT_VARIABLE failed)
    if(NOT failed AND head)
        set(BUILD_COMMIT ${head})
    endif()
endif()
file(CONFIGURE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/build_info.h CONTENT "#define BUILD_COMMIT \"${BUILD_COMMIT}\"\n")

# dependencies: on Android SDL3 from the checkout Gradle makes (its Java side goes into the APK); on Linux the system's
# SDL3 when it has one, else fetched and linked in; the rest fetched
set(SDL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/SDL)
if(NOT ANDROID)
    find_package(SDL3 3.2 CONFIG QUIET COMPONENTS SDL3-shared)
    if(SDL3_FOUND)
        message(STATUS "SDL3 ${SDL3_VERSION} from the system")
    elseif(NOT EXISTS ${SDL_DIR}/CMakeLists.txt)
        FetchContent_Declare(SDL3 GIT_REPOSITORY https://github.com/libsdl-org/SDL.git GIT_TAG release-3.4.16 GIT_SHALLOW TRUE)
        FetchContent_GetProperties(SDL3)
        if(NOT sdl3_POPULATED)
            FetchContent_Populate(SDL3)
        endif()
        set(SDL_DIR ${sdl3_SOURCE_DIR})
    endif()
endif()
if(NOT TARGET SDL3::SDL3)
    if(NOT EXISTS ${SDL_DIR}/CMakeLists.txt)
        message(FATAL_ERROR "SDL3 is missing from ${SDL_DIR}: the Gradle build clones it")
    endif()
    set(SDL_SHARED ${ANDROID} CACHE BOOL "" FORCE)
    if(ANDROID)
        set(SDL_STATIC OFF CACHE BOOL "" FORCE)
    else()
        set(SDL_STATIC ON CACHE BOOL "" FORCE)
    endif()
    set(SDL_TEST_LIBRARY OFF CACHE BOOL "" FORCE)
    set(SDL_RENDER OFF CACHE BOOL "" FORCE)
    set(SDL_GPU OFF CACHE BOOL "" FORCE)
    set(SDL_CAMERA OFF CACHE BOOL "" FORCE)
    add_subdirectory(${SDL_DIR} ${CMAKE_CURRENT_BINARY_DIR}/SDL EXCLUDE_FROM_ALL)
endif()

set(ENABLE_OPT OFF CACHE BOOL "" FORCE)
set(ENABLE_HLSL ON CACHE BOOL "" FORCE)
set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "" FORCE)
set(ENABLE_SPVREMAPPER OFF CACHE BOOL "" FORCE)
set(GLSLANG_TESTS OFF CACHE BOOL "" FORCE)
set(GLSLANG_ENABLE_INSTALL OFF CACHE BOOL "" FORCE)
set(BUILD_EXTERNAL OFF CACHE BOOL "" FORCE)
FetchContent_Declare(glslang GIT_REPOSITORY https://github.com/KhronosGroup/glslang.git GIT_TAG 16.0.0 GIT_SHALLOW TRUE)
FetchContent_Declare(tomlplusplus GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git GIT_TAG v3.4.0 GIT_SHALLOW TRUE)
FetchContent_Declare(imgui GIT_REPOSITORY https://github.com/ocornut/imgui.git GIT_TAG v1.91.0 GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(glslang tomlplusplus imgui)

# the SDK's runtime but its Windows parts, and those the game replaces (src/sound, src/d3d)
file(GLOB RUNTIME_SOURCES ${SDK}/runtime/*/*.cpp)
list(FILTER RUNTIME_SOURCES EXCLUDE REGEX
     "/runtime/app/|/core/input\\.cpp$|/gpu/(d3d12|render_thread)\\.cpp$|/audio/xaudio2\\.cpp$|/xdk/(dsound|d3d8)\\.cpp$")
# the game's sources: its hooks, sound, Direct3D 8 and settings
file(GLOB GAME_HOST_SOURCES CONFIGURE_DEPENDS ${GAME}/*/*.cpp)
file(GLOB HOST_PLATFORM_SOURCES CONFIGURE_DEPENDS ${NATIVE}/*.cpp)
# main.cpp is Android's, main_linux.cpp a PC's: the rest of native/ is shared
if(ANDROID)
    list(FILTER HOST_PLATFORM_SOURCES EXCLUDE REGEX "_linux\\.cpp$")
else()
    list(FILTER HOST_PLATFORM_SOURCES EXCLUDE REGEX "/native/main\\.cpp$")
endif()
set(IMGUI_SOURCES ${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}/backends/imgui_impl_vulkan.cpp)

set(ALL_SOURCES ${RUNTIME_SOURCES} ${GAME_HOST_SOURCES} ${HOST_PLATFORM_SOURCES} ${GEN_SOURCES} ${IMGUI_SOURCES}
    ${CMAKE_CURRENT_BINARY_DIR}/image_sha1.cpp)
if(ANDROID)
    add_library(main SHARED ${ALL_SOURCES})
else()
    add_executable(main ${ALL_SOURCES})
    set_target_properties(main PROPERTIES OUTPUT_NAME mostwanted)
endif()
# compat/ for the SDK's x86 header on ARM (an x86 host has its own), the SDK harness's for the Winsock and DXGI names
# its portable runtime uses
if(ANDROID OR NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64")
    target_include_directories(main PRIVATE ${NATIVE}/compat)
endif()
target_include_directories(main PRIVATE ${SDK}/harness/compat ${NATIVE} ${GAME} ${SDK}/runtime ${GEN}
                           ${CMAKE_CURRENT_BINARY_DIR} ${glslang_SOURCE_DIR})
target_include_directories(main SYSTEM PRIVATE ${imgui_SOURCE_DIR})
# x86 chars are signed, as the game's code and the runtime were written for
target_compile_options(main PRIVATE -fno-strict-aliasing -fsigned-char)
set(HOST_SOURCES ${RUNTIME_SOURCES} ${GAME_HOST_SOURCES} ${HOST_PLATFORM_SOURCES})
set_source_files_properties(${HOST_SOURCES} PROPERTIES COMPILE_OPTIONS "-include;${NATIVE}/compat/crt.h")
set_source_files_properties(${GEN_SOURCES} PROPERTIES
    COMPILE_OPTIONS "-O2;-w;-fno-strict-aliasing;-fsigned-char")
set_source_files_properties(${NATIVE}/vk_shader.cpp PROPERTIES COMPILE_DEFINITIONS ENABLE_HLSL)
target_link_libraries(main PRIVATE SDL3::SDL3 tomlplusplus::tomlplusplus glslang glslang-default-resource-limits)
if(ANDROID)
    target_link_libraries(main PRIVATE vulkan android log mediandk z)
else()
    find_package(Vulkan REQUIRED)
    find_package(Threads REQUIRED)
    target_link_libraries(main PRIVATE Vulkan::Vulkan Threads::Threads ${CMAKE_DL_LIBS})
    # cinematic mode's photos deflated; without zlib they are written uncompressed (native/video.cpp)
    find_package(ZLIB)
    if(ZLIB_FOUND)
        target_link_libraries(main PRIVATE ZLIB::ZLIB)
        target_compile_definitions(main PRIVATE HAVE_ZLIB)
    endif()
endif()
# -PverboseLog: the info lines in the log of a release build too
option(XBE_VERBOSE_LOG "log info lines in a release build" OFF)
if(XBE_VERBOSE_LOG)
    target_compile_definitions(main PRIVATE XBE_VERBOSE_LOG)
endif()
if(ANDROID)
    # 16 KB pages, as Android 15 devices may have
    target_link_options(main PRIVATE -Wl,-z,max-page-size=16384)
endif()
