Merge remote-tracking branch 'yquake2/master'

This commit is contained in:
Denis Pauk 2024-04-07 18:12:09 +03:00
commit 4bd19bf982
21 changed files with 4572 additions and 52 deletions

830
CMakeLists.txt Normal file
View file

@ -0,0 +1,830 @@
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
# Print a message that using the Makefiles is recommended.
message(NOTICE: " The CMakeLists.txt is unmaintained. Use the Makefile if possible.")
# Enforce "Debug" as standard build type.
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif()
# CMake project configuration.
project(yquake2 C)
# Cmake module search path.
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/stuff/cmake/modules ${CMAKE_MODULE_PATH})
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED OFF)
if(YQUAKE2LIBS)
if(CMAKE_CROSSCOMPILING)
set(CMAKE_FIND_ROOT_PATH ${YQUAKE2LIBS})
else()
set(ENV{CMAKE_PREFIX_PATH} ${YQUAKE2LIBS})
endif()
set(ENV{OPENALDIR} ${YQUAKE2LIBS})
set(ENV{SDL2DIR} ${YQUAKE2LIBS})
endif()
# Add extended path for FreeBSD and Homebrew on OS X.
list(APPEND CMAKE_PREFIX_PATH /usr/local)
if (MSVC)
add_compile_options(/MP) # parallel build (use all cores, or as many as configured in VS)
# ignore some compiler warnings
add_compile_options(/wd4244 /wd4305) # possible loss of data/truncation (double to float etc; ignore)
add_compile_options(/wd4018) # signed/unsigned mismatch
add_compile_options(/wd4996) # 'function': was declared deprecated (like all that secure CRT stuff)
# don't show me warnings for system headers, why the fuck isn't this default
add_compile_options(/experimental:external /external:W0)
else() # GCC/clang/mingw
# Enforce compiler flags:
# -Wall -> More warnings
# -fno-strict-aliasing -> Quake 2 is far away from strict aliasing
# -fwrapv -> Make signed integer overflows defined
# -fvisibility=hidden -> Force defaultsymbol visibility to hidden
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fno-strict-aliasing -fwrapv -fvisibility=hidden")
# Use -O2 as maximum optimization level. -O3 has it's problems with yquake2.
string(REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
endif() # MSVC'S else-case
# Switch off some annoying warnings
if (${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-braces")
elseif (${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
if (CMAKE_C_COMPILER_VERSION GREATER 7.99)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-truncation -Wno-format-overflow")
endif()
endif()
# Compilation time options.
option(CURL_SUPPORT "cURL support" ON)
option(OPENAL_SUPPORT "OpenAL support" ON)
option(SYSTEMWIDE_SUPPORT "Enable systemwide installation of game assets" OFF)
option(SDL3_SUPPORT "Build against SDL 3 instead of SDL2" OFF)
set(SYSTEMDIR "" CACHE STRING "Override the system default directory")
# These variables will act as our list of include folders and linker flags.
set(yquake2IncludeDirectories)
set(yquake2LinkerDirectories)
set(yquake2LinkerFlags)
set(yquake2ClientLinkerFlags)
set(yquake2ServerLinkerFlags)
set(yquake2OpenGLLinkerFlags)
set(yquake2VulkanLinkerFlags)
set(yquake2SDLLinkerFlags)
set(yquake2ZLibLinkerFlags)
# Set directory locations (allowing us to move directories easily)
set(SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/src)
set(BACKENDS_SRC_DIR ${SOURCE_DIR}/backends)
set(COMMON_SRC_DIR ${SOURCE_DIR}/common)
set(GAME_SRC_DIR ${SOURCE_DIR}/game)
set(SERVER_SRC_DIR ${SOURCE_DIR}/server)
set(CLIENT_SRC_DIR ${SOURCE_DIR}/client)
set(REF_SRC_DIR ${SOURCE_DIR}/client/refresh)
# Operating system.
set(YQ2OSTYPE "${CMAKE_SYSTEM_NAME}" CACHE STRING "Override operation system type")
add_definitions(-DYQ2OSTYPE="${YQ2OSTYPE}")
# Architecture string
# work around CMake's useless/broken CMAKE_SYSTEM_PROCESSOR (taken from dhewm3)
set(cpu ${CMAKE_SYSTEM_PROCESSOR})
# Originally, ${CMAKE_SYSTEM_PROCESSOR} was supposed to contain the *target* CPU, according to CMake's documentation.
# As far as I can tell this has always been broken (always returns host CPU) at least on Windows
# (see e.g. https://cmake.org/pipermail/cmake-developers/2014-September/011405.html) and wasn't reliable on
# other systems either, for example on Linux with 32bit userland but 64bit kernel it returned the kernel CPU type
# (e.g. x86_64 instead of i686). Instead of fixing this, CMake eventually updated their documentation in 3.20,
# now it's officially the same as CMAKE_HOST_SYSTEM_PROCESSOR except when cross-compiling (where it's explicitly set)
# So we gotta figure out the actual target CPU type ourselves..
if(NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_SYSTEM_PROCESSOR))
# special case: cross-compiling, here CMAKE_SYSTEM_PROCESSOR should be correct, hopefully
# (just leave cpu at ${CMAKE_SYSTEM_PROCESSOR})
elseif(MSVC)
# because all this wasn't ugly enough, it turned out that, unlike standalone CMake, Visual Studio's
# integrated CMake doesn't set CMAKE_GENERATOR_PLATFORM, so I gave up on guessing the CPU arch here
# and moved the CPU detection to MSVC-specific code in neo/sys/platform.h
else() # not MSVC and not cross-compiling, assume GCC or clang (-compatible), seems to work for MinGW as well
execute_process(COMMAND ${CMAKE_C_COMPILER} "-dumpmachine"
RESULT_VARIABLE cc_dumpmachine_res
OUTPUT_VARIABLE cc_dumpmachine_out)
if(cc_dumpmachine_res EQUAL 0)
string(STRIP ${cc_dumpmachine_out} cc_dumpmachine_out) # get rid of trailing newline
message(DEBUG "`${CMAKE_C_COMPILER} -dumpmachine` says: \"${cc_dumpmachine_out}\"")
# gcc -dumpmachine and clang -dumpmachine seem to print something like "x86_64-linux-gnu" (gcc)
# or "x64_64-pc-linux-gnu" (clang) or "i686-w64-mingw32" (32bit mingw-w64) i.e. starting with the CPU,
# then "-" and then OS or whatever - so use everything up to first "-"
string(REGEX MATCH "^[^-]+" cpu ${cc_dumpmachine_out})
message(DEBUG " => CPU architecture extracted from that: \"${cpu}\"")
else()
message(WARNING "${CMAKE_C_COMPILER} -dumpmachine failed with error (code) ${cc_dumpmachine_res}")
message(WARNING "will use the (sometimes incorrect) CMAKE_SYSTEM_PROCESSOR (${cpu}) to determine YQ2ARCH")
endif()
endif()
if(cpu STREQUAL "powerpc")
set(cpu "ppc")
elseif(cpu STREQUAL "aarch64")
# "arm64" is more obvious, and some operating systems (like macOS) use it instead of "aarch64"
set(cpu "arm64")
elseif(cpu MATCHES "[aA][mM][dD]64" OR cpu MATCHES "[xX].*64")
set(cpu "x86_64")
elseif(cpu MATCHES "i.86" OR cpu MATCHES "[xX]86")
set(cpu "i386")
elseif(cpu MATCHES "[aA][rR][mM].*") # some kind of arm..
# On 32bit Raspbian gcc -dumpmachine returns sth starting with "arm-",
# while clang -dumpmachine says "arm6k-..." - try to unify that to "arm"
if(CMAKE_SIZEOF_VOID_P EQUAL 8) # sizeof(void*) == 8 => must be arm64
set(cpu "arm64")
else() # should be 32bit arm then (probably "armv7l" "armv6k" or sth like that)
set(cpu "arm")
endif()
endif()
if(MSVC)
# for MSVC YQ2ARCH is set in code (in src/common/header/common.h)
message(STATUS "Setting YQ2OSTYPE to \"${YQ2OSTYPE}\" - NOT setting YQ2ARCH, because we're targeting MSVC (VisualC++)")
else()
set(ARCH "${cpu}")
add_definitions(-DYQ2ARCH="${ARCH}")
message(STATUS "Setting YQ2OSTYPE to \"${YQ2OSTYPE}\" and YQ2ARCH to \"${ARCH}\".")
endif()
# make sure that ${cpu} isn't used below - if at all use ${ARCH}, but not when compiling with MSVC!
unset(cpu)
# END OF workarounds for CMake's poor choices regarding CPU architecture detection
# Systemwide installation of game assets.
if(${SYSTEMWIDE_SUPPORT})
add_definitions(-DSYSTEMWIDE)
if(NOT ${SYSTEMDIR} STREQUAL "")
add_definitions(-DSYSTEMDIR="${SYSTEMDIR}")
endif()
endif()
# We need to pass some options to minizip / unzip.
add_definitions(-DNOUNCRYPT)
if(NOT (CMAKE_SYSTEM_NAME MATCHES "Linux") AND NOT (CMAKE_SYSTEM_NAME MATCHES "Windows"))
add_definitions(-DIOAPI_NO_64)
endif()
# Required libraries to build the different components of the binaries. Find
# them and add the include/linker directories and flags (in case the package
# manager find it in a weird place).
if (SDL3_SUPPORT)
find_package(SDL3 REQUIRED)
add_definitions(-DUSE_SDL3)
else()
find_package(SDL2 REQUIRED)
list(APPEND yquake2IncludeDirectories "${SDL2_INCLUDE_DIR}/..")
list(APPEND yquake2SDLLinkerFlags ${SDL2_LIBRARY})
endif()
# We need an OpenGL implementation.
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL REQUIRED)
list(APPEND yquake2IncludeDirectories ${OPENGL_INCLUDE_DIR})
list(APPEND yquake2OpenGLLinkerFlags ${OPENGL_LIBRARIES})
# backtrace lookup
# Some systems like Linux has it within the libc some like the BSD, Haiku ...
# into an external libexecinfo library
include(CheckFunctionExists)
include(CheckLibraryExists)
check_function_exists(backtrace HAVE_EXECINFO_SYS)
IF (NOT HAVE_EXECINFO_SYS)
check_library_exists(execinfo backtrace "" HAVE_EXECINFO_LIB)
if (HAVE_EXECINFO_LIB)
list(APPEND yquake2ClientLinkerFlags execinfo)
list(APPEND yquake2ServerLinkerFlags execinfo)
add_definitions(-DHAVE_EXECINFO)
endif()
else()
add_definitions(-DHAVE_EXECINFO)
endif()
# cURL support.
if (${CURL_SUPPORT})
find_package(CURL REQUIRED)
add_definitions(-DUSE_CURL)
endif()
# OpenAL support.
if(${OPENAL_SUPPORT})
find_package(OpenAL)
if(${OPENAL_FOUND})
list(APPEND yquake2IncludeDirectories "${OPENAL_INCLUDE_DIR}")
list(APPEND yquake2ClientLinkerFlags ${OPENAL_LIBRARY})
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
add_definitions(-DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER="openal32.dll")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
add_definitions(-DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER="libopenal.dylib")
elseif((${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") OR (${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
add_definitions(-DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER="libopenal.so")
else()
add_definitions(-DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER="libopenal.so.1")
endif()
endif()
endif()
# General linker flags.
if(NOT MSVC)
list(APPEND yquake2LinkerFlags m)
endif()
list(APPEND yquake2LinkerFlags ${CMAKE_DL_LIBS})
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
if(!MSVC)
list(APPEND yquake2LinkerFlags "-static-libgcc")
endif()
else()
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
list(APPEND yquake2LinkerFlags "-rdynamic")
else()
list(APPEND yquake2LinkerFlags "-lnetwork")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
list(APPEND yquake2LinkerFlags "-lsocket -lnsl")
endif()
endif()
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" AND NOT WIN32)
list(APPEND yquake2LinkerFlags "-Wl,--no-undefined")
endif()
# With all of those libraries and user defined paths
# added, lets give them to the compiler and linker.
include_directories(${yquake2IncludeDirectories})
link_directories(${yquake2LinkerDirectories})
# these settings only work for GCC and clang
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
# If we're building with gcc for i386 let's define -ffloat-store.
# This helps the old and crappy x87 FPU to produce correct values.
# Would be nice if Clang had something comparable.
if ("${ARCH}" STREQUAL "i386" AND ${CMAKE_C_COMPILER_ID} STREQUAL "GNU")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffloat-store")
endif()
# Force SSE math on x86_64. All sane compilers should do this
# anyway, just to protect us from broken Linux distros.
if ("${ARCH}" STREQUAL "x86_64")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse")
endif()
if ("${ARCH}" STREQUAL "arm")
if (CMAKE_SIZEOF_VOID_P EQUAL 4)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv6k")
endif()
endif()
endif()
set(Backends-Generic-Source
${BACKENDS_SRC_DIR}/generic/misc.c
)
set(Backends-Unix-Source
${BACKENDS_SRC_DIR}/unix/main.c
${BACKENDS_SRC_DIR}/unix/network.c
${BACKENDS_SRC_DIR}/unix/signalhandler.c
${BACKENDS_SRC_DIR}/unix/system.c
${BACKENDS_SRC_DIR}/unix/shared/hunk.c
)
set(Backends-Windows-Source
${BACKENDS_SRC_DIR}/windows/icon.rc
${BACKENDS_SRC_DIR}/windows/main.c
${BACKENDS_SRC_DIR}/windows/network.c
${BACKENDS_SRC_DIR}/windows/system.c
${BACKENDS_SRC_DIR}/windows/shared/hunk.c
)
set(Backends-Windows-Header
${BACKENDS_SRC_DIR}/windows/header/resource.h
)
set(REF-Windows-Source
${BACKENDS_SRC_DIR}/windows/shared/hunk.c
)
set(REF-Unix-Source
${BACKENDS_SRC_DIR}/unix/shared/hunk.c
)
# Set the nessesary platform specific source
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(Platform-Specific-Source ${Backends-Windows-Source} ${Backends-Windows-Header})
set(REF-Platform-Specific-Source ${REF-Windows-Source})
else()
set(Platform-Specific-Source ${Backends-Unix-Source})
set(REF-Platform-Specific-Source ${REF-Unix-Source})
endif()
set(Game-Source
${COMMON_SRC_DIR}/shared/flash.c
${COMMON_SRC_DIR}/shared/rand.c
${COMMON_SRC_DIR}/shared/shared.c
${GAME_SRC_DIR}/g_ai.c
${GAME_SRC_DIR}/g_chase.c
${GAME_SRC_DIR}/g_cmds.c
${GAME_SRC_DIR}/g_combat.c
${GAME_SRC_DIR}/g_func.c
${GAME_SRC_DIR}/g_items.c
${GAME_SRC_DIR}/g_main.c
${GAME_SRC_DIR}/g_misc.c
${GAME_SRC_DIR}/g_monster.c
${GAME_SRC_DIR}/g_phys.c
${GAME_SRC_DIR}/g_spawn.c
${GAME_SRC_DIR}/g_svcmds.c
${GAME_SRC_DIR}/g_target.c
${GAME_SRC_DIR}/g_trigger.c
${GAME_SRC_DIR}/g_turret.c
${GAME_SRC_DIR}/g_utils.c
${GAME_SRC_DIR}/g_weapon.c
${GAME_SRC_DIR}/monster/berserker/berserker.c
${GAME_SRC_DIR}/monster/boss2/boss2.c
${GAME_SRC_DIR}/monster/boss3/boss3.c
${GAME_SRC_DIR}/monster/boss3/boss31.c
${GAME_SRC_DIR}/monster/boss3/boss32.c
${GAME_SRC_DIR}/monster/brain/brain.c
${GAME_SRC_DIR}/monster/chick/chick.c
${GAME_SRC_DIR}/monster/flipper/flipper.c
${GAME_SRC_DIR}/monster/float/float.c
${GAME_SRC_DIR}/monster/flyer/flyer.c
${GAME_SRC_DIR}/monster/gladiator/gladiator.c
${GAME_SRC_DIR}/monster/gunner/gunner.c
${GAME_SRC_DIR}/monster/hover/hover.c
${GAME_SRC_DIR}/monster/infantry/infantry.c
${GAME_SRC_DIR}/monster/insane/insane.c
${GAME_SRC_DIR}/monster/medic/medic.c
${GAME_SRC_DIR}/monster/misc/move.c
${GAME_SRC_DIR}/monster/mutant/mutant.c
${GAME_SRC_DIR}/monster/parasite/parasite.c
${GAME_SRC_DIR}/monster/soldier/soldier.c
${GAME_SRC_DIR}/monster/supertank/supertank.c
${GAME_SRC_DIR}/monster/tank/tank.c
${GAME_SRC_DIR}/player/client.c
${GAME_SRC_DIR}/player/hud.c
${GAME_SRC_DIR}/player/trail.c
${GAME_SRC_DIR}/player/view.c
${GAME_SRC_DIR}/player/weapon.c
${GAME_SRC_DIR}/savegame/savegame.c
)
set(Game-Header
${GAME_SRC_DIR}/header/game.h
${GAME_SRC_DIR}/header/local.h
${GAME_SRC_DIR}/monster/berserker/berserker.h
${GAME_SRC_DIR}/monster/boss2/boss2.h
${GAME_SRC_DIR}/monster/boss3/boss31.h
${GAME_SRC_DIR}/monster/boss3/boss32.h
${GAME_SRC_DIR}/monster/brain/brain.h
${GAME_SRC_DIR}/monster/chick/chick.h
${GAME_SRC_DIR}/monster/flipper/flipper.h
${GAME_SRC_DIR}/monster/float/float.h
${GAME_SRC_DIR}/monster/flyer/flyer.h
${GAME_SRC_DIR}/monster/gladiator/gladiator.h
${GAME_SRC_DIR}/monster/gunner/gunner.h
${GAME_SRC_DIR}/monster/hover/hover.h
${GAME_SRC_DIR}/monster/infantry/infantry.h
${GAME_SRC_DIR}/monster/insane/insane.h
${GAME_SRC_DIR}/monster/medic/medic.h
${GAME_SRC_DIR}/monster/misc/player.h
${GAME_SRC_DIR}/monster/mutant/mutant.h
${GAME_SRC_DIR}/monster/parasite/parasite.h
${GAME_SRC_DIR}/monster/soldier/soldier.h
${GAME_SRC_DIR}/monster/supertank/supertank.h
${GAME_SRC_DIR}/monster/tank/tank.h
${GAME_SRC_DIR}/savegame/tables/clientfields.h
${GAME_SRC_DIR}/savegame/tables/fields.h
${GAME_SRC_DIR}/savegame/tables/gamefunc_decs.h
${GAME_SRC_DIR}/savegame/tables/gamefunc_list.h
${GAME_SRC_DIR}/savegame/tables/gamemmove_decs.h
${GAME_SRC_DIR}/savegame/tables/gamemmove_list.h
${GAME_SRC_DIR}/savegame/tables/levelfields.h
)
set(Client-Source
${CLIENT_SRC_DIR}/cl_cin.c
${CLIENT_SRC_DIR}/cl_console.c
${CLIENT_SRC_DIR}/cl_download.c
${CLIENT_SRC_DIR}/cl_effects.c
${CLIENT_SRC_DIR}/cl_entities.c
${CLIENT_SRC_DIR}/cl_input.c
${CLIENT_SRC_DIR}/cl_inventory.c
${CLIENT_SRC_DIR}/cl_keyboard.c
${CLIENT_SRC_DIR}/cl_lights.c
${CLIENT_SRC_DIR}/cl_main.c
${CLIENT_SRC_DIR}/cl_network.c
${CLIENT_SRC_DIR}/cl_parse.c
${CLIENT_SRC_DIR}/cl_particles.c
${CLIENT_SRC_DIR}/cl_prediction.c
${CLIENT_SRC_DIR}/cl_screen.c
${CLIENT_SRC_DIR}/cl_tempentities.c
${CLIENT_SRC_DIR}/cl_view.c
${CLIENT_SRC_DIR}/curl/download.c
${CLIENT_SRC_DIR}/curl/qcurl.c
${CLIENT_SRC_DIR}/menu/menu.c
${CLIENT_SRC_DIR}/menu/qmenu.c
${CLIENT_SRC_DIR}/menu/videomenu.c
${CLIENT_SRC_DIR}/sound/ogg.c
${CLIENT_SRC_DIR}/sound/openal.c
${CLIENT_SRC_DIR}/sound/qal.c
${CLIENT_SRC_DIR}/sound/sdl.c
${CLIENT_SRC_DIR}/sound/sound.c
${CLIENT_SRC_DIR}/sound/wave.c
${CLIENT_SRC_DIR}/vid/vid.c
${COMMON_SRC_DIR}/argproc.c
${COMMON_SRC_DIR}/clientserver.c
${COMMON_SRC_DIR}/collision.c
${COMMON_SRC_DIR}/crc.c
${COMMON_SRC_DIR}/cmdparser.c
${COMMON_SRC_DIR}/cvar.c
${COMMON_SRC_DIR}/filesystem.c
${COMMON_SRC_DIR}/glob.c
${COMMON_SRC_DIR}/md4.c
${COMMON_SRC_DIR}/movemsg.c
${COMMON_SRC_DIR}/frame.c
${COMMON_SRC_DIR}/netchan.c
${COMMON_SRC_DIR}/pmove.c
${COMMON_SRC_DIR}/szone.c
${COMMON_SRC_DIR}/zone.c
${COMMON_SRC_DIR}/shared/flash.c
${COMMON_SRC_DIR}/shared/rand.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/unzip/ioapi.c
${COMMON_SRC_DIR}/unzip/unzip.c
${COMMON_SRC_DIR}/unzip/miniz/miniz.c
${COMMON_SRC_DIR}/unzip/miniz/miniz_tdef.c
${COMMON_SRC_DIR}/unzip/miniz/miniz_tinfl.c
${SERVER_SRC_DIR}/sv_cmd.c
${SERVER_SRC_DIR}/sv_conless.c
${SERVER_SRC_DIR}/sv_entities.c
${SERVER_SRC_DIR}/sv_game.c
${SERVER_SRC_DIR}/sv_init.c
${SERVER_SRC_DIR}/sv_main.c
${SERVER_SRC_DIR}/sv_save.c
${SERVER_SRC_DIR}/sv_send.c
${SERVER_SRC_DIR}/sv_user.c
${SERVER_SRC_DIR}/sv_world.c
)
if(SDL3_SUPPORT)
set(Client-SDL-Source
${CLIENT_SRC_DIR}/input/sdl3.c
${CLIENT_SRC_DIR}/vid/glimp_sdl3.c
)
else()
set(Client-SDL-Source
${CLIENT_SRC_DIR}/input/sdl2.c
${CLIENT_SRC_DIR}/vid/glimp_sdl2.c
)
endif()
set(Client-Header
${CLIENT_SRC_DIR}/header/client.h
${CLIENT_SRC_DIR}/header/console.h
${CLIENT_SRC_DIR}/header/keyboard.h
${CLIENT_SRC_DIR}/header/screen.h
${CLIENT_SRC_DIR}/curl/header/download.h
${CLIENT_SRC_DIR}/curl/header/qcurl.h
${CLIENT_SRC_DIR}/input/header/input.h
${CLIENT_SRC_DIR}/menu/header/qmenu.h
${CLIENT_SRC_DIR}/sound/header/local.h
${CLIENT_SRC_DIR}/sound/header/qal.h
${CLIENT_SRC_DIR}/sound/header/sound.h
${CLIENT_SRC_DIR}/sound/header/stb_vorbis.h
${CLIENT_SRC_DIR}/sound/header/vorbis.h
${CLIENT_SRC_DIR}/vid/header/ref.h
${CLIENT_SRC_DIR}/vid/header/stb_image_write.h
${CLIENT_SRC_DIR}/vid/header/vid.h
${COMMON_SRC_DIR}/header/common.h
${COMMON_SRC_DIR}/header/crc.h
${COMMON_SRC_DIR}/header/files.h
${COMMON_SRC_DIR}/header/glob.h
${COMMON_SRC_DIR}/header/shared.h
${COMMON_SRC_DIR}/header/zone.h
${COMMON_SRC_DIR}/unzip/ioapi.h
${COMMON_SRC_DIR}/unzip/unzip.h
${COMMON_SRC_DIR}/unzip/miniz/miniz.h
${COMMON_SRC_DIR}/unzip/miniz/miniz_tdef.h
${COMMON_SRC_DIR}/unzip/miniz/miniz_tinfl.h
${COMMON_SRC_DIR}/unzip/miniz/minizconf.h
${SERVER_SRC_DIR}/header/server.h
)
set(Server-Source
${COMMON_SRC_DIR}/argproc.c
${COMMON_SRC_DIR}/clientserver.c
${COMMON_SRC_DIR}/collision.c
${COMMON_SRC_DIR}/crc.c
${COMMON_SRC_DIR}/cmdparser.c
${COMMON_SRC_DIR}/cvar.c
${COMMON_SRC_DIR}/filesystem.c
${COMMON_SRC_DIR}/glob.c
${COMMON_SRC_DIR}/md4.c
${COMMON_SRC_DIR}/frame.c
${COMMON_SRC_DIR}/movemsg.c
${COMMON_SRC_DIR}/netchan.c
${COMMON_SRC_DIR}/pmove.c
${COMMON_SRC_DIR}/szone.c
${COMMON_SRC_DIR}/zone.c
${COMMON_SRC_DIR}/shared/rand.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/unzip/ioapi.c
${COMMON_SRC_DIR}/unzip/unzip.c
${COMMON_SRC_DIR}/unzip/miniz/miniz.c
${COMMON_SRC_DIR}/unzip/miniz/miniz_tdef.c
${COMMON_SRC_DIR}/unzip/miniz/miniz_tinfl.c
${SERVER_SRC_DIR}/sv_cmd.c
${SERVER_SRC_DIR}/sv_conless.c
${SERVER_SRC_DIR}/sv_entities.c
${SERVER_SRC_DIR}/sv_game.c
${SERVER_SRC_DIR}/sv_init.c
${SERVER_SRC_DIR}/sv_main.c
${SERVER_SRC_DIR}/sv_save.c
${SERVER_SRC_DIR}/sv_send.c
${SERVER_SRC_DIR}/sv_user.c
${SERVER_SRC_DIR}/sv_world.c
)
set(Server-Header
${COMMON_SRC_DIR}/header/common.h
${COMMON_SRC_DIR}/header/crc.h
${COMMON_SRC_DIR}/header/files.h
${COMMON_SRC_DIR}/header/glob.h
${COMMON_SRC_DIR}/header/shared.h
${COMMON_SRC_DIR}/header/zone.h
${COMMON_SRC_DIR}/unzip/ioapi.h
${COMMON_SRC_DIR}/unzip/unzip.h
${COMMON_SRC_DIR}/unzip/miniz/miniz.h
${COMMON_SRC_DIR}/unzip/miniz/miniz_tdef.h
${COMMON_SRC_DIR}/unzip/miniz/miniz_tinfl.h
${COMMON_SRC_DIR}/unzip/miniz/minizconf.h
${SERVER_SRC_DIR}/header/server.h
)
set(GL1-Source
${REF_SRC_DIR}/gl1/qgl.c
${REF_SRC_DIR}/gl1/gl1_draw.c
${REF_SRC_DIR}/gl1/gl1_image.c
${REF_SRC_DIR}/gl1/gl1_light.c
${REF_SRC_DIR}/gl1/gl1_lightmap.c
${REF_SRC_DIR}/gl1/gl1_main.c
${REF_SRC_DIR}/gl1/gl1_mesh.c
${REF_SRC_DIR}/gl1/gl1_misc.c
${REF_SRC_DIR}/gl1/gl1_model.c
${REF_SRC_DIR}/gl1/gl1_scrap.c
${REF_SRC_DIR}/gl1/gl1_surf.c
${REF_SRC_DIR}/gl1/gl1_warp.c
${REF_SRC_DIR}/gl1/gl1_sdl.c
${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/pcx.c
${REF_SRC_DIR}/files/stb.c
${REF_SRC_DIR}/files/surf.c
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/pvs.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/md4.c
)
set(GL1-Header
${REF_SRC_DIR}/ref_shared.h
${REF_SRC_DIR}/constants/anorms.h
${REF_SRC_DIR}/constants/anormtab.h
${REF_SRC_DIR}/constants/warpsin.h
${REF_SRC_DIR}/files/stb_image.h
${REF_SRC_DIR}/files/surf.c
${REF_SRC_DIR}/gl1/header/local.h
${REF_SRC_DIR}/gl1/header/model.h
${REF_SRC_DIR}/gl1/header/qgl.h
${COMMON_SRC_DIR}/header/shared.h
)
set(GL3-Source
${REF_SRC_DIR}/gl3/gl3_draw.c
${REF_SRC_DIR}/gl3/gl3_image.c
${REF_SRC_DIR}/gl3/gl3_light.c
${REF_SRC_DIR}/gl3/gl3_lightmap.c
${REF_SRC_DIR}/gl3/gl3_main.c
${REF_SRC_DIR}/gl3/gl3_mesh.c
${REF_SRC_DIR}/gl3/gl3_misc.c
${REF_SRC_DIR}/gl3/gl3_model.c
${REF_SRC_DIR}/gl3/gl3_sdl.c
${REF_SRC_DIR}/gl3/gl3_surf.c
${REF_SRC_DIR}/gl3/gl3_warp.c
${REF_SRC_DIR}/gl3/gl3_shaders.c
${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/pcx.c
${REF_SRC_DIR}/files/stb.c
${REF_SRC_DIR}/files/surf.c
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/pvs.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/md4.c
)
set(Glad-GL3-Source ${REF_SRC_DIR}/gl3/glad/src/glad.c)
set(Glad-GLES3-Source ${REF_SRC_DIR}/gl3/glad-gles3/src/glad.c)
set(GL3-Header
${REF_SRC_DIR}/ref_shared.h
${REF_SRC_DIR}/constants/anorms.h
${REF_SRC_DIR}/constants/anormtab.h
${REF_SRC_DIR}/constants/warpsin.h
${REF_SRC_DIR}/files/stb_image.h
${REF_SRC_DIR}/gl3/header/DG_dynarr.h
${REF_SRC_DIR}/gl3/header/HandmadeMath.h
${REF_SRC_DIR}/gl3/header/local.h
${REF_SRC_DIR}/gl3/header/model.h
${COMMON_SRC_DIR}/header/shared.h
)
set(Glad-GL3-Header
${REF_SRC_DIR}/gl3/glad/include/glad/glad.h
${REF_SRC_DIR}/gl3/glad/include/KHR/khrplatform.h
)
set(Glad-GLES3-Header
${REF_SRC_DIR}/gl3/glad-gles3/include/glad/glad.h
${REF_SRC_DIR}/gl3/glad-gles3/include/KHR/khrplatform.h
)
set(SOFT-Source
${REF_SRC_DIR}/soft/sw_aclip.c
${REF_SRC_DIR}/soft/sw_alias.c
${REF_SRC_DIR}/soft/sw_bsp.c
${REF_SRC_DIR}/soft/sw_draw.c
${REF_SRC_DIR}/soft/sw_edge.c
${REF_SRC_DIR}/soft/sw_image.c
${REF_SRC_DIR}/soft/sw_light.c
${REF_SRC_DIR}/soft/sw_main.c
${REF_SRC_DIR}/soft/sw_misc.c
${REF_SRC_DIR}/soft/sw_model.c
${REF_SRC_DIR}/soft/sw_part.c
${REF_SRC_DIR}/soft/sw_poly.c
${REF_SRC_DIR}/soft/sw_polyset.c
${REF_SRC_DIR}/soft/sw_rast.c
${REF_SRC_DIR}/soft/sw_scan.c
${REF_SRC_DIR}/soft/sw_sprite.c
${REF_SRC_DIR}/soft/sw_surf.c
${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/pcx.c
${REF_SRC_DIR}/files/stb.c
${REF_SRC_DIR}/files/surf.c
${REF_SRC_DIR}/files/wal.c
${REF_SRC_DIR}/files/pvs.c
${COMMON_SRC_DIR}/shared/shared.c
${COMMON_SRC_DIR}/md4.c
)
set(SOFT-Header
${REF_SRC_DIR}/ref_shared.h
${REF_SRC_DIR}/files/stb_image.h
${REF_SRC_DIR}/files/stb_image_resize.h
${REF_SRC_DIR}/soft/header/local.h
${REF_SRC_DIR}/soft/header/model.h
${COMMON_SRC_DIR}/header/shared.h
)
# Main Quake 2 executable
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
add_executable(yquake2 WIN32 ${Client-Source} ${Client-SDL-Source} ${Client-Header}
${Platform-Specific-Source} ${Backends-Generic-Source})
set_target_properties(yquake2 PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
)
target_link_libraries(yquake2 ${yquake2LinkerFlags} ${yquake2ClientLinkerFlags}
${yquake2SDLLinkerFlags} ${yquake2ZLibLinkerFlags} ws2_32 winmm)
if(SDL3_SUPPORT)
target_link_libraries(yquake2 SDL3::SDL3)
endif()
if(MSVC AND CMAKE_MAJOR_VERSION GREATER 3 OR ( CMAKE_MAJOR_VERSION EQUAL 3 AND CMAKE_MINOR_VERSION GREATER_EQUAL 6 ))
# CMake >= 3.6 supports setting the default project started for debugging (instead of trying to launch ALL_BUILD ...)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yquake2)
set_target_properties(yquake2 PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/release)
endif()
# Wrapper for the Windows binary
set(Wrapper-Source
src/win-wrapper/wrapper.c
${BACKENDS_SRC_DIR}/windows/icon.rc
)
add_executable(quake2 WIN32 ${Wrapper-Source})
set_target_properties(quake2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release)
else()
add_executable(quake2 ${Client-Source} ${Client-SDL-Source} ${Client-Header}
${Platform-Specific-Source} ${Backends-Generic-Source})
set_target_properties(quake2 PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
)
target_link_libraries(quake2 ${yquake2LinkerFlags} ${yquake2ClientLinkerFlags}
${yquake2SDLLinkerFlags} ${yquake2ZLibLinkerFlags})
if(SDL3_SUPPORT)
target_link_libraries(quake2 SDL3::SDL3)
endif()
endif()
# Quake 2 Dedicated Server
add_executable(q2ded ${Server-Source} ${Server-Header} ${Platform-Specific-Source}
${Backends-Generic-Source})
set_target_properties(q2ded PROPERTIES
COMPILE_DEFINITIONS "DEDICATED_ONLY"
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
)
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
target_link_libraries(q2ded ${yquake2LinkerFlags})
else()
target_link_libraries(q2ded ${yquake2LinkerFlags} ${yquake2ServerLinkerFlags} ${yquake2ZLibLinkerFlags})
endif()
# Build the game dynamic library
add_library(game MODULE ${Game-Source} ${Game-Header})
set_target_properties(game PROPERTIES
PREFIX ""
SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}
)
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(isMultiConfig) # multi-config, like Visual Studio solution
set_target_properties(game PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release/$<CONFIG>/baseq2
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release/$<CONFIG>/baseq2
)
else() # single-config, like normal Makefiles
set_target_properties(game PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release/baseq2
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release/baseq2
)
endif()
target_link_libraries(game ${yquake2LinkerFlags})
# Build the GL1 dynamic library
add_library(ref_gl1 MODULE ${GL1-Source} ${GL1-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_gl1 PROPERTIES
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}
)
target_link_libraries(ref_gl1 ${yquake2LinkerFlags} ${yquake2OpenGLLinkerFlags}
${yquake2SDLLinkerFlags})
if(SDL3_SUPPORT)
target_link_libraries(ref_gl1 SDL3::SDL3)
endif()
# Build the GL3 dynamic library
add_library(ref_gl3 MODULE ${GL3-Source} ${Glad-GL3-Source} ${GL3-Header} ${Glad-GL3-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_gl3 PROPERTIES
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}
)
target_include_directories(ref_gl3 PRIVATE ${CMAKE_SOURCE_DIR}/src/client/refresh/gl3/glad/include)
target_link_libraries(ref_gl3 ${yquake2LinkerFlags} ${yquake2SDLLinkerFlags})
if(SDL3_SUPPORT)
target_link_libraries(ref_gl3 SDL3::SDL3)
endif()
# Build the GLES3 dynamic library
add_library(ref_gles3 MODULE ${GL3-Source} ${Glad-GLES3-Source} ${GL3-Header} ${Glad-GLES3-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_gles3 PROPERTIES
PREFIX ""
#COMPILE_DEFINITIONS "YQ2_GL3_GLES3=1;YQ2_GL3_GLES=1"
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}
)
target_include_directories(ref_gles3 PRIVATE ${CMAKE_SOURCE_DIR}/src/client/refresh/gl3/glad-gles3/include)
target_compile_definitions(ref_gles3 PRIVATE YQ2_GL3_GLES3=1 YQ2_GL3_GLES=1)
target_link_libraries(ref_gles3 ${yquake2LinkerFlags} ${yquake2SDLLinkerFlags})
if(SDL3_SUPPORT)
target_link_libraries(ref_gles3 SDL3::SDL3)
endif()
# Build the soft renderer dynamic library
add_library(ref_soft MODULE ${SOFT-Source} ${SOFT-Header} ${REF-Platform-Specific-Source})
set_target_properties(ref_soft PROPERTIES
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release
SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}
)
target_link_libraries(ref_soft ${yquake2LinkerFlags} ${yquake2SDLLinkerFlags})
if(SDL3_SUPPORT)
target_link_libraries(ref_soft SDL3::SDL3)
endif()

View file

@ -8,7 +8,7 @@
# - Renderer libraries (gl1, gl3, soft) #
# #
# Base dependencies: #
# - SDL 2.0 #
# - SDL 2 or SDL 3 #
# - libGL #
# - Vulkan headers #
# #
@ -56,6 +56,9 @@ WITH_AVCODEC:=yes
# or libopenal.so. Not supported on Windows.
WITH_RPATH:=yes
# Builds with SDL 3 instead of SDL 2.
WITH_SDL3:=no
# Enable systemwide installation of game assets.
WITH_SYSTEMWIDE:=no
@ -279,7 +282,12 @@ endif
# ----------
# Extra CFLAGS for SDL.
ifeq ($(WITH_SDL3),yes)
SDLCFLAGS := $(shell pkgconf --cflags sdl3)
SDLCFLAGS += -DUSE_SDL3
else
SDLCFLAGS := $(shell sdl2-config --cflags)
endif
# ----------
@ -356,11 +364,19 @@ endif
# ----------
# Extra LDFLAGS for SDL
ifeq ($(WITH_SDL3),yes)
ifeq ($(YQ2_OSTYPE), Darwin)
SDLLDFLAGS := -lSDL3
else
SDLLDFLAGS := $(shell pkgconf --libs sdl3)
endif
else
ifeq ($(YQ2_OSTYPE), Darwin)
SDLLDFLAGS := -lSDL2
else # not Darwin
else
SDLLDFLAGS := $(shell sdl2-config --libs)
endif # Darwin
endif
endif
# The renderer libs don't need libSDL2main, libmingw32 or -mwindows.
ifeq ($(YQ2_OSTYPE), Windows)
@ -398,6 +414,7 @@ config:
@echo "WITH_OPENAL = $(WITH_OPENAL)"
@echo "WITH_AVCODEC = $(WITH_AVCODEC)"
@echo "WITH_RPATH = $(WITH_RPATH)"
@echo "WITH_SDL3 = $(WITH_SDL3)"
@echo "WITH_SYSTEMWIDE = $(WITH_SYSTEMWIDE)"
@echo "WITH_SYSTEMDIR = $(WITH_SYSTEMDIR)"
@echo "============================"
@ -971,17 +988,15 @@ CLIENT_OBJS_ := \
src/client/cl_view.o \
src/client/curl/download.o \
src/client/curl/qcurl.o \
src/client/input/sdl.o \
src/client/menu/menu.o \
src/client/menu/qmenu.o \
src/client/menu/videomenu.o \
src/client/sound/sdl.o \
src/client/sound/ogg.o \
src/client/sound/openal.o \
src/client/sound/qal.o \
src/client/sound/sdl.o \
src/client/sound/sound.o \
src/client/sound/wave.o \
src/client/vid/glimp_sdl.o \
src/client/vid/vid.o \
src/common/argproc.o \
src/common/clientserver.o \
@ -1020,6 +1035,16 @@ CLIENT_OBJS_ := \
src/server/sv_user.o \
src/server/sv_world.o
ifeq ($(WITH_SDL3),yes)
CLIENT_OBJS_ += \
src/client/input/sdl3.o \
src/client/vid/glimp_sdl3.o
else
CLIENT_OBJS_ += \
src/client/input/sdl2.o \
src/client/vid/glimp_sdl2.o
endif
ifeq ($(YQ2_OSTYPE), Windows)
CLIENT_OBJS_ += \
src/backends/windows/main.o \
@ -1368,7 +1393,7 @@ endif
ifeq ($(YQ2_OSTYPE), Windows)
release/q2ded.exe : $(SERVER_OBJS) icon
@echo "===> LD $@"
${Q}$(CC) $(LDFLAGS) build/icon/icon.res $(SERVER_OBJS) $(LDLIBS) $(SDLLDFLAGS) -o $@
${Q}$(CC) $(LDFLAGS) build/icon/icon.res $(SERVER_OBJS) $(LDLIBS) -o $@
$(Q)strip $@
else
release/q2ded : $(SERVER_OBJS)

View file

@ -408,12 +408,14 @@ Set `0` by default.
has 59.95hz.
* **vid_gamma**: The value used for gamma correction. Higher values look
brighter. The OpenGL 1.4 and software renderers use "Hardware Gamma",
setting the Gamma of the whole screen to this value in realtime
(except on MacOS where it's applied to textures on load and thus needs
a `vid_restart` after changing). The OpenGL 3.2 and Vulkan renderers
apply this to the window in realtime via shaders (on all platforms).
This is also set by the brightness slider in the video menu.
brighter. The OpenGL 3.2 OpenGL ES3 and Vulkan renderers apply this to
the window in realtime via shaders (on all platforms). When the game
is build against SDL2, the OpenGL 1.4 renderer uses "hardware gamma"
when available, increasing the brightness of the whole screen. On
MacOS the gamma is applied only at renderer start, so a `vid_restart`
is required. When the game is build against SDL3, the OpenGL 1.4
renderer doesn't support gamma. Have a look at `gl1_overbrightbits`
instead. This is also set by the brightness slider in the video menu.
* **vid_fullscreen**: Sets the fullscreen mode. When set to `0` (the
default) the game runs in window mode. When set to `1` the games
@ -428,10 +430,12 @@ Set `0` by default.
scaling factor of the underlying display. Example: The displays
scaling factor is 1.25 and the user requests 1920x1080. The client
will render at 1920\*1.25x1080\*1.25=2400x1350.
When set to `0` (the default) the client leaves the decision if the
window should be scaled to the underlying compositor. Scaling applied
by the compositor may introduce blur and sluggishness.
When set to `0` the client leaves the decision if the window should
be scaled to the underlying compositor. Scaling applied by the
compositor may introduce blur and sluggishness.
Currently high dpi awareness is only supported under Wayland.
Defaults to `0` when build against SDL2 and to `1` when build against
SDL3.
* **vid_maxfps**: The maximum framerate. *Note* that vsync (`r_vsync`)
also restricts the framerate to the monitor refresh rate, so if vsync
@ -444,9 +448,9 @@ Set `0` by default.
game can be paused, e.g. not in multiplayer games. Defaults to `0`.
* **vid_renderer**: Selects the renderer library. Possible options are
`gl1` (the default) for the old OpenGL 1.4 renderer, `gl3` for the
OpenGL 3.2 renderer, `gles3` for the OpenGL ES3 renderer
and `soft` for the software renderer.
`gl3` (the default) for the OpenGL 3.2 renderer, `gles3` for the
OpenGL ES3 renderer, gl1 for the original OpenGL 1.4 renderer and
`soft` for the software renderer.
* **r_dynamic**: Enamble dynamic light in gl1 and vk renders.

View file

@ -26,8 +26,16 @@
*/
#include <windows.h>
#ifndef DEDICATED_ONLY
#ifdef USE_SDL3
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#else
#include <SDL2/SDL.h>
#include <SDL2/SDL_main.h>
#endif
#endif
#include "../../common/header/common.h"

View file

@ -701,7 +701,7 @@ IN_Update(void)
{
// make sure GLimp_GetRefreshRate() will query from SDL again - the window might
// be on another display now!
glimp_refreshRate = -1;
glimp_refreshRate = -1.0f;
}
else if (event.window.event == SDL_WINDOWEVENT_SHOWN)
{

2389
src/client/input/sdl3.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1920,6 +1920,7 @@ GetRefAPI(refimport_t imp)
ri = imp;
refexport.api_version = API_VERSION;
refexport.framework_version = RI_GetSDLVersion();
refexport.Init = RI_Init;
refexport.Shutdown = RI_Shutdown;

View file

@ -27,7 +27,11 @@
#include "header/local.h"
#ifdef USE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL2/SDL.h>
#endif
#if defined(__APPLE__)
#include <OpenGL/gl.h>
@ -155,7 +159,20 @@ void RI_SetVsync(void)
}
}
#ifdef USE_SDL3
int vsyncState;
if (SDL_GL_GetSwapInterval(&vsyncState) != 0)
{
R_Printf(PRINT_ALL, "Failed to get vsync state, assuming vsync inactive.\n");
vsyncActive = false;
}
else
{
vsyncActive = vsyncState ? true : false;
}
#else
vsyncActive = SDL_GL_GetSwapInterval() != 0;
#endif
}
/*
@ -164,6 +181,10 @@ void RI_SetVsync(void)
void
RI_UpdateGamma(void)
{
// TODO SDL3: Hardware gamma / gamma ramps are no longer supported with
// SDL3. There's no replacement and sdl2-compat won't support it either.
// See https://github.com/libsdl-org/SDL/pull/6617 for the rational.
#ifndef USE_SDL3
float gamma = (vid_gamma->value);
Uint16 ramp[256];
@ -173,6 +194,7 @@ RI_UpdateGamma(void)
{
R_Printf(PRINT_ALL, "Setting gamma failed: %s\n", SDL_GetError());
}
#endif
}
/*
@ -251,7 +273,11 @@ int RI_InitContext(void* win)
#if SDL_VERSION_ATLEAST(2, 26, 0)
// Figure out if we are high dpi aware.
int flags = SDL_GetWindowFlags(win);
#ifdef USE_SDL3
IsHighDPIaware = (flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) ? true : false;
#else
IsHighDPIaware = (flags & SDL_WINDOW_ALLOW_HIGHDPI) ? true : false;
#endif
#endif
return true;
@ -262,7 +288,11 @@ int RI_InitContext(void* win)
*/
void RI_GetDrawableSize(int* width, int* height)
{
#ifdef USE_SDL3
SDL_GetWindowSizeInPixels(window, width, height);
#else
SDL_GL_GetDrawableSize(window, width, height);
#endif
}
/*
@ -280,3 +310,21 @@ RI_ShutdownContext(void)
}
}
}
/*
* Returns the SDL major version. Implemented
* here to not polute gl1_main.c with the SDL
* headers.
*/
int RI_GetSDLVersion()
{
#ifdef USE_SDL3
SDL_Version ver;
#else
SDL_version ver;
#endif
SDL_VERSION(&ver);
return ver.major;
}

View file

@ -426,6 +426,13 @@ void *RI_GetProcAddress (const char* proc);
*/
void RI_GetDrawableSize(int* width, int* height);
/*
* Returns the SDL major version. Implemented
* here to not polute gl1_main.c with the SDL
* headers.
*/
int RI_GetSDLVersion();
/* g11_draw */
extern image_t * RDraw_FindPic(const char *name);
extern void RDraw_GetPicSize(int *w, int *h, const char *pic);

View file

@ -1995,6 +1995,7 @@ GetRefAPI(refimport_t imp)
ri = imp;
re.api_version = API_VERSION;
re.framework_version = GL3_GetSDLVersion();
re.Init = GL3_Init;
re.Shutdown = GL3_Shutdown;

View file

@ -29,7 +29,11 @@
#include "header/local.h"
#ifdef USE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL2/SDL.h>
#endif
static SDL_Window* window = NULL;
static SDL_GLContext context = NULL;
@ -162,7 +166,20 @@ void GL3_SetVsync(void)
}
}
#ifdef USE_SDL3
int vsyncState;
if (SDL_GL_GetSwapInterval(&vsyncState) != 0)
{
R_Printf(PRINT_ALL, "Failed to get vsync state, assuming vsync inactive.\n");
vsyncActive = false;
}
else
{
vsyncActive = vsyncState ? true : false;
}
#else
vsyncActive = SDL_GL_GetSwapInterval() != 0;
#endif
}
/*
@ -345,9 +362,9 @@ int GL3_InitContext(void* win)
// Load GL pointers through GLAD and check context.
#ifdef YQ2_GL3_GLES
if( !gladLoadGLES2Loader(SDL_GL_GetProcAddress))
if( !gladLoadGLES2Loader((void *)SDL_GL_GetProcAddress))
#else // Desktop GL
if( !gladLoadGLLoader(SDL_GL_GetProcAddress))
if( !gladLoadGLLoader((void *)SDL_GL_GetProcAddress))
#endif
{
R_Printf(PRINT_ALL, "GL3_InitContext(): ERROR: loading OpenGL function pointers failed!\n");
@ -406,7 +423,11 @@ int GL3_InitContext(void* win)
#if SDL_VERSION_ATLEAST(2, 26, 0)
// Figure out if we are high dpi aware.
int flags = SDL_GetWindowFlags(win);
#ifdef USE_SDL3
IsHighDPIaware = (flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) ? true : false;
#else
IsHighDPIaware = (flags & SDL_WINDOW_ALLOW_HIGHDPI) ? true : false;
#endif
#endif
return true;
@ -417,7 +438,11 @@ int GL3_InitContext(void* win)
*/
void GL3_GetDrawableSize(int* width, int* height)
{
#ifdef USE_SDL3
SDL_GetWindowSizeInPixels(window, width, height);
#else
SDL_GL_GetDrawableSize(window, width, height);
#endif
}
/*
@ -434,3 +459,21 @@ void GL3_ShutdownContext()
}
}
}
/*
* Returns the SDL major version. Implemented
* here to not polute gl3_main.c with the SDL
* headers.
*/
int GL3_GetSDLVersion()
{
#ifdef USE_SDL3
SDL_Version ver;
#else
SDL_version ver;
#endif
SDL_VERSION(&ver);
return ver.major;
}

View file

@ -393,6 +393,7 @@ extern qboolean GL3_IsVsyncActive(void);
extern void GL3_EndFrame(void);
extern void GL3_SetVsync(void);
extern void GL3_ShutdownContext(void);
extern int GL3_GetSDLVersion(void);
// gl3_misc.c
extern void GL3_InitParticleTexture(void);

View file

@ -22,8 +22,12 @@
#include <stdint.h>
#include <limits.h>
#ifdef USE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL2/SDL.h>
#include <SDL2/SDL_video.h>
#endif
#include "header/local.h"
@ -1802,10 +1806,19 @@ GetRefAPI(refimport_t imp)
// used different variable name for prevent confusion and cppcheck warnings
refexport_t refexport;
// Need to communicate the SDL major version to the client.
#ifdef USE_SDL3
SDL_Version ver;
#else
SDL_version ver;
#endif
SDL_VERSION(&ver);
memset(&refexport, 0, sizeof(refexport_t));
ri = imp;
refexport.api_version = API_VERSION;
refexport.framework_version = ver.major;
refexport.BeginRegistration = RE_BeginRegistration;
refexport.RegisterModel = RE_RegisterModel;
@ -1890,11 +1903,19 @@ RE_InitContext(void *win)
if (r_vsync->value)
{
#ifdef USE_SDL3
renderer = SDL_CreateRenderer(window, NULL, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
#else
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
#endif
}
else
{
#ifdef USE_SDL3
renderer = SDL_CreateRenderer(window, NULL, SDL_RENDERER_ACCELERATED);
#else
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
#endif
}
/* Select the color for drawing. It is set to black here. */
@ -1910,7 +1931,11 @@ RE_InitContext(void *win)
#if SDL_VERSION_ATLEAST(2, 26, 0)
// Figure out if we are high dpi aware.
int flags = SDL_GetWindowFlags(win);
#ifdef USE_SDL3
IsHighDPIaware = (flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) ? true : false;
#else
IsHighDPIaware = (flags & SDL_WINDOW_ALLOW_HIGHDPI) ? true : false;
#endif
#endif
/* We can't rely on vid, because the context is created
@ -1949,7 +1974,11 @@ RE_InitContext(void *win)
*/
void RE_GetDrawableSize(int* width, int* height)
{
#ifdef USE_SDL3
SDL_GetCurrentRenderOutputSize(renderer, width, height);
#else
SDL_GetRendererOutputSize(renderer, width, height);
#endif
}
@ -2225,7 +2254,12 @@ RE_FlushFrame(int vmin, int vmax)
SDL_UnlockTexture(texture);
#ifdef USE_SDL3
SDL_RenderTexture(renderer, texture, NULL, NULL);
#else
SDL_RenderCopy(renderer, texture, NULL, NULL);
#endif
SDL_RenderPresent(renderer);
// replace use next buffer

View file

@ -19,7 +19,11 @@
*
*/
#ifdef USE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL2/SDL.h>
#endif
#include "header/local.h"

View file

@ -34,7 +34,11 @@
*/
/* SDL includes */
#ifdef USE_SDL3
#include <SDL3/SDL.h>
#else
#include <SDL2/SDL.h>
#endif
/* Local includes */
#include "../../client/header/client.h"
@ -811,7 +815,9 @@ SDL_ClearBuffer(void)
clear = 0;
}
#ifndef USE_SDL3
SDL_LockAudio();
#endif
if (sound.buffer)
{
@ -827,7 +833,9 @@ SDL_ClearBuffer(void)
}
}
#ifndef USE_SDL3
SDL_UnlockAudio();
#endif
}
/*
@ -1191,7 +1199,9 @@ SDL_Update(void)
}
/* Mix the samples */
#ifndef USE_SDL3
SDL_LockAudio();
#endif
/* Updates SDL time */
SDL_UpdateSoundtime();
@ -1221,7 +1231,9 @@ SDL_Update(void)
}
SDL_PaintChannels(endtime);
#ifndef USE_SDL3
SDL_UnlockAudio();
#endif
}
/* ------------------------------------------------------------------ */
@ -1297,6 +1309,193 @@ SDL_Callback(void *data, Uint8 *stream, int length)
}
}
#ifdef USE_SDL3
/* Global stream handle. */
static SDL_AudioStream *stream;
/* Wrapper function, ties the old existing callback logic
* from the SDL 1.2 days and later fiddled into SDL 2 to
* a SDL 3 compatible callback...
*/
static void
SDL_SDL3Callback(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount)
{
if (additional_amount > 0) {
Uint8 *data = SDL_stack_alloc(Uint8, additional_amount);
if (data) {
SDL_Callback(userdata, data, additional_amount);
SDL_PutAudioStreamData(stream, data, additional_amount);
SDL_stack_free(data);
}
}
}
/*
* Initializes the SDL sound
* backend and sets up SDL.
*/
qboolean
SDL_BackendInit(void)
{
char reqdriver[128];
SDL_AudioSpec spec;
int samples, tmp, val;
/* This should never happen,
but this is Quake 2 ... */
if (snd_inited)
{
return 1;
}
int sndbits = (Cvar_Get("sndbits", "16", CVAR_ARCHIVE))->value;
int sndfreq = (Cvar_Get("s_khz", "44", CVAR_ARCHIVE))->value;
int sndchans = (Cvar_Get("sndchannels", "2", CVAR_ARCHIVE))->value;
#ifdef _WIN32
s_sdldriver = (Cvar_Get("s_sdldriver", "directsound", CVAR_ARCHIVE));
#elif __linux__
s_sdldriver = (Cvar_Get("s_sdldriver", "alsa", CVAR_ARCHIVE));
#elif __APPLE__
s_sdldriver = (Cvar_Get("s_sdldriver", "CoreAudio", CVAR_ARCHIVE));
#else
s_sdldriver = (Cvar_Get("s_sdldriver", "dsp", CVAR_ARCHIVE));
#endif
snprintf(reqdriver, sizeof(reqdriver), "%s=%s", "SDL_AUDIODRIVER", s_sdldriver->string);
putenv(reqdriver);
Com_Printf("Starting SDL audio callback.\n");
if (!SDL_WasInit(SDL_INIT_AUDIO))
{
if (SDL_Init(SDL_INIT_AUDIO) == -1)
{
Com_Printf ("Couldn't init SDL audio: %s.\n", SDL_GetError ());
return 0;
}
}
const char* drivername = SDL_GetCurrentAudioDriver();
if(drivername == NULL)
{
drivername = "(UNKNOWN)";
}
Com_Printf("SDL audio driver is \"%s\".\n", drivername);
memset(&samples, '\0', sizeof(samples));
/* Users are stupid */
if ((sndbits != 16) && (sndbits != 8))
{
sndbits = 16;
}
if (sndfreq == 48)
{
spec.freq = 48000;
}
else if (sndfreq == 44)
{
spec.freq = 44100;
}
else if (sndfreq == 22)
{
spec.freq = 22050;
}
else if (sndfreq == 11)
{
spec.freq = 11025;
}
spec.format = ((sndbits == 16) ? SDL_AUDIO_S16 : SDL_AUDIO_U8);
if (spec.freq <= 11025)
{
samples = 256;
}
else if (spec.freq <= 22050)
{
samples = 512;
}
else if (spec.freq <= 44100)
{
samples = 1024;
}
else
{
samples = 2048;
}
spec.channels = sndchans;
/* Okay, let's try our luck */
stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec, SDL_SDL3Callback, NULL);
if (stream == NULL)
{
Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError());
SDL_QuitSubSystem(SDL_INIT_AUDIO);
return 0;
}
/* This points to the frontend */
backend = &sound;
playpos = 0;
backend->samplebits = spec.format & 0xFF;
backend->channels = spec.channels;
tmp = (samples * spec.channels) * 10;
if (tmp & (tmp - 1))
{ /* make it a power of two */
val = 1;
while (val < tmp)
val <<= 1;
tmp = val;
}
backend->samples = tmp;
backend->submission_chunk = 1;
backend->speed = spec.freq;
samplesize = (backend->samples * (backend->samplebits / 8));
backend->buffer = calloc(1, samplesize);
s_numchannels = MAX_CHANNELS;
s_underwater->modified = true;
s_underwater_gain_hf->modified = true;
lpf_initialize(&lpf_context, lpf_default_gain_hf, backend->speed);
SDL_UpdateScaletable();
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream));
Com_Printf("SDL audio initialized.\n");
soundtime = 0;
snd_inited = 1;
return 1;
}
/*
* Shuts the SDL backend down.
*/
void
SDL_BackendShutdown(void)
{
Com_Printf("Closing SDL audio device...\n");
SDL_PauseAudioDevice(SDL_GetAudioStreamDevice(stream));
SDL_DestroyAudioStream(stream);
SDL_QuitSubSystem(SDL_INIT_AUDIO);
free(backend->buffer);
backend->buffer = NULL;
playpos = samplesize = 0;
snd_inited = 0;
Com_Printf("SDL audio device shut down.\n");
}
#else
/*
* Initializes the SDL sound
* backend and sets up SDL.
@ -1464,4 +1663,4 @@ SDL_BackendShutdown(void)
snd_inited = 0;
Com_Printf("SDL audio device shut down.\n");
}
#endif

View file

@ -33,7 +33,7 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_video.h>
int glimp_refreshRate = -1;
float glimp_refreshRate = -1.0f;
static cvar_t *vid_displayrefreshrate;
static cvar_t *vid_displayindex;
@ -733,35 +733,19 @@ GLimp_GrabInput(qboolean grab)
}
/*
* Returns the current display refresh rate. There're 2 limitations:
*
* * The timing code in frame.c only understands full integers, so
* values given by vid_displayrefreshrate are always round up. For
* example 59.95 become 60. Rounding up is the better choice for
* most users because assuming a too high display refresh rate
* avoids micro stuttering caused by missed frames if the vsync
* is enabled. The price are small and hard to notice timing
* problems.
*
* * SDL returns only full integers. In most cases they're rounded
* up, but in some cases - likely depending on the GPU driver -
* they're rounded down. If the value is rounded up, we'll see
* some small and nard to notice timing problems. If the value
* is rounded down frames will be missed. Both is only relevant
* if the vsync is enabled.
* Returns the current display refresh rate.
*/
int
float
GLimp_GetRefreshRate(void)
{
if (vid_displayrefreshrate->value > -1 ||
vid_displayrefreshrate->modified)
{
glimp_refreshRate = ceil(vid_displayrefreshrate->value);
glimp_refreshRate = vid_displayrefreshrate->value;
vid_displayrefreshrate->modified = false;
}
if (glimp_refreshRate == -1)
else if (glimp_refreshRate == -1)
{
SDL_DisplayMode mode;
@ -835,3 +819,12 @@ GLimp_GetWindowDisplayIndex(void)
{
return last_display;
}
int
GLimp_GetFrameworkVersion(void)
{
SDL_version ver;
SDL_VERSION(&ver);
return ver.major;
}

913
src/client/vid/glimp_sdl3.c Normal file
View file

@ -0,0 +1,913 @@
/*
* Copyright (C) 2010 Yamagi Burmeister
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* This is the client side of the render backend, implemented trough SDL.
* The SDL window and related functrion (mouse grap, fullscreen switch)
* are implemented here, everything else is in the renderers.
*
* =======================================================================
*/
/* TODO SDL3:
* * Bump copyright.
* * Do we need to request High DPI modes when vid_highdpiaware > 0?
* * `fullscreen` should be an enum to make the code more readable.
* * Debug fullscreen handling, maybe refactor it further.
* * Check if window size handling is correct.
* * Check pointers returned by SDL functions for memory leaks.
*/
#include "../../common/header/common.h"
#include "header/ref.h"
#include <SDL3/SDL.h>
float glimp_refreshRate = -1.0f;
static cvar_t *vid_displayrefreshrate;
static cvar_t *vid_displayindex;
static cvar_t *vid_highdpiaware;
static cvar_t *vid_rate;
static int last_flags = 0;
static int last_display = 0;
static int last_position_x = SDL_WINDOWPOS_UNDEFINED;
static int last_position_y = SDL_WINDOWPOS_UNDEFINED;
static SDL_Window* window = NULL;
static qboolean initSuccessful = false;
static char **displayindices = NULL;
static int num_displays = 0;
/* Fullscreen modes */
enum
{
FULLSCREEN_OFF = 0,
FULLSCREEN_EXCLUSIVE = 1,
FULLSCREEN_DESKTOP = 2
};
/*
* Resets the display index Cvar if out of bounds
*/
static void
ClampDisplayIndexCvar(void)
{
if (!vid_displayindex)
{
// uninitialized render?
return;
}
if (vid_displayindex->value < 0 || vid_displayindex->value >= num_displays)
{
Cvar_SetValue("vid_displayindex", 0);
}
}
static void
ClearDisplayIndices(void)
{
if ( displayindices )
{
for ( int i = 0; i < num_displays; i++ )
{
free( displayindices[ i ] );
}
free( displayindices );
displayindices = NULL;
}
}
static qboolean
CreateSDLWindow(int flags, int fullscreen, int w, int h)
{
if (SDL_WINDOWPOS_ISUNDEFINED(last_position_x) || SDL_WINDOWPOS_ISUNDEFINED(last_position_y) || last_position_x < 0 ||last_position_y < 24)
{
last_position_x = last_position_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY((int)vid_displayindex->value);
}
/* Force the window to minimize when focus is lost. This was the
* default behavior until SDL 2.0.12 and changed with 2.0.14.
* The windows staying maximized has some odd implications for
* window ordering under Windows and some X11 window managers
* like kwin. See:
* * https://github.com/libsdl-org/SDL/issues/4039
* * https://github.com/libsdl-org/SDL/issues/3656 */
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1");
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, "Yamagi Quake II");
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, last_position_x);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, last_position_y);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, w);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, h);
SDL_SetNumberProperty(props, "flags", flags);
window = SDL_CreateWindowWithProperties(props);
SDL_DestroyProperties(props);
if (window)
{
/* save current display as default */
if ((last_display = SDL_GetDisplayForWindow(window)) == 0)
{
/* There are some obscure setups were SDL is
unable to get the current display,one X11
server with several screen is one of these,
so add a fallback to the first display. */
last_display = 1;
}
/* Set requested fullscreen mode. */
if (flags & SDL_WINDOW_FULLSCREEN)
{
/* SDLs behavior changed between SDL 2 and SDL 3: In SDL 2
the fullscreen window could be set with whatever mode
was requested. In SDL 3 the fullscreen window is always
created at desktop resolution. If a fullscreen window
is requested, we can't do anything else and are done here. */
if (fullscreen == FULLSCREEN_DESKTOP)
{
return true;
}
/* Otherwise try to find a mode near the requested one and
switch to it in exclusive fullscreen mode. */
/* TODO SDL3: Leak? */
const SDL_DisplayMode *closestMode = SDL_GetClosestFullscreenDisplayMode(last_display, w, h, vid_rate->value, false);
if (closestMode == NULL)
{
Com_Printf("SDL was unable to find a mode close to %ix%i@%f\n", w, h, vid_rate->value);
if (vid_rate->value != 0)
{
Com_Printf("Retrying with desktop refresh rate\n");
closestMode = SDL_GetClosestFullscreenDisplayMode(last_display, w, h, 0, false);
if (closestMode != NULL)
{
Cvar_SetValue("vid_rate", 0);
}
else
{
Com_Printf("SDL was unable to find a mode close to %ix%i@0\n", w, h);
return false;
}
}
}
Com_Printf("User requested %ix%i@%f, setting closest mode %ix%i@%f\n",
w, h, vid_rate->value, closestMode->w, closestMode->h , closestMode->refresh_rate);
/* TODO SDL3: Same code is in InitGraphics(), refactor into
* a function? */
if (SDL_SetWindowFullscreenMode(window, closestMode) < 0)
{
Com_Printf("Couldn't set closest mode: %s\n", SDL_GetError());
return false;
}
if (SDL_SetWindowFullscreen(window, true) < 0)
{
Com_Printf("Couldn't switch to exclusive fullscreen: %s\n", SDL_GetError());
return false;
}
int ret = SDL_SyncWindow(window);
if (ret > 0)
{
Com_Printf("Synchronizing window state timed out\n");
return false;
}
else if (ret < 0)
{
Com_Printf("Couldn't synchronize window state: %s\n", SDL_GetError());
return false;
}
}
}
else
{
Com_Printf("Creating window failed: %s\n", SDL_GetError());
return false;
}
return true;
}
static int
GetFullscreenType()
{
if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)
{
/* TODO SDL3: Leak? */
const SDL_DisplayMode *fsmode = SDL_GetWindowFullscreenMode(window);
if (fsmode != NULL)
{
return FULLSCREEN_EXCLUSIVE;
}
else
{
return FULLSCREEN_DESKTOP;
}
}
return FULLSCREEN_OFF;
}
static qboolean
GetWindowSize(int* w, int* h)
{
if (window == NULL || w == NULL || h == NULL)
{
return false;
}
if (SDL_GetWindowSize(window, w, h) < 0)
{
Com_Printf("Couldn't get window size: %s\n", SDL_GetError());
return false;
}
return true;
}
static void
InitDisplayIndices()
{
displayindices = malloc((num_displays + 1) * sizeof(char *));
for ( int i = 0; i < num_displays; i++ )
{
/* There are a maximum of 10 digits in 32 bit int + 1 for the NULL terminator. */
displayindices[ i ] = malloc(11 * sizeof( char ));
YQ2_COM_CHECK_OOM(displayindices[i], "malloc()", 11 * sizeof( char ))
snprintf( displayindices[ i ], 11, "%d", i );
}
/* The last entry is NULL to indicate the list of strings ends. */
displayindices[ num_displays ] = 0;
}
/*
* Lists all available display modes.
*/
static void
PrintDisplayModes(void)
{
int curdisplay;
if (window == NULL)
{
/* Called without a windows, list modes
from the first display. This is the
primary display and likely the one the
game will run on. */
curdisplay = SDL_GetPrimaryDisplay();
}
else
{
/* Otherwise use the window were the window
is displayed. There are some obscure
setups were this can fail - one X11 server
with several screen is one of these - so
add a fallback to the first display. */
if ((curdisplay = SDL_GetDisplayForWindow(window)) == 0)
{
curdisplay = SDL_GetPrimaryDisplay();
}
}
int nummodes = 0;
const SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(curdisplay, &nummodes);
if (modes)
{
for (int i = 0; i < nummodes; ++i)
{
const SDL_DisplayMode *mode = modes[i];
Com_Printf(" - Mode %2i: %ix%i@%.2f\n", i, mode->w, mode->h, mode->refresh_rate);
}
SDL_free(modes);
}
else
{
Com_Printf("Couldn't get display modes: %s\n", SDL_GetError());
}
}
/*
* Sets the window icon
*/
static void
SetSDLIcon()
{
#include "icon/q2icon64.h" // 64x64 32 Bit
/* these masks are needed to tell SDL_CreateRGBSurface(From)
to assume the data it gets is byte-wise RGB(A) data */
Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
int shift = (q2icon64.bytes_per_pixel == 3) ? 8 : 0;
rmask = 0xff000000 >> shift;
gmask = 0x00ff0000 >> shift;
bmask = 0x0000ff00 >> shift;
amask = 0x000000ff >> shift;
#else /* little endian, like x86 */
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = (q2icon64.bytes_per_pixel == 3) ? 0 : 0xff000000;
#endif
SDL_Surface* icon = SDL_CreateSurfaceFrom((void *)q2icon64.pixel_data, q2icon64.width, q2icon64.height, q2icon64.bytes_per_pixel * q2icon64.width, SDL_GetPixelFormatEnumForMasks(q2icon64.bytes_per_pixel * 8, rmask, gmask, bmask, amask));
SDL_SetWindowIcon(window, icon);
SDL_DestroySurface(icon);
}
// FIXME: We need a header for this.
// Maybe we could put it in vid.h.
void GLimp_GrabInput(qboolean grab);
/*
* Shuts the SDL render backend down
*/
static void
ShutdownGraphics(void)
{
ClampDisplayIndexCvar();
if (window)
{
/* save current display as default */
last_display = SDL_GetDisplayForWindow(window);
/* or if current display isn't the desired default */
if (last_display != vid_displayindex->value) {
last_position_x = last_position_y = SDL_WINDOWPOS_UNDEFINED;
last_display = vid_displayindex->value;
}
else {
SDL_GetWindowPosition(window,
&last_position_x, &last_position_y);
}
/* cleanly ungrab input (needs window) */
GLimp_GrabInput(false);
SDL_DestroyWindow(window);
window = NULL;
}
// make sure that after vid_restart the refreshrate will be queried from SDL2 again.
glimp_refreshRate = -1;
initSuccessful = false; // not initialized anymore
}
// --------
/*
* Initializes the SDL video subsystem. Must
* be called before anything else.
*/
qboolean
GLimp_Init(void)
{
vid_displayrefreshrate = Cvar_Get("vid_displayrefreshrate", "-1", CVAR_ARCHIVE);
vid_displayindex = Cvar_Get("vid_displayindex", "0", CVAR_ARCHIVE);
vid_highdpiaware = Cvar_Get("vid_highdpiaware", "1", CVAR_ARCHIVE);
vid_rate = Cvar_Get("vid_rate", "-1", CVAR_ARCHIVE);
if (!SDL_WasInit(SDL_INIT_VIDEO))
{
if (SDL_Init(SDL_INIT_VIDEO) == -1)
{
Com_Printf("Couldn't init SDL video: %s.\n", SDL_GetError());
return false;
}
SDL_Version version;
SDL_GetVersion(&version);
Com_Printf("-------- vid initialization --------\n");
Com_Printf("SDL version is: %i.%i.%i\n", (int)version.major, (int)version.minor, (int)version.patch);
Com_Printf("SDL video driver is \"%s\".\n", SDL_GetCurrentVideoDriver());
SDL_DisplayID *displays;
if ((displays = SDL_GetDisplays(&num_displays)) == NULL)
{
Com_Printf("Couldn't get number of displays: %s\n", SDL_GetError());
}
else
{
SDL_free(displays);
}
InitDisplayIndices();
ClampDisplayIndexCvar();
Com_Printf("SDL display modes:\n");
PrintDisplayModes();
Com_Printf("------------------------------------\n\n");
}
return true;
}
/*
* Shuts the SDL video subsystem down. Must
* be called after evrything's finished and
* clean up.
*/
void
GLimp_Shutdown(void)
{
ShutdownGraphics();
SDL_QuitSubSystem(SDL_INIT_VIDEO);
ClearDisplayIndices();
}
/*
* Determine if we want to be high dpi aware. If
* we are we must scale ourself. If we are not the
* compositor might scale us.
*/
static int
Glimp_DetermineHighDPISupport(int flags)
{
/* Make sure that high dpi is never set when we don't want it. */
flags &= ~SDL_WINDOW_HIGH_PIXEL_DENSITY;
if (vid_highdpiaware->value == 0)
{
return flags;
}
/* Handle high dpi awareness based on the render backend.
SDL doesn't support high dpi awareness for all backends
and the quality and behavior differs between them. */
if ((strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0))
{
flags |= SDL_WINDOW_HIGH_PIXEL_DENSITY;
}
return flags;
}
/*
* (Re)initializes the actual window.
*/
qboolean
GLimp_InitGraphics(int fullscreen, int *pwidth, int *pheight)
{
int flags;
int curWidth, curHeight;
int width = *pwidth;
int height = *pheight;
unsigned int fs_flag = 0;
if (fullscreen == FULLSCREEN_EXCLUSIVE || fullscreen == FULLSCREEN_DESKTOP)
{
fs_flag = SDL_WINDOW_FULLSCREEN;
}
/* Only do this if we already have a working window and a fully
initialized rendering backend GLimp_InitGraphics() is also
called when recovering if creating GL context fails or the
one we got is unusable. */
if (initSuccessful && GetWindowSize(&curWidth, &curHeight)
&& (curWidth == width) && (curHeight == height))
{
/* TODO SDL3: Leak? */
const SDL_DisplayMode *closestMode = NULL;
/* If we want fullscreen, but aren't */
if (GetFullscreenType())
{
if (fullscreen == FULLSCREEN_EXCLUSIVE)
{
closestMode = SDL_GetClosestFullscreenDisplayMode(last_display, width, height, vid_rate->value, false);
if (closestMode == NULL)
{
Com_Printf("SDL was unable to find a mode close to %ix%i@%f\n", width, height, vid_rate->value);
if (vid_rate->value != 0)
{
Com_Printf("Retrying with desktop refresh rate\n");
closestMode = SDL_GetClosestFullscreenDisplayMode(last_display, width, height, 0, false);
if (closestMode != NULL)
{
Cvar_SetValue("vid_rate", 0);
}
else
{
Com_Printf("SDL was unable to find a mode close to %ix%i@0\n", width, height);
return false;
}
}
}
}
else if (fullscreen == FULLSCREEN_DESKTOP)
{
/* Fullscreen window */
closestMode = NULL;
}
if (SDL_SetWindowFullscreenMode(window, closestMode) < 0)
{
Com_Printf("Couldn't set fullscreen modmode: %s\n", SDL_GetError());
Cvar_SetValue("vid_fullscreen", 0);
}
else
{
if (SDL_SetWindowFullscreen(window, true) < 0)
{
Com_Printf("Couldn't switch to exclusive fullscreen: %s\n", SDL_GetError());
Cvar_SetValue("vid_fullscreen", 0);
}
else
{
int ret = SDL_SyncWindow(window);
if (ret > 0)
{
Com_Printf("Synchronizing window state timed out\n");
Cvar_SetValue("vid_fullscreen", 0);
}
else if (ret < 0)
{
Com_Printf("Couldn't synchronize window state: %s\n", SDL_GetError());
Cvar_SetValue("vid_fullscreen", 0);
}
}
}
Cvar_SetValue("vid_fullscreen", fullscreen);
}
/* Are we now? */
if (GetFullscreenType())
{
return true;
}
}
/* Is the surface used? */
if (window)
{
re.ShutdownContext();
ShutdownGraphics();
window = NULL;
}
if(last_flags != -1 && (last_flags & SDL_WINDOW_OPENGL))
{
/* Reset SDL. */
SDL_GL_ResetAttributes();
}
/* Let renderer prepare things (set OpenGL attributes).
FIXME: This is no longer necessary, the renderer
could and should pass the flags when calling this
function. */
flags = re.PrepareForWindow();
if (flags == -1)
{
/* It's PrepareForWindow() job to log an error */
return false;
}
if (fs_flag)
{
flags |= fs_flag;
}
/* Check for high dpi support. */
flags = Glimp_DetermineHighDPISupport(flags);
/* Mkay, now the hard work. Let's create the window. */
cvar_t *gl_msaa_samples = Cvar_Get("r_msaa_samples", "0", CVAR_ARCHIVE);
while (1)
{
if (!CreateSDLWindow(flags, fullscreen, width, height))
{
if((flags & SDL_WINDOW_OPENGL) && gl_msaa_samples->value)
{
int msaa_samples = gl_msaa_samples->value;
if (msaa_samples > 0)
{
msaa_samples /= 2;
}
Com_Printf("SDL SetVideoMode failed: %s\n", SDL_GetError());
Com_Printf("Reverting to %s r_mode %i (%ix%i) with %dx MSAA.\n",
(flags & fs_flag) ? "fullscreen" : "windowed",
(int) Cvar_VariableValue("r_mode"), width, height,
msaa_samples);
/* Try to recover */
Cvar_SetValue("r_msaa_samples", msaa_samples);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS,
msaa_samples > 0 ? 1 : 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,
msaa_samples);
}
else if (width != 640 || height != 480 || (flags & fs_flag))
{
Com_Printf("SDL SetVideoMode failed: %s\n", SDL_GetError());
Com_Printf("Reverting to windowed r_mode 4 (640x480).\n");
/* Try to recover */
Cvar_SetValue("r_mode", 4);
Cvar_SetValue("vid_fullscreen", 0);
Cvar_SetValue("vid_rate", -1);
fullscreen = FULLSCREEN_OFF;
*pwidth = width = 640;
*pheight = height = 480;
flags &= ~fs_flag;
}
else
{
Com_Printf("Failed to revert to r_mode 4. Will try another render backend...\n");
return false;
}
}
else
{
break;
}
}
last_flags = flags;
/* Now that we've got a working window print it's mode. */
int curdisplay;
if ((curdisplay = SDL_GetDisplayForWindow(window)) == 0)
{
/* There are some obscure setups were SDL is
unable to get the current display,one X11
server with several screen is one of these,
so add a fallback to the first display. */
curdisplay = SDL_GetPrimaryDisplay();
}
const SDL_DisplayMode *mode;
if ((mode = SDL_GetCurrentDisplayMode(curdisplay)) == NULL)
{
Com_Printf("Couldn't get current display mode: %s\n", SDL_GetError());
}
else
{
Com_Printf("Real display mode: %ix%i@%.2f\n", mode->w, mode->h, mode->refresh_rate);
}
/* Initialize rendering context. */
if (!re.InitContext(window))
{
/* InitContext() should have logged an error. */
return false;
}
/* We need the actual drawable size for things like the
console, the menus, etc. This might be different to
the resolution due to high dpi awareness.
The fullscreen window is special. We want it to fill
the screen when native resolution is requestes, all
other cases should look broken. */
if (flags & SDL_WINDOW_HIGH_PIXEL_DENSITY)
{
if (fullscreen != FULLSCREEN_DESKTOP)
{
re.GetDrawableSize(&viddef.width, &viddef.height);
}
else
{
cvar_t *r_mode = Cvar_Get("r_mode", "4", 0);
if (r_mode->value == -2 )
{
re.GetDrawableSize(&viddef.width, &viddef.height);
}
else
{
/* User likes it broken. */
viddef.width = *pwidth;
viddef.height = *pheight;
}
}
}
else
{
/* Another bug or design failure in SDL: When we are
not high dpi aware the drawable size returned by
SDL may be too small. It seems like the window
decoration are taken into account when they shouldn't.
It can be seen when creating a fullscreen window.
Work around that by always using the resolution and
not the drawable size when we are not high dpi aware. */
viddef.width = *pwidth;
viddef.height = *pheight;
}
Com_Printf("Drawable size: %ix%i\n", viddef.width, viddef.height);
/* Set the window icon - For SDL2, this must be done after creating the window */
SetSDLIcon();
/* No cursor */
SDL_ShowCursor();
initSuccessful = true;
return true;
}
/*
* Shuts the window down.
*/
void
GLimp_ShutdownGraphics(void)
{
SDL_GL_ResetAttributes();
ShutdownGraphics();
}
/*
* (Un)grab Input
*/
void
GLimp_GrabInput(qboolean grab)
{
if(window != NULL)
{
SDL_SetWindowMouseGrab(window, grab ? SDL_TRUE : SDL_FALSE);
}
if(SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE) < 0)
{
Com_Printf("WARNING: Setting Relative Mousemode failed, reason: %s\n", SDL_GetError());
Com_Printf(" You should probably update to SDL 2.0.3 or newer!\n");
}
}
/*
* Returns the current display refresh rate.
*/
float
GLimp_GetRefreshRate(void)
{
if (vid_displayrefreshrate->value > -1 ||
vid_displayrefreshrate->modified)
{
glimp_refreshRate = vid_displayrefreshrate->value;
vid_displayrefreshrate->modified = false;
}
else if (glimp_refreshRate == -1)
{
const SDL_DisplayMode *mode;
int curdisplay;
if (window == NULL)
{
/* This is paranoia. This function should only be
called if there is a working window. Otherwise
things will likely break somewhere else in the
client. */
curdisplay = SDL_GetPrimaryDisplay();
}
else
{
if ((curdisplay = SDL_GetDisplayForWindow(window)) == 0)
{
/* There are some obscure setups were SDL is
unable to get the current display,one X11
server with several screen is one of these,
so add a fallback to the first display. */
curdisplay = SDL_GetPrimaryDisplay();
}
}
if ((mode = SDL_GetCurrentDisplayMode(curdisplay)) == NULL)
{
printf("Couldn't get display refresh rate: %s\n", SDL_GetError());
}
else
{
glimp_refreshRate = mode->refresh_rate;
}
}
return glimp_refreshRate;
}
/*
* Detect current desktop mode
*/
qboolean
GLimp_GetDesktopMode(int *pwidth, int *pheight)
{
if (window == NULL)
{
/* Renderers call into this function before the
window is created. This could be refactored
by passing the mode and not the geometry from
the renderer to GLimp_InitGraphics(), however
that would break the renderer API. */
last_display = SDL_GetPrimaryDisplay();
}
else
{
/* save current display as default */
if ((last_display = SDL_GetDisplayForWindow(window)) == 0)
{
/* There are some obscure setups were SDL is
unable to get the current display,one X11
server with several screen is one of these,
so add a fallback to the first display. */
last_display = SDL_GetPrimaryDisplay();
}
SDL_GetWindowPosition(window, &last_position_x, &last_position_y);
}
const SDL_DisplayMode *mode;
if ((mode = SDL_GetCurrentDisplayMode(last_display)) == NULL)
{
Com_Printf("Couldn't detect default desktop mode: %s\n", SDL_GetError());
return false;
}
*pwidth = mode->w;
*pheight = mode->h;
return true;
}
const char**
GLimp_GetDisplayIndices(void)
{
return (const char**)displayindices;
}
int
GLimp_GetNumVideoDisplays(void)
{
return num_displays;
}
int
GLimp_GetWindowDisplayIndex(void)
{
return last_display;
}
int
GLimp_GetFrameworkVersion(void)
{
SDL_Version ver;
SDL_VERSION(&ver);
return ver.major;
}

View file

@ -125,7 +125,7 @@ typedef enum {
} ref_restart_t;
// FIXME: bump API_VERSION?
#define API_VERSION 6
#define API_VERSION 7
#define EXPORT
#define IMPORT
@ -137,6 +137,11 @@ typedef struct
// if api_version is different, the dll cannot be used
int api_version;
// if framework_version is different, the dll cannot be used
// necessary because differend SDL major version cannot be
// mixed.
int framework_version;
// called when the library is loaded
qboolean (EXPORT *Init) (void);

View file

@ -54,7 +54,7 @@ void VID_MenuDraw(void);
const char *VID_MenuKey(int);
// Stuff provided by platform backend.
extern int glimp_refreshRate;
extern float glimp_refreshRate;
const char **GLimp_GetDisplayIndices(void);
int GLimp_GetWindowDisplayIndex(void);
@ -64,7 +64,8 @@ void GLimp_Shutdown(void);
qboolean GLimp_InitGraphics(int fullscreen, int *pwidth, int *pheight);
void GLimp_ShutdownGraphics(void);
void GLimp_GrabInput(qboolean grab);
int GLimp_GetRefreshRate(void);
float GLimp_GetRefreshRate(void);
qboolean GLimp_GetDesktopMode(int *pwidth, int *pheight);
int GLimp_GetFrameworkVersion(void);
#endif

View file

@ -456,9 +456,17 @@ VID_LoadRenderer(void)
// Let's check if we've got a compatible renderer.
if (re.api_version != API_VERSION)
{
Com_Printf("%s has incompatible api_version %d!\n", reflib_name, re.api_version);
VID_ShutdownRenderer();
Com_Printf("%s has incompatible api_version %d!\n", reflib_name, re.api_version);
return false;
}
else if (re.framework_version != GLimp_GetFrameworkVersion())
{
Com_Printf("%s has incompatible sdl_version %d!\n", reflib_name, re.framework_version);
VID_ShutdownRenderer();
return false;
}
@ -525,8 +533,9 @@ VID_CheckChanges(void)
// Mkay, let's try our luck.
while (!VID_LoadRenderer())
{
// We try: custom -> gl3 -> gl1 -> soft.
// We try: custom -> gl3 -> gles3 -> gl1 -> soft.
if ((strcmp(vid_renderer->string, "gl3") != 0) &&
(strcmp(vid_renderer->string, "gles3") != 0) &&
(strcmp(vid_renderer->string, "gl1") != 0) &&
(strcmp(vid_renderer->string, "soft") != 0))
{
@ -534,6 +543,11 @@ VID_CheckChanges(void)
Cvar_Set("vid_renderer", "gl3");
}
else if (strcmp(vid_renderer->string, "gl3") == 0)
{
Com_Printf("Retrying with gles3...\n");
Cvar_Set("vid_renderer", "gles");
}
else if (strcmp(vid_renderer->string, "gles3") == 0)
{
Com_Printf("Retrying with gl1...\n");
Cvar_Set("vid_renderer", "gl1");
@ -569,7 +583,7 @@ VID_Init(void)
// Console variables
vid_gamma = Cvar_Get("vid_gamma", "1.0", CVAR_ARCHIVE);
vid_fullscreen = Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE);
vid_renderer = Cvar_Get("vid_renderer", "gl1", CVAR_ARCHIVE);
vid_renderer = Cvar_Get("vid_renderer", "gl3", CVAR_ARCHIVE);
// Commands
Cmd_AddCommand("vid_restart", VID_Restart_f);

View file

@ -53,7 +53,7 @@ cvar_t *showtrace;
// Forward declarations
#ifndef DEDICATED_ONLY
int GLimp_GetRefreshRate(void);
float GLimp_GetRefreshRate(void);
qboolean R_IsVSyncActive(void);
#endif
@ -570,7 +570,7 @@ Qcommon_Frame(int usec)
// Calculate target and renderframerate.
if (R_IsVSyncActive())
{
int refreshrate = GLimp_GetRefreshRate();
float refreshrate = GLimp_GetRefreshRate();
// using refreshRate - 2, because targeting a value slightly below the
// (possibly not 100% correctly reported) refreshRate would introduce jittering, so only