From 4c6f3f81ebfc90737fd2ea0a027dee367fd97e59 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Sun, 3 Aug 2025 17:36:01 +0100 Subject: [PATCH] CMake build system --- CMakeLists.txt | 71 +++++++++++ cmake/Info.plist.in | 34 +++++ cmake/basegame.cmake | 184 +++++++++++++++++++++++++++ cmake/client.cmake | 115 +++++++++++++++++ cmake/compilers/all.cmake | 5 + cmake/compilers/appleclang.cmake | 5 + cmake/compilers/clang.cmake | 5 + cmake/compilers/gcc.cmake | 5 + cmake/compilers/gnu.cmake | 18 +++ cmake/compilers/msvc.cmake | 37 ++++++ cmake/identity.cmake | 20 +++ cmake/libraries/all.cmake | 9 ++ cmake/libraries/curl.cmake | 15 +++ cmake/libraries/freetype.cmake | 8 ++ cmake/libraries/jpeg.cmake | 18 +++ cmake/libraries/ogg.cmake | 21 +++ cmake/libraries/openal.cmake | 23 ++++ cmake/libraries/opus.cmake | 27 ++++ cmake/libraries/sdl.cmake | 51 ++++++++ cmake/libraries/vorbis.cmake | 22 ++++ cmake/libraries/zlib.cmake | 22 ++++ cmake/missionpack.cmake | 72 +++++++++++ cmake/platforms/all.cmake | 4 + cmake/platforms/emscripten.cmake | 50 ++++++++ cmake/platforms/macos.cmake | 80 ++++++++++++ cmake/platforms/unix.cmake | 21 +++ cmake/platforms/windows.cmake | 35 +++++ cmake/renderer_common.cmake | 37 ++++++ cmake/renderer_gl1.cmake | 62 +++++++++ cmake/renderer_gl2.cmake | 94 ++++++++++++++ cmake/server.cmake | 54 ++++++++ cmake/shared_sources.cmake | 104 +++++++++++++++ cmake/tools/CMakeLists.txt | 86 +++++++++++++ cmake/utils/add_git_dependency.cmake | 27 ++++ cmake/utils/arch.cmake | 23 ++++ cmake/utils/disable_warnings.cmake | 17 +++ cmake/utils/find_include_dirs.cmake | 37 ++++++ cmake/utils/qvm_tools.cmake | 83 ++++++++++++ cmake/utils/set_output_dirs.cmake | 27 ++++ cmake/utils/stringify_shader.cmake | 13 ++ 40 files changed, 1641 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake/Info.plist.in create mode 100644 cmake/basegame.cmake create mode 100644 cmake/client.cmake create mode 100644 cmake/compilers/all.cmake create mode 100644 cmake/compilers/appleclang.cmake create mode 100644 cmake/compilers/clang.cmake create mode 100644 cmake/compilers/gcc.cmake create mode 100644 cmake/compilers/gnu.cmake create mode 100644 cmake/compilers/msvc.cmake create mode 100644 cmake/identity.cmake create mode 100644 cmake/libraries/all.cmake create mode 100644 cmake/libraries/curl.cmake create mode 100644 cmake/libraries/freetype.cmake create mode 100644 cmake/libraries/jpeg.cmake create mode 100644 cmake/libraries/ogg.cmake create mode 100644 cmake/libraries/openal.cmake create mode 100644 cmake/libraries/opus.cmake create mode 100644 cmake/libraries/sdl.cmake create mode 100644 cmake/libraries/vorbis.cmake create mode 100644 cmake/libraries/zlib.cmake create mode 100644 cmake/missionpack.cmake create mode 100644 cmake/platforms/all.cmake create mode 100644 cmake/platforms/emscripten.cmake create mode 100644 cmake/platforms/macos.cmake create mode 100644 cmake/platforms/unix.cmake create mode 100644 cmake/platforms/windows.cmake create mode 100644 cmake/renderer_common.cmake create mode 100644 cmake/renderer_gl1.cmake create mode 100644 cmake/renderer_gl2.cmake create mode 100644 cmake/server.cmake create mode 100644 cmake/shared_sources.cmake create mode 100644 cmake/tools/CMakeLists.txt create mode 100644 cmake/utils/add_git_dependency.cmake create mode 100644 cmake/utils/arch.cmake create mode 100644 cmake/utils/disable_warnings.cmake create mode 100644 cmake/utils/find_include_dirs.cmake create mode 100644 cmake/utils/qvm_tools.cmake create mode 100644 cmake/utils/set_output_dirs.cmake create mode 100644 cmake/utils/stringify_shader.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..94186f4b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 3.18) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) +include(identity) + +project(${PROJECT_NAME} VERSION ${PROJECT_VERSION} LANGUAGES C ASM) + +option(BUILD_SERVER "Build dedicated server" ON) +option(BUILD_CLIENT "Build client" ON) +option(BUILD_RENDERER_GL1 "Build GL1 renderer" ON) +option(BUILD_RENDERER_GL2 "Build GL2 renderer" ON) +option(BUILD_GAME_LIBRARIES "Build game module libraries" ON) +option(BUILD_GAME_QVMS "Build game module qvms" ON) +option(BUILD_STANDALONE "Build binaries for standalone games" OFF) + +option(USE_ARCHLESS_FILENAMES "Don't include the architecture in binary filenames" OFF) +option(USE_RENDERER_DLOPEN "Dynamically load the renderer(s)" ON) +option(USE_OPENAL "OpenAL audio" ON) +option(USE_OPENAL_DLOPEN "Dynamically load OpenAL" ON) +option(USE_HTTP "HTTP download support" ON) +option(USE_CODEC_VORBIS "Ogg Vorbis support" ON) +option(USE_CODEC_OPUS "Ogg Opus support" ON) +option(USE_VOIP "Voice chat" ON) +option(USE_MUMBLE "Mumble support" ON) +option(USE_FREETYPE "Freetype font rendering" OFF) + +option(USE_INTERNAL_LIBS "Use internally packaged libraries" ON) +option(USE_INTERNAL_ZLIB "Use internal copy of zlib" ${USE_INTERNAL_LIBS}) +option(USE_INTERNAL_JPEG "Use internal copy of libjpeg" ${USE_INTERNAL_LIBS}) +option(USE_INTERNAL_OGG "Use internal copy of ogg" ${USE_INTERNAL_LIBS}) +option(USE_INTERNAL_VORBIS "Use internal copy of vorbis" ${USE_INTERNAL_LIBS}) +option(USE_INTERNAL_OPUS "Use internal copy of opus" ${USE_INTERNAL_LIBS}) + +# Release build by default, set externally if you want something else +if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_SHARED_LIBRARY_PREFIX "") + +set(PRODUCT_VERSION "${CMAKE_PROJECT_VERSION}") + +if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + execute_process( + COMMAND git show -s --pretty=format:%h + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_REV + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET) + + if(GIT_REV) + set(PRODUCT_VERSION "${PRODUCT_VERSION}_g${GIT_REV}") + endif() +endif() + +add_compile_definitions(PRODUCT_VERSION="${PRODUCT_VERSION}") + +set(SOURCE_DIR ${CMAKE_SOURCE_DIR}/code) + +include(compilers/all) +include(platforms/all) +include(libraries/all) + +include(server) +include(renderer_gl1) +include(renderer_gl2) +include(client) +include(basegame) +include(missionpack) diff --git a/cmake/Info.plist.in b/cmake/Info.plist.in new file mode 100644 index 00000000..d52ade89 --- /dev/null +++ b/cmake/Info.plist.in @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + @MACOS_APP_EXECUTABLE_NAME@ + CFBundleIconFile + @MACOS_APP_ICON_FILE@ + CFBundleIdentifier + @MACOS_APP_GUI_IDENTIFIER@ + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + @MACOS_APP_BUNDLE_NAME@ + CFBundlePackageType + APPL + CFBundleShortVersionString + @MACOS_APP_SHORT_VERSION_STRING@ + CFBundleVersion + @MACOS_APP_BUNDLE_VERSION@ + NSHumanReadableCopyright + @MACOS_APP_COPYRIGHT@ + NSPrincipalClass + NSApplication + LSMinimumSystemVersion + @MACOS_APP_DEPLOYMENT_TARGET@ + LSApplicationCategoryType + public.app-category.games + + @MACOS_APP_PLIST_URL_TYPES@ + + diff --git a/cmake/basegame.cmake b/cmake/basegame.cmake new file mode 100644 index 00000000..946de095 --- /dev/null +++ b/cmake/basegame.cmake @@ -0,0 +1,184 @@ +if(NOT BUILD_GAME_LIBRARIES AND NOT BUILD_GAME_QVMS) + return() +endif() + +include(utils/arch) +include(utils/qvm_tools) +include(utils/set_output_dirs) + +set(CGAME_SOURCES + ${SOURCE_DIR}/cgame/cg_main.c + ${SOURCE_DIR}/game/bg_misc.c + ${SOURCE_DIR}/game/bg_pmove.c + ${SOURCE_DIR}/game/bg_slidemove.c + ${SOURCE_DIR}/game/bg_lib.c + ${SOURCE_DIR}/cgame/cg_consolecmds.c + ${SOURCE_DIR}/cgame/cg_draw.c + ${SOURCE_DIR}/cgame/cg_drawtools.c + ${SOURCE_DIR}/cgame/cg_effects.c + ${SOURCE_DIR}/cgame/cg_ents.c + ${SOURCE_DIR}/cgame/cg_event.c + ${SOURCE_DIR}/cgame/cg_info.c + ${SOURCE_DIR}/cgame/cg_localents.c + ${SOURCE_DIR}/cgame/cg_marks.c + ${SOURCE_DIR}/cgame/cg_particles.c + ${SOURCE_DIR}/cgame/cg_players.c + ${SOURCE_DIR}/cgame/cg_playerstate.c + ${SOURCE_DIR}/cgame/cg_predict.c + ${SOURCE_DIR}/cgame/cg_scoreboard.c + ${SOURCE_DIR}/cgame/cg_servercmds.c + ${SOURCE_DIR}/cgame/cg_snapshot.c + ${SOURCE_DIR}/cgame/cg_view.c + ${SOURCE_DIR}/cgame/cg_weapons.c +) + +set(CGAME_BINARY_SOURCES ${SOURCE_DIR}/cgame/cg_syscalls.c) +set(CGAME_QVM_SOURCES ${SOURCE_DIR}/cgame/cg_syscalls.asm) + +set(GAME_SOURCES + ${SOURCE_DIR}/game/g_main.c + ${SOURCE_DIR}/game/ai_chat.c + ${SOURCE_DIR}/game/ai_cmd.c + ${SOURCE_DIR}/game/ai_dmnet.c + ${SOURCE_DIR}/game/ai_dmq3.c + ${SOURCE_DIR}/game/ai_main.c + ${SOURCE_DIR}/game/ai_team.c + ${SOURCE_DIR}/game/ai_vcmd.c + ${SOURCE_DIR}/game/bg_misc.c + ${SOURCE_DIR}/game/bg_pmove.c + ${SOURCE_DIR}/game/bg_slidemove.c + ${SOURCE_DIR}/game/bg_lib.c + ${SOURCE_DIR}/game/g_active.c + ${SOURCE_DIR}/game/g_arenas.c + ${SOURCE_DIR}/game/g_bot.c + ${SOURCE_DIR}/game/g_client.c + ${SOURCE_DIR}/game/g_cmds.c + ${SOURCE_DIR}/game/g_combat.c + ${SOURCE_DIR}/game/g_items.c + ${SOURCE_DIR}/game/g_mem.c + ${SOURCE_DIR}/game/g_misc.c + ${SOURCE_DIR}/game/g_missile.c + ${SOURCE_DIR}/game/g_mover.c + ${SOURCE_DIR}/game/g_session.c + ${SOURCE_DIR}/game/g_spawn.c + ${SOURCE_DIR}/game/g_svcmds.c + ${SOURCE_DIR}/game/g_target.c + ${SOURCE_DIR}/game/g_team.c + ${SOURCE_DIR}/game/g_trigger.c + ${SOURCE_DIR}/game/g_utils.c + ${SOURCE_DIR}/game/g_weapon.c +) + +set(GAME_BINARY_SOURCES ${SOURCE_DIR}/game/g_syscalls.c) +set(GAME_QVM_SOURCES ${SOURCE_DIR}/game/g_syscalls.asm) + +set(UI_SOURCES + ${SOURCE_DIR}/q3_ui/ui_main.c + ${SOURCE_DIR}/game/bg_misc.c + ${SOURCE_DIR}/game/bg_lib.c + ${SOURCE_DIR}/q3_ui/ui_addbots.c + ${SOURCE_DIR}/q3_ui/ui_atoms.c + ${SOURCE_DIR}/q3_ui/ui_cdkey.c + ${SOURCE_DIR}/q3_ui/ui_cinematics.c + ${SOURCE_DIR}/q3_ui/ui_confirm.c + ${SOURCE_DIR}/q3_ui/ui_connect.c + ${SOURCE_DIR}/q3_ui/ui_controls2.c + ${SOURCE_DIR}/q3_ui/ui_credits.c + ${SOURCE_DIR}/q3_ui/ui_demo2.c + ${SOURCE_DIR}/q3_ui/ui_display.c + ${SOURCE_DIR}/q3_ui/ui_gameinfo.c + ${SOURCE_DIR}/q3_ui/ui_ingame.c + ${SOURCE_DIR}/q3_ui/ui_loadconfig.c + ${SOURCE_DIR}/q3_ui/ui_menu.c + ${SOURCE_DIR}/q3_ui/ui_mfield.c + ${SOURCE_DIR}/q3_ui/ui_mods.c + ${SOURCE_DIR}/q3_ui/ui_network.c + ${SOURCE_DIR}/q3_ui/ui_options.c + ${SOURCE_DIR}/q3_ui/ui_playermodel.c + ${SOURCE_DIR}/q3_ui/ui_players.c + ${SOURCE_DIR}/q3_ui/ui_playersettings.c + ${SOURCE_DIR}/q3_ui/ui_preferences.c + ${SOURCE_DIR}/q3_ui/ui_qmenu.c + ${SOURCE_DIR}/q3_ui/ui_removebots.c + ${SOURCE_DIR}/q3_ui/ui_saveconfig.c + ${SOURCE_DIR}/q3_ui/ui_serverinfo.c + ${SOURCE_DIR}/q3_ui/ui_servers2.c + ${SOURCE_DIR}/q3_ui/ui_setup.c + ${SOURCE_DIR}/q3_ui/ui_sound.c + ${SOURCE_DIR}/q3_ui/ui_sparena.c + ${SOURCE_DIR}/q3_ui/ui_specifyserver.c + ${SOURCE_DIR}/q3_ui/ui_splevel.c + ${SOURCE_DIR}/q3_ui/ui_sppostgame.c + ${SOURCE_DIR}/q3_ui/ui_spskill.c + ${SOURCE_DIR}/q3_ui/ui_startserver.c + ${SOURCE_DIR}/q3_ui/ui_team.c + ${SOURCE_DIR}/q3_ui/ui_teamorders.c + ${SOURCE_DIR}/q3_ui/ui_video.c +) + +set(UI_BINARY_SOURCES ${SOURCE_DIR}/ui/ui_syscalls.c) +set(UI_QVM_SOURCES ${SOURCE_DIR}/ui/ui_syscalls.asm) + +set(GAME_MODULE_SHARED_SOURCES + ${SOURCE_DIR}/qcommon/q_math.c + ${SOURCE_DIR}/qcommon/q_shared.c +) + +set(CGAME_SOURCES_BASEGAME ${CGAME_SOURCES} ${GAME_MODULE_SHARED_SOURCES}) +set(GAME_SOURCES_BASEGAME ${GAME_SOURCES} ${GAME_MODULE_SHARED_SOURCES}) +set(UI_SOURCES_BASEGAME ${UI_SOURCES} ${GAME_MODULE_SHARED_SOURCES}) + +if(BUILD_GAME_LIBRARIES) + if(USE_ARCHLESS_FILENAMES) + set(CGAME_MODULE_BINARY ${CGAME_MODULE}) + set(GAME_MODULE_BINARY ${GAME_MODULE}) + set(UI_MODULE_BINARY ${UI_MODULE}) + else() + set(CGAME_MODULE_BINARY ${CGAME_MODULE}${ARCH}) + set(GAME_MODULE_BINARY ${GAME_MODULE}${ARCH}) + set(UI_MODULE_BINARY ${UI_MODULE}${ARCH}) + endif() + + set(CGAME_MODULE_BINARY_BASEGAME ${CGAME_MODULE_BINARY}_${BASEGAME}) + set(GAME_MODULE_BINARY_BASEGAME ${GAME_MODULE_BINARY}_${BASEGAME}) + set(UI_MODULE_BINARY_BASEGAME ${UI_MODULE_BINARY}_${BASEGAME}) + + add_library( ${CGAME_MODULE_BINARY_BASEGAME} SHARED ${CGAME_SOURCES_BASEGAME} ${CGAME_BINARY_SOURCES}) + target_compile_definitions( ${CGAME_MODULE_BINARY_BASEGAME} PRIVATE CGAME) + set_target_properties( ${CGAME_MODULE_BINARY_BASEGAME} PROPERTIES OUTPUT_NAME ${CGAME_MODULE_BINARY}) + set_output_dirs( ${CGAME_MODULE_BINARY_BASEGAME} SUBDIRECTORY ${BASEGAME}) + + add_library( ${GAME_MODULE_BINARY_BASEGAME} SHARED ${GAME_SOURCES_BASEGAME} ${GAME_BINARY_SOURCES}) + target_compile_definitions( ${GAME_MODULE_BINARY_BASEGAME} PRIVATE QAGAME) + set_target_properties( ${GAME_MODULE_BINARY_BASEGAME} PROPERTIES OUTPUT_NAME ${GAME_MODULE_BINARY}) + set_output_dirs( ${GAME_MODULE_BINARY_BASEGAME} SUBDIRECTORY ${BASEGAME}) + + add_library( ${UI_MODULE_BINARY_BASEGAME} SHARED ${UI_SOURCES_BASEGAME} ${UI_BINARY_SOURCES}) + target_compile_definitions( ${UI_MODULE_BINARY_BASEGAME} PRIVATE UI) + set_target_properties( ${UI_MODULE_BINARY_BASEGAME} PROPERTIES OUTPUT_NAME ${UI_MODULE_BINARY}) + set_output_dirs( ${UI_MODULE_BINARY_BASEGAME} SUBDIRECTORY ${BASEGAME}) +endif() + +if(BUILD_GAME_QVMS) + set(CGAME_MODULE_QVM_BASEGAME ${CGAME_MODULE}qvm_${BASEGAME}) + set(GAME_MODULE_QVM_BASEGAME ${GAME_MODULE}qvm_${BASEGAME}) + set(UI_MODULE_QVM_BASEGAME ${UI_MODULE}qvm_${BASEGAME}) + + add_qvm(${CGAME_MODULE_QVM_BASEGAME} + DEFINITIONS CGAME + OUTPUT_NAME ${CGAME_MODULE} + OUTPUT_DIRECTORY ${BASEGAME}/vm + SOURCES ${CGAME_SOURCES_BASEGAME} ${CGAME_QVM_SOURCES}) + + add_qvm(${GAME_MODULE_QVM_BASEGAME} + DEFINITIONS QAGAME + OUTPUT_NAME ${GAME_MODULE} + OUTPUT_DIRECTORY ${BASEGAME}/vm + SOURCES ${GAME_SOURCES_BASEGAME} ${GAME_QVM_SOURCES}) + + add_qvm(${UI_MODULE_QVM_BASEGAME} + DEFINITIONS UI + OUTPUT_NAME ${UI_MODULE} + OUTPUT_DIRECTORY ${BASEGAME}/vm + SOURCES ${UI_SOURCES_BASEGAME} ${UI_QVM_SOURCES}) +endif() diff --git a/cmake/client.cmake b/cmake/client.cmake new file mode 100644 index 00000000..2af6b6fc --- /dev/null +++ b/cmake/client.cmake @@ -0,0 +1,115 @@ +if(NOT BUILD_CLIENT) + return() +endif() + +include(utils/add_git_dependency) +include(utils/arch) +include(utils/set_output_dirs) +include(shared_sources) + +include(renderer_common) + +set(CLIENT_SOURCES + ${SOURCE_DIR}/client/cl_cgame.c + ${SOURCE_DIR}/client/cl_cin.c + ${SOURCE_DIR}/client/cl_console.c + ${SOURCE_DIR}/client/cl_input.c + ${SOURCE_DIR}/client/cl_keys.c + ${SOURCE_DIR}/client/cl_main.c + ${SOURCE_DIR}/client/cl_net_chan.c + ${SOURCE_DIR}/client/cl_parse.c + ${SOURCE_DIR}/client/cl_scrn.c + ${SOURCE_DIR}/client/cl_ui.c + ${SOURCE_DIR}/client/cl_avi.c + ${SOURCE_DIR}/client/libmumblelink.c + ${SOURCE_DIR}/client/snd_altivec.c + ${SOURCE_DIR}/client/snd_adpcm.c + ${SOURCE_DIR}/client/snd_dma.c + ${SOURCE_DIR}/client/snd_mem.c + ${SOURCE_DIR}/client/snd_mix.c + ${SOURCE_DIR}/client/snd_wavelet.c + ${SOURCE_DIR}/client/snd_main.c + ${SOURCE_DIR}/client/snd_codec.c + ${SOURCE_DIR}/client/snd_codec_wav.c + ${SOURCE_DIR}/client/snd_codec_ogg.c + ${SOURCE_DIR}/client/snd_codec_opus.c + ${SOURCE_DIR}/client/qal.c + ${SOURCE_DIR}/client/snd_openal.c + ${SOURCE_DIR}/sdl/sdl_input.c + ${SOURCE_DIR}/sdl/sdl_snd.c + ${CLIENT_PLATFORM_SOURCES} +) + +add_git_dependency(${SOURCE_DIR}/client/cl_console.c) + +if(USE_ARCHLESS_FILENAMES) + set(CLIENT_BINARY ${CLIENT_NAME}) + list(APPEND CLIENT_DEFINITIONS USE_ARCHLESS_FILENAMES) +else() + set(CLIENT_BINARY ${CLIENT_NAME}.${ARCH}) +endif() + +list(APPEND CLIENT_DEFINITIONS BOTLIB) + +if(BUILD_STANDALONE) + list(APPEND CLIENT_DEFINITIONS STANDALONE) +endif() + +if(USE_RENDERER_DLOPEN) + list(APPEND CLIENT_DEFINITIONS USE_RENDERER_DLOPEN) +endif() + +if(USE_HTTP) + list(APPEND CLIENT_DEFINITIONS USE_HTTP) +endif() + +if(USE_VOIP) + list(APPEND CLIENT_DEFINITIONS USE_VOIP) +endif() + +if(USE_MUMBLE) + list(APPEND CLIENT_DEFINITIONS USE_MUMBLE) + list(APPEND CLIENT_LIBRARY_SOURCES ${SOURCE_DIR}/client/libmumblelink.c) +endif() + +list(APPEND CLIENT_BINARY_SOURCES + ${SERVER_SOURCES} + ${CLIENT_SOURCES} + ${COMMON_SOURCES} + ${BOTLIB_SOURCES} + ${SYSTEM_SOURCES} + ${ASM_SOURCES} + ${CLIENT_LIBRARY_SOURCES}) + +add_executable(${CLIENT_BINARY} ${CLIENT_EXECUTABLE_OPTIONS} ${CLIENT_BINARY_SOURCES}) + +target_include_directories( ${CLIENT_BINARY} PRIVATE ${CLIENT_INCLUDE_DIRS}) +target_compile_definitions( ${CLIENT_BINARY} PRIVATE ${CLIENT_DEFINITIONS}) +target_compile_options( ${CLIENT_BINARY} PRIVATE ${CLIENT_COMPILE_OPTIONS}) +target_link_libraries( ${CLIENT_BINARY} PRIVATE ${COMMON_LIBRARIES} ${CLIENT_LIBRARIES}) +target_link_options( ${CLIENT_BINARY} PRIVATE ${CLIENT_LINK_OPTIONS}) + +set_output_dirs(${CLIENT_BINARY}) + +if(NOT USE_RENDERER_DLOPEN) + target_sources(${CLIENT_BINARY} PRIVATE + # These are never simultaneously populated + ${RENDERER_GL1_BINARY_SOURCES} + ${RENDERER_GL2_BINARY_SOURCES}) + + target_include_directories( ${CLIENT_BINARY} PRIVATE ${RENDERER_INCLUDE_DIRS}) + target_compile_definitions( ${CLIENT_BINARY} PRIVATE ${RENDERER_DEFINITIONS}) + target_compile_options( ${CLIENT_BINARY} PRIVATE ${RENDERER_COMPILE_OPTIONS}) + target_link_libraries( ${CLIENT_BINARY} PRIVATE ${RENDERER_LIBRARIES}) +endif() + +foreach(LIBRARY IN LISTS CLIENT_DEPLOY_LIBRARIES) + add_custom_command(TARGET ${CLIENT_BINARY} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${LIBRARY} + $) +endforeach() + +if(POST_CLIENT_CONFIGURE_FUNCTION) + cmake_language(CALL ${POST_CLIENT_CONFIGURE_FUNCTION}) +endif() diff --git a/cmake/compilers/all.cmake b/cmake/compilers/all.cmake new file mode 100644 index 00000000..0f3db942 --- /dev/null +++ b/cmake/compilers/all.cmake @@ -0,0 +1,5 @@ +include(compilers/appleclang) +include(compilers/clang) +include(compilers/gcc) +include(compilers/gnu) +include(compilers/msvc) diff --git a/cmake/compilers/appleclang.cmake b/cmake/compilers/appleclang.cmake new file mode 100644 index 00000000..d865a79b --- /dev/null +++ b/cmake/compilers/appleclang.cmake @@ -0,0 +1,5 @@ +# Apple Clang compiler specific settings + +if(NOT CMAKE_C_COMPILER_ID STREQUAL "AppleClang") + return() +endif() diff --git a/cmake/compilers/clang.cmake b/cmake/compilers/clang.cmake new file mode 100644 index 00000000..19650b62 --- /dev/null +++ b/cmake/compilers/clang.cmake @@ -0,0 +1,5 @@ +# Clang compiler specific settings + +if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang") + return() +endif() diff --git a/cmake/compilers/gcc.cmake b/cmake/compilers/gcc.cmake new file mode 100644 index 00000000..b3d7282c --- /dev/null +++ b/cmake/compilers/gcc.cmake @@ -0,0 +1,5 @@ +# GCC compiler specific settings + +if(NOT CMAKE_C_COMPILER_ID STREQUAL "GNU") + return() +endif() diff --git a/cmake/compilers/gnu.cmake b/cmake/compilers/gnu.cmake new file mode 100644 index 00000000..cb2ef0ad --- /dev/null +++ b/cmake/compilers/gnu.cmake @@ -0,0 +1,18 @@ +# GNU style (GCC/Clang) compiler specific settings + +if(NOT CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_ID MATCHES "^(Apple)?Clang$") + return() +endif() + +set(ASM_SOURCES + ${SOURCE_DIR}/asm/snapvector.c + ${SOURCE_DIR}/asm/ftola.c +) + +add_compile_options(-Wall -Wimplicit + -Wstrict-prototypes -Wformat=2 -Wformat-security + -Wstrict-aliasing=2 -Wmissing-format-attribute + -Wdisabled-optimization -Werror-implicit-function-declaration) + +add_compile_options(-Wno-strict-aliasing + -Wno-format-zero-length -Wno-format-nonliteral) diff --git a/cmake/compilers/msvc.cmake b/cmake/compilers/msvc.cmake new file mode 100644 index 00000000..55935403 --- /dev/null +++ b/cmake/compilers/msvc.cmake @@ -0,0 +1,37 @@ +# MSVC compiler specific settings + +if(NOT CMAKE_C_COMPILER_ID STREQUAL "MSVC") + return() +endif() + +include(utils/arch) + +enable_language(ASM_MASM) + +set(ASM_SOURCES + ${SOURCE_DIR}/asm/snapvector.asm + ${SOURCE_DIR}/asm/ftola.asm +) + +if(ARCH MATCHES "x86_64") + list(APPEND ASM_SOURCES ${SOURCE_DIR}/asm/vm_x86_64.asm) + set_source_files_properties( + ${ASM_SOURCES} + PROPERTIES COMPILE_DEFINITIONS "idx64") +endif() + +# Baseline warnings +add_compile_options("$<$:/W4>") + +# C4267: 'var' : conversion from 'size_t' to 'type', possible loss of data +# There are way too many of these to realistically deal with them +add_compile_options("$<$:/wd4267>") + +# MSVC doesn't understand __inline__, which libjpeg uses +add_compile_definitions(__inline__=inline) + +# It's unlikely that we'll move to the _s variants, so stop the warning +add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + +# The sockets platform abstraction layer necessarily uses deprecated APIs +add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS) diff --git a/cmake/identity.cmake b/cmake/identity.cmake new file mode 100644 index 00000000..796d7d86 --- /dev/null +++ b/cmake/identity.cmake @@ -0,0 +1,20 @@ +set(PROJECT_NAME ioq3) +set(PROJECT_VERSION 1.36) + +set(SERVER_NAME ioq3ded) +set(CLIENT_NAME ioquake3) + +set(BASEGAME baseq3) + +set(CGAME_MODULE cgame) +set(GAME_MODULE qagame) +set(UI_MODULE ui) + +set(WINDOWS_ICON_PATH ${CMAKE_SOURCE_DIR}/misc/quake3.ico) + +set(MACOS_ICON_PATH ${CMAKE_SOURCE_DIR}/misc/quake3_flat.icns) +set(MACOS_BUNDLE_ID org.ioquake.${CLIENT_NAME}) + +set(COPYRIGHT "QUAKE III ARENA Copyright © 1999-2000 id Software, Inc. All rights reserved.") + +set(PROTOCOL_HANDLER_SCHEME quake3) diff --git a/cmake/libraries/all.cmake b/cmake/libraries/all.cmake new file mode 100644 index 00000000..112c3489 --- /dev/null +++ b/cmake/libraries/all.cmake @@ -0,0 +1,9 @@ +include(libraries/curl) +include(libraries/freetype) +include(libraries/jpeg) +include(libraries/ogg) +include(libraries/opus) +include(libraries/openal) +include(libraries/sdl) +include(libraries/vorbis) +include(libraries/zlib) diff --git a/cmake/libraries/curl.cmake b/cmake/libraries/curl.cmake new file mode 100644 index 00000000..c0ca61eb --- /dev/null +++ b/cmake/libraries/curl.cmake @@ -0,0 +1,15 @@ +if(NOT USE_HTTP OR WIN32) + return() +endif() + +set(INTERNAL_CURL_DIR ${SOURCE_DIR}/thirdparty/curl-8.15.0) + +find_package(CURL QUIET) + +if(NOT CURL_FOUND) + set(CURL_DEFINITIONS USE_INTERNAL_CURL_HEADERS) + set(CURL_INCLUDE_DIR ${INTERNAL_CURL_DIR}/include) +endif() + +list(APPEND CLIENT_DEFINITIONS ${CURL_DEFINITIONS}) +list(APPEND CLIENT_INCLUDE_DIRS ${CURL_INCLUDE_DIR}) diff --git a/cmake/libraries/freetype.cmake b/cmake/libraries/freetype.cmake new file mode 100644 index 00000000..45bac275 --- /dev/null +++ b/cmake/libraries/freetype.cmake @@ -0,0 +1,8 @@ +if(NOT USE_FREETYPE) + return() +endif() + +find_package(Freetype REQUIRED) + +list(APPEND RENDERER_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS}) +list(APPEND RENDERER_LIBRARIES ${FREETYPE_LIBRARIES}) diff --git a/cmake/libraries/jpeg.cmake b/cmake/libraries/jpeg.cmake new file mode 100644 index 00000000..ccde8a8d --- /dev/null +++ b/cmake/libraries/jpeg.cmake @@ -0,0 +1,18 @@ +include(utils/disable_warnings) +include(utils/find_include_dirs) + +set(INTERNAL_JPEG_DIR ${SOURCE_DIR}/thirdparty/jpeg-9f) + +if(USE_INTERNAL_JPEG) + file(GLOB_RECURSE JPEG_SOURCES ${INTERNAL_JPEG_DIR}/j*.c) + disable_warnings(${JPEG_SOURCES}) + find_include_dirs(JPEG_INCLUDE_DIRS ${JPEG_SOURCES}) + set(JPEG_DEFINITIONS USE_INTERNAL_JPEG) + list(APPEND RENDERER_LIBRARY_SOURCES ${JPEG_SOURCES}) +else() + find_package(JPEG REQUIRED) +endif() + +list(APPEND RENDERER_LIBRARIES ${JPEG_LIBRARIES}) +list(APPEND RENDERER_INCLUDE_DIRS ${JPEG_INCLUDE_DIRS}) +list(APPEND RENDERER_DEFINITIONS ${JPEG_DEFINTIONS}) diff --git a/cmake/libraries/ogg.cmake b/cmake/libraries/ogg.cmake new file mode 100644 index 00000000..c6112854 --- /dev/null +++ b/cmake/libraries/ogg.cmake @@ -0,0 +1,21 @@ +if(NOT USE_CODEC_VORBIS) + return() +endif() + +include(utils/disable_warnings) + +set(INTERNAL_OGG_DIR ${SOURCE_DIR}/thirdparty/libogg-1.3.6) + +if(USE_INTERNAL_OGG) + file(GLOB_RECURSE OGG_SOURCES ${INTERNAL_OGG_DIR}/*.c) + disable_warnings(${OGG_SOURCES}) + set(OGG_INCLUDE_DIRS ${INTERNAL_OGG_DIR}/include) + list(APPEND CLIENT_LIBRARY_SOURCES ${OGG_SOURCES}) +else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(OGG REQUIRED ogg) +endif() + +list(APPEND CLIENT_LIBRARIES ${OGG_LIBRARIES}) +list(APPEND CLIENT_INCLUDE_DIRS ${OGG_INCLUDE_DIRS}) +list(APPEND CLIENT_DEFINITIONS ${OGG_DEFINITIONS}) diff --git a/cmake/libraries/openal.cmake b/cmake/libraries/openal.cmake new file mode 100644 index 00000000..95b2d345 --- /dev/null +++ b/cmake/libraries/openal.cmake @@ -0,0 +1,23 @@ +if(NOT USE_OPENAL) + return() +endif() + +set(INTERNAL_OPENAL_DIR ${SOURCE_DIR}/thirdparty/openal-soft-1.24.3) + +find_package(OpenAL QUIET) + +if(NOT OpenAL_FOUND) + set(OPENAL_DEFINITIONS USE_INTERNAL_OPENAL_HEADERS) + set(OPENAL_INCLUDE_DIR ${INTERNAL_OPENAL_DIR}/include) + set(OPENAL_LIBRARY openal) +endif() + +list(APPEND CLIENT_DEFINITIONS ${OPENAL_DEFINITIONS} USE_OPENAL) +list(APPEND CLIENT_INCLUDE_DIRS ${OPENAL_INCLUDE_DIR}) + +if(USE_OPENAL_DLOPEN) + list(APPEND CLIENT_DEFINITIONS USE_OPENAL_DLOPEN) +else() + find_package(Threads REQUIRED) + list(APPEND CLIENT_LIBRARIES Threads::Threads ${OPENAL_LIBRARY}) +endif() diff --git a/cmake/libraries/opus.cmake b/cmake/libraries/opus.cmake new file mode 100644 index 00000000..01dc1ef2 --- /dev/null +++ b/cmake/libraries/opus.cmake @@ -0,0 +1,27 @@ +if(NOT USE_CODEC_OPUS) + return() +endif() + +include(utils/disable_warnings) +include(utils/find_include_dirs) + +set(INTERNAL_OPUS_DIR ${SOURCE_DIR}/thirdparty/opus-1.5.2) +set(INTERNAL_OPUSFILE_DIR ${SOURCE_DIR}/thirdparty/opusfile-0.12) + +if(USE_INTERNAL_OPUS) + file(GLOB_RECURSE OPUS_SOURCES ${INTERNAL_OPUS_DIR}/*.c) + file(GLOB_RECURSE OPUSFILE_SOURCES ${INTERNAL_OPUSFILE_DIR}/*.c) + disable_warnings(${OPUS_SOURCES} ${OPUSFILE_SOURCES}) + find_include_dirs(OPUS_INCLUDE_DIRS ${OPUS_SOURCES}) + find_include_dirs(OPUSFILE_INCLUDE_DIRS ${OPUSFILE_SOURCES}) + set(OPUS_INCLUDE_DIRS ${OPUS_INCLUDE_DIRS} ${OPUSFILE_INCLUDE_DIRS} ${INTERNAL_OPUSFILE_DIR}/include) + set(OPUS_DEFINITIONS USE_CODEC_OPUS OPUS_BUILD HAVE_LRINTF FLOATING_POINT FLOAT_APPROX USE_ALLOCA) + list(APPEND CLIENT_LIBRARY_SOURCES ${OPUS_SOURCES} ${OPUSFILE_SOURCES}) +else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(OPUS REQUIRED opus) +endif() + +list(APPEND CLIENT_LIBRARIES ${OPUS_LIBRARIES}) +list(APPEND CLIENT_INCLUDE_DIRS ${OPUS_INCLUDE_DIRS}) +list(APPEND CLIENT_DEFINITIONS ${OPUS_DEFINITIONS}) diff --git a/cmake/libraries/sdl.cmake b/cmake/libraries/sdl.cmake new file mode 100644 index 00000000..b1e81ae5 --- /dev/null +++ b/cmake/libraries/sdl.cmake @@ -0,0 +1,51 @@ +set(INTERNAL_SDL_DIR ${SOURCE_DIR}/thirdparty/SDL2-2.32.8) + +include(utils/arch) + +if(NOT WIN32 AND NOT APPLE) + set(SYSTEM_SDL_REQUIRED REQUIRED) +endif() + +find_package(SDL2 QUIET ${SYSTEM_SDL_REQUIRED}) + +if(NOT SDL2_FOUND) + set(SDL2_INCLUDE_DIRS ${INTERNAL_SDL_DIR}/include) + + # On Windows and macOS we have internal SDL binaries we can use + if(WIN32) + if(ARCH STREQUAL "x86_64") + set(LIB_DIR ${SOURCE_DIR}/thirdparty/libs/win64) + elseif(ARCH STREQUAL "x86") + set(LIB_DIR ${SOURCE_DIR}/thirdparty/libs/win32) + else() + message(FATAL_ERROR "Unknown ARCH") + endif() + + if(MINGW) + set(SDL2_LIBRARIES + ${LIB_DIR}/libSDL2main.a + ${LIB_DIR}/libSDL2.dll.a) + elseif(MSVC) + set(SDL2_LIBRARIES + ${LIB_DIR}/SDL2main.lib + ${LIB_DIR}/SDL2.lib) + endif() + + list(APPEND CLIENT_DEPLOY_LIBRARIES ${LIB_DIR}/SDL2.dll) + elseif(APPLE) + set(SDL2_LIBRARIES + ${SOURCE_DIR}/thirdparty/libs/macos/libSDL2main.a + ${SOURCE_DIR}/thirdparty/libs/macos/libSDL2-2.0.0.dylib) + list(APPEND CLIENT_DEPLOY_LIBRARIES + ${SOURCE_DIR}/thirdparty/libs/macos/libSDL2-2.0.0.dylib) + else() + message(FATAL_ERROR "SDL2 not found and no internal binaries available") + endif() +endif() + +list(APPEND CLIENT_LIBRARIES ${SDL2_LIBRARIES}) +list(APPEND CLIENT_INCLUDE_DIRS ${SDL2_INCLUDE_DIRS}) +list(APPEND CLIENT_COMPILE_OPTIONS ${SDL2_CFLAGS_OTHER}) +list(APPEND RENDERER_LIBRARIES ${SDL2_LIBRARIES}) +list(APPEND RENDERER_INCLUDE_DIRS ${SDL2_INCLUDE_DIRS}) +list(APPEND RENDERER_COMPILE_OPTIONS ${SDL2_CFLAGS_OTHER}) diff --git a/cmake/libraries/vorbis.cmake b/cmake/libraries/vorbis.cmake new file mode 100644 index 00000000..d5424162 --- /dev/null +++ b/cmake/libraries/vorbis.cmake @@ -0,0 +1,22 @@ +if(NOT USE_CODEC_VORBIS) + return() +endif() + +include(utils/disable_warnings) + +set(INTERNAL_VORBIS_DIR ${SOURCE_DIR}/thirdparty/libvorbis-1.3.7) + +if(USE_INTERNAL_VORBIS) + file(GLOB_RECURSE VORBIS_SOURCES ${INTERNAL_VORBIS_DIR}/*.c) + disable_warnings(${VORBIS_SOURCES}) + set(VORBIS_INCLUDE_DIRS ${INTERNAL_VORBIS_DIR}/include ${INTERNAL_VORBIS_DIR}/lib) + set(VORBIS_DEFINITIONS USE_CODEC_VORBIS) + list(APPEND CLIENT_LIBRARY_SOURCES ${VORBIS_SOURCES}) +else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(VORBIS REQUIRED vorbis) +endif() + +list(APPEND CLIENT_LIBRARIES ${VORBIS_LIBRARIES}) +list(APPEND CLIENT_INCLUDE_DIRS ${VORBIS_INCLUDE_DIRS}) +list(APPEND CLIENT_DEFINITIONS ${VORBIS_DEFINITIONS}) diff --git a/cmake/libraries/zlib.cmake b/cmake/libraries/zlib.cmake new file mode 100644 index 00000000..44918e6c --- /dev/null +++ b/cmake/libraries/zlib.cmake @@ -0,0 +1,22 @@ +include(utils/disable_warnings) +include(utils/find_include_dirs) + +set(INTERNAL_ZLIB_DIR ${SOURCE_DIR}/thirdparty/zlib-1.3.1) + +if(USE_INTERNAL_ZLIB) + file(GLOB_RECURSE ZLIB_SOURCES ${INTERNAL_ZLIB_DIR}/*.c) + disable_warnings(ZLIB_SOURCES) + find_include_dirs(ZLIB_INCLUDE_DIRS ${ZLIB_SOURCES}) + set(ZLIB_DEFINITIONS NO_GZIP) + list(APPEND SERVER_LIBRARY_SOURCES ${ZLIB_SOURCES}) + list(APPEND CLIENT_LIBRARY_SOURCES ${ZLIB_SOURCES}) +else() + find_package(ZLIB REQUIRED) +endif() + +list(APPEND SERVER_LIBRARIES ${ZLIB_LIBRARIES}) +list(APPEND SERVER_INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS}) +list(APPEND SERVER_DEFINITIONS ${ZLIB_DEFINITIONS}) +list(APPEND CLIENT_LIBRARIES ${ZLIB_LIBRARIES}) +list(APPEND CLIENT_INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS}) +list(APPEND CLIENT_DEFINITIONS ${ZLIB_DEFINITIONS}) diff --git a/cmake/missionpack.cmake b/cmake/missionpack.cmake new file mode 100644 index 00000000..34f94577 --- /dev/null +++ b/cmake/missionpack.cmake @@ -0,0 +1,72 @@ +if(NOT BUILD_GAME_LIBRARIES AND NOT BUILD_GAME_QVMS) + return() +endif() + +include(utils/qvm_tools) +include(utils/set_output_dirs) + +set(MPCGAME_SOURCES + ${SOURCE_DIR}/cgame/cg_newdraw.c + ${SOURCE_DIR}/ui/ui_shared.c +) + +set(MPUI_SOURCES + ${SOURCE_DIR}/ui/ui_main.c + ${SOURCE_DIR}/ui/ui_atoms.c + ${SOURCE_DIR}/ui/ui_gameinfo.c + ${SOURCE_DIR}/ui/ui_players.c + ${SOURCE_DIR}/ui/ui_shared.c + ${SOURCE_DIR}/game/bg_misc.c + ${SOURCE_DIR}/game/bg_lib.c +) + +set(MISSIONPACK "missionpack") + +set(CGAME_SOURCES_MISSIONPACK ${CGAME_SOURCES} ${MPCGAME_SOURCES} ${GAME_MODULE_SHARED_SOURCES}) +set(GAME_SOURCES_MISSIONPACK ${GAME_SOURCES} ${GAME_MODULE_SHARED_SOURCES}) +set(UI_SOURCES_MISSIONPACK ${MPUI_SOURCES} ${GAME_MODULE_SHARED_SOURCES}) + +if(BUILD_GAME_LIBRARIES) + set(CGAME_MODULE_BINARY_MISSIONPACK ${CGAME_MODULE_BINARY}_${MISSIONPACK}) + set(GAME_MODULE_BINARY_MISSIONPACK ${GAME_MODULE_BINARY}_${MISSIONPACK}) + set(UI_MODULE_BINARY_MISSIONPACK ${UI_MODULE_BINARY}_${MISSIONPACK}) + + add_library( ${CGAME_MODULE_BINARY_MISSIONPACK} SHARED ${CGAME_SOURCES_MISSIONPACK} ${CGAME_BINARY_SOURCES}) + target_compile_definitions( ${CGAME_MODULE_BINARY_MISSIONPACK} PRIVATE CGAME MISSIONPACK) + set_target_properties( ${CGAME_MODULE_BINARY_MISSIONPACK} PROPERTIES OUTPUT_NAME ${CGAME_MODULE_BINARY}) + set_output_dirs( ${CGAME_MODULE_BINARY_MISSIONPACK} SUBDIRECTORY ${MISSIONPACK}) + + add_library( ${GAME_MODULE_BINARY_MISSIONPACK} SHARED ${GAME_SOURCES_MISSIONPACK} ${GAME_BINARY_SOURCES}) + target_compile_definitions( ${GAME_MODULE_BINARY_MISSIONPACK} PRIVATE QAGAME MISSIONPACK) + set_target_properties( ${GAME_MODULE_BINARY_MISSIONPACK} PROPERTIES OUTPUT_NAME ${GAME_MODULE_BINARY}) + set_output_dirs( ${GAME_MODULE_BINARY_MISSIONPACK} SUBDIRECTORY ${MISSIONPACK}) + + add_library( ${UI_MODULE_BINARY_MISSIONPACK} SHARED ${UI_SOURCES_MISSIONPACK} ${UI_BINARY_SOURCES}) + target_compile_definitions( ${UI_MODULE_BINARY_MISSIONPACK} PRIVATE UI MISSIONPACK) + set_target_properties( ${UI_MODULE_BINARY_MISSIONPACK} PROPERTIES OUTPUT_NAME ${UI_MODULE_BINARY}) + set_output_dirs( ${UI_MODULE_BINARY_MISSIONPACK} SUBDIRECTORY ${MISSIONPACK}) +endif() + +if(BUILD_GAME_QVMS) + set(CGAME_MODULE_QVM_MISSIONPACK ${CGAME_MODULE}qvm_${MISSIONPACK}) + set(GAME_MODULE_QVM_MISSIONPACK ${GAME_MODULE}qvm_${MISSIONPACK}) + set(UI_MODULE_QVM_MISSIONPACK ${UI_MODULE}qvm_${MISSIONPACK}) + + add_qvm(${CGAME_MODULE_QVM_MISSIONPACK} + DEFINITIONS CGAME MISSIONPACK + OUTPUT_NAME ${CGAME_MODULE} + OUTPUT_DIRECTORY ${MISSIONPACK}/vm + SOURCES ${CGAME_SOURCES_MISSIONPACK} ${CGAME_QVM_SOURCES}) + + add_qvm(${GAME_MODULE_QVM_MISSIONPACK} + DEFINITIONS QAGAME MISSIONPACK + OUTPUT_NAME ${GAME_MODULE} + OUTPUT_DIRECTORY ${MISSIONPACK}/vm + SOURCES ${GAME_SOURCES_MISSIONPACK} ${GAME_QVM_SOURCES}) + + add_qvm(${UI_MODULE_QVM_MISSIONPACK} + DEFINITIONS UI MISSIONPACK + OUTPUT_NAME ${UI_MODULE} + OUTPUT_DIRECTORY ${MISSIONPACK}/vm + SOURCES ${UI_SOURCES_MISSIONPACK} ${UI_QVM_SOURCES}) +endif() diff --git a/cmake/platforms/all.cmake b/cmake/platforms/all.cmake new file mode 100644 index 00000000..7d8ad9a9 --- /dev/null +++ b/cmake/platforms/all.cmake @@ -0,0 +1,4 @@ +include(platforms/emscripten) +include(platforms/macos) +include(platforms/unix) +include(platforms/windows) diff --git a/cmake/platforms/emscripten.cmake b/cmake/platforms/emscripten.cmake new file mode 100644 index 00000000..03ba18f6 --- /dev/null +++ b/cmake/platforms/emscripten.cmake @@ -0,0 +1,50 @@ +# Emscripten specific settings + +if(NOT EMSCRIPTEN) + return() +endif() + +set(CMAKE_EXECUTABLE_SUFFIX ".js") +set(CMAKE_SHARED_LIBRARY_SUFFIX ".wasm") + +# Disable options that don't make sense for emscripten +set(BUILD_SERVER OFF CACHE INTERNAL "") +set(BUILD_RENDERER_GL1 OFF CACHE INTERNAL "") +set(USE_RENDERER_DLOPEN OFF CACHE INTERNAL "") +set(USE_OPENAL_DLOPEN OFF CACHE INTERNAL "") +set(BUILD_GAME_LIBRARIES OFF CACHE INTERNAL "") +set(USE_HTTP OFF CACHE INTERNAL "") + +list(APPEND CLIENT_COMPILE_OPTIONS -sUSE_SDL=2) + +list(APPEND CLIENT_LINK_OPTIONS + -sTOTAL_MEMORY=256MB + -sSTACK_SIZE=5MB + -sMIN_WEBGL_VERSION=1 + -sMAX_WEBGL_VERSION=2 + -sEXPORTED_RUNTIME_METHODS=FS,addRunDependency,removeRunDependency + -sEXIT_RUNTIME=1 + -sEXPORT_ES6 + -sEXPORT_NAME=${CLIENT_NAME} +) + +option(EMSCRIPTEN_PRELOAD_FILE "Preload game files into .data file" OFF) + +if(EMSCRIPTEN_PRELOAD_FILE) + if(NOT EXISTS "${CMAKE_SOURCE_DIR}/${BASEGAME}") + message(FATAL_ERROR "No files in '${BASEGAME}' directory for emscripten to preload.") + endif() + list(APPEND CLIENT_LINK_OPTIONS "--preload-file ${BASEGAME}") +endif() + +set(POST_CLIENT_CONFIGURE_FUNCTION deploy_shell_files) + +function(deploy_shell_files) + configure_file(${SOURCE_DIR}/web/client.html.in + ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${CLIENT_NAME}.html @ONLY) + + if(NOT EMSCRIPTEN_PRELOAD_FILE) + configure_file(${SOURCE_DIR}/web/client-config.json + ${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${CLIENT_NAME}-config.json COPYONLY) + endif() +endfunction() diff --git a/cmake/platforms/macos.cmake b/cmake/platforms/macos.cmake new file mode 100644 index 00000000..5e6a998d --- /dev/null +++ b/cmake/platforms/macos.cmake @@ -0,0 +1,80 @@ +# macOS specific settings + +if(NOT APPLE) + return() +endif() + +# Including the arch in the filename doesn't really make sense +# on macOS where we're building Universal Binaries +set(USE_ARCHLESS_FILENAMES ON CACHE INTERNAL "") + +option(BUILD_MACOS_APP "Deploy as a macOS .app" ON) + +enable_language(OBJC) + +list(APPEND SYSTEM_PLATFORM_SOURCES ${SOURCE_DIR}/sys/sys_osx.m) + +list(APPEND COMMON_LIBRARIES "-framework Cocoa") +list(APPEND CLIENT_LIBRARIES "-framework IOKit") +list(APPEND RENDERER_LIBRARIES "-framework OpenGL") + +set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0) +set(CMAKE_OSX_ARCHITECTURES arm64;x86_64) + +if(BUILD_MACOS_APP) + set(CLIENT_EXECUTABLE_OPTIONS MACOSX_BUNDLE) + set(POST_CLIENT_CONFIGURE_FUNCTION finish_macos_app) +endif() + +function(finish_macos_app) + get_filename_component(MACOS_ICON_FILE ${MACOS_ICON_PATH} NAME) + + set(MACOS_APP_BUNDLE_NAME ${CLIENT_NAME}) + set(MACOS_APP_EXECUTABLE_NAME ${CLIENT_BINARY}) + set(MACOS_APP_GUI_IDENTIFIER ${MACOS_BUNDLE_ID}) + set(MACOS_APP_ICON_FILE ${MACOS_ICON_FILE}) + set(MACOS_APP_SHORT_VERSION_STRING ${PRODUCT_VERSION}) + set(MACOS_APP_BUNDLE_VERSION ${PRODUCT_VERSION}) + set(MACOS_APP_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET}) + set(MACOS_APP_COPYRIGHT ${COPYRIGHT}) + + if(PROTOCOL_HANDLER_SCHEME) + set(MACOS_APP_PLIST_URL_TYPES + "CFBundleURLTypes + + + CFBundleURLName + ${MACOS_APP_BUNDLE_NAME} + CFBundleURLSchemes + + ${PROTOCOL_HANDLER_SCHEME} + + + ") + else() + set(MACOS_APP_PLIST_URL_TYPES "") + endif() + + configure_file(${CMAKE_SOURCE_DIR}/cmake/Info.plist.in + ${CMAKE_BINARY_DIR}/Info.plist @ONLY) + + set_target_properties(${CLIENT_BINARY} PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_BINARY_DIR}/Info.plist) + + set(RESOURCES_DIR $/../Resources) + add_custom_command(TARGET ${CLIENT_BINARY} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${RESOURCES_DIR} + COMMAND ${CMAKE_COMMAND} -E copy ${MACOS_ICON_PATH} ${RESOURCES_DIR}) + + if(USE_RENDERER_DLOPEN) + set(MACOS_APP_BINARY_DIR ${CLIENT_BINARY}.app/Contents/MacOS) + + if(BUILD_RENDERER_GL1) + set_output_dirs(${RENDERER_GL1_BINARY} SUBDIRECTORY ${MACOS_APP_BINARY_DIR}) + endif() + + if(BUILD_RENDERER_GL2) + set_output_dirs(${RENDERER_GL2_BINARY} SUBDIRECTORY ${MACOS_APP_BINARY_DIR}) + endif() + endif() +endfunction() diff --git a/cmake/platforms/unix.cmake b/cmake/platforms/unix.cmake new file mode 100644 index 00000000..97c7aeb7 --- /dev/null +++ b/cmake/platforms/unix.cmake @@ -0,0 +1,21 @@ +# Unix specific settings (this includes macOS and emscripten) + +if(NOT UNIX) + return() +endif() + +list(APPEND SYSTEM_PLATFORM_SOURCES ${SOURCE_DIR}/sys/sys_unix.c) + +if(EMSCRIPTEN) + list(APPEND SYSTEM_PLATFORM_SOURCES ${SOURCE_DIR}/sys/con_passive.c) +else() + list(APPEND SYSTEM_PLATFORM_SOURCES ${SOURCE_DIR}/sys/con_tty.c) +endif() + +if(USE_HTTP) + list(APPEND CLIENT_PLATFORM_SOURCES ${SOURCE_DIR}/client/cl_http_curl.c) +endif() + +list(APPEND COMMON_LIBRARIES dl m) + +list(APPEND CLIENT_DEFINITIONS USE_ICON) diff --git a/cmake/platforms/windows.cmake b/cmake/platforms/windows.cmake new file mode 100644 index 00000000..15de089d --- /dev/null +++ b/cmake/platforms/windows.cmake @@ -0,0 +1,35 @@ +# Windows specific settings + +if(NOT WIN32) + return() +endif() + +list(APPEND SYSTEM_PLATFORM_SOURCES + ${SOURCE_DIR}/sys/sys_win32.c + ${SOURCE_DIR}/sys/con_passive.c + ${SOURCE_DIR}/sys/win_resource.rc +) + +if(USE_HTTP) + list(APPEND CLIENT_PLATFORM_SOURCES ${SOURCE_DIR}/client/cl_http_windows.c) + list(APPEND CLIENT_LIBRARIES wininet) +endif() + +list(APPEND COMMON_LIBRARIES ws2_32 winmm psapi) + +if(MINGW) + list(APPEND COMMON_LIBRARIES mingw32) +endif() + +list(APPEND CLIENT_DEFINITIONS USE_ICON) + +set_source_files_properties(${SOURCE_DIR}/sys/win_resource.rc + PROPERTIES COMPILE_DEFINITIONS WINDOWS_ICON_PATH=${WINDOWS_ICON_PATH}) + +if(MSVC) + # We have our own manifest, disable auto creation + list(APPEND SERVER_LINK_OPTIONS "/MANIFEST:NO") + list(APPEND CLIENT_LINK_OPTIONS "/MANIFEST:NO") +endif() + +set(CLIENT_EXECUTABLE_OPTIONS WIN32) diff --git a/cmake/renderer_common.cmake b/cmake/renderer_common.cmake new file mode 100644 index 00000000..01106c61 --- /dev/null +++ b/cmake/renderer_common.cmake @@ -0,0 +1,37 @@ +include_guard(GLOBAL) + +set(RENDERER_COMMON_SOURCES + ${SOURCE_DIR}/renderercommon/tr_font.c + ${SOURCE_DIR}/renderercommon/tr_image_bmp.c + ${SOURCE_DIR}/renderercommon/tr_image_jpg.c + ${SOURCE_DIR}/renderercommon/tr_image_pcx.c + ${SOURCE_DIR}/renderercommon/tr_image_png.c + ${SOURCE_DIR}/renderercommon/tr_image_tga.c + ${SOURCE_DIR}/renderercommon/tr_noise.c + ${SOURCE_DIR}/renderercommon/puff.c +) + +set(SDL_RENDERER_SOURCES + ${SOURCE_DIR}/sdl/sdl_gamma.c + ${SOURCE_DIR}/sdl/sdl_glimp.c +) + +set(DYNAMIC_RENDERER_SOURCES + ${SOURCE_DIR}/renderercommon/tr_subs.c + ${SOURCE_DIR}/qcommon/q_shared.c + ${SOURCE_DIR}/qcommon/q_math.c +) + +if(USE_FREETYPE) + list(APPEND RENDERER_DEFINITIONS BUILD_FREETYPE) +endif() + +if(USE_RENDERER_DLOPEN) + list(APPEND RENDERER_DEFINITIONS USE_RENDERER_DLOPEN) +elseif(BUILD_RENDERER_GL1 AND BUILD_RENDERER_GL2) + message(FATAL_ERROR "Multiple static renderers enabled; choose one") +elseif(NOT BUILD_RENDERER_GL1 AND NOT BUILD_RENDERER_GL2) + message(FATAL_ERROR "Zero static renderers enabled; choose one") +endif() + +list(APPEND RENDERER_LIBRARIES ${COMMON_LIBRARIES}) diff --git a/cmake/renderer_gl1.cmake b/cmake/renderer_gl1.cmake new file mode 100644 index 00000000..8f1b93f0 --- /dev/null +++ b/cmake/renderer_gl1.cmake @@ -0,0 +1,62 @@ +if(NOT BUILD_RENDERER_GL1) + return() +endif() + +include(utils/arch) +include(utils/set_output_dirs) +include(renderer_common) + +set(RENDERER_GL1_SOURCES + ${SOURCE_DIR}/renderergl1/tr_altivec.c + ${SOURCE_DIR}/renderergl1/tr_animation.c + ${SOURCE_DIR}/renderergl1/tr_backend.c + ${SOURCE_DIR}/renderergl1/tr_bsp.c + ${SOURCE_DIR}/renderergl1/tr_cmds.c + ${SOURCE_DIR}/renderergl1/tr_curve.c + ${SOURCE_DIR}/renderergl1/tr_flares.c + ${SOURCE_DIR}/renderergl1/tr_image.c + ${SOURCE_DIR}/renderergl1/tr_init.c + ${SOURCE_DIR}/renderergl1/tr_light.c + ${SOURCE_DIR}/renderergl1/tr_main.c + ${SOURCE_DIR}/renderergl1/tr_marks.c + ${SOURCE_DIR}/renderergl1/tr_mesh.c + ${SOURCE_DIR}/renderergl1/tr_model.c + ${SOURCE_DIR}/renderergl1/tr_model_iqm.c + ${SOURCE_DIR}/renderergl1/tr_scene.c + ${SOURCE_DIR}/renderergl1/tr_shade.c + ${SOURCE_DIR}/renderergl1/tr_shade_calc.c + ${SOURCE_DIR}/renderergl1/tr_shader.c + ${SOURCE_DIR}/renderergl1/tr_shadows.c + ${SOURCE_DIR}/renderergl1/tr_sky.c + ${SOURCE_DIR}/renderergl1/tr_surface.c + ${SOURCE_DIR}/renderergl1/tr_world.c +) + +set(RENDERER_GL1_BASENAME renderer_opengl1) + +if(USE_ARCHLESS_FILENAMES) + set(RENDERER_GL1_BINARY ${RENDERER_GL1_BASENAME}) + list(APPEND RENDERER_DEFINITIONS USE_ARCHLESS_FILENAMES) +else() + set(RENDERER_GL1_BINARY ${RENDERER_GL1_BASENAME}_${ARCH}) +endif() + +list(APPEND RENDERER_GL1_BINARY_SOURCES + ${RENDERER_COMMON_SOURCES} + ${RENDERER_GL1_SOURCES} + ${SDL_RENDERER_SOURCES} + ${RENDERER_LIBRARY_SOURCES}) + +if(USE_RENDERER_DLOPEN) + list(APPEND RENDERER_GL1_BINARY_SOURCES ${DYNAMIC_RENDERER_SOURCES}) + + add_library(${RENDERER_GL1_BINARY} SHARED ${RENDERER_GL1_BINARY_SOURCES}) + + target_link_libraries( ${RENDERER_GL1_BINARY} PRIVATE ${RENDERER_LIBRARIES}) + target_include_directories( ${RENDERER_GL1_BINARY} PRIVATE ${RENDERER_INCLUDE_DIRS}) + target_compile_definitions( ${RENDERER_GL1_BINARY} PRIVATE ${RENDERER_DEFINITIONS}) + target_compile_options( ${RENDERER_GL1_BINARY} PRIVATE ${RENDERER_COMPILE_OPTIONS}) + target_link_options( ${RENDERER_GL1_BINARY} PRIVATE ${RENDERER_LINK_OPTIONS}) + + set_output_dirs(${RENDERER_GL1_BINARY}) +endif() diff --git a/cmake/renderer_gl2.cmake b/cmake/renderer_gl2.cmake new file mode 100644 index 00000000..78daec11 --- /dev/null +++ b/cmake/renderer_gl2.cmake @@ -0,0 +1,94 @@ +if(NOT BUILD_RENDERER_GL2) + return() +endif() + +include(utils/arch) +include(utils/set_output_dirs) +include(renderer_common) + +set(RENDERER_GL2_SOURCES + ${SOURCE_DIR}/renderergl2/tr_animation.c + ${SOURCE_DIR}/renderergl2/tr_backend.c + ${SOURCE_DIR}/renderergl2/tr_bsp.c + ${SOURCE_DIR}/renderergl2/tr_cmds.c + ${SOURCE_DIR}/renderergl2/tr_curve.c + ${SOURCE_DIR}/renderergl2/tr_dsa.c + ${SOURCE_DIR}/renderergl2/tr_extramath.c + ${SOURCE_DIR}/renderergl2/tr_extensions.c + ${SOURCE_DIR}/renderergl2/tr_fbo.c + ${SOURCE_DIR}/renderergl2/tr_flares.c + ${SOURCE_DIR}/renderergl2/tr_glsl.c + ${SOURCE_DIR}/renderergl2/tr_image.c + ${SOURCE_DIR}/renderergl2/tr_image_dds.c + ${SOURCE_DIR}/renderergl2/tr_init.c + ${SOURCE_DIR}/renderergl2/tr_light.c + ${SOURCE_DIR}/renderergl2/tr_main.c + ${SOURCE_DIR}/renderergl2/tr_marks.c + ${SOURCE_DIR}/renderergl2/tr_mesh.c + ${SOURCE_DIR}/renderergl2/tr_model.c + ${SOURCE_DIR}/renderergl2/tr_model_iqm.c + ${SOURCE_DIR}/renderergl2/tr_postprocess.c + ${SOURCE_DIR}/renderergl2/tr_scene.c + ${SOURCE_DIR}/renderergl2/tr_shade.c + ${SOURCE_DIR}/renderergl2/tr_shade_calc.c + ${SOURCE_DIR}/renderergl2/tr_shader.c + ${SOURCE_DIR}/renderergl2/tr_shadows.c + ${SOURCE_DIR}/renderergl2/tr_sky.c + ${SOURCE_DIR}/renderergl2/tr_surface.c + ${SOURCE_DIR}/renderergl2/tr_vbo.c + ${SOURCE_DIR}/renderergl2/tr_world.c +) + +file(GLOB RENDERER_GL2_SHADER_SOURCES ${SOURCE_DIR}/renderergl2/glsl/*.glsl) + +set(SHADERS_DIR ${CMAKE_BINARY_DIR}/shaders.dir) +file(MAKE_DIRECTORY ${SHADERS_DIR}) + +foreach(SHADER_FILE IN LISTS RENDERER_GL2_SHADER_SOURCES) + get_filename_component(SHADER_NAME ${SHADER_FILE} NAME_WE) + set(SHADER_C_FILE ${SHADERS_DIR}/${SHADER_NAME}.c) + + string(REPLACE "${CMAKE_BINARY_DIR}/" "" SHADER_C_FILE_COMMENT ${SHADER_C_FILE}) + + add_custom_command( + OUTPUT ${SHADER_C_FILE} + COMMAND ${CMAKE_COMMAND} + -DINPUT_FILE=${SHADER_FILE} + -DOUTPUT_FILE=${SHADER_C_FILE} + -DSHADER_NAME=${SHADER_NAME} + -P ${CMAKE_SOURCE_DIR}/cmake/utils/stringify_shader.cmake + DEPENDS ${SHADER_FILE} + COMMENT "Stringify shader ${SHADER_C_FILE_COMMENT}") + + list(APPEND RENDERER_GL2_SHADER_C_SOURCES ${SHADER_C_FILE}) +endforeach() + +set(RENDERER_GL2_BASENAME renderer_opengl2) + +if(USE_ARCHLESS_FILENAMES) + set(RENDERER_GL2_BINARY ${RENDERER_GL2_BASENAME}) + list(APPEND RENDERER_DEFINITIONS USE_ARCHLESS_FILENAMES) +else() + set(RENDERER_GL2_BINARY ${RENDERER_GL2_BASENAME}_${ARCH}) +endif() + +list(APPEND RENDERER_GL2_BINARY_SOURCES + ${RENDERER_COMMON_SOURCES} + ${RENDERER_GL2_SOURCES} + ${RENDERER_GL2_SHADER_C_SOURCES} + ${SDL_RENDERER_SOURCES} + ${RENDERER_LIBRARY_SOURCES}) + +if(USE_RENDERER_DLOPEN) + list(APPEND RENDERER_GL2_BINARY_SOURCES ${DYNAMIC_RENDERER_SOURCES}) + + add_library(${RENDERER_GL2_BINARY} SHARED ${RENDERER_GL2_BINARY_SOURCES}) + + target_link_libraries( ${RENDERER_GL2_BINARY} PRIVATE ${RENDERER_LIBRARIES}) + target_include_directories( ${RENDERER_GL2_BINARY} PRIVATE ${RENDERER_INCLUDE_DIRS}) + target_compile_definitions( ${RENDERER_GL2_BINARY} PRIVATE ${RENDERER_DEFINITIONS}) + target_compile_options( ${RENDERER_GL2_BINARY} PRIVATE ${RENDERER_COMPILE_OPTIONS}) + target_link_options( ${RENDERER_GL2_BINARY} PRIVATE ${RENDERER_LINK_OPTIONS}) + + set_output_dirs(${RENDERER_GL2_BINARY}) +endif() diff --git a/cmake/server.cmake b/cmake/server.cmake new file mode 100644 index 00000000..5a06e42d --- /dev/null +++ b/cmake/server.cmake @@ -0,0 +1,54 @@ + +if(NOT BUILD_SERVER) + return() +endif() + +include(utils/set_output_dirs) +include(shared_sources) + +set(NULL_SOURCES + ${SOURCE_DIR}/null/null_client.c + ${SOURCE_DIR}/null/null_input.c + ${SOURCE_DIR}/null/null_snddma.c +) + +if(USE_ARCHLESS_FILENAMES) + set(SERVER_BINARY ${SERVER_NAME}) + list(APPEND SERVER_DEFINITIONS USE_ARCHLESS_FILENAMES) +else() + set(SERVER_BINARY ${SERVER_NAME}.${ARCH}) +endif() + +list(APPEND SERVER_DEFINITIONS DEDICATED) +list(APPEND SERVER_DEFINITIONS BOTLIB) + +if(BUILD_STANDALONE) + list(APPEND SERVER_DEFINITIONS STANDALONE) +endif() + +if(USE_VOIP) + list(APPEND SERVER_DEFINITIONS USE_VOIP) +endif() + +list(APPEND SERVER_BINARY_SOURCES + ${SERVER_SOURCES} + ${NULL_SOURCES} + ${COMMON_SOURCES} + ${BOTLIB_SOURCES} + ${SYSTEM_SOURCES} + ${ASM_SOURCES} + ${SERVER_LIBRARY_SOURCES}) + +add_executable(${SERVER_BINARY} ${SERVER_EXECUTABLE_OPTIONS} ${SERVER_BINARY_SOURCES}) + +target_include_directories( ${SERVER_BINARY} PRIVATE ${SERVER_INCLUDE_DIRS}) +target_compile_definitions( ${SERVER_BINARY} PRIVATE ${SERVER_DEFINITIONS}) +target_compile_options( ${SERVER_BINARY} PRIVATE ${SERVER_COMPILE_OPTIONS}) +target_link_libraries( ${SERVER_BINARY} PRIVATE ${COMMON_LIBRARIES} ${SERVER_LIBRARIES}) +target_link_options( ${SERVER_BINARY} PRIVATE ${SERVER_LINK_OPTIONS}) + +set_output_dirs(${SERVER_BINARY}) + +if(POST_SERVER_CONFIGURE_FUNCTION) + cmake_language(CALL ${POST_SERVER_CONFIGURE_FUNCTION}) +endif() diff --git a/cmake/shared_sources.cmake b/cmake/shared_sources.cmake new file mode 100644 index 00000000..b385d663 --- /dev/null +++ b/cmake/shared_sources.cmake @@ -0,0 +1,104 @@ +include_guard(GLOBAL) + +include(utils/add_git_dependency) +include(utils/arch) +include(utils/disable_warnings) + +set(COMMON_SOURCES + ${SOURCE_DIR}/qcommon/cm_load.c + ${SOURCE_DIR}/qcommon/cm_patch.c + ${SOURCE_DIR}/qcommon/cm_polylib.c + ${SOURCE_DIR}/qcommon/cm_test.c + ${SOURCE_DIR}/qcommon/cm_trace.c + ${SOURCE_DIR}/qcommon/cmd.c + ${SOURCE_DIR}/qcommon/common.c + ${SOURCE_DIR}/qcommon/cvar.c + ${SOURCE_DIR}/qcommon/files.c + ${SOURCE_DIR}/qcommon/md4.c + ${SOURCE_DIR}/qcommon/md5.c + ${SOURCE_DIR}/qcommon/msg.c + ${SOURCE_DIR}/qcommon/net_chan.c + ${SOURCE_DIR}/qcommon/net_ip.c + ${SOURCE_DIR}/qcommon/huffman.c + ${SOURCE_DIR}/qcommon/q_math.c + ${SOURCE_DIR}/qcommon/q_shared.c + ${SOURCE_DIR}/qcommon/unzip.c + ${SOURCE_DIR}/qcommon/ioapi.c + ${SOURCE_DIR}/qcommon/vm.c + ${SOURCE_DIR}/qcommon/vm_interpreted.c +) + +disable_warnings( + ${SOURCE_DIR}/qcommon/unzip.c + ${SOURCE_DIR}/qcommon/ioapi.c +) + +add_git_dependency(${SOURCE_DIR}/qcommon/common.c) + +if(ARCH MATCHES "x86" OR ARCH MATCHES "x86_64") + list(APPEND COMMON_SOURCES + ${SOURCE_DIR}/qcommon/vm_x86.c + ) +elseif(ARCH MATCHES "ppc" OR ARCH MATCHES "ppc64") + list(APPEND COMMON_SOURCES + ${SOURCE_DIR}/qcommon/vm_powerpc.c + ${SOURCE_DIR}/qcommon/vm_powerpc_asm.c + ) +elseif(ARCH MATCHES "arm") + list(APPEND COMMON_SOURCES + ${SOURCE_DIR}/qcommon/vm_armv71.c + ) +else() + list(APPEND SERVER_DEFINITIONS NO_VM_COMPILED) + list(APPEND CLIENT_DEFINITIONS NO_VM_COMPILED) +endif() + +set(SYSTEM_SOURCES + ${SOURCE_DIR}/sys/con_log.c + ${SOURCE_DIR}/sys/sys_autoupdater.c + ${SOURCE_DIR}/sys/sys_main.c + ${SYSTEM_PLATFORM_SOURCES} +) + +set(SERVER_SOURCES + ${SOURCE_DIR}/server/sv_bot.c + ${SOURCE_DIR}/server/sv_client.c + ${SOURCE_DIR}/server/sv_ccmds.c + ${SOURCE_DIR}/server/sv_game.c + ${SOURCE_DIR}/server/sv_init.c + ${SOURCE_DIR}/server/sv_main.c + ${SOURCE_DIR}/server/sv_net_chan.c + ${SOURCE_DIR}/server/sv_snapshot.c + ${SOURCE_DIR}/server/sv_world.c +) + +set(BOTLIB_SOURCES + ${SOURCE_DIR}/botlib/be_aas_bspq3.c + ${SOURCE_DIR}/botlib/be_aas_cluster.c + ${SOURCE_DIR}/botlib/be_aas_debug.c + ${SOURCE_DIR}/botlib/be_aas_entity.c + ${SOURCE_DIR}/botlib/be_aas_file.c + ${SOURCE_DIR}/botlib/be_aas_main.c + ${SOURCE_DIR}/botlib/be_aas_move.c + ${SOURCE_DIR}/botlib/be_aas_optimize.c + ${SOURCE_DIR}/botlib/be_aas_reach.c + ${SOURCE_DIR}/botlib/be_aas_route.c + ${SOURCE_DIR}/botlib/be_aas_routealt.c + ${SOURCE_DIR}/botlib/be_aas_sample.c + ${SOURCE_DIR}/botlib/be_ai_char.c + ${SOURCE_DIR}/botlib/be_ai_chat.c + ${SOURCE_DIR}/botlib/be_ai_gen.c + ${SOURCE_DIR}/botlib/be_ai_goal.c + ${SOURCE_DIR}/botlib/be_ai_move.c + ${SOURCE_DIR}/botlib/be_ai_weap.c + ${SOURCE_DIR}/botlib/be_ai_weight.c + ${SOURCE_DIR}/botlib/be_ea.c + ${SOURCE_DIR}/botlib/be_interface.c + ${SOURCE_DIR}/botlib/l_crc.c + ${SOURCE_DIR}/botlib/l_libvar.c + ${SOURCE_DIR}/botlib/l_log.c + ${SOURCE_DIR}/botlib/l_memory.c + ${SOURCE_DIR}/botlib/l_precomp.c + ${SOURCE_DIR}/botlib/l_script.c + ${SOURCE_DIR}/botlib/l_struct.c +) diff --git a/cmake/tools/CMakeLists.txt b/cmake/tools/CMakeLists.txt new file mode 100644 index 00000000..4fbf0dd9 --- /dev/null +++ b/cmake/tools/CMakeLists.txt @@ -0,0 +1,86 @@ +cmake_minimum_required(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION}) +project(qvm_tools LANGUAGES C) + +include(utils/set_output_dirs) + +set(Q3ASM_SOURCES + ${SOURCE_DIR}/tools/asm/q3asm.c + ${SOURCE_DIR}/tools/asm/cmdlib.c +) + +set(Q3LCC_SOURCES + ${SOURCE_DIR}/tools/lcc/etc/lcc.c + ${SOURCE_DIR}/tools/lcc/etc/bytecode.c +) + +set(Q3RCC_SOURCES + ${SOURCE_DIR}/tools/lcc/src/alloc.c + ${SOURCE_DIR}/tools/lcc/src/bind.c + ${SOURCE_DIR}/tools/lcc/src/bytecode.c + ${SOURCE_DIR}/tools/lcc/src/dag.c + ${SOURCE_DIR}/tools/lcc/src/decl.c + ${SOURCE_DIR}/tools/lcc/src/enode.c + ${SOURCE_DIR}/tools/lcc/src/error.c + ${SOURCE_DIR}/tools/lcc/src/event.c + ${SOURCE_DIR}/tools/lcc/src/expr.c + ${SOURCE_DIR}/tools/lcc/src/gen.c + ${SOURCE_DIR}/tools/lcc/src/init.c + ${SOURCE_DIR}/tools/lcc/src/inits.c + ${SOURCE_DIR}/tools/lcc/src/input.c + ${SOURCE_DIR}/tools/lcc/src/lex.c + ${SOURCE_DIR}/tools/lcc/src/list.c + ${SOURCE_DIR}/tools/lcc/src/main.c + ${SOURCE_DIR}/tools/lcc/src/null.c + ${SOURCE_DIR}/tools/lcc/src/output.c + ${SOURCE_DIR}/tools/lcc/src/prof.c + ${SOURCE_DIR}/tools/lcc/src/profio.c + ${SOURCE_DIR}/tools/lcc/src/simp.c + ${SOURCE_DIR}/tools/lcc/src/stmt.c + ${SOURCE_DIR}/tools/lcc/src/string.c + ${SOURCE_DIR}/tools/lcc/src/sym.c + ${SOURCE_DIR}/tools/lcc/src/symbolic.c + ${SOURCE_DIR}/tools/lcc/src/trace.c + ${SOURCE_DIR}/tools/lcc/src/tree.c + ${SOURCE_DIR}/tools/lcc/src/types.c +) + +set(Q3RCC_DAGCHECK_SOURCE ${SOURCE_DIR}/tools/lcc/src/dagcheck.md) + +set(Q3CPP_SOURCES + ${SOURCE_DIR}/tools/lcc/cpp/cpp.c + ${SOURCE_DIR}/tools/lcc/cpp/lex.c + ${SOURCE_DIR}/tools/lcc/cpp/nlist.c + ${SOURCE_DIR}/tools/lcc/cpp/tokens.c + ${SOURCE_DIR}/tools/lcc/cpp/macro.c + ${SOURCE_DIR}/tools/lcc/cpp/eval.c + ${SOURCE_DIR}/tools/lcc/cpp/include.c + ${SOURCE_DIR}/tools/lcc/cpp/hideset.c + ${SOURCE_DIR}/tools/lcc/cpp/getopt.c + ${SOURCE_DIR}/tools/lcc/cpp/unix.c +) + +set(LBURG_SOURCES + ${SOURCE_DIR}/tools/lcc/lburg/lburg.c + ${SOURCE_DIR}/tools/lcc/lburg/gram.c +) + +add_executable(q3asm ${Q3ASM_SOURCES}) +set_output_dirs(q3asm) +add_executable(q3lcc ${Q3LCC_SOURCES}) +set_output_dirs(q3lcc) +add_dependencies(q3lcc q3rcc q3cpp) + +add_executable(lburg ${LBURG_SOURCES}) +set_output_dirs(lburg) +set(DAGCHECK_C ${CMAKE_BINARY_DIR}/dagcheck.c) +add_custom_command( + OUTPUT ${DAGCHECK_C} + COMMAND lburg ${Q3RCC_DAGCHECK_SOURCE} ${DAGCHECK_C} + DEPENDS lburg ${Q3RCC_DAGCHECK_SOURCE}) + +add_executable(q3rcc ${Q3RCC_SOURCES} ${DAGCHECK_C}) +set_output_dirs(q3rcc) +target_include_directories(q3rcc PRIVATE ${SOURCE_DIR}/tools/lcc/src) + +add_executable(q3cpp ${Q3CPP_SOURCES}) +set_output_dirs(q3cpp) diff --git a/cmake/utils/add_git_dependency.cmake b/cmake/utils/add_git_dependency.cmake new file mode 100644 index 00000000..30cec055 --- /dev/null +++ b/cmake/utils/add_git_dependency.cmake @@ -0,0 +1,27 @@ +include_guard(GLOBAL) + +function(add_git_dependency SOURCE_FILE) + set(GIT_DIR ${CMAKE_SOURCE_DIR}/.git) + if(NOT EXISTS ${GIT_DIR}) + return() + endif() + + set(GIT_FILES) + list(APPEND GIT_FILES ${GIT_DIR}/HEAD) + list(APPEND GIT_FILES ${GIT_DIR}/packed-refs) + + file(READ ${GIT_DIR}/HEAD GIT_HEAD) + string(REGEX MATCH "^ref: (.+)$" HAVE_REF ${GIT_HEAD}) + if(HAVE_REF) + set(GIT_REF_PATH ${CMAKE_MATCH_1}) + string(STRIP ${GIT_REF_PATH} GIT_REF_PATH) + list(APPEND GIT_FILES ${GIT_DIR}/${GIT_REF_PATH}) + endif() + + foreach(GIT_FILE IN LISTS GIT_FILES) + if(EXISTS ${GIT_FILE}) + set_source_files_properties(${SOURCE_FILE} + PROPERTIES OBJECT_DEPENDS ${GIT_FILE}) + endif() + endforeach() +endfunction() diff --git a/cmake/utils/arch.cmake b/cmake/utils/arch.cmake new file mode 100644 index 00000000..4915a3f6 --- /dev/null +++ b/cmake/utils/arch.cmake @@ -0,0 +1,23 @@ +include_guard(GLOBAL) + +set(DETECT_ARCH_C ${CMAKE_BINARY_DIR}/detect_arch.c) + +file(WRITE ${DETECT_ARCH_C} +"#include \"${SOURCE_DIR}/qcommon/q_platform.h\" +#include +int main() +{ + puts(ARCH_STRING); + return 0; +} +") + +try_run(RUN_EXITCODE COMPILE_SUCCESS + ${CMAKE_BINARY_DIR} ${DETECT_ARCH_C} + RUN_OUTPUT_VARIABLE ARCH) + +string(STRIP ${ARCH} ARCH) + +if(NOT COMPILE_SUCCESS OR RUN_EXITCODE OR NOT ARCH) + message(FATAL_ERROR "Architecture detection failed") +endif() diff --git a/cmake/utils/disable_warnings.cmake b/cmake/utils/disable_warnings.cmake new file mode 100644 index 00000000..061a65af --- /dev/null +++ b/cmake/utils/disable_warnings.cmake @@ -0,0 +1,17 @@ +include_guard(GLOBAL) + +function(disable_warnings) + set(SOURCES ${ARGN}) + + foreach(FILE IN LISTS SOURCES) + if(MSVC) + # Annoyingly if you disable all warnings (/w) in combination with enabling + # some warnings, which we and/or CMake inevitably do, this causes a + # meta-warning D9025, so instead we have to individually disable them: + set_source_files_properties(${FILE} PROPERTIES COMPILE_FLAGS + "/wd4131 /wd4245 /wd4100 /wd4127 /wd4244 /wd4310 /wd4457 /wd4456 /wd4701 /wd4305 /wd4189 /wd4232") + else() + set_source_files_properties(${FILE} PROPERTIES COMPILE_FLAGS -w) + endif() + endforeach() +endfunction() diff --git a/cmake/utils/find_include_dirs.cmake b/cmake/utils/find_include_dirs.cmake new file mode 100644 index 00000000..4ea1aa9e --- /dev/null +++ b/cmake/utils/find_include_dirs.cmake @@ -0,0 +1,37 @@ +include_guard(GLOBAL) + +function(find_include_dirs OUT_VAR) + set(SOURCES ${ARGN}) + + # Get top most common directory prefix for all source files + set(COMMON_PATH "") + foreach(FILE IN LISTS SOURCES) + get_filename_component(DIR ${FILE} DIRECTORY) + file(REAL_PATH ${DIR} DIR) + if(COMMON_PATH STREQUAL "") + set(COMMON_PATH ${DIR}) + else() + string(LENGTH ${COMMON_PATH} PREFIX_LEN) + while(NOT ${DIR} MATCHES "^${COMMON_PATH}(/|$)" AND PREFIX_LEN GREATER 0) + string(SUBSTRING ${COMMON_PATH} 0 ${PREFIX_LEN} COMMON_PATH) + math(EXPR PREFIX_LEN "${PREFIX_LEN} - 1") + endwhile() + endif() + endforeach() + + if(NOT IS_DIRECTORY ${COMMON_PATH}) + message(FATAL_ERROR "Could not determine common directory for source files") + endif() + + # Recursively find directories that contain .h files under common directory + file(GLOB_RECURSE HEADER_FILES ${COMMON_PATH}/*.h) + set(INCLUDE_DIRS "") + foreach(HEADER_FILE IN LISTS HEADER_FILES) + get_filename_component(HEADER_DIR ${HEADER_FILE} DIRECTORY) + list(APPEND INCLUDE_DIRS ${HEADER_DIR}) + endforeach() + + list(REMOVE_DUPLICATES INCLUDE_DIRS) + + set(${OUT_VAR} ${INCLUDE_DIRS} PARENT_SCOPE) +endfunction() diff --git a/cmake/utils/qvm_tools.cmake b/cmake/utils/qvm_tools.cmake new file mode 100644 index 00000000..cf299ca3 --- /dev/null +++ b/cmake/utils/qvm_tools.cmake @@ -0,0 +1,83 @@ +include_guard(GLOBAL) + +if(NOT BUILD_GAME_QVMS) + return() +endif() + +include(ExternalProject) + +set(TOOLS_DIR ${CMAKE_BINARY_DIR}/tools) + +if(CMAKE_BUILD_TYPE) + set(BUILD_TYPE_ARG -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) +endif() + +ExternalProject_Add(qvm_tools + SOURCE_DIR ${CMAKE_SOURCE_DIR}/cmake/tools + BINARY_DIR ${TOOLS_DIR} + CMAKE_ARGS + -DSOURCE_DIR=${SOURCE_DIR} + -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} + -DCMAKE_MINIMUM_REQUIRED_VERSION=${CMAKE_MINIMUM_REQUIRED_VERSION} + ${BUILD_TYPE_ARG} + INSTALL_COMMAND "") + +set(Q3LCC ${TOOLS_DIR}/$/q3lcc) +set(Q3ASM ${TOOLS_DIR}/$/q3asm) + +function(add_qvm MODULE_NAME) + list(REMOVE_AT ARGV 0) + cmake_parse_arguments(ARG "" "" "DEFINITIONS;OUTPUT_NAME;OUTPUT_DIRECTORY;SOURCES" ${ARGV}) + + set(QVM_OUTPUT_DIR ${CMAKE_BINARY_DIR}/$) + if(ARG_OUTPUT_DIRECTORY) + set(QVM_OUTPUT_DIR ${QVM_OUTPUT_DIR}/${ARG_OUTPUT_DIRECTORY}) + endif() + add_custom_command( + OUTPUT ${QVM_OUTPUT_DIR} + COMMAND ${CMAKE_COMMAND} -E make_directory ${QVM_OUTPUT_DIR}) + + if(ARG_OUTPUT_NAME) + set(QVM_FILE ${QVM_OUTPUT_DIR}/${ARG_OUTPUT_NAME}.qvm) + else() + set(QVM_FILE ${QVM_OUTPUT_DIR}/${MODULE_NAME}.qvm) + endif() + + set(QVM_ASM_DIR ${CMAKE_BINARY_DIR}/qvm.dir/${MODULE_NAME}) + file(MAKE_DIRECTORY ${QVM_ASM_DIR}) + + set(LCC_FLAGS "") + foreach(DEFINITION IN LISTS ARG_DEFINITIONS) + list(APPEND LCC_FLAGS "-D${DEFINITION}") + endforeach() + + set(ASM_FILES "") + foreach(SOURCE ${ARG_SOURCES}) + if(${SOURCE} MATCHES "\\.asm$") + list(APPEND ASM_FILES ${SOURCE}) + continue() + endif() + + get_filename_component(BASE_FILE ${SOURCE} NAME_WE) + set(ASM_FILE ${QVM_ASM_DIR}/${BASE_FILE}.asm) + string(REPLACE "${CMAKE_BINARY_DIR}/" "" ASM_FILE_COMMENT ${ASM_FILE}) + + add_custom_command( + OUTPUT ${ASM_FILE} + COMMAND ${Q3LCC} ${LCC_FLAGS} -o ${ASM_FILE} ${SOURCE} + DEPENDS ${SOURCE} qvm_tools + COMMENT "Building C object ${ASM_FILE_COMMENT}") + + list(APPEND ASM_FILES ${ASM_FILE}) + endforeach() + + string(REPLACE "${CMAKE_BINARY_DIR}/" "" QVM_FILE_COMMENT ${QVM_FILE}) + add_custom_command( + OUTPUT ${QVM_FILE} + COMMAND ${Q3ASM} -o ${QVM_FILE} ${ASM_FILES} + DEPENDS ${ASM_FILES} qvm_tools + COMMENT "Linking C QVM library ${QVM_FILE_COMMENT}") + + string(REGEX REPLACE "[^A-Za-z0-9]" "_" TARGET_NAME ${MODULE_NAME}) + add_custom_target(${TARGET_NAME} ALL DEPENDS ${QVM_FILE}) +endfunction() diff --git a/cmake/utils/set_output_dirs.cmake b/cmake/utils/set_output_dirs.cmake new file mode 100644 index 00000000..a38ecc03 --- /dev/null +++ b/cmake/utils/set_output_dirs.cmake @@ -0,0 +1,27 @@ +include_guard(GLOBAL) + +function(set_output_dirs TARGET) + list(REMOVE_AT ARGV 0) + cmake_parse_arguments(ARG "" "" "SUBDIRECTORY" ${ARGV}) + + if(CMAKE_CONFIGURATION_TYPES) # Multi-config + set(CONFIGS ${CMAKE_CONFIGURATION_TYPES}) + else() # Single-config + set(CONFIGS ${CMAKE_BUILD_TYPE}) + endif() + + foreach(CONFIG ${CONFIGS}) + string(TOUPPER ${CONFIG} CONFIG_UPPER) + + if(ARG_SUBDIRECTORY) + set(OUT_DIR ${CMAKE_BINARY_DIR}/${CONFIG}/${ARG_SUBDIRECTORY}) + else() + set(OUT_DIR ${CMAKE_BINARY_DIR}/${CONFIG}) + endif() + + set_target_properties(${TARGET} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY_${CONFIG_UPPER} ${OUT_DIR} + RUNTIME_OUTPUT_DIRECTORY_${CONFIG_UPPER} ${OUT_DIR} + ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_UPPER} ${OUT_DIR}) + endforeach() +endfunction() diff --git a/cmake/utils/stringify_shader.cmake b/cmake/utils/stringify_shader.cmake new file mode 100644 index 00000000..71cc76be --- /dev/null +++ b/cmake/utils/stringify_shader.cmake @@ -0,0 +1,13 @@ +# Convert a shader file to a compilable C file + +# INPUT_FILE, OUTPUT_FILE, SHADER_NAME must be set via -D + +file(READ ${INPUT_FILE} CONTENTS) + +string(REPLACE "\\" "\\\\" CONTENTS "${CONTENTS}") # Escape backslashes +string(REPLACE "\"" "\\\"" CONTENTS "${CONTENTS}") # Escape double quotes +string(REPLACE "\n" "\\n\"\n\"" CONTENTS "${CONTENTS}") # Escape newlines + +set(OUTPUT_CONTENT "const char *fallbackShader_${SHADER_NAME} =\n\"${CONTENTS}\";\n") + +file(WRITE ${OUTPUT_FILE} "${OUTPUT_CONTENT}")