cmake_minimum_required(VERSION 3.13)
project(marioparty4 LANGUAGES C CXX)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)

set(VERSION 0)

option(USE_ASAN "Enable address sanitization" OFF)
option(SKIP_HU_ALLOC "Skip the game's built in allocator" ON)

set(USE_ASAN OFF CACHE BOOL "Disable ASan" FORCE)
set(SKIP_HU_ALLOC OFF CACHE BOOL "Skip the built in allocator" FORCE)

# Set build type to Debug if not specified
if (NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Debug)
endif ()

set(CMAKE_INSTALL_RPATH "$ORIGIN")
set(CMAKE_BUILD_RPATH "$ORIGIN")
if (MSVC)
    add_compile_options(/bigobj)
endif ()

# Global ASAN option
# add_compile_options(-fsanitize=address)

add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
add_subdirectory(extern/musyx EXCLUDE_FROM_ALL)

include(extern/aurora/cmake/AuroraCopyRuntimeDLLs.cmake)

set(GAME_FILES
        src/game/board/audio.c
        src/game/board/basic_space.c
        src/game/board/battle.c
        src/game/board/block.c
        src/game/board/boo.c
        src/game/board/boo_house.c
        src/game/board/bowser.c
        src/game/board/char_wheel.c
        src/game/board/com.c
        src/game/board/com_path.c
        src/game/board/fortune.c
        src/game/board/item.c
        src/game/board/last5.c
        src/game/board/lottery.c
        src/game/board/main.c
        src/game/board/mg_setup.c
        src/game/board/model.c
        src/game/board/mushroom.c
        src/game/board/pause.c
        src/game/board/player.c
        src/game/board/roll.c
        src/game/board/shop.c
        src/game/board/space.c
        src/game/board/star.c
        src/game/board/start.c
        src/game/board/tutorial.c
        src/game/board/ui.c
        src/game/board/view.c
        src/game/board/warp.c
        src/game/board/window.c

        src/game/armem.c
        src/game/card.c
        src/game/chrman.c
        src/game/ClusterExec.c
        src/game/data.c
        src/game/decode.c
        src/game/dvd.c
        src/game/EnvelopeExec.c
        src/game/esprite.c
        src/game/fault.c
        src/game/flag.c
        src/game/font.c
        src/game/frand.c
        src/game/gamework.c
        src/game/hsfanim.c
        src/game/hsfdraw.c
        src/game/hsfex.c
        src/game/hsfload.c
        src/game/hsfman.c
        src/game/hsfmotion.c
        src/game/init.c
        src/game/main.c
        src/game/malloc.c
        src/game/mapspace.c
        src/game/memory.c
        src/game/messdata.c
        src/game/minigame_seq.c
        src/game/objdll.c
        src/game/objmain.c
        src/game/objsub.c
        src/game/objsysobj.c
        src/game/ovllist.c
        src/game/pad.c
        src/game/perf.c
        src/game/printfunc.c
        src/game/process.c
        src/game/saveload.c
        src/game/ShapeExec.c
        src/game/sprman.c
        src/game/sprput.c
        src/game/window.c
        src/game/wipe.c

        src/libhu/setvf.c
        src/libhu/subvf.c
)

set(PORT_FILES
        src/port/audio.c
        src/port/byteswap.cpp
        src/port/dvd.c
        src/port/imgui.cpp
        src/port/OS.c
        src/port/stubs.c
)

source_group("Dolphin" FILES ${DOLPHIN_FILES})
source_group("Game" FILES ${GAME_FILES})
source_group("Port" FILES ${PORT_FILES})

if (NOT MSVC)
    foreach (file ${DOLPHIN_FILES})
        set_source_files_properties(${file} PROPERTIES COMPILE_FLAGS "-Dinline=")
    endforeach ()
    foreach (file ${GAME_FILES})
        set_source_files_properties(${file} PROPERTIES COMPILE_FLAGS "-Dinline=")
    endforeach ()
endif ()

add_library(dol SHARED ${DOLPHIN_FILES} ${GAME_FILES} ${PORT_FILES} extern/libco/libco.c)
target_compile_definitions(dol PRIVATE TARGET_PC NON_MATCHING OPTIMIZED_TEXTURE_LOADING BYTESWAPPING TARGET_DOL VERSION=${VERSION} MUSY_VERSION_MAJOR=1 MUSY_VERSION_MINOR=5 MUSY_VERSION_PATCH=4)
target_include_directories(dol PRIVATE include extern/aurora/include extern/aurora/include/dolphin build/GMPE01_00/include extern/libco)
target_link_libraries(dol PRIVATE aurora::core aurora::card aurora::gx aurora::mtx aurora::os aurora::si aurora::vi aurora::pad musyx)
# TODO it doesn't work on Linux yet
if (CMAKE_SYSTEM_NAME STREQUAL Windows)
    if(USE_ASAN)
        target_compile_definitions(dol PRIVATE USE_ASAN)
        set_source_files_properties(${DOLPHIN_FILES} ${GAME_FILES} PROPERTIES COMPILE_OPTIONS "-fsanitize=address")
    endif()
    if(SKIP_HU_ALLOC)
        target_compile_definitions(dol PRIVATE SKIP_HU_ALLOC)
    endif()
endif()
if (MSVC)
    target_link_options(dol PRIVATE "/DEF:${CMAKE_SOURCE_DIR}/dol.def")
    # target_compile_options(dol PRIVATE "/WX")
    target_compile_options(dol PRIVATE "/wd4244") # implicit narrowing conversion
    target_compile_options(dol PRIVATE "/wd4101") # unreferenced local variable
    target_compile_options(dol PRIVATE "/wd4102") # unreferenced label
    target_compile_options(dol PRIVATE "/wd4305") # truncation
    target_compile_options(dol PRIVATE "/wd4018") # signed/unsigned mismatch
    target_compile_options(dol PRIVATE "/wd4996") # unsafe sprintf, etc
    target_compile_options(dol PRIVATE "/wd4146") # unary minus operator applied to unsigned type, result still unsigned
    target_compile_options(dol PRIVATE "/wd4552") # result of expression not used
    target_compile_options(dol PRIVATE "/wd4553") # result of expression not used: == vs =
    target_compile_options(dol PRIVATE "/wd4113") # function pointer parameter list mismatch
    target_compile_options(dol PRIVATE "/Zi")
    target_compile_options(dol PRIVATE "/Ob0")
    target_compile_options(dol PRIVATE "/Od")
    if(NOT USE_ASAN)
        # target_compile_options(dol PRIVATE "/GS")
        # target_compile_options(dol PRIVATE "/RTC1")  # incompatible with asan
    endif()
else ()
    # target_compile_options(dol PRIVATE "-fvisibility=hidden")
    # target_link_options(dol PRIVATE "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/dol.map")
endif ()

add_executable(marioparty4 src/port/portmain.c)
target_compile_definitions(marioparty4 PRIVATE TARGET_PC NON_MATCHING VERSION=${VERSION})
target_include_directories(marioparty4 PRIVATE include)
target_link_libraries(marioparty4 PRIVATE dol aurora::main)
aurora_copy_runtime_dlls(marioparty4)

file(GLOB REL_DIRS RELATIVE ${CMAKE_SOURCE_DIR}/src/REL ${CMAKE_SOURCE_DIR}/src/REL/*)
set(EXCLUDED_RELS "nisDll" "safDll")

foreach (dir ${REL_DIRS})
    if (IS_DIRECTORY ${CMAKE_SOURCE_DIR}/src/REL/${dir})
        if (dir IN_LIST EXCLUDED_RELS)
            continue()
        endif()
        file(GLOB_RECURSE REL_FILES src/REL/${dir}/*.c)

        if (REL_FILES)
            add_library(${dir} SHARED ${REL_FILES})
            if (USE_ASAN)
               set_source_files_properties(${REL_FILES} PROPERTIES COMPILE_OPTIONS "-fsanitize=address")
               target_compile_definitions(${dir} PRIVATE USE_ASAN)
            endif()
            if (dir MATCHES "^w..Dll")
                target_sources(${dir} PRIVATE src/REL/board_executor.c)
            endif()
            target_compile_definitions(${dir} PRIVATE TARGET_PC OPTIMIZED_TEXTURE_LOADING BYTESWAPPING NON_MATCHING VERSION=${VERSION})
            target_include_directories(${dir} PRIVATE include extern/aurora/include extern/aurora/include/dolphin build/GMPE01_00/include extern/libco)
            if (MSVC)
                set_target_properties(${dir} PROPERTIES LINK_FLAGS "/EXPORT:ObjectSetup")
#                target_compile_options(${dir} PRIVATE "/WX")
                target_compile_options(${dir} PRIVATE "/wd4244") # implicit narrowing conversion
                target_compile_options(${dir} PRIVATE "/wd4101") # unreferenced local variable
                target_compile_options(${dir} PRIVATE "/wd4102") # unreferenced label
                target_compile_options(${dir} PRIVATE "/wd4305") # truncation
                target_compile_options(${dir} PRIVATE "/wd4018") # signed/unsigned mismatch
                target_compile_options(${dir} PRIVATE "/wd4996") # unsafe sprintf, etc
                target_compile_options(${dir} PRIVATE "/wd4146") # unary minus operator applied to unsigned type, result still unsigned
                target_compile_options(${dir} PRIVATE "/wd4552") # result of expression not used
                target_compile_options(${dir} PRIVATE "/wd4553") # result of expression not used: == vs =
                target_compile_options(${dir} PRIVATE "/wd4113") # function pointer parameter list mismatch
                target_compile_options(${dir} PRIVATE "/Zi")
                target_compile_options(${dir} PRIVATE "/Ob0")
                target_compile_options(${dir} PRIVATE "/Od")
                if(NOT USE_ASAN)
#                    target_compile_options(${dir} PRIVATE "/GS")
#                    target_compile_options(${dir} PRIVATE "/RTC1")  # incompatible with asan
                endif()
            elseif (NOT CMAKE_SYSTEM_NAME STREQUAL Windows)
                # target_compile_options(${dir} PRIVATE "-fvisibility=hidden")
                target_link_options(${dir} PRIVATE "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/rel.map")
                set_target_properties(${dir} PROPERTIES PREFIX "")
            endif ()
            target_link_libraries(${dir} PRIVATE dol musyx)
            add_dependencies(marioparty4 ${dir})
        endif ()
    endif ()
endforeach ()
