diff --git a/.gitignore b/.gitignore index 190cbaea6..87da86892 100644 --- a/.gitignore +++ b/.gitignore @@ -2,12 +2,20 @@ .q2pro/ .q2proded/ .baseq2/ +rogue/ +xatrix/ q2pro q2proded game*.so *.swp build/ -/baseq2 shader_vkpt ./vkpt ./vkptded +*.exe +*.ilk +*.pdb +.vs +baseq2/* +*.dll +*.so \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..b0dfd6c4c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,10 @@ +[submodule "extern/zlib"] + path = extern/zlib + url = https://github.com/madler/zlib.git + ignore = dirty +[submodule "extern/curl"] + path = extern/curl + url = https://github.com/curl/curl.git +[submodule "extern/SDL2"] + path = extern/SDL2 + url = https://github.com/spurious/SDL-mirror.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 740cbf57f..84a43ba5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,64 +1,85 @@ cmake_minimum_required (VERSION 3.8) -include("cmake/HunterGate.cmake") -# ---------- Startup hunter ------------------------- -HunterGate( - URL "https://github.com/ruslo/hunter/archive/v0.20.7.tar.gz" - SHA1 "a376088a679fbfbe3a2c330746801f1d47e51a37" -) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +project(quake2-RTX) +set(Q2RTX_VERSION_MAJOR 1) +set(Q2RTX_VERSION_MINOR 0) +set(Q2RTX_VERSION_POINT 0) -PROJECT(quake2-pt) +# get short-hash +execute_process( + COMMAND git rev-parse --short HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE Q2RTX_VERSION_SHA + OUTPUT_STRIP_TRAILING_WHITESPACE +) -OPTION(CONFIG_GL_RENDERER "Enable GL renderer") +OPTION(CONFIG_GL_RENDERER "Enable GL renderer" ON) OPTION(CONFIG_VKPT_RENDERER "Enable VKPT renderer" ON) -OPTION(CONFIG_USE_OPTIX "Use optix for tracing rays") -SET(CONFIG_OPTIX_DIR "" CACHE PATH "Optix SDK directory") +OPTION(CONFIG_VKPT_ENABLE_DEVICE_GROUPS "Enable device groups (multi-gpu) support" ON) +OPTION(CONFIG_VKPT_ENABLE_IMAGE_DUMPS "Enable image dumping functionality" OFF) +OPTION(CONFIG_USE_CURL "Use CURL for HTTP support" ON) +OPTION(CONFIG_LINUX_PACKAGING_SUPPORT "Enable Linux Packaging support" OFF) +OPTION(CONFIG_LINUX_STEAM_RUNTIME_SUPPORT "Enable Linux Steam Runtime support" OFF) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) # ---------- Setup output Directories ------------------------- -SET (CMAKE_LIBRARY_OUTPUT_DIRECTORY +set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Bin CACHE PATH "Single Directory for all Libraries" ) # --------- Setup the Executable output Directory ------------- -SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY - ${PROJECT_BINARY_DIR}/Bin - CACHE PATH - "Single Directory for all Executables." - ) +set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Bin CACHE PATH "Single Directory for all Executables.") # --------- Dependencies ------------------------------------- if (CMAKE_SIZEOF_VOID_P EQUAL 8) set( IS_64_BIT 1 ) -else () endif () -# --------- Dependencies ------------------------------------- -hunter_add_package(zlib) -hunter_add_package(png) -hunter_add_package(jpeg) -hunter_add_package(sdl2) -#hunter_add_package(curl) - -find_package(ZLIB CONFIG REQUIRED) -find_package(PNG CONFIG REQUIRED) -find_package(JPEG CONFIG REQUIRED) -find_package(SDL2 CONFIG REQUIRED) -#find_package(Vulkan) -#find_library(Vulkan_LIBRARY NAMES vulkan-1 vulkan PATHS "C:/VulkanSDK/1.1.85.0") +IF(WIN32) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") + set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_RELEASE} /MT") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELEASE} /MT") +ENDIF() + +add_subdirectory(extern) link_directories(.) -# Compatibility mode -find_package(ZLIB REQUIRED) -string(COMPARE EQUAL "${ZLIB_INCLUDE_DIRS}" "" is_empty) -if(is_empty) - message(FATAL_ERROR "Expected non-empty") -endif() +set(CMAKE_INSTALL_PREFIX ${PROJECT_BINARY_DIR}/install) + +add_subdirectory(src) + +IF(CONFIG_LINUX_PACKAGING_SUPPORT) + # https://cmake.org/cmake/help/v3.8/module/CPackDeb.html + set(CPACK_GENERATOR "DEB") + set(CPACK_PACKAGE_NAME "quake2rtx") + set(CPACK_PACKAGE_VENDOR "NVIDIA Corporation") + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "RTX Remaster of Quake 2") + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/license.txt") + set(CPACK_PACKAGE_VERSION_MAJOR ${Q2RTX_VERSION_MAJOR}) + set(CPACK_PACKAGE_VERSION_MINOR ${Q2RTX_VERSION_MINOR}) + set(CPACK_PACKAGE_VERSION_PATCH ${Q2RTX_VERSION_POINT}) + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") + set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") + set(CPACK_DEBIAN_PACKAGE_SECTION "games") + + set(CPACK_PACKAGE_CONTACT "http://nvidia.com/object/support.html") + + set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.nvidia.com/en-us/geforce/news/quake-ii-rtx-ray-tracing-vulkan-vkray-geforce-rtx/") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "libopenal1, libvulkan1") -SET(CMAKE_INSTALL_PREFIX ${PROJECT_BINARY_DIR}/install) + set(CPACK_DEB_PACKAGE_COMPONENT ON) + set(CPACK_DEB_COMPONENT_INSTALL ON) + set(CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS ON) + # Mark as shareware to be clear this is demo levels + RTX + set(CPACK_COMPONENTS_ALL shareware) -ADD_SUBDIRECTORY(src) + include(CPack) +ENDIF() diff --git a/INSTALL b/INSTALL deleted file mode 100644 index d1ff62f14..000000000 --- a/INSTALL +++ /dev/null @@ -1,96 +0,0 @@ -Q2VKPT: - -Linux: -Q2VKPT mostly relies on the build system provided by Q2PRO. Please read -the instructions below for more details. - -Q2VKPT only works with the SDL2 backend. Please refer to config_vkpt for -an example build config. - -Windows: -Q2VKPT provides a CMake file for building on Windows. Unfortunately -it currently does not support compiling the shaders. You can use -the WSL (linux on windows) subsystem to run the linux makefile for -building the shaders using "make compile_shaders" - - - -Prerequisities --------------- - -For building Q2PRO on Linux, BSD and similar platfroms you need to have a C -compiler installed. Recent versions of both GCC (4.x.x) and Clang (3.x) are -supported. - -Q2PRO client requires libSDL 1.2.x for video and sound output. Both client and -dedicated server require zlib support for full compatibility at network -protocol level. The rest of dependencies are purely optional. - -To install the *full* set of dependencies for building Q2PRO on Debian-based -Linux distributions, use the following command: - - apt-get install libc6-dev libx11-dev libsdl1.2-dev libopenal-dev \ - libpng12-dev libjpeg8-dev zlib1g-dev mesa-common-dev \ - liblircclient-dev libcurl4-gnutls-dev - -You can exchange libjpeg8-dev with libjpeg62-dev and libcurl4-gnutls-dev with -libcurl4-openssl-dev if you wish. - -Users of other distributions should look for equivalent development packages -and install them. - - -Building --------- - -Q2PRO uses a simple build system consisting of a single top-level Makefile and -a build-time configuration file. Configuration file is optional; if there is no -one, Q2PRO will be built with minimal subset of dependencies, but some features -will be unavailable. - -Copy an example configuration file from `doc/examples/buildconfig' to `.config' -and modify it to suit your needs. Enable needed features by uncommenting them. -By default *nothing* optional is enabled. - -Type `make' to build a client, dedicated server and baseq2 game library. Type -`make strip' to strip off debugging symbols from resulting executables. Type -`make clean' to remove all generated executables, object files and -dependencies. - -To enable verbose output during the build, set the V variable, e.g. `make V=1'. - - -Installation ------------- - -Before you begin, you need to have either full version of Quake 2 unpacked -somewhere, or a demo. Both should be patched to 3.20 point release. - -Run the following commands to do a per-user installation of Q2PRO into your -home directory. - - mkdir -p ~/.q2pro/baseq2 - cp -a /path/to/quake2/baseq2/pak*.pak ~/.q2pro/baseq2/ - cp -a /path/to/quake2/baseq2/players ~/.q2pro/baseq2/ - cp -a src/client/ui/q2pro.menu ~/.q2pro/baseq2/ - cp -a game*.so ~/.q2pro/baseq2/ - cp -a q2pro ~/.q2pro/ - -Then change directory to ~/.q2pro and run ./q2pro from there. - - -Mouse input on Linux --------------------- - -SDL 1.2.x way of handling mouse input in X11 environment is hardly suitable for -any serious gaming. For optimal control and performance using Linux evdev -kernel interface for reading mouse input is recommended. Enable it by defining -CONFIG_DIRECT_INPUT option in `.config'. - -By default, evdev device nodes have permissions that disallow normal uses to -read them. If you are the only physical user of computer, it is safe to change -default permissions of the mouse device node. - -To do so, copy `doc/examples/92-direct-input.rules' into `etc/udev/rules.d/', -then run `udevadm trigger' as root. Change `plugdev' group name if needed -(depends on Linux distribution). diff --git a/Makefile b/Makefile deleted file mode 100644 index abc667df3..000000000 --- a/Makefile +++ /dev/null @@ -1,771 +0,0 @@ -### Q2PRO Makefile ### - --include .config - - -ifdef CONFIG_WINDOWS - CPU ?= x86 - SYS ?= Win32 -else - ifndef CPU - CPU := $(shell uname -m | sed -e s/i.86/i386/ -e s/amd64/x86_64/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/alpha/axp/) - endif - ifndef SYS - SYS := $(shell uname -s) - endif -endif - -ifndef REV - REV := $(shell ./version.sh --revision) -endif -ifndef VER - VER := $(shell ./version.sh --version) -endif - -CC ?= gcc -WINDRES ?= windres -STRIP ?= strip -RM ?= rm -f -RMDIR ?= rm -rf -MKDIR ?= mkdir -p - -CFLAGS ?= -O2 -Wall -g -MMD $(INCLUDES) -RCFLAGS ?= -LDFLAGS ?= -LIBS ?= - -CFLAGS_s := -iquote./inc -CFLAGS_c := -iquote./inc -CFLAGS_g := -iquote./inc -fno-strict-aliasing - -RCFLAGS_s := -RCFLAGS_c := -RCFLAGS_g := - -LDFLAGS_s := -LDFLAGS_c := -LDFLAGS_g := -shared - -ifdef CONFIG_SANITIZE -CFLAGS_c += -O0 -fsanitize=address -fno-omit-frame-pointer -LDFLAGS_c += -fsanitize=address -endif - -ifdef CONFIG_VKPT_ENABLE_VALIDATION -ifneq ($(CONFIG_VKPT_ENABLE_VALIDATION),0) -CFLAGS_c += -DVKPT_ENABLE_VALIDATION -endif -endif - -ifdef CONFIG_WINDOWS - # Force i?86-netware calling convention on x86 Windows - ifeq ($(CPU),x86) - CONFIG_X86_GAME_ABI_HACK := y - else - CONFIG_X86_GAME_ABI_HACK := - endif - - LDFLAGS_s += -mconsole - LDFLAGS_c += -mwindows - LDFLAGS_g += -mconsole - - # Mark images as DEP and ASLR compatible - LDFLAGS_s += -Wl,--nxcompat,--dynamicbase - LDFLAGS_c += -Wl,--nxcompat,--dynamicbase - LDFLAGS_g += -Wl,--nxcompat,--dynamicbase - - # Force relocations to be generated for 32-bit .exe files and work around - # binutils bug that causes invalid image entry point to be set when - # relocations are enabled. - ifeq ($(CPU),x86) - LDFLAGS_s += -Wl,--pic-executable,--entry,_mainCRTStartup - LDFLAGS_c += -Wl,--pic-executable,--entry,_WinMainCRTStartup - endif -else - # Disable x86 features on other arches - ifneq ($(CPU),i386) - CONFIG_X86_GAME_ABI_HACK := - endif - - # Disable Linux features on other systems - ifneq ($(SYS),Linux) - CONFIG_DIRECT_INPUT := - CONFIG_NO_ICMP := y - endif - - # Hide ELF symbols by default - CFLAGS_s += -fvisibility=hidden - CFLAGS_c += -fvisibility=hidden - CFLAGS_g += -fvisibility=hidden - - # Resolve all symbols at link time - ifeq ($(SYS),Linux) - LDFLAGS_s += -Wl,--no-undefined - LDFLAGS_c += -Wl,--no-undefined - LDFLAGS_g += -Wl,--no-undefined - endif - - CFLAGS_g += -fPIC -endif - -BUILD_DEFS := -DCPUSTRING='"$(CPU)"' -BUILD_DEFS += -DBUILDSTRING='"$(SYS)"' - -VER_DEFS := -DREVISION=$(REV) -VER_DEFS += -DVERSION='"$(VER)"' - -CONFIG_GAME_BASE ?= baseq2 -CONFIG_GAME_DEFAULT ?= -PATH_DEFS := -DBASEGAME='"$(CONFIG_GAME_BASE)"' -PATH_DEFS += -DDEFGAME='"$(CONFIG_GAME_DEFAULT)"' - -# System paths -ifndef CONFIG_WINDOWS - CONFIG_PATH_DATA ?= . - CONFIG_PATH_LIB ?= . - CONFIG_PATH_HOME ?= - PATH_DEFS += -DDATADIR='"$(CONFIG_PATH_DATA)"' - PATH_DEFS += -DLIBDIR='"$(CONFIG_PATH_LIB)"' - PATH_DEFS += -DHOMEDIR='"$(CONFIG_PATH_HOME)"' -endif - -CFLAGS_s += $(BUILD_DEFS) $(VER_DEFS) $(PATH_DEFS) -DUSE_SERVER=1 -DUSE_CLIENT=0 -CFLAGS_c += $(BUILD_DEFS) $(VER_DEFS) $(PATH_DEFS) -DUSE_SERVER=1 -DUSE_CLIENT=1 - -# windres needs special quoting... -RCFLAGS_s += -DREVISION=$(REV) -DVERSION='\"$(VER)\"' -RCFLAGS_c += -DREVISION=$(REV) -DVERSION='\"$(VER)\"' -RCFLAGS_g += -DREVISION=$(REV) -DVERSION='\"$(VER)\"' - - -### Object Files ### - -COMMON_OBJS := \ - src/common/bsp.o \ - src/common/cmd.o \ - src/common/cmodel.o \ - src/common/common.o \ - src/common/cvar.o \ - src/common/error.o \ - src/common/field.o \ - src/common/fifo.o \ - src/common/files.o \ - src/common/math.o \ - src/common/mdfour.o \ - src/common/msg.o \ - src/common/net/chan.o \ - src/common/net/net.o \ - src/common/pmove.o \ - src/common/prompt.o \ - src/common/sizebuf.o \ - src/common/utils.o \ - src/common/zone.o \ - src/shared/shared.o - -OBJS_c := \ - $(COMMON_OBJS) \ - src/shared/m_flash.o \ - src/client/ascii.o \ - src/client/console.o \ - src/client/crc.o \ - src/client/demo.o \ - src/client/download.o \ - src/client/effects.o \ - src/client/entities.o \ - src/client/input.o \ - src/client/keys.o \ - src/client/locs.o \ - src/client/main.o \ - src/client/newfx.o \ - src/client/parse.o \ - src/client/precache.o \ - src/client/predict.o \ - src/client/refresh.o \ - src/client/screen.o \ - src/client/tent.o \ - src/client/view.o \ - src/client/sound/main.o \ - src/client/sound/mem.o \ - src/refresh/images.o \ - src/refresh/models.o \ - src/server/commands.o \ - src/server/entities.o \ - src/server/game.o \ - src/server/init.o \ - src/server/save.o \ - src/server/send.o \ - src/server/main.o \ - src/server/user.o \ - src/server/world.o \ - -OBJS_s := \ - $(COMMON_OBJS) \ - src/client/null.o \ - src/server/commands.o \ - src/server/entities.o \ - src/server/game.o \ - src/server/init.o \ - src/server/send.o \ - src/server/main.o \ - src/server/user.o \ - src/server/world.o - -OBJS_g := \ - src/shared/shared.o \ - src/shared/m_flash.o \ - src/baseq2/g_ai.o \ - src/baseq2/g_chase.o \ - src/baseq2/g_cmds.o \ - src/baseq2/g_combat.o \ - src/baseq2/g_func.o \ - src/baseq2/g_items.o \ - src/baseq2/g_main.o \ - src/baseq2/g_misc.o \ - src/baseq2/g_monster.o \ - src/baseq2/g_phys.o \ - src/baseq2/g_ptrs.o \ - src/baseq2/g_save.o \ - src/baseq2/g_spawn.o \ - src/baseq2/g_svcmds.o \ - src/baseq2/g_target.o \ - src/baseq2/g_trigger.o \ - src/baseq2/g_turret.o \ - src/baseq2/g_utils.o \ - src/baseq2/g_weapon.o \ - src/baseq2/m_actor.o \ - src/baseq2/m_berserk.o \ - src/baseq2/m_boss2.o \ - src/baseq2/m_boss31.o \ - src/baseq2/m_boss32.o \ - src/baseq2/m_boss3.o \ - src/baseq2/m_brain.o \ - src/baseq2/m_chick.o \ - src/baseq2/m_flipper.o \ - src/baseq2/m_float.o \ - src/baseq2/m_flyer.o \ - src/baseq2/m_gladiator.o \ - src/baseq2/m_gunner.o \ - src/baseq2/m_hover.o \ - src/baseq2/m_infantry.o \ - src/baseq2/m_insane.o \ - src/baseq2/m_medic.o \ - src/baseq2/m_move.o \ - src/baseq2/m_mutant.o \ - src/baseq2/m_parasite.o \ - src/baseq2/m_soldier.o \ - src/baseq2/m_supertank.o \ - src/baseq2/m_tank.o \ - src/baseq2/p_client.o \ - src/baseq2/p_hud.o \ - src/baseq2/p_trail.o \ - src/baseq2/p_view.o \ - src/baseq2/p_weapon.o - - -### Configuration Options ### - -# cd tracks via ogg -ifdef CONFIG_OGG - OBJS_c += src/client/sound/ogg.o - CFLAGS_c += -DOGG - LIBS_c += -lvorbisfile -lvorbis -logg -endif - -ifdef CONFIG_HTTP - CURL_CFLAGS ?= $(shell pkg-config libcurl --cflags) - CURL_LIBS ?= $(shell pkg-config libcurl --libs) - CFLAGS_c += -DUSE_CURL=1 $(CURL_CFLAGS) - LIBS_c += $(CURL_LIBS) - OBJS_c += src/client/http.o -endif - -ifdef CONFIG_CLIENT_GTV - CFLAGS_c += -DUSE_CLIENT_GTV=1 - OBJS_c += src/client/gtv.o -endif - -ifndef CONFIG_NO_SOFTWARE_SOUND - CFLAGS_c += -DUSE_SNDDMA=1 - OBJS_c += src/client/sound/mix.o - OBJS_c += src/client/sound/dma.o -endif - -ifdef CONFIG_OPENAL - CFLAGS_c += -DUSE_OPENAL=1 - OBJS_c += src/client/sound/al.o - ifdef CONFIG_FIXED_LIBAL - AL_CFLAGS ?= $(shell pkg-config openal --cflags) - AL_LIBS ?= $(shell pkg-config openal --libs) - CFLAGS_c += -DUSE_FIXED_LIBAL=1 $(AL_CFLAGS) - LIBS_c += $(AL_LIBS) - OBJS_c += src/client/sound/qal/fixed.o - else - OBJS_c += src/client/sound/qal/dynamic.o - endif -endif - -ifndef CONFIG_NO_MENUS - CFLAGS_c += -DUSE_UI=1 - OBJS_c += src/client/ui/demos.o - OBJS_c += src/client/ui/menu.o - OBJS_c += src/client/ui/playerconfig.o - OBJS_c += src/client/ui/playermodels.o - OBJS_c += src/client/ui/script.o - OBJS_c += src/client/ui/servers.o - OBJS_c += src/client/ui/ui.o -endif - -# Light styles are always enabled -CFLAGS_c += -DUSE_LIGHTSTYLES=1 - -ifndef CONFIG_NO_DYNAMIC_LIGHTS - CFLAGS_c += -DUSE_DLIGHTS=1 -endif - -ifndef CONFIG_NO_AUTOREPLY - CFLAGS_c += -DUSE_AUTOREPLY=1 -endif - -ifndef CONFIG_NO_MAPCHECKSUM - CFLAGS_c += -DUSE_MAPCHECKSUM=1 -endif - -ifdef CONFIG_SOFTWARE_RENDERER - CFLAGS_c += -DREF_SOFT=1 -DUSE_REF=1 -DVID_REF='"soft"' - OBJS_c += src/refresh/sw/aclip.o - OBJS_c += src/refresh/sw/alias.o - OBJS_c += src/refresh/sw/bsp.o - OBJS_c += src/refresh/sw/draw.o - OBJS_c += src/refresh/sw/edge.o - OBJS_c += src/refresh/sw/image.o - OBJS_c += src/refresh/sw/light.o - OBJS_c += src/refresh/sw/main.o - OBJS_c += src/refresh/sw/misc.o - OBJS_c += src/refresh/sw/model.o - OBJS_c += src/refresh/sw/part.o - OBJS_c += src/refresh/sw/poly.o - OBJS_c += src/refresh/sw/polyset.o - OBJS_c += src/refresh/sw/raster.o - OBJS_c += src/refresh/sw/scan.o - OBJS_c += src/refresh/sw/surf.o - OBJS_c += src/refresh/sw/sird.o - OBJS_c += src/refresh/sw/sky.o -endif -ifdef CONFIG_GL_RENDERER - CFLAGS_c += -DREF_GL=1 -DUSE_REF=1 -DVID_REF='"gl"' - OBJS_c += src/refresh/gl/draw.o - OBJS_c += src/refresh/gl/hq2x.o - OBJS_c += src/refresh/gl/images.o - OBJS_c += src/refresh/gl/main.o - OBJS_c += src/refresh/gl/mesh.o - OBJS_c += src/refresh/gl/models.o - OBJS_c += src/refresh/gl/sky.o - OBJS_c += src/refresh/gl/state.o - OBJS_c += src/refresh/gl/surf.o - OBJS_c += src/refresh/gl/tess.o - OBJS_c += src/refresh/gl/world.o - ifdef CONFIG_FIXED_LIBGL - GL_CFLAGS ?= - GL_LIBS ?= -lGL - CFLAGS_c += -DUSE_FIXED_LIBGL=1 $(GL_CFLAGS) - LIBS_c += $(GL_LIBS) - OBJS_c += src/refresh/gl/qgl/fixed.o - else - OBJS_c += src/refresh/gl/qgl/dynamic.o - endif -endif -ifdef CONFIG_VKPT_RENDERER - VKPT_SHADER_DIR=shader_vkpt - CFLAGS_c += -DREF_VKPT=1 -DUSE_REF=1 -DVID_REF='"vkpt"' -Isrc/refresh/vkpt/ -DVKPT_SHADER_DIR='"$(VKPT_SHADER_DIR)"' - LIBS_c +=-lvulkan - OBJS_c += src/refresh/vkpt/main.o - OBJS_c += src/refresh/vkpt/textures.o - OBJS_c += src/refresh/vkpt/draw.o - OBJS_c += src/refresh/vkpt/matrix.o - OBJS_c += src/refresh/vkpt/models.o - OBJS_c += src/refresh/vkpt/path_tracer.o - OBJS_c += src/refresh/vkpt/vk_util.o - OBJS_c += src/refresh/vkpt/bsp_mesh.o - OBJS_c += src/refresh/vkpt/uniform_buffer.o - OBJS_c += src/refresh/vkpt/vertex_buffer.o - OBJS_c += src/refresh/vkpt/light_hierarchy.o - OBJS_c += src/refresh/vkpt/asvgf.o - OBJS_c += src/refresh/vkpt/stb.o - OBJS_c += src/refresh/vkpt/profiler.o - - VKPT_SHADER_SRC = $(shell find src/refresh/vkpt/shader -type f | egrep '\.(vert|frag|geom|rchit|rgen|rmiss|rcall|comp)$$' | sed s!.*/!!) - VKPT_SHADER_HDR = $(shell find src/refresh/vkpt/shader -type f | egrep '\.(h|glsl)$$') - VKPT_SHADER_SPV = $(VKPT_SHADER_SRC:%=$(VKPT_SHADER_DIR)/%.spv) - -endif - -CONFIG_DEFAULT_MODELIST ?= 640x480 800x600 1024x768 -CONFIG_DEFAULT_GEOMETRY ?= 640x480 -CFLAGS_c += -DVID_MODELIST='"$(CONFIG_DEFAULT_MODELIST)"' -CFLAGS_c += -DVID_GEOMETRY='"$(CONFIG_DEFAULT_GEOMETRY)"' - -ifndef CONFIG_SOFTWARE_RENDERER - ifndef CONFIG_NO_MD3 - CFLAGS_c += -DUSE_MD3=1 - endif -endif - -ifdef CONFIG_NO_BINDLESS_TEXTURES - CFLAGS_c += -DNO_BINDLESS_TEXTURES=1 -endif - -ifdef CONFIG_SMALL_GPU - CFLAGS_c += -DUSE_SMALL_GPU=1 -endif - -ifndef CONFIG_NO_TGA - CFLAGS_c += -DUSE_TGA=1 -endif - -ifdef CONFIG_PNG - PNG_CFLAGS ?= $(shell libpng-config --cflags) - PNG_LIBS ?= $(shell libpng-config --libs) - CFLAGS_c += -DUSE_PNG=1 $(PNG_CFLAGS) - LIBS_c += $(PNG_LIBS) -endif - -ifdef CONFIG_JPEG - JPG_CFLAGS ?= - JPG_LIBS ?= -ljpeg - CFLAGS_c += -DUSE_JPG=1 $(JPG_CFLAGS) - LIBS_c += $(JPG_LIBS) -endif - -ifdef CONFIG_ANTICHEAT_SERVER - CFLAGS_s += -DUSE_AC_SERVER=1 - OBJS_s += src/server/ac.o -endif - -ifdef CONFIG_MVD_SERVER - CFLAGS_s += -DUSE_MVD_SERVER=1 - CFLAGS_c += -DUSE_MVD_SERVER=1 - OBJS_s += src/server/mvd.o - OBJS_c += src/server/mvd.o -endif - -ifdef CONFIG_MVD_CLIENT - CFLAGS_s += -DUSE_MVD_CLIENT=1 - CFLAGS_c += -DUSE_MVD_CLIENT=1 - OBJS_s += src/server/mvd/client.o src/server/mvd/game.o src/server/mvd/parse.o - OBJS_c += src/server/mvd/client.o src/server/mvd/game.o src/server/mvd/parse.o -endif - -ifdef CONFIG_NO_ZLIB - CFLAGS_c += -DUSE_ZLIB=0 - CFLAGS_s += -DUSE_ZLIB=0 -else - ZLIB_CFLAGS ?= - ZLIB_LIBS ?= -lz - CFLAGS_c += -DUSE_ZLIB=1 $(ZLIB_CFLAGS) - CFLAGS_s += -DUSE_ZLIB=1 $(ZLIB_CFLAGS) - LIBS_c += $(ZLIB_LIBS) - LIBS_s += $(ZLIB_LIBS) -endif - -ifndef CONFIG_NO_ICMP - CFLAGS_c += -DUSE_ICMP=1 - CFLAGS_s += -DUSE_ICMP=1 -endif - -ifndef CONFIG_NO_SYSTEM_CONSOLE - CFLAGS_c += -DUSE_SYSCON=1 - CFLAGS_s += -DUSE_SYSCON=1 -endif - -ifdef CONFIG_X86_GAME_ABI_HACK - CFLAGS_c += -DUSE_GAME_ABI_HACK=1 - CFLAGS_s += -DUSE_GAME_ABI_HACK=1 - CFLAGS_g += -DUSE_GAME_ABI_HACK=1 -endif - -ifdef CONFIG_VARIABLE_SERVER_FPS - CFLAGS_c += -DUSE_FPS=1 - CFLAGS_s += -DUSE_FPS=1 -endif - -ifdef CONFIG_WINDOWS - OBJS_c += src/windows/client.o - - ifdef CONFIG_DIRECT_INPUT - CFLAGS_c += -DUSE_DINPUT=1 - OBJS_c += src/windows/dinput.o - endif - - ifndef CONFIG_NO_SOFTWARE_SOUND - OBJS_c += src/windows/wave.o - ifdef CONFIG_DIRECT_SOUND - CFLAGS_c += -DUSE_DSOUND=1 - OBJS_c += src/windows/dsound.o - endif - endif - - ifdef CONFIG_SOFTWARE_RENDERER - OBJS_c += src/windows/swimp.o - endif - ifdef CONFIG_GL_RENDERER - OBJS_c += src/windows/glimp.o - OBJS_c += src/windows/wgl.o - endif - - ifdef CONFIG_WINDOWS_CRASH_DUMPS - CFLAGS_c += -DUSE_DBGHELP=1 - CFLAGS_s += -DUSE_DBGHELP=1 - OBJS_c += src/windows/debug.o - OBJS_s += src/windows/debug.o - endif - - ifdef CONFIG_WINDOWS_SERVICE - CFLAGS_s += -DUSE_WINSVC=1 - endif - - OBJS_c += src/windows/hunk.o src/windows/system.o - OBJS_s += src/windows/hunk.o src/windows/system.o - - # Resources - OBJS_c += src/windows/res/q2pro.o - OBJS_s += src/windows/res/q2proded.o - OBJS_g += src/windows/res/baseq2.o - - # System libs - LIBS_s += -lws2_32 -lwinmm -ladvapi32 - LIBS_c += -lws2_32 -lwinmm -else - ifdef CONFIG_SDL2 - SDL_CFLAGS ?= $(shell sdl2-config --cflags) - SDL_LIBS ?= $(shell sdl2-config --libs) - CFLAGS_c += -DUSE_SDL=2 $(SDL_CFLAGS) - LIBS_c += $(SDL_LIBS) - OBJS_c += src/unix/sdl2/video.o - else - SDL_CFLAGS ?= $(shell sdl-config --cflags) - SDL_LIBS ?= $(shell sdl-config --libs) - CFLAGS_c += -DUSE_SDL=1 $(SDL_CFLAGS) - LIBS_c += $(SDL_LIBS) - OBJS_c += src/unix/sdl/video.o - OBJS_c += src/unix/sdl/clipboard.o - - ifdef CONFIG_SOFTWARE_RENDERER - OBJS_c += src/unix/sdl/swimp.o - endif - ifdef CONFIG_GL_RENDERER - OBJS_c += src/unix/sdl/glimp.o - endif - - ifdef CONFIG_X11 - X11_CFLAGS ?= - X11_LIBS ?= -lX11 - CFLAGS_c += -DUSE_X11=1 $(X11_CFLAGS) - LIBS_c += $(X11_LIBS) - ifdef CONFIG_GL_RENDERER - OBJS_c += src/unix/sdl/glx.o - endif - endif - - ifdef CONFIG_DIRECT_INPUT - CFLAGS_c += -DUSE_DINPUT=1 - OBJS_c += src/unix/evdev.o - ifndef CONFIG_NO_UDEV - UDEV_CFLAGS ?= - UDEV_LIBS ?= -ludev - CFLAGS_c += -DUSE_UDEV=1 $(UDEV_CFLAGS) - LIBS_c += $(UDEV_LIBS) - endif - endif - endif - - ifdef CONFIG_LIRC - LIRC_CFLAGS ?= - LIRC_LIBS ?= -llirc_client - CFLAGS_c += -DUSE_LIRC=1 $(LIRC_CFLAGS) - OBJS_c += src/unix/lirc.o - LIBS_c += $(LIRC_LIBS) - endif - - ifndef CONFIG_NO_SOFTWARE_SOUND - ifdef CONFIG_SDL2 - OBJS_c += src/unix/sdl2/sound.o - else - OBJS_c += src/unix/sdl/sound.o - endif - ifdef CONFIG_DIRECT_SOUND - CFLAGS_c += -DUSE_DSOUND=1 - OBJS_c += src/unix/oss.o - endif - endif - - OBJS_s += src/unix/hunk.o src/unix/system.o - OBJS_c += src/unix/hunk.o src/unix/system.o - - ifndef CONFIG_NO_SYSTEM_CONSOLE - OBJS_s += src/unix/tty.o - OBJS_c += src/unix/tty.o - endif - - # System libs - LIBS_s += -lm - LIBS_c += -lm - LIBS_g += -lm - - ifeq ($(SYS),Linux) - LIBS_s += -ldl - LIBS_c += -ldl - endif -endif - -ifdef CONFIG_TESTS - CFLAGS_c += -DUSE_TESTS=1 - CFLAGS_s += -DUSE_TESTS=1 - OBJS_c += src/common/tests.o - OBJS_s += src/common/tests.o -endif - -ifdef CONFIG_DEBUG - CFLAGS_c += -D_DEBUG - CFLAGS_s += -D_DEBUG -endif - -ifdef CONFIG_GL_DEBUG - CFLAGS_c += -D_GL_DEBUG -endif - -ifeq ($(CPU),x86) - OBJS_c += src/common/x86/fpu.o - OBJS_s += src/common/x86/fpu.o -endif - -ifeq ($(CPU),i386) - OBJS_c += src/common/x86/fpu.o - OBJS_s += src/common/x86/fpu.o -endif - -### Targets ### - -ifdef CONFIG_WINDOWS - TARG_s := q2proded.exe - TARG_c := q2pro.exe - TARG_g := game$(CPU).dll - TARG_t := -else - TARG_s := vkptded - TARG_c := q2vkpt - TARG_g := game$(CPU).so - TARG_t := -endif - -all: $(TARG_s) $(TARG_c) $(TARG_g) - -default: all - -.PHONY: all default clean strip - -# Define V=1 to show command line. -ifdef V - Q := - E := @true -else - Q := @ - E := @echo -endif - -# Temporary build directories -BUILD_s := .q2proded -BUILD_c := .q2pro -BUILD_g := .baseq2 - -# Rewrite paths to build directories -OBJS_s := $(patsubst %,$(BUILD_s)/%,$(OBJS_s)) -OBJS_c := $(patsubst %,$(BUILD_c)/%,$(OBJS_c)) -OBJS_g := $(patsubst %,$(BUILD_g)/%,$(OBJS_g)) - -DEPS_s := $(OBJS_s:.o=.d) -DEPS_c := $(OBJS_c:.o=.d) -DEPS_g := $(OBJS_g:.o=.d) - - -ifdef CONFIG_VKPT_RENDERER -$(TARG_c): $(VKPT_SHADER_SPV) -compile_shaders: $(VKPT_SHADER_SPV) - -CONFIG_GLSLANGVALIDATOR ?= glslangValidator - -$(VKPT_SHADER_DIR)/%.spv: src/refresh/vkpt/shader/% $(VKPT_SHADER_HDR) - $(E) [GLSL] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(CONFIG_GLSLANGVALIDATOR) \ - --target-env vulkan1.1 \ - -DVKPT_SHADER \ - -DSHADER_STAGE_$$(echo $< | sed 's/.*\.//' | tr 'a-z' 'A-Z') \ - -V $< -o $@ | sed 1d - -endif - --include $(DEPS_s) --include $(DEPS_c) --include $(DEPS_g) - -clean: - $(E) [CLEAN] - $(Q)$(RM) $(TARG_s) $(TARG_c) $(TARG_g) - $(Q)$(RM) $(VKPT_SHADER_SPV) - $(Q)$(RMDIR) $(BUILD_s) $(BUILD_c) $(BUILD_g) - -strip: $(TARG_s) $(TARG_c) $(TARG_g) - $(E) [STRIP] - $(Q)$(STRIP) $(TARG_s) $(TARG_c) $(TARG_g) - -# ------ - -$(BUILD_s)/%.o: %.c - $(E) [CC] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(CC) -c $(CFLAGS) $(CFLAGS_s) -o $@ $< - -$(BUILD_s)/%.o: %.rc - $(E) [RC] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(WINDRES) $(RCFLAGS) $(RCFLAGS_s) -o $@ $< - -$(TARG_s): $(OBJS_s) - $(E) [LD] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(CC) $(LDFLAGS) $(LDFLAGS_s) -o $@ $(OBJS_s) $(LIBS) $(LIBS_s) - -# ------ - -$(BUILD_c)/%.o: %.c - $(E) [CC] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(CC) -c $(CFLAGS) $(CFLAGS_c) -o $@ $< - -$(BUILD_c)/%.o: %.rc - $(E) [RC] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(WINDRES) $(RCFLAGS) $(RCFLAGS_c) -o $@ $< - -$(TARG_c): $(OBJS_c) - $(E) [LD] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(CC) $(LDFLAGS) $(LDFLAGS_c) -o $@ $(OBJS_c) $(LIBS) $(LIBS_c) - -# ------ - -$(BUILD_g)/%.o: %.c - $(E) [CC] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(CC) -c $(CFLAGS) $(CFLAGS_g) -o $@ $< - -$(BUILD_g)/%.o: %.rc - $(E) [RC] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(WINDRES) $(RCFLAGS) $(RCFLAGS_g) -o $@ $< - -$(TARG_g): $(OBJS_g) - $(E) [LD] $@ - $(Q)$(MKDIR) $(@D) - $(Q)$(CC) $(LDFLAGS) $(LDFLAGS_g) -o $@ $(OBJS_g) $(LIBS) $(LIBS_g) - diff --git a/README b/README deleted file mode 100644 index c92951ef1..000000000 --- a/README +++ /dev/null @@ -1,13 +0,0 @@ -Welcome to Q2VKPT, a Quake II engine with real-time path tracing. This client -implements fully dynamic illumination without precomputation supporting area -light sources, reflections, soft shadows, and indirect illumination. This -client is a port of our real-time path tracer vkpt and is based on the Quake II -engine Q2PRO. - -This client requires a high-end GPU supporting the Vulkan extension -VK_NV_ray_tracing. - -Please refer to our project page for more details. - -Project homepage: http://brechpunkt.de/q2vkpt - diff --git a/build_materials.py b/build_materials.py new file mode 100644 index 000000000..ed117ace2 --- /dev/null +++ b/build_materials.py @@ -0,0 +1,86 @@ +# Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. +# +# 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import os +import sys +import glob + +# +# scan textures to build materials index +# +def scan_textures(q2_path, paks_path): + + # scan bsp mesh textures in 'textures' folder + bsp_tex = set() + for fmt in [".wal", ".pcx"]: + folder = os.path.join(paks_path, 'textures') + for filename in glob.iglob(folder+'/**/*'+fmt, recursive=True): + filename = os.path.relpath(filename, paks_path) + filename = os.path.splitext(filename)[0] + bsp_tex.add(filename) + + # scan model textures in both base paks & expanded baseq2 folders + # to catch added md2 / md3 items & weapons + model_tex = set() + for path in [paks_path, q2_path]: + for folder in ['models', 'players', 'sprites']: + for fmt in [".tga", ".png", ".jgg", ".wal", ".pcx"]: + for filename in glob.iglob(os.path.join(path, folder)+'/**/*'+fmt, recursive=True): + filename = os.path.relpath(filename, path) + filename = os.path.splitext(filename)[0] + # skip normal / emissive textures + if (filename.endswith('_n') or filename.endswith('_light')): + continue + model_tex.add(filename) + + return sorted(list(bsp_tex | model_tex), key=lambda s: s.lower()) + +# +# build materials csv file from list of texture names +# +def build_csv(textures): + + print('"key", "bump scale", "rough scale", "spec scale", "emit scale", "chrome flg", "invisible flg", "light flg"') + + for tex in textures: + print('"%s", 1.0, 1.0, 1.0, 1.0, 0, 0, 0'%(tex)) + +# +# main +# + +# +# usage : build_materials > +# + +q2_path = None +if (len(sys.argv) > 1): + if (not os.path.isabs(sys.argv[1])): + q2_path = os.path.join(os.getcwd(), sys.argv[1]) + else: + q2_path = sys.argv[1] + +paks_path = None +if (len(sys.argv) > 2): + if (not os.path.isabs(sys.argv[2])): + paks_path = os.path.join(os.getcwd(), sys.argv[2]) + else: + paks_path = sys.argv[2] + + +textures = scan_textures(q2_path, paks_path) + +build_csv(textures) diff --git a/cmake/HunterGate.cmake b/cmake/HunterGate.cmake deleted file mode 100644 index c24c0e577..000000000 --- a/cmake/HunterGate.cmake +++ /dev/null @@ -1,543 +0,0 @@ -# Copyright (c) 2013-2017, Ruslan Baratov -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# This is a gate file to Hunter package manager. -# Include this file using `include` command and add package you need, example: -# -# cmake_minimum_required(VERSION 3.0) -# -# include("cmake/HunterGate.cmake") -# HunterGate( -# URL "https://github.com/path/to/hunter/archive.tar.gz" -# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" -# ) -# -# project(MyProject) -# -# hunter_add_package(Foo) -# hunter_add_package(Boo COMPONENTS Bar Baz) -# -# Projects: -# * https://github.com/hunter-packages/gate/ -# * https://github.com/ruslo/hunter - -option(HUNTER_ENABLED "Enable Hunter package manager support" ON) -if(HUNTER_ENABLED) - if(CMAKE_VERSION VERSION_LESS "3.0") - message(FATAL_ERROR "At least CMake version 3.0 required for hunter dependency management." - " Update CMake or set HUNTER_ENABLED to OFF.") - endif() -endif() - -include(CMakeParseArguments) # cmake_parse_arguments - -option(HUNTER_STATUS_PRINT "Print working status" ON) -option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) -option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) - -set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki") - -function(hunter_gate_status_print) - foreach(print_message ${ARGV}) - if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) - message(STATUS "[hunter] ${print_message}") - endif() - endforeach() -endfunction() - -function(hunter_gate_status_debug) - foreach(print_message ${ARGV}) - if(HUNTER_STATUS_DEBUG) - string(TIMESTAMP timestamp) - message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") - endif() - endforeach() -endfunction() - -function(hunter_gate_wiki wiki_page) - message("------------------------------ WIKI -------------------------------") - message(" ${HUNTER_WIKI}/${wiki_page}") - message("-------------------------------------------------------------------") - message("") - message(FATAL_ERROR "") -endfunction() - -function(hunter_gate_internal_error) - message("") - foreach(print_message ${ARGV}) - message("[hunter ** INTERNAL **] ${print_message}") - endforeach() - message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") - message("") - hunter_gate_wiki("error.internal") -endfunction() - -function(hunter_gate_fatal_error) - cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}") - string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki) - if(have_no_wiki) - hunter_gate_internal_error("Expected wiki") - endif() - message("") - foreach(x ${hunter_UNPARSED_ARGUMENTS}) - message("[hunter ** FATAL ERROR **] ${x}") - endforeach() - message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") - message("") - hunter_gate_wiki("${hunter_WIKI}") -endfunction() - -function(hunter_gate_user_error) - hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data") -endfunction() - -function(hunter_gate_self root version sha1 result) - string(COMPARE EQUAL "${root}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("root is empty") - endif() - - string(COMPARE EQUAL "${version}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("version is empty") - endif() - - string(COMPARE EQUAL "${sha1}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("sha1 is empty") - endif() - - string(SUBSTRING "${sha1}" 0 7 archive_id) - - if(EXISTS "${root}/cmake/Hunter") - set(hunter_self "${root}") - else() - set( - hunter_self - "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" - ) - endif() - - set("${result}" "${hunter_self}" PARENT_SCOPE) -endfunction() - -# Set HUNTER_GATE_ROOT cmake variable to suitable value. -function(hunter_gate_detect_root) - # Check CMake variable - string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty) - if(not_empty) - set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) - hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") - return() - endif() - - # Check environment variable - string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty) - if(not_empty) - set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) - hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") - return() - endif() - - # Check HOME environment variable - string(COMPARE NOTEQUAL "$ENV{HOME}" "" result) - if(result) - set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) - hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") - return() - endif() - - # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) - if(WIN32) - string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result) - if(result) - set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) - hunter_gate_status_debug( - "HUNTER_ROOT set using SYSTEMDRIVE environment variable" - ) - return() - endif() - - string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result) - if(result) - set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) - hunter_gate_status_debug( - "HUNTER_ROOT set using USERPROFILE environment variable" - ) - return() - endif() - endif() - - hunter_gate_fatal_error( - "Can't detect HUNTER_ROOT" - WIKI "error.detect.hunter.root" - ) -endfunction() - -macro(hunter_gate_lock dir) - if(NOT HUNTER_SKIP_LOCK) - if("${CMAKE_VERSION}" VERSION_LESS "3.2") - hunter_gate_fatal_error( - "Can't lock, upgrade to CMake 3.2 or use HUNTER_SKIP_LOCK" - WIKI "error.can.not.lock" - ) - endif() - hunter_gate_status_debug("Locking directory: ${dir}") - file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) - hunter_gate_status_debug("Lock done") - endif() -endmacro() - -function(hunter_gate_download dir) - string( - COMPARE - NOTEQUAL - "$ENV{HUNTER_DISABLE_AUTOINSTALL}" - "" - disable_autoinstall - ) - if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) - hunter_gate_fatal_error( - "Hunter not found in '${dir}'" - "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" - "Settings:" - " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" - " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" - WIKI "error.run.install" - ) - endif() - string(COMPARE EQUAL "${dir}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("Empty 'dir' argument") - endif() - - string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") - endif() - - string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("HUNTER_GATE_URL empty") - endif() - - set(done_location "${dir}/DONE") - set(sha1_location "${dir}/SHA1") - - set(build_dir "${dir}/Build") - set(cmakelists "${dir}/CMakeLists.txt") - - hunter_gate_lock("${dir}") - if(EXISTS "${done_location}") - # while waiting for lock other instance can do all the job - hunter_gate_status_debug("File '${done_location}' found, skip install") - return() - endif() - - file(REMOVE_RECURSE "${build_dir}") - file(REMOVE_RECURSE "${cmakelists}") - - file(MAKE_DIRECTORY "${build_dir}") # check directory permissions - - # Disabling languages speeds up a little bit, reduces noise in the output - # and avoids path too long windows error - file( - WRITE - "${cmakelists}" - "cmake_minimum_required(VERSION 3.0)\n" - "project(HunterDownload LANGUAGES NONE)\n" - "include(ExternalProject)\n" - "ExternalProject_Add(\n" - " Hunter\n" - " URL\n" - " \"${HUNTER_GATE_URL}\"\n" - " URL_HASH\n" - " SHA1=${HUNTER_GATE_SHA1}\n" - " DOWNLOAD_DIR\n" - " \"${dir}\"\n" - " TLS_VERIFY\n" - " ${HUNTER_TLS_VERIFY}\n" - " SOURCE_DIR\n" - " \"${dir}/Unpacked\"\n" - " CONFIGURE_COMMAND\n" - " \"\"\n" - " BUILD_COMMAND\n" - " \"\"\n" - " INSTALL_COMMAND\n" - " \"\"\n" - ")\n" - ) - - if(HUNTER_STATUS_DEBUG) - set(logging_params "") - else() - set(logging_params OUTPUT_QUIET) - endif() - - hunter_gate_status_debug("Run generate") - - # Need to add toolchain file too. - # Otherwise on Visual Studio + MDD this will fail with error: - # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" - if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") - get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE) - set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}") - else() - # 'toolchain_arg' can't be empty - set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") - endif() - - string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) - if(no_make) - set(make_arg "") - else() - # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM - set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") - endif() - - execute_process( - COMMAND - "${CMAKE_COMMAND}" - "-H${dir}" - "-B${build_dir}" - "-G${CMAKE_GENERATOR}" - "${toolchain_arg}" - ${make_arg} - WORKING_DIRECTORY "${dir}" - RESULT_VARIABLE download_result - ${logging_params} - ) - - if(NOT download_result EQUAL 0) - hunter_gate_internal_error("Configure project failed") - endif() - - hunter_gate_status_print( - "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" - " ${HUNTER_GATE_URL}" - " -> ${dir}" - ) - execute_process( - COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" - WORKING_DIRECTORY "${dir}" - RESULT_VARIABLE download_result - ${logging_params} - ) - - if(NOT download_result EQUAL 0) - hunter_gate_internal_error("Build project failed") - endif() - - file(REMOVE_RECURSE "${build_dir}") - file(REMOVE_RECURSE "${cmakelists}") - - file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") - file(WRITE "${done_location}" "DONE") - - hunter_gate_status_debug("Finished") -endfunction() - -# Must be a macro so master file 'cmake/Hunter' can -# apply all variables easily just by 'include' command -# (otherwise PARENT_SCOPE magic needed) -macro(HunterGate) - if(HUNTER_GATE_DONE) - # variable HUNTER_GATE_DONE set explicitly for external project - # (see `hunter_download`) - set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) - endif() - - # First HunterGate command will init Hunter, others will be ignored - get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) - - if(NOT HUNTER_ENABLED) - # Empty function to avoid error "unknown function" - function(hunter_add_package) - endfunction() - - set( - _hunter_gate_disabled_mode_dir - "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode" - ) - if(EXISTS "${_hunter_gate_disabled_mode_dir}") - hunter_gate_status_debug( - "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}" - ) - list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}") - endif() - elseif(_hunter_gate_done) - hunter_gate_status_debug("Secondary HunterGate (use old settings)") - hunter_gate_self( - "${HUNTER_CACHED_ROOT}" - "${HUNTER_VERSION}" - "${HUNTER_SHA1}" - _hunter_self - ) - include("${_hunter_self}/cmake/Hunter") - else() - set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_LIST_DIR}") - - string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) - if(_have_project_name) - hunter_gate_fatal_error( - "Please set HunterGate *before* 'project' command. " - "Detected project: ${PROJECT_NAME}" - WIKI "error.huntergate.before.project" - ) - endif() - - cmake_parse_arguments( - HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} - ) - - string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) - string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) - string( - COMPARE - NOTEQUAL - "${HUNTER_GATE_UNPARSED_ARGUMENTS}" - "" - _have_unparsed - ) - string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) - string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) - - if(_have_unparsed) - hunter_gate_user_error( - "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" - ) - endif() - if(_empty_sha1) - hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") - endif() - if(_empty_url) - hunter_gate_user_error("URL suboption of HunterGate is mandatory") - endif() - if(_have_global) - if(HUNTER_GATE_LOCAL) - hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") - endif() - if(_have_filepath) - hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") - endif() - endif() - if(HUNTER_GATE_LOCAL) - if(_have_global) - hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") - endif() - if(_have_filepath) - hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") - endif() - endif() - if(_have_filepath) - if(_have_global) - hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") - endif() - if(HUNTER_GATE_LOCAL) - hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") - endif() - endif() - - hunter_gate_detect_root() # set HUNTER_GATE_ROOT - - # Beautify path, fix probable problems with windows path slashes - get_filename_component( - HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE - ) - hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") - if(NOT HUNTER_ALLOW_SPACES_IN_PATH) - string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) - if(NOT _contain_spaces EQUAL -1) - hunter_gate_fatal_error( - "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." - "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" - "(Use at your own risk!)" - WIKI "error.spaces.in.hunter.root" - ) - endif() - endif() - - string( - REGEX - MATCH - "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" - HUNTER_GATE_VERSION - "${HUNTER_GATE_URL}" - ) - string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) - if(_is_empty) - set(HUNTER_GATE_VERSION "unknown") - endif() - - hunter_gate_self( - "${HUNTER_GATE_ROOT}" - "${HUNTER_GATE_VERSION}" - "${HUNTER_GATE_SHA1}" - _hunter_self - ) - - set(_master_location "${_hunter_self}/cmake/Hunter") - if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") - # Hunter downloaded manually (e.g. by 'git clone') - set(_unused "xxxxxxxxxx") - set(HUNTER_GATE_SHA1 "${_unused}") - set(HUNTER_GATE_VERSION "${_unused}") - else() - get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) - set(_done_location "${_archive_id_location}/DONE") - set(_sha1_location "${_archive_id_location}/SHA1") - - # Check Hunter already downloaded by HunterGate - if(NOT EXISTS "${_done_location}") - hunter_gate_download("${_archive_id_location}") - endif() - - if(NOT EXISTS "${_done_location}") - hunter_gate_internal_error("hunter_gate_download failed") - endif() - - if(NOT EXISTS "${_sha1_location}") - hunter_gate_internal_error("${_sha1_location} not found") - endif() - file(READ "${_sha1_location}" _sha1_value) - string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal) - if(NOT _is_equal) - hunter_gate_internal_error( - "Short SHA1 collision:" - " ${_sha1_value} (from ${_sha1_location})" - " ${HUNTER_GATE_SHA1} (HunterGate)" - ) - endif() - if(NOT EXISTS "${_master_location}") - hunter_gate_user_error( - "Master file not found:" - " ${_master_location}" - "try to update Hunter/HunterGate" - ) - endif() - endif() - include("${_master_location}") - set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) - endif() -endmacro() diff --git a/cmake/compileShaders.cmake b/cmake/compileShaders.cmake new file mode 100644 index 000000000..a9b7a4b9f --- /dev/null +++ b/cmake/compileShaders.cmake @@ -0,0 +1,86 @@ +set(SHADER_SOURCE_DEPENDENCIES + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/asvgf.glsl + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/brdf.glsl + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/constants.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/global_textures.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/global_ubo.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/light_lists.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/path_tracer_rgen.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/path_tracer.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/precomputed_sky.glsl + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/precomputed_sky_params.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/projection.glsl + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/read_visbuf.glsl + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/sky.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/tiny_encryption_algorithm.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/tone_mapping_utils.glsl + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/utils.glsl + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/vertex_buffer.h + ${CMAKE_SOURCE_DIR}/src/refresh/vkpt/shader/water.glsl) + +find_program(GLSLANG_COMPILER + glslangValidator + PATHS + $ENV{VULKAN_SDK}/bin/ +) + +message(STATUS "Glslang compiler : ${GLSLANG_COMPILER}") + +function(compile_shader) + set(options "") + set(oneValueArgs SOURCE_FILE OUTPUT_FILE_LIST) + set(multiValueArgs "") + cmake_parse_arguments(params "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT params_SOURCE_FILE) + message(FATAL_ERROR "compile_shader: SOURCE_FILE argument missing") + endif() + + if (NOT params_OUTPUT_FILE_LIST) + message(FATAL_ERROR "compile_shader: OUTPUT_FILE_LIST argument missing") + endif() + + set(src_file "${CMAKE_CURRENT_SOURCE_DIR}/${params_SOURCE_FILE}") + get_filename_component(base_file_name ${src_file} NAME) + get_filename_component(file_extension ${src_file} EXT) + + if (file_extension STREQUAL ".comp") + set(DEFINES "-DSHADER_STAGE_COMP") + elseif(file_extension STREQUAL ".rahit") + set(DEFINES "-DSHADER_STAGE_ACHIT") + elseif(file_extension STREQUAL ".rmiss") + set(DEFINES "-DSHADER_STAGE_RMISS") + elseif(file_extension STREQUAL ".rchit") + set(DEFINES "-DSHADER_STAGE_RCHIT") + elseif(file_extension STREQUAL ".rgen") + set(DEFINES "-DSHADER_STAGE_RGEN") + elseif(file_extension STREQUAL ".frag") + set(DEFINES "-DSHADER_STAGE_FRAG") + elseif(file_extension STREQUAL ".vert") + set(DEFINES "-DSHADER_STAGE_VERT") + else() + message(FATAL_ERROR "unknown extension in shader source file: ${file_extension}") + endif() + + set_source_files_properties(${src_file} PROPERTIES VS_TOOL_OVERRIDE "None") + + set (out_dir "${CMAKE_SOURCE_DIR}/baseq2/shader_vkpt") + set (out_file "${out_dir}/${base_file_name}.spv") + + set(glslang_command_line + --target-env vulkan1.1 + -DVKPT_SHADER + -V + ${DEFINES} + "${src_file}" + -o "${out_file}") + + add_custom_command(OUTPUT ${out_file} + DEPENDS ${src_file} + DEPENDS ${SHADER_SOURCE_DEPENDENCIES} + MAIN_DEPENDENCY ${src_file} + COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir} + COMMAND ${GLSLANG_COMPILER} ${glslang_command_line}) + + set(${params_OUTPUT_FILE_LIST} ${${params_OUTPUT_FILE_LIST}} ${out_file} PARENT_SCOPE) +endfunction() diff --git a/compile_shaders.bat b/compile_shaders.bat new file mode 100644 index 000000000..dec49678f --- /dev/null +++ b/compile_shaders.bat @@ -0,0 +1,18 @@ +@echo off + +IF "%BUILD_DIRECTORY%" == "" SET BUILD_DIRECTORY=build + +IF NOT EXIST %BUILD_DIRECTORY% ( + echo build directory not found + exit /b 1 +) + +cd %BUILD_DIRECTORY% + +IF EXIST *.sln ( + set "EXTRA_FLAGS=-- /nologo /verbosity:minimal" +) + +cmake --build . --target shaders %EXTRA_FLAGS% +cd .. + diff --git a/config_vkpt b/config_vkpt deleted file mode 100644 index 2e4a1c68e..000000000 --- a/config_vkpt +++ /dev/null @@ -1,19 +0,0 @@ -# save as .config for compiling with Make (linux) - -CONFIG_PNG=1 -CONFIG_JPEG=1 -CONFIG_SDL2=1 - -# use vkpt renderer -CONFIG_VKPT_RENDERER=1 - -# enable/disable vulkan validation layer -CONFIG_VKPT_ENABLE_VALIDATION=0 - -# q2vkpt currently does not support md3 -CONFIG_NO_MD3=1 - -# set up a custom path to the glslangValidator binary here -#CONFIG_GLSLANGVALIDATOR=glslangValidator - -CC=gcc diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt new file mode 100644 index 000000000..149787685 --- /dev/null +++ b/extern/CMakeLists.txt @@ -0,0 +1,58 @@ + +# +# ZLIB +# + +if (NOT CONFIG_LINUX_STEAM_RUNTIME_SUPPORT) + add_subdirectory(zlib) + target_include_directories(zlibstatic PUBLIC $ $) + + set_target_properties(zlib PROPERTIES FOLDER extern) + set_target_properties(zlibstatic PROPERTIES FOLDER extern) + set_target_properties(minigzip PROPERTIES FOLDER extern) + set_target_properties(example PROPERTIES FOLDER extern) +endif() + +# +# SDL 2 +# + +option(SDL_SHARED"" OFF) +option(SDL_STATIC"" ON) +option(SDL_SHARED_ENABLED_BY_DEFAULT OFF) + +if (CONFIG_LINUX_STEAM_RUNTIME_SUPPORT) + option(INPUT_TSLIB OFF) +endif() + +add_subdirectory(SDL2) + +set_target_properties(SDL2main PROPERTIES FOLDER extern) +set_target_properties(SDL2-static PROPERTIES FOLDER extern) +set_target_properties(uninstall PROPERTIES FOLDER extern) + +# +# CURL +# + +if(CONFIG_USE_CURL) + + option(BUILD_CURL_EXE "" OFF) + option(BUILD_SHARED_LIBS "" OFF) + option(CURL_STATICLIB "" ON) + option(BUILD_TESTING "" OFF) + option(ENABLE_MANUAL "" OFF) + option(ENABLE_DOCS "" OFF) + option(HTTP_ONLY "" ON) + option(CURL_ZLIB "" OFF) + option(CMAKE_USE_OPENSSL "" OFF) + set(CURL_CA_PATH "none" CACHE PATH "") + + set(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Override CMAKE_DEBUG_POSTFIX, which curl sets to '-d'") + + set(ZLIB_DIR "{CMAKE_CURRENT_SOURCE_DIR}/zlib") + + add_subdirectory(curl) + + set_target_properties(libcurl PROPERTIES FOLDER extern) +endif() diff --git a/extern/SDL2 b/extern/SDL2 new file mode 160000 index 000000000..efee635e2 --- /dev/null +++ b/extern/SDL2 @@ -0,0 +1 @@ +Subproject commit efee635e2493936da7f5fc0b0580c40da1832424 diff --git a/extern/curl b/extern/curl new file mode 160000 index 000000000..191ffd070 --- /dev/null +++ b/extern/curl @@ -0,0 +1 @@ +Subproject commit 191ffd07082322cdfd4ca4581f39160166534405 diff --git a/extern/zlib b/extern/zlib new file mode 160000 index 000000000..cacf7f1d4 --- /dev/null +++ b/extern/zlib @@ -0,0 +1 @@ +Subproject commit cacf7f1d4e3d44d871b605da3b647f07d718623f diff --git a/inc/client/video.h b/inc/client/video.h index 1195cc713..6c9bd3e95 100644 --- a/inc/client/video.h +++ b/inc/client/video.h @@ -1,5 +1,6 @@ /* Copyright (C) 2003-2006 Andrey Nazarov +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -19,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef VIDEO_H #define VIDEO_H -extern cvar_t *vid_ref; +extern cvar_t *vid_rtx; extern cvar_t *vid_geometry; extern cvar_t *vid_modelist; extern cvar_t *vid_fullscreen; @@ -32,7 +33,9 @@ void VID_PumpEvents(void); void VID_SetMode(void); char *VID_GetDefaultModeList(void); -qboolean VID_Init(void); +typedef enum { GAPI_OPENGL, GAPI_VULKAN } graphics_api_t; + +qboolean VID_Init(graphics_api_t api); void VID_Shutdown(void); void VID_FatalShutdown(void); diff --git a/inc/common/bsp.h b/inc/common/bsp.h index dfc433570..9ea64bc81 100644 --- a/inc/common/bsp.h +++ b/inc/common/bsp.h @@ -1,6 +1,7 @@ /* Copyright (C) 1997-2001 Id Software, Inc. Copyright (C) 2008 Andrey Nazarov +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -44,7 +45,12 @@ typedef struct mtexinfo_s { // used internally due to name len probs //ZOID int radiance; vec3_t axis[2]; vec2_t offset; - struct image_s *image; // used for texturing +#if REF_VKPT + struct pbr_material_s *material; +#endif +#if REF_GL + struct image_s *image; // used for texturing +#endif int numframes; struct mtexinfo_s *next; // used for animation #if USE_REF == REF_SOFT @@ -95,7 +101,7 @@ typedef struct mface_s { int texturemins[2]; int extents[2]; -#if USE_REF == REF_GL || USE_REF == REF_GLPT +#if USE_REF == REF_GL int texnum[2]; int statebits; int firstvert; @@ -277,6 +283,11 @@ typedef struct bsp_s { msurfedge_t *surfedges; #endif + char *pvs_matrix; + char *pvs2_matrix; + qboolean pvs_patched; + + // WARNING: the 'name' string is actually longer than this, and the bsp_t structure is allocated larger than sizeof(bsp_t) in BSP_Load char name[1]; } bsp_t; @@ -301,6 +312,11 @@ byte *BSP_ClusterVis(bsp_t *bsp, byte *mask, int cluster, int vis); mleaf_t *BSP_PointLeaf(mnode_t *node, vec3_t p); mmodel_t *BSP_InlineModel(bsp_t *bsp, const char *name); +char* BSP_GetPvs(bsp_t *bsp, int cluster); +char* BSP_GetPvs2(bsp_t *bsp, int cluster); + +qboolean BSP_SavePatchedPVS(bsp_t *bsp); + void BSP_Init(void); #endif // BSP_H diff --git a/inc/common/cmodel.h b/inc/common/cmodel.h index 5ae2397ef..32593147a 100644 --- a/inc/common/cmodel.h +++ b/inc/common/cmodel.h @@ -75,7 +75,7 @@ mleaf_t *CM_PointLeaf(cm_t *cm, vec3_t p); #define CM_LeafCluster(leaf) (leaf)->cluster #define CM_LeafArea(leaf) (leaf)->area -byte *CM_FatPVS(cm_t *cm, byte *mask, const vec3_t org); +byte *CM_FatPVS(cm_t *cm, byte *mask, const vec3_t org, int vis); void CM_SetAreaPortalState(cm_t *cm, int portalnum, qboolean open); qboolean CM_AreasConnected(cm_t *cm, int area1, int area2); diff --git a/inc/common/common.h b/inc/common/common.h index 3978b7dcf..5f3f0b5f6 100644 --- a/inc/common/common.h +++ b/inc/common/common.h @@ -26,24 +26,20 @@ with this program; if not, write to the Free Software Foundation, Inc., // common.h -- definitions common between client and server, but not game.dll // -#define PRODUCT "Q2VKPT" +#define PRODUCT "Quake II RTX" #if USE_CLIENT -#define APPLICATION "q2vkpt" +#define APPLICATION "q2rtx" #else -#define APPLICATION "q2proded" +#define APPLICATION "q2rtxded" #endif #define COM_DEFAULT_CFG "default.cfg" +#define COM_Q2RTX_CFG "q2rtx.cfg" #define COM_AUTOEXEC_CFG "autoexec.cfg" #define COM_POSTEXEC_CFG "postexec.cfg" #define COM_POSTINIT_CFG "postinit.cfg" - -#ifdef _WIN32 #define COM_CONFIG_CFG "q2config.cfg" -#else -#define COM_CONFIG_CFG "config.cfg" -#endif // FIXME: rename these #define COM_HISTORYFILE_NAME ".conhistory" diff --git a/inc/common/files.h b/inc/common/files.h index c2ab66a03..26a92027a 100644 --- a/inc/common/files.h +++ b/inc/common/files.h @@ -78,11 +78,10 @@ typedef struct file_info_s { // Limit the maximum file size FS_LoadFile can handle, as a protection from // malicious paks causing memory exhaustion. // -// Maximum size of legitimate BSP file on disk is ~12.7 MiB, let's round this -// up to 16 MiB. Assume that no loadable Q2 resource should ever exceed this -// limit. +// Originally set to 16 MiB because that looked like enough for everyone, +// later increased to 256 MiB to support large textures. // -#define MAX_LOADFILE 0x1000000 +#define MAX_LOADFILE 0x10000000 #define FS_Malloc(size) Z_TagMalloc(size, TAG_FILESYSTEM) #define FS_Mallocz(size) Z_TagMallocz(size, TAG_FILESYSTEM) @@ -159,6 +158,8 @@ ssize_t FS_Length(qhandle_t f); qboolean FS_WildCmp(const char *filter, const char *string); qboolean FS_ExtCmp(const char *extension, const char *string); +qerror_t FS_LastModified(char const * file, uint64_t * last_modified); + void **FS_ListFiles(const char *path, const char *filter, unsigned flags, int *count_p); void **FS_CopyList(void **list, int count); file_info_t *FS_CopyInfo(const char *name, size_t size, time_t ctime, time_t mtime); diff --git a/inc/common/qbvhmp.h b/inc/common/qbvhmp.h deleted file mode 100644 index 91890f007..000000000 --- a/inc/common/qbvhmp.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - This file is part of corona-13. - - corona-13 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 3 of the License, or - (at your option) any later version. - - corona-13 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 corona-13. If not, see . -*/ - -#pragma once -#include "threads.h" -#include -#include -#include - -// will keep some stats and print them at the end: -// #define ACCEL_DEBUG -// don't do motion blur: -#define ACCEL_STATIC -// number of split planes tested for surface area heuristic: -#define SAH_TESTS 7 - -typedef union -{ - __m128 m; - float f[4]; - unsigned int i[4]; -} -qbvh_float4_t; - -typedef struct -{ -#ifdef ACCEL_STATIC - uint32_t paabbx, paabby, paabbz; - uint32_t aabb_mx, aabb_my, aabb_mz, aabb_Mx, aabb_My, aabb_Mz; - uint32_t pad0, pad1, pad2; - - // uint16_t paabb[6]; // more parent box in uint16_t - // uint8_t aabb[6][4]; // 8-bit quantised child boxes - // uint32_t pad[3]; - - // qbvh_float4_t aabb0[6]; - // TODO: we'll get away with very few bits here, say 16 per child - // TODO: use the rest for the axis bits - // 1 2 24 5 - // child is | 1 | ax | prim | cnt | for leaves and - // | 0 | ax | child | for inner - uint32_t child[4]; // child index or, if leaf -(prim<<5|num_prims) index -#else // with motion blur: double a regular qbvh node, 256 bytes - qbvh_float4_t aabb0[6]; - qbvh_float4_t aabb1[6]; - uint64_t child[4]; // child index or, if leaf -(prim<<5|num_prims) index - uint64_t parent; - int64_t axis0; - int64_t axis00; - int64_t axis01; -#endif -} -qbvh_node_t; - -#ifdef ACCEL_DEBUG -typedef struct accel_debug_t -{ - uint64_t aabb_intersect; - uint64_t prims_intersect; - uint64_t accel_intersect; - uint64_t aabb_true; -} -accel_debug_t; -#endif - -typedef enum job_type_t -{ - s_job_all = 0, - s_job_node, - s_job_split, - s_job_scan, - s_job_swap -} -job_type_t; - -// shared struct for split job -typedef struct shared_split_job_t -{ - int binmin[SAH_TESTS+1]; - int binmax[SAH_TESTS+1]; - float bound_m[SAH_TESTS+1]; - float bound_M[SAH_TESTS+1]; - int64_t left; // prim index bounds - int64_t right; - int64_t step; // step size - int64_t done; // thread counter - int p, q, d; // split dim and the other two (permutation of 0 1 2) - float aabb0, aabb1; -} -shared_split_job_t; - -typedef struct job_t -{ - job_type_t type; - union - { - struct - { - qbvh_node_t *node; - qbvh_node_t *parent; - int64_t left; - int64_t right; - float paabb[6]; - int depth; - int child; - } - node; - struct - { - shared_split_job_t *job; - int64_t left; - int64_t right; - } - split; - struct - { - uint64_t begin, back; - int axis; - float split; - // output: - int64_t *right; - float *aabbl, *aabbr; - int *done; - } - scan; - struct - { - uint64_t read, num_read; // indices to read from - uint64_t write; // current write index - uint64_t read_block, write_block; // block id of read/write indices - uint64_t *b_l, *b_r, *b_e; // pointers to shared thread blocks - int *done; - } - swap; - }; -} -job_t; - -typedef struct queue_t -{ - pthread_mutex_t mutex; - job_t *jobs; - int32_t num_jobs; -} -queue_t; - -typedef struct accel_t -{ - queue_t *queue; - uint64_t built; - pthread_mutex_t mutex; - threads_t *threads; - - float *prim_aabb; // cached prim aabb, allocated from outside - uint32_t *primid; // primid array, passed in, too - uint32_t num_prims; // number of primitives - - uint64_t num_nodes; - uint64_t node_bufsize; - float aabb[6]; - qbvh_node_t *tree; - - uint32_t *shadow_cache; - uint32_t shadow_cache_last; -#ifdef ACCEL_DEBUG - accel_debug_t *debug; -#endif -} -accel_t; - -// init new acceleration structure for given primitives (don't build yet) -accel_t* accel_init( - float *aabb, // bounding boxes of primitives - uint32_t *primid, // primitive id array - const int num_prims, // number of primitives - threads_t *t); // thread pool to use during construction - -// free memory -void accel_cleanup(accel_t *b); - -// build acceleration structure -void accel_build(accel_t *b); - -// build in the background -void accel_build_async(accel_t *b); - -// block until the background threads have finished working -void accel_build_wait(accel_t *b); - -#if 0 // disabled for now, we want to ray trace on GPU -// intersect ray (closest point) -void accel_intersect(const accel_t *b, const ray_t *ray, hit_t *hit); - -// test visibility up to max distance -int accel_visible(const accel_t *b, const ray_t *ray, const float max_dist); - -// find closest geo intersection point to world space point at ray with parameter centre: -// ray->pos + centre * ray->dir -void accel_closest(const accel_t *b, ray_t *ray, hit_t *hit, const float centre); - -// return pointer to the 6-float minxyz-maxxyz aabb -const float *accel_aabb(const accel_t *b); -#endif diff --git a/inc/common/utils.h b/inc/common/utils.h index fffc0d7f6..b43283c75 100644 --- a/inc/common/utils.h +++ b/inc/common/utils.h @@ -59,7 +59,7 @@ void Com_PageInMemory(void *buffer, size_t size); color_index_t Com_ParseColor(const char *s, color_index_t last); -#if (USE_REF == REF_GL) || (USE_REF == REF_GLPT) +#if USE_REF == REF_GL unsigned Com_ParseExtensionString(const char *s, const char *const extnames[]); #endif diff --git a/inc/format/bsp.h b/inc/format/bsp.h index 5af13711b..3f1aed0f7 100644 --- a/inc/format/bsp.h +++ b/inc/format/bsp.h @@ -190,6 +190,7 @@ typedef struct { // compressed bit vectors #define DVIS_PVS 0 #define DVIS_PHS 1 +#define DVIS_PVS2 16 // Q2RTX : 2nd order PVS #define DVIS_CLUSTERS 8 diff --git a/inc/format/sp2.h b/inc/format/sp2.h index 631c37a09..2eba0b776 100644 --- a/inc/format/sp2.h +++ b/inc/format/sp2.h @@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define SP2_IDENT (('2'<<24)+('S'<<16)+('D'<<8)+'I') #define SP2_VERSION 2 -#define SP2_MAX_FRAMES 32 +#define SP2_MAX_FRAMES 256 #define SP2_MAX_FRAMENAME 64 typedef struct { diff --git a/inc/refresh/images.h b/inc/refresh/images.h index b3b793078..dc6e4fd38 100644 --- a/inc/refresh/images.h +++ b/inc/refresh/images.h @@ -1,6 +1,7 @@ /* Copyright (C) 1997-2001 Id Software, Inc. Copyright (C) 2003-2006 Andrey Nazarov +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -33,7 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define R_Malloc(size) Z_TagMalloc(size, TAG_RENDERER) #define R_Mallocz(size) Z_TagMallocz(size, TAG_RENDERER) -#if USE_REF == REF_GL || USE_REF == REF_GLPT +#if USE_REF == REF_GL #define IMG_AllocPixels(x) FS_AllocTempMem(x) #define IMG_FreePixels(x) FS_FreeTempMem(x) #else @@ -58,15 +59,9 @@ with this program; if not, write to the Free Software Foundation, Inc., typedef enum { IM_PCX, IM_WAL, -#if USE_TGA IM_TGA, -#endif -#if USE_JPG IM_JPG, -#endif -#if USE_PNG IM_PNG, -#endif IM_MAX } imageformat_t; @@ -79,23 +74,26 @@ typedef struct image_s { int width, height; // source image int upload_width, upload_height; // after power of two and picmip int registration_sequence; // 0 = free -#if USE_REF == REF_GL || USE_REF == REF_GLPT + char filepath[MAX_QPATH]; // actual path loaded, with correct format extension + int is_srgb; + uint64_t last_modified; +#if REF_GL unsigned texnum; // gl texture binding float sl, sh, tl, th; -#elif USE_REF == REF_VKPT +#endif +#if REF_VKPT byte *pix_data; // todo: add miplevels - int material_idx; - uint32_t light_color; // use this color if this is a light source - int is_light; + vec3_t light_color; // use this color if this is a light source + vec2_t min_light_texcoord; + vec2_t max_light_texcoord; + qboolean entire_texture_emissive; + qboolean emissive_processing_complete; #else byte *pixels[4]; // mip levels #endif -#if USE_REF == REF_GLPT - uint64_t texhandle; // gl handle for bindless textures -#endif } image_t; -#define MAX_RIMAGES 1024 +#define MAX_RIMAGES 2048 extern image_t r_images[MAX_RIMAGES]; extern int r_numImages; @@ -107,6 +105,7 @@ extern int registration_sequence; extern uint32_t d_8to24table[256]; // these are implemented in src/refresh/images.c +void IMG_ReloadAll(); image_t *IMG_Find(const char *name, imagetype_t type, imageflags_t flags); void IMG_FreeUnused(void); void IMG_FreeAll(void); @@ -121,9 +120,9 @@ void IMG_ResampleTexture(const byte *in, int inwidth, int inheight, void IMG_MipMap(byte *out, byte *in, int width, int height); // these are implemented in src/refresh/[gl,sw]/images.c -void IMG_Unload(image_t *image); -void IMG_Load(image_t *image, byte *pic); -byte *IMG_ReadPixels(int *width, int *height, int *rowbytes); +extern void (*IMG_Unload)(image_t *image); +extern void (*IMG_Load)(image_t *image, byte *pic); +extern byte* (*IMG_ReadPixels)(int *width, int *height, int *rowbytes); #endif // IMAGES_H diff --git a/inc/refresh/models.h b/inc/refresh/models.h index ab5f46bdf..a378c1df4 100644 --- a/inc/refresh/models.h +++ b/inc/refresh/models.h @@ -1,6 +1,7 @@ /* Copyright (C) 1997-2001 Id Software, Inc. Copyright (C) 2008 Andrey Nazarov +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -38,6 +39,14 @@ typedef struct mspriteframe_s { struct image_s *image; } mspriteframe_t; +typedef enum +{ + MCLASS_REGULAR, + MCLASS_EXPLOSION, + MCLASS_SMOKE, + MCLASS_STATIC_LIGHT +} model_class_t; + typedef struct model_s { enum { MOD_FREE, @@ -52,9 +61,10 @@ typedef struct model_s { // alias models int numframes; struct maliasframe_s *frames; -#if USE_REF == REF_GL || USE_REF == REF_GLPT || USE_REF == REF_VKPT +#if USE_REF == REF_GL || USE_REF == REF_VKPT int nummeshes; struct maliasmesh_s *meshes; + model_class_t model_class; #else int numskins; struct image_s *skins[MAX_ALIAS_SKINS]; @@ -69,6 +79,7 @@ typedef struct model_s { // sprite models struct mspriteframe_s *spriteframes; + qboolean sprite_vertical; } model_t; extern model_t r_models[]; @@ -90,10 +101,10 @@ qerror_t MOD_ValidateMD2(struct dmd2header_s *header, size_t length); // these are implemented in [gl,sw]_models.c typedef qerror_t (*mod_load_t)(model_t *, const void *, size_t); -qerror_t MOD_LoadMD2(model_t *model, const void *rawdata, size_t length); +extern qerror_t (*MOD_LoadMD2)(model_t *model, const void *rawdata, size_t length); #if USE_MD3 -qerror_t MOD_LoadMD3(model_t *model, const void *rawdata, size_t length); +extern qerror_t (*MOD_LoadMD3)(model_t *model, const void *rawdata, size_t length); #endif -void MOD_Reference(model_t *model); +extern void (*MOD_Reference)(model_t *model); #endif // MODELS_H diff --git a/inc/refresh/refresh.h b/inc/refresh/refresh.h index bf99e2c18..293822ed8 100644 --- a/inc/refresh/refresh.h +++ b/inc/refresh/refresh.h @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -24,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define MAX_DLIGHTS 32 #define MAX_ENTITIES 256 // == MAX_PACKET_ENTITIES * 2 -#define MAX_PARTICLES 4096 +#define MAX_PARTICLES 16384 #define MAX_LIGHTSTYLES 256 #define POWERSUIT_SCALE 4.0f @@ -86,6 +87,10 @@ typedef struct entity_s { int flags; int id; + + int tent_type; + + float scale; } entity_t; typedef struct dlight_s { @@ -95,6 +100,7 @@ typedef struct dlight_s { #endif vec3_t color; float intensity; + float radius; } dlight_t; typedef struct particle_s { @@ -102,6 +108,8 @@ typedef struct particle_s { int color; // -1 => use rgba float alpha; color_t rgba; + float brightness; + float radius; } particle_t; typedef struct lightstyle_s { @@ -122,6 +130,16 @@ typedef struct decal_s { float dummy; } decal_t; +// passes information back from the RTX renderer to the engine for various development maros +typedef struct ref_feedback_s { + int viewcluster; + int lookatcluster; + int num_light_polys; + + char view_material[MAX_QPATH]; + char view_material_override[MAX_QPATH]; +} ref_feedback_t; + typedef struct refdef_s { int x, y, width, height;// in virtual screen coordinates float fov_x, fov_y; @@ -147,6 +165,8 @@ typedef struct refdef_s { int decal_beg; int decal_end; decal_t decal[MAX_DECALS]; + + ref_feedback_t feedback; } refdef_t; typedef enum { @@ -179,6 +199,7 @@ typedef enum { IF_REPEAT = (1 << 6), IF_NEAREST = (1 << 7), IF_OPAQUE = (1 << 8), + IF_SRGB = (1 << 9) } imageflags_t; typedef enum { @@ -193,10 +214,10 @@ typedef enum { } imagetype_t; // called when the library is loaded -qboolean R_Init(qboolean total); +extern qboolean (*R_Init)(qboolean total); // called before the library is unloaded -void R_Shutdown(qboolean total); +extern void (*R_Shutdown)(qboolean total); // All data that will be used in a level should be // registered before rendering any frames to prevent disk hits, @@ -211,47 +232,51 @@ void R_Shutdown(qboolean total); // are flood filled to eliminate mip map edge errors, and pics have // an implicit "pics/" prepended to the name. (a pic name that starts with a // slash will not use the "pics/" prefix or the ".pcx" postfix) -void R_BeginRegistration(const char *map); +extern void (*R_BeginRegistration)(const char *map); qhandle_t R_RegisterModel(const char *name); qhandle_t R_RegisterImage(const char *name, imagetype_t type, imageflags_t flags, qerror_t *err_p); -void R_SetSky(const char *name, float rotate, vec3_t axis); -void R_EndRegistration(void); - -#define R_RegisterPic(name) R_RegisterImage(name, IT_PIC, IF_PERMANENT, NULL) -#define R_RegisterPic2(name) R_RegisterImage(name, IT_PIC, IF_NONE, NULL) -#define R_RegisterFont(name) R_RegisterImage(name, IT_FONT, IF_PERMANENT, NULL) -#define R_RegisterSkin(name) R_RegisterImage(name, IT_SKIN, IF_NONE, NULL) - -void R_RenderFrame(refdef_t *fd); -void R_LightPoint(vec3_t origin, vec3_t light); - -void R_ClearColor(void); -void R_SetAlpha(float clpha); -void R_SetColor(uint32_t color); -void R_SetClipRect(const clipRect_t *clip); +extern void (*R_SetSky)(const char *name, float rotate, vec3_t axis); +extern void (*R_EndRegistration)(void); + +#define R_RegisterPic(name) R_RegisterImage(name, IT_PIC, IF_PERMANENT | IF_SRGB, NULL) +#define R_RegisterPic2(name) R_RegisterImage(name, IT_PIC, IF_SRGB, NULL) +#define R_RegisterFont(name) R_RegisterImage(name, IT_FONT, IF_PERMANENT | IF_SRGB, NULL) +#define R_RegisterSkin(name) R_RegisterImage(name, IT_SKIN, IF_SRGB, NULL) + +extern void (*R_RenderFrame)(refdef_t *fd); +extern void (*R_LightPoint)(vec3_t origin, vec3_t light); + +extern void (*R_ClearColor)(void); +extern void (*R_SetAlpha)(float clpha); +extern void (*R_SetAlphaScale)(float alpha); +extern void (*R_SetColor)(uint32_t color); +extern void (*R_SetClipRect)(const clipRect_t *clip); float R_ClampScale(cvar_t *var); -void R_SetScale(float scale); -void R_DrawChar(int x, int y, int flags, int ch, qhandle_t font); -int R_DrawString(int x, int y, int flags, size_t maxChars, +extern void (*R_SetScale)(float scale); +extern void (*R_DrawChar)(int x, int y, int flags, int ch, qhandle_t font); +extern int (*R_DrawString)(int x, int y, int flags, size_t maxChars, const char *string, qhandle_t font); // returns advanced x coord qboolean R_GetPicSize(int *w, int *h, qhandle_t pic); // returns transparency bit -void R_DrawPic(int x, int y, qhandle_t pic); -void R_DrawStretchPic(int x, int y, int w, int h, qhandle_t pic); -void R_TileClear(int x, int y, int w, int h, qhandle_t pic); -void R_DrawFill8(int x, int y, int w, int h, int c); -void R_DrawFill32(int x, int y, int w, int h, uint32_t color); +extern void (*R_DrawPic)(int x, int y, qhandle_t pic); +extern void (*R_DrawStretchPic)(int x, int y, int w, int h, qhandle_t pic); +extern void (*R_TileClear)(int x, int y, int w, int h, qhandle_t pic); +extern void (*R_DrawFill8)(int x, int y, int w, int h, int c); +extern void (*R_DrawFill32)(int x, int y, int w, int h, uint32_t color); // video mode and refresh state management entry points -void R_BeginFrame(void); -void R_EndFrame(void); -void R_ModeChanged(int width, int height, int flags, int rowbytes, void *pixels); +extern void (*R_BeginFrame)(void); +extern void (*R_EndFrame)(void); +extern void (*R_ModeChanged)(int width, int height, int flags, int rowbytes, void *pixels); // add decal to ring buffer -void R_AddDecal(decal_t *d); +extern void (*R_AddDecal)(decal_t *d); -#ifdef _GL_DEBUG -void R_SetRayProbe(vec3_t p, vec3_t n); +#if REF_GL +void R_RegisterFunctionsGL(); +#endif +#if REF_VKPT +void R_RegisterFunctionsRTX(); #endif #endif // REFRESH_H diff --git a/VC/inc/config.h b/inc/shared/config.h similarity index 68% rename from VC/inc/config.h rename to inc/shared/config.h index fd372f188..13cf21eb1 100644 --- a/VC/inc/config.h +++ b/inc/shared/config.h @@ -2,15 +2,23 @@ // Q2PRO configuration file for MSVC // -#define REVISION 1337 -#define VERSION "v133.7" +// expand to generate version string +#define STRING(x) #x +#define _STR(x) STRING(x) +#define VERSION_STRING "" _STR(VERSION_MAJOR) "." _STR(VERSION_MINOR) "." _STR(VERSION_POINT) "-" _STR(VERSION_SHA) #ifdef _WIN64 #define CPUSTRING "x86_64" #define BUILDSTRING "Win64" -#else +#elif _WIN32 #define CPUSTRING "x86" #define BUILDSTRING "Win32" +#elif __x86_64__ +#define CPUSTRING "x86_64" +#define BUILDSTRING "Linux" +#else +#define CPUSTRING "x86" +#define BUILDSTRING "Linux" #endif #define BASEGAME "baseq2" @@ -24,23 +32,24 @@ #if USE_CLIENT //#define VID_REF "gl" -#define VID_MODELIST "640x480 800x600 1024x768" -#define VID_GEOMETRY "640x480" +#define VID_MODELIST "640x480 800x600 1024x768 1280x720" +#define VID_GEOMETRY "1280x720" //#define REF_GL 1 //#define USE_REF REF_GL #define USE_UI 1 #define USE_PNG 1 #define USE_JPG 1 #define USE_TGA 1 -#define USE_MD3 0 +#define USE_MD3 1 #define USE_LIGHTSTYLES 1 #define USE_DLIGHTS 1 //#define USE_DINPUT 1 //#define USE_DSOUND 1 -//#define USE_OPENAL 1 +#define USE_OPENAL 1 #define USE_SNDDMA 1 -#define USE_CURL 0 +//#define USE_CURL 0 #define USE_AUTOREPLY 1 +#define USE_CLIENT_GTV 1 #endif #if USE_SERVER @@ -58,7 +67,7 @@ #ifdef _WIN64 typedef __int64 ssize_t; #define SSIZE_MAX _I64_MAX -#else +#elif _WIN32 typedef __int32 ssize_t; #define SSIZE_MAX _I32_MAX #endif diff --git a/inc/shared/shared.h b/inc/shared/shared.h index f796b4681..a6eee253b 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -251,6 +251,9 @@ static inline float Q_fabs(float f) (e)[2]=(a)[2]*(c)+(b)[2]*(d)) #define PlaneDiff(v,p) (DotProduct(v,(p)->normal)-(p)->dist) +#define Vector2Subtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1]) +#define Vector2Add(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1]) + #define Vector4Subtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) #define Vector4Add(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3]) #define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) @@ -970,6 +973,9 @@ typedef struct { #define MZ_NUKE4 38 #define MZ_NUKE8 39 //ROGUE +// Q2RTX +#define MZ_FLARE 40 +// Q2RTX // // monster muzzle flashes @@ -1272,6 +1278,9 @@ typedef enum { TE_EXPLOSION1_NP, TE_FLECHETTE, //ROGUE +// Q2RTX + TE_FLARE, +// Q2RTX TE_NUM_ENTITIES } temp_event_t; diff --git a/LICENSE b/license.txt similarity index 59% rename from LICENSE rename to license.txt index d8cf7d463..cb6bf7e34 100644 --- a/LICENSE +++ b/license.txt @@ -1,3 +1,27 @@ + +Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. +Copyright (c) 2018 Christoph Schied +Copyright (C) 2018 Florian Simon +Copyright (C) 2018 Tobias Zirr +Copyright (c) 2003-2013 Andrey Nazarov +Copyright (c) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or modify it +under the terms and conditions of the GNU General Public License, +version 2, as published by the Free Software Foundation. + +This program is distributed in the hope 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, see . + +Source code is available at the following location: + https://github.com/NVIDIA/Q2RTX + + GNU GENERAL PUBLIC LICENSE Version 2, June 1991 @@ -278,3 +302,173 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS + + + + LIMITED USE SOFTWARE DEMO LICENSE AGREEMENT + +This Limited Use Software Demo License Agreement (the "Agreement") is a +legal agreement between you, the end-user, and Id Software, Inc. ("ID"). +BY CONTINUING THE INSTALLATION OF THIS GAME PROGRAM ENTITLED QUAKE II, +BY LOADING OR RUNNING THE GAME PROGRAM, OR BY PLACING OR COPYING THE +GAME PROGRAM ONTO YOUR COMPUTER HARD DRIVE, COMPUTER RAM OR OTHER STORAGE, +YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. + +1. Grant of License. ID grants to you the non-exclusive limited + right to use this Id Software game program in executable or + object code form only (the "Software"), which is the demo + version of the Software, for non-commercial, recreational + purposes. The term "Software" includes all elements of the + Software such as data files and screen displays. You are not + receiving any ownership or proprietary right, title or interest + in or to the Software or the copyright, trademarks, or other rights + related thereto. For purposes of this section, "use" means loading + the Software into RAM and/or onto computer hard drive, as well as + installation of the Software on a hard disk or other storage device. + + You agree that the Software will not be shipped, transferred or + exported into any country in violation of the U.S. Export + Administration Act (or any other law governing such matters) by you + or anyone at your direction and that you will not utilize and will not + authorize anyone to utilize, in any other manner, the Software in + violation of any applicable law. The Software may not be downloaded + or otherwise exported or reexported into (or to a national or resident + of) any country to which the U.S. has embargoed goods or to anyone or + into any country who/which are prohibited, by applicable law, from + receiving such property. + +2. Prohibitions. You, either directly or indirectly, shall not do any of + the following acts: + + a. rent the Software; + + b. sell the Software; + + c. lease or lend the Software; + + d. offer the Software on a ?pay-per-play? basis; + + e. distribute the Software (except by electronic means, as + permitted by section 3. hereinbelow) by any means, + including, but not limited to direct mail, retail, mail + order or other means; + + f. in any other manner and through any medium whatsoever + commercially exploit the Software or use the Software + for any commercial purpose; + + g. disassemble, reverse engineer, decompile, modify or + alter the Software; + + h. translate the Software; + + i. reproduce or copy the Software (except as permitted by + section 3. hereinbelow); + + j. publicly display the Software; or + + k. prepare or develop derivative works based upon the + Software. + + 3. Permitted Electronic Distribution and Copying. So long as this + Agreement accompanies the Software at all times, ID grants to you + the limited right to distribute, free of charge and by electronic + means only, the Software. Anyone who receives the Software from + Provider, as defined below, shall be limited to all the terms and + conditions of this Agreement. The term "Provider" shall mean an + enduser who installs a copy of the Software on his/its server and + allows other endusers to download a copy of the Software from such + server. You may make only the following copies of the Software: + (i) you may download the Software from the Internet and onto your + computer hard drive; (ii) you may copy the Software from your computer + hard drive into your computer RAM; and (iii) you may make one (1) + "back up" or archival copy of the Software on one (1) hard disk. + + 4. Copyright. The Software and all copyrights, trademarks and all other + conceivable intellectual property rights related to the Software are + owned by ID and are protected by United States copyright laws, + international treaty provisions and all applicable law, such as the + Lanham Act. You must treat the Software like any other copyrighted + material, as required by 17 U.S.C., section 101 et seq. and other + applicable law. You agree to use your best efforts to see that any + user of the Software licensed hereunder complies with this Agreement. + You agree that you are receiving a copy of the Software by license only + and not by sale and that the "first sale" doctrine of 17 U.S.C. section + 109 does not apply to your receipt or use of the Software. + +5. NO WARRANTIES. ID DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS OR IMPLIED, + INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT TO THE SOFTWARE. ID DOES + NOT WARRANT THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR + ERROR FREE OR THAT THE SOFTWARE WILL MEET YOUR SPECIFIC REQUIREMENTS. + ADDITIONAL STATEMENTS SUCH AS PRESENTATIONS, WHETHER ORAL OR WRITTEN, DO + NOT CONSTITUTE WARRANTIES BY ID AND SHOULD NOT BE RELIED UPON. + +6. Venue and Liability Limitation. This Agreement shall be construed in + accordance with and governed by the laws of the State of Texas and U.S. + federal law. Copyright and other proprietary matters will be governed by + United States laws and international treaties. Exclusive venue for all + litigation regarding this Agreement shall be in Dallas County, Texas and you + agree to submit to the jurisdiction of the courts in Dallas, Texas for any + such litigation. IN ANY CASE, NEITHER ID NOR ID'S OFFICERS, EMPLOYEES, + DIRECTORS, AGENTS, LICENSEES, SUBLICENSEES, SUCCESSORS OR ASSIGNS SHALL BE + LIABLE FOR LOSS OF DATA, LOSS OF PROFITS, LOST SAVINGS, SPECIAL, INCIDENTAL, + CONSEQUENTIAL, INDIRECT, PUNITIVE OR OTHER SIMILAR DAMAGES ARISING FROM + BREACH OF WARRANTY, BREACH OF CONTRACT, NEGLIGENCE, STRICT PRODUCT + LIABILITY, OR OTHER LEGAL THEORY EVEN IF ID OR ITS AGENT HAS BEEN ADVISED + OF THE POSSIBILITY OF SUCH DAMAGES OR EVEN IF SUCH DAMAGES ARE FORESEEABLE, + OR LIABLE FOR ANY CLAIM BY ANY OTHER PARTY. Some jurisdictions do not + allow the exclusion or limitation of incidental or consequential damages, + so the above limitation or exclusion may not apply to you. + +7. U.S. Government Restricted Rights. To the extent applicable, the United + States Government shall only have those rights to use the Software as + expressly stated and expressly limited and restricted in this Agreement, + as provided in 48 C.F.R. sections 227.7202-1 through 227.7204, inclusive. + +8. General Provisions. A copy of all notices or other correspondence which + you send to ID shall also be sent by you to ID's counsel: + +D. Wade Cloud, Jr. +HIERSCHE, MARTENS, HAYWARD, DRAKELEY & URBACH, P.C. +15303 Dallas Parkway, Suite 700 +Dallas, TX 75248 +(972) 701-7000 +Facsimile: (972) 701-8765 + +Neither this Agreement nor any part or portion hereof shall be assigned or s +ublicensed by you. ID may assign its rights under this Agreement in ID's sole +discretion. Should any provision of this Agreement be held to be void, invalid, +unenforceable or illegal by a court, the validity and enforceability of the +other provisions shall not be affected thereby. If any provision is determined +to be unenforceable, you agree to a modification of such provision to provide +for enforcement of the provision's intent, to the extent permitted by applicable +law. Failure of ID to enforce any provision of this Agreement shall not +constitute or be construed as a waiver of such provision or of the right to +enforce such provision. If you fail to comply with any term of this Agreement, +YOUR LICENSE IS AUTOMATICALLY TERMINATED, WITHOUT NOTICE. In the event this +Agreement is terminated, you shall have no right to use the Software, in any +manner and you shall immediately destroy all copies of the Software in your +possession, custody or control. You agree that your unauthorized use of any +ID property, whether in whole or in part, would immediately and irreparably +damage ID such that ID could not be adequately compensated by an award of +monetary damages, and in the event of such threatened or actual unauthorized +use ID shall be entitled to an injunctive order appropriately restraining and/or +prohibiting such unauthorized use without the necessity of ID posting bond or +other security. + +YOU ACKNOWLEDGE THAT YOU HAVE READ THIS AGREEMENT, YOU UNDERSTAND THIS +AGREEMENT, AND UNDERSTAND THAT BY CONTINUING THE INSTALLATION OF THE SOFTWARE, +BY LOADING OR RUNNING THE SOFTWARE, OR BY PLACING OR COPYING THE SOFTWARE +ONTO YOUR COMPUTER HARD DRIVE OR RAM, YOU AGREE TO BE BOUND BY THE TERMS AND +CONDITIONS OF THIS AGREEMENT. YOU FURTHER AGREE THAT, EXCEPT FOR WRITTEN +SEPARATE AGREEMENTS BETWEEN ID AND YOU, THIS AGREEMENT IS A COMPLETE AND +EXCLUSIVE STATEMENT OF THE RIGHTS AND LIABILITIES OF THE PARTIES HERETO. +THIS AGREEMENT SUPERSEDES ALL PRIOR ORAL AGREEMENTS, PROPOSALS OR +UNDERSTANDINGS, AND ANY OTHER COMMUNICATIONS BETWEEN ID AND YOU RELATING TO +THE SUBJECT MATTER OF THIS AGREEMENT. + + +February 16, 1998 (9:22am) + + diff --git a/notice.txt b/notice.txt new file mode 100644 index 000000000..e380dca57 --- /dev/null +++ b/notice.txt @@ -0,0 +1,52 @@ + Quake II RTX + Copyright (C) 2019, NVIDIA CORPORATION + All rights reserved. + + https://github.com/NVIDIA/Q2RTX + +NVIDIA, the NVIDIA logo, GeForce, GeForce GTX, GeForce RTX, NVIDIA GameWorks, +and NVIDIA RTX are trademarks and/or registered trademarks of NVIDIA Corporation +in the U.S. and/or other countries. Other company and product names may be +trademarks of the respective companies with which they are associated. +NVIDIA's trademarks may be used publicly with permission only from NVIDIA, +and nothing in this Agreement shall be construed as granting such permission. +Fair use of NVIDIA's trademarks in advertising and promotion of NVIDIA products +requires proper acknowledgment; + +https://www.nvidia.com/content/dam/en-zz/Solutions/about-us/documents/NVIDIA-Trademark-and-Logo-Usage-Guidelines.pdf + + +Third Party IP +============== + +This product is based on or incorporates materials from the sources listed below +(third party IP). Such licenses and notices are provided for informational +purposes only. + +* Quake II + Copyright (C) 1997-2001 Id Software, Inc. + licensed under the terms of the GPLv2. + https://github.com/id-Software/Quake-2 + +* Q2PRO + Copyright © 2003-2011 Andrey Nazarov + licensed under the terms of the GPLv2. + https://github.com/skullernet/q2pro + +* Q2VKPT + Copyright © 2018 Christoph Schied + licensed under the terms of the GPLv2. + https://github.com/cschied/q2vkpt + +* Q2XP mod pack + https://www.moddb.com/mods/quake-2-xp + used with permission from Arthur Galaktionov + +* Quake2MaX "A Modscape Production" + http://quake2max.planetquake.gamespy.com + Textures from Quake2Max used in Quake2XP. + Copyright © 2019 D Scott Boyce. All Rights Reserved. + Subject to Creative Commons license version 1.0, + +Roughness and specular channels were adjusted in texture maps to work with +the Quake II RTX engine. diff --git a/readme.md b/readme.md new file mode 100644 index 000000000..78b1b349a --- /dev/null +++ b/readme.md @@ -0,0 +1,136 @@ +# Quake II RTX + +**Quake II RTX** is NVIDIA's attempt at implemeting a fully functional +version of Id Software's 1997 hit game **Quake II** with RTX path-traced +global illumination. + +**Quake II RTX** builds upon the [Q2VKPT](http://brechpunkt.de/q2vkpt) +branch of the Quake II open source engine. Q2VKPT was created by former +NVIDIA intern Christoph Schied, a Ph.D. student at the Karlsruhe Institute +of Technology in Germany. + +Q2VKPT, in turn, builds upon [Q2PRO](https://skuller.net/q2pro/), which is a +modernized version of the Quake II engine. Consequently, many of the settings +and console variables that work for Q2PRO also work for Quake II RTX. The +[client](https://skuller.net/q2pro/nightly/client.html) and +[server](https://skuller.net/q2pro/nightly/server.html) manuals are particularly useful. + +## License + +**Quake II RTX** is licensed under the terms of the **GPL v.2** (GNU General Public License). +You can find the entire license in the license.txt file. + +The **Quake II** game data files remain copyrighted and licensed under the +original id Software terms, so you cannot redistribute the pak files from the +original game. + +## Features + +**Quake II RTX** introduces the following features: + - Caustics approximation + - Cylindrical projection mode + - Dynamic lighting for items such as blinking lights, signs, switches, elevators and moving objects + - Dynamic real-time "time of day" lighting + - Flare gun and other high-detail weapons + - High-quality screenshot mode + - Improved denoising technology + - Multi-GPU (SLI) support + - Multiplayer modes (deathmatch and cooperative) + - Optional two-bounce indirect illumination + - Particles, laser beams, and new explosion sprites + - Physically based materials, including roughness, metallic, emissive, and normal maps + - Player avatar (casting shadows, visible in reflections) + - Reflections and refractions on water and glass, reflective chrome and screen surfaces + - Procedural environments (sky, mountains, clouds that react to lighting; also space) + - Sunlight with direct and indirect illumination + - Volumetric lighting (god-rays) + +You can download functional builds of the game from [NVIDIA](https://www.geforce.com/quakeiirtx/) +or [Steam](https://store.steampowered.com/). + +## Additional Information + + * [Announcement Article](https://www.nvidia.com/en-us/geforce/news/quake-ii-rtx-ray-tracing-vulkan-vkray-geforce-rtx/) + * [Ray-Tracing Deep Dive](https://www.nvidia.com/en-us/geforce/news/geforce-gtx-dxr-ray-tracing-available-now/) + * [Launch Trailer Video](https://www.youtube.com/watch?v=unGtBbhaPeU) + * [Path Tracer Overview Video](https://www.youtube.com/watch?v=BOltWXdV2XY) + * [GDC 2019 Presentation](https://www.gdcvault.com/play/1026185/) + +## Forum + + * https://forums.geforce.com/default/topic/1119082/geforce-rtx-20-series/quake-ii-rtx-installation-guide/ + +## System Requirements + +In order to build **Quake II RTX** you will need the following software +installed on your computer (with at least the specified versions or more +recent ones). + +### Operating System + +| | Windows | Linux | +|-------------|------------|-----------| +| Min Version | Win 7 x64 | Ubuntu 16 | + +Note: only the Windows 10 version has been extensively tested. + +Note: distributions that are binary compatible with Ubuntu 16 should work as well. + +### Software + +| | min Version | +|-----------------------------------------------------|-------------| +| NVIDIA driver
https://www.geforce.com/drivers | 430 | +| git
https://git-scm.com/downloads | 2.15 | +| CMake
https://cmake.org/download/ | 3.8 | +| Vulkan SDK
https://www.lunarg.com/vulkan-sdk/ | 1.1.92 | + +## Submodules + +* [zlib](https://github.com/madler/zlib) +* [curl](https://github.com/curl/curl) +* [SDL2](https://github.com/spurious/SDL-mirror) + +## Build Instructions + + 1. Clone the repository and its submodules from git : + + ```git clone --recursive https://github.com/NVIDIA/q2rtx.git ``` + + 2. Create a build folder named 'build' under the repository root (q2rtx/build) + + Note: this is required by the shader build rules. + + 3. Copy (or create a symbolic link) to the game assets folder (q2rtx/baseq2) + + Note: the asset packages from the binary build of Quake II RTX are required for the engine to run. + Specifically, the `blue_noise.pkz` and `q2rtx_media.pkz` files or their extracted contents. + + 4. Configure CMake with either the GUI or the command line and make sure to + point the build at the 'build' folder created in step 1. + + 5. Build with Visual Studio on Windows, make on Linux, or the CMake command + line: + + ```cmake --build . ``` + +## MIDI Controller Support + +The Quake II console can be remote operated through a UDP connection, which +allows users to control in-game effects from input peripherals such as MIDI controllers. This is +useful for tuning various graphics parameters such as position of the sun, intensities of lights, +material parameters, filter settings, etc. + +You can find a compatible MIDI controller driver [here](https://github.com/NVIDIA/korgi) + +To enable remote access to your Quake II RTX client, you will need to set the following +console variables _before_ starting the game, i.e. in the config file or through the command line: +``` + rcon_password "" + backdoor "1" +``` + +Note: the password set here should match the password specified in the korgi configuration file. + +Note 2: enabling the rcon backdoor allows other people to issue console commands to your game from +other computers, so choose a good password. diff --git a/setup/Nvidia.ico b/setup/Nvidia.ico new file mode 100644 index 000000000..e465f8317 Binary files /dev/null and b/setup/Nvidia.ico differ diff --git a/setup/WelcomeImage.bmp b/setup/WelcomeImage.bmp new file mode 100644 index 000000000..4a101562f Binary files /dev/null and b/setup/WelcomeImage.bmp differ diff --git a/setup/find-retail-paks.sh b/setup/find-retail-paks.sh new file mode 100755 index 000000000..9a59170ec --- /dev/null +++ b/setup/find-retail-paks.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +DEST_DIR="${HOME}/.quake2rtx" + +# Check for zenity/yad +ZEN="" + +# Default to not copying retail files (since we can't distribute them, and not +# every player will have the full game) +NO_COPY_RETAIL=1 + +copy_retail_files() { + FULL_GAME_DIR="$1" + pushd "${FULL_GAME_DIR}" + cp baseq2/pak*.pak "${DEST_DIR}/baseq2" + cp -R baseq2/players "${DEST_DIR}/baseq2" + popd +} + + +# which zenity +if [[ -f "/usr/bin/zenity" ]]; then + ZEN="$(which zenity)" + # XXX[ljm] WAR steam-runtime bug: https://github.com/ValveSoftware/steam-runtime/issues/104 + # The steam-runtime copy of zenity relies on a older zenity.ui file + # version, and won't work on more modern distros + ZEN="/usr/bin/zenity" + ZEN_QUESTION="${ZEN} --question --text" + ZEN_INFO="${ZEN} --info --text" + ZEN_DIR_SELECT="${ZEN} --file-selection --directory" +else + which kdialog + if [[ ! -z "$?" ]]; then + ZEN="$(which kdialog)" + ZEN_QUESTION="${ZEN} --title Q2RTX --warningyesnocancel" + ZEN_INFO="${ZEN} --title Q2RTX --msgbox" + ZEN_DIR_SELECT="${ZEN} --title Q@RTX --getexistingdirectory" + else + ZEN=0 + fi +fi + +if [[ ! -z ${ZEN} ]]; then + ${ZEN_QUESTION} "Do you own the Retail copy of Quake 2 and would like to import the PAK files to Quake 2 RTX?" + # XXX[ljm] -z isn't working for some reason :( + if [[ "0" -eq "$?" ]]; then + NO_COPY_RETAIL=0 + fi +fi + +# XXX[ljm] -z isn't working for some reason :( +if [[ "0" -eq ${NO_COPY_RETAIL} ]]; then + + # Check usual install location + if [[ -d "${HOME}/.steam/steam/steamapps/common/Quake 2" ]]; then + copy_retail_files "${HOME}/.steam/steam/steamapps/common/Quake 2" + exit 0; + fi + + # Prompt user for custom existing-install location + if [[ ! -z ${ZEN} ]]; then + ${ZEN_INFO} "Please select your existing Quake 2 Retail Installation Directory." + copy_retail_files $(${ZEN_DIR_SELECT}) + exit 0; + fi +fi + +# No retail found or user wasn't interested +exit 1 diff --git a/setup/package_for_steam.bat b/setup/package_for_steam.bat new file mode 100644 index 000000000..b0be542ff --- /dev/null +++ b/setup/package_for_steam.bat @@ -0,0 +1,8 @@ +@echo off +PUSHD .. +SET SEVENZIP="C:\Program Files\7-Zip\7z.exe" +SET SOURCES=q2rtx.exe q2rtxded.exe baseq2\gamex86_64.dll baseq2\shaders.pkz baseq2\blue_noise.pkz baseq2\q2rtx_media.pkz setup\Quake2RTX-Steam-Setup.exe +SET DEST=setup\q2rtx_steam.zip +IF EXIST %DEST% DEL %DEST% +%SEVENZIP% a -mx1 -tzip %DEST% %SOURCES% +POPD \ No newline at end of file diff --git a/setup/package_media.bat b/setup/package_media.bat new file mode 100644 index 000000000..010400f18 --- /dev/null +++ b/setup/package_media.bat @@ -0,0 +1,8 @@ +@echo off +PUSHD ..\baseq2 +SET SEVENZIP="C:\Program Files\7-Zip\7z.exe" +SET SOURCES=env maps models overrides pics sound sprites textures materials.csv prefetch.txt pt_toggles.cfg q2rtx.cfg q2rtx.menu sky_clusters.txt +SET DEST=q2rtx_media.pkz +IF EXIST %DEST% DEL %DEST% +%SEVENZIP% a -tzip %DEST% %SOURCES% +POPD \ No newline at end of file diff --git a/setup/package_media.cmake b/setup/package_media.cmake new file mode 100644 index 000000000..73ce1e50d --- /dev/null +++ b/setup/package_media.cmake @@ -0,0 +1,18 @@ +SET(MEDIA_SOURCES + ${SOURCE}/baseq2/env + ${SOURCE}/baseq2/maps + ${SOURCE}/baseq2/models + ${SOURCE}/baseq2/overrides + ${SOURCE}/baseq2/pics + ${SOURCE}/baseq2/sound + ${SOURCE}/baseq2/sprites + ${SOURCE}/baseq2/textures + ${SOURCE}/baseq2/materials.csv + ${SOURCE}/baseq2/prefetch.txt + ${SOURCE}/baseq2/pt_toggles.cfg + ${SOURCE}/baseq2/q2rtx.cfg + ${SOURCE}/baseq2/q2rtx.menu + ${SOURCE}/baseq2/sky_clusters.txt +) +set(out_file "${SOURCE}/baseq2/q2rtx_media.pkz") +exec_program(7za ARGS "a -tzip" ${out_file} ${MEDIA_SOURCES}) diff --git a/setup/package_shaders.bat b/setup/package_shaders.bat new file mode 100644 index 000000000..35e665102 --- /dev/null +++ b/setup/package_shaders.bat @@ -0,0 +1,8 @@ +@echo off +PUSHD ..\baseq2 +SET SEVENZIP="C:\Program Files\7-Zip\7z.exe" +SET SOURCES=shader_vkpt +SET DEST=shaders.pkz +IF EXIST %DEST% DEL %DEST% +%SEVENZIP% a -tzip %DEST% %SOURCES% +POPD \ No newline at end of file diff --git a/setup/package_shaders.cmake b/setup/package_shaders.cmake new file mode 100644 index 000000000..48654f5ad --- /dev/null +++ b/setup/package_shaders.cmake @@ -0,0 +1,5 @@ +SET(SHADER_SOURCES + ${SOURCE}/baseq2/shader_vkpt +) +set(out_file "${SOURCE}/baseq2/shaders.pkz") +exec_program(7za ARGS "a -tzip" ${out_file} ${SHADER_SOURCES}) diff --git a/setup/q2rtx.desktop b/setup/q2rtx.desktop new file mode 100644 index 000000000..e6641bc15 --- /dev/null +++ b/setup/q2rtx.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Encoding=UTF-8 +Name=Quake II RTX +Exec=q2rtx +Icon=q2rtx +Categories=Game;Shooter diff --git a/setup/q2rtx.png b/setup/q2rtx.png new file mode 100644 index 000000000..92a67311d Binary files /dev/null and b/setup/q2rtx.png differ diff --git a/setup/q2rtx.sh b/setup/q2rtx.sh new file mode 100755 index 000000000..80e08c236 --- /dev/null +++ b/setup/q2rtx.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +BIN_PREFIX="." + +# If the game is installed via a package manager q2rtx won't be in the same +# directory as q2rtx.sh +if [[ -d "/usr/share/quake2rtx" ]]; then + BIN_PREFIX="/usr/share/quake2rtx/bin" +fi + +# Generate the user's game dir if doesn't exist +if [[ ! -d "${HOME}/.quake2rtx/baseq2" ]]; then + mkdir -p "${HOME}/.quake2rtx/baseq2" +fi + +# Only run this script on first-launch +if [[ ! -f "${HOME}/.quake2rtx/.retail_checked" ]]; then + ${BIN_PREFIX}/find-retail-paks.sh + touch ${HOME}/.quake2rtx/.retail_checked +fi + +${BIN_PREFIX}/q2rtx "$@" diff --git a/setup/setup.nsi b/setup/setup.nsi new file mode 100644 index 000000000..e1a6e8c52 --- /dev/null +++ b/setup/setup.nsi @@ -0,0 +1,134 @@ + +RequestExecutionLevel user + +!include "nsDialogs.nsh" +!include "MUI2.nsh" +!include "FileFunc.nsh" +!include "StrFunc.nsh" + +${StrTrimNewLines} +${StrRep} + +!define SOURCE_DIR ".." +!define REG_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\Quake2RTX" +!define GAME_EXE "$INSTDIR\q2rtx.exe" +!define UNINSTALL_EXE "$INSTDIR\Uninstall.exe" + +!define MUI_ICON "..\src\windows\res\q2rtx.ico" +!define MUI_WELCOMEFINISHPAGE_BITMAP "WelcomeImage.bmp" +!define MUI_ABORTWARNING + +Outfile "Quake2RTX-Setup.exe" +Name "Quake II RTX" + +; InstallDir "$PROGRAMFILES\Quake2RTX" +InstallDir "C:\Games\Quake2RTX" + +!insertmacro MUI_PAGE_WELCOME + +!define MUI_DIRECTORYPAGE_TEXT_TOP "Choose the folder where to install Quake II RTX.$\r$\n\ +Installing into a system folder like '$PROGRAMFILES' is NOT recommended.$\r$\n\ +Installing into a folder with an existing installation of Quake II is also NOT recommended." + +!insertmacro MUI_PAGE_DIRECTORY + +!define MUI_COMPONENTSPAGE_SMALLDESC +!insertmacro MUI_PAGE_COMPONENTS + +Var FullGameDir +!define MUI_PAGE_CUSTOMFUNCTION_PRE FullGamePage_Pre +!define MUI_PAGE_CUSTOMFUNCTION_LEAVE FullGamePage_Leave +!define MUI_PAGE_HEADER_TEXT "Quake II Game Files" +!define MUI_PAGE_HEADER_SUBTEXT "" +!define MUI_DIRECTORYPAGE_TEXT_TOP "Choose the folder where the Quake II game files are located. The installer will copy the necessary files to the Quake II RTX install location." +!define MUI_DIRECTORYPAGE_TEXT_DESTINATION "Folder with the Quake II executable" +!define MUI_DIRECTORYPAGE_VARIABLE $FullGameDir +!insertmacro MUI_PAGE_DIRECTORY + +!insertmacro MUI_PAGE_INSTFILES +;!insertmacro MUI_PAGE_FINISH +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_LANGUAGE "English" + + +Section "Engine Files (Required)" Section_Game + + SectionIn RO + + SetOutPath "$INSTDIR" + File "${SOURCE_DIR}\q2rtx.exe" + File "${SOURCE_DIR}\q2rtx.pdb" + File "${SOURCE_DIR}\q2rtxded.exe" + File "${SOURCE_DIR}\q2rtxded.pdb" + File "${SOURCE_DIR}\license.txt" + File "${SOURCE_DIR}\notice.txt" + File "${SOURCE_DIR}\readme.md" + + SetOutPath "$INSTDIR\baseq2" + File "${SOURCE_DIR}\baseq2\gamex86_64.dll" + + SetCompress OFF + File "${SOURCE_DIR}\baseq2\shaders.pkz" + File "${SOURCE_DIR}\baseq2\blue_noise.pkz" + File "${SOURCE_DIR}\baseq2\q2rtx_media.pkz" + + WriteUninstaller ${UNINSTALL_EXE} + + WriteRegStr HKLM "${REG_KEY}" "DisplayName" "Quake II RTX" + WriteRegStr HKLM "${REG_KEY}" "DisplayIcon" "${GAME_EXE}" + WriteRegStr HKLM "${REG_KEY}" "Publisher" "NVIDIA Corporation" + WriteRegStr HKLM "${REG_KEY}" "UninstallString" "$\"${UNINSTALL_EXE}$\"" + + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${REG_KEY}" "EstimatedSize" "$0" + +SectionEnd + +Section "Quake II Shareware Demo" Section_Shareware + + SetOutPath "$INSTDIR\baseq2" + SetCompress AUTO + File "${SOURCE_DIR}\baseq2\shareware\pak0.pak" + +SectionEnd + +Section /o "Quake II Full Game" Section_FullGame + + CopyFiles "$FullGameDir\baseq2\pak*.pak" "$INSTDIR\baseq2" + CopyFiles "$FullGameDir\baseq2\players" "$INSTDIR\baseq2" + +SectionEnd + +Section "Desktop Shortcut" Section_DesktopShortcut + + CreateShortCut "$DESKTOP\Quake II RTX.lnk" "${GAME_EXE}" + +SectionEnd + +;Section "Start Menu Shortcuts" +; +; CreateDirectory "$SMPROGRAMS\Quake II RTX" +; CreateShortCut "$SMPROGRAMS\Quake II RTX\Quake II RTX.lnk" "${GAME_EXE}" +; +;SectionEnd + +Section "Uninstall" + + Delete "${UNINSTALL_EXE}" + Delete "$DESKTOP\Quake II RTX.lnk" + Delete "$SMPROGRAMS\Quake II RTX\Quake II RTX.lnk" + DeleteRegKey HKLM "${REG_KEY}" + RMDir /r "$INSTDIR" + +SectionEnd + +!include "setup_gamefiles.nsh" + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${Section_Game} "Executable and media files for Quake II RTX" + !insertmacro MUI_DESCRIPTION_TEXT ${Section_Shareware} "Install a copy of the Quake II Shareware Demo" + !insertmacro MUI_DESCRIPTION_TEXT ${Section_FullGame} "Locate and copy the media files for the full game" + !insertmacro MUI_DESCRIPTION_TEXT ${Section_DesktopShortcut} "Place a shortcut for the game onto the Desktop" +!insertmacro MUI_FUNCTION_DESCRIPTION_END \ No newline at end of file diff --git a/setup/setup_gamefiles.nsh b/setup/setup_gamefiles.nsh new file mode 100644 index 000000000..aa4b5be3c --- /dev/null +++ b/setup/setup_gamefiles.nsh @@ -0,0 +1,90 @@ + +Function FullGamePage_Pre + ${IfNot} ${SectionIsSelected} ${Section_FullGame} + Abort + ${EndIf} + + Var /GLOBAL BethesdaDir + Var /GLOBAL SteamDir + Var /GLOBAL CurLine + Var /GLOBAL FileHandle + Var /GLOBAL CharIndex + + ; try to find Quake 2 in the Bethesda library + ReadRegStr $BethesdaDir HKLM "SOFTWARE\Bethesda Softworks\Bethesda.net" "installLocation" + ${IfNot} ${Errors} + StrCpy $FullGameDir "$BethesdaDir\games\Quake II" + IfFileExists "$FullGameDir\quake2.exe" SearchDone + + ; not found - clear the variable + StrCpy $FullGameDir "" + ${EndIf} + + ; try to find Quake 2 in the Steam folders + ReadRegStr $SteamDir HKLM "SOFTWARE\Valve\Steam" "InstallPath" + ${IfNot} ${Errors} + ; first, look in the default Steam library + StrCpy $FullGameDir "$SteamDir\steamapps\common\Quake 2" + IfFileExists "$FullGameDir\quake2.exe" SearchDone + + ; not found - clear the variable + StrCpy $FullGameDir "" + + ; now look for other libraries which are listed in + FileOpen $FileHandle "$SteamDir\steamapps\libraryfolders.vdf" r + IfErrors SearchDone + + NextLine: + FileRead $FileHandle $CurLine + StrCmp $CurLine '' FileDone + + ${StrTrimNewLines} $CurLine $CurLine + + ; test if the line ends with a quote + StrCpy $0 $CurLine 1 -1 + StrCmp $0 '"' 0 NextLine + + StrCpy $CharIndex -2 + NextChar: + StrCpy $0 $CurLine 1 $CharIndex + IntOp $CharIndex $CharIndex - 1 + + StrCmp $0 '' NextLine 0 ; beginning of line, no quote - go to next line + StrCmp $0 '"' 0 NextChar ; if this is not a quote, try next character; otherwise, go on + + IntOp $CharIndex $CharIndex + 2 + IntOp $1 -1 - $CharIndex + StrCpy $FullGameDir $CurLine $1 $CharIndex ; extract the quoted substring from CurLine + StrCpy $FullGameDir "$FullGameDir\steamapps\common\Quake 2" + ${StrRep} $FullGameDir $FullGameDir "\\" "\" + + IfFileExists "$FullGameDir\quake2.exe" FileDone + + ; not a valid path - clear FullGameDir and keep looking + StrCpy $FullGameDir "" + Goto NextLine + + FileDone: + FileClose $FileHandle + + SearchDone: + ${EndIf} +FunctionEnd + +Function FullGamePage_Leave + IfFileExists "$FullGameDir\baseq2\pak0.pak" exists 0 + MessageBox MB_OK "Game files (baseq2\pak*.pak) are not found in the specified location. Please specify the correct location." + Abort + exists: +FunctionEnd + +Function .onInit +StrCpy $1 ${Section_Shareware} +FunctionEnd + +Function .onSelChange +!insertmacro StartRadioButtons $1 +!insertmacro RadioButton "${Section_Shareware}" +!insertmacro RadioButton "${Section_FullGame}" +!insertmacro EndRadioButtons +FunctionEnd diff --git a/setup/steam_setup.nsi b/setup/steam_setup.nsi new file mode 100644 index 000000000..d81958031 --- /dev/null +++ b/setup/steam_setup.nsi @@ -0,0 +1,59 @@ + +RequestExecutionLevel user + +!include "nsDialogs.nsh" +!include "MUI2.nsh" +!include "FileFunc.nsh" +!include "StrFunc.nsh" + +${StrTrimNewLines} +${StrRep} + +!define SOURCE_DIR ".." + +!define MUI_ICON "..\src\windows\res\q2rtx.ico" +!define MUI_ABORTWARNING + +Outfile "Quake2RTX-Steam-Setup.exe" +Name "Quake II RTX" + +InstallDir "$EXEDIR\.." + +!define MUI_COMPONENTSPAGE_SMALLDESC +!insertmacro MUI_PAGE_COMPONENTS + +Var FullGameDir +!define MUI_PAGE_CUSTOMFUNCTION_PRE FullGamePage_Pre +!define MUI_PAGE_CUSTOMFUNCTION_LEAVE FullGamePage_Leave +!define MUI_PAGE_HEADER_TEXT "Quake II Game Files" +!define MUI_PAGE_HEADER_SUBTEXT "" +!define MUI_DIRECTORYPAGE_TEXT_TOP "Choose the folder where the Quake II game files are located. The installer will copy the necessary files to the Quake II RTX install location." +!define MUI_DIRECTORYPAGE_TEXT_DESTINATION "Folder with the Quake II executable" +!define MUI_DIRECTORYPAGE_VARIABLE $FullGameDir +!insertmacro MUI_PAGE_DIRECTORY + +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_LANGUAGE "English" + + +Section "Quake II Shareware Demo" Section_Shareware + + SetOutPath "$INSTDIR\baseq2" + SetCompress AUTO + File "${SOURCE_DIR}\baseq2\shareware\pak0.pak" + +SectionEnd + +Section /o "Quake II Full Game" Section_FullGame + + CopyFiles "$FullGameDir\baseq2\pak*.pak" "$INSTDIR\baseq2" + CopyFiles "$FullGameDir\baseq2\players" "$INSTDIR\baseq2" + +SectionEnd + +!include "setup_gamefiles.nsh" + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${Section_Shareware} "Install a copy of the Quake II Shareware Demo" + !insertmacro MUI_DESCRIPTION_TEXT ${Section_FullGame} "Locate and copy the media files for the full game" +!insertmacro MUI_FUNCTION_DESCRIPTION_END \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 16a8e5124..6a19e0e8b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -87,8 +87,7 @@ SET(SRC_CLIENT client/download.c client/effects.c client/entities.c -# client/gtv.c -# client/http.c + client/gtv.c client/input.c client/keys.c client/locs.c @@ -110,7 +109,7 @@ SET(SRC_CLIENT client/ui/servers.c client/ui/ui.c client/sound/dma.c - #client/sound/al.c + client/sound/al.c client/sound/main.c client/sound/mem.c client/sound/mix.c @@ -118,6 +117,10 @@ SET(SRC_CLIENT client/sound/qal/dynamic.c ) +SET(SRC_CLIENT_HTTP + client/http.c +) + SET(HEADERS_CLIENT client/client.h client/ui/ui.h @@ -127,20 +130,19 @@ SET(HEADERS_CLIENT ) SET(SRC_SERVER -# server/ac.c server/commands.c server/entities.c server/game.c server/init.c server/main.c server/mvd.c - server/save.c server/send.c server/user.c server/world.c server/mvd/client.c server/mvd/parse.c server/mvd/game.c + server/save.c ) SET(HEADERS_SERVER @@ -180,8 +182,10 @@ SET(HEADERS_COMMON SET(SRC_REFRESH refresh/images.c refresh/models.c + refresh/stb/stb.c ) + SET(SRC_GL refresh/gl/draw.c refresh/gl/hq2x.c @@ -208,22 +212,37 @@ SET(SRC_SHARED shared/shared.c ) +SET(SRC_LINUX + unix/hunk.c + unix/system.c + unix/tty.c +) + +SET(SRC_LINUX_CLIENT + unix/sdl2/sound.c + unix/sdl2/video.c +) + SET(SRC_WINDOWS windows/ac.c -# windows/ascii.c -#windows/client.c windows/debug.c + windows/hunk.c + windows/system.c +) + +SET(SRC_WINDOWS_CLIENT + windows/wave.c + unix/sdl2/video.c +) + + #windows/ascii.c + #windows/client.c #windows/dinput.c #windows/dsound.c #windows/glimp.c - windows/hunk.c #windows/swimp.c - windows/system.c - windows/wave.c #windows/wgl.c #unix/sdl2/sound.c - unix/sdl2/video.c -) SET(HEADERS_WINDOWS windows/wgl.h @@ -234,90 +253,178 @@ SET(HEADERS_WINDOWS SET(SRC_VKPT refresh/vkpt/asvgf.c + refresh/vkpt/bloom.c refresh/vkpt/bsp_mesh.c refresh/vkpt/draw.c - refresh/vkpt/light_hierarchy.c refresh/vkpt/main.c + refresh/vkpt/material.c refresh/vkpt/matrix.c + refresh/vkpt/mgpu.c refresh/vkpt/models.c refresh/vkpt/path_tracer.c + refresh/vkpt/physical_sky.c + refresh/vkpt/precomputed_sky.c refresh/vkpt/profiler.c - refresh/vkpt/stb.c + refresh/vkpt/shadow_map.c refresh/vkpt/textures.c + refresh/vkpt/tone_mapping.c + refresh/vkpt/transparency.c refresh/vkpt/uniform_buffer.c refresh/vkpt/vertex_buffer.c refresh/vkpt/vk_util.c + refresh/vkpt/buddy_allocator.c + refresh/vkpt/device_memory_allocator.c + refresh/vkpt/god_rays.c ) SET(HEADERS_VKPT refresh/vkpt/vkpt.h refresh/vkpt/vk_util.h + refresh/vkpt/buddy_allocator.h + refresh/vkpt/device_memory_allocator.h + refresh/vkpt/material.h + refresh/vkpt/physical_sky.h + refresh/vkpt/precomputed_sky.h ) -SET(SRC_QBVH - common/qbvhmp.c - refresh/glpt/bvh.c - windows/threads/threads.c +set(SRC_SHADERS + refresh/vkpt/shader/animate_materials.comp + refresh/vkpt/shader/god_rays_filter.comp + refresh/vkpt/shader/god_rays.comp + refresh/vkpt/shader/bloom_composite.comp + refresh/vkpt/shader/bloom_blur.comp + refresh/vkpt/shader/primary_rays.rgen + refresh/vkpt/shader/direct_lighting.rgen + refresh/vkpt/shader/checkerboard_interleave.comp + refresh/vkpt/shader/indirect_lighting.rgen + refresh/vkpt/shader/path_tracer.rchit + refresh/vkpt/shader/path_tracer.rmiss + refresh/vkpt/shader/path_tracer_particle.rahit + refresh/vkpt/shader/path_tracer_sprite.rahit + refresh/vkpt/shader/path_tracer_beam.rahit + refresh/vkpt/shader/path_tracer_explosion.rahit + refresh/vkpt/shader/path_tracer_shadow.rmiss + refresh/vkpt/shader/asvgf_atrous.comp + refresh/vkpt/shader/asvgf_fwd_project.comp + refresh/vkpt/shader/asvgf_gradient_atrous.comp + refresh/vkpt/shader/asvgf_gradient_img.comp + refresh/vkpt/shader/asvgf_lf.comp + refresh/vkpt/shader/asvgf_seed_rng.comp + refresh/vkpt/shader/asvgf_taa.comp + refresh/vkpt/shader/asvgf_temporal.comp + refresh/vkpt/shader/instance_geometry.comp + refresh/vkpt/shader/tone_mapping_histogram.comp + refresh/vkpt/shader/tone_mapping_curve.comp + refresh/vkpt/shader/tone_mapping_apply.comp + refresh/vkpt/shader/physical_sky.comp + refresh/vkpt/shader/physical_sky_space.comp + refresh/vkpt/shader/shadow_map.vert + refresh/vkpt/shader/sky_buffer_resolve.comp + refresh/vkpt/shader/stretch_pic.frag + refresh/vkpt/shader/stretch_pic.vert + refresh/vkpt/shader/final_blit_lanczos.frag + refresh/vkpt/shader/final_blit.vert ) -SET(SRC_OPTIX - refresh/glpt/optix.c -) +include(../cmake/compileShaders.cmake) -FILE(GLOB SRC_SHADERS - refresh/vkpt/shader/*.vert - refresh/vkpt/shader/*.geom - refresh/vkpt/shader/*.frag - refresh/vkpt/shader/*.comp - refresh/vkpt/shader/*.glsl - refresh/vkpt/shader/*.h - refresh/vkpt/shader/*.rgen - refresh/vkpt/shader/*.rchit - refresh/vkpt/shader/*.rmiss -) +if (GLSLANG_COMPILER) + foreach(s ${SRC_SHADERS}) + compile_shader(SOURCE_FILE ${s} OUTPUT_FILE_LIST shader_bytecode) + endforeach() + + add_custom_target(shaders DEPENDS ${shader_bytecode}) +else() + message(WARNING "Could not find shader compiler: you're on your own to build the shaders") +endif() + +# Embed version number +ADD_DEFINITIONS(-DVERSION_MAJOR=${Q2RTX_VERSION_MAJOR}) +ADD_DEFINITIONS(-DVERSION_MINOR=${Q2RTX_VERSION_MINOR}) +ADD_DEFINITIONS(-DVERSION_POINT=${Q2RTX_VERSION_POINT}) +ADD_DEFINITIONS(-DVERSION_SHA=${Q2RTX_VERSION_SHA}) -ADD_DEFINITIONS(-DHAVE_CONFIG_H=1 -DUSE_SERVER=1 -DUSE_CLIENT=1 -DCURL_STATICLIB) +ADD_DEFINITIONS(-DHAVE_CONFIG_H=1 -DCURL_STATICLIB) + +IF(WIN32) + ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS) +ENDIF() ADD_LIBRARY(gamex86 SHARED ${SRC_BASEQ2} ${HEADERS_BASEQ2} ${SRC_SHARED}) +IF(WIN32) ADD_EXECUTABLE(client WIN32 ${SRC_CLIENT} ${HEADERS_CLIENT} ${SRC_COMMON} ${HEADERS_COMMON} ${SRC_REFRESH} ${SRC_SHADERS} ${SRC_SHARED} + ${SRC_WINDOWS} ${SRC_WINDOWS_CLIENT} ${HEADERS_WINDOWS} + ${SRC_SERVER} ${HEADERS_SERVER} + windows/res/q2rtx.rc +) +ADD_EXECUTABLE(server + ${SRC_COMMON} ${HEADERS_COMMON} + ${SRC_SHARED} ${SRC_WINDOWS} ${HEADERS_WINDOWS} ${SRC_SERVER} ${HEADERS_SERVER} + server/ac.c + client/null.c + windows/res/q2rtxded.rc ) +ELSE() +ADD_EXECUTABLE(client + ${SRC_CLIENT} ${HEADERS_CLIENT} + ${SRC_COMMON} ${HEADERS_COMMON} + ${SRC_REFRESH} ${SRC_SHADERS} + ${SRC_SHARED} + ${SRC_LINUX} ${SRC_LINUX_CLIENT} + ${SRC_SERVER} ${HEADERS_SERVER} +) +ADD_EXECUTABLE(server + ${SRC_COMMON} ${HEADERS_COMMON} + ${SRC_SHARED} + ${SRC_LINUX} + ${SRC_SERVER} ${HEADERS_SERVER} + server/ac.c + client/null.c +) +ENDIF() + +TARGET_COMPILE_DEFINITIONS(client PRIVATE USE_SERVER=1 USE_CLIENT=1) +TARGET_COMPILE_DEFINITIONS(server PRIVATE USE_SERVER=1 USE_CLIENT=0) + +IF(CONFIG_USE_CURL) + TARGET_SOURCES(client PRIVATE ${SRC_CLIENT_HTTP}) + TARGET_COMPILE_DEFINITIONS(client PRIVATE USE_CURL=1) + TARGET_LINK_LIBRARIES(client libcurl) +ENDIF() + +if (GLSLANG_COMPILER) + add_dependencies(client shaders) +endif() IF (CONFIG_GL_RENDERER) TARGET_SOURCES(client PRIVATE ${SRC_GL} ${HEADERS_GL}) - TARGET_COMPILE_DEFINITIONS(client PRIVATE REF_GL=1 USE_REF=1 VID_REF="gl") + TARGET_COMPILE_DEFINITIONS(client PRIVATE REF_GL=1 USE_REF=1) ENDIF() IF (CONFIG_VKPT_RENDERER) TARGET_SOURCES(client PRIVATE ${SRC_VKPT} ${HEADERS_VKPT}) TARGET_INCLUDE_DIRECTORIES(client PRIVATE refresh/vkpt/include) LINK_DIRECTORIES(client PRIVATE refresh/vkpt/include/vulkan) - TARGET_COMPILE_DEFINITIONS(client PRIVATE REF_VKPT=1 USE_REF=1 VID_REF="vkpt") + TARGET_COMPILE_DEFINITIONS(client PRIVATE REF_VKPT=1 USE_REF=1) + IF (CONFIG_VKPT_ENABLE_DEVICE_GROUPS) + TARGET_COMPILE_DEFINITIONS(client PRIVATE VKPT_DEVICE_GROUPS) + ENDIF() + if (CONFIG_VKPT_ENABLE_IMAGE_DUMPS) + TARGET_COMPILE_DEFINITIONS(client PRIVATE VKPT_IMAGE_DUMPS) + ENDIF() + IF (WIN32) TARGET_LINK_LIBRARIES(client vulkan-1) + ELSE () + TARGET_LINK_LIBRARIES(client vulkan) + ENDIF() ENDIF() -#IF (CONFIG_USE_OPTIX) -# TARGET_COMPILE_DEFINITIONS(client PRIVATE USE_OPTIX=1) -# FIND_PACKAGE(CUDA REQUIRED) -# GET_FILENAME_COMPONENT(CUDA_LIB_DIR ${CUDA_LIBRARIES} DIRECTORY) -# TARGET_LINK_LIBRARIES(client ${CUDA_LIB_DIR}/cuda.lib ${CONFIG_OPTIX_DIR}/lib64/optix_prime.1.lib) -# TARGET_INCLUDE_DIRECTORIES(client PRIVATE ${CUDA_INCLUDE_DIRS} ${CONFIG_OPTIX_DIR}/include) -# TARGET_SOURCES(client PRIVATE ${SRC_OPTIX}) -#ELSE() -# TARGET_COMPILE_DEFINITIONS(client PRIVATE ACCEL_NO_VLA=1) -# TARGET_SOURCES(client PRIVATE ${SRC_QBVH}) -# IF (WIN32) -# TARGET_INCLUDE_DIRECTORIES(client PRIVATE windows/threads) -# ELSE() -# TARGET_INCLUDE_DIRECTORIES(client PRIVATE unix/threads) -# ENDIF() -#ENDIF() - SOURCE_GROUP("baseq2\\sources" FILES ${SRC_BASEQ2}) SOURCE_GROUP("baseq2\\headers" FILES ${HEADERS_BASEQ2}) SOURCE_GROUP("client\\sources" FILES ${SRC_CLIENT}) @@ -335,39 +442,140 @@ SOURCE_GROUP("windows\\headers" FILES ${HEADERS_WINDOWS}) IF (WIN32) TARGET_INCLUDE_DIRECTORIES(client PRIVATE ../VC/inc) + TARGET_INCLUDE_DIRECTORIES(server PRIVATE ../VC/inc) TARGET_INCLUDE_DIRECTORIES(gamex86 PRIVATE ../VC/inc) + TARGET_SOURCES(gamex86 PRIVATE windows/res/baseq2.rc) TARGET_LINK_LIBRARIES(client winmm ws2_32) + TARGET_LINK_LIBRARIES(server winmm ws2_32) set_target_properties(client PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") + set_target_properties(server PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") + + # macro redefinition, deprecation + target_compile_options(client PRIVATE /wd4005 /wd4996) + target_compile_options(server PRIVATE /wd4005 /wd4996) + target_compile_options(gamex86 PRIVATE /wd4005 /wd4996) ENDIF() TARGET_INCLUDE_DIRECTORIES(gamex86 PRIVATE ../inc) TARGET_INCLUDE_DIRECTORIES(client PRIVATE ../inc) TARGET_INCLUDE_DIRECTORIES(client PRIVATE "${ZLIB_INCLUDE_DIRS}") - -TARGET_LINK_LIBRARIES(client PNG::png) -TARGET_LINK_LIBRARIES(client JPEG::jpeg) -TARGET_LINK_LIBRARIES(client SDL2::SDL2main SDL2::SDL2) +TARGET_INCLUDE_DIRECTORIES(server PRIVATE ../inc) +TARGET_INCLUDE_DIRECTORIES(server PRIVATE "${ZLIB_INCLUDE_DIRS}") + +# Use dynamic zlib for steam runtime +if (CONFIG_LINUX_STEAM_RUNTIME_SUPPORT) + TARGET_LINK_LIBRARIES(client SDL2main SDL2-static z) + TARGET_LINK_LIBRARIES(server SDL2main SDL2-static z) +else() + TARGET_LINK_LIBRARIES(client SDL2main SDL2-static zlibstatic) + TARGET_LINK_LIBRARIES(server SDL2main SDL2-static zlibstatic) +endif() SET_TARGET_PROPERTIES(client PROPERTIES + OUTPUT_NAME "q2rtx" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}" RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_SOURCE_DIR}" RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_SOURCE_DIR}" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_SOURCE_DIR}" DEBUG_POSTFIX "" ) +SET_TARGET_PROPERTIES(server + PROPERTIES + OUTPUT_NAME "q2rtxded" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_SOURCE_DIR}" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_SOURCE_DIR}" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_SOURCE_DIR}" + DEBUG_POSTFIX "" +) + +# specify both LIBRARY and RUNTIME because one works only on Windows and another works only on Linux + SET_TARGET_PROPERTIES(gamex86 PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/baseq2" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}/baseq2" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_SOURCE_DIR}/baseq2" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_SOURCE_DIR}/baseq2" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_SOURCE_DIR}/baseq2" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/baseq2" RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_SOURCE_DIR}/baseq2" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_SOURCE_DIR}/baseq2" RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_SOURCE_DIR}/baseq2" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_SOURCE_DIR}/baseq2" + PREFIX "" DEBUG_POSTFIX "" ) IF(IS_64_BIT) SET_TARGET_PROPERTIES(gamex86 PROPERTIES + LIBRARY_OUTPUT_NAME "gamex86_64" RUNTIME_OUTPUT_NAME "gamex86_64" ) ENDIF() + +IF(CONFIG_LINUX_PACKAGING_SUPPORT) + # Put the real game binary in /usr/share so we can have a wrapper in /usr/bin + INSTALL(TARGETS client DESTINATION share/quake2rtx/bin COMPONENT shareware) + INSTALL(TARGETS server DESTINATION games COMPONENT shareware) + + # Compress NVIDIA custom content + INSTALL(CODE "set(SOURCE \"${CMAKE_SOURCE_DIR}\")" + SCRIPT "${CMAKE_SOURCE_DIR}/setup/package_media.cmake" + SCRIPT "${CMAKE_SOURCE_DIR}/setup/package_shaders.cmake" + COMPONENT shareware) + INSTALL(TARGETS gamex86 DESTINATION share/quake2rtx/baseq2 COMPONENT shareware) + + # Package data files, including the shareware pak0 for demo levels + set (SHAREWARE_DATA_FILES_LIST + "${CMAKE_SOURCE_DIR}/baseq2/q2rtx_media.pkz" + "${CMAKE_SOURCE_DIR}/baseq2/shaders.pkz" + "${CMAKE_SOURCE_DIR}/baseq2/blue_noise.pkz" + "${CMAKE_SOURCE_DIR}/baseq2/shareware/pak0.pak" + ) + INSTALL(FILES + ${SHAREWARE_DATA_FILES_LIST} + DESTINATION share/quake2rtx/baseq2 + COMPONENT shareware) + + # Package the legal files + INSTALL(FILES + "${CMAKE_SOURCE_DIR}/license.txt" + "${CMAKE_SOURCE_DIR}/notice.txt" + "${CMAKE_SOURCE_DIR}/readme.md" + DESTINATION share/quake2rtx/ + COMPONENT shareware) + + # Package the icon/desktop file + INSTALL(FILES + "${CMAKE_SOURCE_DIR}/setup/q2rtx.desktop" + DESTINATION share/applications/ + COMPONENT shareware) + INSTALL(FILES + "${CMAKE_SOURCE_DIR}/setup/q2rtx.png" + DESTINATION share/pixmaps/ + COMPONENT shareware) + + # Install Client Wrapper + INSTALL(FILES + "${CMAKE_SOURCE_DIR}/setup/q2rtx.sh" + DESTINATION games/ + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + COMPONENT shareware + RENAME q2rtx) + + # Install PAK file finder + INSTALL(FILES + "${CMAKE_SOURCE_DIR}/setup/find-retail-paks.sh" + DESTINATION share/quake2rtx/bin + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + COMPONENT shareware) +ENDIF() diff --git a/src/baseq2/g_items.c b/src/baseq2/g_items.c index 78b4ad186..221b50106 100644 --- a/src/baseq2/g_items.c +++ b/src/baseq2/g_items.c @@ -33,6 +33,7 @@ void Weapon_Grenade(edict_t *ent); void Weapon_GrenadeLauncher(edict_t *ent); void Weapon_Railgun(edict_t *ent); void Weapon_BFG(edict_t *ent); +void Weapon_FlareGun(edict_t *ent); gitem_armor_t jacketarmor_info = { 25, 50, .30, .00, ARMOR_JACKET}; gitem_armor_t combatarmor_info = { 50, 100, .60, .30, ARMOR_COMBAT}; @@ -1466,6 +1467,28 @@ gitem_t itemlist[] = { /* precache */ "sprites/s_bfg1.sp2 sprites/s_bfg2.sp2 sprites/s_bfg3.sp2 weapons/bfg__f1y.wav weapons/bfg__l1a.wav weapons/bfg__x1b.wav weapons/bfg_hum.wav" }, + /*QUAKED weapon_flaregun (.3 .3 1) (-16 -16 -16) (16 16 16)*/ + { + "weapon_flaregun", // class name + Pickup_Weapon, // Function to use to pickup weapon + Use_Weapon, // Function to use to use weapon + Drop_Weapon, // Function to use to drop weapon + Weapon_FlareGun, // Function called every frame this weapon is active + "misc/w_pkup.wav",// Sound to play when picked up + "models/weapons/g_flareg/tris.md2", // Item model for placement on maps + EF_ROTATE,//Flags + "models/weapons/v_flareg/tris.md3",//Model player sees + "w_flareg", //name of item icon in item list (minus .pcx) + "Flare Gun", //Item name (ie use flare gun) + 0, // Count width (for timed things like quad) + 1, // Ammo per shot + "Grenades", // Type of ammo to use + IT_WEAPON, // IT_WEAPON, IT_ARMOR, or IT_AMMO + WEAP_FLAREGUN, + NULL, // userinfo? (void*) + 0, // tag + "" //things to precache + }, // // AMMO ITEMS // diff --git a/src/baseq2/g_local.h b/src/baseq2/g_local.h index 2bf70a8dc..a83f329b5 100644 --- a/src/baseq2/g_local.h +++ b/src/baseq2/g_local.h @@ -227,6 +227,7 @@ typedef struct { #define WEAP_HYPERBLASTER 9 #define WEAP_RAILGUN 10 #define WEAP_BFG 11 +#define WEAP_FLAREGUN 12 typedef struct gitem_s { char *classname; // spawning name @@ -515,6 +516,7 @@ extern cvar_t *spectator_password; extern cvar_t *needpass; extern cvar_t *g_select_empty; extern cvar_t *dedicated; +extern cvar_t *nomonsters; extern cvar_t *filterban; @@ -543,6 +545,8 @@ extern cvar_t *sv_maplist; extern cvar_t *sv_features; +extern cvar_t *sv_flaregun; + #define world (&g_edicts[0]) // item spawnflags diff --git a/src/baseq2/g_main.c b/src/baseq2/g_main.c index 9becd8c44..31ce734d2 100644 --- a/src/baseq2/g_main.c +++ b/src/baseq2/g_main.c @@ -44,6 +44,7 @@ cvar_t *maxspectators; cvar_t *maxentities; cvar_t *g_select_empty; cvar_t *dedicated; +cvar_t *nomonsters; cvar_t *filterban; @@ -72,6 +73,8 @@ cvar_t *sv_maplist; cvar_t *sv_features; +cvar_t *sv_flaregun; + void SpawnEntities(const char *mapname, const char *entities, const char *spawnpoint); void ClientThink(edict_t *ent, usercmd_t *cmd); qboolean ClientConnect(edict_t *ent, char *userinfo); @@ -125,6 +128,8 @@ void InitGame(void) // noset vars dedicated = gi.cvar("dedicated", "0", CVAR_NOSET); + nomonsters = gi.cvar("nomonsters", "0", 0); + // latched vars sv_cheats = gi.cvar("cheats", "0", CVAR_SERVERINFO | CVAR_LATCH); gi.cvar("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH); @@ -165,6 +170,12 @@ void InitGame(void) // obtain server features sv_features = gi.cvar("sv_features", NULL, 0); + // flare gun switch: + // 0 = no flare gun + // 1 = spawn with the flare gun + // 2 = spawn with the flare gun and some grenades + sv_flaregun = gi.cvar("sv_flaregun", "2", 0); + // export our own features gi.cvar_forceset("g_features", va("%d", G_FEATURES)); diff --git a/src/baseq2/g_ptrs.c b/src/baseq2/g_ptrs.c index e0cbb1b48..29bd80c71 100644 --- a/src/baseq2/g_ptrs.c +++ b/src/baseq2/g_ptrs.c @@ -614,6 +614,8 @@ extern void door_secret_move1(void); extern void door_secret_move3(void); extern void door_secret_move5(void); extern void door_secret_done(void); +extern void flare_think(void); // Q2RTX +extern void flare_touch(void); // Q2RTX const save_ptr_t save_ptrs[] = { { P_blocked, door_blocked }, { P_blocked, door_secret_blocked }, @@ -1144,6 +1146,8 @@ const save_ptr_t save_ptrs[] = { { P_think, turret_driver_link }, { P_think, turret_driver_think }, { P_think, walkmonster_start_go }, +{ P_think, flare_think }, // Q2RTX +{ P_touch, flare_touch }, // Q2RTX { P_touch, barrel_touch }, { P_touch, bfg_touch }, { P_touch, blaster_touch }, diff --git a/src/baseq2/g_spawn.c b/src/baseq2/g_spawn.c index cb83ed541..8c7eb3bef 100644 --- a/src/baseq2/g_spawn.c +++ b/src/baseq2/g_spawn.c @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -618,6 +619,11 @@ void SpawnEntities(const char *mapname, const char *entities, const char *spawnp // remove things (except the world) from different skill levels or deathmatch if (ent != g_edicts) { + if (nomonsters->value && strstr(ent->classname, "monster")) { + G_FreeEdict(ent); + inhibit++; + continue; + } if (deathmatch->value) { if (ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH) { G_FreeEdict(ent); diff --git a/src/baseq2/g_weapon.c b/src/baseq2/g_weapon.c index 1dc5c6861..eeabc7c97 100644 --- a/src/baseq2/g_weapon.c +++ b/src/baseq2/g_weapon.c @@ -862,3 +862,128 @@ void fire_bfg(edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, fl gi.linkentity(bfg); } + +/* + * Drops a spark from the flare flying thru the air. Checks to make + * sure we aren't in the water. + */ +void flare_sparks(edict_t *self) +{ + vec3_t dir; + vec3_t forward, right, up; + // Spawn some sparks. This isn't net-friendly at all, but will + // be fine for single player. + // + gi.WriteByte(svc_temp_entity); + gi.WriteByte(TE_FLARE); + + gi.WriteShort(self - g_edicts); + // if this is the first tick of flare, set count to 1 to start the sound + gi.WriteByte( self->timestamp - level.time < 14.75 ? 0 : 1); + + gi.WritePosition(self->s.origin); + + // If we are still moving, calculate the normal to the direction + // we are travelling. + // + if (VectorLength(self->velocity) > 0.0) + { + vectoangles(self->velocity, dir); + AngleVectors(dir, forward, right, up); + + gi.WriteDir(up); + } + // If we're stopped, just write out the origin as our normal + // + else + { + gi.WriteDir(vec3_origin); + } + gi.multicast(self->s.origin, MULTICAST_PVS); +} + +/* + void flare_think( edict_t *self ) + + Purpose: The think function of a flare round. It generates sparks + on the flare using a temp entity, and kills itself after + self->timestamp runs out. + Parameters: + self: A pointer to the edict_t structure representing the + flare round. self->timestamp is the value used to + measure the lifespan of the round, and is set in + fire_flaregun blow. + + Notes: + - I'm not sure how much bandwidth is eaten by spawning a temp + entity every FRAMETIME seconds. It might very well turn out + that the sparks need to go bye-bye in favor of less bandwidth + usage. Then again, why the hell would you use this gun on + a DM server???? + + - I haven't seen self->timestamp used anywhere else in the code, + but I never really looked that hard. It doesn't seem to cause + any problems, and is aptly named, so I used it. + */ +void flare_think(edict_t *self) +{ + // self->timestamp is 15 seconds after the flare was spawned. + // + if (level.time > self->timestamp) + { + G_FreeEdict(self); + return; + } + + // We're still active, so lets shoot some sparks. + // + flare_sparks(self); + + // We'll think again in .2 seconds + // + self->nextthink = level.time + 0.2; +} + +void flare_touch(edict_t *ent, edict_t *other, + cplane_t *plane, csurface_t *surf) +{ + // Flares don't weigh that much, so let's have them stop + // the instant they whack into anything. + // + VectorClear(ent->velocity); +} + +void fire_flaregun(edict_t *self, vec3_t start, vec3_t aimdir, + int damage, int speed, float timer, + float damage_radius) +{ + edict_t *flare; + vec3_t dir; + vec3_t forward, right, up; + + vectoangles(aimdir, dir); + AngleVectors(dir, forward, right, up); + + flare = G_Spawn(); + VectorCopy(start, flare->s.origin); + VectorScale(aimdir, speed, flare->velocity); + VectorSet(flare->avelocity, 300, 300, 300); + flare->movetype = MOVETYPE_BOUNCE; + flare->clipmask = MASK_SHOT; + flare->solid = SOLID_BBOX; + + const float size = 4; + VectorSet(flare->mins, -size, -size, -size); + VectorSet(flare->maxs, size, size, size); + + flare->s.modelindex = gi.modelindex("models/objects/flare/tris.md2"); + flare->owner = self; + flare->touch = flare_touch; + flare->nextthink = FRAMETIME; + flare->think = flare_think; + flare->radius_dmg = damage; + flare->dmg_radius = damage_radius; + flare->classname = "flare"; + flare->timestamp = level.time + 15.0; //live for 15 seconds + gi.linkentity(flare); +} \ No newline at end of file diff --git a/src/baseq2/p_client.c b/src/baseq2/p_client.c index 0fa8890db..2fb84bb7d 100644 --- a/src/baseq2/p_client.c +++ b/src/baseq2/p_client.c @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -573,15 +574,32 @@ but is called after each death and level change in deathmatch */ void InitClientPersistant(gclient_t *client) { - gitem_t *item; + gitem_t *item; + + memset(&client->pers, 0, sizeof(client->pers)); + + item = FindItem("Blaster"); + client->pers.selected_item = ITEM_INDEX(item); + client->pers.inventory[client->pers.selected_item] = 1; - memset(&client->pers, 0, sizeof(client->pers)); + client->pers.weapon = item; - item = FindItem("Blaster"); - client->pers.selected_item = ITEM_INDEX(item); - client->pers.inventory[client->pers.selected_item] = 1; + if (sv_flaregun->integer > 0) + { + // Q2RTX: Spawn with a flare gun and some grenades to use with it. + // Flare gun is new and not found anywhere in the game as a pickup item. + gitem_t* item_flareg = FindItem("Flare Gun"); + if (item_flareg) + { + client->pers.inventory[ITEM_INDEX(item_flareg)] = 1; - client->pers.weapon = item; + if (sv_flaregun->integer == 2) + { + gitem_t* item_grenades = FindItem("Grenades"); + client->pers.inventory[ITEM_INDEX(item_grenades)] = 5; + } + } + } client->pers.health = 100; client->pers.max_health = 100; @@ -1079,7 +1097,7 @@ void PutClientInServer(edict_t *ent) memcpy(userinfo, client->pers.userinfo, sizeof(userinfo)); InitClientPersistant(client); ClientUserinfoChanged(ent, userinfo); - } else if (coop->value) { + } else { // int n; char userinfo[MAX_INFO_STRING]; @@ -1097,9 +1115,7 @@ void PutClientInServer(edict_t *ent) ClientUserinfoChanged(ent, userinfo); if (resp.score > client->pers.score) client->pers.score = resp.score; - } else { - memset(&resp, 0, sizeof(resp)); - } + } // clear everything but the persistant data saved = client->pers; diff --git a/src/baseq2/p_view.c b/src/baseq2/p_view.c index 260211c16..08e65597a 100644 --- a/src/baseq2/p_view.c +++ b/src/baseq2/p_view.c @@ -411,7 +411,8 @@ void SV_CalcBlend(edict_t *ent) // add for contents VectorAdd(ent->s.origin, ent->client->ps.viewoffset, vieworg); contents = gi.pointcontents(vieworg); - if (contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) + + if (contents & (CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA)) ent->client->ps.rdflags |= RDF_UNDERWATER; else ent->client->ps.rdflags &= ~RDF_UNDERWATER; @@ -766,8 +767,8 @@ void G_SetClientSound(edict_t *ent) ent->client->pers.helpchanged = 1; } - // help beep (no more than three times) - if (ent->client->pers.helpchanged && ent->client->pers.helpchanged <= 3 && !(level.framenum & 63)) { + // help beep (no more than ONE time - that's annoying enough) + if (ent->client->pers.helpchanged && ent->client->pers.helpchanged <= 1 && !(level.framenum & 63)) { ent->client->pers.helpchanged++; gi.sound(ent, CHAN_VOICE, gi.soundindex("misc/pc_up.wav"), 1, ATTN_STATIC, 0); } diff --git a/src/baseq2/p_weapon.c b/src/baseq2/p_weapon.c index 11f716ac0..7c4b872bd 100644 --- a/src/baseq2/p_weapon.c +++ b/src/baseq2/p_weapon.c @@ -1301,3 +1301,74 @@ void Weapon_BFG(edict_t *ent) //====================================================================== + +/* + * Forward declaration for fire_flaregun(), which is defined in + * g_weapon.c. + */ +void fire_flaregun(edict_t *self, vec3_t start, vec3_t aimdir, int damage, + int speed, float timer, float damage_radius); +/* + * weapon_flaregun_fire (edict_t *ent) + * + * Basically used to wrap the call to fire_flaregun(), this function + * calculates all the parameters needed by fire_flaregun. Calls + * fire_flaregun and then subtracts 1 from the firing entity's + * cell stash. + */ +void weapon_flaregun_fire(edict_t *ent) +{ + vec3_t offset; + vec3_t forward, right; + vec3_t start; + + // Setup the parameters used in the call to fire_flaregun() + // + VectorSet(offset, 8, 8, ent->viewheight - 8); + AngleVectors(ent->client->v_angle, forward, right, NULL); + P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start); + + VectorScale(forward, -2, ent->client->kick_origin); + ent->client->kick_angles[0] = -1; + + // Make the flaregun actually shoot the flare + // + fire_flaregun(ent, start, forward, 0, 800, 25, 0); + + gi.WriteByte(svc_muzzleflash); + gi.WriteShort(ent - g_edicts); + gi.WriteByte(MZ_FLARE | is_silenced); + gi.multicast(ent->s.origin, MULTICAST_PVS); + + // Bump the gunframe + // + ent->client->ps.gunframe++; + + PlayerNoise(ent, start, PNOISE_WEAPON); + + // Subtract one cell from our inventory + // + ent->client->pers.inventory[ent->client->ammo_index]--; +} + +/* + * Weapon_FlareGun (edict_t *ent) + * + * This is the function that is referenced in the itemlist structure + * defined in g_items.c. It is called every frame when our weapon is + * active. It calls Weapon_Generic() to handle per-frame weapon + * handling (like animation and stuff). Haven't delved too deeply + * into Weapon_Generic()'s responsiblities... if someone has insight + * drop me a line :) + */ +void Weapon_FlareGun(edict_t *ent) +{ + static int pause_frames[] = { 39, 45, 50, 53, 0 }; + static int fire_frames[] = { 9, 17, 0 }; + // Check the top of p_weapon.c for definition of Weapon_Generic + // + Weapon_Generic(ent, 8, 13, 49, 53, + pause_frames, + fire_frames, + weapon_flaregun_fire); +} \ No newline at end of file diff --git a/src/client/client.h b/src/client/client.h index 9f084c642..358c06254 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -55,6 +55,33 @@ with this program; if not, write to the Free Software Foundation, Inc., //============================================================================= +#define MAX_EXPLOSIONS 32 + +typedef struct { + enum { + ex_free, + ex_explosion, + ex_misc, + ex_flash, + ex_mflash, + ex_poly, + ex_poly2, + ex_light, + ex_blaster, + ex_flare + } type; + + entity_t ent; + int frames; + float light; + vec3_t lightcolor; + float start; + int baseframe; + int frametime; /* in milliseconds */ +} explosion_t; + +extern explosion_t cl_explosions[MAX_EXPLOSIONS]; + typedef struct centity_s { entity_state_t current; entity_state_t prev; // will always be valid, but might just be a copy of current @@ -510,6 +537,8 @@ extern cvar_t *cl_vwep; extern cvar_t *cl_disable_particles; extern cvar_t *cl_disable_explosions; +extern cvar_t *cl_explosion_sprites; +extern cvar_t *cl_explosion_frametime; extern cvar_t *cl_chat_notify; extern cvar_t *cl_chat_sound; @@ -521,7 +550,12 @@ extern cvar_t *cl_beginmapcmd; extern cvar_t *cl_gibs; -extern cvar_t *cl_thirdperson; +#define CL_PLAYER_MODEL_DISABLED 0 +#define CL_PLAYER_MODEL_ONLY_GUN 1 +#define CL_PLAYER_MODEL_FIRST_PERSON 2 +#define CL_PLAYER_MODEL_THIRD_PERSON 3 + +extern cvar_t *cl_player_model; extern cvar_t *cl_thirdperson_angle; extern cvar_t *cl_thirdperson_range; @@ -562,6 +596,7 @@ const char *CL_Server_g(const char *partial, int argnum, int state); void CL_CheckForPause(void); void CL_UpdateFrameTimes(void); qboolean CL_CheckForIgnore(const char *s); +void CL_WriteConfig(void); // @@ -688,8 +723,10 @@ void V_AddEntity(entity_t *ent); void V_AddParticle(particle_t *p); #if USE_DLIGHTS void V_AddLight(vec3_t org, float intensity, float r, float g, float b); +void V_AddLightEx(vec3_t org, float intensity, float r, float g, float b, float radius); #else #define V_AddLight(org, intensity, r, g, b) +#define V_AddLightEx(org, intensity, r, g, b, radius) #endif #if USE_LIGHTSTYLES void V_AddLightStyle(int style, vec4_t value); @@ -736,7 +773,7 @@ void CL_CheckPredictionError(void); // // effects.c // -#define PARTICLE_GRAVITY 40 +#define PARTICLE_GRAVITY 120 #define BLASTER_PARTICLE_COLOR 0xe0 #define INSTANT_PARTICLE -10000.0 @@ -752,6 +789,7 @@ typedef struct cparticle_s { float alpha; float alphavel; color_t rgba; + float brightness; } cparticle_t; #if USE_DLIGHTS @@ -761,7 +799,8 @@ typedef struct cdlight_s { vec3_t origin; float radius; float die; // stop lighting after this time - //float decay; // drop this each second + float decay; // drop this each second + vec3_t velosity; // move this far each second //float minlight; // don't add when contributing less } cdlight_t; #endif @@ -787,6 +826,7 @@ void CL_MuzzleFlash2(void); void CL_TeleporterParticles(vec3_t org); void CL_TeleportParticles(vec3_t org); void CL_ParticleEffect(vec3_t org, vec3_t dir, int color, int count); +void CL_ParticleEffectWaterSplash(vec3_t org, vec3_t dir, int color, int count); void CL_BloodParticleEffect(vec3_t org, vec3_t dir, int color, int count); void CL_ParticleEffect2(vec3_t org, vec3_t dir, int color, int count); cparticle_t *CL_AllocParticle(void); @@ -917,6 +957,8 @@ void SCR_ModeChanged(void); void SCR_LagSample(void); void SCR_LagClear(void); void SCR_SetCrosshairColor(void); +qhandle_t SCR_GetFont(void); +void SCR_SetHudAlpha(float alpha); float SCR_FadeAlpha(unsigned startTime, unsigned visTime, unsigned fadeTime); int SCR_DrawStringEx(int x, int y, int flags, size_t maxlen, const char *s, qhandle_t font); @@ -983,3 +1025,11 @@ void CL_GTV_Shutdown(void); // crc.c // byte COM_BlockSequenceCRCByte(byte *base, size_t length, int sequence); + +// +// effects.c +// +void FX_Init(void); + +// RTX development feature that loads and spawns a set of material sample balls +#define CL_RTX_SHADERBALLS 0 \ No newline at end of file diff --git a/src/client/console.c b/src/client/console.c index cbaebf337..9303342c6 100644 --- a/src/client/console.c +++ b/src/client/console.c @@ -629,24 +629,24 @@ void Con_RegisterMedia(void) { qerror_t err; - con.charsetImage = R_RegisterImage(con_font->string, IT_FONT, IF_PERMANENT, &err); + con.charsetImage = R_RegisterImage(con_font->string, IT_FONT, IF_PERMANENT | IF_SRGB, &err); if (!con.charsetImage) { if (strcmp(con_font->string, "conchars")) { Com_WPrintf("Couldn't load %s: %s\n", con_font->string, Q_ErrorString(err)); Cvar_Reset(con_font); - con.charsetImage = R_RegisterImage("conchars", IT_FONT, IF_PERMANENT, &err); + con.charsetImage = R_RegisterImage("conchars", IT_FONT, IF_PERMANENT | IF_SRGB, &err); } if (!con.charsetImage) { Com_Error(ERR_FATAL, "Couldn't load pics/conchars.pcx: %s", Q_ErrorString(err)); } } - con.backImage = R_RegisterImage(con_background->string, IT_PIC, IF_PERMANENT, &err); + con.backImage = R_RegisterImage(con_background->string, IT_PIC, IF_PERMANENT | IF_SRGB, &err); if (!con.backImage) { if (strcmp(con_background->string, "conback")) { Com_WPrintf("Couldn't load %s: %s\n", con_background->string, Q_ErrorString(err)); Cvar_Reset(con_background); - con.backImage = R_RegisterImage("conback", IT_PIC, IF_PERMANENT, &err); + con.backImage = R_RegisterImage("conback", IT_PIC, IF_PERMANENT | IF_SRGB, &err); } if (!con.backImage) { Com_EPrintf("Couldn't load pics/conback.pcx: %s\n", Q_ErrorString(err)); @@ -938,7 +938,7 @@ static void Con_DrawSolidConsole(void) UI_DRAWCURSOR, con.charsetImage); } -#define APP_VERSION APPLICATION " " VERSION +#define APP_VERSION APPLICATION " " VERSION_STRING #define VER_WIDTH ((int)(sizeof(APP_VERSION) + 1) * CHAR_WIDTH) y = vislines - CON_PRESTEP + CHAR_HEIGHT; diff --git a/src/client/effects.c b/src/client/effects.c index bf8bbd190..df26a59b0 100644 --- a/src/client/effects.c +++ b/src/client/effects.c @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -215,11 +216,12 @@ void CL_RunDLights(void) dl->radius = 0; return; } -#if 0 - dl->radius -= cls.frametime * dl->decay; + + dl->radius -= cls.frametime * dl->decay; if (dl->radius < 0) dl->radius = 0; -#endif + + VectorMA(dl->origin, cls.frametime, dl->velosity, dl->origin); } } @@ -365,8 +367,7 @@ void CL_MuzzleFlash(void) case MZ_BFG: DL_COLOR(0, 1, 0); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0); - break; - + break; case MZ_LOGIN: DL_COLOR(0, 1, 0); DL_DIE(1.0); @@ -432,8 +433,21 @@ void CL_MuzzleFlash(void) case MZ_NUKE8: DL_COLOR(0, 1, 1); DL_DIE(100); - break; - } + break; + + // Q2RTX + case MZ_FLARE: + DL_RADIUS(0); + S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("weapons/flaregun.wav"), volume, ATTN_NORM, 0); + break; + // Q2RTX + } + + if (vid_rtx->integer) + { + // don't add muzzle flashes in RTX mode + DL_RADIUS(0.f); + } } @@ -484,7 +498,7 @@ void CL_MuzzleFlash2(void) case MZ2_INFANTRY_MACHINEGUN_12: case MZ2_INFANTRY_MACHINEGUN_13: DL_COLOR(1, 1, 0); - CL_ParticleEffect(origin, vec3_origin, 0, 40); + CL_ParticleEffect(origin, forward, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0); break; @@ -498,7 +512,7 @@ void CL_MuzzleFlash2(void) case MZ2_SOLDIER_MACHINEGUN_7: case MZ2_SOLDIER_MACHINEGUN_8: DL_COLOR(1, 1, 0); - CL_ParticleEffect(origin, vec3_origin, 0, 40); + CL_ParticleEffect(origin, forward, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0); break; @@ -512,7 +526,7 @@ void CL_MuzzleFlash2(void) case MZ2_GUNNER_MACHINEGUN_7: case MZ2_GUNNER_MACHINEGUN_8: DL_COLOR(1, 1, 0); - CL_ParticleEffect(origin, vec3_origin, 0, 40); + CL_ParticleEffect(origin, forward, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0); break; @@ -526,7 +540,7 @@ void CL_MuzzleFlash2(void) case MZ2_SUPERTANK_MACHINEGUN_6: case MZ2_TURRET_MACHINEGUN: DL_COLOR(1, 1, 0); - CL_ParticleEffect(origin, vec3_origin, 0, 40); + CL_ParticleEffect(origin, forward, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0); break; @@ -539,7 +553,7 @@ void CL_MuzzleFlash2(void) case MZ2_CARRIER_MACHINEGUN_L1: case MZ2_CARRIER_MACHINEGUN_L2: DL_COLOR(1, 1, 0); - CL_ParticleEffect(origin, vec3_origin, 0, 40); + CL_ParticleEffect(origin, forward, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0); break; @@ -618,7 +632,7 @@ void CL_MuzzleFlash2(void) case MZ2_TANK_MACHINEGUN_18: case MZ2_TANK_MACHINEGUN_19: DL_COLOR(1, 1, 0); - CL_ParticleEffect(origin, vec3_origin, 0, 40); + CL_ParticleEffect(origin, forward, 0, 40); CL_SmokeAndFlash(origin); Q_snprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound(soundname), 1, ATTN_NORM, 0); @@ -699,7 +713,7 @@ void CL_MuzzleFlash2(void) case MZ2_JORG_MACHINEGUN_L5: case MZ2_JORG_MACHINEGUN_L6: DL_COLOR(1, 1, 0); - CL_ParticleEffect(origin, vec3_origin, 0, 40); + CL_ParticleEffect(origin, forward, 0, 40); CL_SmokeAndFlash(origin); S_StartSound(NULL, mz.entity, CHAN_WEAPON, S_RegisterSound("boss3/xfiref.wav"), 1, ATTN_NORM, 0); break; @@ -711,7 +725,7 @@ void CL_MuzzleFlash2(void) case MZ2_JORG_MACHINEGUN_R5: case MZ2_JORG_MACHINEGUN_R6: DL_COLOR(1, 1, 0); - CL_ParticleEffect(origin, vec3_origin, 0, 40); + CL_ParticleEffect(origin, forward, 0, 40); CL_SmokeAndFlash(origin); break; @@ -727,7 +741,7 @@ void CL_MuzzleFlash2(void) case MZ2_CARRIER_MACHINEGUN_R1: case MZ2_CARRIER_MACHINEGUN_R2: DL_COLOR(1, 1, 0); - CL_ParticleEffect(origin, vec3_origin, 0, 40); + CL_ParticleEffect(origin, forward, 0, 40); CL_SmokeAndFlash(origin); break; @@ -816,6 +830,17 @@ static cparticle_t *active_particles, *free_particles; static cparticle_t particles[MAX_PARTICLES]; static const int cl_numparticles = MAX_PARTICLES; +extern uint32_t d_8to24table[256]; + +cvar_t* cvar_pt_particle_emissive = NULL; +static cvar_t* cl_particle_num_factor = NULL; + +void FX_Init(void) +{ + cvar_pt_particle_emissive = Cvar_Get("pt_particle_emissive", "10.0", 0); + cl_particle_num_factor = Cvar_Get("cl_particle_num_factor", "1", 0); +} + static void CL_ClearParticles(void) { int i; @@ -851,23 +876,124 @@ Wall impact puffs */ void CL_ParticleEffect(vec3_t org, vec3_t dir, int color, int count) { - int i, j; - cparticle_t *p; - float d; + vec3_t oy; + VectorSet(oy, 0.0f, 1.0f, 0.0f); + if (fabs(DotProduct(oy, dir)) > 0.95f) + VectorSet(oy, 1.0f, 0.0f, 0.0f); - for (i = 0; i < count; i++) { - p = CL_AllocParticle(); + vec3_t ox; + CrossProduct(oy, dir, ox); + + count *= cl_particle_num_factor->value; + const int spark_count = count / 10; + + const float dirt_horizontal_spread = 2.0f; + const float dirt_vertical_spread = 1.0f; + const float dirt_base_velocity = 40.0f; + const float dirt_rand_velocity = 70.0f; + + const float spark_horizontal_spread = 1.0f; + const float spark_vertical_spread = 1.0f; + const float spark_base_velocity = 50.0f; + const float spark_rand_velocity = 130.0f; + + for (int i = 0; i < count; i++) { + cparticle_t* p = CL_AllocParticle(); if (!p) return; p->time = cl.time; + p->color = color + (rand() & 7); + p->brightness = 0.5f; - d = rand() & 31; - for (j = 0; j < 3; j++) { - p->org[j] = org[j] + ((rand() & 7) - 4) + d * dir[j]; - p->vel[j] = crand() * 20; - } + vec3_t origin; + VectorCopy(org, origin); + VectorMA(origin, dirt_horizontal_spread * crand(), ox, origin); + VectorMA(origin, dirt_horizontal_spread * crand(), oy, origin); + VectorMA(origin, dirt_vertical_spread * frand() + 1.0f, dir, origin); + VectorCopy(origin, p->org); + + vec3_t velocity; + VectorSubtract(origin, org, velocity); + VectorNormalize(velocity); + VectorScale(velocity, dirt_base_velocity + frand() * dirt_rand_velocity, p->vel); + + p->accel[0] = p->accel[1] = 0; + p->accel[2] = -PARTICLE_GRAVITY; + p->alpha = 1.0; + + p->alphavel = -1.0 / (0.5 + frand() * 0.3); + } + + for (int i = 0; i < spark_count; i++) { + cparticle_t* p = CL_AllocParticle(); + if (!p) + return; + + p->time = cl.time; + + p->color = 0xe0 + (rand() & 7); + p->brightness = cvar_pt_particle_emissive->value; + + vec3_t origin; + VectorCopy(org, origin); + VectorMA(origin, spark_horizontal_spread * crand(), ox, origin); + VectorMA(origin, spark_horizontal_spread * crand(), oy, origin); + VectorMA(origin, spark_vertical_spread * frand() + 1.0f, dir, origin); + VectorCopy(origin, p->org); + + vec3_t velocity; + VectorSubtract(origin, org, velocity); + VectorNormalize(velocity); + VectorScale(velocity, spark_base_velocity + powf(frand(), 2.0f) * spark_rand_velocity, p->vel); + + p->accel[0] = p->accel[1] = 0; + p->accel[2] = -PARTICLE_GRAVITY; + p->alpha = 1.0; + + p->alphavel = -2.0 / (0.5 + frand() * 0.3); + } +} + +void CL_ParticleEffectWaterSplash(vec3_t org, vec3_t dir, int color, int count) +{ + vec3_t oy; + VectorSet(oy, 0.0f, 1.0f, 0.0f); + if (fabs(DotProduct(oy, dir)) > 0.95f) + VectorSet(oy, 1.0f, 0.0f, 0.0f); + + vec3_t ox; + CrossProduct(oy, dir, ox); + + count *= cl_particle_num_factor->value; + + const float water_horizontal_spread = 0.25f; + const float water_vertical_spread = 1.0f; + const float water_base_velocity = 80.0f; + const float water_rand_velocity = 150.0f; + + for (int i = 0; i < count; i++) { + cparticle_t* p = CL_AllocParticle(); + if (!p) + return; + + p->time = cl.time; + + p->color = color + (rand() & 7); + p->brightness = 1.0f; + + vec3_t origin; + VectorCopy(org, origin); + VectorMA(origin, water_horizontal_spread * crand(), ox, origin); + VectorMA(origin, water_horizontal_spread * crand(), oy, origin); + VectorMA(origin, water_vertical_spread * frand() + 1.0f, dir, origin); + VectorCopy(origin, p->org); + + vec3_t velocity; + VectorSubtract(origin, org, velocity); + VectorNormalize(velocity); + VectorScale(velocity, water_base_velocity + frand() * water_rand_velocity, p->vel); p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY; @@ -894,13 +1020,17 @@ void CL_BloodParticleEffect(vec3_t org, vec3_t dir, int color, int count) float a[3] = {dir[1], -dir[2], dir[0]}; float b[3] = {-dir[2], dir[0], dir[1]}; + count *= cl_particle_num_factor->value; + for (i = 0; i < count; i++) { p = CL_AllocParticle(); if (!p) return; p->time = cl.time; + p->color = color + (rand() & 7); + p->brightness = 0.5f; d = (rand() & 31) * 10.0f; for (j = 0; j < 3; j++) { @@ -915,7 +1045,7 @@ void CL_BloodParticleEffect(vec3_t org, vec3_t dir, int color, int count) p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY; - p->alpha = 1.0; + p->alpha = 0.5; p->alphavel = -1.0 / (0.5 + frand() * 0.3); } @@ -933,13 +1063,17 @@ void CL_ParticleEffect2(vec3_t org, vec3_t dir, int color, int count) cparticle_t *p; float d; + count *= cl_particle_num_factor->value; + for (i = 0; i < count; i++) { p = CL_AllocParticle(); if (!p) return; p->time = cl.time; + p->color = color; + p->brightness = 1.0f; d = rand() & 7; for (j = 0; j < 3; j++) { @@ -966,13 +1100,17 @@ void CL_TeleporterParticles(vec3_t org) int i, j; cparticle_t *p; - for (i = 0; i < 8; i++) { + const int count = 8 * cl_particle_num_factor->value; + + for (i = 0; i < count; i++) { p = CL_AllocParticle(); if (!p) return; p->time = cl.time; + p->color = 0xdb; + p->brightness = 1.0f; for (j = 0; j < 2; j++) { p->org[j] = org[j] - 16 + (rand() & 31); @@ -1009,12 +1147,16 @@ static void CL_LogoutEffect(vec3_t org, int type) p->time = cl.time; + int color; if (type == MZ_LOGIN) - p->color = 0xd0 + (rand() & 7); // green + color = 0xd0 + (rand() & 7); // green else if (type == MZ_LOGOUT) - p->color = 0x40 + (rand() & 7); // red + color = 0x40 + (rand() & 7); // red else - p->color = 0xe0 + (rand() & 7); // yellow + color = 0xe0 + (rand() & 7); // yellow + + p->color = color; + p->brightness = 1.0f; p->org[0] = org[0] - 16 + frand() * 32; p->org[1] = org[1] - 16 + frand() * 32; @@ -1043,7 +1185,9 @@ void CL_ItemRespawnParticles(vec3_t org) int i, j; cparticle_t *p; - for (i = 0; i < 64; i++) { + const int count = 64 * cl_particle_num_factor->value; + + for (i = 0; i < count; i++) { p = CL_AllocParticle(); if (!p) return; @@ -1051,6 +1195,7 @@ void CL_ItemRespawnParticles(vec3_t org) p->time = cl.time; p->color = 0xd4 + (rand() & 3); // green + p->brightness = 1.0f; p->org[0] = org[0] + crand() * 8; p->org[1] = org[1] + crand() * 8; @@ -1078,13 +1223,17 @@ void CL_ExplosionParticles(vec3_t org) int i, j; cparticle_t *p; - for (i = 0; i < 256; i++) { + const int count = 256 * cl_particle_num_factor->value; + + for (i = 0; i < count; i++) { p = CL_AllocParticle(); if (!p) return; p->time = cl.time; + p->color = 0xe0 + (rand() & 7); + p->brightness = cvar_pt_particle_emissive->value; for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((rand() % 32) - 16); @@ -1119,6 +1268,7 @@ void CL_BigTeleportParticles(vec3_t org) p->time = cl.time; p->color = colortable[rand() & 3]; + p->brightness = 1.0f; angle = M_PI * 2 * (rand() & 1023) / 1023.0; dist = rand() & 31; @@ -1153,13 +1303,17 @@ void CL_BlasterParticles(vec3_t org, vec3_t dir) cparticle_t *p; float d; - for (i = 0; i < 40; i++) { + const int count = 40 * cl_particle_num_factor->value; + + for (i = 0; i < count; i++) { p = CL_AllocParticle(); if (!p) return; p->time = cl.time; + p->color = 0xe0 + (rand() & 7); + p->brightness = cvar_pt_particle_emissive->value; d = rand() & 15; for (j = 0; j < 3; j++) { @@ -1211,7 +1365,10 @@ void CL_BlasterTrail(vec3_t start, vec3_t end) p->alpha = 1.0; p->alphavel = -1.0 / (0.3 + frand() * 0.2); + p->color = 0xe0; + p->brightness = cvar_pt_particle_emissive->value; + for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand(); p->vel[j] = crand() * 5; @@ -1256,7 +1413,10 @@ void CL_QuadTrail(vec3_t start, vec3_t end) p->alpha = 1.0; p->alphavel = -1.0 / (0.8 + frand() * 0.2); + p->color = 115; + p->brightness = cvar_pt_particle_emissive->value; + for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand() * 16; p->vel[j] = crand() * 5; @@ -1301,7 +1461,10 @@ void CL_FlagTrail(vec3_t start, vec3_t end, int color) p->alpha = 1.0; p->alphavel = -1.0 / (0.8 + frand() * 0.2); + p->color = color; + p->brightness = 1.0f; + for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand() * 16; p->vel[j] = crand() * 5; @@ -1362,7 +1525,10 @@ void CL_DiminishingTrail(vec3_t start, vec3_t end, centity_t *old, int flags) if (flags & EF_GIB) { p->alpha = 1.0; p->alphavel = -1.0 / (1 + frand() * 0.4); + p->color = 0xe8 + (rand() & 7); + p->brightness = 1.0f; + for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand() * orgscale; p->vel[j] = crand() * velscale; @@ -1372,7 +1538,10 @@ void CL_DiminishingTrail(vec3_t start, vec3_t end, centity_t *old, int flags) } else if (flags & EF_GREENGIB) { p->alpha = 1.0; p->alphavel = -1.0 / (1 + frand() * 0.4); + p->color = 0xdb + (rand() & 7); + p->brightness = 1.0f; + for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand() * orgscale; p->vel[j] = crand() * velscale; @@ -1382,7 +1551,10 @@ void CL_DiminishingTrail(vec3_t start, vec3_t end, centity_t *old, int flags) } else { p->alpha = 1.0; p->alphavel = -1.0 / (1 + frand() * 0.2); + p->color = 4 + (rand() & 7); + p->brightness = 1.0f; + for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand() * orgscale; p->vel[j] = crand() * velscale; @@ -1437,7 +1609,10 @@ void CL_RocketTrail(vec3_t start, vec3_t end, centity_t *old) p->alpha = 1.0; p->alphavel = -1.0 / (1 + frand() * 0.2); + p->color = 0xdc + (rand() & 3); + p->brightness = cvar_pt_particle_emissive->value; + for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand() * 5; p->vel[j] = crand() * 20; @@ -1491,7 +1666,10 @@ void CL_OldRailTrail(void) p->alpha = 1.0; p->alphavel = -1.0 / (1 + frand() * 0.2); + p->color = clr + (rand() & 7); + p->brightness = cvar_pt_particle_emissive->value; + for (j = 0; j < 3; j++) { p->org[j] = move[j] + dir[j] * 3; p->vel[j] = dir[j] * 6; @@ -1516,7 +1694,9 @@ void CL_OldRailTrail(void) p->alpha = 1.0; p->alphavel = -1.0 / (0.6 + frand() * 0.2); + p->color = rand() & 15; + p->brightness = 1.0f; for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand() * 3; @@ -1561,7 +1741,10 @@ void CL_BubbleTrail(vec3_t start, vec3_t end) p->alpha = 1.0; p->alphavel = -1.0 / (1 + frand() * 0.2); + p->color = 4 + (rand() & 7); + p->brightness = 1.0f; + for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand() * 2; p->vel[j] = crand() * 5; @@ -1622,9 +1805,10 @@ static void CL_FlyParticles(vec3_t origin, int count) VectorClear(p->accel); p->color = 0; + p->brightness = 1.0f; p->alpha = 1; - p->alphavel = -100; + p->alphavel = INSTANT_PARTICLE; } } @@ -1655,7 +1839,6 @@ void CL_FlyEffect(centity_t *ent, vec3_t origin) CL_FlyParticles(origin, count); } - /* =============== CL_BfgParticles @@ -1672,8 +1855,10 @@ void CL_BfgParticles(entity_t *ent) vec3_t v; float ltime; + const int count = NUMVERTEXNORMALS * cl_particle_num_factor->value; + ltime = (float)cl.time / 1000.0; - for (i = 0; i < NUMVERTEXNORMALS; i++) { + for (i = 0; i < count; i++) { angle = ltime * avelocities[i][0]; sy = sin(angle); cy = cos(angle); @@ -1701,10 +1886,12 @@ void CL_BfgParticles(entity_t *ent) VectorSubtract(p->org, ent->origin, v); dist = VectorLength(v) / 90.0; + p->color = floor(0xd0 + dist * 7); + p->brightness = cvar_pt_particle_emissive->value; p->alpha = 1.0 - dist; - p->alphavel = -100; + p->alphavel = INSTANT_PARTICLE; } } @@ -1720,13 +1907,17 @@ void CL_BFGExplosionParticles(vec3_t org) int i, j; cparticle_t *p; - for (i = 0; i < 256; i++) { + const int count = 256 * cl_particle_num_factor->value; + + for (i = 0; i < count; i++) { p = CL_AllocParticle(); if (!p) return; p->time = cl.time; + p->color = 0xd0 + (rand() & 7); + p->brightness = cvar_pt_particle_emissive->value; for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((rand() % 32) - 16); @@ -1763,7 +1954,9 @@ void CL_TeleportParticles(vec3_t org) return; p->time = cl.time; + p->color = 7 + (rand() & 7); + p->brightness = 1.0f; p->alpha = 1.0; p->alphavel = -1.0 / (0.3 + (rand() & 7) * 0.02); @@ -1851,14 +2044,16 @@ void CL_AddParticles(void) } part->color = color; - part->alpha = alpha; + part->brightness = p->brightness; + part->alpha = alpha; + part->radius = 0.f; if (p->alphavel == INSTANT_PARTICLE) { p->alphavel = 0.0; p->alpha = 0.0; } } - + active_particles = active; } diff --git a/src/client/entities.c b/src/client/entities.c index 5eceee5a1..7fea01e6b 100644 --- a/src/client/entities.c +++ b/src/client/entities.c @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -18,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., // cl_ents.c -- entity parsing and management #include "client.h" +#include "refresh/models.h" extern qhandle_t cl_mod_powerscreen; extern qhandle_t cl_mod_laser; @@ -459,6 +461,46 @@ INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS ========================================================================== */ +// Use a static entity ID on some things because the renderer relies on eid to match between meshes +// on the current and previous frames. +#define RESERVED_ENTITIY_GUN 1 +#define RESERVED_ENTITIY_COUNT 2 + +static int adjust_shell_fx(int renderfx) +{ + // PMM - at this point, all of the shells have been handled + // if we're in the rogue pack, set up the custom mixing, otherwise just + // keep going + if (!strcmp(fs_game->string, "rogue")) { + // all of the solo colors are fine. we need to catch any of the combinations that look bad + // (double & half) and turn them into the appropriate color, and make double/quad something special + if (renderfx & RF_SHELL_HALF_DAM) { + // ditch the half damage shell if any of red, blue, or double are on + if (renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE)) + renderfx &= ~RF_SHELL_HALF_DAM; + } + + if (renderfx & RF_SHELL_DOUBLE) { + // lose the yellow shell if we have a red, blue, or green shell + if (renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_GREEN)) + renderfx &= ~RF_SHELL_DOUBLE; + // if we have a red shell, turn it to purple by adding blue + if (renderfx & RF_SHELL_RED) + renderfx |= RF_SHELL_BLUE; + // if we have a blue shell (and not a red shell), turn it to cyan by adding green + else if (renderfx & RF_SHELL_BLUE) { + // go to green if it's on already, otherwise do cyan (flash green) + if (renderfx & RF_SHELL_GREEN) + renderfx &= ~RF_SHELL_BLUE; + else + renderfx |= RF_SHELL_GREEN; + } + } + } + + return renderfx; +} + /* =============== CL_AddPacketEntities @@ -490,7 +532,7 @@ static void CL_AddPacketEntities(void) s1 = &cl.entityStates[i]; cent = &cl_entities[s1->number]; - ent.id = cent->id; + ent.id = cent->id + RESERVED_ENTITIY_COUNT; effects = s1->effects; renderfx = s1->renderfx; @@ -668,6 +710,8 @@ static void CL_AddPacketEntities(void) } } + int base_entity_flags = 0; + if (s1->number == cl.frame.clientNum + 1) { if (effects & EF_FLAG1) V_AddLight(ent.origin, 225, 1.0, 0.1, 0.1); @@ -678,13 +722,13 @@ static void CL_AddPacketEntities(void) else if (effects & EF_TRACKERTRAIL) V_AddLight(ent.origin, 225, -1.0, -1.0, -1.0); - if (!cl.thirdPersonView) { -#if 0 - ent.flags |= RF_VIEWERMODEL; // only draw from mirrors -#else - goto skip; -#endif - } + if (!cl.thirdPersonView) + { + if(vid_rtx->integer) + base_entity_flags |= RF_VIEWERMODEL; // only draw from mirrors + else + goto skip; + } } // if set to invisible, skip @@ -710,48 +754,37 @@ static void CL_AddPacketEntities(void) ent.alpha = 0.3; } - // add to refresh list - V_AddEntity(&ent); - - // color shells generate a seperate entity for the main model - if (effects & EF_COLOR_SHELL) { - // PMM - at this point, all of the shells have been handled - // if we're in the rogue pack, set up the custom mixing, otherwise just - // keep going - if (!strcmp(fs_game->string, "rogue")) { - // all of the solo colors are fine. we need to catch any of the combinations that look bad - // (double & half) and turn them into the appropriate color, and make double/quad something special - if (renderfx & RF_SHELL_HALF_DAM) { - // ditch the half damage shell if any of red, blue, or double are on - if (renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE)) - renderfx &= ~RF_SHELL_HALF_DAM; - } + ent.flags |= base_entity_flags; - if (renderfx & RF_SHELL_DOUBLE) { - // lose the yellow shell if we have a red, blue, or green shell - if (renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_GREEN)) - renderfx &= ~RF_SHELL_DOUBLE; - // if we have a red shell, turn it to purple by adding blue - if (renderfx & RF_SHELL_RED) - renderfx |= RF_SHELL_BLUE; - // if we have a blue shell (and not a red shell), turn it to cyan by adding green - else if (renderfx & RF_SHELL_BLUE) { - // go to green if it's on already, otherwise do cyan (flash green) - if (renderfx & RF_SHELL_GREEN) - renderfx &= ~RF_SHELL_BLUE; - else - renderfx |= RF_SHELL_GREEN; - } - } - } - ent.flags = renderfx | RF_TRANSLUCENT; + // in rtx mode, the base entity has the renderfx for shells + if ((effects & EF_COLOR_SHELL) && vid_rtx->integer) { + renderfx = adjust_shell_fx(renderfx); + ent.flags |= renderfx; + } + + // add to refresh list + V_AddEntity(&ent); + + // add dlights for wall lamps + model_t* model; + if (vid_rtx->integer && ent.model && !(ent.model & 0x80000000) && + (model = MOD_ForHandle(ent.model)) && + (model->model_class == MCLASS_STATIC_LIGHT)) + { + V_AddLightEx(ent.origin, 200.f, 0.25f, 0.5f, 0.1f, 3.f); + } + + // color shells generate a separate entity for the main model + if ((effects & EF_COLOR_SHELL) && !vid_rtx->integer) { + renderfx = adjust_shell_fx(renderfx); + ent.flags = renderfx | RF_TRANSLUCENT | base_entity_flags; ent.alpha = 0.30; V_AddEntity(&ent); } ent.skin = 0; // never use a custom skin on others ent.skinnum = 0; - ent.flags = 0; + ent.flags = base_entity_flags; ent.alpha = 0; // duplicate for linked models @@ -778,10 +811,14 @@ static void CL_AddPacketEntities(void) ent.flags = RF_TRANSLUCENT; } + if ((effects & EF_COLOR_SHELL) && vid_rtx->integer) { + ent.flags |= renderfx; + } + V_AddEntity(&ent); //PGM - make sure these get reset. - ent.flags = 0; + ent.flags = base_entity_flags; ent.alpha = 0; } @@ -810,20 +847,20 @@ static void CL_AddPacketEntities(void) if (!(cl_disable_particles->integer & NOPART_ROCKET_TRAIL)) { CL_RocketTrail(cent->lerp_origin, ent.origin, cent); } - V_AddLight(ent.origin, 200, 1, 1, 0); + V_AddLight(ent.origin, 200, 0.6f, 0.4f, 0.12f); } else if (effects & EF_BLASTER) { if (effects & EF_TRACKER) { CL_BlasterTrail2(cent->lerp_origin, ent.origin); - V_AddLight(ent.origin, 200, 0, 1, 0); + V_AddLight(ent.origin, 200, 0.1f, 0.4f, 0.12f); } else { CL_BlasterTrail(cent->lerp_origin, ent.origin); - V_AddLight(ent.origin, 200, 1, 1, 0); + V_AddLight(ent.origin, 200, 0.6f, 0.4f, 0.12f); } } else if (effects & EF_HYPERBLASTER) { if (effects & EF_TRACKER) - V_AddLight(ent.origin, 200, 0, 1, 0); + V_AddLight(ent.origin, 200, 0.1f, 0.4f, 0.12f); else - V_AddLight(ent.origin, 200, 1, 1, 0); + V_AddLight(ent.origin, 200, 0.6f, 0.4f, 0.12f); } else if (effects & EF_GIB) { CL_DiminishingTrail(cent->lerp_origin, ent.origin, cent, effects); } else if (effects & EF_GRENADE) { @@ -836,7 +873,7 @@ static void CL_AddPacketEntities(void) if (effects & EF_ANIM_ALLFAST) { CL_BfgParticles(&ent); #if USE_DLIGHTS - i = 200; + i = 100; } else { static const int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75}; @@ -844,7 +881,8 @@ static void CL_AddPacketEntities(void) i = bfg_lightramp[i]; #endif } - V_AddLight(ent.origin, i, 0, 1, 0); + const vec3_t nvgreen = { 0.2716f, 0.5795f, 0.04615f }; + V_AddLightEx(ent.origin, i, nvgreen[0], nvgreen[1], nvgreen[2], 20.f); } else if (effects & EF_TRAP) { ent.origin[2] += 32; CL_TrapParticles(&ent); @@ -932,10 +970,10 @@ static void CL_AddViewWeapon(void) { player_state_t *ps, *ops; entity_t gun; // view model - int i, flags; + int i, shell_flags; // allow the gun to be completely removed - if (cl_gun->integer < 1) { + if (cl_player_model->integer == CL_PLAYER_MODEL_DISABLED) { return; } @@ -958,6 +996,8 @@ static void CL_AddViewWeapon(void) return; } + gun.id = RESERVED_ENTITIY_GUN; + // set up gun position for (i = 0; i < 3; i++) { gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i] + @@ -972,6 +1012,31 @@ static void CL_AddViewWeapon(void) VectorMA(gun.origin, ofs, cl.v_forward, gun.origin); } + // adjust the gun origin so that the gun doesn't intersect with walls + { + vec3_t view_dir, right_dir, up_dir; + vec3_t gun_real_pos, gun_tip; + const float gun_length = 28.f; + const float gun_right = 10.f; + const float gun_up = -5.f; + trace_t trace; + static vec3_t mins = { -4, -4, -4 }, maxs = { 4, 4, 4 }; + + AngleVectors(cl.refdef.viewangles, view_dir, right_dir, up_dir); + VectorMA(gun.origin, gun_right, right_dir, gun_real_pos); + VectorMA(gun_real_pos, gun_up, up_dir, gun_real_pos); + VectorMA(gun_real_pos, gun_length, view_dir, gun_tip); + + CM_BoxTrace(&trace, gun_real_pos, gun_tip, mins, maxs, cl.bsp->nodes, MASK_SOLID); + + if (trace.fraction != 1.0f) + { + VectorMA(trace.endpos, -gun_length, view_dir, gun.origin); + VectorMA(gun.origin, -gun_right, right_dir, gun.origin); + VectorMA(gun.origin, -gun_up, up_dir, gun.origin); + } + } + VectorCopy(gun.origin, gun.oldorigin); // don't lerp at all if (gun_frame) { @@ -995,15 +1060,26 @@ static void CL_AddViewWeapon(void) if (cl_gunalpha->value != 1) { gun.alpha = Cvar_ClampValue(cl_gunalpha, 0.1f, 1.0f); gun.flags |= RF_TRANSLUCENT; - } + } + + // add shell effect from player entity + shell_flags = shell_effect_hack(); + + // same entity in rtx mode + if (vid_rtx->integer) { + gun.flags |= shell_flags; + } + + model_t* model = MOD_ForHandle(gun.model); + if (model && strstr(model->name, "v_flareg")) + gun.scale = 0.3f; V_AddEntity(&gun); - // add shell effect from player entity - flags = shell_effect_hack(); - if (flags) { + // separate entity in non-rtx mode + if (shell_flags && !vid_rtx->integer) { gun.alpha = 0.30f * cl_gunalpha->value; - gun.flags |= flags | RF_TRANSLUCENT; + gun.flags |= shell_flags | RF_TRANSLUCENT; V_AddEntity(&gun); } } @@ -1083,7 +1159,7 @@ static void CL_FinishViewValues(void) { centity_t *ent; - if (!cl_thirdperson->integer) + if (cl_player_model->integer != CL_PLAYER_MODEL_THIRD_PERSON) goto first; if (cl.frame.clientNum == CLIENTNUM_NONE) diff --git a/src/client/main.c b/src/client/main.c index e4e3d3de7..f502ec9d3 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -43,7 +44,7 @@ cvar_t *cl_showmiss; cvar_t *cl_showclamp; #endif -cvar_t *cl_thirdperson; +cvar_t *cl_player_model; cvar_t *cl_thirdperson_angle; cvar_t *cl_thirdperson_range; @@ -52,6 +53,8 @@ cvar_t *cl_disable_explosions; cvar_t *cl_chat_notify; cvar_t *cl_chat_sound; cvar_t *cl_chat_filter; +cvar_t *cl_explosion_sprites; +cvar_t *cl_explosion_frametime; cvar_t *cl_disconnectcmd; cvar_t *cl_changemapcmd; @@ -88,6 +91,8 @@ extern cvar_t *gl_modulate_entities; extern cvar_t *gl_brightness; #endif +extern cvar_t *fs_shareware; + client_static_t cls; client_state_t cl; @@ -181,9 +186,7 @@ static void CL_UpdateGunSetting(void) return; } - if (cl_gun->integer == -1) { - nogun = 2; - } else if (cl_gun->integer == 0 || info_hand->integer == 2) { + if (cl_player_model->integer == CL_PLAYER_MODEL_DISABLED || info_hand->integer == 2) { nogun = 1; } else { nogun = 0; @@ -511,6 +514,12 @@ static void CL_Connect_f(void) int protocol; int argc = Cmd_Argc(); + if (fs_shareware->integer) + { + Com_EPrintf("Multiplayer is not supported in the shareware version of the game.\n"); + return; + } + if (argc < 2) { usage: Com_Printf("Usage: %s [34|35|36]\n", Cmd_Argv(0)); @@ -711,9 +720,9 @@ void CL_ClearState(void) #if USE_REF == REF_GL // unprotect our custom modulate cvars - gl_modulate_world->flags &= ~CVAR_CHEAT; - gl_modulate_entities->flags &= ~CVAR_CHEAT; - gl_brightness->flags &= ~CVAR_CHEAT; + if(gl_modulate_world) gl_modulate_world->flags &= ~CVAR_CHEAT; + if(gl_modulate_entities) gl_modulate_entities->flags &= ~CVAR_CHEAT; + if(gl_brightness) gl_brightness->flags &= ~CVAR_CHEAT; #endif } @@ -2261,7 +2270,7 @@ static size_t CL_DemoPos_m(char *buffer, size_t size) "%d:%02d.%d", min, sec, framenum); } -static size_t CL_Fps_m(char *buffer, size_t size) +size_t CL_Fps_m(char *buffer, size_t size) { return Q_scnprintf(buffer, size, "%i", C_FPS); } @@ -2314,6 +2323,32 @@ static size_t CL_WeaponModel_m(char *buffer, size_t size) cl.configstrings[cl.frame.ps.gunindex + CS_MODELS]); } +static size_t CL_Cluster_m(char *buffer, size_t size) +{ + return Q_scnprintf(buffer, size, "%i", cl.refdef.feedback.viewcluster); +} + +static size_t CL_ClusterThere_m(char *buffer, size_t size) +{ + return Q_scnprintf(buffer, size, "%i", cl.refdef.feedback.lookatcluster); +} + +static size_t CL_NumLightPolys_m(char *buffer, size_t size) +{ + return Q_scnprintf(buffer, size, "%i", cl.refdef.feedback.num_light_polys); +} + +static size_t CL_Material_m(char *buffer, size_t size) +{ + return Q_scnprintf(buffer, size, "%s", cl.refdef.feedback.view_material); +} + +static size_t CL_Material_Override_m(char *buffer, size_t size) +{ + return Q_scnprintf(buffer, size, "%s", cl.refdef.feedback.view_material_override); +} + + /* =============== CL_WriteConfig @@ -2321,7 +2356,7 @@ CL_WriteConfig Writes key bindings and archived cvars to config.cfg =============== */ -static void CL_WriteConfig(void) +void CL_WriteConfig(void) { qhandle_t f; qerror_t ret; @@ -2526,7 +2561,7 @@ static void exec_server_string(cmdbuf_t *buf, const char *text) Cmd_ExecuteCommand(buf); } -static void cl_gun_changed(cvar_t *self) +static void cl_player_model_changed(cvar_t *self) { CL_UpdateGunSetting(); } @@ -2667,8 +2702,6 @@ static void CL_InitLocal(void) // // register our variables // - cl_gun = Cvar_Get("cl_gun", "1", 0); - cl_gun->changed = cl_gun_changed; cl_gunalpha = Cvar_Get("cl_gunalpha", "1", 0); cl_footsteps = Cvar_Get("cl_footsteps", "1", 0); cl_footsteps->changed = cl_footsteps_changed; @@ -2704,12 +2737,15 @@ static void CL_InitLocal(void) rcon_address = Cvar_Get("rcon_address", "", CVAR_PRIVATE); rcon_address->generator = Com_Address_g; - cl_thirdperson = Cvar_Get("cl_thirdperson", "0", CVAR_CHEAT); + cl_player_model = Cvar_Get("cl_player_model", va("%d", CL_PLAYER_MODEL_FIRST_PERSON), CVAR_ARCHIVE); + cl_player_model->changed = cl_player_model_changed; cl_thirdperson_angle = Cvar_Get("cl_thirdperson_angle", "0", 0); cl_thirdperson_range = Cvar_Get("cl_thirdperson_range", "60", 0); cl_disable_particles = Cvar_Get("cl_disable_particles", "0", 0); - cl_disable_explosions = Cvar_Get("cl_disable_explosions", "0", 0); + cl_disable_explosions = Cvar_Get("cl_disable_explosions", "0", 0); + cl_explosion_sprites = Cvar_Get("cl_explosion_sprites", "1", 0); + cl_explosion_frametime = Cvar_Get("cl_explosion_frametime", "20", 0); cl_gibs = Cvar_Get("cl_gibs", "1", 0); cl_gibs->changed = cl_gibs_changed; @@ -2743,7 +2779,7 @@ static void CL_InitLocal(void) // info_password = Cvar_Get("password", "", CVAR_USERINFO); info_spectator = Cvar_Get("spectator", "0", CVAR_USERINFO); - info_name = Cvar_Get("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE); + info_name = Cvar_Get("name", "Player", CVAR_USERINFO | CVAR_ARCHIVE); info_skin = Cvar_Get("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE); info_rate = Cvar_Get("rate", "5000", CVAR_USERINFO | CVAR_ARCHIVE); info_msg = Cvar_Get("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE); @@ -2754,6 +2790,15 @@ static void CL_InitLocal(void) info_gender->modified = qfalse; // clear this so we know when user sets it manually info_uf = Cvar_Get("uf", "", CVAR_USERINFO); + // Generate a random user name to avoid new users being kicked out of MP servers. + // The default quake2 config files set the user name to "Player", same as the cvar initialization above. + if (Q_strcasecmp(info_name->string, "Player") == 0) + { + int random_number = rand() % 10000; + char buf[MAX_CLIENT_NAME]; + Q_snprintf(buf, sizeof(buf), "Player-%04d", random_number); + Cvar_Set("name", buf); + } // // macros @@ -2773,6 +2818,11 @@ static void CL_InitLocal(void) Cmd_AddMacro("cl_ammo", CL_Ammo_m); Cmd_AddMacro("cl_armor", CL_Armor_m); Cmd_AddMacro("cl_weaponmodel", CL_WeaponModel_m); + Cmd_AddMacro("cl_cluster", CL_Cluster_m); + Cmd_AddMacro("cl_clusterthere", CL_ClusterThere_m); + Cmd_AddMacro("cl_lightpolys", CL_NumLightPolys_m); + Cmd_AddMacro("cl_material", CL_Material_m); + Cmd_AddMacro("cl_material_override", CL_Material_Override_m); } /* diff --git a/src/client/parse.c b/src/client/parse.c index ce77b2b9f..6ebd691ec 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -671,7 +671,7 @@ static void CL_ParseTEntPacket(void) case TE_BLASTER: case TE_GREENBLOOD: case TE_BLASTER2: - case TE_FLECHETTE: + case TE_FLECHETTE: case TE_HEATBEAM_SPARKS: case TE_HEATBEAM_STEAM: case TE_MOREBLOOD: @@ -773,6 +773,13 @@ static void CL_ParseTEntPacket(void) MSG_ReadPos(te.pos1); break; + case TE_FLARE: + te.entity1 = MSG_ReadShort(); + te.count = MSG_ReadByte(); + MSG_ReadPos(te.pos1); + MSG_ReadDir(te.dir); + break; + default: Com_Error(ERR_DROP, "%s: bad type", __func__); } diff --git a/src/client/precache.c b/src/client/precache.c index dff31c9a0..0cf4f4e62 100644 --- a/src/client/precache.c +++ b/src/client/precache.c @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -317,6 +318,11 @@ void CL_SetSky(void) R_SetSky(cl.configstrings[CS_SKY], rotate, axis); } +#if CL_RTX_SHADERBALLS +cvar_t* cvar_shaderballs; +qhandle_t cl_dev_shaderballs = -1; +#endif + /* ================= CL_PrepRefresh @@ -341,6 +347,15 @@ void CL_PrepRefresh(void) CL_RegisterTEntModels(); +#if CL_RTX_SHADERBALLS + cvar_shaderballs = Cvar_Get("cl_shaderballs", "0", CVAR_ARCHIVE); + if (cvar_shaderballs->integer) + { + cl_dev_shaderballs = R_RegisterModel("develop/objects/ShaderBallArray/ShaderBallArray16.MD3"); + Com_WPrintf("Precached ShaderBalls - remove from release build !"); + } +#endif + for (i = 2; i < MAX_MODELS; i++) { name = cl.configstrings[CS_MODELS + i]; if (!name[0]) { diff --git a/src/client/refresh.c b/src/client/refresh.c index 9921a639f..904b6ab8c 100644 --- a/src/client/refresh.c +++ b/src/client/refresh.c @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -22,9 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client.h" +#include "refresh/images.h" +#include "refresh/models.h" // Console variables that we need to access from this module -cvar_t *vid_ref; // Name of Refresh DLL loaded +cvar_t *vid_rtx; cvar_t *vid_geometry; cvar_t *vid_modelist; cvar_t *vid_fullscreen; @@ -143,10 +146,10 @@ qboolean VID_GetGeometry(vrect_t *rc) char *s; // fill in default parameters - rc->x = 0; - rc->y = 0; - rc->width = 640; - rc->height = 480; + rc->x = 100; + rc->y = 100; + rc->width = 1280; + rc->height = 720; if (!vid_geometry) return qfalse; @@ -161,7 +164,8 @@ qboolean VID_GetGeometry(vrect_t *rc) return qfalse; } h = strtoul(s + 1, &s, 10); - x = y = 0; + x = rc->x; + y = rc->y; if (*s == '+' || *s == '-') { x = strtol(s, &s, 10); if (*s == '+' || *s == '-') { @@ -296,7 +300,15 @@ void CL_InitRefresh(void) } // Create the video variables so we know how to start the graphics drivers - vid_ref = Cvar_Get("vid_ref", VID_REF, CVAR_ROM); + + vid_rtx = Cvar_Get("vid_rtx", +#if REF_VKPT + "1", +#else + "0", +#endif + CVAR_REFRESH | CVAR_ARCHIVE); + vid_fullscreen = Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE); _vid_fullscreen = Cvar_Get("_vid_fullscreen", "1", CVAR_ARCHIVE); vid_modelist = Cvar_Get("vid_modelist", modelist, 0); @@ -312,6 +324,19 @@ void CL_InitRefresh(void) Com_SetLastError(NULL); +#if REF_GL && REF_VKPT + if (vid_rtx->integer) + R_RegisterFunctionsRTX(); + else + R_RegisterFunctionsGL(); +#elif REF_GL + R_RegisterFunctionsGL(); +#elif REF_VKPT + R_RegisterFunctionsRTX(); +#else +#error "REF_GL and REF_VKPT are both disabled, at least one has to be enableds" +#endif + if (!R_Init(qtrue)) { Com_Error(ERR_FATAL, "Couldn't initialize refresh: %s", Com_GetLastError()); } @@ -324,6 +349,8 @@ void CL_InitRefresh(void) mode_changed = 0; + FX_Init(); + // Initialize the rest of graphics subsystems V_Init(); SCR_Init(); @@ -365,3 +392,58 @@ void CL_ShutdownRefresh(void) Z_LeakTest(TAG_RENDERER); } + +refcfg_t r_config; + +qboolean(*R_Init)(qboolean total) = NULL; +void(*R_Shutdown)(qboolean total) = NULL; +void(*R_BeginRegistration)(const char *map) = NULL; +void(*R_SetSky)(const char *name, float rotate, vec3_t axis) = NULL; +void(*R_EndRegistration)(void) = NULL; +void(*R_RenderFrame)(refdef_t *fd) = NULL; +void(*R_LightPoint)(vec3_t origin, vec3_t light) = NULL; +void(*R_ClearColor)(void) = NULL; +void(*R_SetAlpha)(float clpha) = NULL; +void(*R_SetAlphaScale)(float alpha) = NULL; +void(*R_SetColor)(uint32_t color) = NULL; +void(*R_SetClipRect)(const clipRect_t *clip) = NULL; +void(*R_SetScale)(float scale) = NULL; +void(*R_DrawChar)(int x, int y, int flags, int ch, qhandle_t font) = NULL; +int(*R_DrawString)(int x, int y, int flags, size_t maxChars, + const char *string, qhandle_t font) = NULL; +void(*R_DrawPic)(int x, int y, qhandle_t pic) = NULL; +void(*R_DrawStretchPic)(int x, int y, int w, int h, qhandle_t pic) = NULL; +void(*R_TileClear)(int x, int y, int w, int h, qhandle_t pic) = NULL; +void(*R_DrawFill8)(int x, int y, int w, int h, int c) = NULL; +void(*R_DrawFill32)(int x, int y, int w, int h, uint32_t color) = NULL; +void(*R_BeginFrame)(void) = NULL; +void(*R_EndFrame)(void) = NULL; +void(*R_ModeChanged)(int width, int height, int flags, int rowbytes, void *pixels) = NULL; +void(*R_AddDecal)(decal_t *d) = NULL; + +void(*IMG_Unload)(image_t *image) = NULL; +void(*IMG_Load)(image_t *image, byte *pic) = NULL; +byte* (*IMG_ReadPixels)(int *width, int *height, int *rowbytes) = NULL; + +qerror_t(*MOD_LoadMD2)(model_t *model, const void *rawdata, size_t length) = NULL; +#if USE_MD3 +qerror_t(*MOD_LoadMD3)(model_t *model, const void *rawdata, size_t length) = NULL; +#endif +void(*MOD_Reference)(model_t *model) = NULL; + +float R_ClampScale(cvar_t *var) +{ + if (!var) + return 1.0f; + + if (var->value) + return 1.0f / Cvar_ClampValue(var, 1.0f, 10.0f); + + if (r_config.width * r_config.height >= 2560 * 1440) + return 0.25f; + + if (r_config.width * r_config.height >= 1280 * 720) + return 0.5f; + + return 1.0f; +} diff --git a/src/client/screen.c b/src/client/screen.c index 7579d17bd..cd9e7429a 100644 --- a/src/client/screen.c +++ b/src/client/screen.c @@ -47,9 +47,10 @@ static struct { int hud_width, hud_height; float hud_scale; + float hud_alpha; } scr; -static cvar_t *scr_viewsize; +cvar_t *scr_viewsize; static cvar_t *scr_centertime; static cvar_t *scr_showpause; #ifdef _DEBUG @@ -65,6 +66,7 @@ static cvar_t *scr_lag_draw; static cvar_t *scr_lag_min; static cvar_t *scr_lag_max; static cvar_t *scr_alpha; +static cvar_t *scr_fps; static cvar_t *scr_demobar; static cvar_t *scr_font; @@ -846,6 +848,26 @@ static void SCR_DrawObjects(void) } } +extern size_t CL_Fps_m(char *buffer, size_t size); + +static void SCR_DrawFPS(void) +{ + if (scr_fps->integer == 0) + return; + + char buffer[MAX_QPATH]; + CL_Fps_m(buffer, sizeof(buffer)); + + int len = strlen(buffer); + strncat(buffer, " FPS", max(0, sizeof(buffer) - len - 1)); + + int x = scr.hud_width - 2; + int y = 1; + + R_SetColor(~0u); + SCR_DrawString(x, y, UI_RIGHT, buffer); +} + /* =============================================================================== @@ -1054,22 +1076,12 @@ static void SCR_DrawDebugPmove(void) //============================================================================ // Sets scr_vrect, the coordinates of the rendered window -static void SCR_CalcVrect(void) +void SCR_CalcVrect(void) { - int size; - - // bound viewsize - size = Cvar_ClampInteger(scr_viewsize, 40, 100); - scr_viewsize->modified = qfalse; - - scr_vrect.width = scr.hud_width * size / 100; - scr_vrect.width &= ~7; - - scr_vrect.height = scr.hud_height * size / 100; - scr_vrect.height &= ~1; - - scr_vrect.x = (scr.hud_width - scr_vrect.width) / 2; - scr_vrect.y = (scr.hud_height - scr_vrect.height) / 2; + scr_vrect.width = scr.hud_width; + scr_vrect.height = scr.hud_height; + scr_vrect.x = 0; + scr_vrect.y = 0; } /* @@ -1265,6 +1277,8 @@ void SCR_ModeChanged(void) cls.disable_screen = 0; if (scr.initialized) scr.hud_scale = R_ClampScale(scr_scale); + + scr.hud_alpha = 1.f; } /* @@ -1339,7 +1353,7 @@ void SCR_Init(void) scr_demobar = Cvar_Get("scr_demobar", "1", 0); scr_font = Cvar_Get("scr_font", "conchars", 0); scr_font->changed = scr_font_changed; - scr_scale = Cvar_Get("scr_scale", "1", 0); + scr_scale = Cvar_Get("scr_scale", "2", 0); scr_scale->changed = scr_scale_changed; scr_crosshair = Cvar_Get("crosshair", "0", CVAR_ARCHIVE); scr_crosshair->changed = scr_crosshair_changed; @@ -1373,7 +1387,8 @@ void SCR_Init(void) scr_lag_draw = Cvar_Get("scr_lag_draw", "0", 0); scr_lag_min = Cvar_Get("scr_lag_min", "0", 0); scr_lag_max = Cvar_Get("scr_lag_max", "200", 0); - scr_alpha = Cvar_Get("scr_alpha", "1", 0); + scr_alpha = Cvar_Get("scr_alpha", "1", 0); + scr_fps = Cvar_Get("scr_fps", "0", CVAR_ARCHIVE); #ifdef _DEBUG scr_showstats = Cvar_Get("scr_showstats", "0", 0); scr_showpmove = Cvar_Get("scr_showpmove", "0", 0); @@ -1472,32 +1487,6 @@ void SCR_EndLoadingPlaque(void) // Clear any parts of the tiled background that were drawn on last frame static void SCR_TileClear(void) { - int top, bottom, left, right; - - //if (con.currentHeight == 1) - // return; // full screen console - - if (scr_viewsize->integer == 100) - return; // full screen rendering - - top = scr_vrect.y; - bottom = top + scr_vrect.height - 1; - left = scr_vrect.x; - right = left + scr_vrect.width - 1; - - // clear above view screen - R_TileClear(0, 0, r_config.width, top, scr.backtile_pic); - - // clear below view screen - R_TileClear(0, bottom, r_config.width, - r_config.height - bottom, scr.backtile_pic); - - // clear left of view screen - R_TileClear(0, top, left, scr_vrect.height, scr.backtile_pic); - - // clear right of view screen - R_TileClear(right, top, r_config.width - right, - scr_vrect.height, scr.backtile_pic); } /* @@ -1705,7 +1694,7 @@ static void SCR_ExecuteLayoutString(const char *s) Com_Error(ERR_DROP, "%s: invalid pic index", __func__); } token = cl.configstrings[CS_IMAGES + value]; - if (token[0]) { + if (token[0] && cl.image_precache[value]) { R_DrawPic(x, y, cl.image_precache[value]); } continue; @@ -2026,6 +2015,8 @@ static void SCR_Draw2D(void) if (cls.key_dest & KEY_MENU) return; + R_SetAlphaScale(scr.hud_alpha); + R_SetScale(scr.hud_scale); scr.hud_height *= scr.hud_scale; @@ -2050,6 +2041,8 @@ static void SCR_Draw2D(void) SCR_DrawObjects(); + SCR_DrawFPS(); + SCR_DrawChatHUD(); SCR_DrawTurtle(); @@ -2065,6 +2058,7 @@ static void SCR_Draw2D(void) #endif R_SetScale(1.0f); + R_SetAlphaScale(1.0f); } static void SCR_DrawActive(void) @@ -2165,3 +2159,13 @@ void SCR_UpdateScreen(void) recursive--; } + +qhandle_t SCR_GetFont(void) +{ + return scr.font_pic; +} + +void SCR_SetHudAlpha(float alpha) +{ + scr.hud_alpha = alpha; +} diff --git a/src/client/sound/dma.c b/src/client/sound/dma.c index 01532459f..cc222edf3 100644 --- a/src/client/sound/dma.c +++ b/src/client/sound/dma.c @@ -45,8 +45,8 @@ qboolean DMA_Init(void) { sndinitstat_t ret = SIS_FAILURE; - s_khz = Cvar_Get("s_khz", "22", CVAR_ARCHIVE | CVAR_SOUND); - s_mixahead = Cvar_Get("s_mixahead", "0.2", CVAR_ARCHIVE); + s_khz = Cvar_Get("s_khz", "44", CVAR_ARCHIVE | CVAR_SOUND); + s_mixahead = Cvar_Get("s_mixahead", "0.1", CVAR_ARCHIVE); s_testsound = Cvar_Get("s_testsound", "0", 0); #if USE_DSOUND diff --git a/src/client/sound/main.c b/src/client/sound/main.c index fc00401b2..f902039c7 100644 --- a/src/client/sound/main.c +++ b/src/client/sound/main.c @@ -147,7 +147,7 @@ S_Init */ void S_Init(void) { - s_enable = Cvar_Get("s_enable", "1", CVAR_SOUND); + s_enable = Cvar_Get("s_enable", "2", CVAR_SOUND); if (s_enable->integer <= SS_NOT) { Com_Printf("Sound initialization disabled.\n"); return; diff --git a/src/client/tent.c b/src/client/tent.c index 1feced50a..0fda21d77 100644 --- a/src/client/tent.c +++ b/src/client/tent.c @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -18,11 +19,13 @@ with this program; if not, write to the Free Software Foundation, Inc., // cl_tent.c -- client side temporary entities #include "client.h" +#include "refresh/models.h" qhandle_t cl_sfx_ric1; qhandle_t cl_sfx_ric2; qhandle_t cl_sfx_ric3; qhandle_t cl_sfx_lashit; +qhandle_t cl_sfx_flare; qhandle_t cl_sfx_spark5; qhandle_t cl_sfx_spark6; qhandle_t cl_sfx_spark7; @@ -45,11 +48,14 @@ qhandle_t cl_mod_bfg_explo; qhandle_t cl_mod_powerscreen; qhandle_t cl_mod_laser; qhandle_t cl_mod_dmspot; +qhandle_t cl_mod_explosions[4]; qhandle_t cl_mod_lightning; qhandle_t cl_mod_heatbeam; qhandle_t cl_mod_explo4_big; +extern cvar_t* cvar_pt_particle_emissive; + /* ================= CL_RegisterTEntSounds @@ -64,6 +70,7 @@ void CL_RegisterTEntSounds(void) cl_sfx_ric2 = S_RegisterSound("world/ric2.wav"); cl_sfx_ric3 = S_RegisterSound("world/ric3.wav"); cl_sfx_lashit = S_RegisterSound("weapons/lashit.wav"); + cl_sfx_flare = S_RegisterSound("weapons/flare.wav"); cl_sfx_spark5 = S_RegisterSound("world/spark5.wav"); cl_sfx_spark6 = S_RegisterSound("world/spark6.wav"); cl_sfx_spark7 = S_RegisterSound("world/spark7.wav"); @@ -97,7 +104,11 @@ void CL_RegisterTEntModels(void) cl_mod_flash = R_RegisterModel("models/objects/flash/tris.md2"); cl_mod_parasite_segment = R_RegisterModel("models/monsters/parasite/segment/tris.md2"); cl_mod_grapple_cable = R_RegisterModel("models/ctf/segment/tris.md2"); - cl_mod_explo4 = R_RegisterModel("models/objects/r_explode/tris.md2"); + cl_mod_explo4 = R_RegisterModel("models/objects/r_explode/tris.md2"); + cl_mod_explosions[0] = R_RegisterModel("sprites/rocket_0.sp2"); + cl_mod_explosions[1] = R_RegisterModel("sprites/rocket_1.sp2"); + cl_mod_explosions[2] = R_RegisterModel("sprites/rocket_5.sp2"); + cl_mod_explosions[3] = R_RegisterModel("sprites/rocket_6.sp2"); cl_mod_bfg_explo = R_RegisterModel("sprites/s_bfg2.sp2"); cl_mod_powerscreen = R_RegisterModel("models/items/armor/effect/tris.md2"); cl_mod_laser = R_RegisterModel("models/objects/laser/tris.md2"); @@ -105,7 +116,13 @@ void CL_RegisterTEntModels(void) cl_mod_lightning = R_RegisterModel("models/proj/lightning/tris.md2"); cl_mod_heatbeam = R_RegisterModel("models/proj/beam/tris.md2"); - cl_mod_explo4_big = R_RegisterModel("models/objects/r_explode2/tris.md2"); + cl_mod_explo4_big = R_RegisterModel("models/objects/r_explode2/tris.md2"); + + for (int i = 0; i < sizeof(cl_mod_explosions) / sizeof(*cl_mod_explosions); i++) + { + model_t* model = MOD_ForHandle(cl_mod_explosions[i]); + model->sprite_vertical = qtrue; + } } /* @@ -116,29 +133,7 @@ EXPLOSION MANAGEMENT ============================================================== */ -#define MAX_EXPLOSIONS 32 - -typedef struct { - enum { - ex_free, - ex_explosion, - ex_misc, - ex_flash, - ex_mflash, - ex_poly, - ex_poly2, - ex_light - } type; - - entity_t ent; - int frames; - float light; - vec3_t lightcolor; - float start; - int baseframe; -} explosion_t; - -static explosion_t cl_explosions[MAX_EXPLOSIONS]; +explosion_t cl_explosions[MAX_EXPLOSIONS]; static void CL_ClearExplosions(void) { @@ -171,7 +166,7 @@ static explosion_t *CL_AllocExplosion(void) return oldest; } -static explosion_t *CL_PlainExplosion(void) +static explosion_t *CL_PlainExplosion(qboolean big) { explosion_t *ex; @@ -183,12 +178,25 @@ static explosion_t *CL_PlainExplosion(void) ex->light = 350; VectorSet(ex->lightcolor, 1.0, 0.5, 0.5); ex->ent.angles[1] = rand() % 360; - ex->ent.model = cl_mod_explo4; - if (frand() < 0.5) - ex->baseframe = 15; - ex->frames = 15; - return ex; + int model_idx = rand() % (sizeof(cl_mod_explosions) / sizeof(*cl_mod_explosions)); + model_t* sprite_model = MOD_ForHandle(cl_mod_explosions[model_idx]); + + if (cl_explosion_sprites->integer && !big && sprite_model) + { + ex->ent.model = cl_mod_explosions[model_idx]; + ex->frames = sprite_model->numframes; + ex->frametime = cl_explosion_frametime->integer; + } + else + { + ex->ent.model = big ? cl_mod_explo4_big : cl_mod_explo4; + if (frand() < 0.5) + ex->baseframe = 15; + ex->frames = 15; + } + + return ex; } /* @@ -217,6 +225,93 @@ void CL_SmokeAndFlash(vec3_t origin) ex->ent.model = cl_mod_flash; } +#define LENGTH(a) ((sizeof (a)) / (sizeof(*(a)))) + +typedef struct light_curve_s { + vec3_t color; + float radius; + float offset; +} light_curve_t; + +static light_curve_t ex_poly_light[] = { + { { 0.4f, 0.2f, 0.02f }, 12.5f, 20.00f }, + { { 0.351563f, 0.175781f, 0.017578f }, 15.0f, 23.27f }, + { { 0.30625f, 0.153125f, 0.015312f }, 20.0f, 24.95f }, + { { 0.264062f, 0.132031f, 0.013203f }, 22.5f, 25.01f }, + { { 0.225f, 0.1125f, 0.01125f }, 25.0f, 27.53f }, + { { 0.189063f, 0.094531f, 0.009453f }, 27.5f, 28.55f }, + { { 0.15625f, 0.078125f, 0.007813f }, 30.0f, 30.80f }, + { { 0.126563f, 0.063281f, 0.006328f }, 27.5f, 40.43f }, + { { 0.1f, 0.05f, 0.005f }, 25.0f, 49.02f }, + { { 0.076563f, 0.038281f, 0.003828f }, 22.5f, 58.15f }, + { { 0.05625f, 0.028125f, 0.002812f }, 20.0f, 61.03f }, + { { 0.039063f, 0.019531f, 0.001953f }, 17.5f, 63.59f }, + { { 0.025f, 0.0125f, 0.00125f }, 15.0f, 66.47f }, + { { 0.014063f, 0.007031f, 0.000703f }, 12.5f, 71.34f }, + { { 0.f, 0.f, 0.f }, 10.0f, 72.00f } +}; + +static light_curve_t ex_blaster_light[] = { + { { 0.04f, 0.02f, 0.0f }, 5.f, 15.00f }, + { { 0.2f, 0.15f, 0.01f }, 15.f, 15.00f }, + { { 0.04f, 0.02f, 0.0f }, 5.f, 15.00f }, +}; + +static light_curve_t ex_flare_light[] = { + { { 1.2f, 0.75f, 0.15f }, 10.f, 5.00f }, + { { 1.6f, 1.0f, 0.2f }, 10.f, 10.00f }, + { { 1.2f, 0.75f, 0.15f }, 10.f, 5.00f }, +}; + +static void CL_AddExplosionLight(explosion_t *ex, float phase) +{ + int curve_size; + light_curve_t* curve; + + switch (ex->type) + { + case ex_poly: + curve = ex_poly_light; + curve_size = LENGTH(ex_poly_light); + break; + case ex_blaster: + curve = ex_blaster_light; + curve_size = LENGTH(ex_blaster_light); + break; + case ex_flare: + curve = ex_flare_light; + curve_size = LENGTH(ex_flare_light); + break; + default: + return; + } + + float timeAlpha = ((float)(curve_size - 1)) * phase; + int baseSample = (int)floorf(timeAlpha); + baseSample = max(0, min(curve_size - 2, baseSample)); + + float w1 = timeAlpha - (float)(baseSample); + float w0 = 1.f - w1; + + light_curve_t* s0 = curve + baseSample; + light_curve_t* s1 = curve + baseSample + 1; + + float offset = w0 * s0->offset + w1 * s1->offset; + float radius = w0 * s0->radius + w1 * s1->radius; + + vec3_t origin; + vec3_t up; + AngleVectors(ex->ent.angles, NULL, NULL, up); + VectorMA(ex->ent.origin, offset, up, origin); + + vec3_t color; + VectorClear(color); + VectorMA(color, w0, s0->color, color); + VectorMA(color, w1, s1->color, color); + + V_AddLightEx(origin, 500.f, color[0], color[1], color[2], radius); +} + static void CL_AddExplosions(void) { entity_t *ent; @@ -230,17 +325,20 @@ static void CL_AddExplosions(void) for (i = 0, ex = cl_explosions; i < MAX_EXPLOSIONS; i++, ex++) { if (ex->type == ex_free) continue; - frac = (cl.time - ex->start) * BASE_1_FRAMETIME; + float inv_frametime = ex->frametime ? 1.f / (float)ex->frametime : BASE_1_FRAMETIME; + frac = (cl.time - ex->start) * inv_frametime; f = floor(frac); ent = &ex->ent; switch (ex->type) { case ex_mflash: - if (f >= ex->frames - 1) + if (f >= ex->frames - 1) ex->type = ex_free; break; - case ex_misc: + case ex_misc: + case ex_blaster: + case ex_flare: case ex_light: if (f >= ex->frames - 1) { ex->type = ex_free; @@ -261,7 +359,9 @@ static void CL_AddExplosions(void) break; } - ent->alpha = (16.0 - (float)f) / 16.0; + ent->alpha = ((float)ex->frames - (float)f) / (float)ex->frames; + ent->alpha = max(0.f, min(1.f, ent->alpha)); + ent->alpha = ent->alpha * ent->alpha * (3.f - 2.f * ent->alpha); // smoothstep if (f < 10) { ent->skinnum = (f >> 1); @@ -292,9 +392,14 @@ static void CL_AddExplosions(void) if (ex->type == ex_free) continue; - if (ex->light) - V_AddLight(ent->origin, ex->light * ent->alpha, - ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]); + if (vid_rtx->integer) + CL_AddExplosionLight(ex, frac / (ex->frames - 1)); + else + { + if (ex->light) + V_AddLight(ent->origin, ex->light * ent->alpha, + ex->lightcolor[0], ex->lightcolor[1], ex->lightcolor[2]); + } if (ex->type != ex_light) { VectorCopy(ent->origin, ent->oldorigin); @@ -878,6 +983,7 @@ static void CL_RailSpiral(void) p->alphavel = -1.0 / (cl_railtrail_time->value + frand() * 0.2); p->color = -1; p->rgba.u32 = railspiral_color.u32; + p->brightness = cvar_pt_particle_emissive->value; for (j = 0; j < 3; j++) { p->org[j] = move[j] + dir[j] * cl_railspiral_radius->value; p->vel[j] = dir[j] * 6; @@ -887,16 +993,63 @@ static void CL_RailSpiral(void) } } +static void CL_RailLights(color_t color) +{ + vec3_t fcolor; + fcolor[0] = (float)color.u8[0] / 255.f; + fcolor[1] = (float)color.u8[1] / 255.f; + fcolor[2] = (float)color.u8[2] / 255.f; + + vec3_t move; + vec3_t vec; + float len; + + VectorCopy(te.pos1, move); + VectorSubtract(te.pos2, te.pos1, vec); + len = VectorNormalize(vec); + + float num_segments = ceilf(len / 100.f); + float segment_size = len / num_segments; + + for (float segment = 0; segment < num_segments; segment++) + { + float offset = (segment + 0.25f) * segment_size; + vec3_t pos; + VectorMA(move, offset, vec, pos); + + cdlight_t* dl = CL_AllocDlight(0); + VectorScale(fcolor, 0.25f, dl->color); + VectorCopy(pos, dl->origin); + dl->radius = 400; + dl->decay = 400; + dl->die = cl.time + 1000; + VectorScale(vec, segment_size * 0.5f, dl->velosity); + } +} + +extern uint32_t d_8to24table[256]; + static void CL_RailTrail(void) { - if (!cl_railtrail_type->integer) { - CL_OldRailTrail(); - } else { - CL_RailCore(); - if (cl_railtrail_type->integer > 1) { - CL_RailSpiral(); - } - } + color_t rail_color; + + if (!cl_railtrail_type->integer) + { + rail_color.u32 = d_8to24table[0x74]; + + CL_OldRailTrail(); + } + else + { + rail_color = railcore_color; + + CL_RailCore(); + if (cl_railtrail_type->integer > 1) { + CL_RailSpiral(); + } + } + + CL_RailLights(rail_color); } static void dirtoangles(vec3_t angles) @@ -975,7 +1128,7 @@ void CL_ParseTEnt(void) r = 0x00; else r = splash_color[te.color]; - CL_ParticleEffect(te.pos1, te.dir, r, te.count); + CL_ParticleEffectWaterSplash(te.pos1, te.dir, r, te.count); if (te.color == SPLASH_SPARKS) { r = rand() & 3; @@ -998,17 +1151,16 @@ void CL_ParseTEnt(void) case TE_BLASTER: // blaster hitting wall case TE_BLASTER2: // green blaster hitting wall - case TE_FLECHETTE: // flechette + case TE_FLECHETTE: // flechette + case TE_FLARE: // flare ex = CL_AllocExplosion(); VectorCopy(te.pos1, ex->ent.origin); dirtoangles(ex->ent.angles); - ex->type = ex_misc; + ex->type = ex_blaster; ex->ent.flags = RF_FULLBRIGHT | RF_TRANSLUCENT; + ex->ent.tent_type = te.type; switch (te.type) { case TE_BLASTER: -#if USE_REF == REF_GLPT - R_SetRayProbe(te.pos1, te.dir); -#endif CL_BlasterParticles(te.pos1, te.dir); ex->lightcolor[0] = 1; ex->lightcolor[1] = 1; @@ -1024,13 +1176,29 @@ void CL_ParseTEnt(void) ex->lightcolor[0] = 0.19; ex->lightcolor[1] = 0.41; ex->lightcolor[2] = 0.75; - break; + break; + case TE_FLARE: + CL_BlasterParticles2(te.pos1, te.dir, 0xd0); + ex->lightcolor[0] = 1; + ex->lightcolor[1] = 1; + ex->type = ex_flare; + break; } ex->start = cl.servertime - CL_FRAMETIME; ex->light = 150; ex->ent.model = cl_mod_explode; ex->frames = 4; - S_StartSound(te.pos1, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + + if (te.type != TE_FLARE) + { + S_StartSound(te.pos1, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + } + else + { + // te.count is set to 1 on the first tick of the flare, 0 afterwards + if (te.count!=0) + S_StartSound(NULL, te.entity1, 0, cl_sfx_flare, 0.5, ATTN_NORM, 0); + } break; case TE_RAILTRAIL: // railgun effect @@ -1040,9 +1208,12 @@ void CL_ParseTEnt(void) case TE_GRENADE_EXPLOSION: case TE_GRENADE_EXPLOSION_WATER: - ex = CL_PlainExplosion(); - ex->frames = 19; - ex->baseframe = 30; + ex = CL_PlainExplosion(qfalse); + if (!cl_explosion_sprites->integer) + { + ex->frames = 19; + ex->baseframe = 30; + } if (cl_disable_explosions->integer & NOEXP_GRENADE) ex->type = ex_light; @@ -1056,22 +1227,25 @@ void CL_ParseTEnt(void) break; case TE_EXPLOSION2: - ex = CL_PlainExplosion(); - ex->frames = 19; - ex->baseframe = 30; + ex = CL_PlainExplosion(qfalse); + if (!cl_explosion_sprites->integer) + { + ex->frames = 19; + ex->baseframe = 30; + } CL_ExplosionParticles(te.pos1); S_StartSound(te.pos1, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0); break; case TE_PLASMA_EXPLOSION: - CL_PlainExplosion(); + CL_PlainExplosion(qfalse); CL_ExplosionParticles(te.pos1); S_StartSound(te.pos1, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); break; case TE_ROCKET_EXPLOSION: case TE_ROCKET_EXPLOSION_WATER: - ex = CL_PlainExplosion(); + ex = CL_PlainExplosion(qfalse); if (cl_disable_explosions->integer & NOEXP_ROCKET) ex->type = ex_light; @@ -1085,19 +1259,18 @@ void CL_ParseTEnt(void) break; case TE_EXPLOSION1: - CL_PlainExplosion(); + CL_PlainExplosion(qfalse); CL_ExplosionParticles(te.pos1); S_StartSound(te.pos1, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); break; case TE_EXPLOSION1_NP: - CL_PlainExplosion(); + CL_PlainExplosion(qfalse); S_StartSound(te.pos1, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); break; case TE_EXPLOSION1_BIG: - ex = CL_PlainExplosion(); - ex->ent.model = cl_mod_explo4_big; + ex = CL_PlainExplosion(qtrue); S_StartSound(te.pos1, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0); break; @@ -1113,7 +1286,7 @@ void CL_ParseTEnt(void) ex->lightcolor[2] = 0.0; ex->ent.model = cl_mod_bfg_explo; ex->ent.flags |= RF_TRANSLUCENT; - ex->ent.alpha = 0.30; + ex->ent.alpha = 0.80; ex->frames = 4; break; @@ -1183,7 +1356,7 @@ void CL_ParseTEnt(void) break; case TE_PLAIN_EXPLOSION: - CL_PlainExplosion(); + CL_PlainExplosion(qfalse); break; case TE_FLASHLIGHT: diff --git a/src/client/ui/menu.c b/src/client/ui/menu.c index dd1015dc2..c9ce4f6dd 100644 --- a/src/client/ui/menu.c +++ b/src/client/ui/menu.c @@ -1,5 +1,6 @@ /* Copyright (C) 1997-2001 Id Software, Inc. +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -1669,6 +1670,11 @@ static void Slider_Draw(menuSlider_t *s) clamp(pos, 0, 1); UI_DrawChar(CHAR_WIDTH + RCOLUMN_OFFSET + s->generic.x + (SLIDER_RANGE - 1) * CHAR_WIDTH * pos, s->generic.y, flags | UI_LEFT, 131); + + char sbuf[16]; + snprintf(sbuf, sizeof(sbuf), "%.1f", s->curvalue); + + UI_DrawString(s->generic.x + RCOLUMN_OFFSET + CHAR_WIDTH * (SLIDER_RANGE + 3), s->generic.y, flags | UI_LEFT, sbuf); } /* @@ -1767,6 +1773,7 @@ void Menu_AddItem(menuFrameWork_t *menu, void *item) menu->items[menu->nitems++] = item; ((menuCommon_t *)item)->parent = menu; + ((menuCommon_t *)item)->condition = menu->current_condition; } static void UI_ClearBounds(int mins[2], int maxs[2]) @@ -1800,6 +1807,20 @@ void Menu_Init(menuFrameWork_t *menu) menu->y1 = 0; menu->y2 = uis.height; + for (i = 0; i < menu->nitems; i++) { + item = menu->items[i]; + + menuCondition_t *condition = &((menuCommon_t*)item)->condition; + if (condition->cvar) + { + qboolean equals = condition->cvar->integer == condition->value; + if (equals == condition->equals) + ((menuCommon_t *)item)->flags &= ~QMF_HIDDEN; + else + ((menuCommon_t *)item)->flags |= QMF_HIDDEN; + } + } + if (!menu->size) { menu->size = Menu_Size; } @@ -1850,13 +1871,18 @@ void Menu_Init(menuFrameWork_t *menu) } } - // set focus to the first item by default + // set focus to the first non-hidden item by default if (!focus && menu->nitems) { - item = menu->items[0]; - ((menuCommon_t *)item)->flags |= QMF_HASFOCUS; - if (((menuCommon_t *)item)->status) { - menu->status = ((menuCommon_t *)item)->status; - } + for (i = 0; i < menu->nitems; i++) { + item = menu->items[i]; + if (!(((menuCommon_t *)item)->flags & QMF_HIDDEN) && (((menuCommon_t *)item)->type != MTYPE_SEPARATOR)) { + ((menuCommon_t *)item)->flags |= QMF_HASFOCUS; + if (((menuCommon_t *)item)->status) { + menu->status = ((menuCommon_t *)item)->status; + } + break; + } + } } // calc menu bounding box @@ -1963,7 +1989,7 @@ void Menu_Size(menuFrameWork_t *menu) menu->logo_rc.x = x - CURSOR_WIDTH - menu->logo_rc.width; menu->logo_rc.y = (uis.height + h) / 2 - menu->logo_rc.height; } - + // align items for (i = 0; i < menu->nitems; i++) { item = menu->items[i]; @@ -1979,6 +2005,21 @@ void Menu_Size(menuFrameWork_t *menu) } } + // footer is horizontally centered and + // positioned below all menu items + if (menu->footer) { + menu->footer_rc.x = (uis.width - menu->footer_rc.width) / 2; + + menu->footer_rc.y = y; + + if (menu->plaque) + menu->footer_rc.y = max(menu->footer_rc.y, menu->plaque_rc.y + menu->plaque_rc.height); + + if (menu->logo) + menu->footer_rc.y = max(menu->footer_rc.y, menu->logo_rc.y + menu->logo_rc.height); + + menu->footer_rc.y += menu->footer_rc.height; + } } menuCommon_t *Menu_ItemAtCursor(menuFrameWork_t *m) @@ -2123,8 +2164,6 @@ static void Menu_DrawStatus(menuFrameWork_t *menu) lens[count++] = x; - R_DrawFill8(0, menu->y2 - count * CHAR_HEIGHT, uis.width, count * CHAR_HEIGHT, 4); - for (l = 0; l < count; l++) { x = (uis.width - lens[l] * CHAR_WIDTH) / 2; y = menu->y2 - (count - l) * CHAR_HEIGHT; @@ -2172,7 +2211,10 @@ void Menu_Draw(menuFrameWork_t *menu) } if (menu->logo) { R_DrawPic(menu->logo_rc.x, menu->logo_rc.y, menu->logo); - } + } + if (menu->footer) { + R_DrawStretchPic(menu->footer_rc.x, menu->footer_rc.y, menu->footer_rc.width, menu->footer_rc.height, menu->footer); + } // // draw contents diff --git a/src/client/ui/playerconfig.c b/src/client/ui/playerconfig.c index 72d5e88fa..87020b858 100644 --- a/src/client/ui/playerconfig.c +++ b/src/client/ui/playerconfig.c @@ -35,7 +35,8 @@ typedef struct m_player_s { menuField_t name; menuSpinControl_t model; menuSpinControl_t skin; - menuSpinControl_t hand; + menuSpinControl_t hand; + menuSpinControl_t view; refdef_t refdef; entity_t entities[2]; @@ -48,6 +49,8 @@ typedef struct m_player_s { static m_player_t m_player; +extern cvar_t *vid_rtx; + static const char *handedness[] = { "right", "left", @@ -55,6 +58,19 @@ static const char *handedness[] = { 0 }; +static const char *viewmodes[] = { + "nothing", + "just the gun", + "first person model", + "third person", + 0 +}; + +static dlight_t dlights[] = { + {.origin = { -120.f, -80.f, 80.f },.color = {1.f, 1.f, 1.f},.intensity = 200.f,.radius = 20.f }, + {.origin = { 100.f, 80.f, 20.f },.color = {0.5f, 0.5f, 1.f},.intensity = 200.f,.radius = 20.f } +}; + static void ReloadMedia(void) { char scratch[MAX_QPATH]; @@ -181,6 +197,10 @@ static void Size(menuFrameWork_t *self) m_player.hand.generic.x = x; m_player.hand.generic.y = y; + y += MENU_SPACING; + + m_player.view.generic.x = x; + m_player.view.generic.y = y; } static menuSound_t Change(menuCommon_t *self) @@ -213,7 +233,9 @@ static void Pop(menuFrameWork_t *self) Cvar_SetEx("skin", scratch, FROM_CONSOLE); - Cvar_SetEx("hand", va("%d", m_player.hand.curvalue), FROM_CONSOLE); + Cvar_SetEx("hand", va("%d", m_player.hand.curvalue), FROM_CONSOLE); + + Cvar_SetEx("cl_player_model", va("%d", m_player.view.curvalue), FROM_CONSOLE); } static qboolean Push(menuFrameWork_t *self) @@ -270,6 +292,9 @@ static qboolean Push(menuFrameWork_t *self) m_player.hand.curvalue = Cvar_VariableInteger("hand"); clamp(m_player.hand.curvalue, 0, 2); + m_player.view.curvalue = Cvar_VariableInteger("cl_player_model"); + clamp(m_player.view.curvalue, 0, 3); + m_player.menu.banner = R_RegisterPic("m_banner_plauer_setup"); if (m_player.menu.banner) { R_GetPicSize(&m_player.menu.banner_rc.width, @@ -305,17 +330,30 @@ void M_Menu_PlayerConfig(void) m_player.menu.size = Size; m_player.menu.draw = Draw; m_player.menu.free = Free; - m_player.menu.image = uis.backgroundHandle; - m_player.menu.color.u32 = uis.color.background.u32; - m_player.menu.transparent = uis.transparent; + m_player.menu.image = uis.backgroundHandle; + + if (vid_rtx->integer) + { + // Q2RTX: make the player menu transparent so that we can see + // the model below: all 2D stuff is rendered after 3D, in stretch_pics. + m_player.menu.color.u32 = 0; + } + else + { + m_player.menu.color.u32 = MakeColor(0, 0, 0, 255); + } + + m_player.menu.transparent = uis.transparent; m_player.entities[0].flags = RF_FULLBRIGHT; + m_player.entities[0].id = 1; // Q2RTX: add entity id to fix motion vectors VectorCopy(angles, m_player.entities[0].angles); VectorCopy(origin, m_player.entities[0].origin); VectorCopy(origin, m_player.entities[0].oldorigin); m_player.entities[1].flags = RF_FULLBRIGHT; - VectorCopy(angles, m_player.entities[1].angles); + m_player.entities[1].id = 2; // Q2RTX: add entity id to fix motion vectors + VectorCopy(angles, m_player.entities[1].angles); VectorCopy(origin, m_player.entities[1].origin); VectorCopy(origin, m_player.entities[1].oldorigin); @@ -323,6 +361,16 @@ void M_Menu_PlayerConfig(void) m_player.refdef.entities = m_player.entities; m_player.refdef.rdflags = RDF_NOWORLDMODEL; + if (vid_rtx->integer) + { + m_player.refdef.num_dlights = sizeof(dlights) / sizeof(*dlights); + m_player.refdef.dlights = dlights; + } + else + { + m_player.refdef.num_dlights = 0; + } + m_player.name.generic.type = MTYPE_FIELD; m_player.name.generic.flags = QMF_HASFOCUS; m_player.name.generic.name = "name"; @@ -337,15 +385,20 @@ void M_Menu_PlayerConfig(void) m_player.skin.generic.id = ID_SKIN; m_player.skin.generic.name = "skin"; m_player.skin.generic.change = Change; - + m_player.hand.generic.type = MTYPE_SPINCONTROL; m_player.hand.generic.name = "handedness"; m_player.hand.itemnames = (char **)handedness; + m_player.view.generic.type = MTYPE_SPINCONTROL; + m_player.view.generic.name = "view"; + m_player.view.itemnames = (char **)viewmodes; + Menu_AddItem(&m_player.menu, &m_player.name); Menu_AddItem(&m_player.menu, &m_player.model); Menu_AddItem(&m_player.menu, &m_player.skin); - Menu_AddItem(&m_player.menu, &m_player.hand); + Menu_AddItem(&m_player.menu, &m_player.hand); + Menu_AddItem(&m_player.menu, &m_player.view); List_Append(&ui_menus, &m_player.menu.entry); } diff --git a/src/client/ui/script.c b/src/client/ui/script.c index cd5dd4738..d46e44936 100644 --- a/src/client/ui/script.c +++ b/src/client/ui/script.c @@ -1,5 +1,6 @@ /* Copyright (C) 2008 Andrey Nazarov +Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved. 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 @@ -23,7 +24,9 @@ static menuSound_t Activate(menuCommon_t *self) { switch (self->type) { case MTYPE_ACTION: - Cbuf_AddText(&cmd_buffer, ((menuAction_t *)self)->cmd); + if (strcmp(((menuAction_t *)self)->cmd, "_ignore")) { + Cbuf_AddText(&cmd_buffer, ((menuAction_t *)self)->cmd); + } break; case MTYPE_BITMAP: Cbuf_AddText(&cmd_buffer, ((menuBitmap_t *)self)->cmd); @@ -563,6 +566,45 @@ static void Parse_Banner(menuFrameWork_t *menu) } } +static void Parse_Footer(menuFrameWork_t *menu) +{ + if (Cmd_Argc() < 2) { + Com_Printf("Usage: %s