# MSVC build of the SDL2 port, the base for the DirectX 12 renderer.
# Mirrors the Makefile's `modern` target; source lists must stay in step with it.
cmake_minimum_required(VERSION 3.21)
project(wc1_rtx C CXX)

set(WC1_DEPS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../deps" CACHE PATH "Third-party packages")
set(WC1_SDL2_DIR "${WC1_DEPS_DIR}/SDL2-2.32.10" CACHE PATH "SDL2 Visual C++ development package")
set(WC1_MINILZO_DIR "${WC1_DEPS_DIR}/minilzo-2.10" CACHE PATH "minilzo source")
set(WC1_GAME_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../game-data/WC1" CACHE PATH "Kilrathi Saga WC1 directory (GAMEDAT, STREAMS)")
option(WC1_DEBUG_OUTPUT "Print the game's SystemDebugPrintf messages to stderr" ON)

list(APPEND CMAKE_PREFIX_PATH "${WC1_SDL2_DIR}/cmake")
find_package(SDL2 REQUIRED CONFIG)

set(GAMEPLAY_SRCS
    src/fl.c src/cutscene.c src/mission.c src/auto.c src/barracks.c
    src/brains.c src/winsys.c src/eject.c src/cmpgn.c src/cockpt.c
    src/comm.c src/damage.c src/view.c src/dib.c src/disk.c src/ending.c
    src/eventmgr.c src/fade.c src/geom.c src/gr.c src/globals.c src/init.c
    src/input.c src/joycal.c src/launch.c src/install.c src/joystick.c
    src/killbrd.c src/logic.c src/main.c src/targ.c src/select.c
    src/timer.c src/mathfp.c src/mathutil.c src/mono.c src/music.c
    src/nav.c src/nearheap.c src/objdata.c src/gameflow.c src/title.c
    src/pload.c src/screen.c src/screens.c src/ship.c src/smart.c
    src/data.c src/spc.c src/strdos.c src/trainsim.c src/game.c
    src/version.c src/video.c src/winmain.c)
set(GAMEPLAY_CXX_SRCS src/debug.cpp src/pilot.cpp)
# Compiled as C++ like the Makefile's `-x c++` rule.
set(GAMEPLAY_CXX_C_SRCS src/sound.c)
set(IX_SRCS
    src/ix/ixlog.cpp src/ix/streamer.cpp src/ix/thread.cpp
    src/ix/streamfile.cpp src/ix/dsp.cpp src/ix/dsps.cpp src/ix/mixer.cpp
    src/ix/dspv.cpp src/ix/system.cpp src/ix/sound.cpp src/ix/sample.cpp
    src/ix/lzo1x.cpp src/ix/ixfile.cpp)
set(BASE_HOST_SRCS
    src/sdl/compat.c src/sdl/input.c src/sdl/resources.c
    src/sdl/swc_mission.c src/swc/cmf.c src/sdl/registry.c src/sdl/thread.c
    src/sdl/timer.c src/sdl/video_state.c)
set(GAME_HOST_SRCS
    src/sdl/swc_flight.c src/sdl/swc_raster.c src/sdl/swc_cockpit.c
    src/sdl/swc_nav.c src/sdl/swc_sound.c src/sdl/swc_music.c
    src/sdl/swc_text.c src/sdl/swc_rooms.c src/sdl/swc_movie.c
    src/swc/speech.c src/swc/sound.c src/swc/movie.c src/swc/music.c
    src/swc/shape.c src/swc/rsrc.c src/sdl/audio.c src/sdl/dos_intro.c
    src/sdl/events.c src/sdl/gl_renderer.c src/sdl/joystick.c
    src/sdl/music.c src/sdl/video.c)
set(GAME_HOST_CXX_SRCS src/sdl/originfx.cpp src/sdl/wave.cpp)
set(YMFM_SRCS
    third_party/ymfm/ymfm_adpcm.cpp third_party/ymfm/ymfm_opl.cpp
    third_party/ymfm/ymfm_pcm.cpp)
set(LAUNCHER_SRC src/sdl/launcher.c)
set(RTX_SRCS rtx/src/frame_dump.c rtx/src/hang_watchdog.c rtx/src/auto_input.c
    rtx/src/mf_video.cpp rtx/src/cutscene_video.c rtx/src/d3d12_renderer.cpp
    rtx/src/space_scene.c rtx/src/script_dump.c rtx/src/room_video.c
    rtx/src/voiced_talk.c rtx/src/cockpit_plate.c rtx/src/input_bindings.c
    rtx/src/controls_menu.c rtx/src/hud_text.c rtx/src/scene_films.c
    rtx/src/medal_case.c rtx/src/recorder.c rtx/src/songs.cpp rtx/src/audio_lock.cpp rtx/launcher/icon.rc)

# HLSL → DXIL headers with the Windows SDK's dxc (Shader Model 6, signed by
# dxil.dll beside it).  vcvars puts the SDK's bin directory on PATH.
find_program(WC1_DXC dxc HINTS "$ENV{WindowsSdkVerBinPath}/x64" REQUIRED)
set(WC1_SHADER_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders")
file(MAKE_DIRECTORY "${WC1_SHADER_DIR}")
set(WC1_SHADER_HEADERS)
foreach(shader IN ITEMS quad mesh billboard sky post nebula nebula_up backdrop hudtext explosion)
    foreach(stage IN ITEMS vs ps)
        string(TOUPPER "${stage}" STAGE)
        set(source "${CMAKE_CURRENT_SOURCE_DIR}/rtx/shaders/${shader}.hlsl")
        set(header "${WC1_SHADER_DIR}/${shader}_${stage}.h")
        add_custom_command(OUTPUT "${header}"
            COMMAND "${WC1_DXC}" -nologo -T ${stage}_6_0 -E ${STAGE}Main -O3
                    -Fh "${header}" -Vn g_${shader}_${stage} "${source}"
            DEPENDS "${source}" "${CMAKE_CURRENT_SOURCE_DIR}/rtx/shaders/nebula_field.hlsli"
            COMMENT "dxc ${shader}.hlsl (${stage})")
        list(APPEND WC1_SHADER_HEADERS "${header}")
    endforeach()
endforeach()
set(WC1_CUTSCENE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../cutscenes" CACHE PATH "Rendered cutscene videos (<name>.mp4)")
set(WC1_MODEL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../models" CACHE PATH "Converted ship models (typeNN.wcm, rtx/tools/convert_models.py)")
set(WC1_MUSIC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../music" CACHE PATH "Fernando's songs in place of the game's music (rtx/src/songs.h)")
set(WC1_BUILD_LABEL "alpha" CACHE STRING "The build's name in the window title")

add_executable(wc1-rtx
    ${LAUNCHER_SRC} ${BASE_HOST_SRCS} ${GAME_HOST_SRCS} ${GAME_HOST_CXX_SRCS}
    ${YMFM_SRCS} ${GAMEPLAY_SRCS} ${GAMEPLAY_CXX_SRCS} ${GAMEPLAY_CXX_C_SRCS}
    ${IX_SRCS} "${WC1_MINILZO_DIR}/minilzo.c" ${RTX_SRCS} ${WC1_SHADER_HEADERS})

set_source_files_properties(${GAMEPLAY_CXX_C_SRCS} PROPERTIES
    LANGUAGE CXX
    COMPILE_DEFINITIONS "ix_system_new_sound=SdlNewWaveSound")
set_source_files_properties(${IX_SRCS} ${GAMEPLAY_CXX_SRCS} ${GAMEPLAY_CXX_C_SRCS}
    PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/src/ix")
set_source_files_properties(src/sdl/originfx.cpp ${YMFM_SRCS}
    PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/third_party/ymfm")

target_include_directories(wc1-rtx PRIVATE
    include rtx/src rtx/lzo-shim "${WC1_MINILZO_DIR}" "${WC1_SHADER_DIR}")
target_compile_definitions(wc1-rtx PRIVATE
    SDL_PORT=1 SDL_MAIN_HANDLED _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_WARNINGS
    PATH_MAX=4096
    "WC1_RTX_CUTSCENE_DIR=\"${WC1_CUTSCENE_DIR}\""
    "WC1_RTX_MODEL_DIR=\"${WC1_MODEL_DIR}\""
    "WC1_RTX_MUSIC_DIR=\"${WC1_MUSIC_DIR}\""
    "WC1_RTX_BUILD_LABEL=\"${WC1_BUILD_LABEL}\""
    $<$<BOOL:${WC1_DEBUG_OUTPUT}>:SDL_PORT_LEGACY_DEBUG_OUTPUT>)
set_target_properties(wc1-rtx PROPERTIES
    C_STANDARD 11 CXX_STANDARD 14
    VS_DEBUGGER_WORKING_DIRECTORY "${WC1_GAME_DIR}")

# The port's headers use GCC attributes (packed structs), so cl.exe cannot
# build it; clang-cl can.
if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
    message(FATAL_ERROR "Build with clang-cl (rtx/build.cmd does).")
endif()
# The Makefile's -Wno-return-type and -Wno-error=incompatible-pointer-types.
target_compile_options(wc1-rtx PRIVATE
    $<$<COMPILE_LANGUAGE:C>:-Wno-return-type -Wno-incompatible-pointer-types
        -Wno-error=incompatible-pointer-types -Wno-int-conversion>
    -Wno-microsoft-enum-forward-reference -Wno-deprecated-declarations /utf-8)

target_link_libraries(wc1-rtx PRIVATE SDL2::SDL2 imm32 dbghelp
    mfplat mfreadwrite mfuuid ole32 d3d12 dxgi dxguid windowscodecs gdi32)
# A windowed program, so no console opens beside the game; main() stays the
# entry, and attaches to the console it was started from, if any
# (src/sdl/launcher.c).
if(WIN32)
    target_link_options(wc1-rtx PRIVATE /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup)
endif()

add_custom_command(TARGET wc1-rtx POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        $<TARGET_FILE:SDL2::SDL2> $<TARGET_FILE_DIR:wc1-rtx>
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        "${CMAKE_CURRENT_SOURCE_DIR}/third_party/generaluser/GeneralUser-GS.sf2"
        "$<TARGET_FILE_DIR:wc1-rtx>/swc-music.sf2")
