cmake_minimum_required(VERSION 3.16)
project(raverace C)

if(NOT CMAKE_C_COMPILER_ID STREQUAL "GNU")
  message(FATAL_ERROR "gcc required (the lifted code uses computed labels and statement expressions)")
endif()
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_EXTENSIONS ON)
add_compile_options(-fno-strict-aliasing -fwrapv)

# PORTABLE (default ON): pin glibc symbol versions so a binary built here runs on
# older systems -- the Steam Deck included. See include/glibc_compat.h.
option(PORTABLE "Bind glibc symbols to baseline versions (runs on glibc >= 2.34)" ON)
if(PORTABLE AND NOT WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
  add_compile_options(-include ${CMAKE_CURRENT_SOURCE_DIR}/include/glibc_compat.h)
endif()

include_directories(include gen)

# THE SHARED ENGINE (../engine): the same renderer, texture bake, C352 and
# sound-MCU peripheral model Prop Cycle uses (HARD RULE 3 in ../CLAUDE.md).
include(${CMAKE_CURRENT_SOURCE_DIR}/../engine/engine.cmake)

# The sound program, translated to C from the ROM files (tools/gen/snd_translate.py).
# Input: tools/gen/snd.cov -- the (address, M/X, length) of every instruction the
# test oracle executed (addresses only, no ROM data; committed). Regenerate it with
#   RR_SNDCOV=f ./build/rr_sndoracle extracted ... (merge runs, sort -u)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/gen/snd_driver.c
  COMMAND ${Python3_EXECUTABLE} tools/gen/snd_translate.py tools/gen/snd.cov
  DEPENDS tools/gen/snd_translate.py tools/gen/m7700_decode.py tools/gen/snd_rom.py tools/gen/c74_bios.cov ../tools/gen/snd_spin.inc ../tools/gen/snd_dispatch.py ../tools/gen/snd_indirect.py ../tools/gen/snd_exits.py tools/gen/snd.cov
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  COMMENT "Translating the C74 sound program to C")

# The MASTER DSP program (the C71 BIOS + the block the 68K uploads), translated
# to C from the ROM files by the shared tool ../tools/gen/c25_translate.py.
# tools/gen/c25.cov: the addresses the interpreter oracle executed (addresses
# only, no ROM data; committed). The game has no C25 fetch/decode loop.
add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/gen/rr_c25.c
  COMMAND ${Python3_EXECUTABLE} ../tools/gen/c25_translate.py --game rr --roms extracted
          --cov tools/gen/c25.cov --out gen/rr_c25.c --func rr_c25_exec
          # the game's program (FUN_000318BE) and the test-mode ones (FUN_00006DA2's calls)
          --block 31A68 --block 6DE6 --block 6E46 --block 6F3E --block 707E --block 72FE --block 75EE --block 764C
  DEPENDS ../tools/gen/c25_translate.py tools/gen/c25.cov ../engine/c25/c71_bios.inc
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  COMMENT "Translating the master DSP program to C")
set_source_files_properties(gen/rr_c25.c PROPERTIES COMPILE_OPTIONS "-O2;-w")

# gen/rr_lifted.c is GENERATED by tools/gen/lift.py -- 8 MB of goto-heavy C;
# -O1 keeps the build to a minute and is plenty fast for a 25 MHz 68020.
set_source_files_properties(gen/rr_lifted.c PROPERTIES COMPILE_OPTIONS "-O1;-w")

# Readable-C replacements (Phase B): every file in src/rd/ registers itself.
file(GLOB RD_SRC CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/rd/*.c)

find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
if(WIN32)
  set(ZLIB_USE_STATIC_LIBS ON)   # MSYS2's zlib comes as a DLL too: link the static one, or the .exe needs zlib1.dll (CMake 3.24+)
endif()
find_package(ZLIB REQUIRED)
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL REQUIRED)
# Windows (MinGW-w64, ./build-windows.sh at the top of the tree): the few POSIX calls
# mapped in include/win_compat.h, no console window, and everything linked in --
# SDL2 statically too -- so RaveRacer.exe needs no DLL beside it. (Every DLL it
# imports ships with Windows. OpenGL is NOT linked: the shared engine's
# engine/gl_dyn.c resolves it at run time, so the bundled Mesa can stand in
# when Windows has no real driver -- exactly as Prop Cycle.)
if(WIN32)
  add_compile_options(-include ${CMAKE_CURRENT_SOURCE_DIR}/include/win_compat.h)
  add_link_options(-mwindows -static-libgcc -static)
  set(SDL2_LIBRARIES ${SDL2_STATIC_LDFLAGS})
  set(RR_GL_LIB "")
  set(RR_GL_SRC ${NAMCO22_ENGINE_DIR}/gl_dyn.c)
  set(RR_NET_LIB ws2_32)   # rr_net.c: Winsock2
else()
  set(RR_GL_LIB OpenGL::GL)
  set(RR_GL_SRC "")
  set(RR_NET_LIB "")
endif()

add_executable(rr src/rr_win.c src/rr_romzip.c ${NAMCO22_ENGINE_DIR}/romzip.c src/rr_main.c ${NAMCO22_ENGINE_LIFT_SRC} src/rr_mem.c src/rr_hw.c src/rr_game.c src/rr_env.c src/rr_link.c src/rr_net.c ${NAMCO22_ENGINE_NET_SRC} src/rr_dsp.c ${NAMCO22_ENGINE_C25_SRC} gen/rr_c25.c src/rr_scene.c src/rr_gl.c ${NAMCO22_ENGINE_GL_SRC} ${RR_GL_SRC} src/rr_host.c src/rr_ui.c src/rr_input.c ${NAMCO22_ENGINE_DIR}/twin_stick.c ${NAMCO22_ENGINE_FFB_SRC} src/rr_audio.c ${NAMCO22_ENGINE_SND_SRC} src/snd/snd_board.c gen/snd_driver.c gen/rr_lifted.c ${RD_SRC})
target_compile_options(rr PRIVATE -Wall)
target_include_directories(rr PRIVATE src/snd)
# gen/snd_driver.c is GENERATED by tools/gen/snd_translate.py (the C74 sound program
# translated to C from the ROM files); like gen/rr_lifted.c it is big and -O1 is plenty.
set_source_files_properties(gen/snd_driver.c PROPERTIES COMPILE_OPTIONS "-O1;-w")
target_include_directories(rr PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(rr ${SDL2_LIBRARIES} ${RR_GL_LIB} ZLIB::ZLIB ${RR_NET_LIB} m)

# Development tools (the instruction-trace build and the sound test oracle):
# only when their sources are present -- the public tree has just the game.
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tools/sndoracle/sound_oracle.c)
# instruction-trace build: every instruction logs PC + D0-D7/A0-A7
add_executable(rr_trace ${NAMCO22_C25_ORACLE_SRC} src/rr_romzip.c ${NAMCO22_ENGINE_DIR}/romzip.c src/rr_main.c ${NAMCO22_ENGINE_LIFT_SRC} src/rr_mem.c src/rr_hw.c src/rr_game.c src/rr_env.c src/rr_link.c src/rr_net.c ${NAMCO22_ENGINE_NET_SRC} src/rr_dsp.c ${NAMCO22_ENGINE_C25_SRC} gen/rr_c25.c src/rr_video.c src/rr_scene.c src/rr_gl.c ${NAMCO22_ENGINE_GL_SRC} ${RR_GL_SRC} src/rr_host.c src/rr_ui.c src/rr_input.c ${NAMCO22_ENGINE_DIR}/twin_stick.c ${NAMCO22_ENGINE_FFB_SRC} src/rr_audio.c ${NAMCO22_ENGINE_SND_SRC} src/snd/snd_board.c gen/snd_driver.c gen/rr_lifted.c ${RD_SRC})
target_include_directories(rr_trace PRIVATE ${SDL2_INCLUDE_DIRS} src/snd)
target_link_libraries(rr_trace ${SDL2_LIBRARIES} OpenGL::GL ZLIB::ZLIB ${RR_NET_LIB} m)
target_compile_definitions(rr_trace PRIVATE RR_TRACE RR_ORACLE C25_DEV_HOOKS)

# THE RENDERER ORACLE: the game with the software MAME port of namcos22_v.cpp
# (src/rr_video.c) built in beside the engine -- --render-dump without --gl is
# pixel-exact against MAME's own snapshots, and is what the engine's OpenGL
# picture is measured against. Never shipped (HARD RULE 2).
add_executable(rr_oracle ${NAMCO22_C25_ORACLE_SRC} src/rr_romzip.c ${NAMCO22_ENGINE_DIR}/romzip.c src/rr_main.c ${NAMCO22_ENGINE_LIFT_SRC} src/rr_mem.c src/rr_hw.c src/rr_game.c src/rr_env.c src/rr_link.c src/rr_net.c ${NAMCO22_ENGINE_NET_SRC} src/rr_dsp.c ${NAMCO22_ENGINE_C25_SRC} gen/rr_c25.c src/rr_video.c src/rr_scene.c src/rr_gl.c ${NAMCO22_ENGINE_GL_SRC} ${RR_GL_SRC} src/rr_host.c src/rr_ui.c src/rr_input.c ${NAMCO22_ENGINE_DIR}/twin_stick.c ${NAMCO22_ENGINE_FFB_SRC} src/rr_audio.c ${NAMCO22_ENGINE_SND_SRC} src/snd/snd_board.c gen/snd_driver.c gen/rr_lifted.c ${RD_SRC})
target_include_directories(rr_oracle PRIVATE ${SDL2_INCLUDE_DIRS} src/snd)
target_link_libraries(rr_oracle ${SDL2_LIBRARIES} OpenGL::GL ZLIB::ZLIB ${RR_NET_LIB} m)
target_compile_definitions(rr_oracle PRIVATE RR_ORACLE C25_DEV_HOOKS)

# TEST ORACLE: the same engine with the ORIGINAL C74 sound program fetched and
# decoded from memory in place of the translated driver. Never shipped -- the game
# (rr) links gen/snd_driver.c and contains no fetch/decode loop. See tools/sndoracle/.
add_executable(rr_sndoracle ${NAMCO22_C25_ORACLE_SRC} src/rr_romzip.c ${NAMCO22_ENGINE_DIR}/romzip.c src/rr_main.c ${NAMCO22_ENGINE_LIFT_SRC} src/rr_mem.c src/rr_hw.c src/rr_game.c src/rr_env.c src/rr_link.c src/rr_net.c ${NAMCO22_ENGINE_NET_SRC} src/rr_dsp.c ${NAMCO22_ENGINE_C25_SRC} gen/rr_c25.c src/rr_video.c src/rr_scene.c src/rr_gl.c ${NAMCO22_ENGINE_GL_SRC} ${RR_GL_SRC} src/rr_host.c src/rr_ui.c src/rr_input.c ${NAMCO22_ENGINE_DIR}/twin_stick.c ${NAMCO22_ENGINE_FFB_SRC} src/rr_audio.c ${NAMCO22_ENGINE_SND_SRC} src/snd/snd_board.c tools/sndoracle/sound_oracle.c tools/sndoracle/m37710.c gen/rr_lifted.c ${RD_SRC})
target_include_directories(rr_sndoracle PRIVATE ${SDL2_INCLUDE_DIRS} src/snd tools/sndoracle)
target_compile_definitions(rr_sndoracle PRIVATE RR_ORACLE C25_DEV_HOOKS)
target_link_libraries(rr_sndoracle ${SDL2_LIBRARIES} OpenGL::GL ZLIB::ZLIB ${RR_NET_LIB} m)
endif()
