diff --git a/.gitignore b/.gitignore index 1c9a7e10..6c9b2397 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ build *.swp *tags +*~ # OS X #################### diff --git a/.travis.yml b/.travis.yml index ed9a59b5..4ee5cbc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,8 @@ +# sudo is required for travis-ci to use ubuntu trusty +# ubuntu trusty is required for libsdl2-dev +sudo: required +dist: trusty + language: c env: @@ -6,19 +11,27 @@ env: - CC=gcc - CC=clang # extra libs - - CC=gcc USE_CODEC_VORBIS=1 USE_FREETYPE=1 - - CC=clang USE_CODEC_VORBIS=1 USE_FREETYPE=1 + - CC=gcc USE_FREETYPE=1 + - CC=clang USE_FREETYPE=1 # cross-compile using mingw - - CC= PLATFORM="mingw32" ARCH="x86" - - CC= PLATFORM="mingw32" ARCH="x86_64" + # dlopen curl to workaround link error because mingw-w64 in trusty is missing strtok_r required by libcurl.a + - CC= PLATFORM="mingw32" ARCH="x86" USE_CURL_DLOPEN=1 + - CC= PLATFORM="mingw32" ARCH="x86_64" USE_CURL_DLOPEN=1 script: ./travis-ci-build.sh -before_install: - - echo "yes" | sudo apt-add-repository ppa:zoogie/sdl2-snapshots - - sudo apt-get update -qq - - sudo apt-get remove -qq -y mingw32 - - sudo apt-get install -q -y libgl1-mesa-dev libsdl2-dev libfreetype6-dev mingw-w64 - notifications: - email: false \ No newline at end of file + email: false + +addons: + apt: + packages: + - binutils-mingw-w64-i686 + - gcc-mingw-w64-i686 + - binutils-mingw-w64-x86-64 + - gcc-mingw-w64-x86-64 + - gcc-mingw-w64 + - mingw-w64 + - libgl1-mesa-dev + - libsdl2-dev + - libfreetype6-dev diff --git a/BUGS b/BUGS deleted file mode 100644 index 081c55dc..00000000 --- a/BUGS +++ /dev/null @@ -1,4 +0,0 @@ -- On Solaris/SPARC gcc optimizations higher than -O0 currently lead - to a segfault - -https://bugzilla.icculus.org/ for more. diff --git a/ChangeLog b/ChangeLog index ab963fe3..e26df8c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -634,7 +634,7 @@ #1 current directory #2 fs_homepath #3 fs_basepath - this was needed to make mod developement easier + this was needed to make mod development easier 2001-10-09 Timothee Besset + https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=51 @@ -814,7 +814,7 @@ * rebuilding 1.28b, various fixes on linux build: - SetProgramPath was renamed to Sys_SetDefaultCDPath in unix_shared.c updated unix_main.c accordingly - - some prototypes in qgl.h are guarded by #ifndef GL_VERSION_1_2 (ARB extentions) + - some prototypes in qgl.h are guarded by #ifndef GL_VERSION_1_2 (ARB extensions) those prototypes are needed by linux_glimp for importing functions and casting, added a #ifdef __linux__ (not a clean solution) - game/q_shared.h @@ -861,7 +861,7 @@ 2001-04-23 Timothee Besset * cleanup the mod selection code, remove duplicates - * some issues with release builds, my main developement box doesn't build stable binaries with release settings + * some issues with release builds, my main development box doesn't build stable binaries with release settings removing -fomit-frame-pointer seems to fix (there's probably a performance hit) see OMIT-FRAME-POINTER.txt @@ -984,7 +984,7 @@ //* or // /* or variations of this. I reverted to exact mirror image of SOS to be sure - short of removing it's too easy to mistake live code for dead one. - Later: have to change 5 occurences to avoid gcc complaints about + Later: have to change 5 occurrences to avoid gcc complaints about nested comment tokens. TODO: somebody please get rid of the cruft in here. @@ -1235,7 +1235,7 @@ * code/game/g_cmds.c (G_SayTo): CON_CONNECTED. * code/game/ai_main.c: HOOK added (SOS). * code/botlib/be_aas_move.c (AAS_HorizontalVelocityForJump): - correct fix for FPE occuring (SOS). + correct fix for FPE occurring (SOS). * code/game/ai_dmq3.c: initmove.viewoffset (SOS). * code/game/q_math.c: guard asser/isnan with Q3_VM (q3asm). @@ -1679,7 +1679,7 @@ * code/game/q_shared.c: Q_strncpyz does zero padding (duh). Note: calls strncpy, which does a zero fill up to destsize. If destsize exceeds memory size, zero padding will overwrite - adjacent memory. Suspicion was this happend to botimport. + adjacent memory. Suspicion was this happened to botimport. * code/qcommon/cvar.c: possible problem in Q_strncpyz call. @@ -1783,7 +1783,7 @@ * TEST: running with RC4 data files. TODO: "bot library used before setup" (Q3+TA) TODO: Q3 old mods wreak havoc (graceful bounce) - TODO: supress "FreeType code not available" in renderer + TODO: suppress "FreeType code not available" in renderer TODO: can't move in Q3 TODO: items flicker in Q3 TODO: no decals in Q3 @@ -2015,7 +2015,7 @@ * TEST: tried executing a script - get bounced. TODO: is there any way to jump into a map? - TODO: cl_cinematics 0 (supress all fullscreen RoQ) + TODO: cl_cinematics 0 (suppress all fullscreen RoQ) Next: used r_logfile 200 in Win32 (RC4) and Linux. There is a buckload of setup code seemingly not done at all in Linux? Either that, or logging is enabled @@ -2983,7 +2983,7 @@ Modules: code: the Q3 engine code, including a jpeg-6/ copy common: code shared by tools - libs: code shared by tools, inlcuding a jpeg6/ copy + libs: code shared by tools, including a jpeg6/ copy q3asm: VM bytecode assembly q3data: misc. Q3 data conversions q3map: BSP builder diff --git a/Makefile b/Makefile index 8c385b80..d44fa2d2 100644 --- a/Makefile +++ b/Makefile @@ -3,18 +3,12 @@ # # GNU Make required # - -COMPILE_PLATFORM=$(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]'|sed -e 's/\//_/g') - -COMPILE_ARCH=$(shell uname -m | sed -e s/i.86/x86/ | sed -e 's/^arm.*/arm/') +COMPILE_PLATFORM=$(shell uname | sed -e 's/_.*//' | tr '[:upper:]' '[:lower:]' | sed -e 's/\//_/g') +COMPILE_ARCH=$(shell uname -m | sed -e 's/i.86/x86/' | sed -e 's/^arm.*/arm/') ifeq ($(COMPILE_PLATFORM),sunos) # Solaris uname and GNU uname differ - COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/x86/) -endif -ifeq ($(COMPILE_PLATFORM),darwin) - # Apple does some things a little differently... - COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/x86/) + COMPILE_ARCH=$(shell uname -p | sed -e 's/i.86/x86/') endif ifndef BUILD_STANDALONE @@ -41,6 +35,9 @@ endif ifndef BUILD_RENDERER_OPENGL2 BUILD_RENDERER_OPENGL2= endif +ifndef BUILD_AUTOUPDATER # DON'T build unless you mean to! + BUILD_AUTOUPDATER=0 +endif ############################################################################# # @@ -179,7 +176,7 @@ ifndef USE_CURL_DLOPEN endif ifndef USE_CODEC_VORBIS -USE_CODEC_VORBIS=0 +USE_CODEC_VORBIS=1 endif ifndef USE_CODEC_OPUS @@ -230,8 +227,16 @@ ifndef USE_RENDERER_DLOPEN USE_RENDERER_DLOPEN=1 endif +ifndef USE_YACC +USE_YACC=0 +endif + +ifndef USE_AUTOUPDATER # DON'T include unless you mean to! +USE_AUTOUPDATER=0 +endif + ifndef DEBUG_CFLAGS -DEBUG_CFLAGS=-g -O0 +DEBUG_CFLAGS=-ggdb -O0 endif ############################################################################# @@ -264,6 +269,9 @@ LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg Q3CPPDIR=$(MOUNT_DIR)/tools/lcc/cpp Q3LCCETCDIR=$(MOUNT_DIR)/tools/lcc/etc Q3LCCSRCDIR=$(MOUNT_DIR)/tools/lcc/src +AUTOUPDATERSRCDIR=$(MOUNT_DIR)/autoupdater +LIBTOMCRYPTSRCDIR=$(AUTOUPDATERSRCDIR)/rsa_tools/libtomcrypt-1.17 +TOMSFASTMATHSRCDIR=$(AUTOUPDATERSRCDIR)/rsa_tools/tomsfastmath-0.13.1 LOKISETUPDIR=misc/setup NSISDIR=misc/nsis SDLHDIR=$(MOUNT_DIR)/SDL2 @@ -271,29 +279,42 @@ LIBSDIR=$(MOUNT_DIR)/libs bin_path=$(shell which $(1) 2> /dev/null) +# The autoupdater uses curl, so figure out its flags no matter what. # We won't need this if we only build the server -ifneq ($(BUILD_CLIENT),0) - # set PKG_CONFIG_PATH to influence this, e.g. - # PKG_CONFIG_PATH=/opt/cross/i386-mingw32msvc/lib/pkgconfig - ifneq ($(call bin_path, pkg-config),) - CURL_CFLAGS ?= $(shell pkg-config --silence-errors --cflags libcurl) - CURL_LIBS ?= $(shell pkg-config --silence-errors --libs libcurl) - OPENAL_CFLAGS ?= $(shell pkg-config --silence-errors --cflags openal) - OPENAL_LIBS ?= $(shell pkg-config --silence-errors --libs openal) - SDL_CFLAGS ?= $(shell pkg-config --silence-errors --cflags sdl2|sed 's/-Dmain=SDL_main//') - SDL_LIBS ?= $(shell pkg-config --silence-errors --libs sdl2) - FREETYPE_CFLAGS ?= $(shell pkg-config --silence-errors --cflags freetype2) - else - # assume they're in the system default paths (no -I or -L needed) - CURL_LIBS ?= -lcurl - OPENAL_LIBS ?= -lopenal - endif - # Use sdl2-config if all else fails - ifeq ($(SDL_CFLAGS),) - ifneq ($(call bin_path, sdl2-config),) - SDL_CFLAGS ?= $(shell sdl2-config --cflags) - SDL_LIBS ?= $(shell sdl2-config --libs) - endif + +# set PKG_CONFIG_PATH or PKG_CONFIG to influence this, e.g. +# PKG_CONFIG_PATH=/opt/cross/i386-mingw32msvc/lib/pkgconfig or +# PKG_CONFIG=arm-linux-gnueabihf-pkg-config +ifeq ($(CROSS_COMPILING),0) + PKG_CONFIG ?= pkg-config +else +ifneq ($(PKG_CONFIG_PATH),) + PKG_CONFIG ?= pkg-config +else + # Don't use host pkg-config when cross-compiling. + # (unknown-pkg-config is meant to be a non-existant command.) + PKG_CONFIG ?= unknown-pkg-config +endif +endif + +ifneq ($(call bin_path, $(PKG_CONFIG)),) + CURL_CFLAGS ?= $(shell $(PKG_CONFIG) --silence-errors --cflags libcurl) + CURL_LIBS ?= $(shell $(PKG_CONFIG) --silence-errors --libs libcurl) + OPENAL_CFLAGS ?= $(shell $(PKG_CONFIG) --silence-errors --cflags openal) + OPENAL_LIBS ?= $(shell $(PKG_CONFIG) --silence-errors --libs openal) + SDL_CFLAGS ?= $(shell $(PKG_CONFIG) --silence-errors --cflags sdl2|sed 's/-Dmain=SDL_main//') + SDL_LIBS ?= $(shell $(PKG_CONFIG) --silence-errors --libs sdl2) +else + # assume they're in the system default paths (no -I or -L needed) + CURL_LIBS ?= -lcurl + OPENAL_LIBS ?= -lopenal +endif + +# Use sdl2-config if all else fails +ifeq ($(SDL_CFLAGS),) + ifneq ($(call bin_path, sdl2-config),) + SDL_CFLAGS = $(shell sdl2-config --cflags) + SDL_LIBS = $(shell sdl2-config --libs) endif endif @@ -313,7 +334,7 @@ endif ############################################################################# INSTALL=install -MKDIR=mkdir +MKDIR=mkdir -p EXTRA_FILES= CLIENT_EXTRA_FILES= @@ -340,11 +361,11 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu") HAVE_VM_COMPILED=true else ifeq ($(ARCH),ppc) - BASE_CFLAGS += -maltivec + ALTIVEC_CFLAGS = -maltivec HAVE_VM_COMPILED=true endif ifeq ($(ARCH),ppc64) - BASE_CFLAGS += -maltivec + ALTIVEC_CFLAGS = -maltivec HAVE_VM_COMPILED=true endif ifeq ($(ARCH),sparc) @@ -352,6 +373,9 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu") OPTIMIZEVM += -mtune=ultrasparc3 -mv8plus HAVE_VM_COMPILED=true endif + ifeq ($(ARCH),armv7l) + HAVE_VM_COMPILED=true + endif ifeq ($(ARCH),alpha) # According to http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=410555 # -ffast-math will cause the client to die with SIGFPE on Alpha @@ -366,9 +390,10 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu") THREAD_LIBS=-lpthread LIBS=-ldl -lm + AUTOUPDATER_LIBS += -ldl CLIENT_LIBS=$(SDL_LIBS) - RENDERER_LIBS = $(SDL_LIBS) -lGL + RENDERER_LIBS = $(SDL_LIBS) ifeq ($(USE_OPENAL),1) ifneq ($(USE_OPENAL_DLOPEN),1) @@ -406,17 +431,35 @@ ifeq ($(PLATFORM),darwin) LIBS = -framework Cocoa CLIENT_LIBS= RENDERER_LIBS= - OPTIMIZEVM= + OPTIMIZEVM = -O3 - BASE_CFLAGS = -Wall -Wimplicit -Wstrict-prototypes -mmacosx-version-min=10.5 \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1050 -DREACTION + # Default minimum Mac OS X version + ifeq ($(MACOSX_VERSION_MIN),) + MACOSX_VERSION_MIN=10.7 + endif + + MACOSX_MAJOR=$(shell echo $(MACOSX_VERSION_MIN) | cut -d. -f1) + MACOSX_MINOR=$(shell echo $(MACOSX_VERSION_MIN) | cut -d. -f2) + ifeq ($(shell test $(MACOSX_MINOR) -gt 9; echo $$?),0) + # Multiply and then remove decimal. 10.10 -> 101000.0 -> 101000 + MAC_OS_X_VERSION_MIN_REQUIRED=$(shell echo "$(MACOSX_MAJOR) * 10000 + $(MACOSX_MINOR) * 100" | bc | cut -d. -f1) + else + # Multiply by 100 and then remove decimal. 10.7 -> 1070.0 -> 1070 + MAC_OS_X_VERSION_MIN_REQUIRED=$(shell echo "$(MACOSX_VERSION_MIN) * 100" | bc | cut -d. -f1) + endif + + LDFLAGS += -mmacosx-version-min=$(MACOSX_VERSION_MIN) + BASE_CFLAGS += -mmacosx-version-min=$(MACOSX_VERSION_MIN) \ + -DMAC_OS_X_VERSION_MIN_REQUIRED=$(MAC_OS_X_VERSION_MIN_REQUIRED) \ + -DREACTION ifeq ($(ARCH),ppc) - BASE_CFLAGS += -arch ppc -faltivec - OPTIMIZEVM += -O3 + BASE_CFLAGS += -arch ppc + ALTIVEC_CFLAGS = -faltivec endif ifeq ($(ARCH),ppc64) - BASE_CFLAGS += -arch ppc64 -faltivec + BASE_CFLAGS += -arch ppc64 + ALTIVEC_CFLAGS = -faltivec endif ifeq ($(ARCH),x86) OPTIMIZEVM += -march=prescott -mfpmath=sse @@ -425,7 +468,8 @@ ifeq ($(PLATFORM),darwin) BASE_CFLAGS += -arch i386 -m32 -mstackrealign endif ifeq ($(ARCH),x86_64) - OPTIMIZEVM += -arch x86_64 -mfpmath=sse + OPTIMIZEVM += -mfpmath=sse + BASE_CFLAGS += -arch x86_64 endif # When compiling on OSX for OSX, we're not cross compiling as far as the @@ -447,13 +491,14 @@ ifeq ($(PLATFORM),darwin) $(error Architecture $(ARCH) is not supported when cross compiling) endif endif - else - TOOLS_CFLAGS += -DMACOS_X endif - BASE_CFLAGS += -fno-strict-aliasing -DMACOS_X -fno-common -pipe + BASE_CFLAGS += -fno-strict-aliasing -fno-common -pipe ifeq ($(USE_OPENAL),1) + ifneq ($(USE_LOCAL_HEADERS),1) + CLIENT_CFLAGS += -I/System/Library/Frameworks/OpenAL.framework/Headers + endif ifneq ($(USE_OPENAL_DLOPEN),1) CLIENT_LIBS += -framework OpenAL endif @@ -468,18 +513,29 @@ ifeq ($(PLATFORM),darwin) BASE_CFLAGS += -D_THREAD_SAFE=1 - ifeq ($(USE_LOCAL_HEADERS),1) - BASE_CFLAGS += -I$(SDLHDIR)/include - endif + CLIENT_LIBS += -framework IOKit + RENDERER_LIBS += -framework OpenGL - # We copy sdlmain before ranlib'ing it so that subversion doesn't think - # the file has been modified by each build. - LIBSDLMAIN=$(B)/libSDL2main.a - LIBSDLMAINSRC=$(LIBSDIR)/macosx/libSDL2main.a - CLIENT_LIBS += -framework IOKit \ - $(LIBSDIR)/macosx/libSDL2-2.0.0.dylib - RENDERER_LIBS += -framework OpenGL $(LIBSDIR)/macosx/libSDL2-2.0.0.dylib - CLIENT_EXTRA_FILES += $(LIBSDIR)/macosx/libSDL2-2.0.0.dylib + ifeq ($(USE_LOCAL_HEADERS),1) + # libSDL2-2.0.0.dylib for PPC is SDL 2.0.1 + changes to compile + ifneq ($(findstring $(ARCH),ppc ppc64),) + BASE_CFLAGS += -I$(SDLHDIR)/include-macppc + else + BASE_CFLAGS += -I$(SDLHDIR)/include + endif + + # We copy sdlmain before ranlib'ing it so that subversion doesn't think + # the file has been modified by each build. + LIBSDLMAIN=$(B)/libSDL2main.a + LIBSDLMAINSRC=$(LIBSDIR)/macosx/libSDL2main.a + CLIENT_LIBS += $(LIBSDIR)/macosx/libSDL2-2.0.0.dylib + RENDERER_LIBS += $(LIBSDIR)/macosx/libSDL2-2.0.0.dylib + CLIENT_EXTRA_FILES += $(LIBSDIR)/macosx/libSDL2-2.0.0.dylib + else + BASE_CFLAGS += -I/Library/Frameworks/SDL2.framework/Headers + CLIENT_LIBS += -framework SDL2 + RENDERER_LIBS += -framework SDL2 + endif OPTIMIZE = $(OPTIMIZEVM) -ffast-math @@ -507,20 +563,20 @@ ifdef MINGW # We need to figure out the correct gcc and windres ifeq ($(ARCH),x86_64) - MINGW_PREFIXES=amd64-mingw32msvc x86_64-w64-mingw32 + MINGW_PREFIXES=x86_64-w64-mingw32 amd64-mingw32msvc endif ifeq ($(ARCH),x86) - MINGW_PREFIXES=i586-mingw32msvc i686-w64-mingw32 i686-pc-mingw32 + MINGW_PREFIXES=i686-w64-mingw32 i586-mingw32msvc i686-pc-mingw32 endif ifndef CC - CC=$(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \ - $(call bin_path, $(MINGW_PREFIX)-gcc))) + CC=$(firstword $(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \ + $(call bin_path, $(MINGW_PREFIX)-gcc)))) endif ifndef WINDRES - WINDRES=$(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \ - $(call bin_path, $(MINGW_PREFIX)-windres))) + WINDRES=$(firstword $(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \ + $(call bin_path, $(MINGW_PREFIX)-windres)))) endif else # Some MinGW installations define CC to cc, but don't actually provide cc, @@ -529,9 +585,11 @@ ifdef MINGW CC=gcc endif - ifndef WINDRES - WINDRES=windres - endif + endif + + # using generic windres if specific one is not present + ifndef WINDRES + WINDRES=windres endif ifeq ($(CC),) @@ -580,12 +638,14 @@ ifdef MINGW endif LIBS= -lws2_32 -lwinmm -lpsapi + AUTOUPDATER_LIBS += -lwininet + # clang 3.4 doesn't support this ifneq ("$(CC)", $(findstring "$(CC)", "clang" "clang++")) CLIENT_LDFLAGS += -mwindows endif CLIENT_LIBS = -lgdi32 -lole32 - RENDERER_LIBS = -lgdi32 -lole32 -lopengl32 + RENDERER_LIBS = -lgdi32 -lole32 -static-libgcc ifeq ($(USE_FREETYPE),1) FREETYPE_CFLAGS = -Ifreetype2 @@ -597,9 +657,9 @@ ifdef MINGW ifeq ($(USE_LOCAL_HEADERS),1) CLIENT_CFLAGS += -DCURL_STATICLIB ifeq ($(ARCH),x86_64) - CLIENT_LIBS += $(LIBSDIR)/win64/libcurl.a + CLIENT_LIBS += $(LIBSDIR)/win64/libcurl.a -lcrypt32 else - CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a + CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a -lcrypt32 endif else CLIENT_LIBS += $(CURL_LIBS) @@ -651,13 +711,13 @@ else # ifdef MINGW ifeq ($(PLATFORM),freebsd) # flags - BASE_CFLAGS = $(shell env MACHINE_ARCH=$(ARCH) make -f /dev/null -VCFLAGS) \ + BASE_CFLAGS = \ -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ -DUSE_ICON -DMAP_ANONYMOUS=MAP_ANON -DREACTION CLIENT_CFLAGS += $(SDL_CFLAGS) HAVE_VM_COMPILED = true - OPTIMIZEVM = -O3 + OPTIMIZEVM = OPTIMIZE = $(OPTIMIZEVM) -ffast-math SHLIBEXT=so @@ -671,7 +731,7 @@ ifeq ($(PLATFORM),freebsd) CLIENT_LIBS = CLIENT_LIBS += $(SDL_LIBS) - RENDERER_LIBS = $(SDL_LIBS) -lGL + RENDERER_LIBS = $(SDL_LIBS) # optional features/libraries ifeq ($(USE_OPENAL),1) @@ -724,11 +784,11 @@ ifeq ($(PLATFORM),openbsd) HAVE_VM_COMPILED=true else ifeq ($(ARCH),ppc) - BASE_CFLAGS += -maltivec + ALTIVEC_CFLAGS = -maltivec HAVE_VM_COMPILED=true endif ifeq ($(ARCH),ppc64) - BASE_CFLAGS += -maltivec + ALTIVEC_CFLAGS = -maltivec HAVE_VM_COMPILED=true endif ifeq ($(ARCH),sparc64) @@ -762,7 +822,7 @@ ifeq ($(PLATFORM),openbsd) CLIENT_LIBS = CLIENT_LIBS += $(SDL_LIBS) - RENDERER_LIBS = $(SDL_LIBS) -lGL + RENDERER_LIBS = $(SDL_LIBS) ifeq ($(USE_OPENAL),1) ifneq ($(USE_OPENAL_DLOPEN),1) @@ -808,7 +868,6 @@ ifeq ($(PLATFORM),irix64) ARCH=mips CC = c99 - MKDIR = mkdir -p BASE_CFLAGS=-Dstricmp=strcasecmp -Xcpluscomm -woff 1185 \ -I. -I$(ROOT)/usr/include -DREACTION @@ -820,10 +879,12 @@ ifeq ($(PLATFORM),irix64) SHLIBLDFLAGS=-shared LIBS=-ldl -lm -lgen + AUTOUPDATER_LIBS += -ldl + # FIXME: The X libraries probably aren't necessary? CLIENT_LIBS=-L/usr/X11/$(LIB) $(SDL_LIBS) \ -lX11 -lXext -lm - RENDERER_LIBS = $(SDL_LIBS) -lGL + RENDERER_LIBS = $(SDL_LIBS) else # ifeq IRIX @@ -835,7 +896,7 @@ ifeq ($(PLATFORM),sunos) CC=gcc INSTALL=ginstall - MKDIR=gmkdir + MKDIR=gmkdir -p COPYDIR="/usr/local/share/games/quake3" ifneq ($(ARCH),x86) @@ -874,11 +935,12 @@ ifeq ($(PLATFORM),sunos) THREAD_LIBS=-lpthread LIBS=-lsocket -lnsl -ldl -lm + AUTOUPDATER_LIBS += -ldl BOTCFLAGS=-O0 CLIENT_LIBS +=$(SDL_LIBS) -lX11 -lXext -liconv -lm - RENDERER_LIBS = $(SDL_LIBS) -lGL + RENDERER_LIBS = $(SDL_LIBS) else # ifeq sunos @@ -972,6 +1034,16 @@ ifneq ($(BUILD_GAME_QVM),0) endif endif +ifneq ($(BUILD_AUTOUPDATER),0) + # PLEASE NOTE that if you run an exe on Windows Vista or later + # with "setup", "install", "update" or other related terms, it + # will unconditionally trigger a UAC prompt, and in the case of + # ioq3 calling CreateProcess() on it, it'll just fail immediately. + # So don't call this thing "autoupdater" here! + AUTOUPDATER_BIN := autosyncerator$(FULLBINEXT) + TARGETS += $(B)/$(AUTOUPDATER_BIN) +endif + ifeq ($(USE_OPENAL),1) CLIENT_CFLAGS += -DUSE_OPENAL ifeq ($(USE_OPENAL_DLOPEN),1) @@ -1003,8 +1075,8 @@ ifeq ($(NEED_OPUS),1) -I$(OPUSDIR)/include -I$(OPUSDIR)/celt -I$(OPUSDIR)/silk \ -I$(OPUSDIR)/silk/float -I$(OPUSFILEDIR)/include else - OPUS_CFLAGS ?= $(shell pkg-config --silence-errors --cflags opusfile opus || true) - OPUS_LIBS ?= $(shell pkg-config --silence-errors --libs opusfile opus || echo -lopusfile -lopus) + OPUS_CFLAGS ?= $(shell $(PKG_CONFIG) --silence-errors --cflags opusfile opus || true) + OPUS_LIBS ?= $(shell $(PKG_CONFIG) --silence-errors --libs opusfile opus || echo -lopusfile -lopus) endif CLIENT_CFLAGS += $(OPUS_CFLAGS) CLIENT_LIBS += $(OPUS_LIBS) @@ -1016,8 +1088,8 @@ ifeq ($(USE_CODEC_VORBIS),1) ifeq ($(USE_INTERNAL_VORBIS),1) CLIENT_CFLAGS += -I$(VORBISDIR)/include -I$(VORBISDIR)/lib else - VORBIS_CFLAGS ?= $(shell pkg-config --silence-errors --cflags vorbisfile vorbis || true) - VORBIS_LIBS ?= $(shell pkg-config --silence-errors --libs vorbisfile vorbis || echo -lvorbisfile -lvorbis) + VORBIS_CFLAGS ?= $(shell $(PKG_CONFIG) --silence-errors --cflags vorbisfile vorbis || true) + VORBIS_LIBS ?= $(shell $(PKG_CONFIG) --silence-errors --libs vorbisfile vorbis || echo -lvorbisfile -lvorbis) endif CLIENT_CFLAGS += $(VORBIS_CFLAGS) CLIENT_LIBS += $(VORBIS_LIBS) @@ -1028,8 +1100,8 @@ ifeq ($(NEED_OGG),1) ifeq ($(USE_INTERNAL_OGG),1) OGG_CFLAGS = -I$(OGGDIR)/include else - OGG_CFLAGS ?= $(shell pkg-config --silence-errors --cflags ogg || true) - OGG_LIBS ?= $(shell pkg-config --silence-errors --libs ogg || echo -logg) + OGG_CFLAGS ?= $(shell $(PKG_CONFIG) --silence-errors --cflags ogg || true) + OGG_LIBS ?= $(shell $(PKG_CONFIG) --silence-errors --libs ogg || echo -logg) endif CLIENT_CFLAGS += $(OGG_CFLAGS) CLIENT_LIBS += $(OGG_LIBS) @@ -1046,8 +1118,8 @@ endif ifeq ($(USE_INTERNAL_ZLIB),1) ZLIB_CFLAGS = -DNO_GZIP -I$(ZDIR) else - ZLIB_CFLAGS ?= $(shell pkg-config --silence-errors --cflags zlib || true) - ZLIB_LIBS ?= $(shell pkg-config --silence-errors --libs zlib || echo -lz) + ZLIB_CFLAGS ?= $(shell $(PKG_CONFIG) --silence-errors --cflags zlib || true) + ZLIB_LIBS ?= $(shell $(PKG_CONFIG) --silence-errors --libs zlib || echo -lz) endif BASE_CFLAGS += $(ZLIB_CFLAGS) LIBS += $(ZLIB_LIBS) @@ -1058,20 +1130,29 @@ ifeq ($(USE_INTERNAL_JPEG),1) else # IJG libjpeg doesn't have pkg-config, but libjpeg-turbo uses libjpeg.pc; # we fall back to hard-coded answers if libjpeg.pc is unavailable - JPEG_CFLAGS ?= $(shell pkg-config --silence-errors --cflags libjpeg || true) - JPEG_LIBS ?= $(shell pkg-config --silence-errors --libs libjpeg || echo -ljpeg) + JPEG_CFLAGS ?= $(shell $(PKG_CONFIG) --silence-errors --cflags libjpeg || true) + JPEG_LIBS ?= $(shell $(PKG_CONFIG) --silence-errors --libs libjpeg || echo -ljpeg) BASE_CFLAGS += $(JPEG_CFLAGS) RENDERER_LIBS += $(JPEG_LIBS) endif ifeq ($(USE_FREETYPE),1) - FREETYPE_CFLAGS ?= $(shell pkg-config --silence-errors --cflags freetype2 || true) - FREETYPE_LIBS ?= $(shell pkg-config --silence-errors --libs freetype2 || echo -lfreetype) + FREETYPE_CFLAGS ?= $(shell $(PKG_CONFIG) --silence-errors --cflags freetype2 || true) + FREETYPE_LIBS ?= $(shell $(PKG_CONFIG) --silence-errors --libs freetype2 || echo -lfreetype) BASE_CFLAGS += -DBUILD_FREETYPE $(FREETYPE_CFLAGS) RENDERER_LIBS += $(FREETYPE_LIBS) endif +ifeq ($(USE_AUTOUPDATER),1) + CLIENT_CFLAGS += -DUSE_AUTOUPDATER -DAUTOUPDATER_BIN=\\\"$(AUTOUPDATER_BIN)\\\" + SERVER_CFLAGS += -DUSE_AUTOUPDATER -DAUTOUPDATER_BIN=\\\"$(AUTOUPDATER_BIN)\\\" +endif + +ifeq ($(BUILD_AUTOUPDATER),1) + AUTOUPDATER_LIBS += $(LIBTOMCRYPTSRCDIR)/libtomcrypt.a $(TOMSFASTMATHSRCDIR)/libtfm.a +endif + ifeq ("$(CC)", $(findstring "$(CC)", "clang" "clang++")) BASE_CFLAGS += -Qunused-arguments endif @@ -1100,6 +1181,11 @@ else STRIP_FLAG = -s endif +# https://reproducible-builds.org/specs/source-date-epoch/ +ifdef SOURCE_DATE_EPOCH + BASE_CFLAGS += -DPRODUCT_DATE=\\\"$(shell date --date="@$$SOURCE_DATE_EPOCH" "+%b %_d %Y" | sed -e 's/ /\\\ /'g)\\\" +endif + BASE_CFLAGS += -DPRODUCT_VERSION=\\\"$(VERSION)\\\" BASE_CFLAGS += -Wformat=2 -Wno-format-zero-length -Wformat-security -Wno-format-nonliteral BASE_CFLAGS += -Wstrict-aliasing=2 -Wmissing-format-attribute @@ -1119,16 +1205,26 @@ $(echo_cmd) "CC $<" $(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(CLIENT_CFLAGS) $(OPTIMIZE) -o $@ -c $< endef +define DO_CC_ALTIVEC +$(echo_cmd) "CC $<" +$(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(CLIENT_CFLAGS) $(OPTIMIZE) $(ALTIVEC_CFLAGS) -o $@ -c $< +endef + define DO_REF_CC $(echo_cmd) "REF_CC $<" $(Q)$(CC) $(SHLIBCFLAGS) $(CFLAGS) $(CLIENT_CFLAGS) $(OPTIMIZE) -o $@ -c $< endef +define DO_REF_CC_ALTIVEC +$(echo_cmd) "REF_CC $<" +$(Q)$(CC) $(SHLIBCFLAGS) $(CFLAGS) $(CLIENT_CFLAGS) $(OPTIMIZE) $(ALTIVEC_CFLAGS) -o $@ -c $< +endef + define DO_REF_STR $(echo_cmd) "REF_STR $<" $(Q)rm -f $@ $(Q)echo "const char *fallbackShader_$(notdir $(basename $<)) =" >> $@ -$(Q)cat $< | sed 's/^/\"/;s/$$/\\n\"/' >> $@ +$(Q)cat $< | sed -e 's/^/\"/;s/$$/\\n\"/' | tr -d '\r' >> $@ $(Q)echo ";" >> $@ endef @@ -1274,6 +1370,8 @@ targets: makedirs @echo " VERSION: $(VERSION)" @echo " COMPILE_PLATFORM: $(COMPILE_PLATFORM)" @echo " COMPILE_ARCH: $(COMPILE_ARCH)" + @echo " HAVE_VM_COMPILED: $(HAVE_VM_COMPILED)" + @echo " PKG_CONFIG: $(PKG_CONFIG)" @echo " CC: $(CC)" ifeq ($(PLATFORM),mingw32) @echo " WINDRES: $(WINDRES)" @@ -1297,6 +1395,9 @@ endif @echo " CLIENT_LIBS:" $(call print_wrapped, $(CLIENT_LIBS)) @echo "" + @echo " AUTOUPDATER_LIBS:" + $(call print_wrapped, $(AUTOUPDATER_LIBS)) + @echo "" @echo " Output:" $(call print_list, $(NAKED_TARGETS)) @echo "" @@ -1320,33 +1421,28 @@ ifneq ($(PLATFORM),darwin) endif makedirs: - @if [ ! -d $(BUILD_DIR) ];then $(MKDIR) $(BUILD_DIR);fi - @if [ ! -d $(B) ];then $(MKDIR) $(B);fi - @if [ ! -d $(B)/client ];then $(MKDIR) $(B)/client;fi - @if [ ! -d $(B)/client/opus ];then $(MKDIR) $(B)/client/opus;fi - @if [ ! -d $(B)/client/vorbis ];then $(MKDIR) $(B)/client/vorbis;fi - @if [ ! -d $(B)/renderergl1 ];then $(MKDIR) $(B)/renderergl1;fi - @if [ ! -d $(B)/renderergl2 ];then $(MKDIR) $(B)/renderergl2;fi - @if [ ! -d $(B)/renderergl2/glsl ];then $(MKDIR) $(B)/renderergl2/glsl;fi - @if [ ! -d $(B)/ded ];then $(MKDIR) $(B)/ded;fi - @if [ ! -d $(B)/$(BASEGAME) ];then $(MKDIR) $(B)/$(BASEGAME);fi - @if [ ! -d $(B)/$(BASEGAME)/cgame ];then $(MKDIR) $(B)/$(BASEGAME)/cgame;fi - @if [ ! -d $(B)/$(BASEGAME)/game ];then $(MKDIR) $(B)/$(BASEGAME)/game;fi - @if [ ! -d $(B)/$(BASEGAME)/ui ];then $(MKDIR) $(B)/$(BASEGAME)/ui;fi - @if [ ! -d $(B)/$(BASEGAME)/qcommon ];then $(MKDIR) $(B)/$(BASEGAME)/qcommon;fi - @if [ ! -d $(B)/$(BASEGAME)/vm ];then $(MKDIR) $(B)/$(BASEGAME)/vm;fi - @if [ ! -d $(B)/$(MISSIONPACK) ];then $(MKDIR) $(B)/$(MISSIONPACK);fi - @if [ ! -d $(B)/$(MISSIONPACK)/cgame ];then $(MKDIR) $(B)/$(MISSIONPACK)/cgame;fi - @if [ ! -d $(B)/$(MISSIONPACK)/game ];then $(MKDIR) $(B)/$(MISSIONPACK)/game;fi - @if [ ! -d $(B)/$(MISSIONPACK)/ui ];then $(MKDIR) $(B)/$(MISSIONPACK)/ui;fi - @if [ ! -d $(B)/$(MISSIONPACK)/qcommon ];then $(MKDIR) $(B)/$(MISSIONPACK)/qcommon;fi - @if [ ! -d $(B)/$(MISSIONPACK)/vm ];then $(MKDIR) $(B)/$(MISSIONPACK)/vm;fi - @if [ ! -d $(B)/tools ];then $(MKDIR) $(B)/tools;fi - @if [ ! -d $(B)/tools/asm ];then $(MKDIR) $(B)/tools/asm;fi - @if [ ! -d $(B)/tools/etc ];then $(MKDIR) $(B)/tools/etc;fi - @if [ ! -d $(B)/tools/rcc ];then $(MKDIR) $(B)/tools/rcc;fi - @if [ ! -d $(B)/tools/cpp ];then $(MKDIR) $(B)/tools/cpp;fi - @if [ ! -d $(B)/tools/lburg ];then $(MKDIR) $(B)/tools/lburg;fi + @$(MKDIR) $(B)/autoupdater + @$(MKDIR) $(B)/client/opus + @$(MKDIR) $(B)/client/vorbis + @$(MKDIR) $(B)/renderergl1 + @$(MKDIR) $(B)/renderergl2 + @$(MKDIR) $(B)/renderergl2/glsl + @$(MKDIR) $(B)/ded + @$(MKDIR) $(B)/$(BASEGAME)/cgame + @$(MKDIR) $(B)/$(BASEGAME)/game + @$(MKDIR) $(B)/$(BASEGAME)/ui + @$(MKDIR) $(B)/$(BASEGAME)/qcommon + @$(MKDIR) $(B)/$(BASEGAME)/vm + @$(MKDIR) $(B)/$(MISSIONPACK)/cgame + @$(MKDIR) $(B)/$(MISSIONPACK)/game + @$(MKDIR) $(B)/$(MISSIONPACK)/ui + @$(MKDIR) $(B)/$(MISSIONPACK)/qcommon + @$(MKDIR) $(B)/$(MISSIONPACK)/vm + @$(MKDIR) $(B)/tools/asm + @$(MKDIR) $(B)/tools/etc + @$(MKDIR) $(B)/tools/rcc + @$(MKDIR) $(B)/tools/cpp + @$(MKDIR) $(B)/tools/lburg ############################################################################# # QVM BUILD TOOLS @@ -1357,6 +1453,10 @@ ifndef TOOLS_CC TOOLS_CC = gcc endif +ifndef YACC + YACC = yacc +endif + TOOLS_OPTIMIZE = -g -Wall -fno-strict-aliasing TOOLS_CFLAGS += $(TOOLS_OPTIMIZE) \ -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \ @@ -1369,6 +1469,12 @@ ifeq ($(GENERATE_DEPENDENCIES),1) TOOLS_CFLAGS += -MMD endif +define DO_YACC +$(echo_cmd) "YACC $<" +$(Q)$(YACC) $< +$(Q)mv -f y.tab.c $@ +endef + define DO_TOOLS_CC $(echo_cmd) "TOOLS_CC $<" $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) -o $@ -c $< @@ -1390,6 +1496,12 @@ LBURGOBJ= \ $(B)/tools/lburg/lburg.o \ $(B)/tools/lburg/gram.o +# override GNU Make built-in rule for converting gram.y to gram.c +%.c: %.y +ifeq ($(USE_YACC),1) + $(DO_YACC) +endif + $(B)/tools/lburg/%.o: $(LBURGDIR)/%.c $(DO_TOOLS_CC) @@ -1525,6 +1637,26 @@ $(Q3ASM): $(Q3ASMOBJ) $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS) +############################################################################# +# AUTOUPDATER +############################################################################# + +define DO_AUTOUPDATER_CC +$(echo_cmd) "AUTOUPDATER_CC $<" +$(Q)$(CC) $(CFLAGS) -I$(LIBTOMCRYPTSRCDIR)/src/headers -I$(TOMSFASTMATHSRCDIR)/src/headers $(CURL_CFLAGS) -o $@ -c $< +endef + +Q3AUTOUPDATEROBJ = \ + $(B)/autoupdater/autoupdater.o + +$(B)/autoupdater/%.o: $(AUTOUPDATERSRCDIR)/%.c + $(DO_AUTOUPDATER_CC) + +$(B)/$(AUTOUPDATER_BIN): $(Q3AUTOUPDATEROBJ) + $(echo_cmd) "AUTOUPDATER_LD $@" + $(Q)$(CC) $(LDFLAGS) -o $@ $(Q3AUTOUPDATEROBJ) $(AUTOUPDATER_LIBS) + + ############################################################################# # CLIENT/SERVER ############################################################################# @@ -1559,6 +1691,7 @@ Q3OBJ = \ $(B)/client/net_ip.o \ $(B)/client/huffman.o \ \ + $(B)/client/snd_altivec.o \ $(B)/client/snd_adpcm.o \ $(B)/client/snd_dma.o \ $(B)/client/snd_mem.o \ @@ -1628,6 +1761,7 @@ Q3OBJ = \ $(B)/client/sdl_snd.o \ \ $(B)/client/con_log.o \ + $(B)/client/sys_autoupdater.o \ $(B)/client/sys_main.o ifdef MINGW @@ -1711,6 +1845,7 @@ Q3R2STRINGOBJ = \ $(B)/renderergl2/glsl/tonemap_vp.o Q3ROBJ = \ + $(B)/renderergl1/tr_altivec.o \ $(B)/renderergl1/tr_animation.o \ $(B)/renderergl1/tr_backend.o \ $(B)/renderergl1/tr_bsp.o \ @@ -2026,6 +2161,9 @@ ifeq ($(HAVE_VM_COMPILED),true) ifeq ($(ARCH),sparc) Q3OBJ += $(B)/client/vm_sparc.o endif + ifeq ($(ARCH),armv7l) + Q3OBJ += $(B)/client/vm_armv7l.o + endif endif ifdef MINGW @@ -2050,7 +2188,7 @@ endif ifneq ($(USE_RENDERER_DLOPEN),0) $(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(LIBSDLMAIN) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \ + $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(NOTSHLIBLDFLAGS) \ -o $@ $(Q3OBJ) \ $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS) @@ -2066,13 +2204,13 @@ $(B)/renderer_opengl2_$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) else $(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(Q3ROBJ) $(JPGOBJ) $(LIBSDLMAIN) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \ + $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(NOTSHLIBLDFLAGS) \ -o $@ $(Q3OBJ) $(Q3ROBJ) $(JPGOBJ) \ $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS) $(B)/$(CLIENTBIN)_opengl2$(FULLBINEXT): $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) $(LIBSDLMAIN) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \ + $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(NOTSHLIBLDFLAGS) \ -o $@ $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \ $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS) endif @@ -2159,6 +2297,7 @@ Q3DOBJ = \ $(B)/ded/null_snddma.o \ \ $(B)/ded/con_log.o \ + $(B)/ded/sys_autoupdater.o \ $(B)/ded/sys_main.o ifeq ($(ARCH),x86) @@ -2194,6 +2333,9 @@ ifeq ($(HAVE_VM_COMPILED),true) ifeq ($(ARCH),sparc) Q3DOBJ += $(B)/ded/vm_sparc.o endif + ifeq ($(ARCH),armv7l) + Q3DOBJ += $(B)/client/vm_armv7l.o + endif endif ifdef MINGW @@ -2214,7 +2356,7 @@ endif $(B)/$(SERVERBIN)$(FULLBINEXT): $(Q3DOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(Q3DOBJ) $(LIBS) + $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(NOTSHLIBLDFLAGS) -o $@ $(Q3DOBJ) $(LIBS) @@ -2490,6 +2632,9 @@ $(B)/client/%.o: $(ASMDIR)/%.s $(B)/client/%.o: $(ASMDIR)/%.c $(DO_CC) -march=k8 +$(B)/client/snd_altivec.o: $(CDIR)/snd_altivec.c + $(DO_CC_ALTIVEC) + $(B)/client/%.o: $(CDIR)/%.c $(DO_CC) @@ -2535,7 +2680,7 @@ $(B)/client/%.o: $(SYSDIR)/%.c $(B)/client/%.o: $(SYSDIR)/%.m $(DO_CC) -$(B)/client/%.o: $(SYSDIR)/%.rc +$(B)/client/win_resource.o: $(SYSDIR)/win_resource.rc $(SYSDIR)/win_manifest.xml $(DO_WINDRES) @@ -2554,6 +2699,9 @@ $(B)/renderergl1/%.o: $(RCOMMONDIR)/%.c $(B)/renderergl1/%.o: $(RGL1DIR)/%.c $(DO_REF_CC) +$(B)/renderergl1/tr_altivec.o: $(RGL1DIR)/tr_altivec.c + $(DO_REF_CC_ALTIVEC) + $(B)/renderergl2/glsl/%.c: $(RGL2DIR)/glsl/%.glsl $(DO_REF_STR) @@ -2592,7 +2740,7 @@ $(B)/ded/%.o: $(SYSDIR)/%.c $(B)/ded/%.o: $(SYSDIR)/%.m $(DO_DED_CC) -$(B)/ded/%.o: $(SYSDIR)/%.rc +$(B)/ded/win_resource.o: $(SYSDIR)/win_resource.rc $(SYSDIR)/win_manifest.xml $(DO_WINDRES) $(B)/ded/%.o: $(NDIR)/%.c @@ -2600,9 +2748,9 @@ $(B)/ded/%.o: $(NDIR)/%.c # Extra dependencies to ensure the git version is incorporated ifeq ($(USE_GIT),1) - $(B)/client/cl_console.o : .git/index - $(B)/client/common.o : .git/index - $(B)/ded/common.o : .git/index + $(B)/client/cl_console.o : .git + $(B)/client/common.o : .git + $(B)/ded/common.o : .git endif @@ -2701,10 +2849,10 @@ copyfiles: release @if [ ! -d $(COPYDIR)/$(BASEGAME) ]; then echo "You need to set COPYDIR to where your Quake3 data is!"; fi ifneq ($(BUILD_GAME_SO),0) ifneq ($(BUILD_BASEGAME),0) - -$(MKDIR) -p -m 0755 $(COPYDIR)/$(BASEGAME) + -$(MKDIR) -m 0755 $(COPYDIR)/$(BASEGAME) endif ifneq ($(BUILD_MISSIONPACK),0) - -$(MKDIR) -p -m 0755 $(COPYDIR)/$(MISSIONPACK) + -$(MKDIR) -m 0755 $(COPYDIR)/$(MISSIONPACK) endif endif diff --git a/Makefile.local b/Makefile.local index 133d0db4..fb4d30be 100644 --- a/Makefile.local +++ b/Makefile.local @@ -1,10 +1,9 @@ BUILD_STANDALONE = 1 BUILD_CLIENT = 1 -BUILD_CLIENT_SMP = 1 BUILD_SERVER = 1 BUILD_GAME_SO = 1 BUILD_GAME_QVM = 1 BUILD_MISSIONPACK = 0 USE_RENDERER_DLOPEN = 1 -BUILD_RENDERER_REND2 = 1 +BUILD_RENDERER_OPENGL2 = 1 diff --git a/NOTTODO b/NOTTODO deleted file mode 100644 index 0db15474..00000000 --- a/NOTTODO +++ /dev/null @@ -1 +0,0 @@ -http://wiki.ioquake3.org/NotToDo diff --git a/README.md b/README.md index 426e5c95..5e16a3da 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The intent of this project is to provide a baseline Quake 3 which may be used for further development and baseq3 fun. Some of the major features currently implemented are: - * SDL backend + * SDL 2 backend * OpenAL sound API support (multiple speaker support and better sound quality) * Full x86_64 support on Linux @@ -36,11 +36,15 @@ use a modern copy from http://icculus.org/gtkradiant/. The original id software readme that accompanied the Q3 source release has been renamed to id-readme.txt so as to prevent confusion. Please refer to the -web-site for updated status. +website for updated status. -More documentation is on: +More documentation including a Player's Guide and Sysadmin Guide is on: http://wiki.ioquake3.org/ +If you've got issues that you aren't sure are worth filing as bugs, or just +want to chat, please visit our forums: +http://discourse.ioquake.org + # Compilation and installation For *nix @@ -89,6 +93,7 @@ Makefile.local: SERVERBIN - rename 'ioq3ded' server binary CLIENTBIN - rename 'ioquake3' client binary USE_RENDERER_DLOPEN - build and use the renderer in a library + USE_YACC - use yacc to update code/tools/lcc/lburg/gram.c BASEGAME - rename 'baseq3' BASEGAME_CFLAGS - custom CFLAGS for basegame MISSIONPACK - rename 'missionpack' @@ -101,13 +106,11 @@ Makefile.local: USE_CODEC_OPUS - enable Ogg Opus support USE_MUMBLE - enable Mumble support USE_VOIP - enable built-in VoIP support + USE_FREETYPE - enable FreeType support for rendering fonts USE_INTERNAL_LIBS - build internal libraries instead of dynamically linking against system libraries; this just sets - the default for USE_INTERNAL_SPEEX etc. + the default for USE_INTERNAL_ZLIB etc. and USE_LOCAL_HEADERS - USE_INTERNAL_SPEEX - build internal speex library instead of dynamically - linking against system libspeex - USE_FREETYPE - enable FreeType support for rendering fonts USE_INTERNAL_ZLIB - build and link against internal zlib USE_INTERNAL_JPEG - build and link against internal JPEG library USE_INTERNAL_OGG - build and link against internal ogg library @@ -137,6 +140,12 @@ The defaults for these variables differ depending on the target platform. behaviour, 0 for standard q3 cl_mouseAccelOffset - Tuning the acceleration curve, see below + con_autochat - Set to 0 to disable sending console input + text as chat when there is not a slash + at the beginning + con_autoclear - Set to 0 to disable clearing console + input text when console is closed + in_joystickUseAnalog - Do not translate joystick axis events to keyboard commands @@ -244,7 +253,7 @@ The defaults for these variables differ depending on the target platform. ipv6 servers on the local network net_mcastiface - outgoing interface to use for scan - r_allowResize - make window resizable (SDL only) + r_allowResize - make window resizable r_ext_texture_filter_anisotropic - anisotropic texture filtering r_zProj - distance of observer camera to projection plane in quake3 standard units @@ -324,6 +333,8 @@ The defaults for these variables differ depending on the target platform. cvar_modified [filter] - list modified cvars, can filter results (such as "r*" for renderer cvars) like cvarlist which lists all cvars + + addbot random - the bot name "random" now selects a random bot ``` @@ -480,6 +491,7 @@ The focus for ioq3 is to develop a stable base suitable for further development and provide players with the same Quake 3 experience they've had for years. We do have graphical improvements with the new renderer, but they are off by default. +See opengl2-readme.md for more information. # Building Official Installers @@ -502,13 +514,11 @@ but we have some general guidelines: providing pak0.pk3 and the patch pk3s are not referred to or included in the installer. - * Please include at least an SDL so/dylib/dll on every platform. + * Please include at least a libSDL2 so/dylib/dll on every platform. * Please include an OpenAL so/dylib/dll, since every platform should be using it by now. - * Please contact the mailing list when you've made your installer. - * Please be prepared to alter your installer on the whim of the maintainers. * Your installer will be mirrored to an "official" directory, thus making it diff --git a/autoupdater-readme.txt b/autoupdater-readme.txt new file mode 100644 index 00000000..34561b7c --- /dev/null +++ b/autoupdater-readme.txt @@ -0,0 +1,165 @@ +The updater program's code is public domain. The rest of ioquake3 is not. + +The source code to the autoupdater is in the code/autoupdater directory. +There is a small piece of code in ioquake3 itself at startup, too; this is +in code/sys/sys_autoupdater.c ... + +(This is all Unix terminology, but similar approaches on Windows apply.) + +The updater is a separate program, written in C, with no dependencies on +the game. It (statically) links to libcurl and uses the C runtime, but +otherwise has no external dependencies. It has to be a single binary file +with no shared libraries. + +The basic flow looks like this: + +- The game launches as usual. +- Right after main() starts, the game creates a pipe, forks off a new process, + and execs the updater in that process. The game won't ever touch the pipe + again. It's just there to block the child app until the game terminates. +- The updater has no UI. It writes a log file. +- The updater downloads a manifest from a known URL over https://, using + libCurl. The base URL is platform-specific (it might be + https://example.com/mac/, or https://example.com/linux-x86/, whatever). + The url might have other features, like a updater version or a specific + product name, etc. + The manifest is at $BASEURL/manifest.txt +- The updater also downloads $BASEURL/manifest.txt.sig, which is a digital + signature for the manifest. It checks the manifest against this signature + and a known public RSA key; if the manifest doesn't match the signature, + the updater refuses to continue. +- The manifest looks like this: three lines per item... + +Contents/MacOS/baseq3/uix86_64.dylib +332428 +a49bbe77f8eb6c195265ea136f881f7830db58e4d8a883b27f59e1e23e396a20 + +- That's the file's path, its size in bytes, and an sha256 hash of the data. +- The file will be at this path under the base url on the webserver. +- The manifest only lists files that ever needed updating; it's not necessary + to list every file in the game's installation (unless you want to allow the + entire game to download). +- The updater will check each item in the manifest: + - Does the file not exist in the install? Needs downloading. + - Does the file have a different size? Needs downloading. + - Does the file have a different sha256sum? Needs downloading. + - Otherwise, file is up to date, leave it alone. +- If an item needs downloading, do these same checks against the file in the + download directory (if it's already there and matches, don't download again.) +- Download necessary files with libcurl, put it in a download directory. +- The downloaded file is also checked for size and sha256 vs the manifest, to + make sure there was no corruption or confusion. If a downloaded file doesn't + match what was expected, the updater aborts and will try again next time. + This could fail checksum due to i/o errors and compromised security, but + it might just be that a new version was being published and bad luck + happened, and a retry later could correct everything. +- If the updater itself needs upgrading, we deal with that first. It's + downloaded, then the updater relaunches from the downloaded binary with + a special command line. That relaunched process copies itself to the proper + location, and then relaunches _again_ to restart the normal updating + process with the new updater in its correct position. +- Once the downloads are complete and the updater itself doesn't need + upgrading, we are ready to start the normal upgrade. Since we can't replace + executables on some platforms while they are running, and swapping out a + game's data files at runtime isn't wise in general, the updater will now + block until the game terminates. It does this by reading on the pipe that + the game created when forking the updater; since the game never writes + anything to this pipe, it causes the updater to block until the pipe closes. + Since the game never deliberately closes the pipe either, it remains open + until the OS forcibly closes it as the game process terminates. Being an + unnamed pipe, it just vaporizes at this point, leaving no state that might + accidentally hang us up later, like a global semaphore or whatnot. This + technique also lets us localize the game's code changes to one small block + of C code, with no need to manage these resources elsewhere. +- As a sanity check, the updater will also kill(game_process_id, 0) until it + fails, sleeping for 100 milliseconds between each attempt, in case the + process is still being cleaned up by the OS after closing the pipe. +- Once the updater is confident the game process is gone, it will start + upgrading the appropriate files. It does this in two steps: it moves + the old file to a "rollback" directory so it's out of the way but still + available, then it moves the newly-downloaded file into place. Since these + are all simple renames and not copies, this can move fast. Any missing + parent directories are created, in case the update is adding a new file + in a directory that didn't previously exist. +- If something goes wrong at this point (file i/o error, etc), the updater + will roll back the changes by deleting the updated files, and moving the + files in the "rollback" directory back to their original locations. Then + the updater aborts. +- If nothing went wrong, the rollback files are deleted. And we are officially + up to date! The updater terminates. + + +The updater is designed to fail at any point. If a download fails, it'll +pick up and try again next time, etc. Completed downloads will remain, so it +will just need to download any missing/incomplete files. + +The server side just needs to be able to serve static files over HTTPS from +any standard Apache/nginx/whatever process. + +Failure points: +- If the updater fails when still downloading data, it just picks up on next + restart. +- If the updater fails when replacing files, it rolls back any changes it has + made. +- If the updater fails when rolling back, then running the updater again after + fixing the specific problem (disk error, etc?) will redownload and replace + any files that were left in an uncertain state. The only true point of + risk is crashing during a rollback and then having the updater bricked for + some reason, but that's an extremely small surface area, knock on wood. +- If the updater crashes or totally bricks, ioquake3 should just keep being + ioquake3. It will still launch and play, even if the updater is quietly + segfaulting in the background on startup. +- If an update bricks ioquake3 to the point where it can't run the updater, + running the updater directly should let it recover (assuming a future update + fixes the problem). +- If the download server is compromised, they would need the private key + (not stored on the download server) to alter the manifest to serve + compromised files to players. If they try to change a file or the manifest, + the updater will know to abort without updating anything. +- If the private key is compromised, we generate a new one, ship new + installers with an updated public key, and re-sign the manifest with the + new private key. Existing installations will never update again until they + do a fresh install, or at least update their copy of the public key. + + +How manifest signing works: + +Some admin will generate a public/private key with the rsa_make_keys program, +keeping the private key secret. Using the private key and the rsa_sign +program, the admin will sign the manifest, generating manifest.txt.sig. + +The public key ships with the game (adding 270 bytes to the download), the +.sig is downloaded with the manifest by the autoupdater (256 bytes extra +download), then the autoupdater checks the manifest against the signature +with the public key. if the signature isn't valid (the manifest was tampered +with or corrupt), the autoupdater refuses to continue. + +If the manifest is to be trusted, it lists sha256 checksums for every file to +download, so there's no need to sign every file; if they can't tamper with the +manifest, they can't tamper with any other file to be updated since the file's +listed sha256 won't match. + +If the private key is compromised, we generate new keys and ship new +installers, so new installations will be able to update but existing ones +will need to do a new install to keep getting updates. Don't let the private +key get compromised. The private key doesn't go on a public server. Maybe it +doesn't even live on the admin's laptop hard drive. + +If the download server is compromised and serving malware, the autoupdater +will reject it outright if they haven't compromised the private key, generated +a new manifest, and signed it with the private key. + + + +Items to consider for future revisions: +- Maybe put a limit on the number manifest downloads, so we only check once + every hour? Every day? +- Channels? Stable (what everyone gets by default), Nightly (once a day), + Experimental (some other work-in-progress branch), Bloody (literally the + latest commit). +- Let mods update, separate from the main game? + +Questions? Ask Ryan: icculus@icculus.org + +--ryan. + diff --git a/code/autoupdater/autoupdater.c b/code/autoupdater/autoupdater.c new file mode 100644 index 00000000..4a052027 --- /dev/null +++ b/code/autoupdater/autoupdater.c @@ -0,0 +1,1043 @@ +/* +The code in this file is in the public domain. The rest of ioquake3 +is licensed under the GPLv2. Do not mingle code, please! +*/ + +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef __int64 int64_t; +#else +#include +#endif + +#include +#include +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +#define PIDFMT "%u" +#define PIDFMTCAST unsigned int +typedef DWORD PID; +#else +#include +#include +typedef pid_t PID; +#define PIDFMT "%llu" +#define PIDFMTCAST unsigned long long +#endif + +/* If your build fails here with tomcrypt.h missing, you probably need to + run the build-libtom script in the rsa_tools subdirectory. */ +#define TFM_DESC +#define LTC_NO_ROLC +#include "tomcrypt.h" + +#define PUBLICKEY_FNAME "updater-publickey.bin" +#define SALT_LEN 8 +static int sha256_hash_index = 0; + + +#ifndef AUTOUPDATE_USER_AGENT +#define AUTOUPDATE_USER_AGENT "ioq3autoupdater/0.1" +#endif + + +#ifndef AUTOUPDATE_URL + +#ifndef AUTOUPDATE_BASEURL +#define AUTOUPDATE_BASEURL "https://upd.ioquake3.org/updates/v1" +#endif + +#ifndef AUTOUPDATE_PACKAGE +#define AUTOUPDATE_PACKAGE "ioquake3" +#endif + +#ifdef __APPLE__ +#define AUTOUPDATE_PLATFORM "mac" +#elif defined(__linux__) +#define AUTOUPDATE_PLATFORM "linux" +#elif defined(_WIN32) +#define AUTOUPDATE_PLATFORM "windows" +#else +#error Please define your platform. +#endif + +#ifdef __i386__ +#define AUTOUPDATE_ARCH "x86" +#elif defined(__x86_64__) +#define AUTOUPDATE_ARCH "x86_64" +#else +#error Please define your platform. +#endif + +#define AUTOUPDATE_URL AUTOUPDATE_BASEURL "/" AUTOUPDATE_PACKAGE "/" AUTOUPDATE_PLATFORM "/" AUTOUPDATE_ARCH "/" +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define NEVER_RETURNS __attribute__((noreturn)) +#define PRINTF_FUNC(fmtargnum, dotargnum) __attribute__ (( format( __printf__, fmtargnum, dotargnum ))) +#else +#define NEVER_RETURNS +#define PRINTF_FUNC(fmtargnum, dotargnum) +#endif + + +typedef struct +{ + pid_t waitforprocess; + const char *updateself; +} Options; + +static Options options; + + +typedef struct ManifestItem +{ + char *fname; + unsigned char sha256[32]; + int64_t len; + int update; + int rollback; + struct ManifestItem *next; +} ManifestItem; + +static ManifestItem *manifest = NULL; + +static void freeManifest(void) +{ + ManifestItem *item = manifest; + manifest = NULL; + + while (item != NULL) { + ManifestItem *next = item->next; + free(item->fname); + free(item); + item = next; + } + manifest = NULL; +} + +static const char *timestamp(void) +{ + time_t t = time(NULL); + char *retval = asctime(localtime(&t)); + if (retval) { + char *ptr; + for (ptr = retval; *ptr; ptr++) { + if ((*ptr == '\r') || (*ptr == '\n')) { + *ptr = '\0'; + break; + } + } + } + return retval ? retval : "[date unknown]"; +} + + +static FILE *logfile = NULL; + +static void info(const char *str) +{ + fputs(str, logfile); + fputs("\n", logfile); + fflush(logfile); +} + +static void infof(const char *fmt, ...) PRINTF_FUNC(1, 2); +static void infof(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(logfile, fmt, ap); + va_end(ap); + fputs("\n", logfile); + fflush(logfile); +} + +static void restoreRollbacks(void) +{ + /* you can't call die() in this function! If this fails, you're doomed. */ + ManifestItem *item; + for (item = manifest; item != NULL; item = item->next) { + if (item->rollback) { + char rollbackPath[64]; + snprintf(rollbackPath, sizeof (rollbackPath), "updates/rollbacks/%d", item->rollback); + infof("restore rollback: '%s' -> '%s'", rollbackPath, item->fname); + remove(item->fname); + rename(rollbackPath, item->fname); + } + } +} + +static void die(const char *why) NEVER_RETURNS; + + + +#ifdef _WIN32 + +#define chmod(a,b) do {} while (0) +#define makeDir(path) mkdir(path) + +static void windowsWaitForProcessToDie(const DWORD pid) +{ + HANDLE h; + infof("Waiting on process ID #%u", (unsigned int) pid); + h = OpenProcess(SYNCHRONIZE, FALSE, pid); + if (!h) { + const DWORD err = GetLastError(); + if (err == ERROR_INVALID_PARAMETER) { + info("No such process; probably already dead. Carry on."); + return; /* process is (probably) already gone. */ + } + infof("OpenProcess failed. err=%d", (unsigned int) err); + die("OpenProcess failed"); + } + if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) { + die("WaitForSingleObject failed"); + } + CloseHandle(h); +} + +static void launchProcess(const char *exe, ...) +{ + PROCESS_INFORMATION procinfo; + STARTUPINFO startinfo; + va_list ap; + char cmdline[1024]; + char *ptr = cmdline; + size_t totallen = 0; + const char *arg = NULL; + + #define APPENDCMDLINE(str) { \ + const size_t len = strlen(str); \ + totallen += len; \ + if ((totallen + 1) < sizeof (cmdline)) { \ + strcpy(ptr, str); \ + ptr += len; \ + } \ + } + + va_start(ap, exe); + APPENDCMDLINE(exe); + while ((arg = va_arg(ap, const char *)) != NULL) { + APPENDCMDLINE(arg); + } + va_end(ap); + + if (totallen >= sizeof (cmdline)) { + die("command line too long to launch."); + } + + cmdline[totallen] = 0; + + infof("launching process '%s' with cmdline '%s'", exe, cmdline); + + memset(&procinfo, '\0', sizeof (procinfo)); + memset(&startinfo, '\0', sizeof (startinfo)); + startinfo.cb = sizeof (startinfo); + if (CreateProcessA(exe, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startinfo, &procinfo)) + { + CloseHandle(procinfo.hProcess); + CloseHandle(procinfo.hThread); + exit(0); /* we're done, it's launched. */ + } + + infof("CreateProcess failed: err=%d", (int) GetLastError()); +} + +static HINTERNET hInternet; +static void prepHttpLib(void) +{ + hInternet = InternetOpenA(AUTOUPDATE_USER_AGENT, + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, NULL, 0); + if (!hInternet) { + die("InternetOpen failed"); + } +} + +static void shutdownHttpLib(void) +{ + if (hInternet) { + InternetCloseHandle(hInternet); + hInternet = NULL; + } +} + +static int runHttpDownload(const char *from, FILE *to) +{ + /* !!! FIXME: some of this could benefit from GetLastError+FormatMessage. */ + int retval = 0; + DWORD httpcode = 0; + DWORD dwordlen = sizeof (DWORD); + DWORD zero = 0; + HINTERNET hUrl = InternetOpenUrlA(hInternet, from, NULL, 0, + INTERNET_FLAG_HYPERLINK | + INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | + INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | + INTERNET_FLAG_NO_CACHE_WRITE | + INTERNET_FLAG_NO_COOKIES | + INTERNET_FLAG_NO_UI | + INTERNET_FLAG_RESYNCHRONIZE | + INTERNET_FLAG_RELOAD | + INTERNET_FLAG_SECURE, 0); + + if (!hUrl) { + infof("InternetOpenUrl failed. err=%d", (int) GetLastError()); + } else if (!HttpQueryInfo(hUrl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &httpcode, &dwordlen, &zero)) { + infof("HttpQueryInfo failed. err=%d", (int) GetLastError()); + } else if (httpcode != 200) { + infof("HTTP request failed with response code %d", (int) httpcode); + } else { + while (1) { + DWORD br = 0; + BYTE buf[1024 * 64]; + if (!InternetReadFile(hUrl, buf, sizeof (buf), &br)) { + infof("InternetReadFile failed. err=%d", (int) GetLastError()); + break; + } else if (br == 0) { + retval = 1; + break; /* done! */ + } else { + if (fwrite(buf, br, 1, to) != 1) { + info("fwrite failed"); + break; + } + } + } + } + + InternetCloseHandle(hUrl); + return retval; +} + +#else /* Everything that isn't Windows. */ + +#define launchProcess execl +#define makeDir(path) mkdir(path, 0777) + +/* hooray for Unix linker hostility! */ +#undef curl_easy_setopt +#include +typedef void (*CURLFN_curl_easy_cleanup)(CURL *curl); +typedef CURL *(*CURLFN_curl_easy_init)(void); +typedef CURLcode (*CURLFN_curl_easy_setopt)(CURL *curl, CURLoption option, ...); +typedef CURLcode (*CURLFN_curl_easy_perform)(CURL *curl); +typedef CURLcode (*CURLFN_curl_global_init)(long flags); +typedef void (*CURLFN_curl_global_cleanup)(void); + +static CURLFN_curl_easy_cleanup CURL_curl_easy_cleanup; +static CURLFN_curl_easy_init CURL_curl_easy_init; +static CURLFN_curl_easy_setopt CURL_curl_easy_setopt; +static CURLFN_curl_easy_perform CURL_curl_easy_perform; +static CURLFN_curl_global_init CURL_curl_global_init; +static CURLFN_curl_global_cleanup CURL_curl_global_cleanup; + +static void prepHttpLib(void) +{ + #ifdef __APPLE__ + const char *libname = "libcurl.4.dylib"; + #else + const char *libname = "libcurl.so.4"; + #endif + + void *handle = dlopen(libname, RTLD_NOW | RTLD_GLOBAL); + if (!handle) { + infof("dlopen(\"%s\") failed: %s", libname, dlerror()); + die("Failed to load libcurl library"); + } + #define LOADCURLSYM(fn) \ + if ((CURL_##fn = (CURLFN_##fn) dlsym(handle, #fn)) == NULL) { \ + die("Failed to load libcurl symbol '" #fn "'"); \ + } + + LOADCURLSYM(curl_easy_cleanup); + LOADCURLSYM(curl_easy_init); + LOADCURLSYM(curl_easy_setopt); + LOADCURLSYM(curl_easy_perform); + LOADCURLSYM(curl_global_init); + LOADCURLSYM(curl_global_cleanup); + + #define curl_easy_cleanup CURL_curl_easy_cleanup + #define curl_easy_init CURL_curl_easy_init + #define curl_easy_setopt CURL_curl_easy_setopt + #define curl_easy_perform CURL_curl_easy_perform + #define curl_global_init CURL_curl_global_init + #define curl_global_cleanup CURL_curl_global_cleanup + + if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) { + die("curl_global_init() failed!"); + } +} + +static void shutdownHttpLib(void) +{ + if (curl_global_cleanup) { + curl_global_cleanup(); + } +} + +static int runHttpDownload(const char *from, FILE *to) +{ + int retval; + CURL *curl = curl_easy_init(); + if (!curl) { + info("curl_easy_init() failed"); + return 0; + } + + #if 0 + /* !!! FIXME: enable compression? */ + curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); /* enable compression */ + + /* !!! FIXME; hook up proxy support to libcurl */ + curl_easy_setopt(curl, CURLOPT_PROXY, proxyURL); + #endif + + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt(curl, CURLOPT_STDERR, logfile); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, to); + + curl_easy_setopt(curl, CURLOPT_URL, from); + + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); /* allow redirects. */ + curl_easy_setopt(curl, CURLOPT_USERAGENT, AUTOUPDATE_USER_AGENT); + + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); /* require valid SSL cert. */ + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); /* require SSL cert with same hostname as we connected to. */ + + retval = (curl_easy_perform(curl) == CURLE_OK); + curl_easy_cleanup(curl); + return retval; +} +#endif + + +static void die(const char *why) +{ + infof("FAILURE: %s", why); + restoreRollbacks(); + freeManifest(); + infof("Updater ending (in failure), %s", timestamp()); + exit(1); +} + +static void outOfMemory(void) NEVER_RETURNS; +static void outOfMemory(void) +{ + die("Out of memory"); +} + +static void buildParentDirs(const char *_path) +{ + char *ptr; + char *path = (char *) alloca(strlen(_path) + 1); + if (!path) { + outOfMemory(); + } + strcpy(path, _path); + + for (ptr = path; *ptr; ptr++) { + if (*ptr == '/') { + *ptr = '\0'; + makeDir(path); + *ptr = '/'; + } + } +} + +static int64_t fileLength(const char *fname) +{ + struct stat statbuf; + if (stat(fname, &statbuf) == -1) { + return -1; + } + return (int64_t) statbuf.st_size; +} + +static void parseArgv(int argc, char **argv) +{ + int i; + + infof("command line (argc=%d)...", argc); + for (i = 0; i < argc; i++) { + infof(" argv[%d]: %s",i, argv[i]); + } + + for (i = 1; i < argc; i += 2) { + if (strcmp(argv[i], "--waitpid") == 0) { + options.waitforprocess = atoll(argv[i + 1]); + infof("We will wait for process " PIDFMT " if necessary", (PIDFMTCAST) options.waitforprocess); + } else if (strcmp(argv[i], "--updateself") == 0) { + options.updateself = argv[i + 1]; + infof("We are updating ourself ('%s')", options.updateself); + } + } +} + +static void downloadURL(const char *from, const char *to) +{ + FILE *io = NULL; + const size_t len = strlen(AUTOUPDATE_URL) + strlen(from) + 1; + char *fullurl = (char *) alloca(len); + if (!fullurl) { + outOfMemory(); + } + snprintf(fullurl, len, "%s%s", AUTOUPDATE_URL, from); + + infof("Downloading from '%s' to '%s'", fullurl, to); + + buildParentDirs(to); + io = fopen(to, "wb"); + if (!io) { + die("Failed to open output file"); + } + + if (!runHttpDownload(fullurl, io)) { + fclose(io); + remove(to); + die("Download failed"); + } + + if (fclose(io) == EOF) { + die("Can't flush file on close. i/o error? Disk full?"); + } + + chmod(to, 0777); /* !!! FIXME */ +} + +static int hexcvt(const int ch) +{ + if ((ch >= 'a') && (ch <= 'f')) { + return (ch - 'a') + 10; + } else if ((ch >= 'A') && (ch <= 'F')) { + return (ch - 'A') + 10; + } else if ((ch >= '0') && (ch <= '9')) { + return ch - '0'; + } else { + die("Invalid hex character"); + } + return 0; +} + +static void convertSha256(char *str, unsigned char *sha256) +{ + int i; + for (i = 0; i < 32; i++) { + const int a = hexcvt(*(str++)); + const int b = hexcvt(*(str++)); + *sha256 = (a << 4) | b; + sha256++; + } +} + +static void parseManifest(const char *fname) +{ + ManifestItem *item = NULL; + FILE *io = fopen(fname, "r"); + char buf[512]; + if (!io) { + die("Failed to open manifest for reading"); + } + + /* !!! FIXME: this code sucks. */ + while (fgets(buf, sizeof (buf), io)) { + char *ptr = (buf + strlen(buf)) - 1; + while (ptr >= buf) { + if ((*ptr != '\n') && (*ptr != '\r')) { + break; + } + *ptr = '\0'; + ptr--; + } + + if (!item && !buf[0]) { + continue; /* blank line between items or blank at EOF */ + } + + if (!item) { + infof("Next manifest item: %s", buf); + + item = (ManifestItem *) calloc(1, sizeof (ManifestItem)); + if (!item) { + outOfMemory(); + } + item->fname = strdup(buf); + if (!item->fname) { + outOfMemory(); + } + item->len = -1; + item->next = NULL; + } else if (item->len == -1) { + infof("Item size: %s", buf); + item->len = atoll(buf); + } else { + infof("Item sha256: %s", buf); + convertSha256(buf, item->sha256); + item->next = manifest; + manifest = item; + item = NULL; + } + } + + if (ferror(io)) { + die("Error reading manifest"); + } else if (item) { + die("Incomplete manifest"); + } + + fclose(io); +} + +static void read_file(const char *fname, void *buf, unsigned long *len) +{ + ssize_t br; + FILE *io = fopen(fname, "rb"); + if (!io) { + infof("Can't open '%s' for reading: %s", fname, strerror(errno)); + die("Failed to read file"); + } + + br = fread(buf, 1, *len, io); + if (ferror(io)) { + infof("Couldn't read '%s': %s", fname, strerror(errno)); + die("Failed to read file"); + } else if (!feof(io)) { + infof("Buffer too small to read '%s'", fname); + die("Failed to read file"); + } + fclose(io); + + *len = (unsigned long) br; +} + +static void read_rsakey(rsa_key *key, const char *fname) +{ + unsigned char buf[4096]; + unsigned long len = sizeof (buf); + int rc; + + read_file(fname, buf, &len); + + if ((rc = rsa_import(buf, len, key)) != CRYPT_OK) { + infof("rsa_import for '%s' failed: %s", fname, error_to_string(rc)); + die("Couldn't import public key"); + } +} + +static void verifySignature(const char *fname, const char *sigfname, const char *keyfname) +{ + rsa_key key; + unsigned char hash[256]; + unsigned long hashlen = sizeof (hash); + unsigned char sig[1024]; + unsigned long siglen = sizeof (sig); + int status = 0; + int rc = 0; + + read_rsakey(&key, keyfname); + read_file(sigfname, sig, &siglen); + + if ((rc = hash_file(sha256_hash_index, fname, hash, &hashlen)) != CRYPT_OK) { + infof("hash_file for '%s' failed: %s", fname, error_to_string(rc)); + die("Couldn't verify manifest signature"); + } + + if ((rc = rsa_verify_hash(sig, siglen, hash, hashlen, sha256_hash_index, SALT_LEN, &status, &key)) != CRYPT_OK) { + infof("rsa_verify_hash for '%s' failed: %s", fname, error_to_string(rc)); + die("Couldn't verify manifest signature"); + } + + if (!status) { + infof("Invalid signature for '%s'! Don't trust this file!", fname); + die("Manifest is incomplete, corrupt, or compromised"); + } + + info("Manifest signature appears to be valid"); + rsa_free(&key); +} + +static void downloadManifest(void) +{ + const char *manifestfname = "updates/manifest.txt"; + const char *manifestsigfname = "updates/manifest.txt.sig"; + downloadURL("manifest.txt", manifestfname); + downloadURL("manifest.txt.sig", manifestsigfname); + verifySignature(manifestfname, manifestsigfname, PUBLICKEY_FNAME); + parseManifest(manifestfname); +} + +static void upgradeSelfAndRestart(const char *argv0) NEVER_RETURNS; +static void upgradeSelfAndRestart(const char *argv0) +{ + const char *tempfname = "origUpdater"; + const char *why = NULL; + FILE *in = NULL; + FILE *out = NULL; + + /* unix replaces the process with execl(), but Windows needs to wait for the parent to terminate. */ + #ifdef _WIN32 + DWORD ppid = 0; + HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (h) { + const DWORD myPid = GetCurrentProcessId(); + PROCESSENTRY32 pe; + memset(&pe, '\0', sizeof (pe)); + pe.dwSize = sizeof(PROCESSENTRY32); + + if (Process32First(h, &pe)) { + do { + if (pe.th32ProcessID == myPid) { + ppid = pe.th32ParentProcessID; + break; + } + } while (Process32Next(h, &pe)); + } + CloseHandle(h); + } + if (!ppid) { + die("Can't determine parent process id"); + } + windowsWaitForProcessToDie(ppid); + #endif + + in = fopen(argv0, "rb"); + if (!in) { + die("Can't open self for input while upgrading updater"); + } + + remove(tempfname); + if (rename(options.updateself, tempfname) == -1) { + die("Can't rename original while upgrading updater"); + } + + out = fopen(options.updateself, "wb"); + if (!out) { + die("Can't open file for output while upgrading updater"); + } + + while (!feof(in) && !why) { + char buf[512]; + const size_t br = fread(buf, 1, sizeof (buf), in); + if (br > 0) { + if (fwrite(buf, br, 1, out) != 1) { + why = "write failure while upgrading updater"; + } + } else if (ferror(in)) { + why = "read failure while upgrading updater"; + } + } + + fclose(in); + + if ((fclose(out) == EOF) && (!why)) { + why = "close failure while upgrading updater"; + } + + if (why) { + remove(options.updateself); + rename(tempfname, options.updateself); + die(why); + } + + remove(tempfname); + + chmod(options.updateself, 0777); + + if (options.waitforprocess) { + char pidstr[64]; + snprintf(pidstr, sizeof (pidstr), PIDFMT, (PIDFMTCAST) options.waitforprocess); + launchProcess(options.updateself, options.updateself, "--waitpid", pidstr, NULL); + } else { + launchProcess(options.updateself, options.updateself, NULL); + } + die("Failed to relaunch upgraded updater"); +} + +static const char *justFilename(const char *path) +{ + const char *fname = strrchr(path, '/'); + return fname ? fname + 1 : path; +} + +static void hashFile(const char *fname, unsigned char *sha256) +{ + int rc = 0; + unsigned long hashlen = 32; + if ((rc = hash_file(sha256_hash_index, fname, sha256, &hashlen)) != CRYPT_OK) { + infof("hash_file failed for '%s': %s", fname, error_to_string(rc)); + die("Can't hash file"); + } +} + +static int fileHashMatches(const char *fname, const unsigned char *wanted) +{ + unsigned char sha256[32]; + hashFile(fname, sha256); + return (memcmp(sha256, wanted, 32) == 0); +} + +static int fileNeedsUpdate(const ManifestItem *item) +{ + if (item->len != fileLength(item->fname)) { + infof("Update '%s', file size is different", item->fname); + return 1; /* obviously different. */ + } else if (!fileHashMatches(item->fname, item->sha256)) { + infof("Update '%s', file sha256 is different", item->fname); + return 1; + } + + infof("Don't update '%s', the file is already up to date", item->fname); + return 0; +} + +static void downloadFile(const ManifestItem *item) +{ + const char *outpath = "updates/downloads/"; + const size_t len = strlen(outpath) + strlen(item->fname) + 1; + char *to = (char *) alloca(len); + if (!to) { + outOfMemory(); + } + + snprintf(to, len, "%s%s", outpath, item->fname); + + if ((item->len == fileLength(to)) && fileHashMatches(to, item->sha256)) { + infof("Already downloaded '%s', not getting again", item->fname); + } else { + downloadURL(item->fname, to); + if ((item->len != fileLength(to)) || !fileHashMatches(to, item->sha256)) { + die("Download is incorrect or corrupted"); + } + } +} + +static int downloadUpdates(void) +{ + int updatesAvailable = 0; + ManifestItem *item; + for (item = manifest; item != NULL; item = item->next) { + item->update = fileNeedsUpdate(item); + if (item->update) { + updatesAvailable = 1; + downloadFile(item); + } + } + return updatesAvailable; +} + +static void maybeUpdateSelf(const char *argv0) +{ + ManifestItem *item; + + /* !!! FIXME: this needs to be a different string on macOS. */ + const char *fname = justFilename(argv0); + + for (item = manifest; item != NULL; item = item->next) { + if (strcasecmp(item->fname, fname) == 0) { + if (fileNeedsUpdate(item)) { + const char *outpath = "updates/downloads/"; + const size_t len = strlen(outpath) + strlen(item->fname) + 1; + char *to = (char *) alloca(len); + if (!to) { + outOfMemory(); + } + snprintf(to, len, "%s%s", outpath, item->fname); + info("Have to upgrade the updater"); + downloadFile(item); + chmod(to, 0777); + + if (options.waitforprocess) { + char pidstr[64]; + snprintf(pidstr, sizeof (pidstr), PIDFMT, (PIDFMTCAST) options.waitforprocess); + launchProcess(to, to, "--updateself", argv0, "--waitpid", pidstr, NULL); + } else { + launchProcess(to, to, "--updateself", argv0, NULL); + } + die("Failed to initially launch upgraded updater"); + } + break; /* done in any case. */ + } + } +} + +static void installUpdatedFile(const ManifestItem *item) +{ + const char *basepath = "updates/downloads/"; + const size_t len = strlen(basepath) + strlen(item->fname) + 1; + char *downloadPath = (char *) alloca(len); + if (!downloadPath) { + outOfMemory(); + } + + snprintf(downloadPath, len, "%s%s", basepath, item->fname); + + infof("Moving file for update: '%s' -> '%s'", downloadPath, item->fname); + buildParentDirs(item->fname); + if (rename(downloadPath, item->fname) == -1) { + die("Failed to move updated file to final position"); + } +} + +static void applyUpdates(void) +{ + FILE *io; + ManifestItem *item; + for (item = manifest; item != NULL; item = item->next) { + if (!item->update) { + continue; + } + + io = fopen(item->fname, "rb"); + if (io != NULL) { + static int rollbackIndex = 0; + char rollbackPath[64]; + fclose(io); + item->rollback = ++rollbackIndex; + snprintf(rollbackPath, sizeof (rollbackPath), "updates/rollbacks/%d", rollbackIndex); + infof("Moving file for rollback: '%s' -> '%s'", item->fname, rollbackPath); + remove(rollbackPath); + if (rename(item->fname, rollbackPath) == -1) { + die("failed to move to rollback dir"); + } + } + + installUpdatedFile(item); + } +} + + +static void waitToApplyUpdates(void) +{ + if (options.waitforprocess) { + infof("Waiting for pid " PIDFMT " to die...", (PIDFMTCAST) options.waitforprocess); + { + #ifdef _WIN32 + windowsWaitForProcessToDie(options.waitforprocess); + #else + /* The parent opens a pipe on fd 3, and then forgets about it. We block + on a read to that pipe here. When the game process quits (and the + OS forcibly closes the pipe), we will unblock. Then we can loop on + kill() until the process is truly gone. */ + int x = 0; + read(3, &x, sizeof (x)); + info("Pipe has closed, waiting for process to fully go away now."); + while (kill(options.waitforprocess, 0) == 0) { + usleep(100000); + } + #endif + } + info("pid is gone, continuing"); + } +} + +static void deleteRollbacks(void) +{ + ManifestItem *item; + for (item = manifest; item != NULL; item = item->next) { + if (item->rollback) { + char rollbackPath[64]; + snprintf(rollbackPath, sizeof (rollbackPath), "updates/rollbacks/%d", item->rollback); + infof("delete rollback: %s", rollbackPath); + remove(rollbackPath); + } + } +} + +static void chdirToBasePath(const char *argv0) +{ + const char *fname = justFilename(argv0); + size_t len; + char *buf; + + if (fname == argv0) { /* no path? Assume we're already there. */ + return; + } + + len = ((size_t) (fname - argv0)) - 1; + buf = (char *) alloca(len); + if (!buf) { + outOfMemory(); + } + + memcpy(buf, argv0, len); + buf[len] = '\0'; + if (chdir(buf) == -1) { + infof("base path is '%s'", buf); + die("chdir to base path failed"); + } +} + +int main(int argc, char **argv) +{ + #ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); /* don't trigger signal when fd3 closes */ + #endif + + logfile = stdout; + chdirToBasePath(argv[0]); + + makeDir("updates"); + makeDir("updates/downloads"); + makeDir("updates/rollbacks"); + + logfile = fopen("updates/updater-log.txt", "a"); + if (!logfile) { + logfile = stdout; + } + + infof("Updater starting, %s", timestamp()); + + parseArgv(argc, argv); + + /* set up crypto */ + ltc_mp = tfm_desc; + sha256_hash_index = register_hash(&sha256_desc); + if (sha256_hash_index == -1) { + die("Failed to register sha256 hasher"); + } + + /* if we have downloaded a new updater and restarted with that binary, + replace the original updater and restart again in the right place. */ + if (options.updateself) { + upgradeSelfAndRestart(argv[0]); + } + + prepHttpLib(); + + downloadManifest(); /* see if we need an update at all. */ + + maybeUpdateSelf(argv[0]); /* might relaunch if there's an updater upgrade. */ + + if (!downloadUpdates()) { + info("Nothing needs updating, so we're done here!"); + } else { + waitToApplyUpdates(); + applyUpdates(); + deleteRollbacks(); + info("You are now up to date!"); + } + + freeManifest(); + shutdownHttpLib(); + + unregister_hash(&sha256_desc); + + infof("Updater ending, %s", timestamp()); + + return 0; +} + diff --git a/code/autoupdater/rsa_tools/.gitignore b/code/autoupdater/rsa_tools/.gitignore new file mode 100644 index 00000000..8182fafc --- /dev/null +++ b/code/autoupdater/rsa_tools/.gitignore @@ -0,0 +1,8 @@ +crypt-*.tar.bz2 +tfm-*.tar.xz +libtomcrypt-* +tomsfastmath-* +rsa_make_keys +rsa_sign +rsa_verify +*.exe diff --git a/code/autoupdater/rsa_tools/build-libtom-unix.sh b/code/autoupdater/rsa_tools/build-libtom-unix.sh new file mode 100644 index 00000000..bbd86312 --- /dev/null +++ b/code/autoupdater/rsa_tools/build-libtom-unix.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +TFMVER=0.13.1 +LTCVER=1.17 +set -e + +OSTYPE=`uname -s` +if [ "$OSTYPE" = "Linux" ]; then + NCPU=`cat /proc/cpuinfo |grep vendor_id |wc -l` + let NCPU=$NCPU+1 +elif [ "$OSTYPE" = "Darwin" ]; then + NCPU=`sysctl -n hw.ncpu` + export CFLAGS="$CFLAGS -mmacosx-version-min=10.7 -DMAC_OS_X_VERSION_MIN_REQUIRED=1070" + export LDFLAGS="$LDFLAGS -mmacosx-version-min=10.7" +elif [ "$OSTYPE" = "SunOS" ]; then + NCPU=`/usr/sbin/psrinfo |wc -l |sed -e 's/^ *//g;s/ *$//g'` +else + NCPU=1 +fi + +if [ -z "$NCPU" ]; then + NCPU=1 +elif [ "$NCPU" = "0" ]; then + NCPU=1 +fi + +if [ ! -f tfm-$TFMVER.tar.xz ]; then + echo "Downloading TomsFastMath $TFMVER sources..." + curl -L -o tfm-$TFMVER.tar.xz https://github.com/libtom/tomsfastmath/releases/download/v$TFMVER/tfm-$TFMVER.tar.xz || exit 1 +fi + +if [ ! -f ./crypt-$LTCVER.tar.bz2 ]; then + echo "Downloading LibTomCrypt $LTCVER sources..." + curl -L -o crypt-$LTCVER.tar.bz2 https://github.com/libtom/libtomcrypt/releases/download/$LTCVER/crypt-$LTCVER.tar.bz2 || exit 1 +fi + +if [ ! -d tomsfastmath-$TFMVER ]; then + echo "Checking TomsFastMath archive hash..." + if [ "`shasum -a 256 tfm-$TFMVER.tar.xz |awk '{print $1;}'`" != "47c97a1ada3ccc9fcbd2a8a922d5859a84b4ba53778c84c1d509c1a955ac1738" ]; then + echo "Uhoh, tfm-$TFMVER.tar.xz does not have the sha256sum we expected!" + exit 1 + fi + echo "Unpacking TomsFastMath $TFMVER sources..." + tar -xJvvf ./tfm-$TFMVER.tar.xz +fi + +if [ ! -d libtomcrypt-$LTCVER ]; then + if [ "`shasum -a 256 crypt-$LTCVER.tar.bz2 |awk '{print $1;}'`" != "e33b47d77a495091c8703175a25c8228aff043140b2554c08a3c3cd71f79d116" ]; then + echo "Uhoh, crypt-$LTCVER.tar.bz2 does not have the sha256sum we expected!" + exit 1 + fi + echo "Unpacking LibTomCrypt $LTCVER sources..." + tar -xjvvf ./crypt-$LTCVER.tar.bz2 +fi + +echo +echo +echo "Will use make -j$NCPU. If this is wrong, check NCPU at top of script." +echo +echo + +set -e +set -x + +# Some compilers can't handle the ROLC inline asm; just turn it off. +cd tomsfastmath-$TFMVER +make -j$NCPU +cd .. + +export CFLAGS="$CFLAGS -DTFM_DESC -DLTC_NO_ROLC -I ../tomsfastmath-$TFMVER/src/headers" +cd libtomcrypt-$LTCVER +make -j$NCPU +cd .. + +set +x +echo "All done." + +# end of build-libtom-unix.sh ... + diff --git a/code/autoupdater/rsa_tools/build-rsa-tools.sh b/code/autoupdater/rsa_tools/build-rsa-tools.sh new file mode 100644 index 00000000..dda9396c --- /dev/null +++ b/code/autoupdater/rsa_tools/build-rsa-tools.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +export TFMDIR="tomsfastmath-0.13.1" +export LTCDIR="libtomcrypt-1.17" + +OSTYPE=`uname -s` +if [ -z "$CC" ]; then + if [ "`uname -o`" = "Cygwin" ]; then + export CC=/usr/bin/i686-w64-mingw32-gcc + else + export CC=cc + fi +fi + +function build { + if [ "$OSTYPE" = "Darwin" ]; then + $CC -mmacosx-version-min=10.7 -DMAC_OS_X_VERSION_MIN_REQUIRED=1070 -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a + else + $CC -I $TFMDIR/src/headers -I $LTCDIR/src/headers -o "$1" -Wall -O3 "$1.c" rsa_common.c $LTCDIR/libtomcrypt.a $TFMDIR/libtfm.a + fi +} + +set -e +set -x + +./build-libtom-unix.sh +build rsa_make_keys +build rsa_sign +build rsa_verify + +set +x +echo "rsa_tools are compiled!" + diff --git a/code/autoupdater/rsa_tools/rsa_common.c b/code/autoupdater/rsa_tools/rsa_common.c new file mode 100644 index 00000000..d0a10a0a --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_common.c @@ -0,0 +1,61 @@ +#include "rsa_common.h" + +void fail(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputs("\n", stderr); + fflush(stderr); + exit(1); +} + +void write_file(const char *fname, const void *buf, const unsigned long len) +{ + FILE *io = fopen(fname, "wb"); + if (!io) { + fail("Can't open '%s' for writing: %s", fname, strerror(errno)); + } + + if (fwrite(buf, len, 1, io) != 1) { + fail("Couldn't write '%s': %s", fname, strerror(errno)); + } + + if (fclose(io) != 0) { + fail("Couldn't flush '%s' to disk: %s", fname, strerror(errno)); + } +} + +void read_file(const char *fname, void *buf, unsigned long *len) +{ + ssize_t br; + FILE *io = fopen(fname, "rb"); + if (!io) { + fail("Can't open '%s' for reading: %s", fname, strerror(errno)); + } + + br = fread(buf, 1, *len, io); + if (ferror(io)) { + fail("Couldn't read '%s': %s", fname, strerror(errno)); + } else if (!feof(io)) { + fail("Buffer too small to read '%s'", fname); + } + fclose(io); + + *len = (unsigned long) br; +} + +void read_rsakey(rsa_key *key, const char *fname) +{ + unsigned char buf[4096]; + unsigned long len = sizeof (buf); + int rc; + + read_file(fname, buf, &len); + + if ((rc = rsa_import(buf, len, key)) != CRYPT_OK) { + fail("rsa_import for '%s' failed: %s", fname, error_to_string(rc)); + } +} + diff --git a/code/autoupdater/rsa_tools/rsa_common.h b/code/autoupdater/rsa_tools/rsa_common.h new file mode 100644 index 00000000..48695522 --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_common.h @@ -0,0 +1,30 @@ +#ifndef _INCL_RSA_COMMON_H_ +#define _INCL_RSA_COMMON_H_ 1 + +#include +#include +#include + +#define TFM_DESC +#define LTC_NO_ROLC +#include "tomcrypt.h" + +#define SALT_LEN 8 + +#if defined(__GNUC__) || defined(__clang__) +#define NEVER_RETURNS __attribute__((noreturn)) +#define PRINTF_FUNC(fmtargnum, dotargnum) __attribute__ (( format( __printf__, fmtargnum, dotargnum ))) +#else +#define NEVER_RETURNS +#define PRINTF_FUNC(fmtargnum, dotargnum) +#endif + +void fail(const char *fmt, ...) NEVER_RETURNS PRINTF_FUNC(1, 2); +void write_file(const char *fname, const void *buf, const unsigned long len); +void read_file(const char *fname, void *buf, unsigned long *len); +void read_rsakey(rsa_key *key, const char *fname); + +#endif + +/* end of rsa_common.h ... */ + diff --git a/code/autoupdater/rsa_tools/rsa_make_keys.c b/code/autoupdater/rsa_tools/rsa_make_keys.c new file mode 100644 index 00000000..a7f801c0 --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_make_keys.c @@ -0,0 +1,45 @@ +#include "rsa_common.h" + +static void write_rsakey(rsa_key *key, const int type, const char *fname) +{ + unsigned char buf[4096]; + unsigned long len = sizeof (buf); + int rc; + + if ((rc = rsa_export(buf, &len, type, key)) != CRYPT_OK) { + fail("rsa_export for '%s' failed: %s", fname, error_to_string(rc)); + } + write_file(fname, buf, len); +} + +int main(int argc, char **argv) +{ + int rc = 0; + prng_state prng; + int prng_index; + rsa_key key; + + ltc_mp = tfm_desc; + prng_index = register_prng(&sprng_desc); /* (fortuna_desc is a good choice if your platform's PRNG sucks.) */ + + if (prng_index == -1) { + fail("Failed to register a RNG"); + } + + if ((rc = rng_make_prng(128, prng_index, &prng, NULL)) != CRYPT_OK) { + fail("rng_make_prng failed: %s", error_to_string(rc)); + } + + if ((rc = rsa_make_key(&prng, prng_index, 256, 65537, &key)) != CRYPT_OK) { + fail("rng_make_key failed: %s", error_to_string(rc)); + } + + write_rsakey(&key, PK_PRIVATE, "privatekey.bin"); + write_rsakey(&key, PK_PUBLIC, "publickey.bin"); + + rsa_free(&key); + + return 0; +} + +/* end of rsa_make_keys.c ... */ diff --git a/code/autoupdater/rsa_tools/rsa_sign.c b/code/autoupdater/rsa_tools/rsa_sign.c new file mode 100644 index 00000000..5eec24dd --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_sign.c @@ -0,0 +1,75 @@ +#include "rsa_common.h" + +static void sign_file(const char *fname, rsa_key *key, prng_state *prng, const int prng_index, const int hash_index) +{ + const size_t sigfnamelen = strlen(fname) + 5; + char *sigfname = (char *) malloc(sigfnamelen); + unsigned char hash[256]; + unsigned long hashlen = sizeof (hash); + unsigned char sig[1024]; + unsigned long siglen = sizeof (sig); + int rc = 0; + int status = 0; + + if (!sigfname) { + fail("out of memory"); + } + + if ((rc = hash_file(hash_index, fname, hash, &hashlen)) != CRYPT_OK) { + fail("hash_file for '%s' failed: %s", fname, error_to_string(rc)); + } + + if ((rc = rsa_sign_hash(hash, hashlen, sig, &siglen, prng, prng_index, hash_index, SALT_LEN, key)) != CRYPT_OK) { + fail("rsa_sign_hash for '%s' failed: %s", fname, error_to_string(rc)); + } + + if ((rc = rsa_verify_hash(sig, siglen, hash, hashlen, hash_index, SALT_LEN, &status, key)) != CRYPT_OK) { + fail("rsa_verify_hash for '%s' failed: %s", fname, error_to_string(rc)); + } + + if (!status) { + fail("Generated signature isn't valid! Bug in the program!"); + } + + snprintf(sigfname, sigfnamelen, "%s.sig", fname); + write_file(sigfname, sig, siglen); + free(sigfname); +} + +int main(int argc, char **argv) +{ + int rc = 0; + prng_state prng; + int prng_index, hash_index; + rsa_key key; + int i; + + ltc_mp = tfm_desc; + + prng_index = register_prng(&sprng_desc); /* (fortuna_desc is a good choice if your platform's PRNG sucks.) */ + if (prng_index == -1) { + fail("Failed to register a RNG"); + } + + hash_index = register_hash(&sha256_desc); + if (hash_index == -1) { + fail("Failed to register sha256 hasher"); + } + + if ((rc = rng_make_prng(128, prng_index, &prng, NULL)) != CRYPT_OK) { + fail("rng_make_prng failed: %s", error_to_string(rc)); + } + + read_rsakey(&key, "privatekey.bin"); + + for (i = 1; i < argc; i++) { + sign_file(argv[i], &key, &prng, prng_index, hash_index); + } + + rsa_free(&key); + + return 0; +} + +/* end of rsa_sign.c ... */ + diff --git a/code/autoupdater/rsa_tools/rsa_verify.c b/code/autoupdater/rsa_tools/rsa_verify.c new file mode 100644 index 00000000..09abfb24 --- /dev/null +++ b/code/autoupdater/rsa_tools/rsa_verify.c @@ -0,0 +1,60 @@ +#include "rsa_common.h" + +static void verify_file(const char *fname, rsa_key *key, const int hash_index) +{ + const size_t sigfnamelen = strlen(fname) + 5; + char *sigfname = (char *) malloc(sigfnamelen); + unsigned char hash[256]; + unsigned long hashlen = sizeof (hash); + unsigned char sig[1024]; + unsigned long siglen = sizeof (sig); + int status = 0; + int rc = 0; + + if (!sigfname) { + fail("out of memory"); + } + + snprintf(sigfname, sigfnamelen, "%s.sig", fname); + read_file(sigfname, sig, &siglen); + free(sigfname); + + if ((rc = hash_file(hash_index, fname, hash, &hashlen)) != CRYPT_OK) { + fail("hash_file for '%s' failed: %s", fname, error_to_string(rc)); + } + + if ((rc = rsa_verify_hash(sig, siglen, hash, hashlen, hash_index, SALT_LEN, &status, key)) != CRYPT_OK) { + fail("rsa_verify_hash for '%s' failed: %s", fname, error_to_string(rc)); + } + + if (!status) { + fail("Invalid signature for '%s'! Don't trust this file!", fname); + } +} + +int main(int argc, char **argv) +{ + int hash_index; + rsa_key key; + int i; + + ltc_mp = tfm_desc; + + hash_index = register_hash(&sha256_desc); + if (hash_index == -1) { + fail("Failed to register sha256 hasher"); + } + + read_rsakey(&key, "publickey.bin"); + + for (i = 1; i < argc; i++) { + verify_file(argv[i], &key, hash_index); + } + + rsa_free(&key); + + return 0; +} + +/* end of rsa_verify.c ... */ + diff --git a/code/autoupdater/rsa_tools/test-rsa-tools.sh b/code/autoupdater/rsa_tools/test-rsa-tools.sh new file mode 100644 index 00000000..f4b4bdb0 --- /dev/null +++ b/code/autoupdater/rsa_tools/test-rsa-tools.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ -f privatekey.bin ]; then + echo "move your existing keys out of the way." + exit 1 +fi + +( ./rsa_make_keys && echo "key making okay") || echo "key making NOT okay" +echo "The quick brown fox jumped over the lazy dog." >testmsg.txt +( ./rsa_sign testmsg.txt && echo "signing okay" ) || echo "signing NOT okay" +( ./rsa_verify testmsg.txt && echo "basic verifying okay" ) || echo "basic verifying NOT okay" +echo "The quick brown fox jumped over the lazy dog!" >testmsg.txt +( ./rsa_verify testmsg.txt 2>/dev/null && echo "tamper test NOT okay" ) || echo "tamper test okay" +echo "The quick brown fox jumped over the lazy dog." >testmsg.txt +( ./rsa_verify testmsg.txt && echo "reverify okay" ) || echo "reverify NOT okay" +rm -f testmsg.txt testmsg.txt.sig publickey.bin privatekey.bin + diff --git a/code/botlib/aasfile.h b/code/botlib/aasfile.h index 8f2fbf62..f23dbab1 100644 --- a/code/botlib/aasfile.h +++ b/code/botlib/aasfile.h @@ -65,8 +65,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define FACE_LADDER 2 //ladder #define FACE_GROUND 4 //standing on ground when in this face #define FACE_GAP 8 //gap in the ground -#define FACE_LIQUID 16 //face seperating two areas with liquid -#define FACE_LIQUIDSURFACE 32 //face seperating liquid and air +#define FACE_LIQUID 16 //face separating two areas with liquid +#define FACE_LIQUIDSURFACE 32 //face separating liquid and air #define FACE_BRIDGE 64 //can walk over this face if bridge is closed //area contents @@ -191,7 +191,7 @@ typedef struct aas_edge_s //edge index, negative if vertexes are reversed typedef int aas_edgeindex_t; -//a face bounds an area, often it will also seperate two areas +//a face bounds an area, often it will also separate two areas typedef struct aas_face_s { int planenum; //number of the plane this face is in diff --git a/code/botlib/be_aas_bspq3.c b/code/botlib/be_aas_bspq3.c index a6b6edb0..34862bcb 100644 --- a/code/botlib/be_aas_bspq3.c +++ b/code/botlib/be_aas_bspq3.c @@ -70,7 +70,7 @@ typedef struct bsp_entity_s bsp_epair_t *epairs; } bsp_entity_t; -//id Sofware BSP data +//id Software BSP data typedef struct bsp_s { //true when bsp file is loaded diff --git a/code/botlib/be_aas_cluster.c b/code/botlib/be_aas_cluster.c index 013e8066..f23d7a67 100644 --- a/code/botlib/be_aas_cluster.c +++ b/code/botlib/be_aas_cluster.c @@ -152,7 +152,7 @@ int AAS_UpdatePortal(int areanum, int clusternum) { //remove the cluster portal flag contents aasworld.areasettings[areanum].contents &= ~AREACONTENTS_CLUSTERPORTAL; - Log_Write("portal area %d is seperating more than two clusters\r\n", areanum); + Log_Write("portal area %d is separating more than two clusters\r\n", areanum); return qfalse; } //end else if (aasworld.portalindexsize >= AAS_MAX_PORTALINDEXSIZE) @@ -1168,7 +1168,7 @@ void AAS_RemoveNotClusterClosingPortals(void) if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; //if the area already has a cluster set if (aasworld.areasettings[otherareanum].cluster) continue; - //another cluster is seperated by this portal + //another cluster is separated by this portal numseperatedclusters++; //flood the cluster AAS_FloodCluster_r(otherareanum, numseperatedclusters); @@ -1185,13 +1185,13 @@ void AAS_RemoveNotClusterClosingPortals(void) if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) continue; //if the area already has a cluster set if (aasworld.areasettings[otherareanum].cluster) continue; - //another cluster is seperated by this portal + //another cluster is separated by this portal numseperatedclusters++; //flood the cluster AAS_FloodCluster_r(otherareanum, numseperatedclusters); AAS_FloodClusterReachabilities(numseperatedclusters); } //end for - //a portal must seperate no more and no less than 2 clusters + //a portal must separate no more and no less than 2 clusters if (numseperatedclusters != 2) { aasworld.areasettings[i].contents &= ~AREACONTENTS_CLUSTERPORTAL; diff --git a/code/botlib/be_aas_debug.c b/code/botlib/be_aas_debug.c index ab44bc0b..b9a1465b 100644 --- a/code/botlib/be_aas_debug.c +++ b/code/botlib/be_aas_debug.c @@ -774,4 +774,5 @@ void AAS_FloodAreas(vec3_t origin) areanum = AAS_PointAreaNum(origin); cluster = AAS_AreaCluster(areanum); AAS_FloodAreas_r(areanum, cluster, done); + FreeMemory(done); } diff --git a/code/botlib/be_aas_def.h b/code/botlib/be_aas_def.h index 4e177cfa..dee60f03 100644 --- a/code/botlib/be_aas_def.h +++ b/code/botlib/be_aas_def.h @@ -39,10 +39,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define DF_AASENTCLIENT(x) (x - aasworld.entities - 1) #define DF_CLIENTAASENT(x) (&aasworld.entities[x + 1]) -#ifndef MAX_PATH - #define MAX_PATH MAX_QPATH -#endif - //structure to link entities to areas and areas to entities typedef struct aas_link_s { @@ -187,8 +183,8 @@ typedef struct aas_s float time; int numframes; //name of the aas file - char filename[MAX_PATH]; - char mapname[MAX_PATH]; + char filename[MAX_QPATH]; + char mapname[MAX_QPATH]; //bounding boxes int numbboxes; aas_bbox_t *bboxes; diff --git a/code/botlib/be_aas_entity.c b/code/botlib/be_aas_entity.c index 02699bde..c78f9e71 100644 --- a/code/botlib/be_aas_entity.c +++ b/code/botlib/be_aas_entity.c @@ -390,9 +390,9 @@ int AAS_NearestEntity(vec3_t origin, int modelindex) ent = &aasworld.entities[i]; if (ent->i.modelindex != modelindex) continue; VectorSubtract(ent->i.origin, origin, dir); - if (abs(dir[0]) < 40) + if (fabsf(dir[0]) < 40) { - if (abs(dir[1]) < 40) + if (fabsf(dir[1]) < 40) { dist = VectorLength(dir); if (dist < bestdist) diff --git a/code/botlib/be_aas_file.c b/code/botlib/be_aas_file.c index f74f5318..f4d91720 100644 --- a/code/botlib/be_aas_file.c +++ b/code/botlib/be_aas_file.c @@ -61,8 +61,8 @@ void AAS_SwapAASData(void) aasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags); for (j = 0; j < 3; j++) { - aasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]); - aasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]); + aasworld.bboxes[i].mins[j] = LittleFloat(aasworld.bboxes[i].mins[j]); + aasworld.bboxes[i].maxs[j] = LittleFloat(aasworld.bboxes[i].maxs[j]); } //end for } //end for //vertexes diff --git a/code/botlib/be_aas_main.c b/code/botlib/be_aas_main.c index 08f82135..88dfc68b 100644 --- a/code/botlib/be_aas_main.c +++ b/code/botlib/be_aas_main.c @@ -220,10 +220,9 @@ void AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_ int AAS_LoadFiles(const char *mapname) { int errnum; - char aasfile[MAX_PATH]; -// char bspfile[MAX_PATH]; + char aasfile[MAX_QPATH]; - strcpy(aasworld.mapname, mapname); + Q_strncpyz(aasworld.mapname, mapname, sizeof(aasworld.mapname)); //NOTE: first reset the entity links into the AAS areas and BSP leaves // the AAS link heap and BSP link heap are reset after respectively the // AAS file and BSP file are loaded @@ -232,17 +231,17 @@ int AAS_LoadFiles(const char *mapname) AAS_LoadBSPFile(); //load the aas file - Com_sprintf(aasfile, MAX_PATH, "maps/%s.aas", mapname); + Com_sprintf(aasfile, sizeof(aasfile), "maps/%s.aas", mapname); errnum = AAS_LoadAASFile(aasfile); if (errnum != BLERR_NOERROR) return errnum; botimport.Print(PRT_MESSAGE, "loaded %s\n", aasfile); - strncpy(aasworld.filename, aasfile, MAX_PATH); + Q_strncpyz(aasworld.filename, aasfile, sizeof(aasworld.filename)); return BLERR_NOERROR; } //end of the function AAS_LoadFiles //=========================================================================== -// called everytime a map changes +// called every time a map changes // // Parameter: - // Returns: - diff --git a/code/botlib/be_aas_move.c b/code/botlib/be_aas_move.c index c42b6cca..8ff56aa9 100644 --- a/code/botlib/be_aas_move.c +++ b/code/botlib/be_aas_move.c @@ -168,7 +168,7 @@ int AAS_AgainstLadder(vec3_t origin) //get the plane the face is in plane = &aasworld.planes[face->planenum ^ side]; //if the origin is pretty close to the plane - if (abs(DotProduct(plane->normal, origin) - plane->dist) < 3) + if (fabsf(DotProduct(plane->normal, origin) - plane->dist) < 3) { if (AAS_PointInsideFace(abs(facenum), origin, 0.1f)) return qtrue; } //end if @@ -553,7 +553,7 @@ int AAS_ClientMovementPrediction(struct aas_clientmove_s *move, //if on the ground or swimming if (onground || swimming) { - friction = swimming ? phys_friction : phys_waterfriction; + friction = swimming ? phys_waterfriction : phys_friction; //apply friction VectorScale(frame_test_vel, 1/frametime, frame_test_vel); AAS_ApplyFriction(frame_test_vel, friction, phys_stopspeed, frametime); diff --git a/code/botlib/be_aas_reach.c b/code/botlib/be_aas_reach.c index 379948aa..0124bfd2 100644 --- a/code/botlib/be_aas_reach.c +++ b/code/botlib/be_aas_reach.c @@ -439,7 +439,7 @@ int AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalor //VectorSubtract(absmaxs, bbmins, absmaxs); //link an invalid (-1) entity areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); - //get the reachable link arae + //get the reachable link area areanum = AAS_BestReachableLinkArea(areas); //unlink the invalid entity AAS_UnlinkFromAreas(areas); @@ -1416,7 +1416,7 @@ int AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(int area1num, int area2 //if there IS water the sv_maxwaterjump height below the bestend point if (aasworld.areasettings[AAS_PointAreaNum(testpoint)].areaflags & AREA_LIQUID) { - //don't create rediculous water jump reachabilities from areas very far below + //don't create ridiculous water jump reachabilities from areas very far below //the water surface if (water_bestdist < aassettings.phys_maxwaterjump + 24) { @@ -2465,8 +2465,8 @@ int AAS_Reachability_Ladder(int area1num, int area2num) VectorMA(area1point, -32, dir, area1point); VectorMA(area2point, 32, dir, area2point); // - ladderface1vertical = abs(DotProduct(plane1->normal, up)) < 0.1; - ladderface2vertical = abs(DotProduct(plane2->normal, up)) < 0.1; + ladderface1vertical = fabsf(DotProduct(plane1->normal, up)) < 0.1; + ladderface2vertical = fabsf(DotProduct(plane2->normal, up)) < 0.1; //there's only reachability between vertical ladder faces if (!ladderface1vertical && !ladderface2vertical) return qfalse; //if both vertical ladder faces @@ -2474,7 +2474,7 @@ int AAS_Reachability_Ladder(int area1num, int area2num) //and the ladder faces do not make a sharp corner && DotProduct(plane1->normal, plane2->normal) > 0.7 //and the shared edge is not too vertical - && abs(DotProduct(sharededgevec, up)) < 0.7) + && fabsf(DotProduct(sharededgevec, up)) < 0.7) { //create a new reachability link lreach = AAS_AllocReachability(); @@ -2599,7 +2599,7 @@ int AAS_Reachability_Ladder(int area1num, int area2num) if (face2->faceflags & FACE_LADDER) { plane2 = &aasworld.planes[face2->planenum]; - if (abs(DotProduct(plane2->normal, up)) < 0.1) break; + if (fabsf(DotProduct(plane2->normal, up)) < 0.1) break; } //end if } //end for //if from another area without vertical ladder faces @@ -3054,7 +3054,7 @@ void AAS_Reachability_Elevator(void) bottomorg[2] += 24; } //end else //look at adjacent areas around the top of the plat - //make larger steps to outside the plat everytime + //make larger steps to outside the plat every time for (n = 0; n < 3; n++) { for (k = 0; k < 3; k++) diff --git a/code/botlib/be_aas_route.c b/code/botlib/be_aas_route.c index bad375d4..7bdc9f22 100644 --- a/code/botlib/be_aas_route.c +++ b/code/botlib/be_aas_route.c @@ -1603,7 +1603,7 @@ int AAS_AreaRouteToGoalArea(int areanum, vec3_t origin, int goalareanum, int tra *reachnum = 0; return qtrue; } - // + //check !AAS_AreaReachability(areanum) with custom developer-only debug message if (areanum <= 0 || areanum >= aasworld.numareas) { if (botDeveloper) @@ -1620,6 +1620,10 @@ int AAS_AreaRouteToGoalArea(int areanum, vec3_t origin, int goalareanum, int tra } //end if return qfalse; } //end if + if (!aasworld.areasettings[areanum].numreachableareas || !aasworld.areasettings[goalareanum].numreachableareas) + { + return qfalse; + } //end if // make sure the routing cache doesn't grow to large while(AvailableMemory() < 1 * 1024 * 1024) { if (!AAS_FreeOldestCache()) break; diff --git a/code/botlib/be_aas_sample.c b/code/botlib/be_aas_sample.c index 095641a4..9ca18f46 100644 --- a/code/botlib/be_aas_sample.c +++ b/code/botlib/be_aas_sample.c @@ -688,7 +688,7 @@ aas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype, side = front < 0; //first put the end part of the line on the stack (back side) VectorCopy(cur_mid, tstack_p->start); - //not necesary to store because still on stack + //not necessary to store because still on stack //VectorCopy(cur_end, tstack_p->end); tstack_p->planenum = aasnode->planenum; tstack_p->nodenum = aasnode->children[!side]; @@ -874,7 +874,7 @@ int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int max side = front < 0; //first put the end part of the line on the stack (back side) VectorCopy(cur_mid, tstack_p->start); - //not necesary to store because still on stack + //not necessary to store because still on stack //VectorCopy(cur_end, tstack_p->end); tstack_p->planenum = aasnode->planenum; tstack_p->nodenum = aasnode->children[!side]; @@ -959,7 +959,7 @@ qboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float ep //edge) and through both the edge vector and the normal vector //of the plane AAS_OrthogonalToVectors(edgevec, pnormal, sepnormal); - //check on wich side of the above plane the point is + //check on which side of the above plane the point is //this is done by checking the sign of the dot product of the //vector orthogonal vector from above and the vector from the //origin (first vertex of edge) to the point diff --git a/code/botlib/be_ai_chat.c b/code/botlib/be_ai_chat.c index e90aaddc..abbcdc09 100644 --- a/code/botlib/be_ai_chat.c +++ b/code/botlib/be_ai_chat.c @@ -342,7 +342,7 @@ void BotQueueConsoleMessage(int chatstate, int type, char *message) m->handle = cs->handle; m->time = AAS_Time(); m->type = type; - strncpy(m->message, message, MAX_MESSAGE_SIZE); + Q_strncpyz(m->message, message, MAX_MESSAGE_SIZE); m->next = NULL; if (cs->lastmessage) { @@ -553,11 +553,11 @@ void StringReplaceWords(char *string, char *synonym, char *replacement) //find the synonym in the string str = StringContainsWord(string, synonym, qfalse); - //if the synonym occured in the string + //if the synonym occurred in the string while(str) { //if the synonym isn't part of the replacement which is already in the string - //usefull for abreviations + //useful for abbreviations str2 = StringContainsWord(string, replacement, qfalse); while(str2) { @@ -1456,7 +1456,7 @@ int BotFindMatch(char *str, bot_match_t *match, unsigned long int context) int i; bot_matchtemplate_t *ms; - strncpy(match->string, str, MAX_MESSAGE_SIZE); + Q_strncpyz(match->string, str, MAX_MESSAGE_SIZE); //remove any trailing enters while(strlen(match->string) && match->string[strlen(match->string)-1] == '\n') @@ -2114,7 +2114,7 @@ bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname) if (pass && ptr) { chattype = (bot_chattype_t *) ptr; - strncpy(chattype->name, token.string, MAX_CHATTYPE_NAME); + Q_strncpyz(chattype->name, token.string, MAX_CHATTYPE_NAME); chattype->firstchatmessage = NULL; //add the chat type to the chat chattype->next = chat->types; @@ -2884,7 +2884,7 @@ void BotSetChatName(int chatstate, char *name, int client) if (!cs) return; cs->client = client; Com_Memset(cs->name, 0, sizeof(cs->name)); - strncpy(cs->name, name, sizeof(cs->name)); + strncpy(cs->name, name, sizeof(cs->name)-1); cs->name[sizeof(cs->name)-1] = '\0'; } //end of the function BotSetChatName //=========================================================================== diff --git a/code/botlib/be_ai_gen.c b/code/botlib/be_ai_gen.c index 5839f8a1..3f27d9c3 100644 --- a/code/botlib/be_ai_gen.c +++ b/code/botlib/be_ai_gen.c @@ -62,7 +62,7 @@ int GeneticSelection(int numranks, float *rankings) } //end for if (sum > 0) { - //select a bot where the ones with the higest rankings have + //select a bot where the ones with the highest rankings have //the highest chance of being selected //sum *= random(); for (i = 0; i < numranks; i++) diff --git a/code/botlib/be_ai_goal.c b/code/botlib/be_ai_goal.c index 3a5d01ab..de7d6ecc 100644 --- a/code/botlib/be_ai_goal.c +++ b/code/botlib/be_ai_goal.c @@ -227,6 +227,9 @@ void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child) p2 = BotGoalStateFromHandle(parent2); c = BotGoalStateFromHandle(child); + if (!p1 || !p2 || !c) + return; + InterbreedWeightConfigs(p1->itemweightconfig, p2->itemweightconfig, c->itemweightconfig); } //end of the function BotInterbreedingGoalFuzzyLogic @@ -241,7 +244,7 @@ void BotSaveGoalFuzzyLogic(int goalstate, char *filename) //bot_goalstate_t *gs; //gs = BotGoalStateFromHandle(goalstate); - + //if (!gs) return; //WriteWeightConfig(filename, gs->itemweightconfig); } //end of the function BotSaveGoalFuzzyLogic //=========================================================================== @@ -255,7 +258,7 @@ void BotMutateGoalFuzzyLogic(int goalstate, float range) bot_goalstate_t *gs; gs = BotGoalStateFromHandle(goalstate); - + if (!gs) return; EvolveWeightConfig(gs->itemweightconfig); } //end of the function BotMutateGoalFuzzyLogic //=========================================================================== @@ -268,7 +271,7 @@ itemconfig_t *LoadItemConfig(char *filename) { int max_iteminfo; token_t token; - char path[MAX_PATH]; + char path[MAX_QPATH]; source_t *source; itemconfig_t *ic; iteminfo_t *ii; @@ -281,7 +284,7 @@ itemconfig_t *LoadItemConfig(char *filename) LibVarSet( "max_iteminfo", "256" ); } - strncpy( path, filename, MAX_PATH ); + Q_strncpyz(path, filename, sizeof(path)); PC_SetBaseFolder(BOTFILESBASEFOLDER); source = LoadSourceFile( path ); if( !source ) { @@ -314,7 +317,7 @@ itemconfig_t *LoadItemConfig(char *filename) return NULL; } //end if StripDoubleQuotes(token.string); - strncpy(ii->classname, token.string, sizeof(ii->classname)-1); + Q_strncpyz(ii->classname, token.string, sizeof(ii->classname)); if (!ReadStructure(source, &iteminfo_struct, (char *) ii)) { FreeMemory(ic); @@ -685,8 +688,7 @@ void BotGoalName(int number, char *name, int size) { if (li->number == number) { - strncpy(name, itemconfig->iteminfo[li->iteminfo].name, size-1); - name[size-1] = '\0'; + Q_strncpyz(name, itemconfig->iteminfo[li->iteminfo].name, size); return; } //end for } //end for @@ -895,6 +897,7 @@ int BotGetLevelItemGoal(int index, char *name, bot_goal_t *goal) goal->number = li->number; goal->flags = GFL_ITEM; if (li->timeout) goal->flags |= GFL_DROPPED; + goal->iteminfo = li->iteminfo; //botimport.Print(PRT_MESSAGE, "found li %s\n", itemconfig->iteminfo[li->iteminfo].name); return li->number; } //end if @@ -921,6 +924,9 @@ int BotGetMapLocationGoal(char *name, bot_goal_t *goal) goal->entitynum = 0; VectorCopy(mins, goal->mins); VectorCopy(maxs, goal->maxs); + goal->number = 0; + goal->flags = 0; + goal->iteminfo = 0; return qtrue; } //end if } //end for @@ -949,6 +955,9 @@ int BotGetNextCampSpotGoal(int num, bot_goal_t *goal) goal->entitynum = 0; VectorCopy(mins, goal->mins); VectorCopy(maxs, goal->maxs); + goal->number = 0; + goal->flags = 0; + goal->iteminfo = 0; return num+1; } //end if } //end for diff --git a/code/botlib/be_ai_move.c b/code/botlib/be_ai_move.c index 0c4de348..814089ff 100644 --- a/code/botlib/be_ai_move.c +++ b/code/botlib/be_ai_move.c @@ -1605,7 +1605,7 @@ bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t VectorSubtract(reach->start, ms->origin, dir); VectorNormalize(dir); BotCheckBlocked(ms, dir, qtrue, &result); - //if the reachability start and end are practially above each other + //if the reachability start and end are practically above each other VectorSubtract(reach->end, reach->start, dir); dir[2] = 0; reachhordist = VectorLength(dir); @@ -2054,7 +2054,7 @@ bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *rea botimport.Print(PRT_MESSAGE, "bot on elevator\n"); #endif //DEBUG_ELEVATOR //if vertically not too far from the end point - if (abs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value) + if (fabsf(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value) { #ifdef DEBUG_ELEVATOR botimport.Print(PRT_MESSAGE, "bot moving to end\n"); @@ -2744,7 +2744,7 @@ bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *r result.ideal_viewangles[PITCH] = 90; //set the view angles directly EA_View(ms->client, result.ideal_viewangles); - //view is important for the movment + //view is important for the movement result.flags |= MOVERESULT_MOVEMENTVIEWSET; //select the rocket launcher EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value); @@ -2804,7 +2804,7 @@ bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reac result.ideal_viewangles[PITCH] = 90; //set the view angles directly EA_View(ms->client, result.ideal_viewangles); - //view is important for the movment + //view is important for the movement result.flags |= MOVERESULT_MOVEMENTVIEWSET; //select the rocket launcher EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value); diff --git a/code/botlib/be_ai_weap.c b/code/botlib/be_ai_weap.c index 8fab4d79..df685114 100644 --- a/code/botlib/be_ai_weap.c +++ b/code/botlib/be_ai_weap.c @@ -199,7 +199,7 @@ weaponconfig_t *LoadWeaponConfig(char *filename) { int max_weaponinfo, max_projectileinfo; token_t token; - char path[MAX_PATH]; + char path[MAX_QPATH]; int i, j; source_t *source; weaponconfig_t *wc; @@ -219,7 +219,7 @@ weaponconfig_t *LoadWeaponConfig(char *filename) max_projectileinfo = 32; LibVarSet("max_projectileinfo", "32"); } //end if - strncpy(path, filename, MAX_PATH); + Q_strncpyz(path, filename, sizeof(path)); PC_SetBaseFolder(BOTFILESBASEFOLDER); source = LoadSourceFile(path); if (!source) diff --git a/code/botlib/be_ai_weight.c b/code/botlib/be_ai_weight.c index a6a478e3..1d73b479 100644 --- a/code/botlib/be_ai_weight.c +++ b/code/botlib/be_ai_weight.c @@ -726,7 +726,7 @@ void EvolveFuzzySeperator_r(fuzzyseperator_t *fs) //every once in a while an evolution leap occurs, mutation if (random() < 0.01) fs->weight += crandom() * (fs->maxweight - fs->minweight); else fs->weight += crandom() * (fs->maxweight - fs->minweight) * 0.5; - //modify bounds if necesary because of mutation + //modify bounds if necessary because of mutation if (fs->weight < fs->minweight) fs->minweight = fs->weight; else if (fs->weight > fs->maxweight) fs->maxweight = fs->weight; } //end else if diff --git a/code/botlib/be_ai_weight.h b/code/botlib/be_ai_weight.h index fb1c8853..283fdd06 100644 --- a/code/botlib/be_ai_weight.h +++ b/code/botlib/be_ai_weight.h @@ -64,7 +64,7 @@ typedef struct weightconfig_s weightconfig_t *ReadWeightConfig(char *filename); //free a weight configuration void FreeWeightConfig(weightconfig_t *config); -//writes a weight configuration, returns true if successfull +//writes a weight configuration, returns true if successful qboolean WriteWeightConfig(char *filename, weightconfig_t *config); //find the fuzzy weight with the given name int FindFuzzyWeight(weightconfig_t *wc, char *name); diff --git a/code/botlib/be_ea.c b/code/botlib/be_ea.c index 41653fda..efecd28d 100644 --- a/code/botlib/be_ea.c +++ b/code/botlib/be_ea.c @@ -39,7 +39,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "be_ea.h" #define MAX_USERMOVE 400 -#define MAX_COMMANDARGUMENTS 10 bot_input_t *botinputs; diff --git a/code/botlib/be_interface.c b/code/botlib/be_interface.c index 6f599753..eb0efb95 100644 --- a/code/botlib/be_interface.c +++ b/code/botlib/be_interface.c @@ -144,26 +144,7 @@ int Export_BotLibSetup(void) if(botDeveloper) { - char *homedir, *gamedir, *basegame; - char logfilename[MAX_OSPATH]; - - homedir = LibVarGetString("homedir"); - gamedir = LibVarGetString("gamedir"); - basegame = LibVarGetString("basegame"); - - if (*homedir) - { - if(*gamedir) - Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, gamedir, PATH_SEP); - else if(*basegame) - Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, basegame, PATH_SEP); - else - Com_sprintf(logfilename, sizeof(logfilename), "%s%c" BASEGAME "%cbotlib.log", homedir, PATH_SEP, PATH_SEP); - } - else - Com_sprintf(logfilename, sizeof(logfilename), "botlib.log"); - - Log_Open(logfilename); + Log_Open("botlib.log"); } botimport.Print(PRT_MESSAGE, "------- BotLib Initialization -------\n"); @@ -238,7 +219,7 @@ int Export_BotLibShutdown(void) // Returns: - // Changes Globals: - //=========================================================================== -int Export_BotLibVarSet(char *var_name, char *value) +int Export_BotLibVarSet(const char *var_name, const char *value) { LibVarSet(var_name, value); return BLERR_NOERROR; @@ -249,7 +230,7 @@ int Export_BotLibVarSet(char *var_name, char *value) // Returns: - // Changes Globals: - //=========================================================================== -int Export_BotLibVarGet(char *var_name, char *value, int size) +int Export_BotLibVarGet(const char *var_name, char *value, int size) { char *varvalue; diff --git a/code/botlib/botlib.h b/code/botlib/botlib.h index abdaa688..830a5eaa 100644 --- a/code/botlib/botlib.h +++ b/code/botlib/botlib.h @@ -409,9 +409,9 @@ typedef struct botlib_export_s //shutdown the bot library, returns BLERR_ int (*BotLibShutdown)(void); //sets a library variable returns BLERR_ - int (*BotLibVarSet)(char *var_name, char *value); + int (*BotLibVarSet)(const char *var_name, const char *value); //gets a library variable returns BLERR_ - int (*BotLibVarGet)(char *var_name, char *value, int size); + int (*BotLibVarGet)(const char *var_name, char *value, int size); //sets a C-like define returns BLERR_ int (*PC_AddGlobalDefine)(char *string); diff --git a/code/botlib/l_libvar.c b/code/botlib/l_libvar.c index 0270781f..4020d0fe 100644 --- a/code/botlib/l_libvar.c +++ b/code/botlib/l_libvar.c @@ -42,7 +42,7 @@ libvar_t *libvarlist = NULL; // Returns: - // Changes Globals: - //=========================================================================== -float LibVarStringValue(char *string) +float LibVarStringValue(const char *string) { int dotfound = 0; float value = 0; @@ -80,7 +80,7 @@ float LibVarStringValue(char *string) // Returns: - // Changes Globals: - //=========================================================================== -libvar_t *LibVarAlloc(char *var_name) +libvar_t *LibVarAlloc(const char *var_name) { libvar_t *v; @@ -128,7 +128,7 @@ void LibVarDeAllocAll(void) // Returns: - // Changes Globals: - //=========================================================================== -libvar_t *LibVarGet(char *var_name) +libvar_t *LibVarGet(const char *var_name) { libvar_t *v; @@ -147,7 +147,7 @@ libvar_t *LibVarGet(char *var_name) // Returns: - // Changes Globals: - //=========================================================================== -char *LibVarGetString(char *var_name) +char *LibVarGetString(const char *var_name) { libvar_t *v; @@ -167,7 +167,7 @@ char *LibVarGetString(char *var_name) // Returns: - // Changes Globals: - //=========================================================================== -float LibVarGetValue(char *var_name) +float LibVarGetValue(const char *var_name) { libvar_t *v; @@ -187,7 +187,7 @@ float LibVarGetValue(char *var_name) // Returns: - // Changes Globals: - //=========================================================================== -libvar_t *LibVar(char *var_name, char *value) +libvar_t *LibVar(const char *var_name, const char *value) { libvar_t *v; v = LibVarGet(var_name); @@ -210,7 +210,7 @@ libvar_t *LibVar(char *var_name, char *value) // Returns: - // Changes Globals: - //=========================================================================== -char *LibVarString(char *var_name, char *value) +char *LibVarString(const char *var_name, const char *value) { libvar_t *v; @@ -223,7 +223,7 @@ char *LibVarString(char *var_name, char *value) // Returns: - // Changes Globals: - //=========================================================================== -float LibVarValue(char *var_name, char *value) +float LibVarValue(const char *var_name, const char *value) { libvar_t *v; @@ -236,7 +236,7 @@ float LibVarValue(char *var_name, char *value) // Returns: - // Changes Globals: - //=========================================================================== -void LibVarSet(char *var_name, char *value) +void LibVarSet(const char *var_name, const char *value) { libvar_t *v; @@ -263,7 +263,7 @@ void LibVarSet(char *var_name, char *value) // Returns: - // Changes Globals: - //=========================================================================== -qboolean LibVarChanged(char *var_name) +qboolean LibVarChanged(const char *var_name) { libvar_t *v; @@ -283,7 +283,7 @@ qboolean LibVarChanged(char *var_name) // Returns: - // Changes Globals: - //=========================================================================== -void LibVarSetNotModified(char *var_name) +void LibVarSetNotModified(const char *var_name) { libvar_t *v; diff --git a/code/botlib/l_libvar.h b/code/botlib/l_libvar.h index d96685f4..531da04b 100644 --- a/code/botlib/l_libvar.h +++ b/code/botlib/l_libvar.h @@ -43,21 +43,21 @@ typedef struct libvar_s //removes all library variables void LibVarDeAllocAll(void); //gets the library variable with the given name -libvar_t *LibVarGet(char *var_name); +libvar_t *LibVarGet(const char *var_name); //gets the string of the library variable with the given name -char *LibVarGetString(char *var_name); +char *LibVarGetString(const char *var_name); //gets the value of the library variable with the given name -float LibVarGetValue(char *var_name); +float LibVarGetValue(const char *var_name); //creates the library variable if not existing already and returns it -libvar_t *LibVar(char *var_name, char *value); +libvar_t *LibVar(const char *var_name, const char *value); //creates the library variable if not existing already and returns the value -float LibVarValue(char *var_name, char *value); +float LibVarValue(const char *var_name, const char *value); //creates the library variable if not existing already and returns the value string -char *LibVarString(char *var_name, char *value); +char *LibVarString(const char *var_name, const char *value); //sets the library variable -void LibVarSet(char *var_name, char *value); +void LibVarSet(const char *var_name, const char *value); //returns true if the library variable has been modified -qboolean LibVarChanged(char *var_name); +qboolean LibVarChanged(const char *var_name); //sets the library variable to unmodified -void LibVarSetNotModified(char *var_name); +void LibVarSetNotModified(const char *var_name); diff --git a/code/botlib/l_log.c b/code/botlib/l_log.c index ee25604e..4d7c4e89 100644 --- a/code/botlib/l_log.c +++ b/code/botlib/l_log.c @@ -34,6 +34,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include "../qcommon/q_shared.h" +#include "../qcommon/qcommon.h" #include "botlib.h" #include "be_interface.h" //for botimport.Print #include "l_libvar.h" @@ -58,6 +59,7 @@ static logfile_t logfile; //=========================================================================== void Log_Open(char *filename) { + char *ospath; if (!LibVarValue("log", "0")) return; if (!filename || !strlen(filename)) { @@ -69,13 +71,14 @@ void Log_Open(char *filename) botimport.Print(PRT_ERROR, "log file %s is already opened\n", logfile.filename); return; } //end if - logfile.fp = fopen(filename, "wb"); + ospath = FS_BuildOSPath(Cvar_VariableString("fs_homepath"), Cvar_VariableString("fs_game"), filename); + logfile.fp = fopen(ospath, "wb"); if (!logfile.fp) { botimport.Print(PRT_ERROR, "can't open the log file %s\n", filename); return; } //end if - strncpy(logfile.filename, filename, MAX_LOGFILENAMESIZE); + Q_strncpyz(logfile.filename, filename, MAX_LOGFILENAMESIZE); botimport.Print(PRT_MESSAGE, "Opened log %s\n", logfile.filename); } //end of the function Log_Create //=========================================================================== diff --git a/code/botlib/l_precomp.c b/code/botlib/l_precomp.c index c0870dbe..2fbc599f 100644 --- a/code/botlib/l_precomp.c +++ b/code/botlib/l_precomp.c @@ -548,7 +548,7 @@ void PC_PrintDefineHashTable(define_t **definehash) int PC_NameHash(char *name) { - int register hash, i; + int hash, i; hash = 0; for (i = 0; name[i] != '\0'; i++) @@ -971,7 +971,7 @@ int PC_Directive_include(source_t *source) { script_t *script; token_t token; - char path[MAX_PATH]; + char path[MAX_QPATH]; #ifdef QUAKE foundfile_t file; #endif //QUAKE @@ -1035,7 +1035,7 @@ int PC_Directive_include(source_t *source) { Com_Memset(&file, 0, sizeof(foundfile_t)); script = LoadScriptFile(path); - if (script) strncpy(script->filename, path, MAX_PATH); + if (script) Q_strncpyz(script->filename, path, sizeof(script->filename)); } //end if #endif //QUAKE if (!script) @@ -1323,7 +1323,7 @@ define_t *PC_DefineFromString(char *string) script = LoadScriptMemory(string, strlen(string), "*extern"); //create a new source Com_Memset(&src, 0, sizeof(source_t)); - strncpy(src.filename, "*extern", MAX_PATH); + Q_strncpyz(src.filename, "*extern", sizeof(src.filename)); src.scriptstack = script; #if DEFINEHASHING src.definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *)); @@ -2960,7 +2960,7 @@ void PC_SetIncludePath(source_t *source, char *path) { size_t len; - Q_strncpyz(source->includepath, path, MAX_PATH-1); + Q_strncpyz(source->includepath, path, sizeof(source->includepath)-1); len = strlen(source->includepath); //add trailing path seperator @@ -3001,7 +3001,7 @@ source_t *LoadSourceFile(const char *filename) source = (source_t *) GetMemory(sizeof(source_t)); Com_Memset(source, 0, sizeof(source_t)); - strncpy(source->filename, filename, MAX_PATH); + Q_strncpyz(source->filename, filename, sizeof(source->filename)); source->scriptstack = script; source->tokens = NULL; source->defines = NULL; @@ -3034,7 +3034,7 @@ source_t *LoadSourceMemory(char *ptr, int length, char *name) source = (source_t *) GetMemory(sizeof(source_t)); Com_Memset(source, 0, sizeof(source_t)); - strncpy(source->filename, name, MAX_PATH); + Q_strncpyz(source->filename, name, sizeof(source->filename)); source->scriptstack = script; source->tokens = NULL; source->defines = NULL; diff --git a/code/botlib/l_precomp.h b/code/botlib/l_precomp.h index bdf8e9c9..cce79db9 100644 --- a/code/botlib/l_precomp.h +++ b/code/botlib/l_precomp.h @@ -29,10 +29,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *****************************************************************************/ -#ifndef MAX_PATH - #define MAX_PATH MAX_QPATH -#endif - #ifndef PATH_SEPERATORSTR #if defined(WIN32)|defined(_WIN32)|defined(__NT__)|defined(__WINDOWS__)|defined(__WINDOWS_386__) #define PATHSEPERATOR_STR "\\" diff --git a/code/botlib/l_script.c b/code/botlib/l_script.c index ee9cddc0..c9b68091 100644 --- a/code/botlib/l_script.c +++ b/code/botlib/l_script.c @@ -160,9 +160,7 @@ punctuation_t default_punctuations[] = {NULL, 0} }; -#ifdef BSPC -char basefolder[MAX_PATH]; -#else +#ifdef BOTLIB char basefolder[MAX_QPATH]; #endif @@ -220,7 +218,7 @@ char *PunctuationFromNum(script_t *script, int num) { if (script->punctuations[i].n == num) return script->punctuations[i].p; } //end for - return "unkown punctuation"; + return "unknown punctuation"; } //end of the function PunctuationFromNum //=========================================================================== // @@ -804,7 +802,7 @@ int PS_ReadPunctuation(script_t *script, token_t *token) //if the script contains the punctuation if (!strncmp(script->script_p, p, len)) { - strncpy(token->string, p, MAX_TOKEN); + Q_strncpyz(token->string, p, MAX_TOKEN); script->script_p += len; token->type = TT_PUNCTUATION; //sub type is the number of the punctuation @@ -838,7 +836,7 @@ int PS_ReadPrimitive(script_t *script, token_t *token) token->string[len] = 0; //copy the token into the script structure Com_Memcpy(&script->token, token, sizeof(token_t)); - //primitive reading successfull + //primitive reading successful return 1; } //end of the function PS_ReadPrimitive //============================================================================ @@ -1441,9 +1439,7 @@ void FreeScript(script_t *script) //============================================================================ void PS_SetBaseFolder(char *path) { -#ifdef BSPC - sprintf(basefolder, path); -#else +#ifdef BOTLIB Com_sprintf(basefolder, sizeof(basefolder), "%s", path); #endif } //end of the function PS_SetBaseFolder diff --git a/code/botlib/l_struct.c b/code/botlib/l_struct.c index 0983b4d4..0d5d6b01 100644 --- a/code/botlib/l_struct.c +++ b/code/botlib/l_struct.c @@ -221,7 +221,7 @@ int ReadString(source_t *source, fielddef_t *fd, void *p) //remove the double quotes StripDoubleQuotes(token.string); //copy the string - strncpy((char *) p, token.string, MAX_STRINGFIELD); + strncpy((char *) p, token.string, MAX_STRINGFIELD-1); //make sure the string is closed with a zero ((char *)p)[MAX_STRINGFIELD-1] = '\0'; // diff --git a/code/botlib/l_utils.h b/code/botlib/l_utils.h index 6944d06f..0c7e6fa4 100644 --- a/code/botlib/l_utils.h +++ b/code/botlib/l_utils.h @@ -30,8 +30,5 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *****************************************************************************/ #define Vector2Angles(v,a) vectoangles(v,a) -#ifndef MAX_PATH -#define MAX_PATH MAX_QPATH -#endif #define Maximum(x,y) (x > y ? x : y) #define Minimum(x,y) (x < y ? x : y) diff --git a/code/client/cl_avi.c b/code/client/cl_avi.c index 17fd371f..2f0dffd6 100644 --- a/code/client/cl_avi.c +++ b/code/client/cl_avi.c @@ -368,6 +368,9 @@ qboolean CL_OpenAVIForWriting( const char *fileName ) afd.a.rate = dma.speed; afd.a.format = WAV_FORMAT_PCM; afd.a.channels = dma.channels; + /* !!! FIXME: if CL_WriteAVIAudioFrame() is ever called from somewhere other + !!! FIXME: than S_TransferStereo16(), we will need to handle/convert + !!! FIXME: float32 samples for AVI writing. */ afd.a.bits = dma.samplebits; afd.a.sampleSize = ( afd.a.bits / 8 ) * afd.a.channels; diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index 04d56b5e..ae4a11f6 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -340,7 +340,7 @@ rescan: // the clientLevelShot command is used during development // to generate 128*128 screenshots from the intermission // point of levels for the menu system to use - // we pass it along to the cgame to make apropriate adjustments, + // we pass it along to the cgame to make appropriate adjustments, // but we also clear the console and notify lines here if ( !strcmp( cmd, "clientLevelShot" ) ) { // don't do it if we aren't running the server locally, @@ -450,7 +450,7 @@ intptr_t CL_CgameSystemCalls( intptr_t *args ) { case CG_FS_FOPENFILE: return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] ); case CG_FS_READ: - FS_Read2( VMA(1), args[2], args[3] ); + FS_Read( VMA(1), args[2], args[3] ); return 0; case CG_FS_WRITE: FS_Write( VMA(1), args[2], args[3] ); @@ -1040,7 +1040,7 @@ void CL_SetCGameTime( void ) { } // if we are playing a demo back, we can just keep reading - // messages from the demo file until the cgame definately + // messages from the demo file until the cgame definitely // has valid snapshots to interpolate between // a timedemo will always use a deterministic set of time samples diff --git a/code/client/cl_cin.c b/code/client/cl_cin.c index be4fb1bc..cdc3ab3e 100644 --- a/code/client/cl_cin.c +++ b/code/client/cl_cin.c @@ -577,8 +577,12 @@ static unsigned short yuv_to_rgb( long y, long u, long v ) g = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 8; b = (YY + ROQ_UB_tab[u]) >> 9; - if (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0; - if (r > 31) r = 31; if (g > 63) g = 63; if (b > 31) b = 31; + if (r<0) r = 0; + if (g<0) g = 0; + if (b<0) b = 0; + if (r > 31) r = 31; + if (g > 63) g = 63; + if (b > 31) b = 31; return (unsigned short)((r<<11)+(g<<5)+(b)); } @@ -598,10 +602,14 @@ static unsigned int yuv_to_rgb24( long y, long u, long v ) g = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 6; b = (YY + ROQ_UB_tab[u]) >> 6; - if (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0; - if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; + if (r<0) r = 0; + if (g<0) g = 0; + if (b<0) b = 0; + if (r > 255) r = 255; + if (g > 255) g = 255; + if (b > 255) b = 255; - return LittleLong ((r)|(g<<8)|(b<<16)|(255<<24)); + return LittleLong ((unsigned long)((r)|(g<<8)|(b<<16))|(255UL<<24)); } /****************************************************************************** @@ -1384,6 +1392,7 @@ e_status CIN_RunCinematic (int handle) RoQReset(); } else { RoQShutdown(); + return FMV_EOF; } } diff --git a/code/client/cl_console.c b/code/client/cl_console.c index 7d806e94..6a65bb79 100644 --- a/code/client/cl_console.c +++ b/code/client/cl_console.c @@ -56,6 +56,7 @@ typedef struct { console_t con; cvar_t *con_conspeed; +cvar_t *con_autoclear; cvar_t *con_notifytime; #define DEFAULT_CONSOLE_WIDTH 78 @@ -72,7 +73,10 @@ void Con_ToggleConsole_f (void) { return; } - Field_Clear( &g_consoleField ); + if ( con_autoclear->integer ) { + Field_Clear( &g_consoleField ); + } + g_consoleField.widthInChars = g_console_field_width; Con_ClearNotify (); @@ -191,6 +195,12 @@ void Con_Dump_f (void) Q_strncpyz( filename, Cmd_Argv( 1 ), sizeof( filename ) ); COM_DefaultExtension( filename, sizeof( filename ), ".txt" ); + if (!COM_CompareExtension(filename, ".txt")) + { + Com_Printf("Con_Dump_f: Only the \".txt\" extension is supported by this command!\n"); + return; + } + f = FS_FOpenFileWrite( filename ); if (!f) { @@ -348,6 +358,7 @@ void Con_Init (void) { con_notifytime = Cvar_Get ("con_notifytime", "3", 0); con_conspeed = Cvar_Get ("scr_conspeed", "3", 0); + con_autoclear = Cvar_Get("con_autoclear", "1", CVAR_ARCHIVE); Field_Clear( &g_consoleField ); g_consoleField.widthInChars = g_console_field_width; diff --git a/code/client/cl_curl.c b/code/client/cl_curl.c index 3ff5a3d8..cca6497f 100644 --- a/code/client/cl_curl.c +++ b/code/client/cl_curl.c @@ -299,6 +299,9 @@ void CL_cURL_BeginDownload( const char *localName, const char *remoteURL ) qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_FAILONERROR, 1); qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_FOLLOWLOCATION, 1); qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_MAXREDIRS, 5); + qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_PROTOCOLS, + CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | CURLPROTO_FTPS); + qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_BUFFERSIZE, CURL_MAX_READ_SIZE); clc.downloadCURLM = qcurl_multi_init(); if(!clc.downloadCURLM) { qcurl_easy_cleanup(clc.downloadCURL); diff --git a/code/client/cl_curl.h b/code/client/cl_curl.h index b361dfe6..147afc21 100644 --- a/code/client/cl_curl.h +++ b/code/client/cl_curl.h @@ -37,7 +37,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifdef WIN32 #define DEFAULT_CURL_LIB "libcurl-4.dll" #define ALTERNATE_CURL_LIB "libcurl-3.dll" -#elif defined(MACOS_X) +#elif defined(__APPLE__) #define DEFAULT_CURL_LIB "libcurl.dylib" #else #define DEFAULT_CURL_LIB "libcurl.so.4" diff --git a/code/client/cl_input.c b/code/client/cl_input.c index 296a7cc0..cfdaa1d1 100644 --- a/code/client/cl_input.c +++ b/code/client/cl_input.c @@ -320,7 +320,7 @@ void CL_KeyMove( usercmd_t *cmd ) { // // adjust for speed key / running - // the walking flag is to keep animations consistant + // the walking flag is to keep animations consistent // even during acceleration and develeration // if ( in_speed.active ^ cl_run->integer ) { @@ -392,6 +392,12 @@ CL_JoystickMove void CL_JoystickMove( usercmd_t *cmd ) { float anglespeed; + float yaw = j_yaw->value * cl.joystickAxis[j_yaw_axis->integer]; + float right = j_side->value * cl.joystickAxis[j_side_axis->integer]; + float forward = j_forward->value * cl.joystickAxis[j_forward_axis->integer]; + float pitch = j_pitch->value * cl.joystickAxis[j_pitch_axis->integer]; + float up = j_up->value * cl.joystickAxis[j_up_axis->integer]; + if ( !(in_speed.active ^ cl_run->integer) ) { cmd->buttons |= BUTTON_WALKING; } @@ -403,22 +409,22 @@ void CL_JoystickMove( usercmd_t *cmd ) { } if ( !in_strafe.active ) { - cl.viewangles[YAW] += anglespeed * j_yaw->value * cl.joystickAxis[j_yaw_axis->integer]; - cmd->rightmove = ClampChar( cmd->rightmove + (int) (j_side->value * cl.joystickAxis[j_side_axis->integer]) ); + cl.viewangles[YAW] += anglespeed * yaw; + cmd->rightmove = ClampChar( cmd->rightmove + (int)right ); } else { - cl.viewangles[YAW] += anglespeed * j_side->value * cl.joystickAxis[j_side_axis->integer]; - cmd->rightmove = ClampChar( cmd->rightmove + (int) (j_yaw->value * cl.joystickAxis[j_yaw_axis->integer]) ); + cl.viewangles[YAW] += anglespeed * right; + cmd->rightmove = ClampChar( cmd->rightmove + (int)yaw ); } if ( in_mlooking ) { - cl.viewangles[PITCH] += anglespeed * j_forward->value * cl.joystickAxis[j_forward_axis->integer]; - cmd->forwardmove = ClampChar( cmd->forwardmove + (int) (j_pitch->value * cl.joystickAxis[j_pitch_axis->integer]) ); + cl.viewangles[PITCH] += anglespeed * forward; + cmd->forwardmove = ClampChar( cmd->forwardmove + (int)pitch ); } else { - cl.viewangles[PITCH] += anglespeed * j_pitch->value * cl.joystickAxis[j_pitch_axis->integer]; - cmd->forwardmove = ClampChar( cmd->forwardmove + (int) (j_forward->value * cl.joystickAxis[j_forward_axis->integer]) ); + cl.viewangles[PITCH] += anglespeed * pitch; + cmd->forwardmove = ClampChar( cmd->forwardmove + (int)forward ); } - cmd->upmove = ClampChar( cmd->upmove + (int) (j_up->value * cl.joystickAxis[j_up_axis->integer]) ); + cmd->upmove = ClampChar( cmd->upmove + (int)up ); } /* diff --git a/code/client/cl_keys.c b/code/client/cl_keys.c index d68d8243..30690b1c 100644 --- a/code/client/cl_keys.c +++ b/code/client/cl_keys.c @@ -177,7 +177,7 @@ keyname_t keynames[] = {"PAUSE", K_PAUSE}, - {"SEMICOLON", ';'}, // because a raw semicolon seperates commands + {"SEMICOLON", ';'}, // because a raw semicolon separates commands {"WORLD_0", K_WORLD_0}, {"WORLD_1", K_WORLD_1}, @@ -289,6 +289,33 @@ keyname_t keynames[] = {"EURO", K_EURO}, {"UNDO", K_UNDO}, + {"PAD0_A", K_PAD0_A }, + {"PAD0_B", K_PAD0_B }, + {"PAD0_X", K_PAD0_X }, + {"PAD0_Y", K_PAD0_Y }, + {"PAD0_BACK", K_PAD0_BACK }, + {"PAD0_GUIDE", K_PAD0_GUIDE }, + {"PAD0_START", K_PAD0_START }, + {"PAD0_LEFTSTICK_CLICK", K_PAD0_LEFTSTICK_CLICK }, + {"PAD0_RIGHTSTICK_CLICK", K_PAD0_RIGHTSTICK_CLICK }, + {"PAD0_LEFTSHOULDER", K_PAD0_LEFTSHOULDER }, + {"PAD0_RIGHTSHOULDER", K_PAD0_RIGHTSHOULDER }, + {"PAD0_DPAD_UP", K_PAD0_DPAD_UP }, + {"PAD0_DPAD_DOWN", K_PAD0_DPAD_DOWN }, + {"PAD0_DPAD_LEFT", K_PAD0_DPAD_LEFT }, + {"PAD0_DPAD_RIGHT", K_PAD0_DPAD_RIGHT }, + + {"PAD0_LEFTSTICK_LEFT", K_PAD0_LEFTSTICK_LEFT }, + {"PAD0_LEFTSTICK_RIGHT", K_PAD0_LEFTSTICK_RIGHT }, + {"PAD0_LEFTSTICK_UP", K_PAD0_LEFTSTICK_UP }, + {"PAD0_LEFTSTICK_DOWN", K_PAD0_LEFTSTICK_DOWN }, + {"PAD0_RIGHTSTICK_LEFT", K_PAD0_RIGHTSTICK_LEFT }, + {"PAD0_RIGHTSTICK_RIGHT", K_PAD0_RIGHTSTICK_RIGHT }, + {"PAD0_RIGHTSTICK_UP", K_PAD0_RIGHTSTICK_UP }, + {"PAD0_RIGHTSTICK_DOWN", K_PAD0_RIGHTSTICK_DOWN }, + {"PAD0_LEFTTRIGGER", K_PAD0_LEFTTRIGGER }, + {"PAD0_RIGHTTRIGGER", K_PAD0_RIGHTTRIGGER }, + {NULL,0} }; @@ -586,7 +613,7 @@ void Console_Key (int key) { // enter finishes the line if ( key == K_ENTER || key == K_KP_ENTER ) { // if not in the game explicitly prepend a slash if needed - if ( clc.state != CA_ACTIVE && + if ( clc.state != CA_ACTIVE && con_autochat->integer && g_consoleField.buffer[0] && g_consoleField.buffer[0] != '\\' && g_consoleField.buffer[0] != '/' ) { @@ -608,7 +635,10 @@ void Console_Key (int key) { if ( !g_consoleField.buffer[0] ) { return; // empty lines just scroll the console without adding to history } else { - Cbuf_AddText ("cmd say "); + if ( con_autochat->integer ) { + Cbuf_AddText ("cmd say "); + } + Cbuf_AddText( g_consoleField.buffer ); Cbuf_AddText ("\n"); } @@ -795,6 +825,7 @@ to be configured even if they don't have defined names. */ int Key_StringToKeynum( char *str ) { keyname_t *kn; + int n; if ( !str || !str[0] ) { return -1; @@ -804,12 +835,9 @@ int Key_StringToKeynum( char *str ) { } // check for hex code - if ( strlen( str ) == 4 ) { - int n = Com_HexStrToInt( str ); - - if ( n >= 0 ) { - return n; - } + n = Com_HexStrToInt( str ); + if ( n >= 0 && n < MAX_KEYS ) { + return n; } // scan for a text match @@ -889,7 +917,7 @@ void Key_SetBinding( int keynum, const char *binding ) { keys[keynum].binding = CopyString( binding ); // consider this like modifying an archived cvar, so the - // file write will be triggered at the next oportunity + // file write will be triggered at the next opportunity cvar_modifiedFlags |= CVAR_ARCHIVE; } @@ -1212,6 +1240,11 @@ void CL_KeyDownEvent( int key, unsigned time ) if( keys[K_ALT].down && key == K_ENTER ) { + // don't repeat fullscreen toggle when keys are held down + if ( keys[K_ENTER].repeats > 1 ) { + return; + } + Cvar_SetValue( "r_fullscreen", !Cvar_VariableIntegerValue( "r_fullscreen" ) ); return; @@ -1270,7 +1303,7 @@ void CL_KeyDownEvent( int key, unsigned time ) // send the bound action CL_ParseBinding( key, qtrue, time ); - // distribute the key down event to the apropriate handler + // distribute the key down event to the appropriate handler if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) { Console_Key( key ); } else if ( Key_GetCatcher( ) & KEYCATCH_UI ) { @@ -1352,7 +1385,7 @@ void CL_CharEvent( int key ) { return; } - // distribute the key down event to the apropriate handler + // distribute the key down event to the appropriate handler if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) { Field_CharEvent( &g_consoleField, key ); @@ -1443,9 +1476,10 @@ void CL_LoadConsoleHistory( void ) return; } - if( consoleSaveBufferSize <= MAX_CONSOLE_SAVE_BUFFER && + if( consoleSaveBufferSize < MAX_CONSOLE_SAVE_BUFFER && FS_Read( consoleSaveBuffer, consoleSaveBufferSize, f ) == consoleSaveBufferSize ) { + consoleSaveBuffer[consoleSaveBufferSize] = '\0'; text_p = consoleSaveBuffer; for( i = COMMAND_HISTORY - 1; i >= 0; i-- ) diff --git a/code/client/cl_main.c b/code/client/cl_main.c index 81f82d09..a5f30c5d 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -573,7 +573,7 @@ CLIENT RELIABLE COMMAND COMMUNICATION ====================== CL_AddReliableCommand -The given command will be transmitted to the server, and is gauranteed to +The given command will be transmitted to the server, and is guaranteed to not have future usercmd_t executed before it is executed ====================== */ @@ -1069,7 +1069,8 @@ demo */ void CL_PlayDemo_f( void ) { char name[MAX_OSPATH]; - char *arg, *ext_test; + char arg[MAX_OSPATH]; + char *ext_test; int protocol, i; char retry[MAX_OSPATH]; @@ -1083,7 +1084,7 @@ void CL_PlayDemo_f( void ) { Cvar_Set( "sv_killserver", "2" ); // open the demo file - arg = Cmd_Argv(1); + Q_strncpyz( arg, Cmd_Argv(1), sizeof( arg ) ); CL_Disconnect( qtrue ); @@ -1244,7 +1245,7 @@ void CL_ClearMemory(qboolean shutdownRef) CL_ShutdownAll(shutdownRef); // if not running a server clear the whole hunk - if ( !com_sv_running->integer ) { + if ( !com_sv_running || !com_sv_running->integer ) { // clear the whole hunk Hunk_Clear(); // clear collision map data @@ -1417,6 +1418,7 @@ void CL_Disconnect( qboolean showMainMenu ) { for (i = 0; i < MAX_CLIENTS; i++) { opus_decoder_destroy(clc.opusDecoder[i]); } + clc.voipCodecInitialized = qfalse; } Cmd_RemoveCommand ("voip"); #endif @@ -1537,7 +1539,7 @@ void CL_RequestMotd( void ) { info[0] = 0; - Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ), "%i", ((rand() << 16) ^ rand()) ^ Com_Milliseconds()); + Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ), "%i", (int)((((unsigned int)rand() << 16) ^ (unsigned int)rand()) ^ Com_Milliseconds())); Info_SetValueForKey( info, "challenge", cls.updateChallenge ); Info_SetValueForKey( info, "renderer", cls.glconfig.renderer_string ); @@ -1689,7 +1691,7 @@ CL_Connect_f ================ */ void CL_Connect_f( void ) { - char *server; + char server[MAX_OSPATH]; const char *serverString; int argc = Cmd_Argc(); netadrtype_t family = NA_UNSPEC; @@ -1700,7 +1702,7 @@ void CL_Connect_f( void ) { } if(argc == 2) - server = Cmd_Argv(1); + Q_strncpyz( server, Cmd_Argv(1), sizeof( server ) ); else { if(!strcmp(Cmd_Argv(1), "-4")) @@ -1710,7 +1712,7 @@ void CL_Connect_f( void ) { else Com_Printf( "warning: only -4 or -6 as address type understood.\n"); - server = Cmd_Argv(2); + Q_strncpyz( server, Cmd_Argv(2), sizeof( server ) ); } // save arguments for reconnect @@ -1766,7 +1768,7 @@ void CL_Connect_f( void ) { clc.state = CA_CONNECTING; // Set a client challenge number that ideally is mirrored back by the server. - clc.challenge = ((rand() << 16) ^ rand()) ^ Com_Milliseconds(); + clc.challenge = (((unsigned int)rand() << 16) ^ (unsigned int)rand()) ^ Com_Milliseconds(); } Key_SetCatcher( 0 ); @@ -1806,7 +1808,7 @@ static void CL_CompletePlayerName( char *args, int argNum ) if( argNum == 2 ) { char names[MAX_CLIENTS][MAX_NAME_LENGTH]; - char *namesPtr[MAX_CLIENTS]; + const char *namesPtr[MAX_CLIENTS]; int i; int clientCount; int nameCount; @@ -1889,6 +1891,7 @@ void CL_Rcon_f( void ) { } NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to); + cls.rconAddress = to; } /* @@ -1957,7 +1960,7 @@ void CL_Vid_Restart_f( void ) { CL_ShutdownCGame(); // shutdown the renderer and clear the renderer interface CL_ShutdownRef(); - // client is no longer pure untill new checksums are sent + // client is no longer pure until new checksums are sent CL_ResetPureClientAtServer(); // clear pak references FS_ClearPakReferences( FS_UI_REF | FS_CGAME_REF ); @@ -1968,7 +1971,7 @@ void CL_Vid_Restart_f( void ) { cls.cgameStarted = qfalse; cls.soundRegistered = qfalse; - // unpause so the cgame definately gets a snapshot and renders a frame + // unpause so the cgame definitely gets a snapshot and renders a frame Cvar_Set("cl_paused", "0"); // initialize the renderer interface @@ -2468,7 +2471,7 @@ void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extend byte* buffptr; byte* buffend; - Com_Printf("CL_ServersResponsePacket\n"); + Com_Printf("CL_ServersResponsePacket from %s\n", NET_AdrToStringwPort(*from)); if (cls.numglobalservers == -1) { // state to detect lack of servers or lack of response @@ -2747,7 +2750,10 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { // echo request from server if ( !Q_stricmp(c, "echo") ) { - NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) ); + // NOTE: we may have to add exceptions for auth and update servers + if ( NET_CompareAdr( from, clc.serverAddress ) || NET_CompareAdr( from, cls.rconAddress ) ) { + NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) ); + } return; } @@ -2764,12 +2770,14 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { } // echo request from server - if(!Q_stricmp(c, "print")){ - s = MSG_ReadString( msg ); - - Q_strncpyz( clc.serverMessage, s, sizeof( clc.serverMessage ) ); - Com_Printf( "%s", s ); + if ( !Q_stricmp(c, "print") ) { + // NOTE: we may have to add exceptions for auth and update servers + if ( NET_CompareAdr( from, clc.serverAddress ) || NET_CompareAdr( from, cls.rconAddress ) ) { + s = MSG_ReadString( msg ); + Q_strncpyz( clc.serverMessage, s, sizeof( clc.serverMessage ) ); + Com_Printf( "%s", s ); + } return; } @@ -3208,7 +3216,7 @@ void CL_InitRef( void ) { Com_Printf("failed:\n\"%s\"\n", Sys_LibraryError()); Cvar_ForceReset("cl_renderer"); - Com_sprintf(dllName, sizeof(dllName), "renderer_opengl1_" ARCH_STRING DLL_EXT); + Com_sprintf(dllName, sizeof(dllName), "renderer_opengl2_" ARCH_STRING DLL_EXT); rendererLib = Sys_LoadDll(dllName, qfalse); } @@ -3293,7 +3301,7 @@ void CL_InitRef( void ) { re = *ret; - // unpause so the cgame definately gets a snapshot and renders a frame + // unpause so the cgame definitely gets a snapshot and renders a frame Cvar_Set( "cl_paused", "0" ); } @@ -3550,11 +3558,11 @@ void CL_Init( void ) { cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE); #ifdef USE_CURL_DLOPEN - cl_cURLLib = Cvar_Get("cl_cURLLib", DEFAULT_CURL_LIB, CVAR_ARCHIVE); + cl_cURLLib = Cvar_Get("cl_cURLLib", DEFAULT_CURL_LIB, CVAR_ARCHIVE | CVAR_PROTECTED); #endif cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); -#ifdef MACOS_X +#ifdef __APPLE__ // In game video is REALLY slow in Mac OS X right now due to driver slowness cl_inGameVideo = Cvar_Get ("r_inGameVideo", "0", CVAR_ARCHIVE); #else @@ -3571,7 +3579,7 @@ void CL_Init( void ) { m_yaw = Cvar_Get ("m_yaw", "0.022", CVAR_ARCHIVE); m_forward = Cvar_Get ("m_forward", "0.25", CVAR_ARCHIVE); m_side = Cvar_Get ("m_side", "0.25", CVAR_ARCHIVE); -#ifdef MACOS_X +#ifdef __APPLE__ // Input is jittery on OS X w/o this m_filter = Cvar_Get ("m_filter", "1", CVAR_ARCHIVE); #else @@ -3582,13 +3590,13 @@ void CL_Init( void ) { j_yaw = Cvar_Get ("j_yaw", "-0.022", CVAR_ARCHIVE); j_forward = Cvar_Get ("j_forward", "-0.25", CVAR_ARCHIVE); j_side = Cvar_Get ("j_side", "0.25", CVAR_ARCHIVE); - j_up = Cvar_Get ("j_up", "1", CVAR_ARCHIVE); + j_up = Cvar_Get ("j_up", "0", CVAR_ARCHIVE); j_pitch_axis = Cvar_Get ("j_pitch_axis", "3", CVAR_ARCHIVE); - j_yaw_axis = Cvar_Get ("j_yaw_axis", "4", CVAR_ARCHIVE); + j_yaw_axis = Cvar_Get ("j_yaw_axis", "2", CVAR_ARCHIVE); j_forward_axis = Cvar_Get ("j_forward_axis", "1", CVAR_ARCHIVE); j_side_axis = Cvar_Get ("j_side_axis", "0", CVAR_ARCHIVE); - j_up_axis = Cvar_Get ("j_up_axis", "2", CVAR_ARCHIVE); + j_up_axis = Cvar_Get ("j_up_axis", "4", CVAR_ARCHIVE); Cvar_CheckRange(j_pitch_axis, 0, MAX_JOYSTICK_AXIS-1, qtrue); Cvar_CheckRange(j_yaw_axis, 0, MAX_JOYSTICK_AXIS-1, qtrue); @@ -4157,6 +4165,10 @@ void CL_LocalServers_f( void ) { /* ================== CL_GlobalServers_f + +Originally master 0 was Internet and master 1 was MPlayer. +ioquake3 2008; added support for requesting five separate master servers using 0-4. +ioquake3 2017; made master 0 fetch all master servers and 1-5 request a single master server. ================== */ void CL_GlobalServers_f( void ) { @@ -4164,13 +4176,36 @@ void CL_GlobalServers_f( void ) { int count, i, masterNum; char command[1024], *masteraddress; - if ((count = Cmd_Argc()) < 3 || (masterNum = atoi(Cmd_Argv(1))) < 0 || masterNum > MAX_MASTER_SERVERS - 1) + if ((count = Cmd_Argc()) < 3 || (masterNum = atoi(Cmd_Argv(1))) < 0 || masterNum > MAX_MASTER_SERVERS) { - Com_Printf("usage: globalservers [keywords]\n", MAX_MASTER_SERVERS - 1); + Com_Printf("usage: globalservers [keywords]\n", MAX_MASTER_SERVERS); return; } - sprintf(command, "sv_master%d", masterNum + 1); + // request from all master servers + if ( masterNum == 0 ) { + int numAddress = 0; + + for ( i = 1; i <= MAX_MASTER_SERVERS; i++ ) { + sprintf(command, "sv_master%d", i); + masteraddress = Cvar_VariableString(command); + + if(!*masteraddress) + continue; + + numAddress++; + + Com_sprintf(command, sizeof(command), "globalservers %d %s %s\n", i, Cmd_Argv(2), Cmd_ArgsFrom(3)); + Cbuf_AddText(command); + } + + if ( !numAddress ) { + Com_Printf( "CL_GlobalServers_f: Error: No master server addresses.\n"); + } + return; + } + + sprintf(command, "sv_master%d", masterNum); masteraddress = Cvar_VariableString(command); if(!*masteraddress) @@ -4192,7 +4227,7 @@ void CL_GlobalServers_f( void ) { else if(i == 2) to.port = BigShort(PORT_MASTER); - Com_Printf("Requesting servers from master %s...\n", masteraddress); + Com_Printf("Requesting servers from %s (%s)...\n", masteraddress, NET_AdrToStringwPort(to)); cls.numglobalservers = -1; cls.pingUpdateSource = AS_GLOBAL; diff --git a/code/client/cl_parse.c b/code/client/cl_parse.c index 39682507..80bbec2d 100644 --- a/code/client/cl_parse.c +++ b/code/client/cl_parse.c @@ -399,7 +399,7 @@ void CL_SystemInfoChanged( void ) { // ehw! if (!Q_stricmp(key, "fs_game")) { - if(FS_CheckDirTraversal(value)) + if(FS_InvalidGameDir(value)) { Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value); continue; @@ -804,10 +804,10 @@ void CL_ParseVoip ( msg_t *msg, qboolean ignoreData ) { #if 0 static FILE *encio = NULL; if (encio == NULL) encio = fopen("voip-incoming-encoded.bin", "wb"); - if (encio != NULL) { fwrite(encoded, len, 1, encio); fflush(encio); } + if (encio != NULL) { fwrite(encoded, packetsize, 1, encio); fflush(encio); } static FILE *decio = NULL; if (decio == NULL) decio = fopen("voip-incoming-decoded.bin", "wb"); - if (decio != NULL) { fwrite(decoded+written, clc.speexFrameSize*2, 1, decio); fflush(decio); } + if (decio != NULL) { fwrite(decoded+written, numSamples*2, 1, decio); fflush(decio); } #endif written += numSamples; diff --git a/code/client/cl_ui.c b/code/client/cl_ui.c index 2c1519a3..c2d2d0a6 100644 --- a/code/client/cl_ui.c +++ b/code/client/cl_ui.c @@ -374,6 +374,7 @@ LAN_CompareServers static int LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ) { int res; serverInfo_t *server1, *server2; + int clients1, clients2; server1 = LAN_GetServerPtr(source, s1); server2 = LAN_GetServerPtr(source, s2); @@ -391,10 +392,19 @@ static int LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int res = Q_stricmp( server1->mapName, server2->mapName ); break; case SORT_CLIENTS: - if (server1->clients < server2->clients) { + // sub sort by max clients + if ( server1->clients == server2->clients ) { + clients1 = server1->maxClients; + clients2 = server2->maxClients; + } else { + clients1 = server1->clients; + clients2 = server2->clients; + } + + if (clients1 < clients2) { res = -1; } - else if (server1->clients > server2->clients) { + else if (clients1 > clients2) { res = 1; } else { @@ -629,9 +639,9 @@ CLUI_GetCDKey */ static void CLUI_GetCDKey( char *buf, int buflen ) { #ifndef STANDALONE - cvar_t *fs; - fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); - if (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) { + const char *gamedir; + gamedir = Cvar_VariableString( "fs_game" ); + if (UI_usesUniqueCDKey() && gamedir[0] != 0) { Com_Memcpy( buf, &cl_cdkey[16], 16); buf[16] = 0; } else { @@ -651,9 +661,9 @@ CLUI_SetCDKey */ #ifndef STANDALONE static void CLUI_SetCDKey( char *buf ) { - cvar_t *fs; - fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); - if (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) { + const char *gamedir; + gamedir = Cvar_VariableString( "fs_game" ); + if (UI_usesUniqueCDKey() && gamedir[0] != 0) { Com_Memcpy( &cl_cdkey[16], buf, 16 ); cl_cdkey[32] = 0; // set the flag so the fle will be written at the next opportunity @@ -780,7 +790,7 @@ intptr_t CL_UISystemCalls( intptr_t *args ) { return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] ); case UI_FS_READ: - FS_Read2( VMA(1), args[2], args[3] ); + FS_Read( VMA(1), args[2], args[3] ); return 0; case UI_FS_WRITE: diff --git a/code/client/client.h b/code/client/client.h index 0fe3889c..0d3e1c33 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -344,6 +344,8 @@ typedef struct { netadr_t authorizeServer; + netadr_t rconAddress; + // rendering info glconfig_t glconfig; qhandle_t charSetShader; diff --git a/code/client/keycodes.h b/code/client/keycodes.h index 706ca1b0..e813368c 100644 --- a/code/client/keycodes.h +++ b/code/client/keycodes.h @@ -260,6 +260,36 @@ typedef enum { K_EURO, K_UNDO, + // Gamepad controls + // Ordered to match SDL2 game controller buttons and axes + // Do not change this order without also changing IN_GamepadMove() in SDL_input.c + K_PAD0_A, + K_PAD0_B, + K_PAD0_X, + K_PAD0_Y, + K_PAD0_BACK, + K_PAD0_GUIDE, + K_PAD0_START, + K_PAD0_LEFTSTICK_CLICK, + K_PAD0_RIGHTSTICK_CLICK, + K_PAD0_LEFTSHOULDER, + K_PAD0_RIGHTSHOULDER, + K_PAD0_DPAD_UP, + K_PAD0_DPAD_DOWN, + K_PAD0_DPAD_LEFT, + K_PAD0_DPAD_RIGHT, + + K_PAD0_LEFTSTICK_LEFT, + K_PAD0_LEFTSTICK_RIGHT, + K_PAD0_LEFTSTICK_UP, + K_PAD0_LEFTSTICK_DOWN, + K_PAD0_RIGHTSTICK_LEFT, + K_PAD0_RIGHTSTICK_RIGHT, + K_PAD0_RIGHTSTICK_UP, + K_PAD0_RIGHTSTICK_DOWN, + K_PAD0_LEFTTRIGGER, + K_PAD0_RIGHTTRIGGER, + // Pseudo-key that brings the console down K_CONSOLE, diff --git a/code/client/qal.h b/code/client/qal.h index 9964ff40..e92758a8 100644 --- a/code/client/qal.h +++ b/code/client/qal.h @@ -37,8 +37,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../AL/al.h" #include "../AL/alc.h" #else -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__APPLE__) // MSVC users must install the OpenAL SDK which doesn't use the AL/*.h scheme. + // OSX framework also needs this #include #include #else diff --git a/code/client/snd_adpcm.c b/code/client/snd_adpcm.c index 4e138726..1a114edf 100644 --- a/code/client/snd_adpcm.c +++ b/code/client/snd_adpcm.c @@ -25,7 +25,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* ** Intel/DVI ADPCM coder/decoder. ** -** The algorithm for this coder was taken from the IMA Compatability Project +** The algorithm for this coder was taken from the IMA Compatibility Project ** proceedings, Vol 2, Number 2; May 1992. ** ** Version 1.2, 18-Dec-92. diff --git a/code/client/snd_altivec.c b/code/client/snd_altivec.c new file mode 100644 index 00000000..e051dda9 --- /dev/null +++ b/code/client/snd_altivec.c @@ -0,0 +1,229 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +/* This file is only compiled for PowerPC builds with Altivec support. + Altivec intrinsics need to be in a separate file, so GCC's -maltivec + command line can enable them, but give us the option to _not_ use that + on other files, where the compiler might then generate Altivec + instructions for normal floating point, crashing on G3 (etc) processors. */ + +#include "client.h" +#include "snd_local.h" + +#if idppc_altivec + +#if !defined(__APPLE__) +#include +#endif + +void S_PaintChannelFrom16_altivec( portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE], int snd_vol, channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) { + int data, aoff, boff; + int leftvol, rightvol; + int i, j; + portable_samplepair_t *samp; + sndBuffer *chunk; + short *samples; + float ooff, fdata[2], fdiv, fleftvol, frightvol; + + if (sc->soundChannels <= 0) { + return; + } + + samp = &paintbuffer[ bufferOffset ]; + + if (ch->doppler) { + sampleOffset = sampleOffset*ch->oldDopplerScale; + } + + if ( sc->soundChannels == 2 ) { + sampleOffset *= sc->soundChannels; + + if ( sampleOffset & 1 ) { + sampleOffset &= ~1; + } + } + + chunk = sc->soundData; + while (sampleOffset>=SND_CHUNK_SIZE) { + chunk = chunk->next; + sampleOffset -= SND_CHUNK_SIZE; + if (!chunk) { + chunk = sc->soundData; + } + } + + if (!ch->doppler || ch->dopplerScale==1.0f) { + vector signed short volume_vec; + vector unsigned int volume_shift; + int vectorCount, samplesLeft, chunkSamplesLeft; + leftvol = ch->leftvol*snd_vol; + rightvol = ch->rightvol*snd_vol; + samples = chunk->sndChunk; + ((short *)&volume_vec)[0] = leftvol; + ((short *)&volume_vec)[1] = leftvol; + ((short *)&volume_vec)[4] = leftvol; + ((short *)&volume_vec)[5] = leftvol; + ((short *)&volume_vec)[2] = rightvol; + ((short *)&volume_vec)[3] = rightvol; + ((short *)&volume_vec)[6] = rightvol; + ((short *)&volume_vec)[7] = rightvol; + volume_shift = vec_splat_u32(8); + i = 0; + + while(i < count) { + /* Try to align destination to 16-byte boundary */ + while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) { + data = samples[sampleOffset++]; + samp[i].left += (data * leftvol)>>8; + + if ( sc->soundChannels == 2 ) { + data = samples[sampleOffset++]; + } + samp[i].right += (data * rightvol)>>8; + + if (sampleOffset == SND_CHUNK_SIZE) { + chunk = chunk->next; + samples = chunk->sndChunk; + sampleOffset = 0; + } + i++; + } + /* Destination is now aligned. Process as many 8-sample + chunks as we can before we run out of room from the current + sound chunk. We do 8 per loop to avoid extra source data reads. */ + samplesLeft = count - i; + chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset; + if(samplesLeft > chunkSamplesLeft) + samplesLeft = chunkSamplesLeft; + + vectorCount = samplesLeft / 8; + + if(vectorCount) + { + vector unsigned char tmp; + vector short s0, s1, sampleData0, sampleData1; + vector signed int merge0, merge1; + vector signed int d0, d1, d2, d3; + vector unsigned char samplePermute0 = + VECCONST_UINT8(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7); + vector unsigned char samplePermute1 = + VECCONST_UINT8(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15); + vector unsigned char loadPermute0, loadPermute1; + + // Rather than permute the vectors after we load them to do the sample + // replication and rearrangement, we permute the alignment vector so + // we do everything in one step below and avoid data shuffling. + tmp = vec_lvsl(0,&samples[sampleOffset]); + loadPermute0 = vec_perm(tmp,tmp,samplePermute0); + loadPermute1 = vec_perm(tmp,tmp,samplePermute1); + + s0 = *(vector short *)&samples[sampleOffset]; + while(vectorCount) + { + /* Load up source (16-bit) sample data */ + s1 = *(vector short *)&samples[sampleOffset+7]; + + /* Load up destination sample data */ + d0 = *(vector signed int *)&samp[i]; + d1 = *(vector signed int *)&samp[i+2]; + d2 = *(vector signed int *)&samp[i+4]; + d3 = *(vector signed int *)&samp[i+6]; + + sampleData0 = vec_perm(s0,s1,loadPermute0); + sampleData1 = vec_perm(s0,s1,loadPermute1); + + merge0 = vec_mule(sampleData0,volume_vec); + merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */ + + merge1 = vec_mulo(sampleData0,volume_vec); + merge1 = vec_sra(merge1,volume_shift); + + d0 = vec_add(merge0,d0); + d1 = vec_add(merge1,d1); + + merge0 = vec_mule(sampleData1,volume_vec); + merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */ + + merge1 = vec_mulo(sampleData1,volume_vec); + merge1 = vec_sra(merge1,volume_shift); + + d2 = vec_add(merge0,d2); + d3 = vec_add(merge1,d3); + + /* Store destination sample data */ + *(vector signed int *)&samp[i] = d0; + *(vector signed int *)&samp[i+2] = d1; + *(vector signed int *)&samp[i+4] = d2; + *(vector signed int *)&samp[i+6] = d3; + + i += 8; + vectorCount--; + s0 = s1; + sampleOffset += 8; + } + if (sampleOffset == SND_CHUNK_SIZE) { + chunk = chunk->next; + samples = chunk->sndChunk; + sampleOffset = 0; + } + } + } + } else { + fleftvol = ch->leftvol*snd_vol; + frightvol = ch->rightvol*snd_vol; + + ooff = sampleOffset; + samples = chunk->sndChunk; + + for ( i=0 ; idopplerScale * sc->soundChannels; + boff = ooff; + fdata[0] = fdata[1] = 0; + for (j=aoff; jsoundChannels) { + if (j == SND_CHUNK_SIZE) { + chunk = chunk->next; + if (!chunk) { + chunk = sc->soundData; + } + samples = chunk->sndChunk; + ooff -= SND_CHUNK_SIZE; + } + if ( sc->soundChannels == 2 ) { + fdata[0] += samples[j&(SND_CHUNK_SIZE-1)]; + fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)]; + } else { + fdata[0] += samples[j&(SND_CHUNK_SIZE-1)]; + fdata[1] += samples[j&(SND_CHUNK_SIZE-1)]; + } + } + fdiv = 256 * (boff-aoff) / sc->soundChannels; + samp[i].left += (fdata[0] * fleftvol)/fdiv; + samp[i].right += (fdata[1] * frightvol)/fdiv; + } + } +} + + +#endif + diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index e243f406..ba4ac961 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -98,9 +98,9 @@ void S_Base_SoundInfo(void) { if (!s_soundStarted) { Com_Printf ("sound system not started\n"); } else { - Com_Printf("%5d stereo\n", dma.channels - 1); + Com_Printf("%5d channels\n", dma.channels); Com_Printf("%5d samples\n", dma.samples); - Com_Printf("%5d samplebits\n", dma.samplebits); + Com_Printf("%5d samplebits (%s)\n", dma.samplebits, dma.isfloat ? "float" : "int"); Com_Printf("%5d submission_chunk\n", dma.submission_chunk); Com_Printf("%5d speed\n", dma.speed); Com_Printf("%p dma buffer\n", dma.buffer); @@ -119,32 +119,31 @@ void S_Base_SoundInfo(void) { static void S_Base_StartCapture( void ) { - // !!! FIXME: write me. + SNDDMA_StartCapture(); } static int S_Base_AvailableCaptureSamples( void ) { - // !!! FIXME: write me. - return 0; + return SNDDMA_AvailableCaptureSamples(); } static void S_Base_Capture( int samples, byte *data ) { - // !!! FIXME: write me. + SNDDMA_Capture(samples, data); } static void S_Base_StopCapture( void ) { - // !!! FIXME: write me. + SNDDMA_StopCapture(); } static void S_Base_MasterGain( float val ) { - // !!! FIXME: write me. + SNDDMA_MasterGain(val); } #endif @@ -432,7 +431,7 @@ void S_SpatializeOrigin (vec3_t origin, int master_vol, int *left_vol, int *righ const float dist_mult = SOUND_ATTENUATE; - // calculate stereo seperation and distance attenuation + // calculate stereo separation and distance attenuation VectorSubtract(origin, listener_origin, source_vec); dist = VectorNormalize(source_vec); @@ -1243,9 +1242,6 @@ void S_GetSoundtime(void) int samplepos; static int buffers; static int oldsamplepos; - int fullsamples; - - fullsamples = dma.samples / dma.channels; if( CL_VideoRecording( ) ) { @@ -1269,13 +1265,13 @@ void S_GetSoundtime(void) if (s_paintedtime > 0x40000000) { // time to chop things off to avoid 32 bit limits buffers = 0; - s_paintedtime = fullsamples; + s_paintedtime = dma.fullsamples; S_Base_StopAllSounds (); } } oldsamplepos = samplepos; - s_soundtime = buffers*fullsamples + samplepos/dma.channels; + s_soundtime = buffers*dma.fullsamples + samplepos/dma.channels; #if 0 // check to make sure that we haven't overshot @@ -1296,7 +1292,6 @@ void S_GetSoundtime(void) void S_Update_(void) { unsigned endtime; - int samps; static float lastTime = 0.0f; float ma, op; float thisTime, sane; @@ -1340,9 +1335,8 @@ void S_Update_(void) { & ~(dma.submission_chunk-1); // never mix more than the complete buffer - samps = dma.samples >> (dma.channels-1); - if (endtime - s_soundtime > samps) - endtime = s_soundtime + samps; + if (endtime - s_soundtime > dma.fullsamples) + endtime = s_soundtime + dma.fullsamples; diff --git a/code/client/snd_local.h b/code/client/snd_local.h index e0f5b1d0..65392e36 100644 --- a/code/client/snd_local.h +++ b/code/client/snd_local.h @@ -65,8 +65,10 @@ typedef struct sfx_s { typedef struct { int channels; int samples; // mono samples in buffer + int fullsamples; // samples with all channels in buffer (samples divided by channels) int submission_chunk; // don't mix less than this # int samplebits; + int isfloat; int speed; byte *buffer; } dma_t; @@ -175,6 +177,15 @@ void SNDDMA_BeginPainting (void); void SNDDMA_Submit(void); +#ifdef USE_VOIP +void SNDDMA_StartCapture(void); +int SNDDMA_AvailableCaptureSamples(void); +void SNDDMA_Capture(int samples, byte *data); +void SNDDMA_StopCapture(void); +void SNDDMA_MasterGain(float val); +#endif + + //==================================================================== #define MAX_CHANNELS 96 @@ -254,3 +265,7 @@ typedef enum typedef int srcHandle_t; qboolean S_AL_Init( soundInterface_t *si ); + +#ifdef idppc_altivec +void S_PaintChannelFrom16_altivec( portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE], int snd_vol, channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ); +#endif diff --git a/code/client/snd_main.c b/code/client/snd_main.c index f0bce67b..f9e6941f 100644 --- a/code/client/snd_main.c +++ b/code/client/snd_main.c @@ -498,7 +498,7 @@ void S_Init( void ) Cmd_AddCommand( "s_stop", S_StopAllSounds ); Cmd_AddCommand( "s_info", S_SoundInfo ); - cv = Cvar_Get( "s_useOpenAL", "1", CVAR_ARCHIVE ); + cv = Cvar_Get( "s_useOpenAL", "1", CVAR_ARCHIVE | CVAR_LATCH ); if( cv->integer ) { //OpenAL started = S_AL_Init( &si ); diff --git a/code/client/snd_mem.c b/code/client/snd_mem.c index 655ae420..b692eb57 100644 --- a/code/client/snd_mem.c +++ b/code/client/snd_mem.c @@ -126,20 +126,22 @@ static int ResampleSfx( sfx_t *sfx, int channels, int inrate, int inwidth, int s outcount = samples / stepscale; + srcsample = 0; samplefrac = 0; fracstep = stepscale * 256 * channels; chunk = sfx->soundData; for (i=0 ; i> 8; + srcsample += samplefrac >> 8; + samplefrac &= 255; samplefrac += fracstep; for (j=0 ; j> 8; + srcsample += samplefrac >> 8; + samplefrac &= 255; samplefrac += fracstep; for (j=0 ; j -#endif static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; static int snd_vol; @@ -122,24 +119,24 @@ void S_TransferStereo16 (unsigned long *pbuf, int endtime) while (ls_paintedtime < endtime) { // handle recirculating buffer issues - lpos = ls_paintedtime & ((dma.samples>>1)-1); + lpos = ls_paintedtime % dma.fullsamples; - snd_out = (short *) pbuf + (lpos<<1); + snd_out = (short *) pbuf + (lpos<<1); // lpos * dma.channels - snd_linear_count = (dma.samples>>1) - lpos; + snd_linear_count = dma.fullsamples - lpos; if (ls_paintedtime + snd_linear_count > endtime) snd_linear_count = endtime - ls_paintedtime; - snd_linear_count <<= 1; + snd_linear_count <<= 1; // snd_linear_count *= dma.channels // write a linear blast of samples S_WriteLinearBlastStereo16 (); snd_p += snd_linear_count; - ls_paintedtime += (snd_linear_count>>1); + ls_paintedtime += (snd_linear_count>>1); // snd_linear_count / dma.channels if( CL_VideoRecording( ) ) - CL_WriteAVIAudioFrame( (byte *)snd_out, snd_linear_count << 1 ); + CL_WriteAVIAudioFrame( (byte *)snd_out, snd_linear_count << 1 ); // snd_linear_count * (dma.samplebits/8) } } @@ -153,18 +150,16 @@ void S_TransferPaintBuffer(int endtime) { int out_idx; int count; - int out_mask; int *p; int step; int val; + int i; unsigned long *pbuf; pbuf = (unsigned long *)dma.buffer; if ( s_testsound->integer ) { - int i; - // write a fixed sine wave count = (endtime - s_paintedtime); for (i=0 ; i= 2) + { + val = 0; + } + else + { + val = *p >> 8; + p+= step; + } + if (val > 0x7fff) + val = 0x7fff; + else if (val < -32767) /* clamp to one less than max to make division max out at -1.0f. */ + val = -32767; + out[out_idx] = ((float) val) / 32767.0f; + out_idx = (out_idx + 1) % dma.samples; + } + } + else if (dma.samplebits == 16) { short *out = (short *) pbuf; - while (count--) + for (i=0 ; i> 8; - p+= step; + if ((i % dma.channels) >= 2) + { + val = 0; + } + else + { + val = *p >> 8; + p+= step; + } if (val > 0x7fff) val = 0x7fff; else if (val < -32768) val = -32768; out[out_idx] = val; - out_idx = (out_idx + 1) & out_mask; + out_idx = (out_idx + 1) % dma.samples; } } else if (dma.samplebits == 8) { unsigned char *out = (unsigned char *) pbuf; - while (count--) + for (i=0 ; i> 8; - p+= step; + if ((i % dma.channels) >= 2) + { + val = 0; + } + else + { + val = *p >> 8; + p+= step; + } if (val > 0x7fff) val = 0x7fff; else if (val < -32768) val = -32768; out[out_idx] = (val>>8) + 128; - out_idx = (out_idx + 1) & out_mask; + out_idx = (out_idx + 1) % dma.samples; } } } @@ -226,197 +256,6 @@ CHANNEL MIXING =============================================================================== */ -#if idppc_altivec -static void S_PaintChannelFrom16_altivec( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) { - int data, aoff, boff; - int leftvol, rightvol; - int i, j; - portable_samplepair_t *samp; - sndBuffer *chunk; - short *samples; - float ooff, fdata[2], fdiv, fleftvol, frightvol; - - if (sc->soundChannels <= 0) { - return; - } - - samp = &paintbuffer[ bufferOffset ]; - - if (ch->doppler) { - sampleOffset = sampleOffset*ch->oldDopplerScale; - } - - if ( sc->soundChannels == 2 ) { - sampleOffset *= sc->soundChannels; - - if ( sampleOffset & 1 ) { - sampleOffset &= ~1; - } - } - - chunk = sc->soundData; - while (sampleOffset>=SND_CHUNK_SIZE) { - chunk = chunk->next; - sampleOffset -= SND_CHUNK_SIZE; - if (!chunk) { - chunk = sc->soundData; - } - } - - if (!ch->doppler || ch->dopplerScale==1.0f) { - vector signed short volume_vec; - vector unsigned int volume_shift; - int vectorCount, samplesLeft, chunkSamplesLeft; - leftvol = ch->leftvol*snd_vol; - rightvol = ch->rightvol*snd_vol; - samples = chunk->sndChunk; - ((short *)&volume_vec)[0] = leftvol; - ((short *)&volume_vec)[1] = leftvol; - ((short *)&volume_vec)[4] = leftvol; - ((short *)&volume_vec)[5] = leftvol; - ((short *)&volume_vec)[2] = rightvol; - ((short *)&volume_vec)[3] = rightvol; - ((short *)&volume_vec)[6] = rightvol; - ((short *)&volume_vec)[7] = rightvol; - volume_shift = vec_splat_u32(8); - i = 0; - - while(i < count) { - /* Try to align destination to 16-byte boundary */ - while(i < count && (((unsigned long)&samp[i] & 0x1f) || ((count-i) < 8) || ((SND_CHUNK_SIZE - sampleOffset) < 8))) { - data = samples[sampleOffset++]; - samp[i].left += (data * leftvol)>>8; - - if ( sc->soundChannels == 2 ) { - data = samples[sampleOffset++]; - } - samp[i].right += (data * rightvol)>>8; - - if (sampleOffset == SND_CHUNK_SIZE) { - chunk = chunk->next; - samples = chunk->sndChunk; - sampleOffset = 0; - } - i++; - } - /* Destination is now aligned. Process as many 8-sample - chunks as we can before we run out of room from the current - sound chunk. We do 8 per loop to avoid extra source data reads. */ - samplesLeft = count - i; - chunkSamplesLeft = SND_CHUNK_SIZE - sampleOffset; - if(samplesLeft > chunkSamplesLeft) - samplesLeft = chunkSamplesLeft; - - vectorCount = samplesLeft / 8; - - if(vectorCount) - { - vector unsigned char tmp; - vector short s0, s1, sampleData0, sampleData1; - vector signed int merge0, merge1; - vector signed int d0, d1, d2, d3; - vector unsigned char samplePermute0 = - VECCONST_UINT8(0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7); - vector unsigned char samplePermute1 = - VECCONST_UINT8(8, 9, 12, 13, 8, 9, 12, 13, 10, 11, 14, 15, 10, 11, 14, 15); - vector unsigned char loadPermute0, loadPermute1; - - // Rather than permute the vectors after we load them to do the sample - // replication and rearrangement, we permute the alignment vector so - // we do everything in one step below and avoid data shuffling. - tmp = vec_lvsl(0,&samples[sampleOffset]); - loadPermute0 = vec_perm(tmp,tmp,samplePermute0); - loadPermute1 = vec_perm(tmp,tmp,samplePermute1); - - s0 = *(vector short *)&samples[sampleOffset]; - while(vectorCount) - { - /* Load up source (16-bit) sample data */ - s1 = *(vector short *)&samples[sampleOffset+7]; - - /* Load up destination sample data */ - d0 = *(vector signed int *)&samp[i]; - d1 = *(vector signed int *)&samp[i+2]; - d2 = *(vector signed int *)&samp[i+4]; - d3 = *(vector signed int *)&samp[i+6]; - - sampleData0 = vec_perm(s0,s1,loadPermute0); - sampleData1 = vec_perm(s0,s1,loadPermute1); - - merge0 = vec_mule(sampleData0,volume_vec); - merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */ - - merge1 = vec_mulo(sampleData0,volume_vec); - merge1 = vec_sra(merge1,volume_shift); - - d0 = vec_add(merge0,d0); - d1 = vec_add(merge1,d1); - - merge0 = vec_mule(sampleData1,volume_vec); - merge0 = vec_sra(merge0,volume_shift); /* Shift down to proper range */ - - merge1 = vec_mulo(sampleData1,volume_vec); - merge1 = vec_sra(merge1,volume_shift); - - d2 = vec_add(merge0,d2); - d3 = vec_add(merge1,d3); - - /* Store destination sample data */ - *(vector signed int *)&samp[i] = d0; - *(vector signed int *)&samp[i+2] = d1; - *(vector signed int *)&samp[i+4] = d2; - *(vector signed int *)&samp[i+6] = d3; - - i += 8; - vectorCount--; - s0 = s1; - sampleOffset += 8; - } - if (sampleOffset == SND_CHUNK_SIZE) { - chunk = chunk->next; - samples = chunk->sndChunk; - sampleOffset = 0; - } - } - } - } else { - fleftvol = ch->leftvol*snd_vol; - frightvol = ch->rightvol*snd_vol; - - ooff = sampleOffset; - samples = chunk->sndChunk; - - for ( i=0 ; idopplerScale * sc->soundChannels; - boff = ooff; - fdata[0] = fdata[1] = 0; - for (j=aoff; jsoundChannels) { - if (j == SND_CHUNK_SIZE) { - chunk = chunk->next; - if (!chunk) { - chunk = sc->soundData; - } - samples = chunk->sndChunk; - ooff -= SND_CHUNK_SIZE; - } - if ( sc->soundChannels == 2 ) { - fdata[0] += samples[j&(SND_CHUNK_SIZE-1)]; - fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)]; - } else { - fdata[0] += samples[j&(SND_CHUNK_SIZE-1)]; - fdata[1] += samples[j&(SND_CHUNK_SIZE-1)]; - } - } - fdiv = 256 * (boff-aoff) / sc->soundChannels; - samp[i].left += (fdata[0] * fleftvol)/fdiv; - samp[i].right += (fdata[1] * frightvol)/fdiv; - } - } -} -#endif - static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) { int data, aoff, boff; int leftvol, rightvol; @@ -515,8 +354,8 @@ static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int cou static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) { #if idppc_altivec if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - S_PaintChannelFrom16_altivec( ch, sc, count, sampleOffset, bufferOffset ); + // must be in a separate translation unit or G3 systems will crash. + S_PaintChannelFrom16_altivec( paintbuffer, snd_vol, ch, sc, count, sampleOffset, bufferOffset ); return; } #endif diff --git a/code/client/snd_openal.c b/code/client/snd_openal.c index a1db8da3..4d368517 100644 --- a/code/client/snd_openal.c +++ b/code/client/snd_openal.c @@ -692,7 +692,7 @@ typedef struct src_s qboolean local; // Is this local (relative to the cam) } src_t; -#ifdef MACOS_X +#ifdef __APPLE__ #define MAX_SRC 64 #else #define MAX_SRC 128 @@ -1031,7 +1031,8 @@ static void S_AL_NewLoopMaster(src_t *rmSource, qboolean iskilled) S_AL_SaveLoopPos(rmSource, rmSource->alSource); } } - else if(rmSource == &srcList[curSfx->masterLoopSrc]) + else if(curSfx->masterLoopSrc != -1 && + rmSource == &srcList[curSfx->masterLoopSrc]) { int firstInactive = -1; @@ -2350,9 +2351,11 @@ static ALCdevice *alCaptureDevice; static cvar_t *s_alCapture; #endif -#ifdef _WIN32 +#if defined(_WIN64) +#define ALDRIVER_DEFAULT "OpenAL64.dll" +#elif defined(_WIN32) #define ALDRIVER_DEFAULT "OpenAL32.dll" -#elif defined(MACOS_X) +#elif defined(__APPLE__) #define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL" #elif defined(__OpenBSD__) #define ALDRIVER_DEFAULT "libopenal.so" @@ -3266,7 +3269,7 @@ qboolean S_AL_Init( soundInterface_t *si ) s_alRolloff = Cvar_Get( "s_alRolloff", "2", CVAR_CHEAT); s_alGraceDistance = Cvar_Get("s_alGraceDistance", "512", CVAR_CHEAT); - s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH ); + s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH | CVAR_PROTECTED ); s_alInputDevice = Cvar_Get( "s_alInputDevice", "", CVAR_ARCHIVE | CVAR_LATCH ); s_alDevice = Cvar_Get("s_alDevice", "", CVAR_ARCHIVE | CVAR_LATCH); @@ -3404,7 +3407,7 @@ qboolean S_AL_Init( soundInterface_t *si ) #endif else { -#ifdef MACOS_X +#ifdef __APPLE__ // !!! FIXME: Apple has a 1.1-compliant OpenAL, which includes // !!! FIXME: capture support, but they don't list it in the // !!! FIXME: extension string. We need to check the version string, diff --git a/code/client/snd_wavelet.c b/code/client/snd_wavelet.c index 3d8f5c7b..e051da29 100644 --- a/code/client/snd_wavelet.c +++ b/code/client/snd_wavelet.c @@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA void daub4(float b[], unsigned long n, int isign) { float wksp[4097] = { 0.0f }; - float *a=b-1; // numerical recipies so a[1] = b[0] +#define a(x) b[(x)-1] // numerical recipies so a[1] = b[0] unsigned long nh,nh1,i,j; @@ -39,22 +39,23 @@ void daub4(float b[], unsigned long n, int isign) nh1=(nh=n >> 1)+1; if (isign >= 0) { for (i=1,j=1;j<=n-3;j+=2,i++) { - wksp[i] = C0*a[j]+C1*a[j+1]+C2*a[j+2]+C3*a[j+3]; - wksp[i+nh] = C3*a[j]-C2*a[j+1]+C1*a[j+2]-C0*a[j+3]; + wksp[i] = C0*a(j)+C1*a(j+1)+C2*a(j+2)+C3*a(j+3); + wksp[i+nh] = C3*a(j)-C2*a(j+1)+C1*a(j+2)-C0*a(j+3); } - wksp[i ] = C0*a[n-1]+C1*a[n]+C2*a[1]+C3*a[2]; - wksp[i+nh] = C3*a[n-1]-C2*a[n]+C1*a[1]-C0*a[2]; + wksp[i ] = C0*a(n-1)+C1*a(n)+C2*a(1)+C3*a(2); + wksp[i+nh] = C3*a(n-1)-C2*a(n)+C1*a(1)-C0*a(2); } else { - wksp[1] = C2*a[nh]+C1*a[n]+C0*a[1]+C3*a[nh1]; - wksp[2] = C3*a[nh]-C0*a[n]+C1*a[1]-C2*a[nh1]; + wksp[1] = C2*a(nh)+C1*a(n)+C0*a(1)+C3*a(nh1); + wksp[2] = C3*a(nh)-C0*a(n)+C1*a(1)-C2*a(nh1); for (i=1,j=3;isurfacePlane], plane, &flipped)) { continue; } - // see if the plane is allready present + // see if the plane is already present for ( i = 0 ; i < facet->numBorders ; i++ ) { if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) break; @@ -933,7 +932,7 @@ void CM_AddFacetBevels( facet_t *facet ) { if (CM_PlaneEqual(&planes[facet->surfacePlane], plane, &flipped)) { continue; } - // see if the plane is allready present + // see if the plane is already present for ( i = 0 ; i < facet->numBorders ; i++ ) { if (CM_PlaneEqual(&planes[facet->borderPlanes[i]], plane, &flipped)) { break; @@ -1106,7 +1105,7 @@ static void CM_PatchCollideFromGrid( cGrid_t *grid, patchCollide_t *pf ) { numFacets++; } } else { - // two seperate triangles + // two separate triangles facet->surfacePlane = gridPlanes[i][j][0]; facet->numBorders = 3; facet->borderPlanes[0] = borders[EN_TOP]; @@ -1215,7 +1214,7 @@ struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *p CM_RemoveDegenerateColumns( &grid ); // we now have a grid of points exactly on the curve - // the aproximate surface defined by these points will be + // the approximate surface defined by these points will be // collided against pf = Hunk_Alloc( sizeof( *pf ), h_high ); ClearBounds( pf->bounds[0], pf->bounds[1] ); @@ -1370,7 +1369,7 @@ int CM_CheckFacetPlane(float *plane, vec3_t start, vec3_t end, float *enterFrac, return qfalse; } - // if it doesn't cross the plane, the plane isn't relevent + // if it doesn't cross the plane, the plane isn't relevant if (d1 <= 0 && d2 <= 0 ) { return qtrue; } @@ -1434,7 +1433,7 @@ void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s * VectorCopy(planes->plane, plane); plane[3] = planes->plane[3]; if ( tw->sphere.use ) { - // adjust the plane distance apropriately for radius + // adjust the plane distance appropriately for radius plane[3] += tw->sphere.radius; // find the closest point on the capsule to the plane @@ -1473,7 +1472,7 @@ void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s * plane[3] = planes->plane[3]; } if ( tw->sphere.use ) { - // adjust the plane distance apropriately for radius + // adjust the plane distance appropriately for radius plane[3] += tw->sphere.radius; // find the closest point on the capsule to the plane @@ -1562,7 +1561,7 @@ qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchColli VectorCopy(planes->plane, plane); plane[3] = planes->plane[3]; if ( tw->sphere.use ) { - // adjust the plane distance apropriately for radius + // adjust the plane distance appropriately for radius plane[3] += tw->sphere.radius; // find the closest point on the capsule to the plane @@ -1595,7 +1594,7 @@ qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchColli plane[3] = planes->plane[3]; } if ( tw->sphere.use ) { - // adjust the plane distance apropriately for radius + // adjust the plane distance appropriately for radius plane[3] += tw->sphere.radius; // find the closest point on the capsule to the plane diff --git a/code/qcommon/cm_polylib.c b/code/qcommon/cm_polylib.c index 4fa97865..68418262 100644 --- a/code/qcommon/cm_polylib.c +++ b/code/qcommon/cm_polylib.c @@ -276,7 +276,7 @@ winding_t *CopyWinding (winding_t *w) winding_t *c; c = AllocWinding (w->numpoints); - size = (intptr_t) ((winding_t *)0)->p[w->numpoints]; + size = (intptr_t)&(w->p[w->numpoints]) - (intptr_t)w; Com_Memcpy (c, w, size); return c; } @@ -353,7 +353,7 @@ void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, return; } - maxpts = in->numpoints+4; // cant use counts[0]+2 because + maxpts = in->numpoints+4; // can't use counts[0]+2 because // of fp grouping errors *front = f = AllocWinding (maxpts); @@ -462,7 +462,7 @@ void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t eps if (!counts[1]) return; // inout stays the same - maxpts = in->numpoints+4; // cant use counts[0]+2 because + maxpts = in->numpoints+4; // can't use counts[0]+2 because // of fp grouping errors f = AllocWinding (maxpts); @@ -574,7 +574,7 @@ void CheckWinding (winding_t *w) if (d < -ON_EPSILON || d > ON_EPSILON) Com_Error (ERR_DROP, "CheckWinding: point off plane"); - // check the edge isnt degenerate + // check the edge isn't degenerate p2 = w->p[j]; VectorSubtract (p2, p1, dir); diff --git a/code/qcommon/cm_trace.c b/code/qcommon/cm_trace.c index a4ac80a5..ec9fd0a0 100644 --- a/code/qcommon/cm_trace.c +++ b/code/qcommon/cm_trace.c @@ -189,7 +189,7 @@ void CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) { side = brush->sides + i; plane = side->plane; - // adjust the plane distance apropriately for radius + // adjust the plane distance appropriately for radius dist = plane->dist + tw->sphere.radius; // find the closest point on the capsule to the plane t = DotProduct( plane->normal, tw->sphere.offset ); @@ -214,7 +214,7 @@ void CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) { side = brush->sides + i; plane = side->plane; - // adjust the plane distance apropriately for mins/maxs + // adjust the plane distance appropriately for mins/maxs dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal ); d1 = DotProduct( tw->start, plane->normal ) - dist; @@ -517,7 +517,7 @@ void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { side = brush->sides + i; plane = side->plane; - // adjust the plane distance apropriately for radius + // adjust the plane distance appropriately for radius dist = plane->dist + tw->sphere.radius; // find the closest point on the capsule to the plane @@ -548,7 +548,7 @@ void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { return; } - // if it doesn't cross the plane, the plane isn't relevent + // if it doesn't cross the plane, the plane isn't relevant if (d1 <= 0 && d2 <= 0 ) { continue; } @@ -584,7 +584,7 @@ void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { side = brush->sides + i; plane = side->plane; - // adjust the plane distance apropriately for mins/maxs + // adjust the plane distance appropriately for mins/maxs dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal ); d1 = DotProduct( tw->start, plane->normal ) - dist; @@ -602,7 +602,7 @@ void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { return; } - // if it doesn't cross the plane, the plane isn't relevent + // if it doesn't cross the plane, the plane isn't relevant if (d1 <= 0 && d2 <= 0 ) { continue; } @@ -1053,13 +1053,13 @@ void CM_TraceThroughTree( traceWork_t *tw, int num, float p1f, float p2f, vec3_t } // - // find the point distances to the seperating plane + // find the point distances to the separating plane // and the offset for the size of the box // node = cm.nodes + num; plane = node->plane; - // adjust the plane distance apropriately for mins/maxs + // adjust the plane distance appropriately for mins/maxs if ( plane->type < 3 ) { t1 = p1[plane->type] - plane->dist; t2 = p2[plane->type] - plane->dist; @@ -1204,7 +1204,7 @@ void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mi tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2]; - // tw.offsets[signbits] = vector to apropriate corner from origin + // tw.offsets[signbits] = vector to appropriate corner from origin tw.offsets[0][0] = tw.size[0][0]; tw.offsets[0][1] = tw.size[0][1]; tw.offsets[0][2] = tw.size[0][2]; diff --git a/code/qcommon/cmd.c b/code/qcommon/cmd.c index 45122e07..b6b5a83c 100644 --- a/code/qcommon/cmd.c +++ b/code/qcommon/cmd.c @@ -489,8 +489,8 @@ void Cmd_Args_Sanitize(void) Cmd_TokenizeString Parses the given string into command line tokens. -The text is copied to a seperate buffer and 0 characters -are inserted in the apropriate place, The argv array +The text is copied to a separate buffer and 0 characters +are inserted in the appropriate place, The argv array will point into this temporary buffer. ============ */ @@ -689,9 +689,7 @@ void Cmd_RemoveCommand( const char *cmd_name ) { } if ( !strcmp( cmd_name, cmd->name ) ) { *back = cmd->next; - if (cmd->name) { - Z_Free(cmd->name); - } + Z_Free (cmd->name); Z_Free (cmd); return; } diff --git a/code/qcommon/common.c b/code/qcommon/common.c index b7d7fd89..58b91a6b 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -46,7 +46,7 @@ int demo_protocols[] = int com_argc; char *com_argv[MAX_NUM_ARGVS+1]; -jmp_buf abortframe; // an ERR_DROP occured, exit the entire frame +jmp_buf abortframe; // an ERR_DROP occurred, exit the entire frame FILE *debuglogfile; @@ -72,7 +72,9 @@ cvar_t *com_showtrace; cvar_t *com_version; cvar_t *com_blood; cvar_t *com_buildScript; // for automated data building scripts +#ifdef CINEMATICS_INTRO cvar_t *com_introPlayed; +#endif cvar_t *cl_paused; cvar_t *sv_paused; cvar_t *cl_packetdelay; @@ -93,6 +95,9 @@ cvar_t *com_legacyprotocol; cvar_t *com_basegame; cvar_t *com_homepath; cvar_t *com_busyWait; +#ifndef DEDICATED +cvar_t *con_autochat; +#endif #if idx64 int (*Q_VMftol)(void); @@ -113,6 +118,7 @@ int com_frameNumber; qboolean com_errorEntered = qfalse; qboolean com_fullyInitialized = qfalse; qboolean com_gameRestarting = qfalse; +qboolean com_gameClientRestarting = qfalse; char com_errorMessage[MAXPRINTMSG]; @@ -152,7 +158,7 @@ void Com_EndRedirect (void) Com_Printf Both client and server can use this, and it will output -to the apropriate place. +to the appropriate place. A raw string should NEVER be passed as fmt, because of "%f" type crashers. ============= @@ -262,6 +268,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { static int lastErrorTime; static int errorCount; int currentTime; + qboolean restartClient; if(com_errorEntered) Sys_Error("recursive error after: %s", com_errorMessage); @@ -294,9 +301,17 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { if (code != ERR_DISCONNECT && code != ERR_NEED_CD) Cvar_Set("com_errorMessage", com_errorMessage); + restartClient = com_gameClientRestarting && !( com_cl_running && com_cl_running->integer ); + + com_gameRestarting = qfalse; + com_gameClientRestarting = qfalse; + if (code == ERR_DISCONNECT || code == ERR_SERVERDISCONNECT) { VM_Forced_Unload_Start(); SV_Shutdown( "Server disconnected" ); + if ( restartClient ) { + CL_Init(); + } CL_Disconnect( qtrue ); CL_FlushMemory( ); VM_Forced_Unload_Done(); @@ -308,6 +323,9 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { Com_Printf ("********************\nERROR: %s\n********************\n", com_errorMessage); VM_Forced_Unload_Start(); SV_Shutdown (va("Server crashed: %s", com_errorMessage)); + if ( restartClient ) { + CL_Init(); + } CL_Disconnect( qtrue ); CL_FlushMemory( ); VM_Forced_Unload_Done(); @@ -317,6 +335,9 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { } else if ( code == ERR_NEED_CD ) { VM_Forced_Unload_Start(); SV_Shutdown( "Server didn't have CD" ); + if ( restartClient ) { + CL_Init(); + } if ( com_cl_running && com_cl_running->integer ) { CL_Disconnect( qtrue ); CL_FlushMemory( ); @@ -349,7 +370,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { Com_Quit_f Both client and server can use this, and it will -do the apropriate things. +do the appropriate things. ============= */ void Com_Quit_f( void ) { @@ -377,7 +398,7 @@ void Com_Quit_f( void ) { COMMAND LINE FUNCTIONS -+ characters seperate the commandLine string into multiple console ++ characters separate the commandLine string into multiple console command lines. All of these are valid: @@ -409,7 +430,7 @@ void Com_ParseCommandLine( char *commandLine ) { if (*commandLine == '"') { inq = !inq; } - // look for a + seperating character + // look for a + separating character // if commandLine came from a file, we might have real line seperators if ( (*commandLine == '+' && !inq) || *commandLine == '\n' || *commandLine == '\r' ) { if ( com_numConsoleLines == MAX_CONSOLE_LINES ) { @@ -473,9 +494,9 @@ void Com_StartupVariable( const char *match ) { if(!match || !strcmp(s, match)) { if(Cvar_Flags(s) == CVAR_NONEXISTENT) - Cvar_Get(s, Cmd_Argv(2), CVAR_USER_CREATED); + Cvar_Get(s, Cmd_ArgsFrom(2), CVAR_USER_CREATED); else - Cvar_Set2(s, Cmd_Argv(2), qfalse); + Cvar_Set2(s, Cmd_ArgsFrom(2), qfalse); } } } @@ -486,7 +507,7 @@ void Com_StartupVariable( const char *match ) { Com_AddStartupCommands Adds command line parameters as script statements -Commands are seperated by + signs +Commands are separated by + signs Returns qtrue if any late commands were added, which will keep the demoloop from immediately starting @@ -504,7 +525,7 @@ qboolean Com_AddStartupCommands( void ) { } // set commands already added with Com_StartupVariable - if ( !Q_stricmpn( com_consoleLines[i], "set", 3 ) ) { + if ( !Q_stricmpn( com_consoleLines[i], "set ", 4 ) ) { continue; } @@ -773,19 +794,19 @@ typedef struct { } memzone_t; // main zone for all "dynamic" memory allocation -memzone_t *mainzone; +static memzone_t *mainzone; // we also have a small zone for small allocations that would only // fragment the main zone (think of cvar and cmd strings) -memzone_t *smallzone; +static memzone_t *smallzone; -void Z_CheckHeap( void ); +static void Z_CheckHeap( void ); /* ======================== Z_ClearZone ======================== */ -void Z_ClearZone( memzone_t *zone, int size ) { +static void Z_ClearZone( memzone_t *zone, int size ) { memblock_t *block; // set the entire zone to one free block @@ -810,7 +831,7 @@ void Z_ClearZone( memzone_t *zone, int size ) { Z_AvailableZoneMemory ======================== */ -int Z_AvailableZoneMemory( memzone_t *zone ) { +static int Z_AvailableZoneMemory( memzone_t *zone ) { return zone->size - zone->used; } @@ -897,7 +918,6 @@ Z_FreeTags ================ */ void Z_FreeTags( int tag ) { - int count; memzone_t *zone; if ( tag == TAG_SMALL ) { @@ -906,13 +926,11 @@ void Z_FreeTags( int tag ) { else { zone = mainzone; } - count = 0; // use the rover as our pointer, because // Z_Free automatically adjusts it zone->rover = zone->blocklist.next; do { if ( zone->rover->tag == tag ) { - count++; Z_Free( (void *)(zone->rover + 1) ); continue; } @@ -1058,7 +1076,7 @@ void *S_Malloc( int size ) { Z_CheckHeap ======================== */ -void Z_CheckHeap( void ) { +static void Z_CheckHeap( void ) { memblock_t *block; for (block = mainzone->blocklist.next ; ; block = block->next) { @@ -1191,7 +1209,7 @@ char *CopyString( const char *in ) { ============================================================================== Goals: - reproducable without history effects -- no out of memory errors on weird map to map changes + reproducible without history effects -- no out of memory errors on weird map to map changes allow restarting of the client without fragmentation minimize total pages in use at run time minimize total pages needed during load time @@ -1266,7 +1284,7 @@ Com_Meminfo_f void Com_Meminfo_f( void ) { memblock_t *block; int zoneBytes, zoneBlocks; - int smallZoneBytes, smallZoneBlocks; + int smallZoneBytes; int botlibBytes, rendererBytes; int unused; @@ -1304,11 +1322,9 @@ void Com_Meminfo_f( void ) { } smallZoneBytes = 0; - smallZoneBlocks = 0; for (block = smallzone->blocklist.next ; ; block = block->next) { if ( block->tag ) { smallZoneBytes += block->size; - smallZoneBlocks++; } if (block->next == &smallzone->blocklist) { @@ -1360,7 +1376,7 @@ Touch all known used data to make sure it is paged in void Com_TouchMemory( void ) { int start, end; int i, j; - int sum; + unsigned sum; memblock_t *block; Z_CheckHeap(); @@ -1945,6 +1961,19 @@ void Com_QueueEvent( int time, sysEventType_t type, int value, int value2, int p { sysEvent_t *ev; + // combine mouse movement with previous mouse event + if ( type == SE_MOUSE && eventHead != eventTail ) + { + ev = &eventQueue[ ( eventHead + MAX_QUEUED_EVENTS - 1 ) & MASK_QUEUED_EVENTS ]; + + if ( ev->evType == SE_MOUSE ) + { + ev->evValue += value; + ev->evValue2 += value2; + return; + } + } + ev = &eventQueue[ eventHead & MASK_QUEUED_EVENTS ]; if ( eventHead - eventTail >= MAX_QUEUED_EVENTS ) @@ -2360,16 +2389,14 @@ void Com_GameRestart(int checksumFeed, qboolean disconnect) // make sure no recursion can be triggered if(!com_gameRestarting && com_fullyInitialized) { - int clWasRunning; - com_gameRestarting = qtrue; - clWasRunning = com_cl_running->integer; - + com_gameClientRestarting = com_cl_running->integer; + // Kill server if we have one if(com_sv_running->integer) SV_Shutdown("Game directory changed"); - if(clWasRunning) + if(com_gameClientRestarting) { if(disconnect) CL_Disconnect(qfalse); @@ -2391,13 +2418,14 @@ void Com_GameRestart(int checksumFeed, qboolean disconnect) NET_Restart_f(); } - if(clWasRunning) + if(com_gameClientRestarting) { CL_Init(); CL_StartHunkUsers(qfalse); } com_gameRestarting = qfalse; + com_gameClientRestarting = qfalse; } } @@ -2411,16 +2439,7 @@ Expose possibility to change current running mod to the user void Com_GameRestart_f(void) { - if(!FS_FilenameCompare(Cmd_Argv(1), com_basegame->string)) - { - // This is the standard base game. Servers and clients should - // use "" and not the standard basegame name because this messes - // up pak file negotiation and lots of other stuff - - Cvar_Set("fs_game", ""); - } - else - Cvar_Set("fs_game", Cmd_Argv(1)); + Cvar_Set("fs_game", Cmd_Argv(1)); Com_GameRestart(0, qtrue); } @@ -2592,7 +2611,7 @@ static void Com_DetectSSE(void) #endif Q_VMftol = qvmftolsse; - Com_Printf("Have SSE support\n"); + Com_Printf("SSE instruction set enabled\n"); #if !idx64 } else @@ -2601,7 +2620,7 @@ static void Com_DetectSSE(void) Q_VMftol = qvmftolx87; Q_SnapVector = qsnapvectorx87; - Com_Printf("No SSE support on this machine\n"); + Com_Printf("SSE instruction set not available\n"); } #endif } @@ -2637,7 +2656,7 @@ void Com_Init( char *commandLine ) { char *s; int qport; - Com_Printf( "%s %s %s\n", Q3_VERSION, PLATFORM_STRING, __DATE__ ); + Com_Printf( "%s %s %s\n", Q3_VERSION, PLATFORM_STRING, PRODUCT_DATE ); if ( setjmp (abortframe) ) { Sys_Error ("Error during initialization"); @@ -2678,10 +2697,7 @@ void Com_Init( char *commandLine ) { com_standalone = Cvar_Get("com_standalone", "0", CVAR_ROM); com_basegame = Cvar_Get("com_basegame", BASEGAME, CVAR_INIT); - com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT); - - if(!com_basegame->string[0]) - Cvar_ForceReset("com_basegame"); + com_homepath = Cvar_Get("com_homepath", "", CVAR_INIT|CVAR_PROTECTED); FS_InitFilesystem (); @@ -2754,9 +2770,11 @@ void Com_Init( char *commandLine ) { com_busyWait = Cvar_Get("com_busyWait", "0", CVAR_ARCHIVE); Cvar_Get("com_errorMessage", "", CVAR_ROM | CVAR_NORESTART); +#ifdef CINEMATICS_INTRO com_introPlayed = Cvar_Get( "com_introplayed", "0", CVAR_ARCHIVE); +#endif - s = va("%s %s %s", Q3_VERSION, PLATFORM_STRING, __DATE__ ); + s = va("%s %s %s", Q3_VERSION, PLATFORM_STRING, PRODUCT_DATE ); com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO ); com_gamename = Cvar_Get("com_gamename", GAMENAME_FOR_MASTER, CVAR_SERVERINFO | CVAR_INIT); com_protocol = Cvar_Get("com_protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_INIT); @@ -2770,19 +2788,13 @@ void Com_Init( char *commandLine ) { #endif Cvar_Get("protocol", com_protocol->string, CVAR_ROM); +#ifndef DEDICATED + con_autochat = Cvar_Get("con_autochat", "1", CVAR_ARCHIVE); +#endif + Sys_Init(); - if( Sys_WritePIDFile( ) ) { -#ifndef DEDICATED - const char *message = "The last time " CLIENT_WINDOW_TITLE " ran, " - "it didn't exit properly. This may be due to inappropriate video " - "settings. Would you like to start with \"safe\" video settings?"; - - if( Sys_Dialog( DT_YES_NO, message, "Abnormal Exit" ) == DR_YES ) { - Cvar_Set( "com_abnormalExit", "1" ); - } -#endif - } + Sys_InitPIDFile( FS_GetCurrentGameDir() ); // Pick a random port value Com_RandomBytes( (byte*)&qport, sizeof(int) ); @@ -2805,11 +2817,15 @@ void Com_Init( char *commandLine ) { if ( !Com_AddStartupCommands() ) { // if the user didn't give any commands, run default action if ( !com_dedicated->integer ) { - Cbuf_AddText ("cinematic Reactionlogo.RoQ\n"); +#ifdef CINEMATICS_LOGO + Cbuf_AddText ("cinematic " CINEMATICS_LOGO "\n"); +#endif +#ifdef CINEMATICS_INTRO if( !com_introPlayed->integer ) { Cvar_Set( com_introPlayed->name, "1" ); - Cvar_Set( "nextmap", "cinematic intro.RoQ" ); + Cvar_Set( "nextmap", "cinematic " CINEMATICS_INTRO ); } +#endif } } @@ -2915,9 +2931,6 @@ Writes key bindings and archived cvars to config file if modified =============== */ void Com_WriteConfiguration( void ) { -#if !defined(DEDICATED) && !defined(STANDALONE) - cvar_t *fs; -#endif // if we are quiting without fully initializing, make sure // we don't write out anything if ( !com_fullyInitialized ) { @@ -2933,12 +2946,12 @@ void Com_WriteConfiguration( void ) { // not needed for dedicated or standalone #if !defined(DEDICATED) && !defined(STANDALONE) - fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); - if(!com_standalone->integer) { - if (UI_usesUniqueCDKey() && fs && fs->string[0] != 0) { - Com_WriteCDKey( fs->string, &cl_cdkey[16] ); + const char *gamedir; + gamedir = Cvar_VariableString( "fs_game" ); + if (UI_usesUniqueCDKey() && gamedir[0] != 0) { + Com_WriteCDKey( gamedir, &cl_cdkey[16] ); } else { Com_WriteCDKey( BASEGAME, cl_cdkey ); } @@ -2964,6 +2977,13 @@ void Com_WriteConfig_f( void ) { Q_strncpyz( filename, Cmd_Argv(1), sizeof( filename ) ); COM_DefaultExtension( filename, sizeof( filename ), ".cfg" ); + + if (!COM_CompareExtension(filename, ".cfg")) + { + Com_Printf("Com_WriteConfig_f: Only the \".cfg\" extension is supported by this command!\n"); + return; + } + Com_Printf( "Writing %s.\n", filename ); Com_WriteConfigToFile( filename ); } @@ -3127,6 +3147,8 @@ void Com_Frame( void ) { NET_Sleep(timeVal - 1); } while(Com_TimeVal(minMsec)); + IN_Frame(); + lastTime = com_frameTime; com_frameTime = Com_EventLoop(); @@ -3456,8 +3478,8 @@ void Field_CompleteCommand( char *cmd, completionString = Cmd_Argv( completionArgument - 1 ); #ifndef DEDICATED - // Unconditionally add a '\' to the start of the buffer - if( completionField->buffer[ 0 ] && + // add a '\' to the start of the buffer if it might be sent as chat otherwise + if( con_autochat->integer && completionField->buffer[ 0 ] && completionField->buffer[ 0 ] != '\\' ) { if( completionField->buffer[ 0 ] != '/' ) @@ -3699,7 +3721,7 @@ qboolean Com_PlayerNameToFieldString( char *str, int length, const char *name ) return qtrue; } -void Field_CompletePlayerName( char **names, int nameCount ) +void Field_CompletePlayerName( const char **names, int nameCount ) { qboolean whitespace; diff --git a/code/qcommon/cvar.c b/code/qcommon/cvar.c index f07705db..7b219f8d 100644 --- a/code/qcommon/cvar.c +++ b/code/qcommon/cvar.c @@ -569,6 +569,12 @@ cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) { return var; } + if ((var->flags & CVAR_CHEAT) && !cvar_cheats->integer) + { + Com_Printf ("%s is cheat protected.\n", var_name); + return var; + } + if (var->flags & CVAR_LATCH) { if (var->latchedString) @@ -589,13 +595,6 @@ cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) { var->modificationCount++; return var; } - - if ( (var->flags & CVAR_CHEAT) && !cvar_cheats->integer ) - { - Com_Printf ("%s is cheat protected.\n", var_name); - return var; - } - } else { @@ -1332,12 +1331,42 @@ void Cvar_Register(vmCvar_t *vmCvar, const char *varName, const char *defaultVal // flags. Unfortunately some historical game code (including single player // baseq3) sets both flags. We unset CVAR_ROM for such cvars. if ((flags & (CVAR_ARCHIVE | CVAR_ROM)) == (CVAR_ARCHIVE | CVAR_ROM)) { - Com_DPrintf( S_COLOR_YELLOW "WARNING: Unsetting CVAR_ROM cvar '%s', " + Com_DPrintf( S_COLOR_YELLOW "WARNING: Unsetting CVAR_ROM from cvar '%s', " "since it is also CVAR_ARCHIVE\n", varName ); flags &= ~CVAR_ROM; } - cv = Cvar_Get(varName, defaultValue, flags | CVAR_VM_CREATED); + // Don't allow VM to specific a different creator or other internal flags. + if ( flags & CVAR_USER_CREATED ) { + Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_USER_CREATED on cvar '%s'\n", varName ); + flags &= ~CVAR_USER_CREATED; + } + if ( flags & CVAR_SERVER_CREATED ) { + Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_SERVER_CREATED on cvar '%s'\n", varName ); + flags &= ~CVAR_SERVER_CREATED; + } + if ( flags & CVAR_PROTECTED ) { + Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_PROTECTED on cvar '%s'\n", varName ); + flags &= ~CVAR_PROTECTED; + } + if ( flags & CVAR_MODIFIED ) { + Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_MODIFIED on cvar '%s'\n", varName ); + flags &= ~CVAR_MODIFIED; + } + if ( flags & CVAR_NONEXISTENT ) { + Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_NONEXISTENT on cvar '%s'\n", varName ); + flags &= ~CVAR_NONEXISTENT; + } + + cv = Cvar_FindVar(varName); + + // Don't modify cvar if it's protected. + if ( cv && ( cv->flags & CVAR_PROTECTED ) ) { + Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to register protected cvar '%s' with value '%s'%s\n", + varName, defaultValue, ( flags & ~cv->flags ) != 0 ? " and new flags" : "" ); + } else { + cv = Cvar_Get(varName, defaultValue, flags | CVAR_VM_CREATED); + } if (!vmCvar) return; diff --git a/code/qcommon/files.c b/code/qcommon/files.c index 5ca4e32c..18f5efee 100644 --- a/code/qcommon/files.c +++ b/code/qcommon/files.c @@ -88,7 +88,7 @@ File search order: when FS_FOpenFileRead gets called it will go through the fs_s structure and stop on the first successful hit. fs_searchpaths is built with successive calls to FS_AddGameDirectory -Additionaly, we search in several subdirectories: +Additionally, we search in several subdirectories: current game is the current mode base game is a variable to allow mods based on other mods (such as baseq3 + missionpack content combination in a mod for instance) @@ -174,6 +174,7 @@ or configs will never get loaded from disk! // every time a new demo pk3 file is built, this checksum must be updated. // the easiest way to get it is to just run the game and see what it spits out +#ifndef STANDALONE #define DEMO_PAK0_CHECKSUM 2985612116u static const unsigned int pak_checksums[] = { 1566731103u, @@ -194,6 +195,7 @@ static const unsigned int missionpak_checksums[] = 2662638993u, 1438664554u }; +#endif // if this is defined, the executable positively won't work with any paks other // than the demo pak, even if productid is present. This is only used for our @@ -246,11 +248,12 @@ static char fs_gamedir[MAX_OSPATH]; // this will be a single file name with no static cvar_t *fs_debug; static cvar_t *fs_homepath; -#ifdef MACOS_X +#ifdef __APPLE__ // Also search the .app bundle for .pk3 files static cvar_t *fs_apppath; #endif static cvar_t *fs_steampath; +static cvar_t *fs_gogpath; static cvar_t *fs_basepath; static cvar_t *fs_basegame; @@ -280,7 +283,6 @@ typedef struct { int zipFilePos; int zipFileLen; qboolean zipFile; - qboolean streamed; char name[MAX_ZPATH]; } fileHandleData_t; @@ -303,6 +305,8 @@ static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS]; // pk3 names // last valid game folder used char lastValidBase[MAX_OSPATH]; +char lastValidComBaseGame[MAX_OSPATH]; +char lastValidFsBaseGame[MAX_OSPATH]; char lastValidGame[MAX_OSPATH]; #ifdef FS_MISSING @@ -564,7 +568,7 @@ static void FS_CheckFilenameIsMutable( const char *filename, const char *function ) { // Check if the filename ends with the library, QVM, or pk3 extension - if( COM_CompareExtension( filename, DLL_EXT ) + if( Sys_DllExtension( filename ) || COM_CompareExtension( filename, ".qvm" ) || COM_CompareExtension( filename, ".pk3" ) ) { @@ -749,7 +753,7 @@ long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp) fsh[f].handleSync = qfalse; } - // Check fs_steampath too + // Check fs_steampath if (!fsh[f].handleFiles.file.o && fs_steampath->string[0]) { ospath = FS_BuildOSPath( fs_steampath->string, filename, "" ); @@ -764,6 +768,21 @@ long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp) fsh[f].handleSync = qfalse; } + // Check fs_gogpath + if (!fsh[f].handleFiles.file.o && fs_gogpath->string[0]) + { + ospath = FS_BuildOSPath( fs_gogpath->string, filename, "" ); + ospath[strlen(ospath)-1] = '\0'; + + if ( fs_debug->integer ) + { + Com_Printf( "FS_SV_FOpenFileRead (fs_gogpath): %s\n", ospath ); + } + + fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "rb" ); + fsh[f].handleSync = qfalse; + } + if ( !fsh[f].handleFiles.file.o ) { f = 0; @@ -1362,12 +1381,18 @@ long FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueF { searchpath_t *search; long len; + qboolean isLocalConfig; if(!fs_searchpaths) Com_Error(ERR_FATAL, "Filesystem call made without initialization"); + isLocalConfig = !strcmp(filename, "autoexec.cfg") || !strcmp(filename, Q3CONFIG_CFG); for(search = fs_searchpaths; search; search = search->next) { + // autoexec.cfg and q3config.cfg can only be loaded outside of pk3 files. + if (isLocalConfig && search->pack) + continue; + len = FS_FOpenFileReadDir(filename, search, file, uniqueFILE, qfalse); if(file == NULL) @@ -1395,7 +1420,7 @@ long FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueF } else { - // When file is NULL, we're querying the existance of the file + // When file is NULL, we're querying the existence of the file // If we've got here, it doesn't exist return 0; } @@ -1502,25 +1527,6 @@ FS_Read Properly handles partial reads ================= */ -int FS_Read2( void *buffer, int len, fileHandle_t f ) { - if ( !fs_searchpaths ) { - Com_Error( ERR_FATAL, "Filesystem call made without initialization" ); - } - - if ( !f ) { - return 0; - } - if (fsh[f].streamed) { - int r; - fsh[f].streamed = qfalse; - r = FS_Read( buffer, len, f ); - fsh[f].streamed = qtrue; - return r; - } else { - return FS_Read( buffer, len, f); - } -} - int FS_Read( void *buffer, int len, fileHandle_t f ) { int block, remaining; int read; @@ -1647,14 +1653,6 @@ int FS_Seek( fileHandle_t f, long offset, int origin ) { return -1; } - if (fsh[f].streamed) { - int r; - fsh[f].streamed = qfalse; - r = FS_Seek( f, offset, origin ); - fsh[f].streamed = qtrue; - return r; - } - if (fsh[f].zipFile == qtrue) { //FIXME: this is really, really crappy //(but better than what was here before) @@ -2208,7 +2206,7 @@ static int FS_AddFileToList( char *name, char *list[MAX_FOUND_FILES], int nfiles } for ( i = 0 ; i < nfiles ; i++ ) { if ( !Q_stricmp( name, list[i] ) ) { - return nfiles; // allready in list + return nfiles; // already in list } } list[nfiles] = CopyString( name ); @@ -2482,124 +2480,129 @@ static char** Sys_ConcatenateFileLists( char **list0, char **list1 ) return cat; } +/* +================ +FS_GetModDescription +================ +*/ +void FS_GetModDescription( const char *modDir, char *description, int descriptionLen ) { + fileHandle_t descHandle; + char descPath[MAX_QPATH]; + int nDescLen; + FILE *file; + + Com_sprintf( descPath, sizeof ( descPath ), "%s%cdescription.txt", modDir, PATH_SEP ); + nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle ); + + if ( nDescLen > 0 ) { + file = FS_FileForHandle(descHandle); + Com_Memset( description, 0, descriptionLen ); + nDescLen = fread(description, 1, descriptionLen, file); + if (nDescLen >= 0) { + description[nDescLen] = '\0'; + } + } else { + Q_strncpyz( description, modDir, descriptionLen ); + } + + if ( descHandle ) { + FS_FCloseFile( descHandle ); + } +} + /* ================ FS_GetModList Returns a list of mod directory names -A mod directory is a peer to baseq3 with a pk3 in it -The directories are searched in base path, cd path and home path +A mod directory is a peer to baseq3 with a pk3 or pk3dir in it ================ */ int FS_GetModList( char *listbuf, int bufsize ) { - int nMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen; + int nMods, i, j, k, nTotal, nLen, nPaks, nDirs, nPakDirs, nPotential, nDescLen; char **pFiles = NULL; char **pPaks = NULL; + char **pDirs = NULL; char *name, *path; - char descPath[MAX_OSPATH]; - fileHandle_t descHandle; + char description[MAX_OSPATH]; int dummy; char **pFiles0 = NULL; - char **pFiles1 = NULL; - char **pFiles2 = NULL; - char **pFiles3 = NULL; qboolean bDrop = qfalse; + // paths to search for mods + const char * const paths[] = { fs_basepath->string, fs_homepath->string, fs_steampath->string, fs_gogpath->string }; + *listbuf = 0; nMods = nTotal = 0; - pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue ); - pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue ); - pFiles2 = Sys_ListFiles( fs_steampath->string, NULL, NULL, &dummy, qtrue ); - // we searched for mods in the three paths - // it is likely that we have duplicate names now, which we will cleanup below - pFiles3 = Sys_ConcatenateFileLists( pFiles0, pFiles1 ); - pFiles = Sys_ConcatenateFileLists( pFiles2, pFiles3 ); + // iterate through paths and get list of potential mods + for (i = 0; i < ARRAY_LEN(paths); i++) { + pFiles0 = Sys_ListFiles(paths[i], NULL, NULL, &dummy, qtrue); + // Sys_ConcatenateFileLists frees the lists so Sys_FreeFileList isn't required + pFiles = Sys_ConcatenateFileLists(pFiles, pFiles0); + } nPotential = Sys_CountFileList(pFiles); - for ( i = 0 ; i < nPotential ; i++ ) { + for (i = 0; i < nPotential; i++) { name = pFiles[i]; // NOTE: cleaner would involve more changes // ignore duplicate mod directories - if (i!=0) { + if (i != 0) { bDrop = qfalse; - for(j=0; jstring) == 0 || Q_stricmpn(name, ".", 1) == 0) { continue; } - // we drop "baseq3" "." and ".." - if (Q_stricmp(name, com_basegame->string) && Q_stricmpn(name, ".", 1)) { - // now we need to find some .pk3 files to validate the mod - // NOTE TTimo: (actually I'm not sure why .. what if it's a mod under developement with no .pk3?) - // we didn't keep the information when we merged the directory names, as to what OS Path it was found under - // so it could be in base path, cd path or home path - // we will try each three of them here (yes, it's a bit messy) - path = FS_BuildOSPath( fs_basepath->string, name, "" ); - nPaks = 0; - pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse); - Sys_FreeFileList( pPaks ); // we only use Sys_ListFiles to check wether .pk3 files are present - /* try on home path */ - if ( nPaks <= 0 ) - { - path = FS_BuildOSPath( fs_homepath->string, name, "" ); - nPaks = 0; - pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse ); - Sys_FreeFileList( pPaks ); + // in order to be a valid mod the directory must contain at least one .pk3 or .pk3dir + // we didn't keep the information when we merged the directory names, as to what OS Path it was found under + // so we will try each of them here + for (j = 0; j < ARRAY_LEN(paths); j++) { + path = FS_BuildOSPath(paths[j], name, ""); + nPaks = nDirs = nPakDirs = 0; + pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse); + pDirs = Sys_ListFiles(path, "/", NULL, &nDirs, qfalse); + for (k = 0; k < nDirs; k++) { + // we only want to count directories ending with ".pk3dir" + if (FS_IsExt(pDirs[k], ".pk3dir", strlen(pDirs[k]))) { + nPakDirs++; + } } + // we only use Sys_ListFiles to check whether files are present + Sys_FreeFileList(pPaks); + Sys_FreeFileList(pDirs); - /* try on steam path */ - if ( nPaks <= 0 ) - { - path = FS_BuildOSPath( fs_steampath->string, name, "" ); - nPaks = 0; - pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse ); - Sys_FreeFileList( pPaks ); + if (nPaks > 0 || nPakDirs > 0) { + break; } + } - if (nPaks > 0) { - nLen = strlen(name) + 1; - // nLen is the length of the mod path - // we need to see if there is a description available - descPath[0] = '\0'; - strcpy(descPath, name); - strcat(descPath, "/description.txt"); - nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle ); - if ( nDescLen > 0 && descHandle) { - FILE *file; - file = FS_FileForHandle(descHandle); - Com_Memset( descPath, 0, sizeof( descPath ) ); - nDescLen = fread(descPath, 1, 48, file); - if (nDescLen >= 0) { - descPath[nDescLen] = '\0'; - } - FS_FCloseFile(descHandle); - } else { - strcpy(descPath, name); - } - nDescLen = strlen(descPath) + 1; + if (nPaks > 0 || nPakDirs > 0) { + nLen = strlen(name) + 1; + // nLen is the length of the mod path + // we need to see if there is a description available + FS_GetModDescription(name, description, sizeof(description)); + nDescLen = strlen(description) + 1; - if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) { - strcpy(listbuf, name); - listbuf += nLen; - strcpy(listbuf, descPath); - listbuf += nDescLen; - nTotal += nLen + nDescLen; - nMods++; - } - else { - break; - } + if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) { + strcpy(listbuf, name); + listbuf += nLen; + strcpy(listbuf, description); + listbuf += nDescLen; + nTotal += nLen + nDescLen; + nMods++; + } else { + break; } } } @@ -3067,6 +3070,23 @@ qboolean FS_CheckDirTraversal(const char *checkdir) return qfalse; } +/* +================ +FS_InvalidGameDir + +return true if path is a reference to current directory or directory traversal +or a sub-directory +================ +*/ +qboolean FS_InvalidGameDir( const char *gamedir ) { + if ( !strcmp( gamedir, "." ) || !strcmp( gamedir, ".." ) + || strchr( gamedir, '/' ) || strchr( gamedir, '\\' ) ) { + return qtrue; + } + + return qfalse; +} + /* ================ FS_ComparePaks @@ -3309,7 +3329,32 @@ static void FS_Startup( const char *gameName ) fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT|CVAR_PROTECTED ); fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); + if (!gameName[0]) { + Cvar_ForceReset( "com_basegame" ); + } + + if (!FS_FilenameCompare(fs_gamedirvar->string, gameName)) { + // This is the standard base game. Servers and clients should + // use "" and not the standard basegame name because this messes + // up pak file negotiation and lots of other stuff + Cvar_ForceReset( "fs_game" ); + } + + if (FS_InvalidGameDir(gameName)) { + Com_Error( ERR_DROP, "Invalid com_basegame '%s'", gameName ); + } + if (FS_InvalidGameDir(fs_basegame->string)) { + Com_Error( ERR_DROP, "Invalid fs_basegame '%s'", fs_basegame->string ); + } + if (FS_InvalidGameDir(fs_gamedirvar->string)) { + Com_Error( ERR_DROP, "Invalid fs_game '%s'", fs_gamedirvar->string ); + } + // add search path elements in reverse priority order + fs_gogpath = Cvar_Get ("fs_gogpath", Sys_GogPath(), CVAR_INIT|CVAR_PROTECTED ); + if (fs_gogpath->string[0]) { + FS_AddGameDirectory( fs_gogpath->string, gameName ); + } fs_steampath = Cvar_Get ("fs_steampath", Sys_SteamPath(), CVAR_INIT|CVAR_PROTECTED ); if (fs_steampath->string[0]) { FS_AddGameDirectory( fs_steampath->string, gameName ); @@ -3319,7 +3364,7 @@ static void FS_Startup( const char *gameName ) } // fs_homepath is somewhat particular to *nix systems, only add if relevant -#ifdef MACOS_X +#ifdef __APPLE__ fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT|CVAR_PROTECTED ); // Make MacOSX also include the base path included with the .app bundle if (fs_apppath->string[0]) @@ -3334,6 +3379,9 @@ static void FS_Startup( const char *gameName ) // check for additional base game so mods can be based upon other mods if ( fs_basegame->string[0] && Q_stricmp( fs_basegame->string, gameName ) ) { + if (fs_gogpath->string[0]) { + FS_AddGameDirectory(fs_gogpath->string, fs_basegame->string); + } if (fs_steampath->string[0]) { FS_AddGameDirectory(fs_steampath->string, fs_basegame->string); } @@ -3347,6 +3395,9 @@ static void FS_Startup( const char *gameName ) // check for additional game folder for mods if ( fs_gamedirvar->string[0] && Q_stricmp( fs_gamedirvar->string, gameName ) ) { + if (fs_gogpath->string[0]) { + FS_AddGameDirectory(fs_gogpath->string, fs_gamedirvar->string); + } if (fs_steampath->string[0]) { FS_AddGameDirectory(fs_steampath->string, fs_gamedirvar->string); } @@ -3359,14 +3410,10 @@ static void FS_Startup( const char *gameName ) } #ifndef STANDALONE - if(!com_standalone->integer) - { - cvar_t *fs; - + if (!com_standalone->integer) { Com_ReadCDKey(BASEGAME); - fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); - if (fs && fs->string[0] != 0) { - Com_AppendCDKey( fs->string ); + if (fs_gamedirvar->string[0]) { + Com_AppendCDKey(fs_gamedirvar->string); } } #endif @@ -3414,17 +3461,17 @@ static void FS_CheckPak0( void ) { searchpath_t *path; pack_t *curpack; + const char *pakBasename; qboolean founddemo = qfalse; unsigned int foundPak = 0, foundTA = 0; for( path = fs_searchpaths; path; path = path->next ) { - const char* pakBasename = path->pack->pakBasename; - if(!path->pack) continue; curpack = path->pack; + pakBasename = curpack->pakBasename; if(!Q_stricmpn( curpack->pakGamename, "demoq3", MAX_OSPATH ) && !Q_stricmpn( pakBasename, "pak0", MAX_OSPATH )) @@ -3921,7 +3968,7 @@ void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames ) ================ FS_InitFilesystem -Called only at inital startup, not when the filesystem +Called only at initial startup, not when the filesystem is resetting due to a game change ================ */ @@ -3952,6 +3999,8 @@ void FS_InitFilesystem( void ) { } Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase)); + Q_strncpyz(lastValidComBaseGame, com_basegame->string, sizeof(lastValidComBaseGame)); + Q_strncpyz(lastValidFsBaseGame, fs_basegame->string, sizeof(lastValidFsBaseGame)); Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame)); } @@ -3962,6 +4011,7 @@ FS_Restart ================ */ void FS_Restart( int checksumFeed ) { + const char *lastGameDir; // free anything we currently have loaded FS_Shutdown(qfalse); @@ -3988,8 +4038,12 @@ void FS_Restart( int checksumFeed ) { if (lastValidBase[0]) { FS_PureServerSetLoadedPaks("", ""); Cvar_Set("fs_basepath", lastValidBase); + Cvar_Set("com_basegame", lastValidComBaseGame); + Cvar_Set("fs_basegame", lastValidFsBaseGame); Cvar_Set("fs_game", lastValidGame); lastValidBase[0] = '\0'; + lastValidComBaseGame[0] = '\0'; + lastValidFsBaseGame[0] = '\0'; lastValidGame[0] = '\0'; FS_Restart(checksumFeed); Com_Error( ERR_DROP, "Invalid game folder" ); @@ -3998,7 +4052,12 @@ void FS_Restart( int checksumFeed ) { Com_Error( ERR_FATAL, "Couldn't load default.cfg" ); } - if ( Q_stricmp(fs_gamedirvar->string, lastValidGame) ) { + lastGameDir = ( lastValidGame[0] ) ? lastValidGame : lastValidComBaseGame; + + if ( Q_stricmp( FS_GetCurrentGameDir(), lastGameDir ) ) { + Sys_RemovePIDFile( lastGameDir ); + Sys_InitPIDFile( FS_GetCurrentGameDir() ); + // skip the q3config.cfg if "safe" is on the command line if ( !Com_SafeMode() ) { Cbuf_AddText ("exec " Q3CONFIG_CFG "\n"); @@ -4006,6 +4065,8 @@ void FS_Restart( int checksumFeed ) { } Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase)); + Q_strncpyz(lastValidComBaseGame, com_basegame->string, sizeof(lastValidComBaseGame)); + Q_strncpyz(lastValidFsBaseGame, fs_basegame->string, sizeof(lastValidFsBaseGame)); Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame)); } @@ -4086,11 +4147,6 @@ int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) { if ( *f ) { fsh[*f].fileSize = r; - fsh[*f].streamed = qfalse; - - if (mode == FS_READ) { - fsh[*f].streamed = qtrue; - } } fsh[*f].handleSync = sync; diff --git a/code/qcommon/huffman.c b/code/qcommon/huffman.c index c1b9f242..0283fb70 100644 --- a/code/qcommon/huffman.c +++ b/code/qcommon/huffman.c @@ -279,9 +279,14 @@ int Huff_Receive (node_t *node, int *ch, byte *fin) { } /* Get a symbol */ -void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { +void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset, int maxoffset) { bloc = *offset; while (node && node->symbol == INTERNAL_NODE) { + if (bloc >= maxoffset) { + *ch = 0; + *offset = maxoffset + 1; + return; + } if (get_bit(fin)) { node = node->right; } else { @@ -298,11 +303,15 @@ void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { } /* Send the prefix code for this node */ -static void send(node_t *node, node_t *child, byte *fout) { +static void send(node_t *node, node_t *child, byte *fout, int maxoffset) { if (node->parent) { - send(node->parent, node, fout); + send(node->parent, node, fout, maxoffset); } if (child) { + if (bloc >= maxoffset) { + bloc = maxoffset + 1; + return; + } if (node->right == child) { add_bit(1, fout); } else { @@ -312,22 +321,22 @@ static void send(node_t *node, node_t *child, byte *fout) { } /* Send a symbol */ -void Huff_transmit (huff_t *huff, int ch, byte *fout) { +void Huff_transmit (huff_t *huff, int ch, byte *fout, int maxoffset) { int i; if (huff->loc[ch] == NULL) { /* node_t hasn't been transmitted, send a NYT, then the symbol */ - Huff_transmit(huff, NYT, fout); + Huff_transmit(huff, NYT, fout, maxoffset); for (i = 7; i >= 0; i--) { add_bit((char)((ch >> i) & 0x1), fout); } } else { - send(huff->loc[ch], NULL, fout); + send(huff->loc[ch], NULL, fout, maxoffset); } } -void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset) { +void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset, int maxoffset) { bloc = *offset; - send(huff->loc[ch], NULL, fout); + send(huff->loc[ch], NULL, fout, maxoffset); *offset = bloc; } @@ -392,7 +401,7 @@ void Huff_Compress(msg_t *mbuf, int offset) { huff_t huff; size = mbuf->cursize - offset; - buffer = mbuf->data+ + offset; + buffer = mbuf->data + offset; if (size<=0) { return; @@ -413,7 +422,7 @@ void Huff_Compress(msg_t *mbuf, int offset) { for (i=0; i length) diff --git a/code/qcommon/msg.c b/code/qcommon/msg.c index 397c603e..8a166732 100644 --- a/code/qcommon/msg.c +++ b/code/qcommon/msg.c @@ -101,18 +101,13 @@ bit functions ============================================================================= */ -int overflows; - // negative bit values include signs void MSG_WriteBits( msg_t *msg, int value, int bits ) { int i; -// FILE* fp; oldsize += bits; - // this isn't an exact overflow check, but close enough - if ( msg->maxsize - msg->cursize < 4 ) { - msg->overflowed = qtrue; + if ( msg->overflowed ) { return; } @@ -120,69 +115,60 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { Com_Error( ERR_DROP, "MSG_WriteBits: bad bits %i", bits ); } - // check for overflows - if ( bits != 32 ) { - if ( bits > 0 ) { - if ( value > ( ( 1 << bits ) - 1 ) || value < 0 ) { - overflows++; - } - } else { - int r; - - r = 1 << (bits-1); - - if ( value > r - 1 || value < -r ) { - overflows++; - } - } - } if ( bits < 0 ) { bits = -bits; } - if (msg->oob) { - if(bits==8) - { + + if ( msg->oob ) { + if ( msg->cursize + ( bits >> 3 ) > msg->maxsize ) { + msg->overflowed = qtrue; + return; + } + + if ( bits == 8 ) { msg->data[msg->cursize] = value; msg->cursize += 1; msg->bit += 8; - } - else if(bits==16) - { + } else if ( bits == 16 ) { short temp = value; - - CopyLittleShort(&msg->data[msg->cursize], &temp); + + CopyLittleShort( &msg->data[msg->cursize], &temp ); msg->cursize += 2; msg->bit += 16; - } - else if(bits==32) - { - CopyLittleLong(&msg->data[msg->cursize], &value); + } else if ( bits==32 ) { + CopyLittleLong( &msg->data[msg->cursize], &value ); msg->cursize += 4; msg->bit += 32; + } else { + Com_Error( ERR_DROP, "can't write %d bits", bits ); } - else - Com_Error(ERR_DROP, "can't write %d bits", bits); } else { -// fp = fopen("c:\\netchan.bin", "a"); - value &= (0xffffffff>>(32-bits)); - if (bits&7) { + value &= (0xffffffff >> (32 - bits)); + if ( bits&7 ) { int nbits; nbits = bits&7; - for(i=0;idata, &msg->bit); - value = (value>>1); + if ( msg->bit + nbits > msg->maxsize << 3 ) { + msg->overflowed = qtrue; + return; + } + for( i = 0; i < nbits; i++ ) { + Huff_putBit( (value & 1), msg->data, &msg->bit ); + value = (value >> 1); } bits = bits - nbits; } - if (bits) { - for(i=0;idata, &msg->bit); - value = (value>>8); + if ( bits ) { + for( i = 0; i < bits; i += 8 ) { + Huff_offsetTransmit( &msgHuff.compressor, (value & 0xff), msg->data, &msg->bit, msg->maxsize << 3 ); + value = (value >> 8); + + if ( msg->bit > msg->maxsize << 3 ) { + msg->overflowed = qtrue; + return; + } } } - msg->cursize = (msg->bit>>3)+1; -// fclose(fp); + msg->cursize = (msg->bit >> 3) + 1; } } @@ -193,6 +179,10 @@ int MSG_ReadBits( msg_t *msg, int bits ) { int i, nbits; // FILE* fp; + if ( msg->readcount > msg->cursize ) { + return 0; + } + value = 0; if ( bits < 0 ) { @@ -203,6 +193,11 @@ int MSG_ReadBits( msg_t *msg, int bits ) { } if (msg->oob) { + if (msg->readcount + (bits>>3) > msg->cursize) { + msg->readcount = msg->cursize + 1; + return 0; + } + if(bits==8) { value = msg->data[msg->readcount]; @@ -230,6 +225,10 @@ int MSG_ReadBits( msg_t *msg, int bits ) { nbits = 0; if (bits&7) { nbits = bits&7; + if (msg->bit + nbits > msg->cursize << 3) { + msg->readcount = msg->cursize + 1; + return 0; + } for(i=0;idata, &msg->bit)<data, &msg->bit); + Huff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit, msg->cursize<<3); // fwrite(&get, 1, 1, fp); - value |= (get<<(i+nbits)); + value = (unsigned int)value | ((unsigned int)get<<(i+nbits)); + + if (msg->bit > msg->cursize<<3) { + msg->readcount = msg->cursize + 1; + return 0; + } } // fclose(fp); } @@ -458,12 +462,14 @@ char *MSG_ReadString( msg_t *msg ) { if ( c > 127 ) { c = '.'; } - - string[l] = c; - l++; - } while (l < sizeof(string)-1); + // break only after reading all expected data from bitstream + if ( l >= sizeof(string)-1 ) { + break; + } + string[l++] = c; + } while (1); - string[l] = 0; + string[l] = '\0'; return string; } @@ -486,12 +492,14 @@ char *MSG_ReadBigString( msg_t *msg ) { if ( c > 127 ) { c = '.'; } - - string[l] = c; - l++; - } while (l < sizeof(string)-1); + // break only after reading all expected data from bitstream + if ( l >= sizeof(string)-1 ) { + break; + } + string[l++] = c; + } while (1); - string[l] = 0; + string[l] = '\0'; return string; } @@ -514,12 +522,14 @@ char *MSG_ReadStringLine( msg_t *msg ) { if ( c > 127 ) { c = '.'; } - - string[l] = c; - l++; - } while (l < sizeof(string)-1); + // break only after reading all expected data from bitstream + if ( l >= sizeof(string)-1 ) { + break; + } + string[l++] = c; + } while (1); - string[l] = 0; + string[l] = '\0'; return string; } @@ -552,55 +562,10 @@ int MSG_HashKey(const char *string, int maxlen) { return hash; } -/* -============================================================================= - -delta functions - -============================================================================= -*/ - extern cvar_t *cl_shownet; #define LOG(x) if( cl_shownet && cl_shownet->integer == 4 ) { Com_Printf("%s ", x ); }; -void MSG_WriteDelta( msg_t *msg, int oldV, int newV, int bits ) { - if ( oldV == newV ) { - MSG_WriteBits( msg, 0, 1 ); - return; - } - MSG_WriteBits( msg, 1, 1 ); - MSG_WriteBits( msg, newV, bits ); -} - -int MSG_ReadDelta( msg_t *msg, int oldV, int bits ) { - if ( MSG_ReadBits( msg, 1 ) ) { - return MSG_ReadBits( msg, bits ); - } - return oldV; -} - -void MSG_WriteDeltaFloat( msg_t *msg, float oldV, float newV ) { - floatint_t fi; - if ( oldV == newV ) { - MSG_WriteBits( msg, 0, 1 ); - return; - } - fi.f = newV; - MSG_WriteBits( msg, 1, 1 ); - MSG_WriteBits( msg, fi.i, 32 ); -} - -float MSG_ReadDeltaFloat( msg_t *msg, float oldV ) { - if ( MSG_ReadBits( msg, 1 ) ) { - floatint_t fi; - - fi.i = MSG_ReadBits( msg, 32 ); - return fi.f; - } - return oldV; -} - /* ============================================================================= diff --git a/code/qcommon/net_chan.c b/code/qcommon/net_chan.c index 0b099b95..9e7d9b87 100644 --- a/code/qcommon/net_chan.c +++ b/code/qcommon/net_chan.c @@ -52,7 +52,7 @@ to the new value before sending out any replies. #define FRAGMENT_SIZE (MAX_PACKETLEN - 100) #define PACKET_HEADER 10 // two ints and a short -#define FRAGMENT_BIT (1<<31) +#define FRAGMENT_BIT (1U<<31) cvar_t *showpackets; cvar_t *showdrop; diff --git a/code/qcommon/net_ip.c b/code/qcommon/net_ip.c index 98555b99..bcccda20 100644 --- a/code/qcommon/net_ip.c +++ b/code/qcommon/net_ip.c @@ -1268,7 +1268,7 @@ static void NET_AddLocalAddress(char *ifname, struct sockaddr *addr, struct sock } } -#if defined(__linux__) || defined(MACOSX) || defined(__BSD__) +#if defined(__linux__) || defined(__APPLE__) || defined(__BSD__) static void NET_GetLocalAddress(void) { struct ifaddrs *ifap, *search; diff --git a/code/qcommon/q_math.c b/code/qcommon/q_math.c index 49673e51..de78a695 100644 --- a/code/qcommon/q_math.c +++ b/code/qcommon/q_math.c @@ -148,7 +148,7 @@ vec3_t bytedirs[NUMVERTEXNORMALS] = //============================================================== int Q_rand( int *seed ) { - *seed = (69069 * *seed + 1); + *seed = (69069U * *seed + 1U); return *seed; } diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index 3ed5357f..27ca856e 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -46,7 +46,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define idppc 1 #if defined(__VEC__) #define idppc_altivec 1 -#ifdef MACOS_X // Apple's GCC does this differently than the FSF. +#ifdef __APPLE__ // Apple's GCC does this differently than the FSF. #define VECCONST_UINT8(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \ (vector unsigned char) (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) #else @@ -139,12 +139,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //============================================================== MAC OS X === -#if defined(MACOS_X) || defined(__APPLE_CC__) - -// make sure this is defined, just for sanity's sake... -#ifndef MACOS_X -#define MACOS_X -#endif +#if defined(__APPLE__) || defined(__APPLE_CC__) #define OS_STRING "macosx" #define ID_INLINE inline diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 820c862c..332341a9 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -23,6 +23,24 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // q_shared.c -- stateless support routines that are included in each code dll #include "q_shared.h" +#if 0 +qboolean Q_IsColorString(const char *p) { + if (!p) + return qfalse; + + if (p[0] != Q_COLOR_ESCAPE) + return qfalse; + + if (p[1] == 0) + return qfalse; + + if (p[1] == Q_COLOR_ESCAPE) + return qfalse; + + return qtrue; +} +#endif + float Com_Clamp( float min, float max, float value ) { if ( value < min ) { return min; @@ -660,15 +678,15 @@ Com_HexStrToInt */ int Com_HexStrToInt( const char *str ) { - if ( !str || !str[ 0 ] ) + if ( !str ) return -1; // check for hex code - if( str[ 0 ] == '0' && str[ 1 ] == 'x' ) + if( str[ 0 ] == '0' && str[ 1 ] == 'x' && str[ 2 ] != '\0' ) { - int i, n = 0; + int i, n = 0, len = strlen( str ); - for( i = 2; i < strlen( str ); i++ ) + for( i = 2; i < len; i++ ) { char digit; @@ -746,13 +764,14 @@ qboolean Q_isintegral( float f ) return (int)f == f; } -#ifdef _MSC_VER +#ifdef _WIN32 /* ============= Q_vsnprintf - + Special wrapper function for Microsoft's broken _vsnprintf() function. -MinGW comes with its own snprintf() which is not broken. +MinGW comes with its own vsnprintf() which is not broken. mingw-w64 +however, uses Microsoft's broken _vsnprintf() function. ============= */ diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index e94c3d9b..bf2d5d88 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -35,8 +35,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define HOMEPATH_NAME_WIN "Reaction" #define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN // #define STEAMPATH_NAME "Foo Bar" -// #define STEAMPATH_APPID "" +// #define STEAMPATH_APPID "" +// #define GOGPATH_ID "" #define GAMENAME_FOR_MASTER "Reaction" + #define CINEMATICS_LOGO "Reactionlogo.RoQ" + #define CINEMATICS_INTRO "intro.RoQ" // #define LEGACY_PROTOCOL // You probably don't need this for your standalone game #else #define PRODUCT_NAME "Reaction" @@ -47,8 +50,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define HOMEPATH_NAME_WIN "Reaction" #define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN // #define STEAMPATH_NAME "Foo Bar" -// #define STEAMPATH_APPID "" +// #define STEAMPATH_APPID "" +// #define GOGPATH_ID "" #define GAMENAME_FOR_MASTER "Reaction" + #define CINEMATICS_LOGO "Reactionlogo.RoQ" + #define CINEMATICS_INTRO "intro.RoQ" // #define LEGACY_PROTOCOL #endif @@ -66,6 +72,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define PRODUCT_VERSION "1.36" #endif +#ifndef PRODUCT_DATE +# define PRODUCT_DATE __DATE__ +#endif + #define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION #define MAX_TEAMNAME 32 @@ -151,6 +161,7 @@ typedef int intptr_t; #include #include #include +#include #include #include #include @@ -167,13 +178,15 @@ typedef int intptr_t; typedef unsigned __int32 uint32_t; typedef unsigned __int16 uint16_t; typedef unsigned __int8 uint8_t; +#else + #include +#endif +#ifdef _WIN32 // vsnprintf is ISO/IEC 9899:1999 // abstracting this to make it portable int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap); #else - #include - #define Q_vsnprintf vsnprintf #endif @@ -260,7 +273,7 @@ typedef int clipHandle_t; #define MAX_SAY_TEXT 150 -// paramters for command buffer stuffing +// parameters for command buffer stuffing typedef enum { EXEC_NOW, // don't return until completed, a VM should NEVER use this, // because some commands might cause the VM to be unloaded... @@ -403,8 +416,7 @@ extern vec4_t colorMdGrey; extern vec4_t colorDkGrey; #define Q_COLOR_ESCAPE '^' -//#define Q_IsColorString(p) ((p) && *(p) == Q_COLOR_ESCAPE && *((p)+1) && isalnum(*((p)+1))) // ^[0-9a-zA-Z] -#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE ) +#define Q_IsColorString(p) ((p) && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE) #define COLOR_BLACK '0' #define COLOR_RED '1' @@ -1243,7 +1255,7 @@ typedef struct playerState_s { #define BUTTON_TALK 2 // displays talk balloon and disables actions #define BUTTON_USE_HOLDABLE 4 #define BUTTON_GESTURE 8 -#define BUTTON_WALKING 16 // walking can't just be infered from MOVE_RUN +#define BUTTON_WALKING 16 // walking can't just be inferred from MOVE_RUN // because a key pressed late in the frame will // only generate a small move value for that frame // walking will use different animations and diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 101b5459..f510a0f2 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -637,6 +637,8 @@ int FS_LoadStack( void ); int FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ); int FS_GetModList( char *listbuf, int bufsize ); +void FS_GetModDescription( const char *modDir, char *description, int descriptionLen ); + fileHandle_t FS_FOpenFileWrite( const char *qpath ); fileHandle_t FS_FOpenFileAppend( const char *filename ); fileHandle_t FS_FCreateOpenPipeFile( const char *filename ); @@ -657,7 +659,6 @@ int FS_FileIsInPAK(const char *filename, int *pChecksum ); int FS_Write( const void *buffer, int len, fileHandle_t f ); -int FS_Read2( void *buffer, int len, fileHandle_t f ); int FS_Read( void *buffer, int len, fileHandle_t f ); // properly handles partial reads and reads from other dlls @@ -668,7 +669,7 @@ long FS_ReadFileDir(const char *qpath, void *searchPath, qboolean unpure, void * long FS_ReadFile(const char *qpath, void **buffer); // returns the length of the file // a null buffer will just return the file length without loading -// as a quick check for existance. -1 length == not present +// as a quick check for existence. -1 length == not present // A 0 byte will always be appended at the end, so string ops are safe. // the buffer should be considered read-only, because it may be cached // for other uses. @@ -725,6 +726,7 @@ void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames ); // sole exception of .cfg files. qboolean FS_CheckDirTraversal(const char *checkdir); +qboolean FS_InvalidGameDir(const char *gamedir); qboolean FS_idPak(char *pak, char *base, int numPaks); qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ); @@ -762,7 +764,7 @@ void Field_CompleteFilename( const char *dir, const char *ext, qboolean stripExt, qboolean allowNonPureFilesOnDisk ); void Field_CompleteCommand( char *cmd, qboolean doCommands, qboolean doCvars ); -void Field_CompletePlayerName( char **names, int count ); +void Field_CompletePlayerName( const char **names, int count ); /* ============================================================== @@ -880,6 +882,9 @@ extern cvar_t *com_protocol; #ifdef LEGACY_PROTOCOL extern cvar_t *com_legacyprotocol; #endif +#ifndef DEDICATED +extern cvar_t *con_autochat; +#endif // com_speeds times extern int time_game; @@ -1054,6 +1059,14 @@ int SV_SendQueuedPackets(void); qboolean UI_GameCommand( void ); qboolean UI_usesUniqueCDKey(void); +// +// input interface +// +void IN_Init( void *windowData ); +void IN_Frame( void ); +void IN_Shutdown( void ); +void IN_Restart( void ); + /* ============================================================== @@ -1071,6 +1084,8 @@ void * QDECL Sys_LoadGameDll( const char *name, intptr_t (QDECL **entryPoint)(in intptr_t (QDECL *systemcalls)(intptr_t, ...) ); void Sys_UnloadDll( void *dllHandle ); +qboolean Sys_DllExtension( const char *name ); + char *Sys_GetCurrentUser( void ); void QDECL Sys_Error( const char *error, ...) __attribute__ ((noreturn, format (printf, 1, 2))); @@ -1107,8 +1122,9 @@ char *Sys_Cwd( void ); void Sys_SetDefaultInstallPath(const char *path); char *Sys_DefaultInstallPath(void); char *Sys_SteamPath(void); +char *Sys_GogPath(void); -#ifdef MACOS_X +#ifdef __APPLE__ char *Sys_DefaultAppPath(void); #endif @@ -1145,7 +1161,8 @@ typedef enum dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title ); -qboolean Sys_WritePIDFile( void ); +void Sys_RemovePIDFile( const char *gamedir ); +void Sys_InitPIDFile( const char *gamedir ); /* This is based on the Adaptive Huffman algorithm described in Sayood's Data * Compression book. The ranks are not actually stored, but implicitly defined @@ -1188,9 +1205,9 @@ void Huff_Decompress(msg_t *buf, int offset); void Huff_Init(huffman_t *huff); void Huff_addRef(huff_t* huff, byte ch); int Huff_Receive (node_t *node, int *ch, byte *fin); -void Huff_transmit (huff_t *huff, int ch, byte *fout); -void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset); -void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset); +void Huff_transmit (huff_t *huff, int ch, byte *fout, int maxoffset); +void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset, int maxoffset); +void Huff_offsetTransmit (huff_t *huff, int ch, byte *fout, int *offset, int maxoffset); void Huff_putBit( int bit, byte *fout, int *offset); int Huff_getBit( byte *fout, int *offset); diff --git a/code/qcommon/surfaceflags.h b/code/qcommon/surfaceflags.h index b191ab54..b1b0225d 100644 --- a/code/qcommon/surfaceflags.h +++ b/code/qcommon/surfaceflags.h @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // // This file must be identical in the quake and utils directories -// contents flags are seperate bits +// contents flags are separate bits // a given brush can contribute multiple content bits // these definitions also need to be in q_shared.h! diff --git a/code/qcommon/unzip.c b/code/qcommon/unzip.c index b5043c19..9a8ee451 100644 --- a/code/qcommon/unzip.c +++ b/code/qcommon/unzip.c @@ -151,7 +151,7 @@ typedef struct /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. - IN assertion: the stream s has been sucessfully opened for reading. + IN assertion: the stream s has been successfully opened for reading. */ @@ -290,8 +290,8 @@ local int strcmpcasenosensitive_internal (fileName1,fileName2) /* Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + If iCaseSenisivity = 1, comparison is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparison is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) diff --git a/code/qcommon/unzip.h b/code/qcommon/unzip.h index b22b72ea..74dee975 100644 --- a/code/qcommon/unzip.h +++ b/code/qcommon/unzip.h @@ -125,8 +125,8 @@ extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, int iCaseSensitivity)); /* Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + If iCaseSenisivity = 1, comparison is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparison is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) diff --git a/code/qcommon/vm.c b/code/qcommon/vm.c index e8818a6c..03bdb966 100644 --- a/code/qcommon/vm.c +++ b/code/qcommon/vm.c @@ -451,13 +451,15 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc, qboolean unpure) if(alloc) { // allocate zero filled space for initialized and uninitialized data - vm->dataBase = Hunk_Alloc(dataLength, h_high); + // leave some space beyond data mask so we can secure all mask operations + vm->dataAlloc = dataLength + 4; + vm->dataBase = Hunk_Alloc(vm->dataAlloc, h_high); vm->dataMask = dataLength - 1; } else { // clear the data, but make sure we're not clearing more than allocated - if(vm->dataMask + 1 != dataLength) + if(vm->dataAlloc != dataLength + 4) { VM_Free(vm); FS_FreeFile(header.v); @@ -467,7 +469,7 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc, qboolean unpure) return NULL; } - Com_Memset(vm->dataBase, 0, dataLength); + Com_Memset(vm->dataBase, 0, vm->dataAlloc); } // copy the intialized data diff --git a/code/qcommon/vm_armv7l.c b/code/qcommon/vm_armv7l.c new file mode 100644 index 00000000..8f2bd8ce --- /dev/null +++ b/code/qcommon/vm_armv7l.c @@ -0,0 +1,1222 @@ +/* +=========================================================================== +Copyright (C) 2009 David S. Miller +Copyright (C) 2013,2014 SUSE Linux Products GmbH + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== + +ARMv7l VM by Ludwig Nussel + +TODO: optimization + +Docu: +http://www.coranac.com/tonc/text/asm.htm +http://www.heyrick.co.uk/armwiki/Category:Opcodes +ARMv7-A_ARMv7-R_DDI0406_2007.pdf +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "vm_local.h" +#define R0 0 +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 + +#define R12 12 + +#define FP 11 +#define SP 13 +#define LR 14 +#define PC 15 + +#define APSR_nzcv 15 + +#define S14 14 +#define S15 15 + +#define rOPSTACK 5 +#define rOPSTACKBASE 6 +#define rCODEBASE 7 +#define rPSTACK 8 +#define rDATABASE 9 +#define rDATAMASK 10 + +#define bit(x) (1<compiled = qfalse; return; } while(0) +#endif + +static void VM_Destroy_Compiled(vm_t *vm) +{ + if (vm->codeBase) { + if (munmap(vm->codeBase, vm->codeLength)) + Com_Printf(S_COLOR_RED "Memory unmap failed, possible memory leak\n"); + } + vm->codeBase = NULL; +} + +/* +================= +ErrJump +Error handler for jump/call to invalid instruction number +================= +*/ + +static void __attribute__((__noreturn__)) ErrJump(unsigned num) +{ + Com_Error(ERR_DROP, "program tried to execute code outside VM (%x)", num); +} + +static int asmcall(int call, int pstack) +{ + // save currentVM so as to allow for recursive VM entry + vm_t *savedVM = currentVM; + int i, ret; + + // modify VM stack pointer for recursive VM entry + currentVM->programStack = pstack - 4; + + if (sizeof(intptr_t) == sizeof(int)) { + intptr_t *argPosition = (intptr_t *)((byte *)currentVM->dataBase + pstack + 4); + argPosition[0] = -1 - call; + ret = currentVM->systemCall(argPosition); + } else { + intptr_t args[MAX_VMSYSCALL_ARGS]; + + args[0] = -1 - call; + int *argPosition = (int *)((byte *)currentVM->dataBase + pstack + 4); + for( i = 1; i < ARRAY_LEN(args); i++ ) + args[i] = argPosition[i]; + + ret = currentVM->systemCall(args); + } + + currentVM = savedVM; + + return ret; +} + +void _emit(vm_t *vm, unsigned isn, int pass) +{ +#if 0 + static int fd = -2; + if (fd == -2) + fd = open("code.bin", O_TRUNC|O_WRONLY|O_CREAT, 0644); + if (fd > 0) + write(fd, &isn, 4); +#endif + + if (pass) + memcpy(vm->codeBase+vm->codeLength, &isn, 4); + vm->codeLength+=4; +} + +#define emit(isn) _emit(vm, isn, pass) + +static unsigned char off8(unsigned val) +{ + if (val&3) + DIE("offset must be multiple of four"); + if (val > 1020) + DIE("offset too large"); + return val>>2; +} + +// ARM is really crazy ... +static unsigned short rimm(unsigned val) +{ + unsigned shift = 0; + if (val < 256) + return val; + // rotate the value until it fits + while (shift < 16 && (val>255 || !(val&3))) { + val = (val&3)<<30 | val>>2; + ++shift; + } + if (shift > 15 || val > 255) { + DIE("immediate cannot be encoded (%d, %d)\n", shift, val); + } + return (16-shift)<<8 | val; +} + +// same as rimm but doesn't die, returns 0 if not encodable so don't call with zero as argument! +static unsigned short can_encode(unsigned val) +{ + unsigned shift = 0; + if (!val) + DIE("can_encode: invalid argument"); + if (val < 256) + return val; + // rotate the value until it fits + while (shift < 16 && (val>255 || !(val&3))) { + val = (val&3)<<30 | val>>2; + ++shift; + } + if (shift > 15 || val > 255) { + return 0; + } + return (16-shift)<<8 | val; +} + +#define PREINDEX (1<<24) + +#define rASR(i, reg) (0b10<<5 | ((i&31)<<7) | reg) +#define rLSL(i, reg) (0b00<<5 | ((i&31)<<7) | reg) +#define rLSR(i, reg) (0b01<<5 | ((i&31)<<7) | reg) +#define rROR(i, reg) (0b11<<5 | ((i&31)<<7) | reg) + +// conditions +#define EQ (0b0000<<28) +#define NE (0b0001<<28) +#define CS (0b0010<<28) +#define HS CS +#define CC (0b0011<<28) +#define LO CC +#define MI (0b0100<<28) +#define PL (0b0101<<28) +#define VS (0b0110<<28) +#define VC (0b0111<<28) +#define HI (0b1000<<28) +#define LS (0b1001<<28) +#define GE (0b1010<<28) +#define LT (0b1011<<28) +#define GT (0b1100<<28) +#define LE (0b1101<<28) +#define AL (0b1110<<28) +#define cond(what, op) (what | (op&~AL)) + +// XXX: v not correctly computed +#define BKPT(v) (AL | 0b10010<<20 | ((v&~0xF)<<4) | 0b0111<<4 | (v&0xF)) + +#define YIELD (0b110010<<20 | 0b1111<<12 | 1) +#define NOP cond(AL, YIELD) + +// immediate value must fit in 0xFF! +#define ANDi(dst, src, i) (AL | (0b001<<25) | (0b00000<<20) | (src<<16) | (dst<<12) | rimm(i)) +#define EORi(dst, src, i) (AL | (0b001<<25) | (0b00010<<20) | (src<<16) | (dst<<12) | rimm(i)) +#define SUBi(dst, src, i) (AL | (0b001<<25) | (0b00100<<20) | (src<<16) | (dst<<12) | rimm(i)) +#define RSBi(dst, src, i) (AL | (0b001<<25) | (0b00110<<20) | (src<<16) | (dst<<12) | rimm(i)) +#define ADDi(dst, src, i) (AL | (0b001<<25) | (0b01000<<20) | (src<<16) | (dst<<12) | rimm(i)) +#define ADCi(dst, src, i) (AL | (0b001<<25) | (0b01010<<20) | (src<<16) | (dst<<12) | rimm(i)) +#define SBCi(dst, src, i) (AL | (0b001<<25) | (0b01100<<20) | (src<<16) | (dst<<12) | rimm(i)) +#define RSCi(dst, src, i) (AL | (0b001<<25) | (0b01110<<20) | (src<<16) | (dst<<12) | rimm(i)) + +#define ORRi(dst, src, i) (AL | (0b001<<25) | (0b11000<<20) | (src<<16) | (dst<<12) | rimm(i)) +#define MOVi(dst, i) (AL | (0b001<<25) | (0b11010<<20) | (dst<<12) | rimm(i)) +#define BICi(dst, src, i) (AL | (0b001<<25) | (0b11100<<20) | (src<<16) | (dst<<12) | rimm(i)) +#define MVNi(dst, i) (AL | (0b001<<25) | (0b11110<<20) | (dst<<12) | rimm(i)) + +#define MOVW(dst, i) (AL | (0b11<<24) | ((((i)>>12)&0xF)<<16) | (dst<<12) | ((i)&((1<<12)-1))) +#define MOVT(dst, i) (AL | (0b11<<24) | (0b0100<<20) | ((((i)>>12)&0xF)<<16) | (dst<<12) | ((i)&((1<<12)-1))) + +#define TSTi( src, i) (AL | (0b001<<25) | (0b10001<<20) | (src<<16) | rimm(i)) +#define TEQi( src, i) (AL | (0b001<<25) | (0b10011<<20) | (src<<16) | rimm(i)) +#define CMPi( src, i) (AL | (0b001<<25) | (0b10101<<20) | (src<<16) | rimm(i)) +#define CMNi( src, i) (AL | (0b001<<25) | (0b10111<<20) | (src<<16) | rimm(i)) + +#define ANDSi(dst, src, i) (ANDi(dst, src, i) | (1<<20)) +#define EORSi(dst, src, i) (EORi(dst, src, i) | (1<<20)) +#define SUBSi(dst, src, i) (SUBi(dst, src, i) | (1<<20)) +#define RSBSi(dst, src, i) (RSBi(dst, src, i) | (1<<20)) +#define ADDSi(dst, src, i) (ADDi(dst, src, i) | (1<<20)) +#define ADCSi(dst, src, i) (ADCi(dst, src, i) | (1<<20)) +#define SBCSi(dst, src, i) (SBCi(dst, src, i) | (1<<20)) +#define RSCSi(dst, src, i) (RSCi(dst, src, i) | (1<<20)) + +#define ORRSi(dst, src, i) (ORRi(dst, src, i) | (1<<20)) +#define MOVSi(dst, i) (MOVi(dst, i) | (1<<20)) +#define BICSi(dst, src, i) (BICi(dst, src, i) | (1<<20)) +#define MVNSi(dst, i) (MVNi(dst, src, i) | (1<<20)) + +#define AND(dst, src, reg) (AL | (0b000<<25) | (0b00000<<20) | (src<<16) | (dst<<12) | reg) +#define EOR(dst, src, reg) (AL | (0b000<<25) | (0b00010<<20) | (src<<16) | (dst<<12) | reg) +#define SUB(dst, src, reg) (AL | (0b000<<25) | (0b00100<<20) | (src<<16) | (dst<<12) | reg) +#define RSB(dst, src, reg) (AL | (0b000<<25) | (0b00110<<20) | (src<<16) | (dst<<12) | reg) +#define ADD(dst, src, reg) (AL | (0b000<<25) | (0b01000<<20) | (src<<16) | (dst<<12) | reg) +#define ADC(dst, src, reg) (AL | (0b000<<25) | (0b01010<<20) | (src<<16) | (dst<<12) | reg) +#define SBC(dst, src, reg) (AL | (0b000<<25) | (0b01100<<20) | (src<<16) | (dst<<12) | reg) +#define RSC(dst, src, reg) (AL | (0b000<<25) | (0b01110<<20) | (src<<16) | (dst<<12) | reg) + +#define ORR(dst, src, reg) (AL | (0b000<<25) | (0b11000<<20) | (src<<16) | (dst<<12) | reg) +#define MOV(dst, src) (AL | (0b000<<25) | (0b11010<<20) | (dst<<12) | src) + +#define LSL(dst, src, reg) (AL | (0b000<<25) | (0b1101<<21) | (0<<20) | (dst<<12) | (reg<<8) | (0b0001<<4) | src) +#define LSR(dst, src, reg) (AL | (0b000<<25) | (0b1101<<21) | (0<<20) | (dst<<12) | (reg<<8) | (0b0011<<4) | src) +#define ASR(dst, src, reg) (AL | (0b000<<25) | (0b1101<<21) | (0<<20) | (dst<<12) | (reg<<8) | (0b0101<<4) | src) +#define ROR(dst, src, reg) (AL | (0b000<<25) | (0b1101<<21) | (0<<20) | (dst<<12) | (reg<<8) | (0b0111<<4) | src) + +#define LSLi(dst, src, i) (AL | (0b000<<25) | (0b1101<<21) | (0<<20) | (dst<<12) | ((i&0x1F)<<7) | (0b000<<4) | src) +#define LSRi(dst, src, i) (AL | (0b000<<25) | (0b1101<<21) | (0<<20) | (dst<<12) | ((i&0x1F)<<7) | (0b010<<4) | src) +#define ASRi(dst, src, i) (AL | (0b000<<25) | (0b1101<<21) | (0<<20) | (dst<<12) | ((i&0x1F)<<7) | (0b100<<4) | src) +#define RORi(dst, src, i) (AL | (0b000<<25) | (0b1101<<21) | (0<<20) | (dst<<12) | ((i&0x1F)<<7) | (0b110<<4) | src) +#define RRX(dst, src) (AL | (0b000<<25) | (0b1101<<21) | (0<<20) | (dst<<12) | (0b110<<4) | src) + +#define BIC(dst, src, reg) (AL | (0b000<<25) | (0b11100<<20) | (src<<16) | (dst<<12) | reg) +#define MVN(dst, reg) (AL | (0b000<<25) | (0b11110<<20) | (dst<<12) | reg) + +#define TST( src, reg) (AL | (0b000<<25) | (0b10001<<20) | (src<<16) | reg) +#define TEQ( src, reg) (AL | (0b000<<25) | (0b10011<<20) | (src<<16) | reg) +#define CMP( src, reg) (AL | (0b000<<25) | (0b10101<<20) | (src<<16) | reg) +#define CMN( src, reg) (AL | (0b000<<25) | (0b10111<<20) | (src<<16) | reg) + +#define LDRa(dst, base, off) (AL | (0b011<<25) | (0b1100<<21) | (1<<20) | base<<16 | dst<<12 | off) +#define LDRx(dst, base, off) (AL | (0b011<<25) | (0b1000<<21) | (1<<20) | base<<16 | dst<<12 | off) + +#define LDRai(dst, base, off) (AL | (0b010<<25) | (0b1100<<21) | (1<<20) | base<<16 | dst<<12 | rimm(off)) +#define LDRxi(dst, base, off) (AL | (0b010<<25) | (0b1000<<21) | (1<<20) | base<<16 | dst<<12 | rimm(off)) +#define LDRxiw(dst, base, off) (AL | (0b010<<25) | (0b1001<<21) | (1<<20) | base<<16 | dst<<12 | rimm(off)) + +#define LDRTa(dst, base, off) (AL | (0b011<<25) | (0b0101<<21) | (1<<20) | base<<16 | dst<<12 | off) +#define LDRTx(dst, base, off) (AL | (0b011<<25) | (0b0001<<21) | (1<<20) | base<<16 | dst<<12 | off) +#define LDRTai(dst, base, off) (AL | (0b010<<25) | (0b0101<<21) | (1<<20) | base<<16 | dst<<12 | rimm(off)) +#define LDRTxi(dst, base, off) (AL | (0b010<<25) | (0b0001<<21) | (1<<20) | base<<16 | dst<<12 | rimm(off)) + +#define LDRBa(dst, base, off) (AL | (0b011<<25) | (0b1110<<21) | (1<<20) | base<<16 | dst<<12 | off) +#define LDRSBai(dst, base, off) (AL | (0b000<<25) | (0b0110<<21) | (1<<20) | base<<16 | dst<<12 | ((off&0xF0)<<4)|0b1101<<4|(off&0x0F)) +#define STRBa(dst, base, off) (AL | (0b011<<25) | (0b1110<<21) | (0<<20) | base<<16 | dst<<12 | off) + +#define LDRHa(dst, base, off) (AL | (0b000<<25) | (0b1100<<21) | (1<<20) | base<<16 | dst<<12 | (0b1011<<4) | off) +#define LDRSHai(dst, base, off) (AL | (0b000<<25) | (0b1110<<21) | (1<<20) | base<<16 | dst<<12 | ((off&0xF0)<<4)|0b1111<<4|(off&0x0F)) +#define STRHa(dst, base, off) (AL | (0b000<<25) | (0b1100<<21) | (0<<20) | base<<16 | dst<<12 | (0b1011<<4) | off) + +#define STRa(dst, base, off) (AL | (0b011<<25) | (0b1100<<21) | (0<<20) | base<<16 | dst<<12 | off) +#define STRx(dst, base, off) (AL | (0b011<<25) | (0b1000<<21) | (0<<20) | base<<16 | dst<<12 | off) +#define STRai(dst, base, off) (AL | (0b010<<25) | (0b1100<<21) | (0<<20) | base<<16 | dst<<12 | rimm(off)) +#define STRxi(dst, base, off) (AL | (0b010<<25) | (0b1000<<21) | (0<<20) | base<<16 | dst<<12 | rimm(off)) +#define STRaiw(dst, base, off) (AL | (0b010<<25) | (0b1101<<21) | (0<<20) | base<<16 | dst<<12 | rimm(off)) +#define STRxiw(dst, base, off) (AL | (0b010<<25) | (0b1001<<21) | (0<<20) | base<<16 | dst<<12 | rimm(off)) + +// load with post-increment +#define POP1(reg) (AL | (0b010<<25) | (0b0100<<21) | (1<<20) | SP<<16 | reg<<12 | reg) +// store with post-increment +#define PUSH1(reg) (AL | (0b010<<25) | (0b1001<<21) | (0<<20) | SP<<16 | reg<<12 | 4) + +// branch to target address (for small jumps) +#define Bi(i) \ + (AL | (0b10)<<26 | (1<<25) /*I*/ | (0<<24) /*L*/ | (i)) +// call subroutine +#define BLi(i) \ + (AL | (0b10)<<26 | (1<<25) /*I*/ | (1<<24) /*L*/ | (i)) +// branch and exchange (register) +#define BX(reg) \ + (AL | 0b00010010<<20 | 0b1111<<16 | 0b1111<<12 | 0b1111<<8| 0b0001<<4 | reg) +// call subroutine (register) +#define BLX(reg) \ + (AL | 0b00010010<<20 | 0b1111<<16 | 0b1111<<12 | 0b1111<<8| 0b0011<<4 | reg) + +#define PUSH(mask) (AL | (0b100100<<22) | (0b10<<20) | (0b1101<<16) | mask) +#define PUSH2(r1, r2) (AL | (0b100100<<22) | (0b10<<20) | (0b1101<<16) | 1< 0xFFFF) \ + emit(MOVT(reg, (((arg>>16)&0xFFFF)))); \ + } while(0) + +// puts integer arg in register reg. adds nop if only one instr is needed to +// make size constant +#define emit_MOVRxi_or_NOP(reg, arg) do { \ + emit(MOVW(reg, (arg&0xFFFF))); \ + if (arg > 0xFFFF) \ + emit(MOVT(reg, (((arg>>16)&0xFFFF)))); \ + else \ + emit(NOP); \ + } while(0) + +// arm core register -> singe precision register +#define VMOVass(Vn, Rt) (AL|(0b1110<<24)|(0b000<<21)|(0<<20)| ((Vn>>1)<<16) | (Rt<<12) | (0b1010<<8) | ((Vn&1)<<7) | (1<<4)) +// singe precision register -> arm core register +#define VMOVssa(Rt, Vn) (AL|(0b1110<<24)|(0b000<<21)|(1<<20)| ((Vn>>1)<<16) | (Rt<<12) | (0b1010<<8) | ((Vn&1)<<7) | (1<<4)) + +#define _VCVT_F(Vd, Vm, opc2, op) \ + (AL|(0b11101<<23)|((Vd&1)<<22)|(0b111<<19)|(opc2<<16)|((Vd>>1)<<12)|(0b101<<9)|(0<<8)|(op<<7)|(1<<6)|((Vm&1)<<5)|(Vm>>1)) +#define VCVT_F32_U32(Sd, Sm) _VCVT_F(Sd, Sm, 0b000, 0 /* unsigned */) +#define VCVT_U32_F32(Sd, Sm) _VCVT_F(Sd, Sm, 0b100, 1 /* round zero */) +#define VCVT_F32_S32(Sd, Sm) _VCVT_F(Sd, Sm, 0b000, 1 /* unsigned */) +#define VCVT_S32_F32(Sd, Sm) _VCVT_F(Sd, Sm, 0b101, 1 /* round zero */) + +#define VLDRa(Vd, Rn, i) (AL|(0b1101<<24)|1<<23|((Vd&1)<<22)|1<<20|(Rn<<16)|((Vd>>1)<<12)|(0b1010<<8)|off8(i)) +#define VSTRa(Vd, Rn, i) (AL|(0b1101<<24)|1<<23|((Vd&1)<<22)|0<<20|(Rn<<16)|((Vd>>1)<<12)|(0b1010<<8)|off8(i)) + +#define VNEG_F32(Vd, Vm) \ + (AL|(0b11101<<23)|((Vd&1)<<22)|(0b11<<20)|(1<<16)|((Vd>>1)<<12)|(0b101<<9)|(0<<8)|(1<<6)|((Vm&1)<<5)|(Vm>>1)) + +#define VADD_F32(Vd, Vn, Vm) \ + (AL|(0b11100<<23)|((Vd&1)<<22)|(0b11<<20)|((Vn>>1)<<16)|((Vd>>1)<<12)|(0b101<<9)|(0<<8)|((Vn&1)<<7)|(0<<6)|((Vm&1)<<5)|(Vm>>1)) +#define VSUB_F32(Vd, Vn, Vm) \ + (AL|(0b11100<<23)|((Vd&1)<<22)|(0b11<<20)|((Vn>>1)<<16)|((Vd>>1)<<12)|(0b101<<9)|(0<<8)|((Vn&1)<<7)|(1<<6)|((Vm&1)<<5)|(Vm>>1)) +#define VMUL_F32(Vd, Vn, Vm) \ + (AL|(0b11100<<23)|((Vd&1)<<22)|(0b10<<20)|((Vn>>1)<<16)|((Vd>>1)<<12)|(0b101)<<9|(0<<8)|((Vn&1)<<7)|(0<<6)|((Vm&1)<<5)|(Vm>>1)) +#define VDIV_F32(Vd, Vn, Vm) \ + (AL|(0b11101<<23)|((Vd&1)<<22)|(0b00<<20)|((Vn>>1)<<16)|((Vd>>1)<<12)|(0b101<<9)|(0<<8)|((Vn&1)<<7)|(0<<6)|((Vm&1)<<5)|(Vm>>1)) + +#define _VCMP_F32(Vd, Vm, E) \ + (AL|(0b11101<<23)|((Vd&1)<<22)|(0b11<<20)|((0b0100)<<16)|((Vd>>1)<<12)|(0b101<<9)|(0<<8)|(E<<7)|(1<<6)|((Vm&1)<<5)|(Vm>>1)) +#define VCMP_F32(Vd, Vm) _VCMP_F32(Vd, Vm, 0) + +#define VMRS(Rt) \ + (AL|(0b11101111<<20)|(0b0001<<16)|(Rt<<12)|(0b1010<<8)|(1<<4)) + +// check if instruction in R0 is within range. Clobbers R1, R12 +#define CHECK_JUMP do { \ + static int bytes_to_skip = -1; \ + static unsigned branch = -1; \ + emit_MOVRxi(R1, (unsigned)vm->instructionCount); \ + emit(CMP(R0, R1)); \ + if (branch == -1) \ + branch = vm->codeLength; \ + emit(cond(LT, Bi(j_rel(bytes_to_skip)))); \ + emit_MOVRxi_or_NOP(R12, (unsigned)ErrJump); \ + emit(BLX(R12)); \ + if (bytes_to_skip == -1) \ + bytes_to_skip = vm->codeLength - branch; \ +} while(0) + +//#define CONST_OPTIMIZE +#ifdef CONST_OPTIMIZE +#define MAYBE_EMIT_CONST() \ + if (got_const) \ + { \ + got_const = 0; \ + vm->instructionPointers[instruction-1] = assembler_get_code_size(); \ + STACK_PUSH(4); \ + emit("movl $%d, (%%r9, %%rbx, 4)", const_value); \ + } +#else +#define MAYBE_EMIT_CONST() +#endif + +// optimize: use load multiple +#define IJ(comparator) do { \ + MAYBE_EMIT_CONST(); \ + emit_MOVRxi(R0, arg.i); \ + CHECK_JUMP; \ + emit(LDRTxi(R0, rOPSTACK, 4)); \ + emit(LDRTxi(R1, rOPSTACK, 4)); \ + emit(CMP(R1, R0)); \ + emit(cond(comparator, Bi(j_rel(vm->instructionPointers[arg.i]-vm->codeLength)))); \ +} while (0) + +#define FJ(comparator) do { \ + emit_MOVRxi(R0, arg.i); \ + CHECK_JUMP; \ + emit(SUBi(rOPSTACK, rOPSTACK, 8)); \ + emit(VLDRa(S15, rOPSTACK, 4)); \ + emit(VLDRa(S14, rOPSTACK, 8)); \ + emit(VCMP_F32(S15, S14)); \ + emit(VMRS(APSR_nzcv)); \ + emit(cond(comparator, Bi(j_rel(vm->instructionPointers[arg.i]-vm->codeLength)))); \ +} while (0) + +#define printreg(reg) emit(PUSH1(R3)); emit(BLX(reg)); emit(POP1(R3)); + +static inline unsigned _j_rel(int x, int pc) +{ + if (x&3) goto err; + x = (x>>2)-2; + if (x < 0) + { + if ((x&(0xFF<<24)) != 0xFF<<24) + goto err; + x &= ~(0xFF<<24); + } + else if (x&(0xFF<<24)) + goto err; + return x; +err: + DIE("jump %d out of range at %d", x, pc); +} + +void VM_Compile(vm_t *vm, vmHeader_t *header) +{ + unsigned char *code; + int i_count, pc = 0; + int pass; + int codeoffsets[2]; // was 1024 but it's only used for OFF_CODE and OFF_IMMEDIATES + +#define j_rel(x) (pass?_j_rel(x, pc):0xBAD) +#define OFFSET(i) (pass?(j_rel(codeoffsets[i]-vm->codeLength)):(0xF000000F)) +//#define new_offset() (offsidx++) +#define get_offset(i) (codeoffsets[i]) +#define save_offset(i) (codeoffsets[i] = vm->codeLength) +#define OFF_CODE 0 +#define OFF_IMMEDIATES 1 + + vm->compiled = qfalse; + + vm->codeBase = NULL; + vm->codeLength = 0; + + for (pass = 0; pass < 2; ++pass) { + +// int offsidx = 0; + +#ifdef CONST_OPTIMIZE + // const optimization + unsigned got_const = 0, const_value = 0; +#endif + + if(pass) + { + vm->codeBase = mmap(NULL, vm->codeLength, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); + if(vm->codeBase == MAP_FAILED) + Com_Error(ERR_FATAL, "VM_CompileARM: can't mmap memory"); + vm->codeLength = 0; + } + + //int (*entry)(vm_t*, int*, int*); + emit(PUSH((((1<<8)-1)<<4)|(1<<14))); // push R4-R11, LR + emit(SUBi(SP, SP, 12)); // align stack! + emit(LDRai(rCODEBASE, R0, offsetof(vm_t, codeBase))); + emit(LDRai(rDATABASE, R0, offsetof(vm_t, dataBase))); + emit(LDRai(rDATAMASK, R0, offsetof(vm_t, dataMask))); + emit(LDRai(rPSTACK, R1, 0)); + emit(MOV(rOPSTACK, R2)); // TODO: reverse opstack to avoid writing to return address + emit(MOV(rOPSTACKBASE, rOPSTACK)); + + emit(BLi(OFFSET(OFF_CODE))); + + // save return value in r0 + emit(LDRTxi(R0, rOPSTACK, 4)); // r0 = *opstack; rOPSTACK -= 4 + + emit(ADDi(SP, SP, 12)); // align stack! + emit(POP((((1<<8)-1)<<4)|(1<<15))); // pop R4-R11, LR -> PC + + /* save some immediates here */ + emit(BKPT(0)); + emit(BKPT(0)); + save_offset(OFF_IMMEDIATES); +// emit((unsigned)whatever); + emit(BKPT(0)); + emit(BKPT(0)); + + save_offset(OFF_CODE); +// offsidx = OFF_IMMEDIATES+1; + + code = (unsigned char *) header + header->codeOffset; + pc = 0; + + for (i_count = 0; i_count < header->instructionCount; i_count++) { + union { + unsigned char b[4]; + unsigned int i; + } arg; + unsigned char op = code[pc++]; + + vm->instructionPointers[i_count] = vm->codeLength; + + if (vm_opInfo[op] & opImm4) + { + memcpy(arg.b, &code[pc], 4); + pc += 4; +#ifdef EXCESSIVE_DEBUG + Com_Printf("%d: instruction %d (%s %d), offset %d\n", pass, i_count, opnames[op], arg.i, vm->codeLength); +#endif + } + else if (vm_opInfo[op] & opImm1) + { + arg.b[0] = code[pc]; + ++pc; +#ifdef EXCESSIVE_DEBUG + Com_Printf("%d: instruction %d (%s %hhd), offset %d\n", pass, i_count, opnames[op], arg.i, vm->codeLength); +#endif + } + else + { +#ifdef EXCESSIVE_DEBUG + Com_Printf("%d: instruction %d (%s), offset %d\n", pass, i_count, opnames[op], vm->codeLength); +#endif + } + + // TODO: for debug only + //emit_MOVRxi(R4, i_count); + + switch ( op ) + { + case OP_UNDEF: + break; + + case OP_IGNORE: + NOTIMPL(op); + break; + + case OP_BREAK: + emit(BKPT(0)); + break; + + case OP_ENTER: + MAYBE_EMIT_CONST(); + emit(PUSH1(LR)); + emit(SUBi(SP, SP, 12)); // align stack + if (arg.i == 0 || can_encode(arg.i)) + { + emit(SUBi(rPSTACK, rPSTACK, arg.i)); // pstack -= arg + } + else + { + emit_MOVR0i(arg.i); + emit(SUB(rPSTACK, rPSTACK, R0)); // pstack -= arg + } + break; + + case OP_LEAVE: + if (arg.i == 0 || can_encode(arg.i)) + { + emit(ADDi(rPSTACK, rPSTACK, arg.i)); // pstack += arg + } + else + { + emit_MOVR0i(arg.i); + emit(ADD(rPSTACK, rPSTACK, R0)); // pstack += arg + } + emit(ADDi(SP, SP, 12)); + emit(0xe49df004); // pop pc + break; + + case OP_CALL: +#if 0 + // save next instruction + emit_MOVR0i(i_count); + emit(STRa(R0, rDATABASE, rPSTACK)); // dataBase[pstack] = r0 +#endif +#ifdef CONST_OPTIMIZE + if (got_const) + { + NOTIMPL(op); + } + else +#endif + { + static int bytes_to_skip = -1; + static unsigned start_block = -1; + MAYBE_EMIT_CONST(); + // get instruction nr from stack + emit(LDRTxi(R0, rOPSTACK, 4)); // r0 = *opstack; rOPSTACK -= 4 + emit(CMPi(R0, 0)); // check if syscall + if (start_block == -1) + start_block = vm->codeLength; + emit(cond(LT, Bi(j_rel(bytes_to_skip)))); + CHECK_JUMP; + emit_MOVRxi_or_NOP(R1, (unsigned)vm->instructionPointers); + emit(LDRa(R0, R1, rLSL(2, R0))); // r0 = ((int*)r1)[r0] + emit(ADD(R0, rCODEBASE, R0)); // r0 = codeBase+r0 + emit(BLX(R0)); + emit(Bi(j_rel(vm->instructionPointers[i_count+1]-vm->codeLength))); + if (bytes_to_skip == -1) + bytes_to_skip = vm->codeLength - start_block; + emit(MOV(R1, rPSTACK)); + emit_MOVRxi(R12, (unsigned)asmcall); + emit(BLX(R12)); + // store return value + emit(STRaiw(R0, rOPSTACK, 4)); // opstack+=4; *opstack = r0 + } + break; + + case OP_PUSH: + MAYBE_EMIT_CONST(); + emit(ADDi(rOPSTACK, rOPSTACK, 4)); + break; + + case OP_POP: + MAYBE_EMIT_CONST(); + emit(SUBi(rOPSTACK, rOPSTACK, 4)); + break; + + case OP_CONST: + MAYBE_EMIT_CONST(); + emit_MOVR0i(arg.i); + emit(STRaiw(R0, rOPSTACK, 4)); // opstack+=4; *opstack = r0 + break; + + case OP_LOCAL: + MAYBE_EMIT_CONST(); + if (arg.i == 0 || can_encode(arg.i)) + { + emit(ADDi(R0, rPSTACK, arg.i)); // r0 = pstack+arg + } + else + { + emit_MOVR0i(arg.i); + emit(ADD(R0, rPSTACK, R0)); // r0 = pstack+arg + } + emit(STRaiw(R0, rOPSTACK, 4)); // opstack+=4; *opstack = r0 + break; + + case OP_JUMP: +#ifdef CONST_OPTIMIZE + if (got_const) + { + NOTIMPL(op); + } + else +#endif + { + emit(LDRTxi(R0, rOPSTACK, 4)); // r0 = *opstack; rOPSTACK -= 4 + CHECK_JUMP; + emit_MOVRxi(R1, (unsigned)vm->instructionPointers); + emit(LDRa(R0, R1, rLSL(2, R0))); // r0 = ((int*)r1)[r0] + emit(ADD(R0, rCODEBASE, R0)); // r0 = codeBase+r0 + emit(BLX(R0)); + } + break; + + case OP_EQ: + IJ(EQ); + break; + + case OP_NE: + IJ(NE); + break; + + case OP_LTI: + IJ(LT); + break; + + case OP_LEI: + IJ(LE); + break; + + case OP_GTI: + IJ(GT); + break; + + case OP_GEI: + IJ(GE); + break; + + case OP_LTU: + IJ(LO); + break; + + case OP_LEU: + IJ(LS); + break; + + case OP_GTU: + IJ(HI); + break; + + case OP_GEU: + IJ(HS); + break; + + case OP_EQF: + FJ(EQ); + break; + + case OP_NEF: + FJ(NE); + break; + + case OP_LTF: + FJ(LT); + break; + + case OP_LEF: + FJ(LE); + break; + + case OP_GTF: + FJ(GT); + break; + + case OP_GEF: + FJ(GE); + break; + + case OP_LOAD1: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(AND(R0, rDATAMASK, R0)); // r0 = r0 & rDATAMASK + emit(LDRBa(R0, rDATABASE, R0)); // r0 = (unsigned char)dataBase[r0] + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_LOAD2: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(AND(R0, rDATAMASK, R0)); // r0 = r0 & rDATAMASK + emit(LDRHa(R0, rDATABASE, R0)); // r0 = (unsigned short)dataBase[r0] + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_LOAD4: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(AND(R0, rDATAMASK, R0)); // r0 = r0 & rDATAMASK + emit(LDRa(R0, rDATABASE, R0)); // r0 = dataBase[r0] + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_STORE1: + MAYBE_EMIT_CONST(); + emit(LDRTxi(R0, rOPSTACK, 4)); // r0 = *opstack; rOPSTACK -= 4 + emit(LDRTxi(R1, rOPSTACK, 4)); // r1 = *opstack; rOPSTACK -= 4 + emit(AND(R1, rDATAMASK, R1)); // r1 = r1 & rDATAMASK + emit(STRBa(R0, rDATABASE, R1)); // database[r1] = r0 + break; + + case OP_STORE2: + MAYBE_EMIT_CONST(); + emit(LDRTxi(R0, rOPSTACK, 4)); // r0 = *opstack; rOPSTACK -= 4 + emit(LDRTxi(R1, rOPSTACK, 4)); // r1 = *opstack; rOPSTACK -= 4 + emit(AND(R1, rDATAMASK, R1)); // r1 = r1 & rDATAMASK + emit(STRHa(R0, rDATABASE, R1)); // database[r1] = r0 + break; + + case OP_STORE4: + MAYBE_EMIT_CONST(); + // optimize: use load multiple + // value + emit(LDRTxi(R0, rOPSTACK, 4)); // r0 = *opstack; rOPSTACK -= 4 + // pointer + emit(LDRTxi(R1, rOPSTACK, 4)); // r1 = *opstack; rOPSTACK -= 4 + emit(AND(R1, rDATAMASK, R1)); // r1 = r1 & rDATAMASK + // store value at pointer + emit(STRa(R0, rDATABASE, R1)); // database[r1] = r0 + break; + + case OP_ARG: + MAYBE_EMIT_CONST(); + emit(LDRTxi(R0, rOPSTACK, 4)); // r0 = *opstack; rOPSTACK -= 4 + emit(ADDi(R1, rPSTACK, arg.b[0])); // r1 = programStack+arg + emit(AND(R1, rDATAMASK, R1)); // r1 = r1 & rDATAMASK + emit(STRa(R0, rDATABASE, R1)); // dataBase[r1] = r0 + break; + + case OP_BLOCK_COPY: + MAYBE_EMIT_CONST(); + emit(LDRTxi(R1, rOPSTACK, 4)); // r0 = *opstack; rOPSTACK -= 4 + emit(LDRTxi(R0, rOPSTACK, 4)); + emit_MOVRxi(R2, arg.i); + emit_MOVRxi(R12, (unsigned)VM_BlockCopy); + emit(BLX(R12)); + break; + + case OP_SEX8: + MAYBE_EMIT_CONST(); + emit(LDRSBai(R0, rOPSTACK, 0)); // sign extend *opstack + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_SEX16: + MAYBE_EMIT_CONST(); + emit(LDRSHai(R0, rOPSTACK, 0)); // sign extend *opstack + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_NEGI: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(RSBi(R0, R0, 0)); // r0 = -r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_ADD: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(LDRxiw(R1, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(ADD(R0, R1, R0)); // r0 = r1 + r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_SUB: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(LDRxiw(R1, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(SUB(R0, R1, R0)); // r0 = r1 - r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_DIVI: + case OP_DIVU: + MAYBE_EMIT_CONST(); + emit(LDRai(R1, rOPSTACK, 0)); // r1 = *opstack + emit(LDRxiw(R0, rOPSTACK, 4)); // opstack-=4; r0 = *opstack + if ( op == OP_DIVI ) + emit_MOVRxi(R12, (unsigned)__aeabi_idiv); + else + emit_MOVRxi(R12, (unsigned)__aeabi_uidiv); + emit(BLX(R12)); + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_MODI: + case OP_MODU: + MAYBE_EMIT_CONST(); + emit(LDRai(R1, rOPSTACK, 0)); // r1 = *opstack + emit(LDRxiw(R0, rOPSTACK, 4)); // opstack-=4; r0 = *opstack + if ( op == OP_MODI ) + emit_MOVRxi(R12, (unsigned)__aeabi_idivmod); + else + emit_MOVRxi(R12, (unsigned)__aeabi_uidivmod); + emit(BLX(R12)); + emit(STRai(R1, rOPSTACK, 0)); // *opstack = r1 + break; + + case OP_MULI: + case OP_MULU: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(LDRxiw(R1, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(MUL(R0, R1, R0)); // r0 = r1 * r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_BAND: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(LDRxiw(R1, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(AND(R0, R1, R0)); // r0 = r1 & r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_BOR: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(LDRxiw(R1, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(ORR(R0, R1, R0)); // r0 = r1 | r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_BXOR: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(LDRxiw(R1, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(EOR(R0, R1, R0)); // r0 = r1 ^ r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_BCOM: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(MVN(R0, R0)); // r0 = ~r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_LSH: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(LDRxiw(R1, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(LSL(R0, R1, R0)); // r0 = r1 << r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_RSHI: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(LDRxiw(R1, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(ASR(R0, R1, R0)); // r0 = r1 >> r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_RSHU: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(LDRxiw(R1, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(LSR(R0, R1, R0)); // r0 = (unsigned)r1 >> r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + + case OP_NEGF: + MAYBE_EMIT_CONST(); + emit(VLDRa(S14, rOPSTACK, 0)); // s14 = *((float*)opstack) + emit(VNEG_F32(S14, S14)); // s15 = -s14 + emit(VSTRa(S14, rOPSTACK, 0)); // *((float*)opstack) = s15 + break; + + case OP_ADDF: + MAYBE_EMIT_CONST(); + emit(VLDRa(S14, rOPSTACK, 0)); // s14 = *((float*)opstack) + // vldr can't modify rOPSTACK so + // we'd either need to change it + // with sub or use regular ldr+vmov + emit(LDRxiw(R0, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(VMOVass(S15,R0)); // s15 = r0 + emit(VADD_F32(S14, S15, S14)); // s14 = s14 + s15 + emit(VSTRa(S14, rOPSTACK, 0)); // *((float*)opstack) = s15 + break; + + case OP_SUBF: + emit(VLDRa(S14, rOPSTACK, 0)); // s14 = *((float*)opstack) + // see OP_ADDF + emit(LDRxiw(R0, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(VMOVass(S15,R0)); // s15 = r0 + emit(VSUB_F32(S14, S15, S14)); // s14 = s14 - s15 + emit(VSTRa(S14, rOPSTACK, 0)); // *((float*)opstack) = s15 + break; + + case OP_DIVF: + emit(VLDRa(S14, rOPSTACK, 0)); // s14 = *((float*)opstack) + // see OP_ADDF + emit(LDRxiw(R0, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(VMOVass(S15,R0)); // s15 = r0 + emit(VDIV_F32(S14, S15, S14)); // s14 = s14 / s15 + emit(VSTRa(S14, rOPSTACK, 0)); // *((float*)opstack) = s15 + break; + + case OP_MULF: + emit(VLDRa(S14, rOPSTACK, 0)); // s14 = *((float*)opstack) + // see OP_ADDF + emit(LDRxiw(R0, rOPSTACK, 4)); // opstack-=4; r1 = *opstack + emit(VMOVass(S15,R0)); // s15 = r0 + emit(VMUL_F32(S14, S15, S14)); // s14 = s14 * s15 + emit(VSTRa(S14, rOPSTACK, 0)); // *((float*)opstack) = s15 + break; + + case OP_CVIF: + MAYBE_EMIT_CONST(); + emit(LDRai(R0, rOPSTACK, 0)); // r0 = *opstack + emit(VMOVass(S14,R0)); // s14 = r0 + emit(VCVT_F32_S32(S14, S14)); // s15 = (float)s14 + emit(VSTRa(S14, rOPSTACK, 0)); // *((float*)opstack) = s15 + break; + + case OP_CVFI: + MAYBE_EMIT_CONST(); + emit(VLDRa(S14, rOPSTACK, 0)); // s14 = *((float*)opstack) + emit(VCVT_S32_F32(S14, S14)); // s15 = (int)s14 + emit(VMOVssa(R0,S14)); // s14 = r0 + emit(STRai(R0, rOPSTACK, 0)); // *opstack = r0 + break; + } + } + + // never reached + emit(BKPT(0)); + } // pass + + if (mprotect(vm->codeBase, vm->codeLength, PROT_READ|PROT_EXEC/* |PROT_WRITE */)) { + VM_Destroy_Compiled(vm); + DIE("mprotect failed"); + } + + // clear icache, http://blogs.arm.com/software-enablement/141-caches-and-self-modifying-code/ + __clear_cache(vm->codeBase, vm->codeBase+vm->codeLength); + + vm->destroy = VM_Destroy_Compiled; + vm->compiled = qtrue; +} + +int VM_CallCompiled(vm_t *vm, int *args) +{ + byte stack[OPSTACK_SIZE + 15]; + int *opStack; + int programStack = vm->programStack; + int stackOnEntry = programStack; + byte *image = vm->dataBase; + int *argPointer; + int retVal; + + currentVM = vm; + + vm->currentlyInterpreting = qtrue; + + programStack -= ( 8 + 4 * MAX_VMMAIN_ARGS ); + argPointer = (int *)&image[ programStack + 8 ]; + memcpy( argPointer, args, 4 * MAX_VMMAIN_ARGS ); + argPointer[-1] = 0; + argPointer[-2] = -1; + + + opStack = PADP(stack, 16); + *opStack = 0xDEADBEEF; + +#if 0 + Com_Printf("r5 opStack:\t\t%p\n", opStack); + Com_Printf("r7 codeBase:\t\t%p\n", vm->codeBase); + Com_Printf("r8 programStack:\t0x%x\n", programStack); + Com_Printf("r9 dataBase:\t\t%p\n", vm->dataBase); +#endif + + /* call generated code */ + { + //int (*entry)(void *, int, void *, int); + int (*entry)(vm_t*, int*, int*); + + entry = (void *)(vm->codeBase); + //__asm__ volatile("bkpt"); + //retVal = entry(vm->codeBase, programStack, vm->dataBase, vm->dataMask); + retVal = entry(vm, &programStack, opStack); + } + + if(*opStack != 0xDEADBEEF) + { + Com_Error(ERR_DROP, "opStack corrupted in compiled code"); + } + + if(programStack != stackOnEntry - (8 + 4 * MAX_VMMAIN_ARGS)) + Com_Error(ERR_DROP, "programStack corrupted in compiled code"); + + vm->programStack = stackOnEntry; + vm->currentlyInterpreting = qfalse; + + return retVal; +} diff --git a/code/qcommon/vm_interpreted.c b/code/qcommon/vm_interpreted.c index aa45fde6..cb86a08d 100644 --- a/code/qcommon/vm_interpreted.c +++ b/code/qcommon/vm_interpreted.c @@ -317,8 +317,8 @@ locals from sp int VM_CallInterpreted( vm_t *vm, int *args ) { byte stack[OPSTACK_SIZE + 15]; - register int *opStack; - register uint8_t opStackOfs; + int *opStack; + uint8_t opStackOfs; int programCounter; int programStack; int stackOnEntry; @@ -436,31 +436,31 @@ nextInstruction2: return 0; } #endif - r0 = opStack[opStackOfs] = *(int *) &image[r0 & dataMask & ~3 ]; + r0 = opStack[opStackOfs] = *(int *) &image[ r0 & dataMask ]; goto nextInstruction2; case OP_LOAD2: - r0 = opStack[opStackOfs] = *(unsigned short *)&image[ r0&dataMask&~1 ]; + r0 = opStack[opStackOfs] = *(unsigned short *)&image[ r0 & dataMask ]; goto nextInstruction2; case OP_LOAD1: - r0 = opStack[opStackOfs] = image[ r0&dataMask ]; + r0 = opStack[opStackOfs] = image[ r0 & dataMask ]; goto nextInstruction2; case OP_STORE4: - *(int *)&image[ r1&(dataMask & ~3) ] = r0; + *(int *)&image[ r1 & dataMask ] = r0; opStackOfs -= 2; goto nextInstruction; case OP_STORE2: - *(short *)&image[ r1&(dataMask & ~1) ] = r0; + *(short *)&image[ r1 & dataMask ] = r0; opStackOfs -= 2; goto nextInstruction; case OP_STORE1: - image[ r1&dataMask ] = r0; + image[ r1 & dataMask ] = r0; opStackOfs -= 2; goto nextInstruction; case OP_ARG: // single byte offset from programStack - *(int *)&image[ (codeImage[programCounter] + programStack)&dataMask&~3 ] = r0; + *(int *)&image[ (codeImage[programCounter] + programStack) & dataMask ] = r0; opStackOfs--; programCounter += 1; goto nextInstruction; diff --git a/code/qcommon/vm_local.h b/code/qcommon/vm_local.h index 76b1a4b1..07e89675 100644 --- a/code/qcommon/vm_local.h +++ b/code/qcommon/vm_local.h @@ -170,6 +170,7 @@ struct vm_s { byte *dataBase; int dataMask; + int dataAlloc; // actually allocated int stackBottom; // if programStack < stackBottom, error diff --git a/code/qcommon/vm_powerpc.c b/code/qcommon/vm_powerpc.c index 3d9ede65..75e10aaa 100644 --- a/code/qcommon/vm_powerpc.c +++ b/code/qcommon/vm_powerpc.c @@ -401,7 +401,7 @@ struct symbolic_jump { // extensions / modifiers (branch-link) unsigned long ext; - // dest_instruction refering to this jump + // dest_instruction referring to this jump dest_instruction_t *parent; // next jump @@ -656,7 +656,7 @@ PPC_MakeFastMask( int mask ) * function local registers, * * normally only volatile registers are used, but if there aren't enough - * or function has to preserve some value while calling annother one + * or function has to preserve some value while calling another one * then caller safe registers are used as well */ static const long int gpr_list[] = { diff --git a/code/qcommon/vm_x86.c b/code/qcommon/vm_x86.c index 9ee26799..6bf349f2 100644 --- a/code/qcommon/vm_x86.c +++ b/code/qcommon/vm_x86.c @@ -103,7 +103,7 @@ static int isu8(uint32_t v) static int NextConstant4(void) { - return (code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24)); + return ((unsigned int)code[pc] | ((unsigned int)code[pc+1]<<8) | ((unsigned int)code[pc+2]<<16) | ((unsigned int)code[pc+3]<<24)); } static int Constant4( void ) { @@ -790,7 +790,7 @@ qboolean ConstOptimize(vm_t *vm, int callProcOfsSyscall) return qtrue; case OP_STORE4: - EmitMovEAXStack(vm, (vm->dataMask & ~3)); + EmitMovEAXStack(vm, vm->dataMask); #if idx64 EmitRexString(0x41, "C7 04 01"); // mov dword ptr [r9 + eax], 0x12345678 Emit4(Constant4()); @@ -805,7 +805,7 @@ qboolean ConstOptimize(vm_t *vm, int callProcOfsSyscall) return qtrue; case OP_STORE2: - EmitMovEAXStack(vm, (vm->dataMask & ~1)); + EmitMovEAXStack(vm, vm->dataMask); #if idx64 Emit1(0x66); // mov word ptr [r9 + eax], 0x1234 EmitRexString(0x41, "C7 04 01"); @@ -1377,7 +1377,7 @@ void VM_Compile(vm_t *vm, vmHeader_t *header) case OP_STORE4: EmitMovEAXStack(vm, 0); EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4] - MASK_REG("E2", vm->dataMask & ~3); // and edx, 0x12345678 + MASK_REG("E2", vm->dataMask); // and edx, 0x12345678 #if idx64 EmitRexString(0x41, "89 04 11"); // mov dword ptr [r9 + edx], eax #else @@ -1389,7 +1389,7 @@ void VM_Compile(vm_t *vm, vmHeader_t *header) case OP_STORE2: EmitMovEAXStack(vm, 0); EmitString("8B 54 9F FC"); // mov edx, dword ptr -4[edi + ebx * 4] - MASK_REG("E2", vm->dataMask & ~1); // and edx, 0x12345678 + MASK_REG("E2", vm->dataMask); // and edx, 0x12345678 #if idx64 Emit1(0x66); // mov word ptr [r9 + edx], eax EmitRexString(0x41, "89 04 11"); diff --git a/code/renderercommon/qgl.h b/code/renderercommon/qgl.h index 971684fb..38f9919f 100644 --- a/code/renderercommon/qgl.h +++ b/code/renderercommon/qgl.h @@ -42,437 +42,152 @@ extern void (APIENTRYP qglUnlockArraysEXT) (void); //=========================================================================== -#define qglAccum glAccum -#define qglAlphaFunc glAlphaFunc -#define qglAreTexturesResident glAreTexturesResident -#define qglArrayElement glArrayElement -#define qglBegin glBegin -#define qglBindTexture glBindTexture -#define qglBitmap glBitmap -#define qglBlendFunc glBlendFunc -#define qglCallList glCallList -#define qglCallLists glCallLists -#define qglClear glClear -#define qglClearAccum glClearAccum -#define qglClearColor glClearColor -#define qglClearDepth glClearDepth -#define qglClearIndex glClearIndex -#define qglClearStencil glClearStencil -#define qglClipPlane glClipPlane -#define qglColor3b glColor3b -#define qglColor3bv glColor3bv -#define qglColor3d glColor3d -#define qglColor3dv glColor3dv -#define qglColor3f glColor3f -#define qglColor3fv glColor3fv -#define qglColor3i glColor3i -#define qglColor3iv glColor3iv -#define qglColor3s glColor3s -#define qglColor3sv glColor3sv -#define qglColor3ub glColor3ub -#define qglColor3ubv glColor3ubv -#define qglColor3ui glColor3ui -#define qglColor3uiv glColor3uiv -#define qglColor3us glColor3us -#define qglColor3usv glColor3usv -#define qglColor4b glColor4b -#define qglColor4bv glColor4bv -#define qglColor4d glColor4d -#define qglColor4dv glColor4dv -#define qglColor4f glColor4f -#define qglColor4fv glColor4fv -#define qglColor4i glColor4i -#define qglColor4iv glColor4iv -#define qglColor4s glColor4s -#define qglColor4sv glColor4sv -#define qglColor4ub glColor4ub -#define qglColor4ubv glColor4ubv -#define qglColor4ui glColor4ui -#define qglColor4uiv glColor4uiv -#define qglColor4us glColor4us -#define qglColor4usv glColor4usv -#define qglColorMask glColorMask -#define qglColorMaterial glColorMaterial -#define qglColorPointer glColorPointer -#define qglCopyPixels glCopyPixels -#define qglCopyTexImage1D glCopyTexImage1D -#define qglCopyTexImage2D glCopyTexImage2D -#define qglCopyTexSubImage1D glCopyTexSubImage1D -#define qglCopyTexSubImage2D glCopyTexSubImage2D -#define qglCullFace glCullFace -#define qglDeleteLists glDeleteLists -#define qglDeleteTextures glDeleteTextures -#define qglDepthFunc glDepthFunc -#define qglDepthMask glDepthMask -#define qglDepthRange glDepthRange -#define qglDisable glDisable -#define qglDisableClientState glDisableClientState -#define qglDrawArrays glDrawArrays -#define qglDrawBuffer glDrawBuffer -#define qglDrawElements glDrawElements -#define qglDrawPixels glDrawPixels -#define qglEdgeFlag glEdgeFlag -#define qglEdgeFlagPointer glEdgeFlagPointer -#define qglEdgeFlagv glEdgeFlagv -#define qglEnable glEnable -#define qglEnableClientState glEnableClientState -#define qglEnd glEnd -#define qglEndList glEndList -#define qglEvalCoord1d glEvalCoord1d -#define qglEvalCoord1dv glEvalCoord1dv -#define qglEvalCoord1f glEvalCoord1f -#define qglEvalCoord1fv glEvalCoord1fv -#define qglEvalCoord2d glEvalCoord2d -#define qglEvalCoord2dv glEvalCoord2dv -#define qglEvalCoord2f glEvalCoord2f -#define qglEvalCoord2fv glEvalCoord2fv -#define qglEvalMesh1 glEvalMesh1 -#define qglEvalMesh2 glEvalMesh2 -#define qglEvalPoint1 glEvalPoint1 -#define qglEvalPoint2 glEvalPoint2 -#define qglFeedbackBuffer glFeedbackBuffer -#define qglFinish glFinish -#define qglFlush glFlush -#define qglFogf glFogf -#define qglFogfv glFogfv -#define qglFogi glFogi -#define qglFogiv glFogiv -#define qglFrontFace glFrontFace -#define qglFrustum glFrustum -#define qglGenLists glGenLists -#define qglGenTextures glGenTextures -#define qglGetBooleanv glGetBooleanv -#define qglGetClipPlane glGetClipPlane -#define qglGetDoublev glGetDoublev -#define qglGetError glGetError -#define qglGetFloatv glGetFloatv -#define qglGetIntegerv glGetIntegerv -#define qglGetLightfv glGetLightfv -#define qglGetLightiv glGetLightiv -#define qglGetMapdv glGetMapdv -#define qglGetMapfv glGetMapfv -#define qglGetMapiv glGetMapiv -#define qglGetMaterialfv glGetMaterialfv -#define qglGetMaterialiv glGetMaterialiv -#define qglGetPixelMapfv glGetPixelMapfv -#define qglGetPixelMapuiv glGetPixelMapuiv -#define qglGetPixelMapusv glGetPixelMapusv -#define qglGetPointerv glGetPointerv -#define qglGetPolygonStipple glGetPolygonStipple -#define qglGetString glGetString -#define qglGetTexGendv glGetTexGendv -#define qglGetTexGenfv glGetTexGenfv -#define qglGetTexGeniv glGetTexGeniv -#define qglGetTexImage glGetTexImage -#define qglGetTexLevelParameterfv glGetTexLevelParameterfv -#define qglGetTexLevelParameteriv glGetTexLevelParameteriv -#define qglGetTexParameterfv glGetTexParameterfv -#define qglGetTexParameteriv glGetTexParameteriv -#define qglHint glHint -#define qglIndexMask glIndexMask -#define qglIndexPointer glIndexPointer -#define qglIndexd glIndexd -#define qglIndexdv glIndexdv -#define qglIndexf glIndexf -#define qglIndexfv glIndexfv -#define qglIndexi glIndexi -#define qglIndexiv glIndexiv -#define qglIndexs glIndexs -#define qglIndexsv glIndexsv -#define qglIndexub glIndexub -#define qglIndexubv glIndexubv -#define qglInitNames glInitNames -#define qglInterleavedArrays glInterleavedArrays -#define qglIsEnabled glIsEnabled -#define qglIsList glIsList -#define qglIsTexture glIsTexture -#define qglLightModelf glLightModelf -#define qglLightModelfv glLightModelfv -#define qglLightModeli glLightModeli -#define qglLightModeliv glLightModeliv -#define qglLightf glLightf -#define qglLightfv glLightfv -#define qglLighti glLighti -#define qglLightiv glLightiv -#define qglLineStipple glLineStipple -#define qglLineWidth glLineWidth -#define qglListBase glListBase -#define qglLoadIdentity glLoadIdentity -#define qglLoadMatrixd glLoadMatrixd -#define qglLoadMatrixf glLoadMatrixf -#define qglLoadName glLoadName -#define qglLogicOp glLogicOp -#define qglMap1d glMap1d -#define qglMap1f glMap1f -#define qglMap2d glMap2d -#define qglMap2f glMap2f -#define qglMapGrid1d glMapGrid1d -#define qglMapGrid1f glMapGrid1f -#define qglMapGrid2d glMapGrid2d -#define qglMapGrid2f glMapGrid2f -#define qglMaterialf glMaterialf -#define qglMaterialfv glMaterialfv -#define qglMateriali glMateriali -#define qglMaterialiv glMaterialiv -#define qglMatrixMode glMatrixMode -#define qglMultMatrixd glMultMatrixd -#define qglMultMatrixf glMultMatrixf -#define qglNewList glNewList -#define qglNormal3b glNormal3b -#define qglNormal3bv glNormal3bv -#define qglNormal3d glNormal3d -#define qglNormal3dv glNormal3dv -#define qglNormal3f glNormal3f -#define qglNormal3fv glNormal3fv -#define qglNormal3i glNormal3i -#define qglNormal3iv glNormal3iv -#define qglNormal3s glNormal3s -#define qglNormal3sv glNormal3sv -#define qglNormalPointer glNormalPointer -#define qglOrtho glOrtho -#define qglPassThrough glPassThrough -#define qglPixelMapfv glPixelMapfv -#define qglPixelMapuiv glPixelMapuiv -#define qglPixelMapusv glPixelMapusv -#define qglPixelStoref glPixelStoref -#define qglPixelStorei glPixelStorei -#define qglPixelTransferf glPixelTransferf -#define qglPixelTransferi glPixelTransferi -#define qglPixelZoom glPixelZoom -#define qglPointSize glPointSize -#define qglPolygonMode glPolygonMode -#define qglPolygonOffset glPolygonOffset -#define qglPolygonStipple glPolygonStipple -#define qglPopAttrib glPopAttrib -#define qglPopClientAttrib glPopClientAttrib -#define qglPopMatrix glPopMatrix -#define qglPopName glPopName -#define qglPrioritizeTextures glPrioritizeTextures -#define qglPushAttrib glPushAttrib -#define qglPushClientAttrib glPushClientAttrib -#define qglPushMatrix glPushMatrix -#define qglPushName glPushName -#define qglRasterPos2d glRasterPos2d -#define qglRasterPos2dv glRasterPos2dv -#define qglRasterPos2f glRasterPos2f -#define qglRasterPos2fv glRasterPos2fv -#define qglRasterPos2i glRasterPos2i -#define qglRasterPos2iv glRasterPos2iv -#define qglRasterPos2s glRasterPos2s -#define qglRasterPos2sv glRasterPos2sv -#define qglRasterPos3d glRasterPos3d -#define qglRasterPos3dv glRasterPos3dv -#define qglRasterPos3f glRasterPos3f -#define qglRasterPos3fv glRasterPos3fv -#define qglRasterPos3i glRasterPos3i -#define qglRasterPos3iv glRasterPos3iv -#define qglRasterPos3s glRasterPos3s -#define qglRasterPos3sv glRasterPos3sv -#define qglRasterPos4d glRasterPos4d -#define qglRasterPos4dv glRasterPos4dv -#define qglRasterPos4f glRasterPos4f -#define qglRasterPos4fv glRasterPos4fv -#define qglRasterPos4i glRasterPos4i -#define qglRasterPos4iv glRasterPos4iv -#define qglRasterPos4s glRasterPos4s -#define qglRasterPos4sv glRasterPos4sv -#define qglReadBuffer glReadBuffer -#define qglReadPixels glReadPixels -#define qglRectd glRectd -#define qglRectdv glRectdv -#define qglRectf glRectf -#define qglRectfv glRectfv -#define qglRecti glRecti -#define qglRectiv glRectiv -#define qglRects glRects -#define qglRectsv glRectsv -#define qglRenderMode glRenderMode -#define qglRotated glRotated -#define qglRotatef glRotatef -#define qglScaled glScaled -#define qglScalef glScalef -#define qglScissor glScissor -#define qglSelectBuffer glSelectBuffer -#define qglShadeModel glShadeModel -#define qglStencilFunc glStencilFunc -#define qglStencilMask glStencilMask -#define qglStencilOp glStencilOp -#define qglTexCoord1d glTexCoord1d -#define qglTexCoord1dv glTexCoord1dv -#define qglTexCoord1f glTexCoord1f -#define qglTexCoord1fv glTexCoord1fv -#define qglTexCoord1i glTexCoord1i -#define qglTexCoord1iv glTexCoord1iv -#define qglTexCoord1s glTexCoord1s -#define qglTexCoord1sv glTexCoord1sv -#define qglTexCoord2d glTexCoord2d -#define qglTexCoord2dv glTexCoord2dv -#define qglTexCoord2f glTexCoord2f -#define qglTexCoord2fv glTexCoord2fv -#define qglTexCoord2i glTexCoord2i -#define qglTexCoord2iv glTexCoord2iv -#define qglTexCoord2s glTexCoord2s -#define qglTexCoord2sv glTexCoord2sv -#define qglTexCoord3d glTexCoord3d -#define qglTexCoord3dv glTexCoord3dv -#define qglTexCoord3f glTexCoord3f -#define qglTexCoord3fv glTexCoord3fv -#define qglTexCoord3i glTexCoord3i -#define qglTexCoord3iv glTexCoord3iv -#define qglTexCoord3s glTexCoord3s -#define qglTexCoord3sv glTexCoord3sv -#define qglTexCoord4d glTexCoord4d -#define qglTexCoord4dv glTexCoord4dv -#define qglTexCoord4f glTexCoord4f -#define qglTexCoord4fv glTexCoord4fv -#define qglTexCoord4i glTexCoord4i -#define qglTexCoord4iv glTexCoord4iv -#define qglTexCoord4s glTexCoord4s -#define qglTexCoord4sv glTexCoord4sv -#define qglTexCoordPointer glTexCoordPointer -#define qglTexEnvf glTexEnvf -#define qglTexEnvfv glTexEnvfv -#define qglTexEnvi glTexEnvi -#define qglTexEnviv glTexEnviv -#define qglTexGend glTexGend -#define qglTexGendv glTexGendv -#define qglTexGenf glTexGenf -#define qglTexGenfv glTexGenfv -#define qglTexGeni glTexGeni -#define qglTexGeniv glTexGeniv -#define qglTexImage1D glTexImage1D -#define qglTexImage2D glTexImage2D -#define qglTexParameterf glTexParameterf -#define qglTexParameterfv glTexParameterfv -#define qglTexParameteri glTexParameteri -#define qglTexParameteriv glTexParameteriv -#define qglTexSubImage1D glTexSubImage1D -#define qglTexSubImage2D glTexSubImage2D -#define qglTranslated glTranslated -#define qglTranslatef glTranslatef -#define qglVertex2d glVertex2d -#define qglVertex2dv glVertex2dv -#define qglVertex2f glVertex2f -#define qglVertex2fv glVertex2fv -#define qglVertex2i glVertex2i -#define qglVertex2iv glVertex2iv -#define qglVertex2s glVertex2s -#define qglVertex2sv glVertex2sv -#define qglVertex3d glVertex3d -#define qglVertex3dv glVertex3dv -#define qglVertex3f glVertex3f -#define qglVertex3fv glVertex3fv -#define qglVertex3i glVertex3i -#define qglVertex3iv glVertex3iv -#define qglVertex3s glVertex3s -#define qglVertex3sv glVertex3sv -#define qglVertex4d glVertex4d -#define qglVertex4dv glVertex4dv -#define qglVertex4f glVertex4f -#define qglVertex4fv glVertex4fv -#define qglVertex4i glVertex4i -#define qglVertex4iv glVertex4iv -#define qglVertex4s glVertex4s -#define qglVertex4sv glVertex4sv -#define qglVertexPointer glVertexPointer -#define qglViewport glViewport +// GL function loader, based on https://gist.github.com/rygorous/16796a0c876cf8a5f542caddb55bce8a +// get missing functions from code/SDL2/include/SDL_opengl.h -// GL_EXT_draw_range_elements -extern void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); +// OpenGL 1.0/1.1, OpenGL ES 1.0, and OpenGL 3.2 core profile +#define QGL_1_1_PROCS \ + GLE(void, BindTexture, GLenum target, GLuint texture) \ + GLE(void, BlendFunc, GLenum sfactor, GLenum dfactor) \ + GLE(void, ClearColor, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) \ + GLE(void, Clear, GLbitfield mask) \ + GLE(void, ClearStencil, GLint s) \ + GLE(void, ColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) \ + GLE(void, CopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) \ + GLE(void, CullFace, GLenum mode) \ + GLE(void, DeleteTextures, GLsizei n, const GLuint *textures) \ + GLE(void, DepthFunc, GLenum func) \ + GLE(void, DepthMask, GLboolean flag) \ + GLE(void, Disable, GLenum cap) \ + GLE(void, DrawArrays, GLenum mode, GLint first, GLsizei count) \ + GLE(void, DrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) \ + GLE(void, Enable, GLenum cap) \ + GLE(void, Finish, void) \ + GLE(void, Flush, void) \ + GLE(void, GenTextures, GLsizei n, GLuint *textures ) \ + GLE(void, GetBooleanv, GLenum pname, GLboolean *params) \ + GLE(GLenum, GetError, void) \ + GLE(void, GetIntegerv, GLenum pname, GLint *params) \ + GLE(const GLubyte *, GetString, GLenum name) \ + GLE(void, LineWidth, GLfloat width) \ + GLE(void, PolygonOffset, GLfloat factor, GLfloat units) \ + GLE(void, ReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) \ + GLE(void, Scissor, GLint x, GLint y, GLsizei width, GLsizei height) \ + GLE(void, StencilFunc, GLenum func, GLint ref, GLuint mask) \ + GLE(void, StencilMask, GLuint mask) \ + GLE(void, StencilOp, GLenum fail, GLenum zfail, GLenum zpass) \ + GLE(void, TexImage2D, GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) \ + GLE(void, TexParameterf, GLenum target, GLenum pname, GLfloat param) \ + GLE(void, TexParameteri, GLenum target, GLenum pname, GLint param) \ + GLE(void, TexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) \ + GLE(void, Translatef, GLfloat x, GLfloat y, GLfloat z) \ + GLE(void, Viewport, GLint x, GLint y, GLsizei width, GLsizei height) \ -// GL_EXT_multi_draw_arrays -extern void (APIENTRY * qglMultiDrawArraysEXT) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -extern void (APIENTRY * qglMultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); +// OpenGL 1.0/1.1 and OpenGL ES 1.x but not OpenGL 3.2 core profile +#define QGL_1_1_FIXED_FUNCTION_PROCS \ + GLE(void, AlphaFunc, GLenum func, GLclampf ref) \ + GLE(void, Color4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) \ + GLE(void, ColorPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) \ + GLE(void, DisableClientState, GLenum cap) \ + GLE(void, EnableClientState, GLenum cap) \ + GLE(void, LoadIdentity, void) \ + GLE(void, LoadMatrixf, const GLfloat *m) \ + GLE(void, MatrixMode, GLenum mode) \ + GLE(void, PopMatrix, void) \ + GLE(void, PushMatrix, void) \ + GLE(void, ShadeModel, GLenum mode) \ + GLE(void, TexCoordPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) \ + GLE(void, TexEnvf, GLenum target, GLenum pname, GLfloat param) \ + GLE(void, VertexPointer, GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) \ -// GL_ARB_shading_language_100 -#ifndef GL_ARB_shading_language_100 -#define GL_ARB_shading_language_100 -#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C -#endif +// OpenGL 1.0/1.1 and 3.2 core profile but not OpenGL ES 1.x +#define QGL_DESKTOP_1_1_PROCS \ + GLE(void, ClearDepth, GLclampd depth) \ + GLE(void, DepthRange, GLclampd near_val, GLclampd far_val) \ + GLE(void, DrawBuffer, GLenum mode) \ + GLE(void, PolygonMode, GLenum face, GLenum mode) \ -// GL_ARB_vertex_program -extern void (APIENTRY * qglVertexAttrib4fARB) (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); -extern void (APIENTRY * qglVertexAttrib4fvARB) (GLuint, const GLfloat *); -extern void (APIENTRY * qglVertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized, - GLsizei stride, const GLvoid * pointer); -extern void (APIENTRY * qglEnableVertexAttribArrayARB) (GLuint index); -extern void (APIENTRY * qglDisableVertexAttribArrayARB) (GLuint index); +// OpenGL 1.0/1.1 but not OpenGL 3.2 core profile or OpenGL ES 1.x +#define QGL_DESKTOP_1_1_FIXED_FUNCTION_PROCS \ + GLE(void, ArrayElement, GLint i) \ + GLE(void, Begin, GLenum mode) \ + GLE(void, ClipPlane, GLenum plane, const GLdouble *equation) \ + GLE(void, Color3f, GLfloat red, GLfloat green, GLfloat blue) \ + GLE(void, Color4ubv, const GLubyte *v) \ + GLE(void, End, void) \ + GLE(void, Frustum, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val) \ + GLE(void, Ortho, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val) \ + GLE(void, TexCoord2f, GLfloat s, GLfloat t) \ + GLE(void, TexCoord2fv, const GLfloat *v) \ + GLE(void, Vertex2f, GLfloat x, GLfloat y) \ + GLE(void, Vertex3f, GLfloat x, GLfloat y, GLfloat z) \ + GLE(void, Vertex3fv, const GLfloat *v) \ -// GL_ARB_vertex_buffer_object -extern void (APIENTRY * qglBindBufferARB) (GLenum target, GLuint buffer); -extern void (APIENTRY * qglDeleteBuffersARB) (GLsizei n, const GLuint * buffers); -extern void (APIENTRY * qglGenBuffersARB) (GLsizei n, GLuint * buffers); -extern GLboolean(APIENTRY * qglIsBufferARB) (GLuint buffer); -extern void (APIENTRY * qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage); -extern void (APIENTRY * qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data); -extern void (APIENTRY * qglGetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid * data); -extern void (APIENTRY * qglGetBufferParameterivARB) (GLenum target, GLenum pname, GLint * params); -extern void (APIENTRY * qglGetBufferPointervARB) (GLenum target, GLenum pname, GLvoid * *params); +// OpenGL ES 1.1 and OpenGL ES 2.0 but not desktop OpenGL 1.x +#define QGL_ES_1_1_PROCS \ + GLE(void, ClearDepthf, GLclampf depth) \ + GLE(void, DepthRangef, GLclampf near_val, GLclampf far_val) \ -// GL_ARB_shader_objects -extern void (APIENTRY * qglDeleteObjectARB) (GLhandleARB obj); -extern GLhandleARB(APIENTRY * qglGetHandleARB) (GLenum pname); -extern void (APIENTRY * qglDetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj); -extern GLhandleARB(APIENTRY * qglCreateShaderObjectARB) (GLenum shaderType); -extern void (APIENTRY * qglShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB * *string, - const GLint * length); -extern void (APIENTRY * qglCompileShaderARB) (GLhandleARB shaderObj); -extern GLhandleARB(APIENTRY * qglCreateProgramObjectARB) (void); -extern void (APIENTRY * qglAttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj); -extern void (APIENTRY * qglLinkProgramARB) (GLhandleARB programObj); -extern void (APIENTRY * qglUseProgramObjectARB) (GLhandleARB programObj); -extern void (APIENTRY * qglValidateProgramARB) (GLhandleARB programObj); -extern void (APIENTRY * qglUniform1fARB) (GLint location, GLfloat v0); -extern void (APIENTRY * qglUniform2fARB) (GLint location, GLfloat v0, GLfloat v1); -extern void (APIENTRY * qglUniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -extern void (APIENTRY * qglUniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -extern void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0); -extern void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1); -extern void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); -extern void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -extern void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value); -extern void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value); -extern void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value); -extern void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value); -extern void (APIENTRY * qglUniform2ivARB) (GLint location, GLsizei count, const GLint * value); -extern void (APIENTRY * qglUniform3ivARB) (GLint location, GLsizei count, const GLint * value); -extern void (APIENTRY * qglUniform4ivARB) (GLint location, GLsizei count, const GLint * value); -extern void (APIENTRY * qglUniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -extern void (APIENTRY * qglUniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -extern void (APIENTRY * qglUniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -extern void (APIENTRY * qglGetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat * params); -extern void (APIENTRY * qglGetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint * params); -extern void (APIENTRY * qglGetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog); -extern void (APIENTRY * qglGetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, - GLhandleARB * obj); -extern GLint(APIENTRY * qglGetUniformLocationARB) (GLhandleARB programObj, const GLcharARB * name); -extern void (APIENTRY * qglGetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxIndex, GLsizei * length, - GLint * size, GLenum * type, GLcharARB * name); -extern void (APIENTRY * qglGetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat * params); -extern void (APIENTRY * qglGetUniformivARB) (GLhandleARB programObj, GLint location, GLint * params); -extern void (APIENTRY * qglGetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source); +// OpenGL ES 1.1 but not OpenGL ES 2.0 or desktop OpenGL 1.x +#define QGL_ES_1_1_FIXED_FUNCTION_PROCS \ + GLE(void, ClipPlanef, GLenum plane, const GLfloat *equation) \ + GLE(void, Frustumf, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near_val, GLfloat far_val) \ + GLE(void, Orthof, GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near_val, GLfloat far_val) \ -// GL_ARB_vertex_shader -extern void (APIENTRY * qglBindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB * name); -extern void (APIENTRY * qglGetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length, - GLint * size, GLenum * type, GLcharARB * name); -extern GLint(APIENTRY * qglGetAttribLocationARB) (GLhandleARB programObj, const GLcharARB * name); +// OpenGL 1.3, was GL_ARB_texture_compression +#define QGL_1_3_PROCS \ + GLE(void, ActiveTexture, GLenum texture) \ + GLE(void, CompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) \ + GLE(void, CompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) \ -// GL_ARB_texture_compression -extern void (APIENTRY * qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, - GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -extern void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, - GLint border, GLsizei imageSize, const GLvoid *data); -extern void (APIENTRY * qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, - GLsizei imageSize, const GLvoid *data); -extern void (APIENTRY * qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -extern void (APIENTRY * qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, - GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -extern void (APIENTRY * qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, - GLsizei imageSize, const GLvoid *data); -extern void (APIENTRY * qglGetCompressedTexImageARB)(GLenum target, GLint lod, - GLvoid *img); +// GL_ARB_occlusion_query, built-in to OpenGL 1.5 but not OpenGL ES 2.0 +#define QGL_ARB_occlusion_query_PROCS \ + GLE(void, GenQueries, GLsizei n, GLuint *ids) \ + GLE(void, DeleteQueries, GLsizei n, const GLuint *ids) \ + GLE(void, BeginQuery, GLenum target, GLuint id) \ + GLE(void, EndQuery, GLenum target) \ + GLE(void, GetQueryObjectiv, GLuint id, GLenum pname, GLint *params) \ + GLE(void, GetQueryObjectuiv, GLuint id, GLenum pname, GLuint *params) \ + +// OpenGL 1.5, was GL_ARB_vertex_buffer_object +#define QGL_1_5_PROCS \ + GLE(void, BindBuffer, GLenum target, GLuint buffer) \ + GLE(void, DeleteBuffers, GLsizei n, const GLuint *buffers) \ + GLE(void, GenBuffers, GLsizei n, GLuint *buffers) \ + GLE(void, BufferData, GLenum target, GLsizeiptr size, const void *data, GLenum usage) \ + GLE(void, BufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void *data) \ + +// OpenGL 2.0, was GL_ARB_shading_language_100, GL_ARB_vertex_program, GL_ARB_shader_objects, and GL_ARB_vertex_shader +#define QGL_2_0_PROCS \ + GLE(void, AttachShader, GLuint program, GLuint shader) \ + GLE(void, BindAttribLocation, GLuint program, GLuint index, const GLchar *name) \ + GLE(void, CompileShader, GLuint shader) \ + GLE(GLuint, CreateProgram, void) \ + GLE(GLuint, CreateShader, GLenum type) \ + GLE(void, DeleteProgram, GLuint program) \ + GLE(void, DeleteShader, GLuint shader) \ + GLE(void, DetachShader, GLuint program, GLuint shader) \ + GLE(void, DisableVertexAttribArray, GLuint index) \ + GLE(void, EnableVertexAttribArray, GLuint index) \ + GLE(void, GetActiveUniform, GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) \ + GLE(void, GetProgramiv, GLuint program, GLenum pname, GLint *params) \ + GLE(void, GetProgramInfoLog, GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) \ + GLE(void, GetShaderiv, GLuint shader, GLenum pname, GLint *params) \ + GLE(void, GetShaderInfoLog, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) \ + GLE(void, GetShaderSource, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) \ + GLE(GLint, GetUniformLocation, GLuint program, const GLchar *name) \ + GLE(void, LinkProgram, GLuint program) \ + GLE(void, ShaderSource, GLuint shader, GLsizei count, const GLchar* *string, const GLint *length) \ + GLE(void, UseProgram, GLuint program) \ + GLE(void, Uniform1f, GLint location, GLfloat v0) \ + GLE(void, Uniform2f, GLint location, GLfloat v0, GLfloat v1) \ + GLE(void, Uniform3f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) \ + GLE(void, Uniform4f, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) \ + GLE(void, Uniform1i, GLint location, GLint v0) \ + GLE(void, Uniform1fv, GLint location, GLsizei count, const GLfloat *value) \ + GLE(void, UniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) \ + GLE(void, ValidateProgram, GLuint program) \ + GLE(void, VertexAttribPointer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) \ // GL_NVX_gpu_memory_info #ifndef GL_NVX_gpu_memory_info @@ -522,160 +237,31 @@ extern void (APIENTRY * qglGetCompressedTexImageARB)(GLenum target, GLint lod, #define GL_HALF_FLOAT_ARB 0x140B #endif -// GL_EXT_framebuffer_object -extern GLboolean (APIENTRY * qglIsRenderbufferEXT)(GLuint renderbuffer); -extern void (APIENTRY * qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer); -extern void (APIENTRY * qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers); -extern void (APIENTRY * qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers); -extern void (APIENTRY * qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); -extern void (APIENTRY * qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params); -extern GLboolean (APIENTRY * qglIsFramebufferEXT)(GLuint framebuffer); -extern void (APIENTRY * qglBindFramebufferEXT)(GLenum target, GLuint framebuffer); -extern void (APIENTRY * qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers); -extern void (APIENTRY * qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers); -extern GLenum (APIENTRY * qglCheckFramebufferStatusEXT)(GLenum target); -extern void (APIENTRY * qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level); -extern void (APIENTRY * qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level); -extern void (APIENTRY * qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level, GLint zoffset); -extern void (APIENTRY * qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget, - GLuint renderbuffer); -extern void (APIENTRY * qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params); -extern void (APIENTRY * qglGenerateMipmapEXT)(GLenum target); +// OpenGL 3.0 specific +#define QGL_3_0_PROCS \ + GLE(const GLubyte *, GetStringi, GLenum name, GLuint index) \ -#ifndef GL_EXT_framebuffer_object -#define GL_EXT_framebuffer_object -#define GL_FRAMEBUFFER_EXT 0x8D40 -#define GL_RENDERBUFFER_EXT 0x8D41 -#define GL_STENCIL_INDEX1_EXT 0x8D46 -#define GL_STENCIL_INDEX4_EXT 0x8D47 -#define GL_STENCIL_INDEX8_EXT 0x8D48 -#define GL_STENCIL_INDEX16_EXT 0x8D49 -#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42 -#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43 -#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44 -#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 -#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51 -#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52 -#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53 -#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54 -#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0 -#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3 -#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4 -#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0 -#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1 -#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2 -#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3 -#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4 -#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5 -#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6 -#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7 -#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8 -#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9 -#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA -#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB -#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC -#define GL_COLOR_ATTACHMENT13_EXT 0x8CED -#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE -#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF -#define GL_DEPTH_ATTACHMENT_EXT 0x8D00 -#define GL_STENCIL_ATTACHMENT_EXT 0x8D20 -#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5 -#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6 -#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 -#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9 -#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA -#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB -#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC -#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD -#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6 -#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7 -#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF -#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 -#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506 -#endif +// GL_ARB_framebuffer_object, built-in to OpenGL 3.0 +#define QGL_ARB_framebuffer_object_PROCS \ + GLE(void, BindRenderbuffer, GLenum target, GLuint renderbuffer) \ + GLE(void, DeleteRenderbuffers, GLsizei n, const GLuint *renderbuffers) \ + GLE(void, GenRenderbuffers, GLsizei n, GLuint *renderbuffers) \ + GLE(void, RenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) \ + GLE(void, BindFramebuffer, GLenum target, GLuint framebuffer) \ + GLE(void, DeleteFramebuffers, GLsizei n, const GLuint *framebuffers) \ + GLE(void, GenFramebuffers, GLsizei n, GLuint *framebuffers) \ + GLE(GLenum, CheckFramebufferStatus, GLenum target) \ + GLE(void, FramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) \ + GLE(void, FramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) \ + GLE(void, GenerateMipmap, GLenum target) \ + GLE(void, BlitFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) \ + GLE(void, RenderbufferStorageMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) \ -// GL_EXT_packed_depth_stencil -#ifndef GL_EXT_packed_depth_stencil -#define GL_EXT_packed_depth_stencil -#define GL_DEPTH_STENCIL_EXT 0x84F9 -#define GL_UNSIGNED_INT_24_8_EXT 0x84FA -#define GL_DEPTH24_STENCIL8_EXT 0x88F0 -#define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 -#endif - -// GL_ARB_occlusion_query -extern void (APIENTRY * qglGenQueriesARB)(GLsizei n, GLuint *ids); -extern void (APIENTRY * qglDeleteQueriesARB)(GLsizei n, const GLuint *ids); -extern GLboolean (APIENTRY * qglIsQueryARB)(GLuint id); -extern void (APIENTRY * qglBeginQueryARB)(GLenum target, GLuint id); -extern void (APIENTRY * qglEndQueryARB)(GLenum target); -extern void (APIENTRY * qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params); -extern void (APIENTRY * qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params); -extern void (APIENTRY * qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params); - -#ifndef GL_ARB_occlusion_query -#define GL_ARB_occlusion_query -#define GL_SAMPLES_PASSED_ARB 0x8914 -#define GL_QUERY_COUNTER_BITS_ARB 0x8864 -#define GL_CURRENT_QUERY_ARB 0x8865 -#define GL_QUERY_RESULT_ARB 0x8866 -#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867 -#endif - -// GL_EXT_framebuffer_blit -extern void (APIENTRY * qglBlitFramebufferEXT)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter); - -#ifndef GL_EXT_framebuffer_blit -#define GL_EXT_framebuffer_blit -#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 -#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 -#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6 -#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA -#endif - -// GL_EXT_framebuffer_multisample -extern void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height); - -#ifndef GL_EXT_framebuffer_multisample -#define GL_EXT_framebuffer_multisample -#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB -#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 -#define GL_MAX_SAMPLES_EXT 0x8D57 -#endif - -#ifndef GL_EXT_texture_sRGB -#define GL_EXT_texture_sRGB -#define GL_SRGB_EXT 0x8C40 -#define GL_SRGB8_EXT 0x8C41 -#define GL_SRGB_ALPHA_EXT 0x8C42 -#define GL_SRGB8_ALPHA8_EXT 0x8C43 -#define GL_SLUMINANCE_ALPHA_EXT 0x8C44 -#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45 -#define GL_SLUMINANCE_EXT 0x8C46 -#define GL_SLUMINANCE8_EXT 0x8C47 -#define GL_COMPRESSED_SRGB_EXT 0x8C48 -#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 -#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A -#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B -#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E -#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F -#endif - -#ifndef GL_EXT_framebuffer_sRGB -#define GL_EXT_framebuffer_sRGB -#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 -#endif +// GL_ARB_vertex_array_object, built-in to OpenGL 3.0 +#define QGL_ARB_vertex_array_object_PROCS \ + GLE(void, BindVertexArray, GLuint array) \ + GLE(void, DeleteVertexArrays, GLsizei n, const GLuint *arrays) \ + GLE(void, GenVertexArrays, GLsizei n, GLuint *arrays) \ #ifndef GL_ARB_texture_compression_rgtc #define GL_ARB_texture_compression_rgtc @@ -693,29 +279,6 @@ extern void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLs #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F #endif -// GL_ARB_draw_buffers -extern void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); -#ifndef GL_ARB_draw_buffers -#define GL_ARB_draw_buffers -#define GL_MAX_DRAW_BUFFERS_ARB 0x8824 -#define GL_DRAW_BUFFER0_ARB 0x8825 -#define GL_DRAW_BUFFER1_ARB 0x8826 -#define GL_DRAW_BUFFER2_ARB 0x8827 -#define GL_DRAW_BUFFER3_ARB 0x8828 -#define GL_DRAW_BUFFER4_ARB 0x8829 -#define GL_DRAW_BUFFER5_ARB 0x882A -#define GL_DRAW_BUFFER6_ARB 0x882B -#define GL_DRAW_BUFFER7_ARB 0x882C -#define GL_DRAW_BUFFER8_ARB 0x882D -#define GL_DRAW_BUFFER9_ARB 0x882E -#define GL_DRAW_BUFFER10_ARB 0x882F -#define GL_DRAW_BUFFER11_ARB 0x8830 -#define GL_DRAW_BUFFER12_ARB 0x8831 -#define GL_DRAW_BUFFER13_ARB 0x8832 -#define GL_DRAW_BUFFER14_ARB 0x8833 -#define GL_DRAW_BUFFER15_ARB 0x8834 -#endif - #ifndef GL_ARB_depth_clamp #define GL_ARB_depth_clamp #define GL_DEPTH_CLAMP 0x864F @@ -726,92 +289,50 @@ extern void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); #define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F #endif -// GL_ARB_vertex_array_object -extern void (APIENTRY * qglBindVertexArrayARB)(GLuint array); -extern void (APIENTRY * qglDeleteVertexArraysARB)(GLsizei n, const GLuint *arrays); -extern void (APIENTRY * qglGenVertexArraysARB)(GLsizei n, GLuint *arrays); -extern GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array); -#ifndef GL_ARB_vertex_array_object -#define GL_ARB_vertex_array_object -#define GL_VERTEX_ARRAY_BINDING_ARB 0x85B5 -#endif - // GL_EXT_direct_state_access -extern GLvoid(APIENTRY * qglBindMultiTexture)(GLenum texunit, GLenum target, GLuint texture); -extern GLvoid(APIENTRY * qglTextureParameterf)(GLuint texture, GLenum target, GLenum pname, GLfloat param); -extern GLvoid(APIENTRY * qglTextureParameteri)(GLuint texture, GLenum target, GLenum pname, GLint param); -extern GLvoid(APIENTRY * qglTextureImage2D)(GLuint texture, GLenum target, GLint level, GLint internalformat, - GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -extern GLvoid(APIENTRY * qglTextureSubImage2D)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -extern GLvoid(APIENTRY * qglCopyTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat, - GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -extern GLvoid(APIENTRY * qglCompressedTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat, - GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -extern GLvoid(APIENTRY * qglCompressedTextureSubImage2D)(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, - GLsizei imageSize, const GLvoid *data); -extern GLvoid(APIENTRY * qglGenerateTextureMipmap)(GLuint texture, GLenum target); +#define QGL_EXT_direct_state_access_PROCS \ + GLE(GLvoid, BindMultiTextureEXT, GLenum texunit, GLenum target, GLuint texture) \ + GLE(GLvoid, TextureParameterfEXT, GLuint texture, GLenum target, GLenum pname, GLfloat param) \ + GLE(GLvoid, TextureParameteriEXT, GLuint texture, GLenum target, GLenum pname, GLint param) \ + GLE(GLvoid, TextureImage2DEXT, GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) \ + GLE(GLvoid, TextureSubImage2DEXT, GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) \ + GLE(GLvoid, CopyTextureSubImage2DEXT, GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) \ + GLE(GLvoid, CompressedTextureImage2DEXT, GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) \ + GLE(GLvoid, CompressedTextureSubImage2DEXT, GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) \ + GLE(GLvoid, GenerateTextureMipmapEXT, GLuint texture, GLenum target) \ + GLE(GLvoid, ProgramUniform1iEXT, GLuint program, GLint location, GLint v0) \ + GLE(GLvoid, ProgramUniform1fEXT, GLuint program, GLint location, GLfloat v0) \ + GLE(GLvoid, ProgramUniform2fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1) \ + GLE(GLvoid, ProgramUniform3fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) \ + GLE(GLvoid, ProgramUniform4fEXT, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) \ + GLE(GLvoid, ProgramUniform1fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value) \ + GLE(GLvoid, ProgramUniformMatrix4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) \ + GLE(GLvoid, NamedRenderbufferStorageEXT, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) \ + GLE(GLvoid, NamedRenderbufferStorageMultisampleEXT, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) \ + GLE(GLenum, CheckNamedFramebufferStatusEXT, GLuint framebuffer, GLenum target) \ + GLE(GLvoid, NamedFramebufferTexture2DEXT, GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) \ + GLE(GLvoid, NamedFramebufferRenderbufferEXT, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) \ -extern GLvoid(APIENTRY * qglProgramUniform1i)(GLuint program, GLint location, GLint v0); -extern GLvoid(APIENTRY * qglProgramUniform1f)(GLuint program, GLint location, GLfloat v0); -extern GLvoid(APIENTRY * qglProgramUniform2f)(GLuint program, GLint location, - GLfloat v0, GLfloat v1); -extern GLvoid(APIENTRY * qglProgramUniform3f)(GLuint program, GLint location, - GLfloat v0, GLfloat v1, GLfloat v2); -extern GLvoid(APIENTRY * qglProgramUniform4f)(GLuint program, GLint location, - GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -extern GLvoid(APIENTRY * qglProgramUniform1fv)(GLuint program, GLint location, - GLsizei count, const GLfloat *value); -extern GLvoid(APIENTRY * qglProgramUniformMatrix4fv)(GLuint program, GLint location, - GLsizei count, GLboolean transpose, - const GLfloat *value); +#define GLE(ret, name, ...) typedef ret APIENTRY name##proc(__VA_ARGS__); +QGL_1_1_PROCS; +QGL_1_1_FIXED_FUNCTION_PROCS; +QGL_DESKTOP_1_1_PROCS; +QGL_DESKTOP_1_1_FIXED_FUNCTION_PROCS; +QGL_ES_1_1_PROCS; +QGL_ES_1_1_FIXED_FUNCTION_PROCS; +QGL_1_3_PROCS; +QGL_1_5_PROCS; +QGL_2_0_PROCS; +QGL_3_0_PROCS; +QGL_ARB_occlusion_query_PROCS; +QGL_ARB_framebuffer_object_PROCS; +QGL_ARB_vertex_array_object_PROCS; +QGL_EXT_direct_state_access_PROCS; +#undef GLE -extern GLvoid(APIENTRY * qglNamedRenderbufferStorage)(GLuint renderbuffer, - GLenum internalformat, GLsizei width, GLsizei height); - -extern GLvoid(APIENTRY * qglNamedRenderbufferStorageMultisample)(GLuint renderbuffer, - GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); - -extern GLenum(APIENTRY * qglCheckNamedFramebufferStatus)(GLuint framebuffer, GLenum target); -extern GLvoid(APIENTRY * qglNamedFramebufferTexture2D)(GLuint framebuffer, - GLenum attachment, GLenum textarget, GLuint texture, GLint level); -extern GLvoid(APIENTRY * qglNamedFramebufferRenderbuffer)(GLuint framebuffer, - GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); - - - - -#if defined(WIN32) -// WGL_ARB_create_context -#ifndef WGL_ARB_create_context -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define ERROR_INVALID_VERSION_ARB 0x2095 -#define ERROR_INVALID_PROFILE_ARB 0x2096 -#endif - -extern HGLRC(APIENTRY * qwglCreateContextAttribsARB) (HDC hdC, HGLRC hShareContext, const int *attribList); -#endif - -#if 0 //defined(__linux__) -// GLX_ARB_create_context -#ifndef GLX_ARB_create_context -#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define GLX_CONTEXT_FLAGS_ARB 0x2094 -#endif - -extern GLXContext (APIENTRY * qglXCreateContextAttribsARB) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); -#endif +extern int qglMajorVersion, qglMinorVersion; +extern int qglesMajorVersion, qglesMinorVersion; +#define QGL_VERSION_ATLEAST( major, minor ) ( qglMajorVersion > major || ( qglMajorVersion == major && qglMinorVersion >= minor ) ) +#define QGLES_VERSION_ATLEAST( major, minor ) ( qglesMajorVersion > major || ( qglesMajorVersion == major && qglesMinorVersion >= minor ) ) #endif diff --git a/code/renderercommon/tr_common.h b/code/renderercommon/tr_common.h index 59184978..9c7e176b 100644 --- a/code/renderercommon/tr_common.h +++ b/code/renderercommon/tr_common.h @@ -43,8 +43,7 @@ typedef enum IMGFLAG_NO_COMPRESSION = 0x0010, IMGFLAG_NOLIGHTSCALE = 0x0020, IMGFLAG_CLAMPTOEDGE = 0x0040, - IMGFLAG_SRGB = 0x0080, - IMGFLAG_GENNORMALMAP = 0x0100, + IMGFLAG_GENNORMALMAP = 0x0080, } imgFlags_t; typedef struct image_s { @@ -117,7 +116,7 @@ extern cvar_t *r_saveFontData; qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ); -float R_NoiseGet4f( float x, float y, float z, float t ); +float R_NoiseGet4f( float x, float y, float z, double t ); void R_NoiseInit( void ); image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ); @@ -156,7 +155,7 @@ IMPLEMENTATION SPECIFIC FUNCTIONS ==================================================================== */ -void GLimp_Init( void ); +void GLimp_Init( qboolean fixedFunction ); void GLimp_Shutdown( void ); void GLimp_EndFrame( void ); diff --git a/code/renderercommon/tr_font.c b/code/renderercommon/tr_font.c index 0f89d5ad..2687bee5 100644 --- a/code/renderercommon/tr_font.c +++ b/code/renderercommon/tr_font.c @@ -303,7 +303,7 @@ static int fdOffset; static byte *fdFile; int readInt( void ) { - int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24); + int i = ((unsigned int)fdFile[fdOffset] | ((unsigned int)fdFile[fdOffset+1]<<8) | ((unsigned int)fdFile[fdOffset+2]<<16) | ((unsigned int)fdFile[fdOffset+3]<<24)); fdOffset += 4; return i; } diff --git a/code/renderercommon/tr_image_png.c b/code/renderercommon/tr_image_png.c index 7b6fbada..3ec8fdec 100644 --- a/code/renderercommon/tr_image_png.c +++ b/code/renderercommon/tr_image_png.c @@ -571,7 +571,7 @@ static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer) { /* * Rewind to the start of this adventure - * and return unsuccessfull + * and return unsuccessful */ BufferedFileRewind(BF, BytesToRewind); @@ -754,7 +754,7 @@ static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer) ri.Free(CompressedData); /* - * Check if the last puff() was successfull. + * Check if the last puff() was successful. */ if(!((puffResult == 0) && (puffDestLen > 0))) diff --git a/code/renderercommon/tr_noise.c b/code/renderercommon/tr_noise.c index 445ef827..abd27cbd 100644 --- a/code/renderercommon/tr_noise.c +++ b/code/renderercommon/tr_noise.c @@ -49,7 +49,7 @@ void R_NoiseInit( void ) } } -float R_NoiseGet4f( float x, float y, float z, float t ) +float R_NoiseGet4f( float x, float y, float z, double t ) { int i; int ix, iy, iz, it; diff --git a/code/renderercommon/tr_public.h b/code/renderercommon/tr_public.h index 38d647f6..8573860b 100644 --- a/code/renderercommon/tr_public.h +++ b/code/renderercommon/tr_public.h @@ -151,7 +151,7 @@ typedef struct { void (*CM_DrawDebugSurface)( void (*drawPoly)(int color, int numPoints, float *points) ); // a -1 return means the file does not exist - // NULL can be passed for buf to just determine existance + // NULL can be passed for buf to just determine existence int (*FS_FileIsInPAK)( const char *name, int *pCheckSum ); long (*FS_ReadFile)( const char *name, void **buf ); void (*FS_FreeFile)( void *buf ); diff --git a/code/renderercommon/tr_types.h b/code/renderercommon/tr_types.h index a1aef1bd..ef4353ef 100644 --- a/code/renderercommon/tr_types.h +++ b/code/renderercommon/tr_types.h @@ -176,7 +176,7 @@ typedef enum { } glDriverType_t; typedef enum { - GLHW_GENERIC, // where everthing works the way it should + GLHW_GENERIC, // where everything works the way it should GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is // the hardware type then there can NOT exist a secondary // display adapter diff --git a/code/renderergl1/tr_altivec.c b/code/renderergl1/tr_altivec.c new file mode 100644 index 00000000..914aa448 --- /dev/null +++ b/code/renderergl1/tr_altivec.c @@ -0,0 +1,414 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +/* This file is only compiled for PowerPC builds with Altivec support. + Altivec intrinsics need to be in a separate file, so GCC's -maltivec + command line can enable them, but give us the option to _not_ use that + on other files, where the compiler might then generate Altivec + instructions for normal floating point, crashing on G3 (etc) processors. */ + +#include "tr_local.h" + +#if idppc_altivec + +#if !defined(__APPLE__) +#include +#endif + +void ProjectDlightTexture_altivec( void ) { + int i, l; + vec_t origin0, origin1, origin2; + float texCoords0, texCoords1; + vector float floatColorVec0, floatColorVec1; + vector float modulateVec, colorVec, zero; + vector short colorShort; + vector signed int colorInt; + vector unsigned char floatColorVecPerm, modulatePerm, colorChar; + vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff); + float *texCoords; + byte *colors; + byte clipBits[SHADER_MAX_VERTEXES]; + float texCoordsArray[SHADER_MAX_VERTEXES][2]; + byte colorArray[SHADER_MAX_VERTEXES][4]; + glIndex_t hitIndexes[SHADER_MAX_INDEXES]; + int numIndexes; + float scale; + float radius; + vec3_t floatColor; + float modulate = 0.0f; + + if ( !backEnd.refdef.num_dlights ) { + return; + } + + // There has to be a better way to do this so that floatColor + // and/or modulate are already 16-byte aligned. + floatColorVecPerm = vec_lvsl(0,(float *)floatColor); + modulatePerm = vec_lvsl(0,(float *)&modulate); + modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0); + zero = (vector float)vec_splat_s8(0); + + for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { + dlight_t *dl; + + if ( !( tess.dlightBits & ( 1 << l ) ) ) { + continue; // this surface definitely doesn't have any of this light + } + texCoords = texCoordsArray[0]; + colors = colorArray[0]; + + dl = &backEnd.refdef.dlights[l]; + origin0 = dl->transformed[0]; + origin1 = dl->transformed[1]; + origin2 = dl->transformed[2]; + radius = dl->radius; + scale = 1.0f / radius; + + if(r_greyscale->integer) + { + float luminance; + + luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; + floatColor[0] = floatColor[1] = floatColor[2] = luminance; + } + else if(r_greyscale->value) + { + float luminance; + + luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; + floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); + floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); + floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); + } + else + { + floatColor[0] = dl->color[0] * 255.0f; + floatColor[1] = dl->color[1] * 255.0f; + floatColor[2] = dl->color[2] * 255.0f; + } + floatColorVec0 = vec_ld(0, floatColor); + floatColorVec1 = vec_ld(11, floatColor); + floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); + for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { + int clip = 0; + vec_t dist0, dist1, dist2; + + dist0 = origin0 - tess.xyz[i][0]; + dist1 = origin1 - tess.xyz[i][1]; + dist2 = origin2 - tess.xyz[i][2]; + + backEnd.pc.c_dlightVertexes++; + + texCoords0 = 0.5f + dist0 * scale; + texCoords1 = 0.5f + dist1 * scale; + + if( !r_dlightBacks->integer && + // dist . tess.normal[i] + ( dist0 * tess.normal[i][0] + + dist1 * tess.normal[i][1] + + dist2 * tess.normal[i][2] ) < 0.0f ) { + clip = 63; + } else { + if ( texCoords0 < 0.0f ) { + clip |= 1; + } else if ( texCoords0 > 1.0f ) { + clip |= 2; + } + if ( texCoords1 < 0.0f ) { + clip |= 4; + } else if ( texCoords1 > 1.0f ) { + clip |= 8; + } + texCoords[0] = texCoords0; + texCoords[1] = texCoords1; + + // modulate the strength based on the height and color + if ( dist2 > radius ) { + clip |= 16; + modulate = 0.0f; + } else if ( dist2 < -radius ) { + clip |= 32; + modulate = 0.0f; + } else { + dist2 = Q_fabs(dist2); + if ( dist2 < radius * 0.5f ) { + modulate = 1.0f; + } else { + modulate = 2.0f * (radius - dist2) * scale; + } + } + } + clipBits[i] = clip; + + modulateVec = vec_ld(0,(float *)&modulate); + modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); + colorVec = vec_madd(floatColorVec0,modulateVec,zero); + colorInt = vec_cts(colorVec,0); // RGBx + colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx + colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx + colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 + vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color + } + + // build a list of triangles that need light + numIndexes = 0; + for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { + int a, b, c; + + a = tess.indexes[i]; + b = tess.indexes[i+1]; + c = tess.indexes[i+2]; + if ( clipBits[a] & clipBits[b] & clipBits[c] ) { + continue; // not lighted + } + hitIndexes[numIndexes] = a; + hitIndexes[numIndexes+1] = b; + hitIndexes[numIndexes+2] = c; + numIndexes += 3; + } + + if ( !numIndexes ) { + continue; + } + + qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); + qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); + + qglEnableClientState( GL_COLOR_ARRAY ); + qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); + + GL_Bind( tr.dlightImage ); + // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light + // where they aren't rendered + if ( dl->additive ) { + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); + } + else { + GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); + } + R_DrawElements( numIndexes, hitIndexes ); + backEnd.pc.c_totalIndexes += numIndexes; + backEnd.pc.c_dlightIndexes += numIndexes; + } +} + +void RB_CalcDiffuseColor_altivec( unsigned char *colors ) +{ + int i; + float *v, *normal; + trRefEntity_t *ent; + int ambientLightInt; + vec3_t lightDir; + int numVertexes; + vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff); + vector float ambientLightVec; + vector float directedLightVec; + vector float lightDirVec; + vector float normalVec0, normalVec1; + vector float incomingVec0, incomingVec1, incomingVec2; + vector float zero, jVec; + vector signed int jVecInt; + vector signed short jVecShort; + vector unsigned char jVecChar, normalPerm; + ent = backEnd.currentEntity; + ambientLightInt = ent->ambientLightInt; + // A lot of this could be simplified if we made sure + // entities light info was 16-byte aligned. + jVecChar = vec_lvsl(0, ent->ambientLight); + ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight); + jVec = vec_ld(11, (vector float *)ent->ambientLight); + ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar); + + jVecChar = vec_lvsl(0, ent->directedLight); + directedLightVec = vec_ld(0,(vector float *)ent->directedLight); + jVec = vec_ld(11,(vector float *)ent->directedLight); + directedLightVec = vec_perm(directedLightVec,jVec,jVecChar); + + jVecChar = vec_lvsl(0, ent->lightDir); + lightDirVec = vec_ld(0,(vector float *)ent->lightDir); + jVec = vec_ld(11,(vector float *)ent->lightDir); + lightDirVec = vec_perm(lightDirVec,jVec,jVecChar); + + zero = (vector float)vec_splat_s8(0); + VectorCopy( ent->lightDir, lightDir ); + + v = tess.xyz[0]; + normal = tess.normal[0]; + + normalPerm = vec_lvsl(0,normal); + numVertexes = tess.numVertexes; + for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { + normalVec0 = vec_ld(0,(vector float *)normal); + normalVec1 = vec_ld(11,(vector float *)normal); + normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm); + incomingVec0 = vec_madd(normalVec0, lightDirVec, zero); + incomingVec1 = vec_sld(incomingVec0,incomingVec0,4); + incomingVec2 = vec_add(incomingVec0,incomingVec1); + incomingVec1 = vec_sld(incomingVec1,incomingVec1,4); + incomingVec2 = vec_add(incomingVec2,incomingVec1); + incomingVec0 = vec_splat(incomingVec2,0); + incomingVec0 = vec_max(incomingVec0,zero); + normalPerm = vec_lvsl(12,normal); + jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec); + jVecInt = vec_cts(jVec,0); // RGBx + jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx + jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx + jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 + vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color + } +} + +void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp) +{ + short *oldXyz, *newXyz, *oldNormals, *newNormals; + float *outXyz, *outNormal; + float oldXyzScale QALIGN(16); + float newXyzScale QALIGN(16); + float oldNormalScale QALIGN(16); + float newNormalScale QALIGN(16); + int vertNum; + unsigned lat, lng; + int numVerts; + + outXyz = tess.xyz[tess.numVertexes]; + outNormal = tess.normal[tess.numVertexes]; + + newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) + + (backEnd.currentEntity->e.frame * surf->numVerts * 4); + newNormals = newXyz + 3; + + newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); + newNormalScale = 1.0 - backlerp; + + numVerts = surf->numVerts; + + if ( backlerp == 0 ) { + vector signed short newNormalsVec0; + vector signed short newNormalsVec1; + vector signed int newNormalsIntVec; + vector float newNormalsFloatVec; + vector float newXyzScaleVec; + vector unsigned char newNormalsLoadPermute; + vector unsigned char newNormalsStorePermute; + vector float zero; + + newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec); + newXyzScaleVec = *(vector float *)&newXyzScale; + newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute); + newXyzScaleVec = vec_splat(newXyzScaleVec,0); + newNormalsLoadPermute = vec_lvsl(0,newXyz); + newNormalsStorePermute = vec_lvsr(0,outXyz); + zero = (vector float)vec_splat_s8(0); + // + // just copy the vertexes + // + for (vertNum=0 ; vertNum < numVerts ; vertNum++, + newXyz += 4, newNormals += 4, + outXyz += 4, outNormal += 4) + { + newNormalsLoadPermute = vec_lvsl(0,newXyz); + newNormalsStorePermute = vec_lvsr(0,outXyz); + newNormalsVec0 = vec_ld(0,newXyz); + newNormalsVec1 = vec_ld(16,newXyz); + newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute); + newNormalsIntVec = vec_unpackh(newNormalsVec0); + newNormalsFloatVec = vec_ctf(newNormalsIntVec,0); + newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero); + newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute); + //outXyz[0] = newXyz[0] * newXyzScale; + //outXyz[1] = newXyz[1] * newXyzScale; + //outXyz[2] = newXyz[2] * newXyzScale; + + lat = ( newNormals[0] >> 8 ) & 0xff; + lng = ( newNormals[0] & 0xff ); + lat *= (FUNCTABLE_SIZE/256); + lng *= (FUNCTABLE_SIZE/256); + + // decode X as cos( lat ) * sin( long ) + // decode Y as sin( lat ) * sin( long ) + // decode Z as cos( long ) + + outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + + vec_ste(newNormalsFloatVec,0,outXyz); + vec_ste(newNormalsFloatVec,4,outXyz); + vec_ste(newNormalsFloatVec,8,outXyz); + } + } else { + // + // interpolate and copy the vertex and normal + // + oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) + + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); + oldNormals = oldXyz + 3; + + oldXyzScale = MD3_XYZ_SCALE * backlerp; + oldNormalScale = backlerp; + + for (vertNum=0 ; vertNum < numVerts ; vertNum++, + oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, + outXyz += 4, outNormal += 4) + { + vec3_t uncompressedOldNormal, uncompressedNewNormal; + + // interpolate the xyz + outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; + outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; + outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; + + // FIXME: interpolate lat/long instead? + lat = ( newNormals[0] >> 8 ) & 0xff; + lng = ( newNormals[0] & 0xff ); + lat *= 4; + lng *= 4; + uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + + lat = ( oldNormals[0] >> 8 ) & 0xff; + lng = ( oldNormals[0] & 0xff ); + lat *= 4; + lng *= 4; + + uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + + outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; + outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; + outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; + +// VectorNormalize (outNormal); + } + VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); + } +} + +#endif diff --git a/code/renderergl1/tr_animation.c b/code/renderergl1/tr_animation.c index b01cf813..2979ab9f 100644 --- a/code/renderergl1/tr_animation.c +++ b/code/renderergl1/tr_animation.c @@ -263,9 +263,9 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { for(j = 0; j < skin->numSurfaces; j++) { - if (!strcmp(skin->surfaces[j]->name, surface->name)) + if (!strcmp(skin->surfaces[j].name, surface->name)) { - shader = skin->surfaces[j]->shader; + shader = skin->surfaces[j].shader; break; } } diff --git a/code/renderergl1/tr_backend.c b/code/renderergl1/tr_backend.c index 41fe47ac..abf15f2e 100644 --- a/code/renderergl1/tr_backend.c +++ b/code/renderergl1/tr_backend.c @@ -509,7 +509,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { int i; drawSurf_t *drawSurf; int oldSort; - float originalTime; + double originalTime; // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; @@ -541,7 +541,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // // change the tess parameters if needed - // a "entityMergable" shader is a shader that can have surfaces from seperate + // a "entityMergable" shader is a shader that can have surfaces from separate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { @@ -562,7 +562,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; - backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; + + // FIXME: e.shaderTime must be passed as int to avoid fp-precision loss issues + backEnd.refdef.floatTime = originalTime - (double)backEnd.currentEntity->e.shaderTime; + // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; @@ -713,7 +716,7 @@ void RB_SetGL2D (void) { // set time for 2D shaders backEnd.refdef.time = ri.Milliseconds(); - backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; + backEnd.refdef.floatTime = backEnd.refdef.time * 0.001; } @@ -739,7 +742,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * RB_EndSurface(); } - // we definately want to sync every frame for the cinematics + // we definitely want to sync every frame for the cinematics qglFinish(); start = 0; @@ -756,25 +759,9 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); } + RE_UploadCinematic (w, h, cols, rows, data, client, dirty); GL_Bind( tr.scratchImage[client] ); - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { - tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; - tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } else { - if (dirty) { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } - } - if ( r_speeds->integer ) { end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); diff --git a/code/renderergl1/tr_bsp.c b/code/renderergl1/tr_bsp.c index 1e660f28..5de7ff90 100644 --- a/code/renderergl1/tr_bsp.c +++ b/code/renderergl1/tr_bsp.c @@ -330,7 +330,7 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int numIndexes = LittleLong( ds->numIndexes ); // create the srfSurfaceFace_t - sfaceSize = ( size_t ) &((srfSurfaceFace_t *)0)->points[numPoints]; + sfaceSize = offsetof( srfSurfaceFace_t, points ) + sizeof( *cv->points ) * numPoints; ofsIndexes = sfaceSize; sfaceSize += sizeof( int ) * numIndexes; @@ -1428,7 +1428,7 @@ static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) { out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces); } - // chain decendants + // chain descendants R_SetParent (s_worldData.nodes, NULL); } diff --git a/code/renderergl1/tr_image.c b/code/renderergl1/tr_image.c index b131f366..9603ff71 100644 --- a/code/renderergl1/tr_image.c +++ b/code/renderergl1/tr_image.c @@ -206,7 +206,6 @@ void R_ImageList_f( void ) { estSize *= 4; break; case GL_LUMINANCE8: - case GL_LUMINANCE16: case GL_LUMINANCE: format = "L "; // 1 byte per pixel? @@ -219,7 +218,6 @@ void R_ImageList_f( void ) { estSize *= 3; break; case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE16_ALPHA16: case GL_LUMINANCE_ALPHA: format = "LA "; // 2 bytes per pixel? @@ -684,10 +682,8 @@ static void Upload32( unsigned *data, { if(r_greyscale->integer) { - if(r_texturebits->integer == 16) + if(r_texturebits->integer == 16 || r_texturebits->integer == 32) internalFormat = GL_LUMINANCE8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16; else internalFormat = GL_LUMINANCE; } @@ -719,10 +715,8 @@ static void Upload32( unsigned *data, { if(r_greyscale->integer) { - if(r_texturebits->integer == 16) + if(r_texturebits->integer == 16 || r_texturebits->integer == 32) internalFormat = GL_LUMINANCE8_ALPHA8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16_ALPHA16; else internalFormat = GL_LUMINANCE_ALPHA; } @@ -861,7 +855,7 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, } image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low ); - image->texnum = 1024 + tr.numImages; + qglGenTextures(1, &image->texnum); tr.numImages++; image->type = type; @@ -941,7 +935,7 @@ static int numImageLoaders = ARRAY_LEN( imageLoaders ); ================= R_LoadImage -Loads any of the supported image types into a cannonical +Loads any of the supported image types into a canonical 32 bit format. ================= */ @@ -1400,7 +1394,7 @@ SKINS CommaParse This is unfortunate, but the skin files aren't -compatable with our normal parsing rules. +compatible with our normal parsing rules. ================== */ static char *CommaParse( char **data_p ) { @@ -1508,6 +1502,7 @@ RE_RegisterSkin =============== */ qhandle_t RE_RegisterSkin( const char *name ) { + skinSurface_t parseSurfaces[MAX_SKIN_SURFACES]; qhandle_t hSkin; skin_t *skin; skinSurface_t *surf; @@ -1518,6 +1513,7 @@ qhandle_t RE_RegisterSkin( const char *name ) { char *text_p; char *token; char surfName[MAX_QPATH]; + int totalSurfaces; if ( !name || !name[0] ) { ri.Printf( PRINT_DEVELOPER, "Empty name passed to RE_RegisterSkin\n" ); @@ -1557,8 +1553,8 @@ qhandle_t RE_RegisterSkin( const char *name ) { // If not a .skin file, load as a single shader if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); + skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low ); + skin->surfaces[0].shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); return hSkin; } @@ -1568,6 +1564,7 @@ qhandle_t RE_RegisterSkin( const char *name ) { return 0; } + totalSurfaces = 0; text_p = text.c; while ( text_p && *text_p ) { // get surface name @@ -1591,25 +1588,32 @@ qhandle_t RE_RegisterSkin( const char *name ) { // parse the shader name token = CommaParse( &text_p ); - if ( skin->numSurfaces >= MD3_MAX_SURFACES ) { - ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES ); - break; + if ( skin->numSurfaces < MAX_SKIN_SURFACES ) { + surf = &parseSurfaces[skin->numSurfaces]; + Q_strncpyz( surf->name, surfName, sizeof( surf->name ) ); + surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue ); + skin->numSurfaces++; } - surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - Q_strncpyz( surf->name, surfName, sizeof( surf->name ) ); - surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue ); - skin->numSurfaces++; + totalSurfaces++; } ri.FS_FreeFile( text.v ); + if ( totalSurfaces > MAX_SKIN_SURFACES ) { + ri.Printf( PRINT_WARNING, "WARNING: Ignoring excess surfaces (found %d, max is %d) in skin '%s'!\n", + totalSurfaces, MAX_SKIN_SURFACES, name ); + } // never let a skin have 0 shaders if ( skin->numSurfaces == 0 ) { return 0; // use default skin } + // copy surfaces to skin + skin->surfaces = ri.Hunk_Alloc( skin->numSurfaces * sizeof( skinSurface_t ), h_low ); + memcpy( skin->surfaces, parseSurfaces, skin->numSurfaces * sizeof( skinSurface_t ) ); + return hSkin; } @@ -1628,8 +1632,8 @@ void R_InitSkins( void ) { skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); Q_strncpyz( skin->name, "", sizeof( skin->name ) ); skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - skin->surfaces[0]->shader = tr.defaultShader; + skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low ); + skin->surfaces[0].shader = tr.defaultShader; } /* @@ -1658,10 +1662,10 @@ void R_SkinList_f( void ) { for ( i = 0 ; i < tr.numSkins ; i++ ) { skin = tr.skins[i]; - ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name ); + ri.Printf( PRINT_ALL, "%3i:%s (%d surfaces)\n", i, skin->name, skin->numSurfaces ); for ( j = 0 ; j < skin->numSurfaces ; j++ ) { ri.Printf( PRINT_ALL, " %s = %s\n", - skin->surfaces[j]->name, skin->surfaces[j]->shader->name ); + skin->surfaces[j].name, skin->surfaces[j].shader->name ); } } ri.Printf (PRINT_ALL, "------------------\n"); diff --git a/code/renderergl1/tr_init.c b/code/renderergl1/tr_init.c index 15e79729..2c7d91de 100644 --- a/code/renderergl1/tr_init.c +++ b/code/renderergl1/tr_init.c @@ -178,8 +178,6 @@ int max_polyverts; */ static void InitOpenGL( void ) { - char renderer_buffer[1024]; - // // initialize OS specific portions of the renderer // @@ -195,10 +193,7 @@ static void InitOpenGL( void ) { GLint temp; - GLimp_Init(); - - strcpy( renderer_buffer, glConfig.renderer_string ); - Q_strlwr( renderer_buffer ); + GLimp_Init( qtrue ); // OpenGL driver constants qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); @@ -920,7 +915,21 @@ void GfxInfo_f( void ) ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " ); - R_PrintLongString( glConfig.extensions_string ); + if ( qglGetStringi ) + { + GLint numExtensions; + int i; + + qglGetIntegerv( GL_NUM_EXTENSIONS, &numExtensions ); + for ( i = 0; i < numExtensions; i++ ) + { + ri.Printf( PRINT_ALL, "%s ", qglGetStringi( GL_EXTENSIONS, i ) ); + } + } + else + { + R_PrintLongString( glConfig.extensions_string ); + } ri.Printf( PRINT_ALL, "\n" ); ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize ); ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits ); @@ -1259,16 +1268,15 @@ void RE_Shutdown( qboolean destroyWindow ) { ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow ); - ri.Cmd_RemoveCommand ("modellist"); - ri.Cmd_RemoveCommand ("screenshotJPEG"); - ri.Cmd_RemoveCommand ("screenshot"); - ri.Cmd_RemoveCommand ("imagelist"); - ri.Cmd_RemoveCommand ("shaderlist"); - ri.Cmd_RemoveCommand ("skinlist"); - ri.Cmd_RemoveCommand ("gfxinfo"); - ri.Cmd_RemoveCommand("minimize"); + ri.Cmd_RemoveCommand( "imagelist" ); + ri.Cmd_RemoveCommand( "shaderlist" ); + ri.Cmd_RemoveCommand( "skinlist" ); + ri.Cmd_RemoveCommand( "modellist" ); ri.Cmd_RemoveCommand( "modelist" ); - ri.Cmd_RemoveCommand( "shaderstate" ); + ri.Cmd_RemoveCommand( "screenshot" ); + ri.Cmd_RemoveCommand( "screenshotJPEG" ); + ri.Cmd_RemoveCommand( "gfxinfo" ); + ri.Cmd_RemoveCommand( "minimize" ); if ( tr.registered ) { @@ -1283,6 +1291,10 @@ void RE_Shutdown( qboolean destroyWindow ) { GLimp_Shutdown(); Com_Memset( &glConfig, 0, sizeof( glConfig ) ); + textureFilterAnisotropic = qfalse; + maxAnisotropy = 0; + displayAspect = 0.0f; + Com_Memset( &glState, 0, sizeof( glState ) ); } diff --git a/code/renderergl1/tr_light.c b/code/renderergl1/tr_light.c index 80b55f5a..3eac0535 100644 --- a/code/renderergl1/tr_light.c +++ b/code/renderergl1/tr_light.c @@ -134,7 +134,7 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) { float totalFactor; if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is + // separate lightOrigins are needed so an object that is // sinking into the ground can still be lit, and so // multi-part models can be lit identically VectorCopy( ent->e.lightingOrigin, lightOrigin ); @@ -304,7 +304,7 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { // trace a sample point down to find ambient light // if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is + // separate lightOrigins are needed so an object that is // sinking into the ground can still be lit, and so // multi-part models can be lit identically VectorCopy( ent->e.lightingOrigin, lightOrigin ); diff --git a/code/renderergl1/tr_local.h b/code/renderergl1/tr_local.h index aedf1a4f..fe42f4de 100644 --- a/code/renderergl1/tr_local.h +++ b/code/renderergl1/tr_local.h @@ -32,6 +32,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../renderercommon/iqm.h" #include "../renderercommon/qgl.h" +#define GLE(ret, name, ...) extern name##proc * qgl##name; +QGL_1_1_PROCS; +QGL_1_1_FIXED_FUNCTION_PROCS; +QGL_DESKTOP_1_1_PROCS; +QGL_DESKTOP_1_1_FIXED_FUNCTION_PROCS; +QGL_3_0_PROCS; +#undef GLE + #define GL_INDEX_TYPE GL_UNSIGNED_INT typedef unsigned int glIndex_t; @@ -362,8 +370,8 @@ typedef struct shader_s { void (*optimalStageIteratorFunc)( void ); - float clampTime; // time this shader is clamped to - float timeOffset; // current time offset for this shader + double clampTime; // time this shader is clamped to + double timeOffset; // current time offset for this shader struct shader_s *remappedShader; // current shader this one is remapped too @@ -388,7 +396,7 @@ typedef struct { byte areamask[MAX_MAP_AREA_BYTES]; qboolean areamaskModified; // qtrue if areamask changed since last scene - float floatTime; // tr.refdef.time / 1000.0 + double floatTime; // tr.refdef.time / 1000.0 // text messages for deform text shaders char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; @@ -411,6 +419,12 @@ typedef struct { //================================================================================= +// max surfaces per-skin +// This is an arbitry limit. Vanilla Q3 only supported 32 surfaces in skins but failed to +// enforce the maximum limit when reading skin files. It was possile to use more than 32 +// surfaces which accessed out of bounds memory past end of skin->surfaces hunk block. +#define MAX_SKIN_SURFACES 256 + // skins allow models to be retextured without modifying the model file typedef struct { char name[MAX_QPATH]; @@ -420,7 +434,7 @@ typedef struct { typedef struct skin_s { char name[MAX_QPATH]; // game path, including extension int numSurfaces; - skinSurface_t *surfaces[MD3_MAX_SURFACES]; + skinSurface_t *surfaces; // dynamically allocated array of surfaces } skin_t; @@ -585,28 +599,33 @@ typedef struct { int num_poses; struct srfIQModel_s *surfaces; + int *triangles; + + // vertex arrays float *positions; float *texcoords; float *normals; float *tangents; - byte *blendIndexes; + byte *colors; + int *influences; // [num_vertexes] indexes into influenceBlendVertexes + + // unique list of vertex blend indexes/weights for faster CPU vertex skinning + byte *influenceBlendIndexes; // [num_influences] union { float *f; byte *b; - } blendWeights; - byte *colors; - int *triangles; + } influenceBlendWeights; // [num_influences] // depending upon the exporter, blend indices and weights might be int/float // as opposed to the recommended byte/byte, for example Noesis exports // int/float whereas the official IQM tool exports byte/byte - byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT + int blendWeightsType; // IQM_UBYTE or IQM_FLOAT + char *jointNames; int *jointParents; float *jointMats; float *poseMats; float *bounds; - char *names; } iqmData_t; // inter-quake-model surface @@ -617,6 +636,7 @@ typedef struct srfIQModel_s { iqmData_t *data; int first_vertex, num_vertexes; int first_triangle, num_triangles; + int first_influence, num_influences; } srfIQModel_t; @@ -834,7 +854,7 @@ typedef struct { int msec; // total msec for backend run } backEndCounters_t; -// all state modified by the back end is seperated +// all state modified by the back end is separated // from the front end state typedef struct { trRefdef_t refdef; @@ -975,7 +995,7 @@ extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measuremen extern cvar_t *r_lodbias; // push/pull LOD transitions extern cvar_t *r_lodscale; -extern cvar_t *r_primitives; // "0" = based on compiled vertex array existance +extern cvar_t *r_primitives; // "0" = based on compiled vertex array existence // "1" = glDrawElemet tristrips // "2" = glDrawElements triangles // "-1" = no drawing @@ -1211,7 +1231,7 @@ typedef struct shaderCommands_s color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16); shader_t *shader; - float shaderTime; + double shaderTime; int fogNum; int dlightBits; // or together of all vertexDlightBits @@ -1577,5 +1597,13 @@ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, void RE_TakeVideoFrame( int width, int height, byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); +void R_DrawElements( int numIndexes, const glIndex_t *indexes ); +void VectorArrayNormalize( vec4_t *normals, unsigned int count ); + +#ifdef idppc_altivec +void LerpMeshVertexes_altivec( md3Surface_t *surf, float backlerp ); +void ProjectDlightTexture_altivec( void ); +void RB_CalcDiffuseColor_altivec( unsigned char *colors ); +#endif #endif //TR_LOCAL_H diff --git a/code/renderergl1/tr_main.c b/code/renderergl1/tr_main.c index 0e388314..09559a2e 100644 --- a/code/renderergl1/tr_main.c +++ b/code/renderergl1/tr_main.c @@ -1332,6 +1332,9 @@ Visualization aid for movement clipping debugging ==================== */ void R_DebugGraphics( void ) { + if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { + return; + } if ( !r_debugSurface->integer ) { return; } diff --git a/code/renderergl1/tr_marks.c b/code/renderergl1/tr_marks.c index e2c92b6c..e757ac88 100644 --- a/code/renderergl1/tr_marks.c +++ b/code/renderergl1/tr_marks.c @@ -414,7 +414,7 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio indexes = (int *)( (byte *)surf + surf->ofsIndices ); for ( k = 0 ; k < surf->numIndices ; k += 3 ) { for ( j = 0 ; j < 3 ; j++ ) { - v = surf->points[0] + VERTEXSIZE * indexes[k+j];; + v = &surf->points[0][0] + VERTEXSIZE * indexes[k+j]; VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] ); } diff --git a/code/renderergl1/tr_mesh.c b/code/renderergl1/tr_mesh.c index d0be29bc..4cdd9fc2 100644 --- a/code/renderergl1/tr_mesh.c +++ b/code/renderergl1/tr_mesh.c @@ -361,8 +361,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { shader = tr.defaultShader; for ( j = 0 ; j < skin->numSurfaces ; j++ ) { // the names have both been lowercased - if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) { - shader = skin->surfaces[j]->shader; + if ( !strcmp( skin->surfaces[j].name, surface->name ) ) { + shader = skin->surfaces[j].shader; break; } } diff --git a/code/renderergl1/tr_model_iqm.c b/code/renderergl1/tr_model_iqm.c index 6c47ed07..02616469 100644 --- a/code/renderergl1/tr_model_iqm.c +++ b/code/renderergl1/tr_model_iqm.c @@ -33,11 +33,11 @@ static float identityMatrix[12] = { }; static qboolean IQM_CheckRange( iqmHeader_t *header, int offset, - int count,int size ) { + int count, int size ) { // return true if the range specified by offset, count and size // doesn't fit into the file return ( count <= 0 || - offset < 0 || + offset <= 0 || offset > header->filesize || offset + count * size < 0 || offset + count * size > header->filesize ); @@ -58,11 +58,6 @@ static void Matrix34Multiply( float *a, float *b, float *out ) { out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10]; out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; } -static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) { - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) { float unLerp = 1.0f - lerp; @@ -143,14 +138,21 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmBounds_t *bounds; unsigned short *framedata; char *str; - int i, j; + int i, j, k; float jointInvMats[IQM_MAX_JOINTS * 12] = {0.0f}; float *mat, *matInv; size_t size, joint_names; + byte *dataPtr; iqmData_t *iqmData; srfIQModel_t *surface; char meshName[MAX_QPATH]; - byte blendIndexesType, blendWeightsType; + int vertexArrayFormat[IQM_COLOR+1]; + int allocateInfluences; + byte *blendIndexes; + union { + byte *b; + float *f; + } blendWeights; if( filesize < sizeof(iqmHeader_t) ) { return qfalse; @@ -206,164 +208,232 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na return qfalse; } - blendIndexesType = blendWeightsType = IQM_UBYTE; - - // check and swap vertex arrays - if( IQM_CheckRange( header, header->ofs_vertexarrays, - header->num_vertexarrays, - sizeof(iqmVertexArray_t) ) ) { - return qfalse; + for ( i = 0; i < ARRAY_LEN( vertexArrayFormat ); i++ ) { + vertexArrayFormat[i] = -1; } - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n, *intPtr; - if( vertexarray->size <= 0 || vertexarray->size > 4 ) { + blendIndexes = NULL; + blendWeights.b = NULL; + + allocateInfluences = 0; + + if ( header->num_meshes ) + { + // check and swap vertex arrays + if( IQM_CheckRange( header, header->ofs_vertexarrays, + header->num_vertexarrays, + sizeof(iqmVertexArray_t) ) ) { + return qfalse; + } + vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); + for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { + int n, *intPtr; + + if( vertexarray->size <= 0 || vertexarray->size > 4 ) { + return qfalse; + } + + // total number of values + n = header->num_vertexes * vertexarray->size; + + switch( vertexarray->format ) { + case IQM_BYTE: + case IQM_UBYTE: + // 1 byte, no swapping necessary + if( IQM_CheckRange( header, vertexarray->offset, + n, sizeof(byte) ) ) { + return qfalse; + } + break; + case IQM_INT: + case IQM_UINT: + case IQM_FLOAT: + // 4-byte swap + if( IQM_CheckRange( header, vertexarray->offset, + n, sizeof(float) ) ) { + return qfalse; + } + intPtr = (int *)((byte *)header + vertexarray->offset); + for( j = 0; j < n; j++, intPtr++ ) { + LL( *intPtr ); + } + break; + default: + // not supported + return qfalse; + break; + } + + if( vertexarray->type < ARRAY_LEN( vertexArrayFormat ) ) { + vertexArrayFormat[vertexarray->type] = vertexarray->format; + } + + switch( vertexarray->type ) { + case IQM_POSITION: + case IQM_NORMAL: + if( vertexarray->format != IQM_FLOAT || + vertexarray->size != 3 ) { + return qfalse; + } + break; + case IQM_TANGENT: + if( vertexarray->format != IQM_FLOAT || + vertexarray->size != 4 ) { + return qfalse; + } + break; + case IQM_TEXCOORD: + if( vertexarray->format != IQM_FLOAT || + vertexarray->size != 2 ) { + return qfalse; + } + break; + case IQM_BLENDINDEXES: + if( (vertexarray->format != IQM_INT && + vertexarray->format != IQM_UBYTE) || + vertexarray->size != 4 ) { + return qfalse; + } + blendIndexes = (byte*)header + vertexarray->offset; + break; + case IQM_BLENDWEIGHTS: + if( (vertexarray->format != IQM_FLOAT && + vertexarray->format != IQM_UBYTE) || + vertexarray->size != 4 ) { + return qfalse; + } + if( vertexarray->format == IQM_FLOAT ) { + blendWeights.f = (float*)( (byte*)header + vertexarray->offset ); + } else { + blendWeights.b = (byte*)header + vertexarray->offset; + } + break; + case IQM_COLOR: + if( vertexarray->format != IQM_UBYTE || + vertexarray->size != 4 ) { + return qfalse; + } + break; + } + } + + // check for required vertex arrays + if( vertexArrayFormat[IQM_POSITION] == -1 || vertexArrayFormat[IQM_NORMAL] == -1 || vertexArrayFormat[IQM_TEXCOORD] == -1 ) { + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_POSITION, IQM_NORMAL, and/or IQM_TEXCOORD array.\n", mod_name ); return qfalse; } - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->format ) { - case IQM_BYTE: - case IQM_UBYTE: - // 1 byte, no swapping necessary - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(byte) ) ) { + if( header->num_joints ) { + if( vertexArrayFormat[IQM_BLENDINDEXES] == -1 || vertexArrayFormat[IQM_BLENDWEIGHTS] == -1 ) { + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_BLENDINDEXES and/or IQM_BLENDWEIGHTS array.\n", mod_name ); return qfalse; } - break; - case IQM_INT: - case IQM_UINT: - case IQM_FLOAT: - // 4-byte swap - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(float) ) ) { - return qfalse; - } - intPtr = (int *)((byte *)header + vertexarray->offset); - for( j = 0; j < n; j++, intPtr++ ) { - LL( *intPtr ); - } - break; - default: - // not supported - return qfalse; - break; - } - - switch( vertexarray->type ) { - case IQM_POSITION: - case IQM_NORMAL: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 3 ) { - return qfalse; - } - break; - case IQM_TANGENT: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 4 ) { - return qfalse; - } - break; - case IQM_TEXCOORD: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 2 ) { - return qfalse; - } - break; - case IQM_BLENDINDEXES: - if( (vertexarray->format != IQM_INT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendIndexesType = vertexarray->format; - break; - case IQM_BLENDWEIGHTS: - if( (vertexarray->format != IQM_FLOAT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendWeightsType = vertexarray->format; - break; - case IQM_COLOR: - if( vertexarray->format != IQM_UBYTE || - vertexarray->size != 4 ) { - return qfalse; - } - break; - } - } - - // check and swap triangles - if( IQM_CheckRange( header, header->ofs_triangles, - header->num_triangles, sizeof(iqmTriangle_t) ) ) { - return qfalse; - } - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - LL( triangle->vertex[0] ); - LL( triangle->vertex[1] ); - LL( triangle->vertex[2] ); - - if( triangle->vertex[0] > header->num_vertexes || - triangle->vertex[1] > header->num_vertexes || - triangle->vertex[2] > header->num_vertexes ) { - return qfalse; - } - } - - // check and swap meshes - if( IQM_CheckRange( header, header->ofs_meshes, - header->num_meshes, sizeof(iqmMesh_t) ) ) { - return qfalse; - } - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - for( i = 0; i < header->num_meshes; i++, mesh++) { - LL( mesh->name ); - LL( mesh->material ); - LL( mesh->first_vertex ); - LL( mesh->num_vertexes ); - LL( mesh->first_triangle ); - LL( mesh->num_triangles ); - - if ( mesh->name < header->num_text ) { - Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); } else { - meshName[0] = '\0'; + // ignore blend arrays if present + vertexArrayFormat[IQM_BLENDINDEXES] = -1; + vertexArrayFormat[IQM_BLENDWEIGHTS] = -1; } - // check ioq3 limits - if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", - mesh->num_vertexes ); + // opengl1 renderer doesn't use tangents + vertexArrayFormat[IQM_TANGENT] = -1; + + // check and swap triangles + if( IQM_CheckRange( header, header->ofs_triangles, + header->num_triangles, sizeof(iqmTriangle_t) ) ) { return qfalse; } - if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", - mesh->num_triangles ); - return qfalse; + triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); + for( i = 0; i < header->num_triangles; i++, triangle++ ) { + LL( triangle->vertex[0] ); + LL( triangle->vertex[1] ); + LL( triangle->vertex[2] ); + + if( triangle->vertex[0] > header->num_vertexes || + triangle->vertex[1] > header->num_vertexes || + triangle->vertex[2] > header->num_vertexes ) { + return qfalse; + } } - if( mesh->first_vertex >= header->num_vertexes || - mesh->first_vertex + mesh->num_vertexes > header->num_vertexes || - mesh->first_triangle >= header->num_triangles || - mesh->first_triangle + mesh->num_triangles > header->num_triangles || - mesh->name >= header->num_text || - mesh->material >= header->num_text ) { + // check and swap meshes + if( IQM_CheckRange( header, header->ofs_meshes, + header->num_meshes, sizeof(iqmMesh_t) ) ) { return qfalse; } + mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); + for( i = 0; i < header->num_meshes; i++, mesh++) { + LL( mesh->name ); + LL( mesh->material ); + LL( mesh->first_vertex ); + LL( mesh->num_vertexes ); + LL( mesh->first_triangle ); + LL( mesh->num_triangles ); + + if ( mesh->name < header->num_text ) { + Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); + } else { + meshName[0] = '\0'; + } + + // check ioq3 limits + if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) { + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", + mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", + mesh->num_vertexes ); + return qfalse; + } + if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) { + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", + mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", + mesh->num_triangles ); + return qfalse; + } + + if( mesh->first_vertex >= header->num_vertexes || + mesh->first_vertex + mesh->num_vertexes > header->num_vertexes || + mesh->first_triangle >= header->num_triangles || + mesh->first_triangle + mesh->num_triangles > header->num_triangles || + mesh->name >= header->num_text || + mesh->material >= header->num_text ) { + return qfalse; + } + + // find number of unique blend influences per mesh + if( header->num_joints ) { + for( j = 0; j < mesh->num_vertexes; j++ ) { + int vtx = mesh->first_vertex + j; + + for( k = 0; k < j; k++ ) { + int influence = mesh->first_vertex + k; + + if( *(int*)&blendIndexes[4*influence] != *(int*)&blendIndexes[4*vtx] ) { + continue; + } + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + if ( blendWeights.f[4*influence+0] == blendWeights.f[4*vtx+0] && + blendWeights.f[4*influence+1] == blendWeights.f[4*vtx+1] && + blendWeights.f[4*influence+2] == blendWeights.f[4*vtx+2] && + blendWeights.f[4*influence+3] == blendWeights.f[4*vtx+3] ) { + break; + } + } else { + if ( *(int*)&blendWeights.b[4*influence] == *(int*)&blendWeights.b[4*vtx] ) { + break; + } + } + } + + if ( k == j ) { + allocateInfluences++; + } + } + } + } } if( header->num_poses != header->num_joints && header->num_poses != 0 ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", mod_name, header->num_poses, header->num_joints ); return qfalse; } @@ -460,26 +530,44 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na // allocate the model and copy the data size = sizeof(iqmData_t); - size += header->num_meshes * sizeof( srfIQModel_t ); - size += header->num_joints * 12 * sizeof( float ); // joint mats - size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats - if(header->ofs_bounds) - size += header->num_frames * 6 * sizeof(float); // model bounds - size += header->num_vertexes * 3 * sizeof(float); // positions - size += header->num_vertexes * 2 * sizeof(float); // texcoords - size += header->num_vertexes * 3 * sizeof(float); // normals - size += header->num_vertexes * 4 * sizeof(float); // tangents - size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes - size += header->num_vertexes * 4 * sizeof(byte); // colors - size += header->num_joints * sizeof(int); // parents - size += header->num_triangles * 3 * sizeof(int); // triangles - size += joint_names; // joint names + if( header->num_meshes ) { + size += header->num_meshes * sizeof( srfIQModel_t ); // surfaces + size += header->num_triangles * 3 * sizeof(int); // triangles + size += header->num_vertexes * 3 * sizeof(float); // positions + size += header->num_vertexes * 2 * sizeof(float); // texcoords + size += header->num_vertexes * 3 * sizeof(float); // normals - // blendWeights - if (blendWeightsType == IQM_FLOAT) { - size += header->num_vertexes * 4 * sizeof(float); - } else { - size += header->num_vertexes * 4 * sizeof(byte); + if ( vertexArrayFormat[IQM_TANGENT] != -1 ) { + size += header->num_vertexes * 4 * sizeof(float); // tangents + } + + if ( vertexArrayFormat[IQM_COLOR] != -1 ) { + size += header->num_vertexes * 4 * sizeof(byte); // colors + } + + if ( allocateInfluences ) { + size += header->num_vertexes * sizeof(int); // influences + size += allocateInfluences * 4 * sizeof(byte); // influenceBlendIndexes + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_UBYTE ) { + size += allocateInfluences * 4 * sizeof(byte); // influenceBlendWeights + } else if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + size += allocateInfluences * 4 * sizeof(float); // influenceBlendWeights + } + } + } + if( header->num_joints ) { + size += joint_names; // joint names + size += header->num_joints * sizeof(int); // joint parents + size += header->num_joints * 12 * sizeof( float ); // joint mats + } + if( header->num_poses ) { + size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats + } + if( header->ofs_bounds ) { + size += header->num_frames * 6 * sizeof(float); // model bounds + } else if( header->num_meshes && header->num_frames == 0 ) { + size += 6 * sizeof(float); // model bounds } mod->type = MOD_IQM; @@ -487,234 +575,323 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na mod->modelData = iqmData; // fill header - iqmData->num_vertexes = header->num_vertexes; - iqmData->num_triangles = header->num_triangles; + iqmData->num_vertexes = ( header->num_meshes > 0 ) ? header->num_vertexes : 0; + iqmData->num_triangles = ( header->num_meshes > 0 ) ? header->num_triangles : 0; iqmData->num_frames = header->num_frames; iqmData->num_surfaces = header->num_meshes; iqmData->num_joints = header->num_joints; - iqmData->num_poses = header->num_poses; - iqmData->blendWeightsType = blendWeightsType; - iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); - iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); - iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; - if(header->ofs_bounds) + iqmData->num_poses = header->num_poses; + iqmData->blendWeightsType = vertexArrayFormat[IQM_BLENDWEIGHTS]; + + dataPtr = (byte*)iqmData + sizeof(iqmData_t); + if( header->num_meshes ) { + iqmData->surfaces = (struct srfIQModel_s*)dataPtr; + dataPtr += header->num_meshes * sizeof( srfIQModel_t ); + + iqmData->triangles = (int*)dataPtr; + dataPtr += header->num_triangles * 3 * sizeof(int); // triangles + + iqmData->positions = (float*)dataPtr; + dataPtr += header->num_vertexes * 3 * sizeof(float); // positions + + iqmData->texcoords = (float*)dataPtr; + dataPtr += header->num_vertexes * 2 * sizeof(float); // texcoords + + iqmData->normals = (float*)dataPtr; + dataPtr += header->num_vertexes * 3 * sizeof(float); // normals + + if ( vertexArrayFormat[IQM_TANGENT] != -1 ) { + iqmData->tangents = (float*)dataPtr; + dataPtr += header->num_vertexes * 4 * sizeof(float); // tangents + } + + if ( vertexArrayFormat[IQM_COLOR] != -1 ) { + iqmData->colors = (byte*)dataPtr; + dataPtr += header->num_vertexes * 4 * sizeof(byte); // colors + } + + if ( allocateInfluences ) { + iqmData->influences = (int*)dataPtr; + dataPtr += header->num_vertexes * sizeof(int); // influences + + iqmData->influenceBlendIndexes = (byte*)dataPtr; + dataPtr += allocateInfluences * 4 * sizeof(byte); // influenceBlendIndexes + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_UBYTE ) { + iqmData->influenceBlendWeights.b = (byte*)dataPtr; + dataPtr += allocateInfluences * 4 * sizeof(byte); // influenceBlendWeights + } else if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + iqmData->influenceBlendWeights.f = (float*)dataPtr; + dataPtr += allocateInfluences * 4 * sizeof(float); // influenceBlendWeights + } + } + } + if( header->num_joints ) { + iqmData->jointNames = (char*)dataPtr; + dataPtr += joint_names; // joint names + + iqmData->jointParents = (int*)dataPtr; + dataPtr += header->num_joints * sizeof(int); // joint parents + + iqmData->jointMats = (float*)dataPtr; + dataPtr += header->num_joints * 12 * sizeof( float ); // joint mats + } + if( header->num_poses ) { + iqmData->poseMats = (float*)dataPtr; + dataPtr += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats + } + if( header->ofs_bounds ) { + iqmData->bounds = (float*)dataPtr; + dataPtr += header->num_frames * 6 * sizeof(float); // model bounds + } else if( header->num_meshes && header->num_frames == 0 ) { + iqmData->bounds = (float*)dataPtr; + dataPtr += 6 * sizeof(float); // model bounds + } + + if( header->num_meshes ) { - iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->positions = iqmData->bounds + 6 * header->num_frames; - } - else - iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes; - iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes; - iqmData->tangents = iqmData->normals + 3 * header->num_vertexes; - iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes); - - if(blendWeightsType == IQM_FLOAT) { - iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes); - iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes); - } else { - iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; - } - - iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes); - iqmData->triangles = iqmData->jointParents + header->num_joints; - iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); - - if ( header->num_joints == 0 ) - iqmData->jointMats = NULL; - - if ( header->num_poses == 0 ) - iqmData->poseMats = NULL; - - // calculate joint matrices and their inverses - // joint inverses are needed only until the pose matrices are calculated - mat = iqmData->jointMats; - matInv = jointInvMats; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - float baseFrame[12], invBaseFrame[12]; - - JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame ); - Matrix34Invert( baseFrame, invBaseFrame ); - - if ( joint->parent >= 0 ) - { - Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); - mat += 12; - Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); - matInv += 12; + // register shaders + // overwrite the material offset with the shader index + mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); + surface = iqmData->surfaces; + str = (char *)header + header->ofs_text; + for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) { + surface->surfaceType = SF_IQM; + Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name)); + Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster + surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue ); + if( surface->shader->defaultShader ) + surface->shader = tr.defaultShader; + surface->data = iqmData; + surface->first_vertex = mesh->first_vertex; + surface->num_vertexes = mesh->num_vertexes; + surface->first_triangle = mesh->first_triangle; + surface->num_triangles = mesh->num_triangles; } - else - { - Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); - mat += 12; - Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); - matInv += 12; + + // copy triangles + triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); + for( i = 0; i < header->num_triangles; i++, triangle++ ) { + iqmData->triangles[3*i+0] = triangle->vertex[0]; + iqmData->triangles[3*i+1] = triangle->vertex[1]; + iqmData->triangles[3*i+2] = triangle->vertex[2]; } - } - // calculate pose matrices - framedata = (unsigned short *)((byte *)header + header->ofs_frames); - mat = iqmData->poseMats; - for( i = 0; i < header->num_frames; i++ ) { - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( j = 0; j < header->num_poses; j++, pose++ ) { - vec3_t translate; - vec4_t rotate; - vec3_t scale; - float mat1[12], mat2[12]; + // copy vertexarrays and indexes + vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); + for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { + int n; - translate[0] = pose->channeloffset[0]; - if( pose->mask & 0x001) - translate[0] += *framedata++ * pose->channelscale[0]; - translate[1] = pose->channeloffset[1]; - if( pose->mask & 0x002) - translate[1] += *framedata++ * pose->channelscale[1]; - translate[2] = pose->channeloffset[2]; - if( pose->mask & 0x004) - translate[2] += *framedata++ * pose->channelscale[2]; + // skip disabled arrays + if( vertexarray->type < ARRAY_LEN( vertexArrayFormat ) + && vertexArrayFormat[vertexarray->type] == -1 ) + continue; - rotate[0] = pose->channeloffset[3]; - if( pose->mask & 0x008) - rotate[0] += *framedata++ * pose->channelscale[3]; - rotate[1] = pose->channeloffset[4]; - if( pose->mask & 0x010) - rotate[1] += *framedata++ * pose->channelscale[4]; - rotate[2] = pose->channeloffset[5]; - if( pose->mask & 0x020) - rotate[2] += *framedata++ * pose->channelscale[5]; - rotate[3] = pose->channeloffset[6]; - if( pose->mask & 0x040) - rotate[3] += *framedata++ * pose->channelscale[6]; + // total number of values + n = header->num_vertexes * vertexarray->size; - scale[0] = pose->channeloffset[7]; - if( pose->mask & 0x080) - scale[0] += *framedata++ * pose->channelscale[7]; - scale[1] = pose->channeloffset[8]; - if( pose->mask & 0x100) - scale[1] += *framedata++ * pose->channelscale[8]; - scale[2] = pose->channeloffset[9]; - if( pose->mask & 0x200) - scale[2] += *framedata++ * pose->channelscale[9]; - - // construct transformation matrix - JointToMatrix( rotate, scale, translate, mat1 ); - - if( pose->parent >= 0 ) { - Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, - mat1, mat2 ); - } else { - Com_Memcpy( mat2, mat1, sizeof(mat1) ); + switch( vertexarray->type ) { + case IQM_POSITION: + Com_Memcpy( iqmData->positions, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + break; + case IQM_NORMAL: + Com_Memcpy( iqmData->normals, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + break; + case IQM_TANGENT: + Com_Memcpy( iqmData->tangents, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + break; + case IQM_TEXCOORD: + Com_Memcpy( iqmData->texcoords, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + break; + case IQM_BLENDINDEXES: + case IQM_BLENDWEIGHTS: + break; + case IQM_COLOR: + Com_Memcpy( iqmData->colors, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + break; } - - Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); - mat += 12; } - } - // register shaders - // overwrite the material offset with the shader index - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - surface = iqmData->surfaces; - str = (char *)header + header->ofs_text; - for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) { - surface->surfaceType = SF_IQM; - Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name)); - Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster - surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue ); - if( surface->shader->defaultShader ) - surface->shader = tr.defaultShader; - surface->data = iqmData; - surface->first_vertex = mesh->first_vertex; - surface->num_vertexes = mesh->num_vertexes; - surface->first_triangle = mesh->first_triangle; - surface->num_triangles = mesh->num_triangles; - } + // find unique blend influences per mesh + if( allocateInfluences ) { + int vtx, influence, totalInfluences = 0; - // copy vertexarrays and indexes - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n; + surface = iqmData->surfaces; + for( i = 0; i < header->num_meshes; i++, surface++ ) { + surface->first_influence = totalInfluences; + surface->num_influences = 0; - // total number of values - n = header->num_vertexes * vertexarray->size; + for( j = 0; j < surface->num_vertexes; j++ ) { + vtx = surface->first_vertex + j; - switch( vertexarray->type ) { - case IQM_POSITION: - Com_Memcpy( iqmData->positions, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_NORMAL: - Com_Memcpy( iqmData->normals, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TANGENT: - Com_Memcpy( iqmData->tangents, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TEXCOORD: - Com_Memcpy( iqmData->texcoords, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_BLENDINDEXES: - if( blendIndexesType == IQM_INT ) { - int *data = (int*)((byte*)header + vertexarray->offset); - for ( j = 0; j < n; j++ ) { - iqmData->blendIndexes[j] = (byte)data[j]; + for( k = 0; k < surface->num_influences; k++ ) { + influence = surface->first_influence + k; + + if( *(int*)&iqmData->influenceBlendIndexes[4*influence] != *(int*)&blendIndexes[4*vtx] ) { + continue; + } + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + if ( iqmData->influenceBlendWeights.f[4*influence+0] == blendWeights.f[4*vtx+0] && + iqmData->influenceBlendWeights.f[4*influence+1] == blendWeights.f[4*vtx+1] && + iqmData->influenceBlendWeights.f[4*influence+2] == blendWeights.f[4*vtx+2] && + iqmData->influenceBlendWeights.f[4*influence+3] == blendWeights.f[4*vtx+3] ) { + break; + } + } else { + if ( *(int*)&iqmData->influenceBlendWeights.b[4*influence] == *(int*)&blendWeights.b[4*vtx] ) { + break; + } + } + } + + iqmData->influences[vtx] = surface->first_influence + k; + + if( k == surface->num_influences ) { + influence = surface->first_influence + k; + + iqmData->influenceBlendIndexes[4*influence+0] = blendIndexes[4*vtx+0]; + iqmData->influenceBlendIndexes[4*influence+1] = blendIndexes[4*vtx+1]; + iqmData->influenceBlendIndexes[4*influence+2] = blendIndexes[4*vtx+2]; + iqmData->influenceBlendIndexes[4*influence+3] = blendIndexes[4*vtx+3]; + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + iqmData->influenceBlendWeights.f[4*influence+0] = blendWeights.f[4*vtx+0]; + iqmData->influenceBlendWeights.f[4*influence+1] = blendWeights.f[4*vtx+1]; + iqmData->influenceBlendWeights.f[4*influence+2] = blendWeights.f[4*vtx+2]; + iqmData->influenceBlendWeights.f[4*influence+3] = blendWeights.f[4*vtx+3]; + } else { + iqmData->influenceBlendWeights.b[4*influence+0] = blendWeights.b[4*vtx+0]; + iqmData->influenceBlendWeights.b[4*influence+1] = blendWeights.b[4*vtx+1]; + iqmData->influenceBlendWeights.b[4*influence+2] = blendWeights.b[4*vtx+2]; + iqmData->influenceBlendWeights.b[4*influence+3] = blendWeights.b[4*vtx+3]; + } + + totalInfluences++; + surface->num_influences++; + } } - } else { - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); } - break; - case IQM_BLENDWEIGHTS: - if( blendWeightsType == IQM_FLOAT ) { - Com_Memcpy( iqmData->blendWeights.f, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - } else { - Com_Memcpy( iqmData->blendWeights.b, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_COLOR: - Com_Memcpy( iqmData->colors, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - break; } } - // copy joint parents - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - iqmData->jointParents[i] = joint->parent; + if( header->num_joints ) + { + // copy joint names + str = iqmData->jointNames; + joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); + for( i = 0; i < header->num_joints; i++, joint++ ) { + char *name = (char *)header + header->ofs_text + + joint->name; + int len = strlen( name ) + 1; + Com_Memcpy( str, name, len ); + str += len; + } + + // copy joint parents + joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); + for( i = 0; i < header->num_joints; i++, joint++ ) { + iqmData->jointParents[i] = joint->parent; + } + + // calculate joint matrices and their inverses + // joint inverses are needed only until the pose matrices are calculated + mat = iqmData->jointMats; + matInv = jointInvMats; + joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); + for( i = 0; i < header->num_joints; i++, joint++ ) { + float baseFrame[12], invBaseFrame[12]; + + JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame ); + Matrix34Invert( baseFrame, invBaseFrame ); + + if ( joint->parent >= 0 ) + { + Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); + mat += 12; + Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); + matInv += 12; + } + else + { + Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); + mat += 12; + Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); + matInv += 12; + } + } } - // copy triangles - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - iqmData->triangles[3*i+0] = triangle->vertex[0]; - iqmData->triangles[3*i+1] = triangle->vertex[1]; - iqmData->triangles[3*i+2] = triangle->vertex[2]; - } + if( header->num_poses ) + { + // calculate pose matrices + framedata = (unsigned short *)((byte *)header + header->ofs_frames); + mat = iqmData->poseMats; + for( i = 0; i < header->num_frames; i++ ) { + pose = (iqmPose_t *)((byte *)header + header->ofs_poses); + for( j = 0; j < header->num_poses; j++, pose++ ) { + vec3_t translate; + vec4_t rotate; + vec3_t scale; + float mat1[12], mat2[12]; - // copy joint names - str = iqmData->names; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - char *name = (char *)header + header->ofs_text + - joint->name; - int len = strlen( name ) + 1; - Com_Memcpy( str, name, len ); - str += len; + translate[0] = pose->channeloffset[0]; + if( pose->mask & 0x001) + translate[0] += *framedata++ * pose->channelscale[0]; + translate[1] = pose->channeloffset[1]; + if( pose->mask & 0x002) + translate[1] += *framedata++ * pose->channelscale[1]; + translate[2] = pose->channeloffset[2]; + if( pose->mask & 0x004) + translate[2] += *framedata++ * pose->channelscale[2]; + + rotate[0] = pose->channeloffset[3]; + if( pose->mask & 0x008) + rotate[0] += *framedata++ * pose->channelscale[3]; + rotate[1] = pose->channeloffset[4]; + if( pose->mask & 0x010) + rotate[1] += *framedata++ * pose->channelscale[4]; + rotate[2] = pose->channeloffset[5]; + if( pose->mask & 0x020) + rotate[2] += *framedata++ * pose->channelscale[5]; + rotate[3] = pose->channeloffset[6]; + if( pose->mask & 0x040) + rotate[3] += *framedata++ * pose->channelscale[6]; + + scale[0] = pose->channeloffset[7]; + if( pose->mask & 0x080) + scale[0] += *framedata++ * pose->channelscale[7]; + scale[1] = pose->channeloffset[8]; + if( pose->mask & 0x100) + scale[1] += *framedata++ * pose->channelscale[8]; + scale[2] = pose->channeloffset[9]; + if( pose->mask & 0x200) + scale[2] += *framedata++ * pose->channelscale[9]; + + // construct transformation matrix + JointToMatrix( rotate, scale, translate, mat1 ); + + if( pose->parent >= 0 ) { + Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, + mat1, mat2 ); + } else { + Com_Memcpy( mat2, mat1, sizeof(mat1) ); + } + + Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); + mat += 12; + } + } } // copy model bounds @@ -735,6 +912,15 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na bounds++; } } + else if( header->num_meshes && header->num_frames == 0 ) + { + mat = iqmData->bounds; + + ClearBounds( &iqmData->bounds[0], &iqmData->bounds[3] ); + for ( i = 0 ; i < header->num_vertexes ; i++ ) { + AddPointToBounds( &iqmData->positions[i*3], &iqmData->bounds[0], &iqmData->bounds[3] ); + } + } return qtrue; } @@ -903,9 +1089,9 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { for(j = 0; j < skin->numSurfaces; j++) { - if (!strcmp(skin->surfaces[j]->name, surface->name)) + if (!strcmp(skin->surfaces[j].name, surface->name)) { - shader = skin->surfaces[j]->shader; + shader = skin->surfaces[j].shader; break; } } @@ -947,18 +1133,6 @@ static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, int *joint = data->jointParents; int i; - if ( data->num_poses == 0 ) { - for( i = 0; i < data->num_joints; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - identityMatrix, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) ); - } - } - return; - } - if ( oldframe == frame ) { mat1 = data->poseMats + 12 * data->num_poses * frame; for( i = 0; i < data->num_poses; i++, joint++ ) { @@ -983,7 +1157,7 @@ static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, } else { InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, mat ); + backlerp, mat + 12*i ); } } } @@ -994,6 +1168,11 @@ static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, float *mat1; int i; + if ( data->num_poses == 0 ) { + Com_Memcpy( mat, data->jointMats, data->num_joints * 12 * sizeof(float) ); + return; + } + ComputePoseMats( data, frame, oldframe, backlerp, mat ); for( i = 0; i < data->num_joints; i++ ) { @@ -1002,7 +1181,7 @@ static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, Com_Memcpy(outmat, mat1, sizeof(outmat)); - Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 ); + Matrix34Multiply( outmat, data->jointMats + 12*i, mat1 ); } } @@ -1017,9 +1196,15 @@ Compute vertices for this model surface void RB_IQMSurfaceAnim( surfaceType_t *surface ) { srfIQModel_t *surf = (srfIQModel_t *)surface; iqmData_t *data = surf->data; - float jointMats[IQM_MAX_JOINTS * 12]; + float poseMats[IQM_MAX_JOINTS * 12]; + float influenceVtxMat[SHADER_MAX_VERTEXES * 12]; + float influenceNrmMat[SHADER_MAX_VERTEXES * 9]; int i; + float *xyz; + float *normal; + float *texCoords; + byte *color; vec4_t *outXYZ; vec4_t *outNormal; vec2_t (*outTexCoord)[2]; @@ -1035,102 +1220,165 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 ); + xyz = &data->positions[surf->first_vertex * 3]; + normal = &data->normals[surf->first_vertex * 3]; + texCoords = &data->texcoords[surf->first_vertex * 2]; + + if ( data->colors ) { + color = &data->colors[surf->first_vertex * 4]; + } else { + color = NULL; + } + outXYZ = &tess.xyz[tess.numVertexes]; outNormal = &tess.normal[tess.numVertexes]; outTexCoord = &tess.texCoords[tess.numVertexes]; outColor = &tess.vertexColors[tess.numVertexes]; - // compute interpolated joint matrices if ( data->num_poses > 0 ) { - ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); - } + // compute interpolated joint matrices + ComputePoseMats( data, frame, oldframe, backlerp, poseMats ); - // transform vertexes and fill other data - for( i = 0; i < surf->num_vertexes; - i++, outXYZ++, outNormal++, outTexCoord++, outColor++ ) { - int j, k; - float vtxMat[12]; - float nrmMat[9]; - int vtx = i + surf->first_vertex; - float blendWeights[4]; - int numWeights; + // compute vertex blend influence matricies + for( i = 0; i < surf->num_influences; i++ ) { + int influence = surf->first_influence + i; + float *vtxMat = &influenceVtxMat[12*i]; + float *nrmMat = &influenceNrmMat[9*i]; + int j; + float blendWeights[4]; + int numWeights; - for ( numWeights = 0; numWeights < 4; numWeights++ ) { - if ( data->blendWeightsType == IQM_FLOAT ) - blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; - else - blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; + for ( numWeights = 0; numWeights < 4; numWeights++ ) { + if ( data->blendWeightsType == IQM_FLOAT ) + blendWeights[numWeights] = data->influenceBlendWeights.f[4*influence + numWeights]; + else + blendWeights[numWeights] = (float)data->influenceBlendWeights.b[4*influence + numWeights] / 255.0f; - if ( blendWeights[numWeights] <= 0 ) - break; - } + if ( blendWeights[numWeights] <= 0.0f ) + break; + } - if ( data->num_poses == 0 || numWeights == 0 ) { - // no blend joint, use identity matrix. - Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); - } else { - // compute the vertex matrix by blending the up to - // four blend weights - Com_Memset( vtxMat, 0, 12 * sizeof (float) ); - for( j = 0; j < numWeights; j++ ) { - for( k = 0; k < 12; k++ ) { - vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + if ( numWeights == 0 ) { + // no blend joint, use identity matrix. + vtxMat[0] = identityMatrix[0]; + vtxMat[1] = identityMatrix[1]; + vtxMat[2] = identityMatrix[2]; + vtxMat[3] = identityMatrix[3]; + vtxMat[4] = identityMatrix[4]; + vtxMat[5] = identityMatrix[5]; + vtxMat[6] = identityMatrix[6]; + vtxMat[7] = identityMatrix[7]; + vtxMat[8] = identityMatrix[8]; + vtxMat[9] = identityMatrix[9]; + vtxMat[10] = identityMatrix[10]; + vtxMat[11] = identityMatrix[11]; + } else { + // compute the vertex matrix by blending the up to + // four blend weights + vtxMat[0] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 0]; + vtxMat[1] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 1]; + vtxMat[2] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 2]; + vtxMat[3] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 3]; + vtxMat[4] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 4]; + vtxMat[5] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 5]; + vtxMat[6] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 6]; + vtxMat[7] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 7]; + vtxMat[8] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 8]; + vtxMat[9] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 9]; + vtxMat[10] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 10]; + vtxMat[11] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 11]; + + for( j = 1; j < numWeights; j++ ) { + vtxMat[0] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 0]; + vtxMat[1] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 1]; + vtxMat[2] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 2]; + vtxMat[3] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 3]; + vtxMat[4] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 4]; + vtxMat[5] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 5]; + vtxMat[6] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 6]; + vtxMat[7] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 7]; + vtxMat[8] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 8]; + vtxMat[9] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 9]; + vtxMat[10] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 10]; + vtxMat[11] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 11]; } } + + // compute the normal matrix as transpose of the adjoint + // of the vertex matrix + nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9]; + nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10]; + nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8]; + nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10]; + nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8]; + nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9]; + nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5]; + nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6]; + nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4]; } - // compute the normal matrix as transpose of the adjoint - // of the vertex matrix - nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9]; - nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10]; - nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8]; - nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10]; - nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8]; - nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9]; - nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5]; - nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6]; - nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4]; + // transform vertexes and fill other data + for( i = 0; i < surf->num_vertexes; + i++, xyz+=3, normal+=3, texCoords+=2, + outXYZ++, outNormal++, outTexCoord++ ) { + int influence = data->influences[surf->first_vertex + i] - surf->first_influence; + float *vtxMat = &influenceVtxMat[12*influence]; + float *nrmMat = &influenceNrmMat[9*influence]; - (*outTexCoord)[0][0] = data->texcoords[2*vtx + 0]; - (*outTexCoord)[0][1] = data->texcoords[2*vtx + 1]; - (*outTexCoord)[1][0] = (*outTexCoord)[0][0]; - (*outTexCoord)[1][1] = (*outTexCoord)[0][1]; + (*outTexCoord)[0][0] = texCoords[0]; + (*outTexCoord)[0][1] = texCoords[1]; - (*outXYZ)[0] = - vtxMat[ 0] * data->positions[3*vtx+0] + - vtxMat[ 1] * data->positions[3*vtx+1] + - vtxMat[ 2] * data->positions[3*vtx+2] + - vtxMat[ 3]; - (*outXYZ)[1] = - vtxMat[ 4] * data->positions[3*vtx+0] + - vtxMat[ 5] * data->positions[3*vtx+1] + - vtxMat[ 6] * data->positions[3*vtx+2] + - vtxMat[ 7]; - (*outXYZ)[2] = - vtxMat[ 8] * data->positions[3*vtx+0] + - vtxMat[ 9] * data->positions[3*vtx+1] + - vtxMat[10] * data->positions[3*vtx+2] + - vtxMat[11]; - (*outXYZ)[3] = 1.0f; + (*outXYZ)[0] = + vtxMat[ 0] * xyz[0] + + vtxMat[ 1] * xyz[1] + + vtxMat[ 2] * xyz[2] + + vtxMat[ 3]; + (*outXYZ)[1] = + vtxMat[ 4] * xyz[0] + + vtxMat[ 5] * xyz[1] + + vtxMat[ 6] * xyz[2] + + vtxMat[ 7]; + (*outXYZ)[2] = + vtxMat[ 8] * xyz[0] + + vtxMat[ 9] * xyz[1] + + vtxMat[10] * xyz[2] + + vtxMat[11]; - (*outNormal)[0] = - nrmMat[ 0] * data->normals[3*vtx+0] + - nrmMat[ 1] * data->normals[3*vtx+1] + - nrmMat[ 2] * data->normals[3*vtx+2]; - (*outNormal)[1] = - nrmMat[ 3] * data->normals[3*vtx+0] + - nrmMat[ 4] * data->normals[3*vtx+1] + - nrmMat[ 5] * data->normals[3*vtx+2]; - (*outNormal)[2] = - nrmMat[ 6] * data->normals[3*vtx+0] + - nrmMat[ 7] * data->normals[3*vtx+1] + - nrmMat[ 8] * data->normals[3*vtx+2]; - (*outNormal)[3] = 0.0f; + (*outNormal)[0] = + nrmMat[ 0] * normal[0] + + nrmMat[ 1] * normal[1] + + nrmMat[ 2] * normal[2]; + (*outNormal)[1] = + nrmMat[ 3] * normal[0] + + nrmMat[ 4] * normal[1] + + nrmMat[ 5] * normal[2]; + (*outNormal)[2] = + nrmMat[ 6] * normal[0] + + nrmMat[ 7] * normal[1] + + nrmMat[ 8] * normal[2]; + } + } else { + // copy vertexes and fill other data + for( i = 0; i < surf->num_vertexes; + i++, xyz+=3, normal+=3, texCoords+=2, + outXYZ++, outNormal++, outTexCoord++ ) { + (*outTexCoord)[0][0] = texCoords[0]; + (*outTexCoord)[0][1] = texCoords[1]; - (*outColor)[0] = data->colors[4*vtx+0]; - (*outColor)[1] = data->colors[4*vtx+1]; - (*outColor)[2] = data->colors[4*vtx+2]; - (*outColor)[3] = data->colors[4*vtx+3]; + (*outXYZ)[0] = xyz[0]; + (*outXYZ)[1] = xyz[1]; + (*outXYZ)[2] = xyz[2]; + + (*outNormal)[0] = normal[0]; + (*outNormal)[1] = normal[1]; + (*outNormal)[2] = normal[2]; + } + } + + if ( color ) { + Com_Memcpy( outColor, color, surf->num_vertexes * sizeof( outColor[0] ) ); + } else { + Com_Memset( outColor, 0, surf->num_vertexes * sizeof( outColor[0] ) ); } tri = data->triangles + 3 * surf->first_triangle; @@ -1152,7 +1400,7 @@ int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, float frac, const char *tagName ) { float jointMats[IQM_MAX_JOINTS * 12]; int joint; - char *names = data->names; + char *names = data->jointNames; // get joint number by reading the joint names for( joint = 0; joint < data->num_joints; joint++ ) { diff --git a/code/renderergl1/tr_scene.c b/code/renderergl1/tr_scene.c index 5d7a3dd1..639f4e2d 100644 --- a/code/renderergl1/tr_scene.c +++ b/code/renderergl1/tr_scene.c @@ -344,7 +344,7 @@ void RE_RenderScene( const refdef_t *fd ) { // derived info - tr.refdef.floatTime = tr.refdef.time * 0.001f; + tr.refdef.floatTime = tr.refdef.time * 0.001; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData->drawSurfs; diff --git a/code/renderergl1/tr_shade.c b/code/renderergl1/tr_shade.c index 9bdf1e39..7ea78d13 100644 --- a/code/renderergl1/tr_shade.c +++ b/code/renderergl1/tr_shade.c @@ -22,9 +22,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_shade.c #include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif /* @@ -163,7 +160,7 @@ instead of using the single glDrawElements call that may be inefficient without compiled vertex arrays. ================== */ -static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) { +void R_DrawElements( int numIndexes, const glIndex_t *indexes ) { int primitives; primitives = r_primitives->integer; @@ -218,7 +215,7 @@ R_BindAnimatedImage ================= */ static void R_BindAnimatedImage( textureBundle_t *bundle ) { - int index; + int64_t index; if ( bundle->isVideoMap ) { ri.CIN_RunCinematic(bundle->videoMapHandle); @@ -233,13 +230,18 @@ static void R_BindAnimatedImage( textureBundle_t *bundle ) { // it is necessary to do this messy calc to make sure animations line up // exactly with waveforms of the same frequency - index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); + index = tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE; index >>= FUNCTABLE_SIZE2; if ( index < 0 ) { index = 0; // may happen with shader time offsets } - index %= bundle->numImageAnimations; + + // Windows x86 doesn't load renderer DLL with 64 bit modulus + //index %= bundle->numImageAnimations; + while ( index >= bundle->numImageAnimations ) { + index -= bundle->numImageAnimations; + } GL_Bind( bundle->image[ index ] ); } @@ -402,189 +404,6 @@ ProjectDlightTexture Perform dynamic lighting with another rendering pass =================== */ -#if idppc_altivec -static void ProjectDlightTexture_altivec( void ) { - int i, l; - vec_t origin0, origin1, origin2; - float texCoords0, texCoords1; - vector float floatColorVec0, floatColorVec1; - vector float modulateVec, colorVec, zero; - vector short colorShort; - vector signed int colorInt; - vector unsigned char floatColorVecPerm, modulatePerm, colorChar; - vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff); - float *texCoords; - byte *colors; - byte clipBits[SHADER_MAX_VERTEXES]; - float texCoordsArray[SHADER_MAX_VERTEXES][2]; - byte colorArray[SHADER_MAX_VERTEXES][4]; - glIndex_t hitIndexes[SHADER_MAX_INDEXES]; - int numIndexes; - float scale; - float radius; - vec3_t floatColor; - float modulate = 0.0f; - - if ( !backEnd.refdef.num_dlights ) { - return; - } - - // There has to be a better way to do this so that floatColor - // and/or modulate are already 16-byte aligned. - floatColorVecPerm = vec_lvsl(0,(float *)floatColor); - modulatePerm = vec_lvsl(0,(float *)&modulate); - modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0); - zero = (vector float)vec_splat_s8(0); - - for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { - dlight_t *dl; - - if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light - } - texCoords = texCoordsArray[0]; - colors = colorArray[0]; - - dl = &backEnd.refdef.dlights[l]; - origin0 = dl->transformed[0]; - origin1 = dl->transformed[1]; - origin2 = dl->transformed[2]; - radius = dl->radius; - scale = 1.0f / radius; - - if(r_greyscale->integer) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = floatColor[1] = floatColor[2] = luminance; - } - else if(r_greyscale->value) - { - float luminance; - - luminance = LUMA(dl->color[0], dl->color[1], dl->color[2]) * 255.0f; - floatColor[0] = LERP(dl->color[0] * 255.0f, luminance, r_greyscale->value); - floatColor[1] = LERP(dl->color[1] * 255.0f, luminance, r_greyscale->value); - floatColor[2] = LERP(dl->color[2] * 255.0f, luminance, r_greyscale->value); - } - else - { - floatColor[0] = dl->color[0] * 255.0f; - floatColor[1] = dl->color[1] * 255.0f; - floatColor[2] = dl->color[2] * 255.0f; - } - floatColorVec0 = vec_ld(0, floatColor); - floatColorVec1 = vec_ld(11, floatColor); - floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm); - for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) { - int clip = 0; - vec_t dist0, dist1, dist2; - - dist0 = origin0 - tess.xyz[i][0]; - dist1 = origin1 - tess.xyz[i][1]; - dist2 = origin2 - tess.xyz[i][2]; - - backEnd.pc.c_dlightVertexes++; - - texCoords0 = 0.5f + dist0 * scale; - texCoords1 = 0.5f + dist1 * scale; - - if( !r_dlightBacks->integer && - // dist . tess.normal[i] - ( dist0 * tess.normal[i][0] + - dist1 * tess.normal[i][1] + - dist2 * tess.normal[i][2] ) < 0.0f ) { - clip = 63; - } else { - if ( texCoords0 < 0.0f ) { - clip |= 1; - } else if ( texCoords0 > 1.0f ) { - clip |= 2; - } - if ( texCoords1 < 0.0f ) { - clip |= 4; - } else if ( texCoords1 > 1.0f ) { - clip |= 8; - } - texCoords[0] = texCoords0; - texCoords[1] = texCoords1; - - // modulate the strength based on the height and color - if ( dist2 > radius ) { - clip |= 16; - modulate = 0.0f; - } else if ( dist2 < -radius ) { - clip |= 32; - modulate = 0.0f; - } else { - dist2 = Q_fabs(dist2); - if ( dist2 < radius * 0.5f ) { - modulate = 1.0f; - } else { - modulate = 2.0f * (radius - dist2) * scale; - } - } - } - clipBits[i] = clip; - - modulateVec = vec_ld(0,(float *)&modulate); - modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm); - colorVec = vec_madd(floatColorVec0,modulateVec,zero); - colorInt = vec_cts(colorVec,0); // RGBx - colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx - colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx - colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 - vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color - } - - // build a list of triangles that need light - numIndexes = 0; - for ( i = 0 ; i < tess.numIndexes ; i += 3 ) { - int a, b, c; - - a = tess.indexes[i]; - b = tess.indexes[i+1]; - c = tess.indexes[i+2]; - if ( clipBits[a] & clipBits[b] & clipBits[c] ) { - continue; // not lighted - } - hitIndexes[numIndexes] = a; - hitIndexes[numIndexes+1] = b; - hitIndexes[numIndexes+2] = c; - numIndexes += 3; - } - - if ( !numIndexes ) { - continue; - } - - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] ); - - qglEnableClientState( GL_COLOR_ARRAY ); - qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray ); - - GL_Bind( tr.dlightImage ); - // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light - // where they aren't rendered - if ( dl->additive ) { - GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - else { - GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - } - R_DrawElements( numIndexes, hitIndexes ); - backEnd.pc.c_totalIndexes += numIndexes; - backEnd.pc.c_dlightIndexes += numIndexes; - } -} -#endif - - static void ProjectDlightTexture_scalar( void ) { int i, l; vec3_t origin; @@ -608,7 +427,7 @@ static void ProjectDlightTexture_scalar( void ) { dlight_t *dl; if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light + continue; // this surface definitely doesn't have any of this light } texCoords = texCoordsArray[0]; colors = colorArray[0]; @@ -740,7 +559,7 @@ static void ProjectDlightTexture_scalar( void ) { static void ProjectDlightTexture( void ) { #if idppc_altivec if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. + // must be in a separate translation unit or G3 systems will crash. ProjectDlightTexture_altivec(); return; } diff --git a/code/renderergl1/tr_shade_calc.c b/code/renderergl1/tr_shade_calc.c index ae33c7fb..455424ed 100644 --- a/code/renderergl1/tr_shade_calc.c +++ b/code/renderergl1/tr_shade_calc.c @@ -22,12 +22,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_shade_calc.c #include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif -#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ri.ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) +#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ( (int64_t) ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) static float *TableForFunc( genFunc_t func ) { @@ -206,12 +203,12 @@ void RB_CalcBulgeVertexes( deformStage_t *ds ) { const float *st = ( const float * ) tess.texCoords[0]; float *xyz = ( float * ) tess.xyz; float *normal = ( float * ) tess.normal; - float now; + double now; - now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f; + now = backEnd.refdef.time * 0.001 * ds->bulgeSpeed; for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) { - int off; + int64_t off; float scale; off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); @@ -345,7 +342,7 @@ static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) { ===================== AutospriteDeform -Assuming all the triangles for this shader are independant +Assuming all the triangles for this shader are independent quads, rebuild them as forward facing sprites ===================== */ @@ -920,7 +917,7 @@ void RB_CalcEnvironmentTexCoords( float *st ) void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st ) { int i; - float now; + double now; now = ( wf->phase + tess.shaderTime * wf->frequency ); @@ -929,8 +926,8 @@ void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st ) float s = st[0]; float t = st[1]; - st[0] = s + tr.sinTable[ ( ( int ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; - st[1] = t + tr.sinTable[ ( ( int ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; + st[0] = s + tr.sinTable[ ( ( int64_t ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; + st[1] = t + tr.sinTable[ ( ( int64_t ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude; } } @@ -954,8 +951,8 @@ void RB_CalcScaleTexCoords( const float scale[2], float *st ) void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st ) { int i; - float timeScale = tess.shaderTime; - float adjustedScrollS, adjustedScrollT; + double timeScale = tess.shaderTime; + double adjustedScrollS, adjustedScrollT; adjustedScrollS = scrollSpeed[0] * timeScale; adjustedScrollT = scrollSpeed[1] * timeScale; @@ -994,9 +991,9 @@ void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st ) */ void RB_CalcRotateTexCoords( float degsPerSecond, float *st ) { - float timeScale = tess.shaderTime; - float degs; - int index; + double timeScale = tess.shaderTime; + double degs; + int64_t index; float sinValue, cosValue; texModInfo_t tmi; @@ -1082,77 +1079,6 @@ void RB_CalcSpecularAlpha( unsigned char *alphas ) { ** ** The basic vertex lighting calc */ -#if idppc_altivec -static void RB_CalcDiffuseColor_altivec( unsigned char *colors ) -{ - int i; - float *v, *normal; - trRefEntity_t *ent; - int ambientLightInt; - vec3_t lightDir; - int numVertexes; - vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff); - vector float ambientLightVec; - vector float directedLightVec; - vector float lightDirVec; - vector float normalVec0, normalVec1; - vector float incomingVec0, incomingVec1, incomingVec2; - vector float zero, jVec; - vector signed int jVecInt; - vector signed short jVecShort; - vector unsigned char jVecChar, normalPerm; - ent = backEnd.currentEntity; - ambientLightInt = ent->ambientLightInt; - // A lot of this could be simplified if we made sure - // entities light info was 16-byte aligned. - jVecChar = vec_lvsl(0, ent->ambientLight); - ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight); - jVec = vec_ld(11, (vector float *)ent->ambientLight); - ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar); - - jVecChar = vec_lvsl(0, ent->directedLight); - directedLightVec = vec_ld(0,(vector float *)ent->directedLight); - jVec = vec_ld(11,(vector float *)ent->directedLight); - directedLightVec = vec_perm(directedLightVec,jVec,jVecChar); - - jVecChar = vec_lvsl(0, ent->lightDir); - lightDirVec = vec_ld(0,(vector float *)ent->lightDir); - jVec = vec_ld(11,(vector float *)ent->lightDir); - lightDirVec = vec_perm(lightDirVec,jVec,jVecChar); - - zero = (vector float)vec_splat_s8(0); - VectorCopy( ent->lightDir, lightDir ); - - v = tess.xyz[0]; - normal = tess.normal[0]; - - normalPerm = vec_lvsl(0,normal); - numVertexes = tess.numVertexes; - for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) { - normalVec0 = vec_ld(0,(vector float *)normal); - normalVec1 = vec_ld(11,(vector float *)normal); - normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm); - incomingVec0 = vec_madd(normalVec0, lightDirVec, zero); - incomingVec1 = vec_sld(incomingVec0,incomingVec0,4); - incomingVec2 = vec_add(incomingVec0,incomingVec1); - incomingVec1 = vec_sld(incomingVec1,incomingVec1,4); - incomingVec2 = vec_add(incomingVec2,incomingVec1); - incomingVec0 = vec_splat(incomingVec2,0); - incomingVec0 = vec_max(incomingVec0,zero); - normalPerm = vec_lvsl(12,normal); - jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec); - jVecInt = vec_cts(jVec,0); // RGBx - jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx - jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx - jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255 - vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color - } -} -#endif - static void RB_CalcDiffuseColor_scalar( unsigned char *colors ) { int i, j; @@ -1206,7 +1132,7 @@ void RB_CalcDiffuseColor( unsigned char *colors ) { #if idppc_altivec if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. + // must be in a separate translation unit or G3 systems will crash. RB_CalcDiffuseColor_altivec( colors ); return; } diff --git a/code/renderergl1/tr_shader.c b/code/renderergl1/tr_shader.c index c931326f..2384a118 100644 --- a/code/renderergl1/tr_shader.c +++ b/code/renderergl1/tr_shader.c @@ -687,6 +687,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) // else if ( !Q_stricmp( token, "animMap" ) ) { + int totalImages = 0; + token = COM_ParseExt( text, qfalse ); if ( !token[0] ) { @@ -721,6 +723,12 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) } stage->bundle[0].numImageAnimations++; } + totalImages++; + } + + if ( totalImages > MAX_IMAGE_ANIMATIONS ) { + ri.Printf( PRINT_WARNING, "WARNING: ignoring excess images for 'animMap' (found %d, max is %d) in shader '%s'\n", + totalImages, MAX_IMAGE_ANIMATIONS, shader.name ); } } else if ( !Q_stricmp( token, "videoMap" ) ) @@ -735,6 +743,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) if (stage->bundle[0].videoMapHandle != -1) { stage->bundle[0].isVideoMap = qtrue; stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle]; + } else { + ri.Printf( PRINT_WARNING, "WARNING: could not load '%s' for 'videoMap' keyword in shader '%s'\n", token, shader.name ); } } // @@ -2078,7 +2088,7 @@ static shader_t *GeneratePermanentShader( void ) { VertexLightingCollapse If vertex lighting is enabled, only render a single -pass, trying to guess which is the correct one to best aproximate +pass, trying to guess which is the correct one to best approximate what it is supposed to look like. ================= */ @@ -2483,18 +2493,18 @@ be defined for every single image used in the game, three default shader behaviors can be auto-created for any image: If lightmapIndex == LIGHTMAP_NONE, then the image will have -dynamic diffuse lighting applied to it, as apropriate for most +dynamic diffuse lighting applied to it, as appropriate for most entity skin surfaces. If lightmapIndex == LIGHTMAP_2D, then the image will be used for 2D rendering unless an explicit shader is found If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use -the vertex rgba modulate values, as apropriate for misc_model +the vertex rgba modulate values, as appropriate for misc_model pre-lit surfaces. Other lightmapIndex values will have a lightmap stage created -and src*dest blending applied with the texture, as apropriate for +and src*dest blending applied with the texture, as appropriate for most world construction surfaces. =============== @@ -2541,7 +2551,7 @@ shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImag InitShader( strippedName, lightmapIndex ); - // FIXME: set these "need" values apropriately + // FIXME: set these "need" values appropriately shader.needsNormal = qtrue; shader.needsST1 = qtrue; shader.needsST2 = qtrue; @@ -2679,7 +2689,7 @@ qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_ InitShader( name, lightmapIndex ); - // FIXME: set these "need" values apropriately + // FIXME: set these "need" values appropriately shader.needsNormal = qtrue; shader.needsST1 = qtrue; shader.needsST2 = qtrue; diff --git a/code/renderergl1/tr_sky.c b/code/renderergl1/tr_sky.c index daa5ff12..1d12e924 100644 --- a/code/renderergl1/tr_sky.c +++ b/code/renderergl1/tr_sky.c @@ -769,6 +769,7 @@ void RB_StageIteratorSky( void ) { qglPushMatrix (); GL_State( 0 ); + GL_Cull( CT_FRONT_SIDED ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); DrawSkyBox( tess.shader ); diff --git a/code/renderergl1/tr_surface.c b/code/renderergl1/tr_surface.c index 79852f05..41e72738 100644 --- a/code/renderergl1/tr_surface.c +++ b/code/renderergl1/tr_surface.c @@ -21,9 +21,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // tr_surf.c #include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif /* @@ -557,19 +554,19 @@ static void RB_SurfaceLightningBolt( void ) { * The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0) * This means that we don't have to worry about zero length or enormously long vectors. */ -static void VectorArrayNormalize(vec4_t *normals, unsigned int count) +void VectorArrayNormalize(vec4_t *normals, unsigned int count) { // assert(count); #if idppc { - register float half = 0.5; - register float one = 1.0; + float half = 0.5; + float one = 1.0; float *components = (float *)normals; // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson - // refinement step to get a little more precision. This seems to yeild results + // refinement step to get a little more precision. This seems to yield results // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5). // (That is, for the given input range of about 0.6 to 2.0). do { @@ -612,136 +609,6 @@ static void VectorArrayNormalize(vec4_t *normals, unsigned int count) /* ** LerpMeshVertexes */ -#if idppc_altivec -static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp) -{ - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale QALIGN(16); - float newXyzScale QALIGN(16); - float oldNormalScale QALIGN(16); - float newNormalScale QALIGN(16); - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - vector signed short newNormalsVec0; - vector signed short newNormalsVec1; - vector signed int newNormalsIntVec; - vector float newNormalsFloatVec; - vector float newXyzScaleVec; - vector unsigned char newNormalsLoadPermute; - vector unsigned char newNormalsStorePermute; - vector float zero; - - newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec); - newXyzScaleVec = *(vector float *)&newXyzScale; - newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute); - newXyzScaleVec = vec_splat(newXyzScaleVec,0); - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - zero = (vector float)vec_splat_s8(0); - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - newNormalsVec0 = vec_ld(0,newXyz); - newNormalsVec1 = vec_ld(16,newXyz); - newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute); - newNormalsIntVec = vec_unpackh(newNormalsVec0); - newNormalsFloatVec = vec_ctf(newNormalsIntVec,0); - newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero); - newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute); - //outXyz[0] = newXyz[0] * newXyzScale; - //outXyz[1] = newXyz[1] * newXyzScale; - //outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - vec_ste(newNormalsFloatVec,0,outXyz); - vec_ste(newNormalsFloatVec,4,outXyz); - vec_ste(newNormalsFloatVec,8,outXyz); - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -} -#endif - static void LerpMeshVertexes_scalar(md3Surface_t *surf, float backlerp) { short *oldXyz, *newXyz, *oldNormals, *newNormals; @@ -844,7 +711,7 @@ static void LerpMeshVertexes(md3Surface_t *surf, float backlerp) { #if idppc_altivec if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. + // must be in a separate translation unit or G3 systems will crash. LerpMeshVertexes_altivec( surf, backlerp ); return; } diff --git a/code/renderergl1/tr_world.c b/code/renderergl1/tr_world.c index 0a2743f9..88eca6d8 100644 --- a/code/renderergl1/tr_world.c +++ b/code/renderergl1/tr_world.c @@ -353,10 +353,10 @@ void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { R_RecursiveWorldNode ================ */ -static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits ) { +static void R_RecursiveWorldNode( mnode_t *node, unsigned int planeBits, unsigned int dlightBits ) { do { - int newDlights[2]; + unsigned int newDlights[2]; // if the node wasn't marked as potentially visible, exit if (node->visframe != tr.visCount) { @@ -661,8 +661,8 @@ void R_AddWorldSurfaces (void) { ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] ); // perform frustum culling and add all the potentially visible surfaces - if ( tr.refdef.num_dlights > 32 ) { - tr.refdef.num_dlights = 32 ; + if ( tr.refdef.num_dlights > MAX_DLIGHTS ) { + tr.refdef.num_dlights = MAX_DLIGHTS ; } - R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1 ); + R_RecursiveWorldNode( tr.world->nodes, 15, ( 1ULL << tr.refdef.num_dlights ) - 1 ); } diff --git a/code/renderergl2/glsl/bokeh_fp.glsl b/code/renderergl2/glsl/bokeh_fp.glsl index d08816ae..d2ec5b4b 100644 --- a/code/renderergl2/glsl/bokeh_fp.glsl +++ b/code/renderergl2/glsl/bokeh_fp.glsl @@ -11,7 +11,15 @@ void main() vec2 tc; #if 0 - float c[7] = float[7](1.0, 0.9659258263, 0.8660254038, 0.7071067812, 0.5, 0.2588190451, 0.0); + float c[7]; + + c[0] = 1.0; + c[1] = 0.9659258263; + c[2] = 0.8660254038; + c[3] = 0.7071067812; + c[4] = 0.5; + c[5] = 0.2588190451; + c[6] = 0.0; tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[6]); color = texture2D(u_TextureMap, tc); tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[5]); color += texture2D(u_TextureMap, tc); @@ -44,7 +52,13 @@ void main() gl_FragColor = color * 0.04166667 * u_Color; #endif - float c[5] = float[5](1.0, 0.9238795325, 0.7071067812, 0.3826834324, 0.0); + float c[5]; + + c[0] = 1.0; + c[1] = 0.9238795325; + c[2] = 0.7071067812; + c[3] = 0.3826834324; + c[4] = 0.0; tc = var_TexCoords + u_InvTexRes * vec2( c[0], c[4]); color = texture2D(u_TextureMap, tc); tc = var_TexCoords + u_InvTexRes * vec2( c[1], c[3]); color += texture2D(u_TextureMap, tc); diff --git a/code/renderergl2/glsl/calclevels4x_fp.glsl b/code/renderergl2/glsl/calclevels4x_fp.glsl index 8246c4b3..c2597681 100644 --- a/code/renderergl2/glsl/calclevels4x_fp.glsl +++ b/code/renderergl2/glsl/calclevels4x_fp.glsl @@ -56,5 +56,5 @@ void main() current.y *= 0.0625; #endif - gl_FragColor = vec4(current, 1.0f); + gl_FragColor = vec4(current, 1.0); } diff --git a/code/renderergl2/glsl/depthblur_fp.glsl b/code/renderergl2/glsl/depthblur_fp.glsl index 15f7be27..d63df88a 100644 --- a/code/renderergl2/glsl/depthblur_fp.glsl +++ b/code/renderergl2/glsl/depthblur_fp.glsl @@ -4,29 +4,44 @@ uniform sampler2D u_ScreenDepthMap; uniform vec4 u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height varying vec2 var_ScreenTex; +//float gauss[8] = float[8](0.17, 0.17, 0.16, 0.14, 0.12, 0.1, 0.08, 0.06); //float gauss[5] = float[5](0.30, 0.23, 0.097, 0.024, 0.0033); -float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044); +//float gauss[4] = float[4](0.40, 0.24, 0.054, 0.0044); //float gauss[3] = float[3](0.60, 0.19, 0.0066); #define BLUR_SIZE 4 +#if !defined(USE_DEPTH) +//#define USE_GAUSS +#endif + float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear) { - float sampleZDivW = texture2D(depthMap, tex).r; - return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); + float sampleZDivW = texture2D(depthMap, tex).r; + return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); } -vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar) +vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFarDivZNear, float zFar, vec2 scale) { - vec2 scale = u_ViewInfo.zw; + float gauss[4]; + + gauss[0] = 0.40; + gauss[1] = 0.24; + gauss[2] = 0.054; + gauss[3] = 0.0044; + +#if defined(USE_DEPTH) + float depthCenter = getLinearDepth(depthMap, tex, zFarDivZNear); + vec2 slope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y)); + scale /= clamp(zFarDivZNear * depthCenter / 32.0, 1.0, 2.0); +#endif #if defined(USE_HORIZONTAL_BLUR) - vec2 direction = vec2(1.0, 0.0) * scale; + vec2 direction = vec2(scale.x * 2.0, 0.0); + vec2 nudge = vec2(0.0, scale.y * 0.5); #else // if defined(USE_VERTICAL_BLUR) - vec2 direction = vec2(0.0, 1.0) * scale; + vec2 direction = vec2(0.0, scale.y * 2.0); + vec2 nudge = vec2(-scale.x * 0.5, 0.0); #endif - - float depthCenter = zFar * getLinearDepth(depthMap, tex, zFarDivZNear); - vec2 centerSlope = vec2(dFdx(depthCenter), dFdy(depthCenter)) / vec2(dFdx(tex.x), dFdy(tex.y)); #if defined(USE_GAUSS) vec4 result = texture2D(imageMap, tex) * gauss[0]; @@ -36,33 +51,38 @@ vec4 depthGaussian1D(sampler2D imageMap, sampler2D depthMap, vec2 tex, float zFa float total = 1.0; #endif + float zLimit = 5.0 / zFar; int i, j; for (i = 0; i < 2; i++) { for (j = 1; j < BLUR_SIZE; j++) { - vec2 offset = direction * j; - float depthSample = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear); - float depthExpected = depthCenter + dot(centerSlope, offset); - if(abs(depthSample - depthExpected) < 5.0) - { -#if defined(USE_GAUSS) - result += texture2D(imageMap, tex + offset) * gauss[j]; - total += gauss[j]; + vec2 offset = direction * (float(j) - 0.25) + nudge; +#if defined(USE_DEPTH) + float depthSample = getLinearDepth(depthMap, tex + offset, zFarDivZNear); + float depthExpected = depthCenter + dot(slope, offset); + float useSample = float(abs(depthSample - depthExpected) < zLimit); #else - result += texture2D(imageMap, tex + offset); - total += 1.0; + float useSample = 1.0; #endif - } +#if defined(USE_GAUSS) + result += texture2D(imageMap, tex + offset) * (gauss[j] * useSample); + total += gauss[j] * useSample; +#else + result += texture2D(imageMap, tex + offset) * useSample; + total += useSample; +#endif + nudge = -nudge; } - + direction = -direction; - } - + nudge = -nudge; + } + return result / total; } void main() -{ - gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y); +{ + gl_FragColor = depthGaussian1D(u_ScreenImageMap, u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.zw); } diff --git a/code/renderergl2/glsl/depthblur_vp.glsl b/code/renderergl2/glsl/depthblur_vp.glsl index 9c46a79f..9c47660c 100644 --- a/code/renderergl2/glsl/depthblur_vp.glsl +++ b/code/renderergl2/glsl/depthblur_vp.glsl @@ -1,12 +1,16 @@ attribute vec4 attr_Position; attribute vec4 attr_TexCoord0; +uniform vec4 u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height + varying vec2 var_ScreenTex; void main() { gl_Position = attr_Position; - var_ScreenTex = attr_TexCoord0.xy; + vec2 wh = vec2(1.0) / u_ViewInfo.zw - vec2(1.0); + var_ScreenTex = (floor(attr_TexCoord0.xy * wh) + vec2(0.5)) * u_ViewInfo.zw; + //vec2 screenCoords = gl_Position.xy / gl_Position.w; //var_ScreenTex = screenCoords * 0.5 + 0.5; } diff --git a/code/renderergl2/glsl/dlight_fp.glsl b/code/renderergl2/glsl/dlight_fp.glsl index 8ffca5b9..41be0494 100644 --- a/code/renderergl2/glsl/dlight_fp.glsl +++ b/code/renderergl2/glsl/dlight_fp.glsl @@ -1,5 +1,7 @@ uniform sampler2D u_DiffuseMap; +uniform int u_AlphaTest; + varying vec2 var_Tex1; varying vec4 var_Color; @@ -8,5 +10,23 @@ void main() { vec4 color = texture2D(u_DiffuseMap, var_Tex1); - gl_FragColor = color * var_Color; + float alpha = color.a * var_Color.a; + if (u_AlphaTest == 1) + { + if (alpha == 0.0) + discard; + } + else if (u_AlphaTest == 2) + { + if (alpha >= 0.5) + discard; + } + else if (u_AlphaTest == 3) + { + if (alpha < 0.5) + discard; + } + + gl_FragColor.rgb = color.rgb * var_Color.rgb; + gl_FragColor.a = alpha; } diff --git a/code/renderergl2/glsl/fogpass_vp.glsl b/code/renderergl2/glsl/fogpass_vp.glsl index c8ec9a93..72ea0af6 100644 --- a/code/renderergl2/glsl/fogpass_vp.glsl +++ b/code/renderergl2/glsl/fogpass_vp.glsl @@ -6,6 +6,9 @@ attribute vec4 attr_TexCoord0; #if defined(USE_VERTEX_ANIMATION) attribute vec3 attr_Position2; attribute vec3 attr_Normal2; +#elif defined(USE_BONE_ANIMATION) +attribute vec4 attr_BoneIndexes; +attribute vec4 attr_BoneWeights; #endif uniform vec4 u_FogDistance; @@ -22,6 +25,8 @@ uniform mat4 u_ModelViewProjectionMatrix; #if defined(USE_VERTEX_ANIMATION) uniform float u_VertexLerp; +#elif defined(USE_BONE_ANIMATION) +uniform mat4 u_BoneMatrix[MAX_GLSL_BONES]; #endif uniform vec4 u_Color; @@ -102,6 +107,15 @@ void main() #if defined(USE_VERTEX_ANIMATION) vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); +#elif defined(USE_BONE_ANIMATION) + mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w; + mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz)); + + vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0)); + vec3 normal = normalize(nrmMat * attr_Normal); #else vec3 position = attr_Position; vec3 normal = attr_Normal; diff --git a/code/renderergl2/glsl/generic_fp.glsl b/code/renderergl2/glsl/generic_fp.glsl index 50db0785..c0a49407 100644 --- a/code/renderergl2/glsl/generic_fp.glsl +++ b/code/renderergl2/glsl/generic_fp.glsl @@ -1,5 +1,7 @@ uniform sampler2D u_DiffuseMap; +uniform int u_AlphaTest; + varying vec2 var_DiffuseTex; varying vec4 var_Color; @@ -8,5 +10,24 @@ varying vec4 var_Color; void main() { vec4 color = texture2D(u_DiffuseMap, var_DiffuseTex); - gl_FragColor = color * var_Color; + + float alpha = color.a * var_Color.a; + if (u_AlphaTest == 1) + { + if (alpha == 0.0) + discard; + } + else if (u_AlphaTest == 2) + { + if (alpha >= 0.5) + discard; + } + else if (u_AlphaTest == 3) + { + if (alpha < 0.5) + discard; + } + + gl_FragColor.rgb = color.rgb * var_Color.rgb; + gl_FragColor.a = alpha; } diff --git a/code/renderergl2/glsl/generic_vp.glsl b/code/renderergl2/glsl/generic_vp.glsl index bbe08e84..a0055263 100644 --- a/code/renderergl2/glsl/generic_vp.glsl +++ b/code/renderergl2/glsl/generic_vp.glsl @@ -4,6 +4,9 @@ attribute vec3 attr_Normal; #if defined(USE_VERTEX_ANIMATION) attribute vec3 attr_Position2; attribute vec3 attr_Normal2; +#elif defined(USE_BONE_ANIMATION) +attribute vec4 attr_BoneIndexes; +attribute vec4 attr_BoneWeights; #endif attribute vec4 attr_Color; @@ -54,6 +57,8 @@ uniform float u_PortalRange; #if defined(USE_VERTEX_ANIMATION) uniform float u_VertexLerp; +#elif defined(USE_BONE_ANIMATION) +uniform mat4 u_BoneMatrix[MAX_GLSL_BONES]; #endif varying vec2 var_DiffuseTex; @@ -204,6 +209,15 @@ void main() #if defined(USE_VERTEX_ANIMATION) vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); +#elif defined(USE_BONE_ANIMATION) + mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w; + mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz)); + + vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0)); + vec3 normal = normalize(nrmMat * attr_Normal); #else vec3 position = attr_Position; vec3 normal = attr_Normal; diff --git a/code/renderergl2/glsl/lightall_fp.glsl b/code/renderergl2/glsl/lightall_fp.glsl index 8edbebda..d77cd7c7 100644 --- a/code/renderergl2/glsl/lightall_fp.glsl +++ b/code/renderergl2/glsl/lightall_fp.glsl @@ -45,6 +45,8 @@ uniform vec4 u_CubeMapInfo; #endif #endif +uniform int u_AlphaTest; + varying vec4 var_TexCoords; varying vec4 var_Color; @@ -53,14 +55,9 @@ varying vec4 var_ColorAmbient; #endif #if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) - #if defined(USE_VERT_TANGENT_SPACE) varying vec4 var_Normal; varying vec4 var_Tangent; varying vec4 var_Bitangent; - #else -varying vec3 var_Normal; -varying vec3 var_ViewDir; - #endif #endif #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) @@ -196,24 +193,35 @@ float CalcLightAttenuation(float point, float normDist) return attenuation; } -// from http://www.thetenthplanet.de/archives/1180 -mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv ) + +vec4 hitCube(vec3 ray, vec3 pos, vec3 invSize, float lod, samplerCube tex) { - // get edge vectors of the pixel triangle - vec3 dp1 = dFdx( p ); - vec3 dp2 = dFdy( p ); - vec2 duv1 = dFdx( uv ); - vec2 duv2 = dFdy( uv ); + // find any hits on cubemap faces facing the camera + vec3 scale = (sign(ray) - pos) / ray; - // solve the linear system - vec3 dp2perp = cross( dp2, N ); - vec3 dp1perp = cross( N, dp1 ); - vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; - vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; + // find the nearest hit + float minScale = min(min(scale.x, scale.y), scale.z); - // construct a scale-invariant frame - float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) ); - return mat3( T * invmax, B * invmax, N ); + // if the nearest hit is behind the camera, ignore + // should not be necessary as long as pos is inside the cube + //if (minScale < 0.0) + //return vec4(0.0); + + // calculate the hit position, that's our texture coordinates + vec3 tc = pos + ray * minScale; + + // if the texture coordinates are outside the cube, ignore + // necessary since we're not fading out outside the cube + if (any(greaterThan(abs(tc), vec3(1.00001)))) + return vec4(0.0); + + // fade out when approaching the cubemap edges + //vec3 fade3 = abs(pos); + //float fade = max(max(fade3.x, fade3.y), fade3.z); + //fade = clamp(1.0 - fade, 0.0, 1.0); + + //return vec4(textureCubeLod(tex, tc, lod).rgb * fade, fade); + return vec4(textureCubeLod(tex, tc, lod).rgb, 1.0); } void main() @@ -223,13 +231,8 @@ void main() float NL, NH, NE, EH, attenuation; #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_VERT_TANGENT_SPACE) mat3 tangentToWorld = mat3(var_Tangent.xyz, var_Bitangent.xyz, var_Normal.xyz); viewDir = vec3(var_Normal.w, var_Tangent.w, var_Bitangent.w); - #else - mat3 tangentToWorld = cotangent_frame(var_Normal, -var_ViewDir, var_TexCoords.xy); - viewDir = var_ViewDir; - #endif E = normalize(viewDir); #endif @@ -257,6 +260,23 @@ void main() #endif vec4 diffuse = texture2D(u_DiffuseMap, texCoords); + + float alpha = diffuse.a * var_Color.a; + if (u_AlphaTest == 1) + { + if (alpha == 0.0) + discard; + } + else if (u_AlphaTest == 2) + { + if (alpha >= 0.5) + discard; + } + else if (u_AlphaTest == 3) + { + if (alpha < 0.5) + discard; + } #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) L = var_LightDir.xyz; @@ -292,7 +312,7 @@ void main() float shadowValue = texture2D(u_ShadowMap, shadowTex).r; // surfaces not facing the light are always shadowed - shadowValue *= clamp(dot(var_Normal.xyz, var_PrimaryLightDir.xyz), 0.0, 1.0); + shadowValue *= clamp(dot(N, var_PrimaryLightDir.xyz), 0.0, 1.0); #if defined(SHADOWMAP_MODULATE) lightColor *= shadowValue * (1.0 - u_PrimaryLightAmbient.r) + u_PrimaryLightAmbient.r; @@ -303,6 +323,9 @@ void main() ambientColor = lightColor; float surfNL = clamp(dot(var_Normal.xyz, L), 0.0, 1.0); + // reserve 25% ambient to avoid black areas on normalmaps + lightColor *= 0.75; + // Scale the incoming light to compensate for the baked-in light angle // attenuation. lightColor /= max(surfNL, 0.25); @@ -316,6 +339,9 @@ void main() NL = clamp(dot(N, L), 0.0, 1.0); NE = clamp(dot(N, E), 0.0, 1.0); + H = normalize(L + E); + EH = clamp(dot(E, H), 0.0, 1.0); + NH = clamp(dot(N, H), 0.0, 1.0); #if defined(USE_SPECULARMAP) vec4 specular = texture2D(u_SpecularMap, texCoords); @@ -330,11 +356,12 @@ void main() #if defined(USE_PBR) // diffuse rgb is base color - // specular red is smoothness + // specular red is gloss // specular green is metallicness float gloss = specular.r; - specular.rgb = specular.g * diffuse.rgb + vec3(0.04 - 0.04 * specular.g); - diffuse.rgb *= 1.0 - specular.g; + float metal = specular.g; + specular.rgb = metal * diffuse.rgb + vec3(0.04 - 0.04 * metal); + diffuse.rgb *= 1.0 - metal; #else // diffuse rgb is diffuse // specular rgb is specular reflectance at normal incidence @@ -357,6 +384,14 @@ void main() reflectance = CalcDiffuse(diffuse.rgb, NH, EH, roughness); + #if defined(r_deluxeSpecular) + #if defined(USE_LIGHT_VECTOR) + reflectance += CalcSpecular(specular.rgb, NH, EH, roughness) * r_deluxeSpecular; + #else + reflectance += CalcSpecular(specular.rgb, NH, EH, pow(roughness, r_deluxeSpecular)); + #endif + #endif + gl_FragColor.rgb = lightColor * reflectance * (attenuation * NL); gl_FragColor.rgb += ambientColor * diffuse.rgb; @@ -369,11 +404,15 @@ void main() // from http://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ vec3 parallax = u_CubeMapInfo.xyz + u_CubeMapInfo.w * viewDir; - vec3 cubeLightColor = textureCubeLod(u_CubeMap, R + parallax, 7.0 * roughness).rgb * u_EnableTextures.w; + #if defined(USE_BOX_CUBEMAP_PARALLAX) + vec3 cubeLightColor = hitCube(R * u_CubeMapInfo.w, parallax, u_CubeMapInfo.www, ROUGHNESS_MIPS * roughness, u_CubeMap).rgb * u_EnableTextures.w; + #else + vec3 cubeLightColor = textureCubeLod(u_CubeMap, R + parallax, ROUGHNESS_MIPS * roughness).rgb * u_EnableTextures.w; + #endif - // normalize cubemap based on lowest mip (~diffuse) + // normalize cubemap based on last roughness mip (~diffuse) // multiplying cubemap values by lighting below depends on either this or the cubemap being normalized at generation - //vec3 cubeLightDiffuse = max(textureCubeLod(u_CubeMap, N, 6.0).rgb, 0.5 / 255.0); + //vec3 cubeLightDiffuse = max(textureCubeLod(u_CubeMap, N, ROUGHNESS_MIPS).rgb, 0.5 / 255.0); //cubeLightColor /= dot(cubeLightDiffuse, vec3(0.2125, 0.7154, 0.0721)); #if defined(USE_PBR) @@ -431,5 +470,5 @@ void main() #endif - gl_FragColor.a = diffuse.a * var_Color.a; + gl_FragColor.a = alpha; } diff --git a/code/renderergl2/glsl/lightall_vp.glsl b/code/renderergl2/glsl/lightall_vp.glsl index 783885e9..428cf1e6 100644 --- a/code/renderergl2/glsl/lightall_vp.glsl +++ b/code/renderergl2/glsl/lightall_vp.glsl @@ -6,16 +6,15 @@ attribute vec4 attr_Color; attribute vec3 attr_Position; attribute vec3 attr_Normal; -#if defined(USE_VERT_TANGENT_SPACE) attribute vec4 attr_Tangent; -#endif #if defined(USE_VERTEX_ANIMATION) attribute vec3 attr_Position2; attribute vec3 attr_Normal2; - #if defined(USE_VERT_TANGENT_SPACE) attribute vec4 attr_Tangent2; - #endif +#elif defined(USE_BONE_ANIMATION) +attribute vec4 attr_BoneIndexes; +attribute vec4 attr_BoneWeights; #endif #if defined(USE_LIGHT) && !defined(USE_LIGHT_VECTOR) @@ -52,6 +51,8 @@ uniform mat4 u_ModelMatrix; #if defined(USE_VERTEX_ANIMATION) uniform float u_VertexLerp; +#elif defined(USE_BONE_ANIMATION) +uniform mat4 u_BoneMatrix[MAX_GLSL_BONES]; #endif #if defined(USE_LIGHT_VECTOR) @@ -74,14 +75,9 @@ varying vec4 var_ColorAmbient; #endif #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - #if defined(USE_VERT_TANGENT_SPACE) varying vec4 var_Normal; varying vec4 var_Tangent; varying vec4 var_Bitangent; - #else -varying vec3 var_Normal; -varying vec3 var_ViewDir; - #endif #endif #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) @@ -157,13 +153,25 @@ void main() #if defined(USE_VERTEX_ANIMATION) vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); - #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) vec3 tangent = mix(attr_Tangent.xyz, attr_Tangent2.xyz, u_VertexLerp); #endif +#elif defined(USE_BONE_ANIMATION) + mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w; + mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz)); + + vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0)); + vec3 normal = normalize(nrmMat * attr_Normal); + #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + vec3 tangent = normalize(nrmMat * attr_Tangent.xyz); + #endif #else vec3 position = attr_Position; vec3 normal = attr_Normal; - #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) vec3 tangent = attr_Tangent.xyz; #endif #endif @@ -185,12 +193,12 @@ void main() #if defined(USE_MODELMATRIX) position = (u_ModelMatrix * vec4(position, 1.0)).xyz; normal = (u_ModelMatrix * vec4(normal, 0.0)).xyz; - #if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) tangent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz; #endif #endif -#if defined(USE_VERT_TANGENT_SPACE) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) +#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) vec3 bitangent = cross(normal, tangent) * attr_Tangent.w; #endif @@ -247,14 +255,9 @@ void main() #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) vec3 viewDir = u_ViewOrigin - position; - #if defined(USE_VERT_TANGENT_SPACE) // store view direction in tangent space to save on varyings var_Normal = vec4(normal, viewDir.x); var_Tangent = vec4(tangent, viewDir.y); var_Bitangent = vec4(bitangent, viewDir.z); - #else - var_Normal = normal; - var_ViewDir = viewDir; - #endif #endif } diff --git a/code/renderergl2/glsl/pshadow_fp.glsl b/code/renderergl2/glsl/pshadow_fp.glsl index b152971a..c196f488 100644 --- a/code/renderergl2/glsl/pshadow_fp.glsl +++ b/code/renderergl2/glsl/pshadow_fp.glsl @@ -8,12 +8,6 @@ uniform float u_LightRadius; varying vec3 var_Position; varying vec3 var_Normal; -float sampleDistMap(sampler2D texMap, vec2 uv, float scale) -{ - vec3 distv = texture2D(texMap, uv).xyz; - return dot(distv, vec3(1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)) * scale; -} - void main() { vec3 lightToPos = var_Position - u_LightOrigin.xyz; @@ -57,42 +51,28 @@ void main() #endif intensity *= fade; -#if defined(USE_PCF) + float part; - - dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, -1.0/512.0), u_LightRadius); - part = max(sign(lightDist - dist), 0.0); +#if defined(USE_PCF) + part = float(texture2D(u_ShadowMap, st + vec2(-1.0/512.0, -1.0/512.0)).r != 1.0); + part += float(texture2D(u_ShadowMap, st + vec2( 1.0/512.0, -1.0/512.0)).r != 1.0); + part += float(texture2D(u_ShadowMap, st + vec2(-1.0/512.0, 1.0/512.0)).r != 1.0); + part += float(texture2D(u_ShadowMap, st + vec2( 1.0/512.0, 1.0/512.0)).r != 1.0); +#else + part = float(texture2D(u_ShadowMap, st).r != 1.0); +#endif - dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, -1.0/512.0), u_LightRadius); - part += max(sign(lightDist - dist), 0.0); - - dist = sampleDistMap(u_ShadowMap, st + vec2(-1.0/512.0, 1.0/512.0), u_LightRadius); - part += max(sign(lightDist - dist), 0.0); - - dist = sampleDistMap(u_ShadowMap, st + vec2( 1.0/512.0, 1.0/512.0), u_LightRadius); - part += max(sign(lightDist - dist), 0.0); - - #if defined(USE_DISCARD) if (part <= 0.0) { discard; } - #endif +#if defined(USE_PCF) intensity *= part * 0.25; #else - dist = sampleDistMap(u_ShadowMap, st, u_LightRadius); - - #if defined(USE_DISCARD) - if (lightDist - dist <= 0.0) - { - discard; - } - #endif - - intensity *= max(sign(lightDist - dist), 0.0); + intensity *= part; #endif - + gl_FragColor.rgb = vec3(0); gl_FragColor.a = clamp(intensity, 0.0, 0.75); } diff --git a/code/renderergl2/glsl/shadowfill_vp.glsl b/code/renderergl2/glsl/shadowfill_vp.glsl index 7de901ba..03f8667c 100644 --- a/code/renderergl2/glsl/shadowfill_vp.glsl +++ b/code/renderergl2/glsl/shadowfill_vp.glsl @@ -2,10 +2,13 @@ attribute vec3 attr_Position; attribute vec3 attr_Normal; attribute vec4 attr_TexCoord0; -//#if defined(USE_VERTEX_ANIMATION) +#if defined(USE_VERTEX_ANIMATION) attribute vec3 attr_Position2; attribute vec3 attr_Normal2; -//#endif +#elif defined(USE_BONE_ANIMATION) +attribute vec4 attr_BoneIndexes; +attribute vec4 attr_BoneWeights; +#endif //#if defined(USE_DEFORM_VERTEXES) uniform int u_DeformGen; @@ -17,9 +20,11 @@ uniform mat4 u_ModelViewProjectionMatrix; uniform mat4 u_ModelMatrix; -//#if defined(USE_VERTEX_ANIMATION) +#if defined(USE_VERTEX_ANIMATION) uniform float u_VertexLerp; -//#endif +#elif defined(USE_BONE_ANIMATION) +uniform mat4 u_BoneMatrix[MAX_GLSL_BONES]; +#endif varying vec3 var_Position; @@ -78,8 +83,22 @@ vec3 DeformPosition(const vec3 pos, const vec3 normal, const vec2 st) void main() { +#if defined(USE_VERTEX_ANIMATION) vec3 position = mix(attr_Position, attr_Position2, u_VertexLerp); vec3 normal = mix(attr_Normal, attr_Normal2, u_VertexLerp); +#elif defined(USE_BONE_ANIMATION) + mat4 vtxMat = u_BoneMatrix[int(attr_BoneIndexes.x)] * attr_BoneWeights.x; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.y)] * attr_BoneWeights.y; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.z)] * attr_BoneWeights.z; + vtxMat += u_BoneMatrix[int(attr_BoneIndexes.w)] * attr_BoneWeights.w; + mat3 nrmMat = mat3(cross(vtxMat[1].xyz, vtxMat[2].xyz), cross(vtxMat[2].xyz, vtxMat[0].xyz), cross(vtxMat[0].xyz, vtxMat[1].xyz)); + + vec3 position = vec3(vtxMat * vec4(attr_Position, 1.0)); + vec3 normal = normalize(nrmMat * attr_Normal); +#else + vec3 position = attr_Position; + vec3 normal = attr_Normal; +#endif position = DeformPosition(position, normal, attr_TexCoord0.st); diff --git a/code/renderergl2/glsl/shadowmask_fp.glsl b/code/renderergl2/glsl/shadowmask_fp.glsl index 053907cf..2b57e3ba 100644 --- a/code/renderergl2/glsl/shadowmask_fp.glsl +++ b/code/renderergl2/glsl/shadowmask_fp.glsl @@ -52,10 +52,10 @@ float PCF(const sampler2DShadow shadowmap, const vec2 st, const float dist) offset.y += offset.x; if (offset.y > 1.1) offset.y = 0.0; - mult = shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, 0.5)) * scale, dist)).r - + shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, 0.5)) * scale, dist)).r - + shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, -1.5)) * scale, dist)).r - + shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, -1.5)) * scale, dist)).r; + mult = shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, 0.5)) * scale, dist)) + + shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, 0.5)) * scale, dist)) + + shadow2D(shadowmap, vec3(st + (offset + vec2(-1.5, -1.5)) * scale, dist)) + + shadow2D(shadowmap, vec3(st + (offset + vec2( 0.5, -1.5)) * scale, dist)); mult *= 0.25; #endif @@ -66,23 +66,23 @@ float PCF(const sampler2DShadow shadowmap, const vec2 st, const float dist) float cosr = cos(r) * scale; mat2 rmat = mat2(cosr, sinr, -sinr, cosr); - mult = shadow2D(shadowmap, vec3(st + rmat * vec2(-0.7055767, 0.196515), dist)).r; - mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.3524343, -0.7791386), dist)).r; - mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.2391056, 0.9189604), dist)).r; + mult = shadow2D(shadowmap, vec3(st + rmat * vec2(-0.7055767, 0.196515), dist)); + mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.3524343, -0.7791386), dist)); + mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.2391056, 0.9189604), dist)); #if defined(USE_SHADOW_FILTER2) - mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.07580382, -0.09224417), dist)).r; - mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.5784913, -0.002528916), dist)).r; - mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.192888, 0.4064181), dist)).r; - mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.6335801, -0.5247476), dist)).r; - mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.5579782, 0.7491854), dist)).r; - mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.7320465, 0.6317794), dist)).r; + mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.07580382, -0.09224417), dist)); + mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.5784913, -0.002528916), dist)); + mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.192888, 0.4064181), dist)); + mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.6335801, -0.5247476), dist)); + mult += shadow2D(shadowmap, vec3(st + rmat * vec2(-0.5579782, 0.7491854), dist)); + mult += shadow2D(shadowmap, vec3(st + rmat * vec2(0.7320465, 0.6317794), dist)); mult *= 0.11111; #else mult *= 0.33333; #endif #else - mult = shadow2D(shadowmap, vec3(st, dist)).r; + mult = shadow2D(shadowmap, vec3(st, dist)); #endif return mult; diff --git a/code/renderergl2/glsl/ssao_fp.glsl b/code/renderergl2/glsl/ssao_fp.glsl index 6263284c..f3054404 100644 --- a/code/renderergl2/glsl/ssao_fp.glsl +++ b/code/renderergl2/glsl/ssao_fp.glsl @@ -1,9 +1,10 @@ uniform sampler2D u_ScreenDepthMap; -uniform vec4 u_ViewInfo; // zfar / znear, zfar +uniform vec4 u_ViewInfo; // zfar / znear, zfar, 1/width, 1/height varying vec2 var_ScreenTex; +#if 0 vec2 poissonDisc[9] = vec2[9]( vec2(-0.7055767, 0.196515), vec2(0.3524343, -0.7791386), vec2(0.2391056, 0.9189604), vec2(-0.07580382, -0.09224417), @@ -11,6 +12,9 @@ vec2(0.5784913, -0.002528916), vec2(0.192888, 0.4064181), vec2(-0.6335801, -0.5247476), vec2(-0.5579782, 0.7491854), vec2(0.7320465, 0.6317794) ); +#endif + +#define NUM_SAMPLES 3 // Input: It uses texture coords as the random number seed. // Output: Random number: [0,1), that is between 0.0 and 0.999999... inclusive. @@ -39,48 +43,59 @@ mat2 randomRotation( const vec2 p ) float getLinearDepth(sampler2D depthMap, const vec2 tex, const float zFarDivZNear) { - float sampleZDivW = texture2D(depthMap, tex).r; - return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); + float sampleZDivW = texture2D(depthMap, tex).r; + return 1.0 / mix(zFarDivZNear, 1.0, sampleZDivW); } -float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar) +float ambientOcclusion(sampler2D depthMap, const vec2 tex, const float zFarDivZNear, const float zFar, const vec2 scale) { - float result = 0; + vec2 poissonDisc[9]; - float sampleZ = zFar * getLinearDepth(depthMap, tex, zFarDivZNear); + poissonDisc[0] = vec2(-0.7055767, 0.196515); + poissonDisc[1] = vec2(0.3524343, -0.7791386); + poissonDisc[2] = vec2(0.2391056, 0.9189604); + poissonDisc[3] = vec2(-0.07580382, -0.09224417); + poissonDisc[4] = vec2(0.5784913, -0.002528916); + poissonDisc[5] = vec2(0.192888, 0.4064181); + poissonDisc[6] = vec2(-0.6335801, -0.5247476); + poissonDisc[7] = vec2(-0.5579782, 0.7491854); + poissonDisc[8] = vec2(0.7320465, 0.6317794); - vec2 expectedSlope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y)); - - if (length(expectedSlope) > 5000.0) + float result = 0.0; + + float sampleZ = getLinearDepth(depthMap, tex, zFarDivZNear); + float scaleZ = zFarDivZNear * sampleZ; + + vec2 slope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y)); + + if (length(slope) * zFar > 5000.0) return 1.0; - - vec2 offsetScale = vec2(3.0 / sampleZ); - + + vec2 offsetScale = vec2(scale * 1024.0 / scaleZ); + mat2 rmat = randomRotation(tex); - + + float invZFar = 1.0 / zFar; + float zLimit = 20.0 * invZFar; int i; - for (i = 0; i < 3; i++) + for (i = 0; i < NUM_SAMPLES; i++) { vec2 offset = rmat * poissonDisc[i] * offsetScale; - float sampleZ2 = zFar * getLinearDepth(depthMap, tex + offset, zFarDivZNear); + float sampleDiff = getLinearDepth(depthMap, tex + offset, zFarDivZNear) - sampleZ; - if (abs(sampleZ - sampleZ2) > 20.0) - result += 1.0; - else - { - float expectedZ = sampleZ + dot(expectedSlope, offset); - result += step(expectedZ - 1.0, sampleZ2); - } + bool s1 = abs(sampleDiff) > zLimit; + bool s2 = sampleDiff + invZFar > dot(slope, offset); + result += float(s1 || s2); } - - result *= 0.33333; - + + result *= 1.0 / float(NUM_SAMPLES); + return result; } void main() { - float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y); - + float result = ambientOcclusion(u_ScreenDepthMap, var_ScreenTex, u_ViewInfo.x, u_ViewInfo.y, u_ViewInfo.wz); + gl_FragColor = vec4(vec3(result), 1.0); } diff --git a/code/renderergl2/tr_animation.c b/code/renderergl2/tr_animation.c index 53e5ee99..38fffc64 100644 --- a/code/renderergl2/tr_animation.c +++ b/code/renderergl2/tr_animation.c @@ -267,9 +267,9 @@ void R_MDRAddAnimSurfaces( trRefEntity_t *ent ) { for(j = 0; j < skin->numSurfaces; j++) { - if (!strcmp(skin->surfaces[j]->name, surface->name)) + if (!strcmp(skin->surfaces[j].name, surface->name)) { - shader = skin->surfaces[j]->shader; + shader = skin->surfaces[j].shader; break; } } @@ -412,10 +412,10 @@ void RB_MDRSurfaceAnim( mdrSurface_t *surface ) tess.xyz[baseVertex + j][1] = tempVert[1]; tess.xyz[baseVertex + j][2] = tempVert[2]; - R_VaoPackNormal((byte *)&tess.normal[baseVertex + j], tempNormal); + R_VaoPackNormal(tess.normal[baseVertex + j], tempNormal); - tess.texCoords[baseVertex + j][0][0] = v->texCoords[0]; - tess.texCoords[baseVertex + j][0][1] = v->texCoords[1]; + tess.texCoords[baseVertex + j][0] = v->texCoords[0]; + tess.texCoords[baseVertex + j][1] = v->texCoords[1]; v = (mdrVertex_t *)&v->weights[v->numWeights]; } diff --git a/code/renderergl2/tr_backend.c b/code/renderergl2/tr_backend.c index 985b8f9f..df54528b 100644 --- a/code/renderergl2/tr_backend.c +++ b/code/renderergl2/tr_backend.c @@ -58,7 +58,7 @@ void GL_BindToTMU( image_t *image, int tmu ) ri.Printf(PRINT_WARNING, "GL_BindToTMU: NULL image\n"); } - GL_BindMultiTexture(GL_TEXTURE0_ARB + tmu, target, texture); + GL_BindMultiTexture(GL_TEXTURE0 + tmu, target, texture); } @@ -263,44 +263,6 @@ void GL_State( unsigned long stateBits ) } } - // - // alpha test - // - if ( diff & GLS_ATEST_BITS ) - { - uint32_t oldState = glState.glStateBits & GLS_ATEST_BITS; - uint32_t newState = stateBits & GLS_ATEST_BITS; - uint32_t storedState = glState.storedGlState & GLS_ATEST_BITS; - - if (oldState == 0) - { - qglEnable(GL_ALPHA_TEST); - } - else if (newState == 0) - { - qglDisable(GL_ALPHA_TEST); - } - - if (newState != 0 && storedState != newState) - { - glState.storedGlState &= ~GLS_ATEST_BITS; - glState.storedGlState |= newState; - - switch ( newState ) - { - case GLS_ATEST_GT_0: - qglAlphaFunc( GL_GREATER, 0.0f ); - break; - case GLS_ATEST_LT_80: - qglAlphaFunc( GL_LESS, 0.5f ); - break; - case GLS_ATEST_GE_80: - qglAlphaFunc( GL_GEQUAL, 0.5f ); - break; - } - } - } - glState.glStateBits = stateBits; } @@ -471,12 +433,8 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { int i; drawSurf_t *drawSurf; int oldSort; - float originalTime; + double originalTime; FBO_t* fbo = NULL; - qboolean inQuery = qfalse; - - float depth[2]; - // save original time for entity shader offsets originalTime = backEnd.refdef.floatTime; @@ -495,9 +453,6 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { oldCubemapIndex = -1; oldSort = -1; - depth[0] = 0.f; - depth[1] = 1.f; - backEnd.pc.c_surfaces += numDrawSurfs; for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) { @@ -515,7 +470,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // // change the tess parameters if needed - // a "entityMergable" shader is a shader that can have surfaces from seperate + // a "entityMergable" shader is a shader that can have surfaces from separate // entities merged into a single batch, like smoke and blood puff sprites if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed || cubemapIndex != oldCubemapIndex || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { @@ -538,12 +493,14 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // change the modelview matrix if needed // if ( entityNum != oldEntityNum ) { - qboolean sunflare = qfalse; depthRange = isCrosshair = qfalse; if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; - backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; + + // FIXME: e.shaderTime must be passed as int to avoid fp-precision loss issues + backEnd.refdef.floatTime = originalTime - (double)backEnd.currentEntity->e.shaderTime; + // we have to reset the shaderTime as well otherwise image animations start // from the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; @@ -604,12 +561,8 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { } } - if(!oldDepthRange) - { - depth[0] = 0; - depth[1] = 0.3f; - qglDepthRange (depth[0], depth[1]); - } + if(!oldDepthRange) + qglDepthRange (0, 0.3); } else { @@ -618,11 +571,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix ); } - if (!sunflare) - qglDepthRange (0, 1); - - depth[0] = 0; - depth[1] = 1; + qglDepthRange (0, 1); } oldDepthRange = depthRange; @@ -643,10 +592,6 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { RB_EndSurface(); } - if (inQuery) { - qglEndQueryARB(GL_SAMPLES_PASSED_ARB); - } - if (glRefConfig.framebufferObject) FBO_Bind(fbo); @@ -707,14 +652,10 @@ void RB_SetGL2D (void) { GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_Cull( CT_TWO_SIDED ); - qglDisable( GL_CLIP_PLANE0 ); // set time for 2D shaders backEnd.refdef.time = ri.Milliseconds(); - backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; - - // reset color scaling - backEnd.refdef.colorScale = 1.0f; + backEnd.refdef.floatTime = backEnd.refdef.time * 0.001; } @@ -742,7 +683,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * RB_EndSurface(); } - // we definately want to sync every frame for the cinematics + // we definitely want to sync every frame for the cinematics qglFinish(); start = 0; @@ -808,16 +749,16 @@ void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTextureImage2D(texture, GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + qglTextureImage2DEXT(texture, GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTextureParameterfEXT(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { if (dirty) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing // it and don't try and do a texture compression - qglTextureSubImage2D(texture, GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data); + qglTextureSubImage2DEXT(texture, GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data); } } } @@ -884,43 +825,43 @@ const void *RB_StretchPic ( const void *data ) { tess.indexes[ numIndexes + 5 ] = numVerts + 1; { - vec4_t color; + uint16_t color[4]; - VectorScale4(backEnd.color2D, 1.0f / 255.0f, color); + VectorScale4(backEnd.color2D, 257, color); - VectorCopy4(color, tess.vertexColors[ numVerts ]); - VectorCopy4(color, tess.vertexColors[ numVerts + 1]); - VectorCopy4(color, tess.vertexColors[ numVerts + 2]); - VectorCopy4(color, tess.vertexColors[ numVerts + 3 ]); + VectorCopy4(color, tess.color[ numVerts ]); + VectorCopy4(color, tess.color[ numVerts + 1]); + VectorCopy4(color, tess.color[ numVerts + 2]); + VectorCopy4(color, tess.color[ numVerts + 3 ]); } tess.xyz[ numVerts ][0] = cmd->x; tess.xyz[ numVerts ][1] = cmd->y; tess.xyz[ numVerts ][2] = 0; - tess.texCoords[ numVerts ][0][0] = cmd->s1; - tess.texCoords[ numVerts ][0][1] = cmd->t1; + tess.texCoords[ numVerts ][0] = cmd->s1; + tess.texCoords[ numVerts ][1] = cmd->t1; tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w; tess.xyz[ numVerts + 1 ][1] = cmd->y; tess.xyz[ numVerts + 1 ][2] = 0; - tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1; + tess.texCoords[ numVerts + 1 ][0] = cmd->s2; + tess.texCoords[ numVerts + 1 ][1] = cmd->t1; tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w; tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h; tess.xyz[ numVerts + 2 ][2] = 0; - tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2; - tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2; + tess.texCoords[ numVerts + 2 ][0] = cmd->s2; + tess.texCoords[ numVerts + 2 ][1] = cmd->t2; tess.xyz[ numVerts + 3 ][0] = cmd->x; tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h; tess.xyz[ numVerts + 3 ][2] = 0; - tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1; - tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2; + tess.texCoords[ numVerts + 3 ][0] = cmd->s1; + tess.texCoords[ numVerts + 3 ][1] = cmd->t2; return (const void *)(cmd + 1); } @@ -934,6 +875,7 @@ RB_DrawSurfs */ const void *RB_DrawSurfs( const void *data ) { const drawSurfsCommand_t *cmd; + qboolean isShadowView; // finish any 2D drawing if needed if ( tess.numIndexes ) { @@ -945,6 +887,8 @@ const void *RB_DrawSurfs( const void *data ) { backEnd.refdef = cmd->refdef; backEnd.viewParms = cmd->viewParms; + isShadowView = !!(backEnd.viewParms.flags & VPF_DEPTHSHADOW); + // clear the z buffer, set the modelview, etc RB_BeginDrawingView (); @@ -953,7 +897,7 @@ const void *RB_DrawSurfs( const void *data ) { qglEnable(GL_DEPTH_CLAMP); } - if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW))) + if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || isShadowView)) { FBO_t *oldFbo = glState.currentFBO; vec4_t viewInfo; @@ -966,198 +910,210 @@ const void *RB_DrawSurfs( const void *data ) { qglColorMask(!backEnd.colorMask[0], !backEnd.colorMask[1], !backEnd.colorMask[2], !backEnd.colorMask[3]); backEnd.depthFill = qfalse; - if (tr.msaaResolveFbo) + if (!isShadowView) { - // If we're using multisampling, resolve the depth first - FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST); - } - else if (tr.renderFbo == NULL && tr.renderDepthImage) - { - // If we're rendering directly to the screen, copy the depth to a texture - qglCopyTextureImage2D(tr.renderDepthImage->texnum, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0); - } - - if (r_ssao->integer) - { - // need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image - FBO_BlitFromTexture(tr.renderDepthImage, NULL, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0); - } - - if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT) - { - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - vec4_t box; - - FBO_Bind(tr.screenShadowFbo); - - box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth; - box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight; - box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth; - box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight; - - qglViewport(box[0], box[1], box[2], box[3]); - qglScissor(box[0], box[1], box[2], box[3]); - - box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth; - box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight; - box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth; - box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight; - - texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; - texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; - texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; - texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; - - box[0] = -1.0f; - box[1] = -1.0f; - box[2] = 1.0f; - box[3] = 1.0f; - - VectorSet4(quadVerts[0], box[0], box[3], 0, 1); - VectorSet4(quadVerts[1], box[2], box[3], 0, 1); - VectorSet4(quadVerts[2], box[2], box[1], 0, 1); - VectorSet4(quadVerts[3], box[0], box[1], 0, 1); - - GL_State( GLS_DEPTHTEST_DISABLE ); - - GLSL_BindProgram(&tr.shadowmaskShader); - - GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP); - - if (r_shadowCascadeZFar->integer != 0) + if (tr.msaaResolveFbo) { - GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); - GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); - GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); - GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP4); - - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP4, backEnd.refdef.sunShadowMvp[3]); + // If we're using multisampling, resolve the depth first + FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST); } - else + else if (tr.renderFbo == NULL && tr.renderDepthImage) { - GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP); - GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[3]); - } - - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); - { - vec3_t viewVector; - - float zmax = backEnd.viewParms.zFar; - float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f); - float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f); - - VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector); - VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector); - VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector); - - GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo); + // If we're rendering directly to the screen, copy the depth to a texture + // This is incredibly slow on Intel Graphics, so just skip it on there + if (!glRefConfig.intelGraphics) + qglCopyTextureSubImage2DEXT(tr.renderDepthImage->texnum, GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight); } - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - - if (r_shadowBlur->integer) + if (tr.hdrDepthFbo) { - viewInfo[2] = 1.0f / (float)(tr.screenScratchFbo->width); - viewInfo[3] = 1.0f / (float)(tr.screenScratchFbo->height); + // need the depth in a texture we can do GL_LINEAR sampling on, so copy it to an HDR image + vec4_t srcTexCoords; - FBO_Bind(tr.screenScratchFbo); + VectorSet4(srcTexCoords, 0.0f, 0.0f, 1.0f, 1.0f); + + FBO_BlitFromTexture(tr.renderDepthImage, srcTexCoords, NULL, tr.hdrDepthFbo, NULL, NULL, NULL, 0); + } + + if (r_sunlightMode->integer && backEnd.viewParms.flags & VPF_USESUNLIGHT) + { + vec4_t quadVerts[4]; + vec2_t texCoords[4]; + vec4_t box; + + FBO_Bind(tr.screenShadowFbo); + + box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth; + box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight; + box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth; + box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight; + + qglViewport(box[0], box[1], box[2], box[3]); + qglScissor(box[0], box[1], box[2], box[3]); + + box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth; + box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight; + box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth; + box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight; + + texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; + texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; + texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; + texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; + + box[0] = -1.0f; + box[1] = -1.0f; + box[2] = 1.0f; + box[3] = 1.0f; + + VectorSet4(quadVerts[0], box[0], box[3], 0, 1); + VectorSet4(quadVerts[1], box[2], box[3], 0, 1); + VectorSet4(quadVerts[2], box[2], box[1], 0, 1); + VectorSet4(quadVerts[3], box[0], box[1], 0, 1); + + GL_State(GLS_DEPTHTEST_DISABLE); + + GLSL_BindProgram(&tr.shadowmaskShader); + + GL_BindToTMU(tr.renderDepthImage, TB_COLORMAP); + + if (r_shadowCascadeZFar->integer != 0) + { + GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); + GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); + GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); + GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP4); + + GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); + GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); + GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); + GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP4, backEnd.refdef.sunShadowMvp[3]); + } + else + { + GL_BindToTMU(tr.sunShadowDepthImage[3], TB_SHADOWMAP); + GLSL_SetUniformMat4(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[3]); + } + + GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); + { + vec3_t viewVector; + + float zmax = backEnd.viewParms.zFar; + float ymax = zmax * tan(backEnd.viewParms.fovY * M_PI / 360.0f); + float xmax = zmax * tan(backEnd.viewParms.fovX * M_PI / 360.0f); + + VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector); + GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector); + VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector); + GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector); + VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector); + GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector); + + GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo); + } + + RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); + + if (r_shadowBlur->integer) + { + viewInfo[2] = 1.0f / (float)(tr.screenScratchFbo->width); + viewInfo[3] = 1.0f / (float)(tr.screenScratchFbo->height); + + FBO_Bind(tr.screenScratchFbo); + + GLSL_BindProgram(&tr.depthBlurShader[0]); + + GL_BindToTMU(tr.screenShadowImage, TB_COLORMAP); + GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); + + GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); + + RB_InstantQuad2(quadVerts, texCoords); + + FBO_Bind(tr.screenShadowFbo); + + GLSL_BindProgram(&tr.depthBlurShader[1]); + + GL_BindToTMU(tr.screenScratchImage, TB_COLORMAP); + GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); + + GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); + + RB_InstantQuad2(quadVerts, texCoords); + } + } + + if (r_ssao->integer) + { + vec4_t quadVerts[4]; + vec2_t texCoords[4]; + + viewInfo[2] = 1.0f / ((float)(tr.quarterImage[0]->width) * tan(backEnd.viewParms.fovX * M_PI / 360.0f) * 2.0f); + viewInfo[3] = 1.0f / ((float)(tr.quarterImage[0]->height) * tan(backEnd.viewParms.fovY * M_PI / 360.0f) * 2.0f); + viewInfo[3] *= (float)backEnd.viewParms.viewportHeight / (float)backEnd.viewParms.viewportWidth; + + FBO_Bind(tr.quarterFbo[0]); + + qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); + qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); + + VectorSet4(quadVerts[0], -1, 1, 0, 1); + VectorSet4(quadVerts[1], 1, 1, 0, 1); + VectorSet4(quadVerts[2], 1, -1, 0, 1); + VectorSet4(quadVerts[3], -1, -1, 0, 1); + + texCoords[0][0] = 0; texCoords[0][1] = 1; + texCoords[1][0] = 1; texCoords[1][1] = 1; + texCoords[2][0] = 1; texCoords[2][1] = 0; + texCoords[3][0] = 0; texCoords[3][1] = 0; + + GL_State( GLS_DEPTHTEST_DISABLE ); + + GLSL_BindProgram(&tr.ssaoShader); + + GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP); + + GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo); + + RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); + + + viewInfo[2] = 1.0f / (float)(tr.quarterImage[0]->width); + viewInfo[3] = 1.0f / (float)(tr.quarterImage[0]->height); + + FBO_Bind(tr.quarterFbo[1]); + + qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); + qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); GLSL_BindProgram(&tr.depthBlurShader[0]); - GL_BindToTMU(tr.screenShadowImage, TB_COLORMAP); + GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); - RB_InstantQuad2(quadVerts, texCoords); + RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - FBO_Bind(tr.screenShadowFbo); + FBO_Bind(tr.screenSsaoFbo); + + qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); + qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); GLSL_BindProgram(&tr.depthBlurShader[1]); - GL_BindToTMU(tr.screenScratchImage, TB_COLORMAP); + GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); - RB_InstantQuad2(quadVerts, texCoords); + + RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); } } - if (r_ssao->integer) - { - vec4_t quadVerts[4]; - vec2_t texCoords[4]; - - viewInfo[2] = 1.0f / (float)(tr.quarterImage[0]->width); - viewInfo[3] = 1.0f / (float)(tr.quarterImage[0]->height); - - FBO_Bind(tr.quarterFbo[0]); - - qglViewport(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); - qglScissor(0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); - - VectorSet4(quadVerts[0], -1, 1, 0, 1); - VectorSet4(quadVerts[1], 1, 1, 0, 1); - VectorSet4(quadVerts[2], 1, -1, 0, 1); - VectorSet4(quadVerts[3], -1, -1, 0, 1); - - texCoords[0][0] = 0; texCoords[0][1] = 1; - texCoords[1][0] = 1; texCoords[1][1] = 1; - texCoords[2][0] = 1; texCoords[2][1] = 0; - texCoords[3][0] = 0; texCoords[3][1] = 0; - - GL_State( GLS_DEPTHTEST_DISABLE ); - - GLSL_BindProgram(&tr.ssaoShader); - - GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP); - - GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo); - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - - - FBO_Bind(tr.quarterFbo[1]); - - qglViewport(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); - qglScissor(0, 0, tr.quarterFbo[1]->width, tr.quarterFbo[1]->height); - - GLSL_BindProgram(&tr.depthBlurShader[0]); - - GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); - GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); - - GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - - - FBO_Bind(tr.screenSsaoFbo); - - qglViewport(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); - qglScissor(0, 0, tr.screenSsaoFbo->width, tr.screenSsaoFbo->height); - - GLSL_BindProgram(&tr.depthBlurShader[1]); - - GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); - GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP); - - GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); - - - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); - } - // reset viewport and scissor FBO_Bind(oldFbo); SetViewportAndScissor(); @@ -1168,7 +1124,7 @@ const void *RB_DrawSurfs( const void *data ) { qglDisable(GL_DEPTH_CLAMP); } - if (!(backEnd.viewParms.flags & VPF_DEPTHSHADOW)) + if (!isShadowView) { RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); @@ -1177,7 +1133,7 @@ const void *RB_DrawSurfs( const void *data ) { RB_DrawSun(0.1, tr.sunShader); } - if (r_drawSunRays->integer) + if (glRefConfig.framebufferObject && r_drawSunRays->integer) { FBO_t *oldFbo = glState.currentFBO; FBO_Bind(tr.sunRaysFbo); @@ -1188,14 +1144,14 @@ const void *RB_DrawSurfs( const void *data ) { if (glRefConfig.occlusionQuery) { tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; - qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); + qglBeginQuery(GL_SAMPLES_PASSED, tr.sunFlareQuery[tr.sunFlareQueryIndex]); } RB_DrawSun(0.3, tr.sunFlareShader); if (glRefConfig.occlusionQuery) { - qglEndQueryARB(GL_SAMPLES_PASSED_ARB); + qglEndQuery(GL_SAMPLES_PASSED); } FBO_Bind(oldFbo); @@ -1214,7 +1170,7 @@ const void *RB_DrawSurfs( const void *data ) { FBO_Bind(NULL); if (cubemap && cubemap->image) - qglGenerateTextureMipmap(cubemap->image->texnum, GL_TEXTURE_CUBE_MAP); + qglGenerateTextureMipmapEXT(cubemap->image->texnum, GL_TEXTURE_CUBE_MAP); } return (const void *)(cmd + 1); @@ -1471,14 +1427,14 @@ const void *RB_CapShadowMap(const void *data) { if (tr.shadowCubemaps[cmd->map]) { - qglCopyTextureImage2D(tr.shadowCubemaps[cmd->map]->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); + qglCopyTextureSubImage2DEXT(tr.shadowCubemaps[cmd->map]->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, 0, 0, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE); } } else { if (tr.pshadowMaps[cmd->map]) { - qglCopyTextureImage2D(tr.pshadowMaps[cmd->map]->texnum, GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - (backEnd.refdef.y + PSHADOW_MAP_SIZE), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0); + qglCopyTextureSubImage2DEXT(tr.pshadowMaps[cmd->map]->texnum, GL_TEXTURE_2D, 0, 0, 0, backEnd.refdef.x, glConfig.vidHeight - (backEnd.refdef.y + PSHADOW_MAP_SIZE), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE); } } } @@ -1537,10 +1493,6 @@ const void *RB_PostProcess(const void *data) srcBox[2] = backEnd.viewParms.viewportWidth * tr.screenSsaoImage->width / (float)glConfig.vidWidth; srcBox[3] = backEnd.viewParms.viewportHeight * tr.screenSsaoImage->height / (float)glConfig.vidHeight; - //FBO_BlitFromTexture(tr.screenSsaoImage, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); - srcBox[1] = tr.screenSsaoImage->height - srcBox[1]; - srcBox[3] = -srcBox[3]; - FBO_Blit(tr.screenSsaoFbo, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); } @@ -1581,19 +1533,97 @@ const void *RB_PostProcess(const void *data) else RB_GaussianBlur(backEnd.refdef.blurFactor); +#if 0 + if (0) + { + vec4_t quadVerts[4]; + vec2_t texCoords[4]; + ivec4_t iQtrBox; + vec4_t box; + vec4_t viewInfo; + static float scale = 5.0f; + + scale -= 0.005f; + if (scale < 0.01f) + scale = 5.0f; + + FBO_FastBlit(NULL, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); + + iQtrBox[0] = backEnd.viewParms.viewportX * tr.quarterImage[0]->width / (float)glConfig.vidWidth; + iQtrBox[1] = backEnd.viewParms.viewportY * tr.quarterImage[0]->height / (float)glConfig.vidHeight; + iQtrBox[2] = backEnd.viewParms.viewportWidth * tr.quarterImage[0]->width / (float)glConfig.vidWidth; + iQtrBox[3] = backEnd.viewParms.viewportHeight * tr.quarterImage[0]->height / (float)glConfig.vidHeight; + + qglViewport(iQtrBox[0], iQtrBox[1], iQtrBox[2], iQtrBox[3]); + qglScissor(iQtrBox[0], iQtrBox[1], iQtrBox[2], iQtrBox[3]); + + VectorSet4(box, 0.0f, 0.0f, 1.0f, 1.0f); + + texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; + texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; + texCoords[2][0] = box[2]; texCoords[2][1] = box[1]; + texCoords[3][0] = box[0]; texCoords[3][1] = box[1]; + + VectorSet4(box, -1.0f, -1.0f, 1.0f, 1.0f); + + VectorSet4(quadVerts[0], box[0], box[3], 0, 1); + VectorSet4(quadVerts[1], box[2], box[3], 0, 1); + VectorSet4(quadVerts[2], box[2], box[1], 0, 1); + VectorSet4(quadVerts[3], box[0], box[1], 0, 1); + + GL_State(GLS_DEPTHTEST_DISABLE); + + + VectorSet4(viewInfo, backEnd.viewParms.zFar / r_znear->value, backEnd.viewParms.zFar, 0.0, 0.0); + + viewInfo[2] = scale / (float)(tr.quarterImage[0]->width); + viewInfo[3] = scale / (float)(tr.quarterImage[0]->height); + + FBO_Bind(tr.quarterFbo[1]); + GLSL_BindProgram(&tr.depthBlurShader[2]); + GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP); + GLSL_SetUniformVec4(&tr.depthBlurShader[2], UNIFORM_VIEWINFO, viewInfo); + RB_InstantQuad2(quadVerts, texCoords); + + FBO_Bind(tr.quarterFbo[0]); + GLSL_BindProgram(&tr.depthBlurShader[3]); + GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP); + GLSL_SetUniformVec4(&tr.depthBlurShader[3], UNIFORM_VIEWINFO, viewInfo); + RB_InstantQuad2(quadVerts, texCoords); + + SetViewportAndScissor(); + + FBO_FastBlit(tr.quarterFbo[1], NULL, NULL, NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); + FBO_Bind(NULL); + } +#endif + if (0 && r_sunlightMode->integer) { ivec4_t dstBox; - VectorSet4(dstBox, 0, 0, 128, 128); + VectorSet4(dstBox, 0, glConfig.vidHeight - 128, 128, 128); FBO_BlitFromTexture(tr.sunShadowDepthImage[0], NULL, NULL, NULL, dstBox, NULL, NULL, 0); - VectorSet4(dstBox, 128, 0, 128, 128); + VectorSet4(dstBox, 128, glConfig.vidHeight - 128, 128, 128); FBO_BlitFromTexture(tr.sunShadowDepthImage[1], NULL, NULL, NULL, dstBox, NULL, NULL, 0); - VectorSet4(dstBox, 256, 0, 128, 128); + VectorSet4(dstBox, 256, glConfig.vidHeight - 128, 128, 128); FBO_BlitFromTexture(tr.sunShadowDepthImage[2], NULL, NULL, NULL, dstBox, NULL, NULL, 0); - VectorSet4(dstBox, 384, 0, 128, 128); + VectorSet4(dstBox, 384, glConfig.vidHeight - 128, 128, 128); FBO_BlitFromTexture(tr.sunShadowDepthImage[3], NULL, NULL, NULL, dstBox, NULL, NULL, 0); } + if (0 && r_shadows->integer == 4) + { + ivec4_t dstBox; + VectorSet4(dstBox, 512 + 0, glConfig.vidHeight - 128, 128, 128); + FBO_BlitFromTexture(tr.pshadowMaps[0], NULL, NULL, NULL, dstBox, NULL, NULL, 0); + VectorSet4(dstBox, 512 + 128, glConfig.vidHeight - 128, 128, 128); + FBO_BlitFromTexture(tr.pshadowMaps[1], NULL, NULL, NULL, dstBox, NULL, NULL, 0); + VectorSet4(dstBox, 512 + 256, glConfig.vidHeight - 128, 128, 128); + FBO_BlitFromTexture(tr.pshadowMaps[2], NULL, NULL, NULL, dstBox, NULL, NULL, 0); + VectorSet4(dstBox, 512 + 384, glConfig.vidHeight - 128, 128, 128); + FBO_BlitFromTexture(tr.pshadowMaps[3], NULL, NULL, NULL, dstBox, NULL, NULL, 0); + } + if (0) { ivec4_t dstBox; diff --git a/code/renderergl2/tr_bsp.c b/code/renderergl2/tr_bsp.c index 78728f81..ad5fe3a3 100644 --- a/code/renderergl2/tr_bsp.c +++ b/code/renderergl2/tr_bsp.c @@ -105,11 +105,7 @@ static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { int shift, r, g, b; // shift the color data based on overbright range -#if defined(USE_OVERBRIGHT) shift = r_mapOverBrightBits->integer - tr.overbrightBits; -#else - shift = 0; -#endif // shift the data based on overbright range r = in[0] << shift; @@ -140,13 +136,10 @@ R_ColorShiftLightingFloats =============== */ -static void R_ColorShiftLightingFloats(float in[4], float out[4], float scale ) +static void R_ColorShiftLightingFloats(float in[4], float out[4]) { float r, g, b; - -#if defined(USE_OVERBRIGHT) - scale *= 1 << (r_mapOverBrightBits->integer - tr.overbrightBits); -#endif + float scale = (1 << (r_mapOverBrightBits->integer - tr.overbrightBits)) / 255.0f; r = in[0] * scale; g = in[1] * scale; @@ -191,12 +184,11 @@ void ColorToRGBM(const vec3_t color, unsigned char rgbm[4]) rgbm[2] = (unsigned char) (sample[2] * 255); } -void ColorToRGBA16F(const vec3_t color, unsigned short rgba16f[4]) +void ColorToRGB16(const vec3_t color, uint16_t rgb16[3]) { - rgba16f[0] = FloatToHalf(color[0]); - rgba16f[1] = FloatToHalf(color[1]); - rgba16f[2] = FloatToHalf(color[2]); - rgba16f[3] = FloatToHalf(1.0f); + rgb16[0] = color[0] * 65535.0f + 0.5f; + rgb16[1] = color[1] * 65535.0f + 0.5f; + rgb16[2] = color[2] * 65535.0f + 0.5f; } @@ -207,13 +199,14 @@ R_LoadLightmaps =============== */ #define DEFAULT_LIGHTMAP_SIZE 128 -#define MAX_LIGHTMAP_PAGES 2 static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { + imgFlags_t imgFlags = IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE; byte *buf, *buf_p; dsurface_t *surf; int len; byte *image; int i, j, numLightmaps, textureInternalFormat = 0; + int numLightmapsPerPage = 16; float maxIntensity = 0; double sumIntensity = 0; @@ -253,36 +246,24 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { if (tr.worldDeluxeMapping) numLightmaps >>= 1; - if(numLightmaps == 1) - { - //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason. - //this avoids this, but isn't the correct solution. - numLightmaps++; - } - else if (r_mergeLightmaps->integer && numLightmaps >= 1024 ) - { - // FIXME: fat light maps don't support more than 1024 light maps - ri.Printf(PRINT_WARNING, "WARNING: number of lightmaps > 1024\n"); - numLightmaps = 1024; - } - - // use fat lightmaps of an appropriate size + // Use fat lightmaps of an appropriate size. if (r_mergeLightmaps->integer) { - tr.fatLightmapSize = 512; - tr.fatLightmapStep = tr.fatLightmapSize / tr.lightmapSize; + int maxLightmapsPerAxis = glConfig.maxTextureSize / tr.lightmapSize; + int lightmapCols = 4, lightmapRows = 4; - // at most MAX_LIGHTMAP_PAGES - while (tr.fatLightmapStep * tr.fatLightmapStep * MAX_LIGHTMAP_PAGES < numLightmaps && tr.fatLightmapSize != glConfig.maxTextureSize ) - { - tr.fatLightmapSize <<= 1; - tr.fatLightmapStep = tr.fatLightmapSize / tr.lightmapSize; - } + // Increase width at first, then height. + while (lightmapCols * lightmapRows < numLightmaps && lightmapCols != maxLightmapsPerAxis) + lightmapCols <<= 1; - tr.numLightmaps = numLightmaps / (tr.fatLightmapStep * tr.fatLightmapStep); + while (lightmapCols * lightmapRows < numLightmaps && lightmapRows != maxLightmapsPerAxis) + lightmapRows <<= 1; - if (numLightmaps % (tr.fatLightmapStep * tr.fatLightmapStep) != 0) - tr.numLightmaps++; + tr.fatLightmapCols = lightmapCols; + tr.fatLightmapRows = lightmapRows; + numLightmapsPerPage = lightmapCols * lightmapRows; + + tr.numLightmaps = (numLightmaps + (numLightmapsPerPage - 1)) / numLightmapsPerPage; } else { @@ -292,25 +273,30 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { tr.lightmaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low ); if (tr.worldDeluxeMapping) - { tr.deluxemaps = ri.Hunk_Alloc( tr.numLightmaps * sizeof(image_t *), h_low ); - } - if (glRefConfig.floatLightmap) - textureInternalFormat = GL_RGBA16F_ARB; - else - textureInternalFormat = GL_RGBA8; + textureInternalFormat = GL_RGBA8; + if (r_hdr->integer) + { + // Check for the first hdr lightmap, if it exists, use GL_RGBA16 for textures. + char filename[MAX_QPATH]; + + Com_sprintf(filename, sizeof(filename), "maps/%s/lm_0000.hdr", s_worldData.baseName); + if (ri.FS_FileExists(filename)) + textureInternalFormat = GL_RGBA16; + } if (r_mergeLightmaps->integer) { + int width = tr.fatLightmapCols * tr.lightmapSize; + int height = tr.fatLightmapRows * tr.lightmapSize; + for (i = 0; i < tr.numLightmaps; i++) { - tr.lightmaps[i] = R_CreateImage(va("_fatlightmap%d", i), NULL, tr.fatLightmapSize, tr.fatLightmapSize, IMGTYPE_COLORALPHA, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, textureInternalFormat ); + tr.lightmaps[i] = R_CreateImage(va("_fatlightmap%d", i), NULL, width, height, IMGTYPE_COLORALPHA, imgFlags, textureInternalFormat); if (tr.worldDeluxeMapping) - { - tr.deluxemaps[i] = R_CreateImage(va("_fatdeluxemap%d", i), NULL, tr.fatLightmapSize, tr.fatLightmapSize, IMGTYPE_DELUXE, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 ); - } + tr.deluxemaps[i] = R_CreateImage(va("_fatdeluxemap%d", i), NULL, width, height, IMGTYPE_DELUXE, imgFlags, 0); } } @@ -322,11 +308,11 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { if (r_mergeLightmaps->integer) { - int lightmaponpage = i % (tr.fatLightmapStep * tr.fatLightmapStep); - xoff = (lightmaponpage % tr.fatLightmapStep) * tr.lightmapSize; - yoff = (lightmaponpage / tr.fatLightmapStep) * tr.lightmapSize; + int lightmaponpage = i % numLightmapsPerPage; + xoff = (lightmaponpage % tr.fatLightmapCols) * tr.lightmapSize; + yoff = (lightmaponpage / tr.fatLightmapCols) * tr.lightmapSize; - lightmapnum /= (tr.fatLightmapStep * tr.fatLightmapStep); + lightmapnum /= numLightmapsPerPage; } // if (tr.worldLightmapping) @@ -336,7 +322,7 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { int size = 0; // look for hdr lightmaps - if (r_hdr->integer) + if (textureInternalFormat == GL_RGBA16) { Com_sprintf( filename, sizeof( filename ), "maps/%s/lm_%04d.hdr", s_worldData.baseName, i * (tr.worldDeluxeMapping ? 2 : 1) ); //ri.Printf(PRINT_ALL, "looking for %s\n", filename); @@ -346,47 +332,37 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { if (hdrLightmap) { - byte *p = hdrLightmap; + byte *p = hdrLightmap, *end = hdrLightmap + size; //ri.Printf(PRINT_ALL, "found!\n"); /* FIXME: don't just skip over this header and actually parse it */ - while (size && !(*p == '\n' && *(p+1) == '\n')) - { - size--; + while (p < end && !(*p == '\n' && *(p+1) == '\n')) p++; - } - if (!size) - ri.Error(ERR_DROP, "Bad header for %s!", filename); - - size -= 2; p += 2; - while (size && !(*p == '\n')) - { - size--; + while (p < end && !(*p == '\n')) p++; - } - size--; p++; - buf_p = (byte *)p; + if (p >= end) + ri.Error(ERR_DROP, "Bad header for %s!", filename); + + buf_p = p; #if 0 // HDRFILE_RGBE - if (size != tr.lightmapSize * tr.lightmapSize * 4) + if ((int)(end - hdrLightmap) != tr.lightmapSize * tr.lightmapSize * 4) ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size); #else // HDRFILE_FLOAT - if (size != tr.lightmapSize * tr.lightmapSize * 12) + if ((int)(end - hdrLightmap) != tr.lightmapSize * tr.lightmapSize * 12) ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size); #endif } else { - if (tr.worldDeluxeMapping) - buf_p = buf + (i * 2) * tr.lightmapSize * tr.lightmapSize * 3; - else - buf_p = buf + i * tr.lightmapSize * tr.lightmapSize * 3; + int imgOffset = tr.worldDeluxeMapping ? i * 2 : i; + buf_p = buf + imgOffset * tr.lightmapSize * tr.lightmapSize * 3; } for ( j = 0 ; j < tr.lightmapSize * tr.lightmapSize; j++ ) @@ -410,14 +386,12 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { #endif color[3] = 1.0f; - R_ColorShiftLightingFloats(color, color, 1.0f/255.0f); + R_ColorShiftLightingFloats(color, color); - if (glRefConfig.floatLightmap) - ColorToRGBA16F(color, (unsigned short *)(&image[j*8])); - else - ColorToRGBM(color, &image[j*4]); + ColorToRGB16(color, (uint16_t *)(&image[j * 8])); + ((uint16_t *)(&image[j * 8]))[3] = 65535; } - else if (glRefConfig.floatLightmap) + else if (textureInternalFormat == GL_RGBA16) { vec4_t color; @@ -437,9 +411,10 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { } color[3] = 1.0f; - R_ColorShiftLightingFloats(color, color, 1.0f/255.0f); + R_ColorShiftLightingFloats(color, color); - ColorToRGBA16F(color, (unsigned short *)(&image[j*8])); + ColorToRGB16(color, (uint16_t *)(&image[j * 8])); + ((uint16_t *)(&image[j * 8]))[3] = 65535; } else { @@ -479,9 +454,9 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { } if (r_mergeLightmaps->integer) - R_UpdateSubImage(tr.lightmaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize); + R_UpdateSubImage(tr.lightmaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize, textureInternalFormat); else - tr.lightmaps[i] = R_CreateImage(va("*lightmap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_COLORALPHA, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, textureInternalFormat ); + tr.lightmaps[i] = R_CreateImage(va("*lightmap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_COLORALPHA, imgFlags, textureInternalFormat ); if (hdrLightmap) ri.FS_FreeFile(hdrLightmap); @@ -508,13 +483,9 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { } if (r_mergeLightmaps->integer) - { - R_UpdateSubImage(tr.deluxemaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize ); - } + R_UpdateSubImage(tr.deluxemaps[lightmapnum], image, xoff, yoff, tr.lightmapSize, tr.lightmapSize, GL_RGBA8 ); else - { - tr.deluxemaps[i] = R_CreateImage(va("*deluxemap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_DELUXE, IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 ); - } + tr.deluxemaps[i] = R_CreateImage(va("*deluxemap%d", i), image, tr.lightmapSize, tr.lightmapSize, IMGTYPE_DELUXE, imgFlags, 0 ); } } @@ -534,15 +505,10 @@ static float FatPackU(float input, int lightmapnum) if (tr.worldDeluxeMapping) lightmapnum >>= 1; - if(tr.fatLightmapSize > 0) + if (tr.fatLightmapCols > 0) { - int x; - - lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); - - x = lightmapnum % tr.fatLightmapStep; - - return (input / ((float)tr.fatLightmapStep)) + ((1.0 / ((float)tr.fatLightmapStep)) * (float)x); + lightmapnum %= (tr.fatLightmapCols * tr.fatLightmapRows); + return (input + (lightmapnum % tr.fatLightmapCols)) / (float)(tr.fatLightmapCols); } return input; @@ -556,15 +522,10 @@ static float FatPackV(float input, int lightmapnum) if (tr.worldDeluxeMapping) lightmapnum >>= 1; - if(tr.fatLightmapSize > 0) + if (tr.fatLightmapCols > 0) { - int y; - - lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); - - y = lightmapnum / tr.fatLightmapStep; - - return (input / ((float)tr.fatLightmapStep)) + ((1.0 / ((float)tr.fatLightmapStep)) * (float)y); + lightmapnum %= (tr.fatLightmapCols * tr.fatLightmapRows); + return (input + (lightmapnum / tr.fatLightmapCols)) / (float)(tr.fatLightmapRows); } return input; @@ -579,10 +540,8 @@ static int FatLightmap(int lightmapnum) if (tr.worldDeluxeMapping) lightmapnum >>= 1; - if (tr.fatLightmapSize > 0) - { - return lightmapnum / (tr.fatLightmapStep * tr.fatLightmapStep); - } + if (tr.fatLightmapCols > 0) + return lightmapnum / (tr.fatLightmapCols * tr.fatLightmapRows); return lightmapnum; } @@ -667,6 +626,67 @@ static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { return shader; } +void LoadDrawVertToSrfVert(srfVert_t *s, drawVert_t *d, int realLightmapNum, float hdrVertColors[3], vec3_t *bounds) +{ + vec4_t v; + + s->xyz[0] = LittleFloat(d->xyz[0]); + s->xyz[1] = LittleFloat(d->xyz[1]); + s->xyz[2] = LittleFloat(d->xyz[2]); + + if (bounds) + AddPointToBounds(s->xyz, bounds[0], bounds[1]); + + s->st[0] = LittleFloat(d->st[0]); + s->st[1] = LittleFloat(d->st[1]); + + if (realLightmapNum >= 0) + { + s->lightmap[0] = FatPackU(LittleFloat(d->lightmap[0]), realLightmapNum); + s->lightmap[1] = FatPackV(LittleFloat(d->lightmap[1]), realLightmapNum); + } + else + { + s->lightmap[0] = LittleFloat(d->lightmap[0]); + s->lightmap[1] = LittleFloat(d->lightmap[1]); + } + + v[0] = LittleFloat(d->normal[0]); + v[1] = LittleFloat(d->normal[1]); + v[2] = LittleFloat(d->normal[2]); + + R_VaoPackNormal(s->normal, v); + + if (hdrVertColors) + { + v[0] = hdrVertColors[0]; + v[1] = hdrVertColors[1]; + v[2] = hdrVertColors[2]; + } + else + { + //hack: convert LDR vertex colors to HDR + if (r_hdr->integer) + { + v[0] = MAX(d->color[0], 0.499f); + v[1] = MAX(d->color[1], 0.499f); + v[2] = MAX(d->color[2], 0.499f); + } + else + { + v[0] = d->color[0]; + v[1] = d->color[1]; + v[2] = d->color[2]; + } + + } + v[3] = d->color[3] / 255.0f; + + R_ColorShiftLightingFloats(v, v); + R_VaoPackColor(s->color, v); +} + + /* =============== ParseFace @@ -714,50 +734,7 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]); verts += LittleLong(ds->firstVert); for(i = 0; i < numVerts; i++) - { - vec4_t color; - - for(j = 0; j < 3; j++) - { - cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]); - cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]); - } - AddPointToBounds(cv->verts[i].xyz, surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]); - for(j = 0; j < 2; j++) - { - cv->verts[i].st[j] = LittleFloat(verts[i].st[j]); - //cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]); - } - cv->verts[i].lightmap[0] = FatPackU(LittleFloat(verts[i].lightmap[0]), realLightmapNum); - cv->verts[i].lightmap[1] = FatPackV(LittleFloat(verts[i].lightmap[1]), realLightmapNum); - - if (hdrVertColors) - { - color[0] = hdrVertColors[(ds->firstVert + i) * 3 ]; - color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1]; - color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2]; - } - else - { - //hack: convert LDR vertex colors to HDR - if (r_hdr->integer) - { - color[0] = MAX(verts[i].color[0], 0.499f); - color[1] = MAX(verts[i].color[1], 0.499f); - color[2] = MAX(verts[i].color[2], 0.499f); - } - else - { - color[0] = verts[i].color[0]; - color[1] = verts[i].color[1]; - color[2] = verts[i].color[2]; - } - - } - color[3] = verts[i].color[3] / 255.0f; - - R_ColorShiftLightingFloats( color, cv->verts[i].vertexColors, 1.0f / 255.0f ); - } + LoadDrawVertToSrfVert(&cv->verts[i], &verts[i], realLightmapNum, hdrVertColors ? hdrVertColors + (ds->firstVert + i) * 3 : NULL, surf->cullinfo.bounds); // copy triangles badTriangles = 0; @@ -798,7 +775,6 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, surf->data = (surfaceType_t *)cv; -#ifdef USE_VERT_TANGENT_SPACE // Calculate tangent spaces { srfVert_t *dv[3]; @@ -812,7 +788,6 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, R_CalcTangentVectors(dv); } } -#endif } @@ -822,8 +797,8 @@ ParseMesh =============== */ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, msurface_t *surf ) { - srfBspSurface_t *grid; - int i, j; + srfBspSurface_t *grid = (srfBspSurface_t *)surf->data; + int i; int width, height, numPoints; srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE]; vec3_t bounds[2]; @@ -858,53 +833,10 @@ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, verts += LittleLong( ds->firstVert ); numPoints = width * height; for(i = 0; i < numPoints; i++) - { - vec4_t color; - - for(j = 0; j < 3; j++) - { - points[i].xyz[j] = LittleFloat(verts[i].xyz[j]); - points[i].normal[j] = LittleFloat(verts[i].normal[j]); - } - - for(j = 0; j < 2; j++) - { - points[i].st[j] = LittleFloat(verts[i].st[j]); - //points[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]); - } - points[i].lightmap[0] = FatPackU(LittleFloat(verts[i].lightmap[0]), realLightmapNum); - points[i].lightmap[1] = FatPackV(LittleFloat(verts[i].lightmap[1]), realLightmapNum); - - if (hdrVertColors) - { - color[0] = hdrVertColors[(ds->firstVert + i) * 3 ]; - color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1]; - color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2]; - } - else - { - //hack: convert LDR vertex colors to HDR - if (r_hdr->integer) - { - color[0] = MAX(verts[i].color[0], 0.499f); - color[1] = MAX(verts[i].color[1], 0.499f); - color[2] = MAX(verts[i].color[2], 0.499f); - } - else - { - color[0] = verts[i].color[0]; - color[1] = verts[i].color[1]; - color[2] = verts[i].color[2]; - } - } - color[3] = verts[i].color[3] / 255.0f; - - R_ColorShiftLightingFloats( color, points[i].vertexColors, 1.0f / 255.0f ); - } + LoadDrawVertToSrfVert(&points[i], &verts[i], realLightmapNum, hdrVertColors ? hdrVertColors + (ds->firstVert + i) * 3 : NULL, NULL); // pre-tesseleate - grid = R_SubdividePatchToGrid( width, height, points ); - surf->data = (surfaceType_t *)grid; + R_SubdividePatchToGrid( grid, width, height, points ); // copy the level of detail origin, which is the center // of the group of all curves that must subdivide the same @@ -917,6 +849,12 @@ static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, VectorScale( bounds[1], 0.5f, grid->lodOrigin ); VectorSubtract( bounds[0], grid->lodOrigin, tmpVec ); grid->lodRadius = VectorLength( tmpVec ); + + surf->cullinfo.type = CULLINFO_BOX | CULLINFO_SPHERE; + VectorCopy(grid->cullBounds[0], surf->cullinfo.bounds[0]); + VectorCopy(grid->cullBounds[1], surf->cullinfo.bounds[1]); + VectorCopy(grid->cullOrigin, surf->cullinfo.localOrigin); + surf->cullinfo.radius = grid->cullRadius; } /* @@ -959,49 +897,7 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColor ClearBounds(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1]); verts += LittleLong(ds->firstVert); for(i = 0; i < numVerts; i++) - { - vec4_t color; - - for(j = 0; j < 3; j++) - { - cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]); - cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]); - } - - AddPointToBounds( cv->verts[i].xyz, surf->cullinfo.bounds[0], surf->cullinfo.bounds[1] ); - - for(j = 0; j < 2; j++) - { - cv->verts[i].st[j] = LittleFloat(verts[i].st[j]); - cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]); - } - - if (hdrVertColors) - { - color[0] = hdrVertColors[(ds->firstVert + i) * 3 ]; - color[1] = hdrVertColors[(ds->firstVert + i) * 3 + 1]; - color[2] = hdrVertColors[(ds->firstVert + i) * 3 + 2]; - } - else - { - //hack: convert LDR vertex colors to HDR - if (r_hdr->integer) - { - color[0] = MAX(verts[i].color[0], 0.499f); - color[1] = MAX(verts[i].color[1], 0.499f); - color[2] = MAX(verts[i].color[2], 0.499f); - } - else - { - color[0] = verts[i].color[0]; - color[1] = verts[i].color[1]; - color[2] = verts[i].color[2]; - } - } - color[3] = verts[i].color[3] / 255.0f; - - R_ColorShiftLightingFloats( color, cv->verts[i].vertexColors, 1.0f / 255.0f ); - } + LoadDrawVertToSrfVert(&cv->verts[i], &verts[i], -1, hdrVertColors ? hdrVertColors + (ds->firstVert + i) * 3 : NULL, surf->cullinfo.bounds); // copy triangles badTriangles = 0; @@ -1031,7 +927,6 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColor cv->numIndexes -= badTriangles * 3; } -#ifdef USE_VERT_TANGENT_SPACE // Calculate tangent spaces { srfVert_t *dv[3]; @@ -1045,7 +940,6 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColor R_CalcTangentVectors(dv); } } -#endif } /* @@ -1077,6 +971,8 @@ static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] ); flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] ); } + + surf->cullinfo.type = CULLINFO_NONE; } @@ -1321,7 +1217,7 @@ int R_StitchPatches( int grid1num, int grid2num ) { // insert column into grid2 right after after column l if (m) row = grid2->height-1; else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, + R_GridInsertColumn( grid2, l+1, row, grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); grid2->lodStitched = qfalse; s_worldData.surfaces[grid2num].data = (void *) grid2; @@ -1365,7 +1261,7 @@ int R_StitchPatches( int grid1num, int grid2num ) { // insert row into grid2 right after after row l if (m) column = grid2->width-1; else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, + R_GridInsertRow( grid2, l+1, column, grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]); grid2->lodStitched = qfalse; s_worldData.surfaces[grid2num].data = (void *) grid2; @@ -1418,7 +1314,7 @@ int R_StitchPatches( int grid1num, int grid2num ) { // insert column into grid2 right after after column l if (m) row = grid2->height-1; else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, + R_GridInsertColumn( grid2, l+1, row, grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); grid2->lodStitched = qfalse; s_worldData.surfaces[grid2num].data = (void *) grid2; @@ -1462,7 +1358,7 @@ int R_StitchPatches( int grid1num, int grid2num ) { // insert row into grid2 right after after row l if (m) column = grid2->width-1; else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, + R_GridInsertRow( grid2, l+1, column, grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]); grid2->lodStitched = qfalse; s_worldData.surfaces[grid2num].data = (void *) grid2; @@ -1516,7 +1412,7 @@ int R_StitchPatches( int grid1num, int grid2num ) { // insert column into grid2 right after after column l if (m) row = grid2->height-1; else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, + R_GridInsertColumn( grid2, l+1, row, grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); grid2->lodStitched = qfalse; s_worldData.surfaces[grid2num].data = (void *) grid2; @@ -1560,7 +1456,7 @@ int R_StitchPatches( int grid1num, int grid2num ) { // insert row into grid2 right after after row l if (m) column = grid2->width-1; else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, + R_GridInsertRow( grid2, l+1, column, grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]); if (!grid2) break; @@ -1615,7 +1511,7 @@ int R_StitchPatches( int grid1num, int grid2num ) { // insert column into grid2 right after after column l if (m) row = grid2->height-1; else row = 0; - grid2 = R_GridInsertColumn( grid2, l+1, row, + R_GridInsertColumn( grid2, l+1, row, grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); grid2->lodStitched = qfalse; s_worldData.surfaces[grid2num].data = (void *) grid2; @@ -1659,7 +1555,7 @@ int R_StitchPatches( int grid1num, int grid2num ) { // insert row into grid2 right after after row l if (m) column = grid2->width-1; else column = 0; - grid2 = R_GridInsertRow( grid2, l+1, column, + R_GridInsertRow( grid2, l+1, column, grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]); grid2->lodStitched = qfalse; s_worldData.surfaces[grid2num].data = (void *) grid2; @@ -1749,472 +1645,41 @@ R_MovePatchSurfacesToHunk =============== */ void R_MovePatchSurfacesToHunk(void) { - int i, size; - srfBspSurface_t *grid, *hunkgrid; + int i; + srfBspSurface_t *grid; for ( i = 0; i < s_worldData.numsurfaces; i++ ) { + void *copyFrom; // grid = (srfBspSurface_t *) s_worldData.surfaces[i].data; // if this surface is not a grid if ( grid->surfaceType != SF_GRID ) continue; // - size = sizeof(*grid); - hunkgrid = ri.Hunk_Alloc(size, h_low); - Com_Memcpy(hunkgrid, grid, size); - hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low ); - Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 ); + copyFrom = grid->widthLodError; + grid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low ); + Com_Memcpy(grid->widthLodError, copyFrom, grid->width * 4); + ri.Free(copyFrom); - hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low ); - Com_Memcpy( hunkgrid->heightLodError, grid->heightLodError, grid->height * 4 ); + copyFrom = grid->heightLodError; + grid->heightLodError = ri.Hunk_Alloc(grid->height * 4, h_low); + Com_Memcpy(grid->heightLodError, copyFrom, grid->height * 4); + ri.Free(copyFrom); - hunkgrid->numIndexes = grid->numIndexes; - hunkgrid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low); - Com_Memcpy(hunkgrid->indexes, grid->indexes, grid->numIndexes * sizeof(glIndex_t)); + copyFrom = grid->indexes; + grid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low); + Com_Memcpy(grid->indexes, copyFrom, grid->numIndexes * sizeof(glIndex_t)); + ri.Free(copyFrom); - hunkgrid->numVerts = grid->numVerts; - hunkgrid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low); - Com_Memcpy(hunkgrid->verts, grid->verts, grid->numVerts * sizeof(srfVert_t)); - - R_FreeSurfaceGridMesh( grid ); - - s_worldData.surfaces[i].data = (void *) hunkgrid; + copyFrom = grid->verts; + grid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low); + Com_Memcpy(grid->verts, copyFrom, grid->numVerts * sizeof(srfVert_t)); + ri.Free(copyFrom); } } -/* -================= -BSPSurfaceCompare -compare function for qsort() -================= -*/ -static int BSPSurfaceCompare(const void *a, const void *b) -{ - msurface_t *aa, *bb; - - aa = *(msurface_t **) a; - bb = *(msurface_t **) b; - - // shader first - if(aa->shader->sortedIndex < bb->shader->sortedIndex) - return -1; - - else if(aa->shader->sortedIndex > bb->shader->sortedIndex) - return 1; - - // by fogIndex - if(aa->fogIndex < bb->fogIndex) - return -1; - - else if(aa->fogIndex > bb->fogIndex) - return 1; - - // by cubemapIndex - if(aa->cubemapIndex < bb->cubemapIndex) - return -1; - - else if(aa->cubemapIndex > bb->cubemapIndex) - return 1; - - // by leaf - if (s_worldData.surfacesViewCount[aa - s_worldData.surfaces] < s_worldData.surfacesViewCount[bb - s_worldData.surfaces]) - return -1; - - else if (s_worldData.surfacesViewCount[aa - s_worldData.surfaces] > s_worldData.surfacesViewCount[bb - s_worldData.surfaces]) - return 1; - - // by surface number - if (aa < bb) - return -1; - - else if (aa > bb) - return 1; - - return 0; -} - - -static void CopyVert(const srfVert_t * in, srfVert_t * out) -{ - VectorCopy(in->xyz, out->xyz); -#ifdef USE_VERT_TANGENT_SPACE - VectorCopy4(in->tangent, out->tangent); -#endif - VectorCopy(in->normal, out->normal); - VectorCopy(in->lightdir, out->lightdir); - - VectorCopy2(in->st, out->st); - VectorCopy2(in->lightmap, out->lightmap); - - VectorCopy4(in->vertexColors, out->vertexColors); -} - - -/* -=============== -R_CreateWorldVaos -=============== -*/ -static void R_CreateWorldVaos(void) -{ - int i, j, k; - - int numVerts; - srfVert_t *verts; - - int numIndexes; - glIndex_t *indexes; - - int numSortedSurfaces, numSurfaces; - msurface_t *surface, **firstSurf, **lastSurf, **currSurf; - msurface_t **surfacesSorted; - - vao_t *vao; - - int maxVboSize = 4 * 1024 * 1024; - - int startTime, endTime; - - startTime = ri.Milliseconds(); - - // mark surfaces with best matching leaf, using overlapping bounds - // using surfaceViewCount[] as leaf number, and surfacesDlightBits[] as coverage * 256 - for (i = 0; i < s_worldData.numWorldSurfaces; i++) - { - s_worldData.surfacesViewCount[i] = -1; - } - - for (i = 0; i < s_worldData.numWorldSurfaces; i++) - { - s_worldData.surfacesDlightBits[i] = 0; - } - - for (i = s_worldData.numDecisionNodes; i < s_worldData.numnodes; i++) - { - mnode_t *leaf = s_worldData.nodes + i; - - for (j = leaf->firstmarksurface; j < leaf->firstmarksurface + leaf->nummarksurfaces; j++) - { - int surfaceNum = s_worldData.marksurfaces[j]; - msurface_t *surface = s_worldData.surfaces + surfaceNum; - float coverage = 1.0f; - int iCoverage; - - for (k = 0; k < 3; k++) - { - float left, right; - - if (leaf->mins[k] > surface->cullinfo.bounds[1][k] || surface->cullinfo.bounds[0][k] > leaf->maxs[k]) - { - coverage = 0.0f; - break; - } - - left = MAX(leaf->mins[k], surface->cullinfo.bounds[0][k]); - right = MIN(leaf->maxs[k], surface->cullinfo.bounds[1][k]); - - // nudge a bit in case this is an axis aligned wall - coverage *= right - left + 1.0f/256.0f; - } - - iCoverage = coverage * 256; - - if (iCoverage > s_worldData.surfacesDlightBits[surfaceNum]) - { - s_worldData.surfacesDlightBits[surfaceNum] = iCoverage; - s_worldData.surfacesViewCount[surfaceNum] = i - s_worldData.numDecisionNodes; - } - } - } - - for (i = 0; i < s_worldData.numWorldSurfaces; i++) - { - s_worldData.surfacesDlightBits[i] = 0; - } - - // count surfaces - numSortedSurfaces = 0; - for(surface = s_worldData.surfaces; surface < s_worldData.surfaces + s_worldData.numWorldSurfaces; surface++) - { - srfBspSurface_t *bspSurf; - shader_t *shader = surface->shader; - - if (shader->isPortal || shader->isSky || ShaderRequiresCPUDeforms(shader)) - continue; - - // check for this now so we can use srfBspSurface_t* universally in the rest of the function - if (!(*surface->data == SF_FACE || *surface->data == SF_GRID || *surface->data == SF_TRIANGLES)) - continue; - - bspSurf = (srfBspSurface_t *) surface->data; - - if (!bspSurf->numIndexes || !bspSurf->numVerts) - continue; - - numSortedSurfaces++; - } - - // presort surfaces - surfacesSorted = ri.Malloc(numSortedSurfaces * sizeof(*surfacesSorted)); - - j = 0; - for(surface = s_worldData.surfaces; surface < s_worldData.surfaces + s_worldData.numWorldSurfaces; surface++) - { - srfBspSurface_t *bspSurf; - shader_t *shader = surface->shader; - - if (shader->isPortal || shader->isSky || ShaderRequiresCPUDeforms(shader)) - continue; - - // check for this now so we can use srfBspSurface_t* universally in the rest of the function - if (!(*surface->data == SF_FACE || *surface->data == SF_GRID || *surface->data == SF_TRIANGLES)) - continue; - - bspSurf = (srfBspSurface_t *) surface->data; - - if (!bspSurf->numIndexes || !bspSurf->numVerts) - continue; - - surfacesSorted[j++] = surface; - } - - qsort(surfacesSorted, numSortedSurfaces, sizeof(*surfacesSorted), BSPSurfaceCompare); - - k = 0; - for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf) - { - int currVboSize; - - // Find range of surfaces to place in a VAO by: - // - Collecting a number of surfaces which fit under maxVboSize, or - // - All the surfaces with a single shader which go over maxVboSize - currVboSize = 0; - while (currVboSize < maxVboSize && lastSurf < surfacesSorted + numSortedSurfaces) - { - int addVboSize, currShaderIndex; - - addVboSize = 0; - currShaderIndex = (*lastSurf)->shader->sortedIndex; - - for(currSurf = lastSurf; currSurf < surfacesSorted + numSortedSurfaces && (*currSurf)->shader->sortedIndex == currShaderIndex; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - - addVboSize += bspSurf->numVerts * sizeof(srfVert_t); - } - - if (currVboSize != 0 && addVboSize + currVboSize > maxVboSize) - break; - - lastSurf = currSurf; - - currVboSize += addVboSize; - } - - // count verts/indexes/surfaces - numVerts = 0; - numIndexes = 0; - numSurfaces = 0; - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - - numVerts += bspSurf->numVerts; - numIndexes += bspSurf->numIndexes; - numSurfaces++; - } - - ri.Printf(PRINT_ALL, "...calculating world VAO %d ( %i verts %i tris )\n", k, numVerts, numIndexes / 3); - - // create arrays - verts = ri.Hunk_AllocateTempMemory(numVerts * sizeof(srfVert_t)); - indexes = ri.Hunk_AllocateTempMemory(numIndexes * sizeof(glIndex_t)); - - // set up indices and copy vertices - numVerts = 0; - numIndexes = 0; - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - glIndex_t *surfIndex; - - bspSurf->firstIndex = numIndexes; - bspSurf->minIndex = numVerts + bspSurf->indexes[0]; - bspSurf->maxIndex = numVerts + bspSurf->indexes[0]; - - for(i = 0, surfIndex = bspSurf->indexes; i < bspSurf->numIndexes; i++, surfIndex++) - { - indexes[numIndexes++] = numVerts + *surfIndex; - bspSurf->minIndex = MIN(bspSurf->minIndex, numVerts + *surfIndex); - bspSurf->maxIndex = MAX(bspSurf->maxIndex, numVerts + *surfIndex); - } - - bspSurf->firstVert = numVerts; - - for(i = 0; i < bspSurf->numVerts; i++) - { - CopyVert(&bspSurf->verts[i], &verts[numVerts++]); - } - } - - vao = R_CreateVao2(va("staticBspModel%i_VAO", k), numVerts, verts, numIndexes, indexes); - - // point bsp surfaces to VAO - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *bspSurf = (srfBspSurface_t *) (*currSurf)->data; - - bspSurf->vao = vao; - } - - ri.Hunk_FreeTempMemory(indexes); - ri.Hunk_FreeTempMemory(verts); - - k++; - } - - if (r_mergeLeafSurfaces->integer) - { - msurface_t *mergedSurf; - - // count merged surfaces - int numMergedSurfaces = 0, numUnmergedSurfaces = 0; - for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf) - { - for (lastSurf++ ; lastSurf < surfacesSorted + numSortedSurfaces; lastSurf++) - { - int lastSurfLeafIndex, firstSurfLeafIndex; - - if ((*lastSurf)->shader != (*firstSurf)->shader - || (*lastSurf)->fogIndex != (*firstSurf)->fogIndex - || (*lastSurf)->cubemapIndex != (*firstSurf)->cubemapIndex) - break; - - lastSurfLeafIndex = s_worldData.surfacesViewCount[*lastSurf - s_worldData.surfaces]; - firstSurfLeafIndex = s_worldData.surfacesViewCount[*firstSurf - s_worldData.surfaces]; - - if (lastSurfLeafIndex != firstSurfLeafIndex) - break; - } - - // don't merge single surfaces - if (firstSurf + 1 == lastSurf) - { - numUnmergedSurfaces++; - continue; - } - - numMergedSurfaces++; - } - - // Allocate merged surfaces - s_worldData.mergedSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfaces) * numMergedSurfaces, h_low); - s_worldData.mergedSurfacesViewCount = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesViewCount) * numMergedSurfaces, h_low); - s_worldData.mergedSurfacesDlightBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesDlightBits) * numMergedSurfaces, h_low); - s_worldData.mergedSurfacesPshadowBits = ri.Hunk_Alloc(sizeof(*s_worldData.mergedSurfacesPshadowBits) * numMergedSurfaces, h_low); - s_worldData.numMergedSurfaces = numMergedSurfaces; - - // view surfaces are like mark surfaces, except negative ones represent merged surfaces - // -1 represents 0, -2 represents 1, and so on - s_worldData.viewSurfaces = ri.Hunk_Alloc(sizeof(*s_worldData.viewSurfaces) * s_worldData.nummarksurfaces, h_low); - - // copy view surfaces into mark surfaces - for (i = 0; i < s_worldData.nummarksurfaces; i++) - { - s_worldData.viewSurfaces[i] = s_worldData.marksurfaces[i]; - } - - // actually merge surfaces - mergedSurf = s_worldData.mergedSurfaces; - for(firstSurf = lastSurf = surfacesSorted; firstSurf < surfacesSorted + numSortedSurfaces; firstSurf = lastSurf) - { - srfBspSurface_t *bspSurf, *vaoSurf; - - for ( lastSurf++ ; lastSurf < surfacesSorted + numSortedSurfaces; lastSurf++) - { - int lastSurfLeafIndex, firstSurfLeafIndex; - - if ((*lastSurf)->shader != (*firstSurf)->shader - || (*lastSurf)->fogIndex != (*firstSurf)->fogIndex - || (*lastSurf)->cubemapIndex != (*firstSurf)->cubemapIndex) - break; - - lastSurfLeafIndex = s_worldData.surfacesViewCount[*lastSurf - s_worldData.surfaces]; - firstSurfLeafIndex = s_worldData.surfacesViewCount[*firstSurf - s_worldData.surfaces]; - - if (lastSurfLeafIndex != firstSurfLeafIndex) - break; - } - - // don't merge single surfaces - if (firstSurf + 1 == lastSurf) - continue; - - bspSurf = (srfBspSurface_t *)(*firstSurf)->data; - - vaoSurf = ri.Hunk_Alloc(sizeof(*vaoSurf), h_low); - memset(vaoSurf, 0, sizeof(*vaoSurf)); - vaoSurf->surfaceType = SF_VAO_MESH; - - vaoSurf->vao = bspSurf->vao; - - vaoSurf->firstIndex = bspSurf->firstIndex; - vaoSurf->minIndex = bspSurf->minIndex; - vaoSurf->maxIndex = bspSurf->maxIndex; - - ClearBounds(vaoSurf->cullBounds[0], vaoSurf->cullBounds[1]); - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - { - srfBspSurface_t *currBspSurf = (srfBspSurface_t *)(*currSurf)->data; - - vaoSurf->numVerts += currBspSurf->numVerts; - vaoSurf->numIndexes += currBspSurf->numIndexes; - vaoSurf->minIndex = MIN(vaoSurf->minIndex, currBspSurf->minIndex); - vaoSurf->maxIndex = MAX(vaoSurf->maxIndex, currBspSurf->maxIndex); - AddPointToBounds((*currSurf)->cullinfo.bounds[0], vaoSurf->cullBounds[0], vaoSurf->cullBounds[1]); - AddPointToBounds((*currSurf)->cullinfo.bounds[1], vaoSurf->cullBounds[0], vaoSurf->cullBounds[1]); - } - - VectorCopy(vaoSurf->cullBounds[0], mergedSurf->cullinfo.bounds[0]); - VectorCopy(vaoSurf->cullBounds[1], mergedSurf->cullinfo.bounds[1]); - - mergedSurf->cullinfo.type = CULLINFO_BOX; - mergedSurf->data = (surfaceType_t *)vaoSurf; - mergedSurf->fogIndex = (*firstSurf)->fogIndex; - mergedSurf->cubemapIndex = (*firstSurf)->cubemapIndex; - mergedSurf->shader = (*firstSurf)->shader; - - // redirect view surfaces to this surf - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - s_worldData.surfacesViewCount[*currSurf - s_worldData.surfaces] = -2; - - for (k = 0; k < s_worldData.nummarksurfaces; k++) - { - if (s_worldData.surfacesViewCount[s_worldData.marksurfaces[k]] == -2) - s_worldData.viewSurfaces[k] = -((int)(mergedSurf - s_worldData.mergedSurfaces) + 1); - } - - for (currSurf = firstSurf; currSurf < lastSurf; currSurf++) - s_worldData.surfacesViewCount[*currSurf - s_worldData.surfaces] = -1; - - mergedSurf++; - } - - ri.Printf(PRINT_ALL, "Processed %d mergeable surfaces into %d merged, %d unmerged\n", - numSortedSurfaces, numMergedSurfaces, numUnmergedSurfaces); - } - - for (i = 0; i < s_worldData.numWorldSurfaces; i++) - s_worldData.surfacesViewCount[i] = -1; - - ri.Free(surfacesSorted); - - endTime = ri.Milliseconds(); - ri.Printf(PRINT_ALL, "world VAOs calculation time = %5.2f seconds\n", (endTime - startTime) / 1000.0); -} - /* =============== R_LoadSurfaces @@ -2283,7 +1748,7 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { for ( i = 0 ; i < count ; i++, in++, out++ ) { switch ( LittleLong( in->surfaceType ) ) { case MST_PATCH: - // FIXME: do this + out->data = ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low); break; case MST_TRIANGLE_SOUP: out->data = ri.Hunk_Alloc( sizeof(srfBspSurface_t), h_low); @@ -2305,15 +1770,6 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { switch ( LittleLong( in->surfaceType ) ) { case MST_PATCH: ParseMesh ( in, dv, hdrVertColors, out ); - { - srfBspSurface_t *surface = (srfBspSurface_t *)out->data; - - out->cullinfo.type = CULLINFO_BOX | CULLINFO_SPHERE; - VectorCopy(surface->cullBounds[0], out->cullinfo.bounds[0]); - VectorCopy(surface->cullBounds[1], out->cullinfo.bounds[1]); - VectorCopy(surface->cullOrigin, out->cullinfo.localOrigin); - out->cullinfo.radius = surface->cullRadius; - } numMeshes++; break; case MST_TRIANGLE_SOUP: @@ -2326,9 +1782,6 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { break; case MST_FLARE: ParseFlare( in, dv, out, indexes ); - { - out->cullinfo.type = CULLINFO_NONE; - } numFlares++; break; default: @@ -2494,7 +1947,7 @@ static void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) { out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces); } - // chain decendants + // chain descendants R_SetParent (s_worldData.nodes, NULL); } @@ -2681,9 +2134,9 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) { out->parms = shader->fogParms; - out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight, - shader->fogParms.color[1] * tr.identityLight, - shader->fogParms.color[2] * tr.identityLight, 1.0 ); + out->colorInt = ColorBytes4 ( shader->fogParms.color[0], + shader->fogParms.color[1], + shader->fogParms.color[2], 1.0 ); d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque; out->tcScale = 1.0f / ( d * 8 ); @@ -2765,29 +2218,47 @@ void R_LoadLightGrid( lump_t *l ) { if (hdrLightGrid) { -#if defined(USE_OVERBRIGHT) - float lightScale = 1 << (r_mapOverBrightBits->integer - tr.overbrightBits); -#else - float lightScale = 1.0f; -#endif - //ri.Printf(PRINT_ALL, "found!\n"); if (size != sizeof(float) * 6 * numGridPoints) - { ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!", filename, size, (int)(sizeof(float)) * 6 * numGridPoints); - } - w->hdrLightGrid = ri.Hunk_Alloc(size, h_low); + w->lightGrid16 = ri.Hunk_Alloc(sizeof(w->lightGrid16) * 6 * numGridPoints, h_low); for (i = 0; i < numGridPoints ; i++) { - w->hdrLightGrid[i * 6 ] = hdrLightGrid[i * 6 ] * lightScale; - w->hdrLightGrid[i * 6 + 1] = hdrLightGrid[i * 6 + 1] * lightScale; - w->hdrLightGrid[i * 6 + 2] = hdrLightGrid[i * 6 + 2] * lightScale; - w->hdrLightGrid[i * 6 + 3] = hdrLightGrid[i * 6 + 3] * lightScale; - w->hdrLightGrid[i * 6 + 4] = hdrLightGrid[i * 6 + 4] * lightScale; - w->hdrLightGrid[i * 6 + 5] = hdrLightGrid[i * 6 + 5] * lightScale; + vec4_t c; + + c[0] = hdrLightGrid[i * 6]; + c[1] = hdrLightGrid[i * 6 + 1]; + c[2] = hdrLightGrid[i * 6 + 2]; + c[3] = 1.0f; + + R_ColorShiftLightingFloats(c, c); + ColorToRGB16(c, &w->lightGrid16[i * 6]); + + c[0] = hdrLightGrid[i * 6 + 3]; + c[1] = hdrLightGrid[i * 6 + 4]; + c[2] = hdrLightGrid[i * 6 + 5]; + c[3] = 1.0f; + + R_ColorShiftLightingFloats(c, c); + ColorToRGB16(c, &w->lightGrid16[i * 6 + 3]); + } + } + else if (0) + { + // promote 8-bit lightgrid to 16-bit + w->lightGrid16 = ri.Hunk_Alloc(sizeof(w->lightGrid16) * 6 * numGridPoints, h_low); + + for (i = 0; i < numGridPoints; i++) + { + w->lightGrid16[i * 6] = w->lightGridData[i * 8] * 257; + w->lightGrid16[i * 6 + 1] = w->lightGridData[i * 8 + 1] * 257; + w->lightGrid16[i * 6 + 2] = w->lightGridData[i * 8 + 2] * 257; + w->lightGrid16[i * 6 + 3] = w->lightGridData[i * 8 + 3] * 257; + w->lightGrid16[i * 6 + 4] = w->lightGridData[i * 8 + 4] * 257; + w->lightGrid16[i * 6 + 5] = w->lightGridData[i * 8 + 5] * 257; } } @@ -3205,7 +2676,14 @@ void R_CalcVertexLightDirs( void ) case SF_GRID: case SF_TRIANGLES: for(i = 0; i < bspSurf->numVerts; i++) - R_LightDirForPoint( bspSurf->verts[i].xyz, bspSurf->verts[i].lightdir, bspSurf->verts[i].normal, &s_worldData ); + { + vec3_t lightDir; + vec3_t normal; + + R_VaoUnpackNormal(normal, bspSurf->verts[i].normal); + R_LightDirForPoint( bspSurf->verts[i].xyz, lightDir, normal, &s_worldData ); + R_VaoPackNormal(bspSurf->verts[i].lightdir, lightDir); + } break; @@ -3237,7 +2715,6 @@ void RE_LoadWorldMap( const char *name ) { } // set default map light scale - tr.mapLightScale = 1.0f; tr.sunShadowScale = 0.5f; // set default sun direction to be used if it isn't @@ -3521,9 +2998,6 @@ void RE_LoadWorldMap( const char *name ) { } } - // create static VAOS from the world - R_CreateWorldVaos(); - s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker; // only set tr.world now that we know the entire level has loaded properly @@ -3533,7 +3007,7 @@ void RE_LoadWorldMap( const char *name ) { R_BindNullVao(); // Render or load all cubemaps - if (r_cubeMapping->integer && tr.numCubemaps) + if (r_cubeMapping->integer && tr.numCubemaps && glRefConfig.framebufferObject) { R_LoadCubemaps(); R_RenderMissingCubemaps(); diff --git a/code/renderergl2/tr_cmds.c b/code/renderergl2/tr_cmds.c index 254bb0d7..38ba45d2 100644 --- a/code/renderergl2/tr_cmds.c +++ b/code/renderergl2/tr_cmds.c @@ -66,8 +66,8 @@ void R_PerformanceCounters( void ) { } else if (r_speeds->integer == 7 ) { - ri.Printf( PRINT_ALL, "VAO draws: static %i dynamic %i\nMultidraws: %i merged %i\n", - backEnd.pc.c_staticVaoDraws, backEnd.pc.c_dynamicVaoDraws, backEnd.pc.c_multidraws, backEnd.pc.c_multidrawsMerged ); + ri.Printf( PRINT_ALL, "VAO draws: static %i dynamic %i\n", + backEnd.pc.c_staticVaoDraws, backEnd.pc.c_dynamicVaoDraws); ri.Printf( PRINT_ALL, "GLSL binds: %i draws: gen %i light %i fog %i dlight %i\n", backEnd.pc.c_glslShaderBinds, backEnd.pc.c_genericDraws, backEnd.pc.c_lightallDraws, backEnd.pc.c_fogDraws, backEnd.pc.c_dlightDraws); } @@ -203,11 +203,11 @@ void R_AddCapShadowmapCmd( int map, int cubeSide ) { /* ============= -R_PostProcessingCmd +R_AddPostProcessCmd ============= */ -void R_AddPostProcessCmd( ) { +void R_AddPostProcessCmd( void ) { postProcessCommand_t *cmd; cmd = R_GetCommandBuffer( sizeof( *cmd ) ); diff --git a/code/renderergl2/tr_curve.c b/code/renderergl2/tr_curve.c index 91c80a4d..1d7e99e8 100644 --- a/code/renderergl2/tr_curve.c +++ b/code/renderergl2/tr_curve.c @@ -54,10 +54,10 @@ static void LerpDrawVert( srfVert_t *a, srfVert_t *b, srfVert_t *out ) { out->lightmap[0] = 0.5f * (a->lightmap[0] + b->lightmap[0]); out->lightmap[1] = 0.5f * (a->lightmap[1] + b->lightmap[1]); - out->vertexColors[0] = 0.5f * (a->vertexColors[0] + b->vertexColors[0]); - out->vertexColors[1] = 0.5f * (a->vertexColors[1] + b->vertexColors[1]); - out->vertexColors[2] = 0.5f * (a->vertexColors[2] + b->vertexColors[2]); - out->vertexColors[3] = 0.5f * (a->vertexColors[3] + b->vertexColors[3]); + out->color[0] = ((int)a->color[0] + (int)b->color[0]) >> 1; + out->color[1] = ((int)a->color[1] + (int)b->color[1]) >> 1; + out->color[2] = ((int)a->color[2] + (int)b->color[2]) >> 1; + out->color[3] = ((int)a->color[3] + (int)b->color[3]) >> 1; } /* @@ -207,12 +207,15 @@ static int neighbors[8][2] = { //if ( count == 0 ) { // printf("bad normal\n"); //} - VectorNormalize2( sum, dv->normal ); + { + vec3_t fNormal; + VectorNormalize2(sum, fNormal); + R_VaoPackNormal(dv->normal, fNormal); + } } } } -#ifdef USE_VERT_TANGENT_SPACE static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numIndexes, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) { @@ -251,17 +254,13 @@ static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRI } } } -#endif -static int MakeMeshIndexes(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], - glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) +static int MakeMeshIndexes(int width, int height, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) { int i, j; int numIndexes; int w, h; - srfVert_t *dv; - static srfVert_t ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE]; h = height - 1; w = width - 1; @@ -288,16 +287,6 @@ static int MakeMeshIndexes(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][ } } - // FIXME: use more elegant way - for(i = 0; i < width; i++) - { - for(j = 0; j < height; j++) - { - dv = &ctrl2[j * width + i]; - *dv = ctrl[j][i]; - } - } - return numIndexes; } @@ -375,21 +364,17 @@ static void PutPointsOnCurve( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], R_CreateSurfaceGridMesh ================= */ -srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, +void R_CreateSurfaceGridMesh(srfBspSurface_t *grid, int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE], int numIndexes, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) { - int i, j, size; + int i, j; srfVert_t *vert; vec3_t tmpVec; - srfBspSurface_t *grid; // copy the results out to a grid - size = (width * height - 1) * sizeof( srfVert_t ) + sizeof( *grid ); + Com_Memset(grid, 0, sizeof(*grid)); #ifdef PATCH_STITCHING - grid = /*ri.Hunk_Alloc*/ ri.Malloc( size ); - Com_Memset(grid, 0, size); - grid->widthLodError = /*ri.Hunk_Alloc*/ ri.Malloc( width * 4 ); Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); @@ -403,9 +388,6 @@ srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, grid->numVerts = (width * height); grid->verts = ri.Malloc(grid->numVerts * sizeof(srfVert_t)); #else - grid = ri.Hunk_Alloc( size ); - Com_Memset(grid, 0, size); - grid->widthLodError = ri.Hunk_Alloc( width * 4 ); Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); @@ -441,7 +423,6 @@ srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, VectorCopy( grid->cullOrigin, grid->lodOrigin ); grid->lodRadius = grid->cullRadius; // - return grid; } /* @@ -449,12 +430,11 @@ srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, R_FreeSurfaceGridMesh ================= */ -void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ) { +static void R_FreeSurfaceGridMeshData( srfBspSurface_t *grid ) { ri.Free(grid->widthLodError); ri.Free(grid->heightLodError); ri.Free(grid->indexes); ri.Free(grid->verts); - ri.Free(grid); } /* @@ -462,7 +442,7 @@ void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ) { R_SubdividePatchToGrid ================= */ -srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, +void R_SubdividePatchToGrid( srfBspSurface_t *grid, int width, int height, srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) { int i, j, k, l; srfVert_t_cleared( prev ); @@ -629,15 +609,13 @@ srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, #endif // calculate indexes - numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); + numIndexes = MakeMeshIndexes(width, height, indexes); // calculate normals MakeMeshNormals( width, height, ctrl ); -#ifdef USE_VERT_TANGENT_SPACE MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes); -#endif - return R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); + R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes); } /* @@ -645,7 +623,7 @@ srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, R_GridInsertColumn =============== */ -srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ) { +void R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ) { int i, j; int width, height, oldwidth; srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; @@ -658,7 +636,7 @@ srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, oldwidth = 0; width = grid->width + 1; if (width > MAX_GRID_SIZE) - return NULL; + return; height = grid->height; for (i = 0; i < width; i++) { if (i == column) { @@ -684,20 +662,20 @@ srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, //PutPointsOnCurve( ctrl, width, height ); // calculate indexes - numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); + numIndexes = MakeMeshIndexes(width, height, indexes); // calculate normals MakeMeshNormals( width, height, ctrl ); + MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes); VectorCopy(grid->lodOrigin, lodOrigin); lodRadius = grid->lodRadius; // free the old grid - R_FreeSurfaceGridMesh(grid); + R_FreeSurfaceGridMeshData(grid); // create a new grid - grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); + R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes); grid->lodRadius = lodRadius; VectorCopy(lodOrigin, grid->lodOrigin); - return grid; } /* @@ -705,7 +683,7 @@ srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, R_GridInsertRow =============== */ -srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ) { +void R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ) { int i, j; int width, height, oldheight; srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE]; @@ -719,7 +697,7 @@ srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, ve width = grid->width; height = grid->height + 1; if (height > MAX_GRID_SIZE) - return NULL; + return; for (i = 0; i < height; i++) { if (i == row) { //insert new row @@ -744,18 +722,18 @@ srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, ve //PutPointsOnCurve( ctrl, width, height ); // calculate indexes - numIndexes = MakeMeshIndexes(width, height, ctrl, indexes); + numIndexes = MakeMeshIndexes(width, height, indexes); // calculate normals MakeMeshNormals( width, height, ctrl ); + MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes); VectorCopy(grid->lodOrigin, lodOrigin); lodRadius = grid->lodRadius; // free the old grid - R_FreeSurfaceGridMesh(grid); + R_FreeSurfaceGridMeshData(grid); // create a new grid - grid = R_CreateSurfaceGridMesh(width, height, ctrl, errorTable, numIndexes, indexes); + R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes); grid->lodRadius = lodRadius; VectorCopy(lodOrigin, grid->lodOrigin); - return grid; } diff --git a/code/renderergl2/tr_dsa.c b/code/renderergl2/tr_dsa.c index 9cd481bd..e43df0bb 100644 --- a/code/renderergl2/tr_dsa.c +++ b/code/renderergl2/tr_dsa.c @@ -35,7 +35,7 @@ static struct } glDsaState; -void GL_BindNullTextures() +void GL_BindNullTextures(void) { int i; @@ -43,7 +43,7 @@ void GL_BindNullTextures() { for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) { - qglBindMultiTexture(GL_TEXTURE0_ARB + i, GL_TEXTURE_2D, 0); + qglBindMultiTextureEXT(GL_TEXTURE0 + i, GL_TEXTURE_2D, 0); glDsaState.textures[i] = 0; } } @@ -51,19 +51,19 @@ void GL_BindNullTextures() { for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) { - qglActiveTextureARB(GL_TEXTURE0_ARB + i); + qglActiveTexture(GL_TEXTURE0 + i); qglBindTexture(GL_TEXTURE_2D, 0); glDsaState.textures[i] = 0; } - qglActiveTextureARB(GL_TEXTURE0_ARB); - glDsaState.texunit = GL_TEXTURE0_ARB; + qglActiveTexture(GL_TEXTURE0); + glDsaState.texunit = GL_TEXTURE0; } } int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture) { - GLuint tmu = texunit - GL_TEXTURE0_ARB; + GLuint tmu = texunit - GL_TEXTURE0; if (glDsaState.textures[tmu] == texture) return 0; @@ -71,145 +71,145 @@ int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture) if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) target = GL_TEXTURE_CUBE_MAP; - qglBindMultiTexture(texunit, target, texture); + qglBindMultiTextureEXT(texunit, target, texture); glDsaState.textures[tmu] = texture; return 1; } -GLvoid APIENTRY GLDSA_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture) +GLvoid APIENTRY GLDSA_BindMultiTextureEXT(GLenum texunit, GLenum target, GLuint texture) { if (glDsaState.texunit != texunit) { - qglActiveTextureARB(texunit); + qglActiveTexture(texunit); glDsaState.texunit = texunit; } qglBindTexture(target, texture); } -GLvoid APIENTRY GLDSA_TextureParameterf(GLuint texture, GLenum target, GLenum pname, GLfloat param) +GLvoid APIENTRY GLDSA_TextureParameterfEXT(GLuint texture, GLenum target, GLenum pname, GLfloat param) { GL_BindMultiTexture(glDsaState.texunit, target, texture); qglTexParameterf(target, pname, param); } -GLvoid APIENTRY GLDSA_TextureParameteri(GLuint texture, GLenum target, GLenum pname, GLint param) +GLvoid APIENTRY GLDSA_TextureParameteriEXT(GLuint texture, GLenum target, GLenum pname, GLint param) { GL_BindMultiTexture(glDsaState.texunit, target, texture); qglTexParameteri(target, pname, param); } -GLvoid APIENTRY GLDSA_TextureImage2D(GLuint texture, GLenum target, GLint level, GLint internalformat, +GLvoid APIENTRY GLDSA_TextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { GL_BindMultiTexture(glDsaState.texunit, target, texture); qglTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } -GLvoid APIENTRY GLDSA_TextureSubImage2D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, +GLvoid APIENTRY GLDSA_TextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) { GL_BindMultiTexture(glDsaState.texunit, target, texture); qglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); } -GLvoid APIENTRY GLDSA_CopyTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalformat, - GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +GLvoid APIENTRY GLDSA_CopyTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint x, GLint y, GLsizei width, GLsizei height) { GL_BindMultiTexture(glDsaState.texunit, target, texture); - qglCopyTexImage2D(target, level, internalformat, x, y, width, height, border); + qglCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); } -GLvoid APIENTRY GLDSA_CompressedTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalformat, +GLvoid APIENTRY GLDSA_CompressedTextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) { GL_BindMultiTexture(glDsaState.texunit, target, texture); - qglCompressedTexImage2DARB(target, level, internalformat, width, height, border, imageSize, data); + qglCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); } -GLvoid APIENTRY GLDSA_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLint level, +GLvoid APIENTRY GLDSA_CompressedTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) { GL_BindMultiTexture(glDsaState.texunit, target, texture); - qglCompressedTexSubImage2DARB(target, level, xoffset, yoffset, width, height, format, imageSize, data); + qglCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); } -GLvoid APIENTRY GLDSA_GenerateTextureMipmap(GLuint texture, GLenum target) +GLvoid APIENTRY GLDSA_GenerateTextureMipmapEXT(GLuint texture, GLenum target) { GL_BindMultiTexture(glDsaState.texunit, target, texture); - qglGenerateMipmapEXT(target); + qglGenerateMipmap(target); } -void GL_BindNullProgram() +void GL_BindNullProgram(void) { - qglUseProgramObjectARB(0); + qglUseProgram(0); glDsaState.program = 0; } -int GL_UseProgramObject(GLuint program) +int GL_UseProgram(GLuint program) { if (glDsaState.program == program) return 0; - qglUseProgramObjectARB(program); + qglUseProgram(program); glDsaState.program = program; return 1; } -GLvoid APIENTRY GLDSA_ProgramUniform1i(GLuint program, GLint location, GLint v0) +GLvoid APIENTRY GLDSA_ProgramUniform1iEXT(GLuint program, GLint location, GLint v0) { - GL_UseProgramObject(program); - qglUniform1iARB(location, v0); + GL_UseProgram(program); + qglUniform1i(location, v0); } -GLvoid APIENTRY GLDSA_ProgramUniform1f(GLuint program, GLint location, GLfloat v0) +GLvoid APIENTRY GLDSA_ProgramUniform1fEXT(GLuint program, GLint location, GLfloat v0) { - GL_UseProgramObject(program); - qglUniform1fARB(location, v0); + GL_UseProgram(program); + qglUniform1f(location, v0); } -GLvoid APIENTRY GLDSA_ProgramUniform2f(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniform2fEXT(GLuint program, GLint location, GLfloat v0, GLfloat v1) { - GL_UseProgramObject(program); - qglUniform2fARB(location, v0, v1); + GL_UseProgram(program); + qglUniform2f(location, v0, v1); } -GLvoid APIENTRY GLDSA_ProgramUniform3f(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniform3fEXT(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { - GL_UseProgramObject(program); - qglUniform3fARB(location, v0, v1, v2); + GL_UseProgram(program); + qglUniform3f(location, v0, v1, v2); } -GLvoid APIENTRY GLDSA_ProgramUniform4f(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniform4fEXT(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { - GL_UseProgramObject(program); - qglUniform4fARB(location, v0, v1, v2, v3); + GL_UseProgram(program); + qglUniform4f(location, v0, v1, v2, v3); } -GLvoid APIENTRY GLDSA_ProgramUniform1fv(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniform1fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value) { - GL_UseProgramObject(program); - qglUniform1fvARB(location, count, value); + GL_UseProgram(program); + qglUniform1fv(location, count, value); } -GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fv(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) { - GL_UseProgramObject(program); - qglUniformMatrix4fvARB(location, count, transpose, value); + GL_UseProgram(program); + qglUniformMatrix4fv(location, count, transpose, value); } -void GL_BindNullFramebuffers() +void GL_BindNullFramebuffers(void) { - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + qglBindFramebuffer(GL_FRAMEBUFFER, 0); glDsaState.drawFramebuffer = glDsaState.readFramebuffer = 0; - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + qglBindRenderbuffer(GL_RENDERBUFFER, 0); glDsaState.renderbuffer = 0; } @@ -217,26 +217,26 @@ void GL_BindFramebuffer(GLenum target, GLuint framebuffer) { switch (target) { - case GL_FRAMEBUFFER_EXT: + case GL_FRAMEBUFFER: if (framebuffer != glDsaState.drawFramebuffer || framebuffer != glDsaState.readFramebuffer) { - qglBindFramebufferEXT(target, framebuffer); + qglBindFramebuffer(target, framebuffer); glDsaState.drawFramebuffer = glDsaState.readFramebuffer = framebuffer; } break; - case GL_DRAW_FRAMEBUFFER_EXT: + case GL_DRAW_FRAMEBUFFER: if (framebuffer != glDsaState.drawFramebuffer) { - qglBindFramebufferEXT(target, framebuffer); + qglBindFramebuffer(target, framebuffer); glDsaState.drawFramebuffer = framebuffer; } break; - case GL_READ_FRAMEBUFFER_EXT: + case GL_READ_FRAMEBUFFER: if (framebuffer != glDsaState.readFramebuffer) { - qglBindFramebufferEXT(target, framebuffer); + qglBindFramebuffer(target, framebuffer); glDsaState.readFramebuffer = framebuffer; } break; @@ -247,41 +247,41 @@ void GL_BindRenderbuffer(GLuint renderbuffer) { if (renderbuffer != glDsaState.renderbuffer) { - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer); + qglBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); glDsaState.renderbuffer = renderbuffer; } } -GLvoid APIENTRY GLDSA_NamedRenderbufferStorage(GLuint renderbuffer, +GLvoid APIENTRY GLDSA_NamedRenderbufferStorageEXT(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) { GL_BindRenderbuffer(renderbuffer); - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalformat, width, height); + qglRenderbufferStorage(GL_RENDERBUFFER, internalformat, width, height); } -GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisample(GLuint renderbuffer, +GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { GL_BindRenderbuffer(renderbuffer); - qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, internalformat, width, height); + qglRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalformat, width, height); } -GLenum APIENTRY GLDSA_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) +GLenum APIENTRY GLDSA_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target) { GL_BindFramebuffer(target, framebuffer); - return qglCheckFramebufferStatusEXT(target); + return qglCheckFramebufferStatus(target); } -GLvoid APIENTRY GLDSA_NamedFramebufferTexture2D(GLuint framebuffer, +GLvoid APIENTRY GLDSA_NamedFramebufferTexture2DEXT(GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { - GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer); - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, textarget, texture, level); + GL_BindFramebuffer(GL_FRAMEBUFFER, framebuffer); + qglFramebufferTexture2D(GL_FRAMEBUFFER, attachment, textarget, texture, level); } -GLvoid APIENTRY GLDSA_NamedFramebufferRenderbuffer(GLuint framebuffer, +GLvoid APIENTRY GLDSA_NamedFramebufferRenderbufferEXT(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { - GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer); - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, renderbuffertarget, renderbuffer); + GL_BindFramebuffer(GL_FRAMEBUFFER, framebuffer); + qglFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, renderbuffertarget, renderbuffer); } diff --git a/code/renderergl2/tr_dsa.h b/code/renderergl2/tr_dsa.h index e820fe00..84e35f56 100644 --- a/code/renderergl2/tr_dsa.h +++ b/code/renderergl2/tr_dsa.h @@ -26,37 +26,37 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. void GL_BindNullTextures(void); int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture); -GLvoid APIENTRY GLDSA_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture); -GLvoid APIENTRY GLDSA_TextureParameterf(GLuint texture, GLenum target, GLenum pname, GLfloat param); -GLvoid APIENTRY GLDSA_TextureParameteri(GLuint texture, GLenum target, GLenum pname, GLint param); -GLvoid APIENTRY GLDSA_TextureImage2D(GLuint texture, GLenum target, GLint level, GLint internalformat, +GLvoid APIENTRY GLDSA_BindMultiTextureEXT(GLenum texunit, GLenum target, GLuint texture); +GLvoid APIENTRY GLDSA_TextureParameterfEXT(GLuint texture, GLenum target, GLenum pname, GLfloat param); +GLvoid APIENTRY GLDSA_TextureParameteriEXT(GLuint texture, GLenum target, GLenum pname, GLint param); +GLvoid APIENTRY GLDSA_TextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLvoid APIENTRY GLDSA_TextureSubImage2D(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, +GLvoid APIENTRY GLDSA_TextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -GLvoid APIENTRY GLDSA_CopyTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalformat, - GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLvoid APIENTRY GLDSA_CompressedTextureImage2D(GLuint texture, GLenum target, GLint level, GLenum internalformat, +GLvoid APIENTRY GLDSA_CopyTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLint x, GLint y, GLsizei width, GLsizei height); +GLvoid APIENTRY GLDSA_CompressedTextureImage2DEXT(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -GLvoid APIENTRY GLDSA_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLint level, +GLvoid APIENTRY GLDSA_CompressedTextureSubImage2DEXT(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -GLvoid APIENTRY GLDSA_GenerateTextureMipmap(GLuint texture, GLenum target); +GLvoid APIENTRY GLDSA_GenerateTextureMipmapEXT(GLuint texture, GLenum target); void GL_BindNullProgram(void); -int GL_UseProgramObject(GLuint program); +int GL_UseProgram(GLuint program); -GLvoid APIENTRY GLDSA_ProgramUniform1i(GLuint program, GLint location, GLint v0); -GLvoid APIENTRY GLDSA_ProgramUniform1f(GLuint program, GLint location, GLfloat v0); -GLvoid APIENTRY GLDSA_ProgramUniform2f(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniform1iEXT(GLuint program, GLint location, GLint v0); +GLvoid APIENTRY GLDSA_ProgramUniform1fEXT(GLuint program, GLint location, GLfloat v0); +GLvoid APIENTRY GLDSA_ProgramUniform2fEXT(GLuint program, GLint location, GLfloat v0, GLfloat v1); -GLvoid APIENTRY GLDSA_ProgramUniform3f(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniform3fEXT(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -GLvoid APIENTRY GLDSA_ProgramUniform4f(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniform4fEXT(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLvoid APIENTRY GLDSA_ProgramUniform1fv(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniform1fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value); -GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fv(GLuint program, GLint location, +GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); @@ -64,16 +64,16 @@ void GL_BindNullFramebuffers(void); void GL_BindFramebuffer(GLenum target, GLuint framebuffer); void GL_BindRenderbuffer(GLuint renderbuffer); -GLvoid APIENTRY GLDSA_NamedRenderbufferStorage(GLuint renderbuffer, +GLvoid APIENTRY GLDSA_NamedRenderbufferStorageEXT(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); -GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisample(GLuint renderbuffer, +GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -GLenum APIENTRY GLDSA_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target); -GLvoid APIENTRY GLDSA_NamedFramebufferTexture2D(GLuint framebuffer, +GLenum APIENTRY GLDSA_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target); +GLvoid APIENTRY GLDSA_NamedFramebufferTexture2DEXT(GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLvoid APIENTRY GLDSA_NamedFramebufferRenderbuffer(GLuint framebuffer, +GLvoid APIENTRY GLDSA_NamedFramebufferRenderbufferEXT(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); diff --git a/code/renderergl2/tr_extensions.c b/code/renderergl2/tr_extensions.c index b33968d4..ebc985a9 100644 --- a/code/renderergl2/tr_extensions.c +++ b/code/renderergl2/tr_extensions.c @@ -30,550 +30,48 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" #include "tr_dsa.h" -// GL_EXT_draw_range_elements -void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); - -// GL_EXT_multi_draw_arrays -void (APIENTRY * qglMultiDrawArraysEXT) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount); -void (APIENTRY * qglMultiDrawElementsEXT) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount); - -// GL_ARB_vertex_shader -void (APIENTRY * qglBindAttribLocationARB) (GLhandleARB programObj, GLuint index, const GLcharARB * name); -void (APIENTRY * qglGetActiveAttribARB) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei * length, - GLint * size, GLenum * type, GLcharARB * name); -GLint(APIENTRY * qglGetAttribLocationARB) (GLhandleARB programObj, const GLcharARB * name); - -// GL_ARB_vertex_program -void (APIENTRY * qglVertexAttrib4fARB) (GLuint, GLfloat, GLfloat, GLfloat, GLfloat); -void (APIENTRY * qglVertexAttrib4fvARB) (GLuint, const GLfloat *); -void (APIENTRY * qglVertexAttribPointerARB) (GLuint index, GLint size, GLenum type, GLboolean normalized, - GLsizei stride, const GLvoid * pointer); -void (APIENTRY * qglEnableVertexAttribArrayARB) (GLuint index); -void (APIENTRY * qglDisableVertexAttribArrayARB) (GLuint index); - -// GL_ARB_vertex_buffer_object -void (APIENTRY * qglBindBufferARB) (GLenum target, GLuint buffer); -void (APIENTRY * qglDeleteBuffersARB) (GLsizei n, const GLuint * buffers); -void (APIENTRY * qglGenBuffersARB) (GLsizei n, GLuint * buffers); - -GLboolean(APIENTRY * qglIsBufferARB) (GLuint buffer); -void (APIENTRY * qglBufferDataARB) (GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage); -void (APIENTRY * qglBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data); -void (APIENTRY * qglGetBufferSubDataARB) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid * data); - -void (APIENTRY * qglGetBufferParameterivARB) (GLenum target, GLenum pname, GLint * params); -void (APIENTRY * qglGetBufferPointervARB) (GLenum target, GLenum pname, GLvoid * *params); - -// GL_ARB_shader_objects -void (APIENTRY * qglDeleteObjectARB) (GLhandleARB obj); - -GLhandleARB(APIENTRY * qglGetHandleARB) (GLenum pname); -void (APIENTRY * qglDetachObjectARB) (GLhandleARB containerObj, GLhandleARB attachedObj); - -GLhandleARB(APIENTRY * qglCreateShaderObjectARB) (GLenum shaderType); -void (APIENTRY * qglShaderSourceARB) (GLhandleARB shaderObj, GLsizei count, const GLcharARB * *string, - const GLint * length); -void (APIENTRY * qglCompileShaderARB) (GLhandleARB shaderObj); - -GLhandleARB(APIENTRY * qglCreateProgramObjectARB) (void); -void (APIENTRY * qglAttachObjectARB) (GLhandleARB containerObj, GLhandleARB obj); -void (APIENTRY * qglLinkProgramARB) (GLhandleARB programObj); -void (APIENTRY * qglUseProgramObjectARB) (GLhandleARB programObj); -void (APIENTRY * qglValidateProgramARB) (GLhandleARB programObj); -void (APIENTRY * qglUniform1fARB) (GLint location, GLfloat v0); -void (APIENTRY * qglUniform2fARB) (GLint location, GLfloat v0, GLfloat v1); -void (APIENTRY * qglUniform3fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); -void (APIENTRY * qglUniform4fARB) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -void (APIENTRY * qglUniform1iARB) (GLint location, GLint v0); -void (APIENTRY * qglUniform2iARB) (GLint location, GLint v0, GLint v1); -void (APIENTRY * qglUniform3iARB) (GLint location, GLint v0, GLint v1, GLint v2); -void (APIENTRY * qglUniform4iARB) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3); -void (APIENTRY * qglUniform1fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform2fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform3fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform4fvARB) (GLint location, GLsizei count, const GLfloat * value); -void (APIENTRY * qglUniform2ivARB) (GLint location, GLsizei count, const GLint * value); -void (APIENTRY * qglUniform3ivARB) (GLint location, GLsizei count, const GLint * value); -void (APIENTRY * qglUniform4ivARB) (GLint location, GLsizei count, const GLint * value); -void (APIENTRY * qglUniformMatrix2fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -void (APIENTRY * qglUniformMatrix3fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -void (APIENTRY * qglUniformMatrix4fvARB) (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); -void (APIENTRY * qglGetObjectParameterfvARB) (GLhandleARB obj, GLenum pname, GLfloat * params); -void (APIENTRY * qglGetObjectParameterivARB) (GLhandleARB obj, GLenum pname, GLint * params); -void (APIENTRY * qglGetInfoLogARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog); -void (APIENTRY * qglGetAttachedObjectsARB) (GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, - GLhandleARB * obj); -GLint(APIENTRY * qglGetUniformLocationARB) (GLhandleARB programObj, const GLcharARB * name); -void (APIENTRY * qglGetActiveUniformARB) (GLhandleARB programObj, GLuint index, GLsizei maxIndex, GLsizei * length, - GLint * size, GLenum * type, GLcharARB * name); -void (APIENTRY * qglGetUniformfvARB) (GLhandleARB programObj, GLint location, GLfloat * params); -void (APIENTRY * qglGetUniformivARB) (GLhandleARB programObj, GLint location, GLint * params); -void (APIENTRY * qglGetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source); - -// GL_ARB_texture_compression -void (APIENTRY * qglCompressedTexImage3DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, - GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexImage2DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, - GLint border, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexImage1DARB)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, - GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexSubImage3DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexSubImage2DARB)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, - GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglCompressedTexSubImage1DARB)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, - GLsizei imageSize, const GLvoid *data); -void (APIENTRY * qglGetCompressedTexImageARB)(GLenum target, GLint lod, - GLvoid *img); - -// GL_EXT_framebuffer_object -GLboolean (APIENTRY * qglIsRenderbufferEXT)(GLuint renderbuffer); -void (APIENTRY * qglBindRenderbufferEXT)(GLenum target, GLuint renderbuffer); -void (APIENTRY * qglDeleteRenderbuffersEXT)(GLsizei n, const GLuint *renderbuffers); -void (APIENTRY * qglGenRenderbuffersEXT)(GLsizei n, GLuint *renderbuffers); - -void (APIENTRY * qglRenderbufferStorageEXT)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); - -void (APIENTRY * qglGetRenderbufferParameterivEXT)(GLenum target, GLenum pname, GLint *params); - -GLboolean (APIENTRY * qglIsFramebufferEXT)(GLuint framebuffer); -void (APIENTRY * qglBindFramebufferEXT)(GLenum target, GLuint framebuffer); -void (APIENTRY * qglDeleteFramebuffersEXT)(GLsizei n, const GLuint *framebuffers); -void (APIENTRY * qglGenFramebuffersEXT)(GLsizei n, GLuint *framebuffers); - -GLenum (APIENTRY * qglCheckFramebufferStatusEXT)(GLenum target); - -void (APIENTRY * qglFramebufferTexture1DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level); -void (APIENTRY * qglFramebufferTexture2DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level); -void (APIENTRY * qglFramebufferTexture3DEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level, GLint zoffset); - -void (APIENTRY * qglFramebufferRenderbufferEXT)(GLenum target, GLenum attachment, GLenum renderbuffertarget, - GLuint renderbuffer); - -void (APIENTRY * qglGetFramebufferAttachmentParameterivEXT)(GLenum target, GLenum attachment, GLenum pname, GLint *params); - -void (APIENTRY * qglGenerateMipmapEXT)(GLenum target); - -// GL_ARB_occlusion_query -void (APIENTRY * qglGenQueriesARB)(GLsizei n, GLuint *ids); -void (APIENTRY * qglDeleteQueriesARB)(GLsizei n, const GLuint *ids); -GLboolean (APIENTRY * qglIsQueryARB)(GLuint id); -void (APIENTRY * qglBeginQueryARB)(GLenum target, GLuint id); -void (APIENTRY * qglEndQueryARB)(GLenum target); -void (APIENTRY * qglGetQueryivARB)(GLenum target, GLenum pname, GLint *params); -void (APIENTRY * qglGetQueryObjectivARB)(GLuint id, GLenum pname, GLint *params); -void (APIENTRY * qglGetQueryObjectuivARB)(GLuint id, GLenum pname, GLuint *params); - -// GL_EXT_framebuffer_blit -void (APIENTRY * qglBlitFramebufferEXT)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter); - -// GL_EXT_framebuffer_multisample -void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, - GLenum internalformat, GLsizei width, GLsizei height); - -// GL_ARB_draw_buffers -void (APIENTRY * qglDrawBuffersARB)(GLsizei n, const GLenum *bufs); - -// GL_ARB_vertex_array_object -void (APIENTRY * qglBindVertexArrayARB)(GLuint array); -void (APIENTRY * qglDeleteVertexArraysARB)(GLsizei n, const GLuint *arrays); -void (APIENTRY * qglGenVertexArraysARB)(GLsizei n, GLuint *arrays); -GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array); - -// GL_EXT_direct_state_access -GLvoid (APIENTRY * qglBindMultiTexture)(GLenum texunit, GLenum target, GLuint texture); -GLvoid (APIENTRY * qglTextureParameterf)(GLuint texture, GLenum target, GLenum pname, GLfloat param); -GLvoid (APIENTRY * qglTextureParameteri)(GLuint texture, GLenum target, GLenum pname, GLint param); -GLvoid (APIENTRY * qglTextureImage2D)(GLuint texture, GLenum target, GLint level, GLint internalformat, - GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -GLvoid (APIENTRY * qglTextureSubImage2D)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -GLvoid (APIENTRY * qglCopyTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat, - GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -GLvoid (APIENTRY * qglCompressedTextureImage2D)(GLuint texture, GLenum target, GLint level, GLenum internalformat, - GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); -GLvoid (APIENTRY * qglCompressedTextureSubImage2D)(GLuint texture, GLenum target, GLint level, - GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, - GLsizei imageSize, const GLvoid *data); -GLvoid (APIENTRY * qglGenerateTextureMipmap)(GLuint texture, GLenum target); - -GLvoid(APIENTRY * qglProgramUniform1i)(GLuint program, GLint location, GLint v0); -GLvoid(APIENTRY * qglProgramUniform1f)(GLuint program, GLint location, GLfloat v0); -GLvoid(APIENTRY * qglProgramUniform2f)(GLuint program, GLint location, - GLfloat v0, GLfloat v1); -GLvoid(APIENTRY * qglProgramUniform3f)(GLuint program, GLint location, - GLfloat v0, GLfloat v1, GLfloat v2); -GLvoid(APIENTRY * qglProgramUniform4f)(GLuint program, GLint location, - GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); -GLvoid(APIENTRY * qglProgramUniform1fv)(GLuint program, GLint location, - GLsizei count, const GLfloat *value); -GLvoid(APIENTRY * qglProgramUniformMatrix4fv)(GLuint program, GLint location, - GLsizei count, GLboolean transpose, - const GLfloat *value); - -GLvoid(APIENTRY * qglNamedRenderbufferStorage)(GLuint renderbuffer, - GLenum internalformat, GLsizei width, GLsizei height); - -GLvoid(APIENTRY * qglNamedRenderbufferStorageMultisample)(GLuint renderbuffer, - GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); - -GLenum(APIENTRY * qglCheckNamedFramebufferStatus)(GLuint framebuffer, GLenum target); -GLvoid(APIENTRY * qglNamedFramebufferTexture2D)(GLuint framebuffer, - GLenum attachment, GLenum textarget, GLuint texture, GLint level); -GLvoid(APIENTRY * qglNamedFramebufferRenderbuffer)(GLuint framebuffer, - GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); - - -static qboolean GLimp_HaveExtension(const char *ext) -{ - const char *ptr = Q_stristr( glConfig.extensions_string, ext ); - if (ptr == NULL) - return qfalse; - ptr += strlen(ext); - return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string. -} - -void GLimp_InitExtraExtensions() +void GLimp_InitExtraExtensions(void) { char *extension; const char* result[3] = { "...ignoring %s\n", "...using %s\n", "...%s not found\n" }; + qboolean q_gl_version_at_least_3_0; + qboolean q_gl_version_at_least_3_2; - // GL_EXT_draw_range_elements - extension = "GL_EXT_draw_range_elements"; - glRefConfig.drawRangeElements = qfalse; - qglMultiDrawArraysEXT = NULL; - qglMultiDrawElementsEXT = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglDrawRangeElementsEXT = (void *) SDL_GL_GetProcAddress("glDrawRangeElementsEXT"); + q_gl_version_at_least_3_0 = QGL_VERSION_ATLEAST( 3, 0 ); + q_gl_version_at_least_3_2 = QGL_VERSION_ATLEAST( 3, 2 ); - if ( r_ext_draw_range_elements->integer) - glRefConfig.drawRangeElements = qtrue; + // Check if we need Intel graphics specific fixes. + glRefConfig.intelGraphics = qfalse; + if (strstr((char *)qglGetString(GL_RENDERER), "Intel")) + glRefConfig.intelGraphics = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.drawRangeElements], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } + // set DSA fallbacks +#define GLE(ret, name, ...) qgl##name = GLDSA_##name; + QGL_EXT_direct_state_access_PROCS; +#undef GLE - // GL_EXT_multi_draw_arrays - extension = "GL_EXT_multi_draw_arrays"; - glRefConfig.multiDrawArrays = qfalse; - qglMultiDrawArraysEXT = NULL; - qglMultiDrawElementsEXT = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglMultiDrawArraysEXT = (PFNGLMULTIDRAWARRAYSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawArraysEXT"); - qglMultiDrawElementsEXT = (PFNGLMULTIDRAWELEMENTSEXTPROC) SDL_GL_GetProcAddress("glMultiDrawElementsEXT"); + // GL function loader, based on https://gist.github.com/rygorous/16796a0c876cf8a5f542caddb55bce8a +#define GLE(ret, name, ...) qgl##name = (name##proc *) SDL_GL_GetProcAddress("gl" #name); - if ( r_ext_multi_draw_arrays->integer ) - glRefConfig.multiDrawArrays = qtrue; + // OpenGL 1.5 - GL_ARB_occlusion_query + glRefConfig.occlusionQuery = qtrue; + QGL_ARB_occlusion_query_PROCS; - ri.Printf(PRINT_ALL, result[glRefConfig.multiDrawArrays], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_vertex_program - //glRefConfig.vertexProgram = qfalse; - extension = "GL_ARB_vertex_program"; - qglVertexAttrib4fARB = NULL; - qglVertexAttrib4fvARB = NULL; - qglVertexAttribPointerARB = NULL; - qglEnableVertexAttribArrayARB = NULL; - qglDisableVertexAttribArrayARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fARB"); - qglVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) SDL_GL_GetProcAddress("glVertexAttrib4fvARB"); - qglVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) SDL_GL_GetProcAddress("glVertexAttribPointerARB"); - qglEnableVertexAttribArrayARB = - (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glEnableVertexAttribArrayARB"); - qglDisableVertexAttribArrayARB = - (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) SDL_GL_GetProcAddress("glDisableVertexAttribArrayARB"); - - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.vertexProgram = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_vertex_buffer_object - //glRefConfig.vertexBufferObject = qfalse; - extension = "GL_ARB_vertex_buffer_object"; - qglBindBufferARB = NULL; - qglDeleteBuffersARB = NULL; - qglGenBuffersARB = NULL; - qglIsBufferARB = NULL; - qglBufferDataARB = NULL; - qglBufferSubDataARB = NULL; - qglGetBufferSubDataARB = NULL; - qglGetBufferParameterivARB = NULL; - qglGetBufferPointervARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglBindBufferARB = (PFNGLBINDBUFFERARBPROC) SDL_GL_GetProcAddress("glBindBufferARB"); - qglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB"); - qglGenBuffersARB = (PFNGLGENBUFFERSARBPROC) SDL_GL_GetProcAddress("glGenBuffersARB"); - qglIsBufferARB = (PFNGLISBUFFERARBPROC) SDL_GL_GetProcAddress("glIsBufferARB"); - qglBufferDataARB = (PFNGLBUFFERDATAARBPROC) SDL_GL_GetProcAddress("glBufferDataARB"); - qglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glBufferSubDataARB"); - qglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC) SDL_GL_GetProcAddress("glGetBufferSubDataARB"); - qglGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetBufferParameterivARB"); - qglGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC) SDL_GL_GetProcAddress("glGetBufferPointervARB"); - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.vertexBufferObject = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_shader_objects - extension = "GL_ARB_shader_objects"; - //glRefConfig.shaderObjects = qfalse; - qglDeleteObjectARB = NULL; - qglGetHandleARB = NULL; - qglDetachObjectARB = NULL; - qglCreateShaderObjectARB = NULL; - qglShaderSourceARB = NULL; - qglCompileShaderARB = NULL; - qglCreateProgramObjectARB = NULL; - qglAttachObjectARB = NULL; - qglLinkProgramARB = NULL; - qglUseProgramObjectARB = NULL; - qglValidateProgramARB = NULL; - qglUniform1fARB = NULL; - qglUniform2fARB = NULL; - qglUniform3fARB = NULL; - qglUniform4fARB = NULL; - qglUniform1iARB = NULL; - qglUniform2iARB = NULL; - qglUniform3iARB = NULL; - qglUniform4iARB = NULL; - qglUniform1fvARB = NULL; - qglUniform2fvARB = NULL; - qglUniform3fvARB = NULL; - qglUniform4fvARB = NULL; - qglUniform2ivARB = NULL; - qglUniform3ivARB = NULL; - qglUniform4ivARB = NULL; - qglUniformMatrix2fvARB = NULL; - qglUniformMatrix3fvARB = NULL; - qglUniformMatrix4fvARB = NULL; - qglGetObjectParameterfvARB = NULL; - qglGetObjectParameterivARB = NULL; - qglGetInfoLogARB = NULL; - qglGetAttachedObjectsARB = NULL; - qglGetUniformLocationARB = NULL; - qglGetActiveUniformARB = NULL; - qglGetUniformfvARB = NULL; - qglGetUniformivARB = NULL; - qglGetShaderSourceARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB"); - qglGetHandleARB = (PFNGLGETHANDLEARBPROC) SDL_GL_GetProcAddress("glGetHandleARB"); - qglDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) SDL_GL_GetProcAddress("glDetachObjectARB"); - qglCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB"); - qglShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB"); - qglCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB"); - qglCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB"); - qglAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB"); - qglLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB"); - qglUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB"); - qglValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) SDL_GL_GetProcAddress("glValidateProgramARB"); - qglUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB"); - qglUniform2fARB = (PFNGLUNIFORM2FARBPROC) SDL_GL_GetProcAddress("glUniform2fARB"); - qglUniform3fARB = (PFNGLUNIFORM3FARBPROC) SDL_GL_GetProcAddress("glUniform3fARB"); - qglUniform4fARB = (PFNGLUNIFORM4FARBPROC) SDL_GL_GetProcAddress("glUniform4fARB"); - qglUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB"); - qglUniform2iARB = (PFNGLUNIFORM2IARBPROC) SDL_GL_GetProcAddress("glUniform2iARB"); - qglUniform3iARB = (PFNGLUNIFORM3IARBPROC) SDL_GL_GetProcAddress("glUniform3iARB"); - qglUniform4iARB = (PFNGLUNIFORM4IARBPROC) SDL_GL_GetProcAddress("glUniform4iARB"); - qglUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) SDL_GL_GetProcAddress("glUniform1fvARB"); - qglUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) SDL_GL_GetProcAddress("glUniform2fvARB"); - qglUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) SDL_GL_GetProcAddress("glUniform3fvARB"); - qglUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) SDL_GL_GetProcAddress("glUniform4fvARB"); - qglUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) SDL_GL_GetProcAddress("glUniform2ivARB"); - qglUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) SDL_GL_GetProcAddress("glUniform3ivARB"); - qglUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) SDL_GL_GetProcAddress("glUniform4ivARB"); - qglUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix2fvARB"); - qglUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix3fvARB"); - qglUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) SDL_GL_GetProcAddress("glUniformMatrix4fvARB"); - qglGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterfvARB"); - qglGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB"); - qglGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB"); - qglGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) SDL_GL_GetProcAddress("glGetAttachedObjectsARB"); - qglGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB"); - qglGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) SDL_GL_GetProcAddress("glGetActiveUniformARB"); - qglGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) SDL_GL_GetProcAddress("glGetUniformfvARB"); - qglGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) SDL_GL_GetProcAddress("glGetUniformivARB"); - qglGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glGetShaderSourceARB"); - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.shaderObjects = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_vertex_shader - //glRefConfig.vertexShader = qfalse; - extension = "GL_ARB_vertex_shader"; - qglBindAttribLocationARB = NULL; - qglGetActiveAttribARB = NULL; - qglGetAttribLocationARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - //int reservedComponents; - - //qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.maxVertexUniforms); - //qglGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats); - //qglGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.maxVertexAttribs); - - //reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices - -#if 0 - if(glConfig.driverType == GLDRV_MESA) - { - // HACK - // restrict to number of vertex uniforms to 512 because of: - // xreal.x86_64: nv50_program.c:4181: nv50_program_validate_data: Assertion `p->param_nr <= 512' failed - - glConfig.maxVertexUniforms = Q_bound(0, glConfig.maxVertexUniforms, 512); - } -#endif - - //glConfig.maxVertexSkinningBones = (int) Q_bound(0.0, (Q_max(glConfig.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES); - //glConfig.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ((glConfig.maxVertexSkinningBones >= 12) ? qtrue : qfalse); - - qglBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glBindAttribLocationARB"); - qglGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) SDL_GL_GetProcAddress("glGetActiveAttribARB"); - qglGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetAttribLocationARB"); - ri.Printf(PRINT_ALL, result[1], extension); - //glRefConfig.vertexShader = qtrue; - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - // GL_ARB_shading_language_100 - extension = "GL_ARB_shading_language_100"; - glRefConfig.textureFloat = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - char version[256]; - - Q_strncpyz( version, (char *) qglGetString (GL_SHADING_LANGUAGE_VERSION_ARB), sizeof( version ) ); - - sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion); - - ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version); - } - else - { - ri.Error(ERR_FATAL, result[2], extension); - } - - glRefConfig.memInfo = MI_NONE; - - if( GLimp_HaveExtension( "GL_NVX_gpu_memory_info" ) ) - { - glRefConfig.memInfo = MI_NVX; - } - else if( GLimp_HaveExtension( "GL_ATI_meminfo" ) ) - { - glRefConfig.memInfo = MI_ATI; - } - - extension = "GL_ARB_texture_non_power_of_two"; - glRefConfig.textureNonPowerOfTwo = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if(1) //(r_ext_texture_non_power_of_two->integer) - { - glRefConfig.textureNonPowerOfTwo = qtrue; - } - - ri.Printf(PRINT_ALL, result[glRefConfig.textureNonPowerOfTwo], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_texture_float - extension = "GL_ARB_texture_float"; - glRefConfig.textureFloat = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if( r_ext_texture_float->integer ) - { - glRefConfig.textureFloat = qtrue; - } - - ri.Printf(PRINT_ALL, result[glRefConfig.textureFloat], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_half_float_pixel - extension = "GL_ARB_half_float_pixel"; - glRefConfig.halfFloatPixel = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if( r_arb_half_float_pixel->integer ) - glRefConfig.halfFloatPixel = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.halfFloatPixel], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_EXT_framebuffer_object - extension = "GL_EXT_framebuffer_object"; + // OpenGL 3.0 - GL_ARB_framebuffer_object + extension = "GL_ARB_framebuffer_object"; glRefConfig.framebufferObject = qfalse; - if( GLimp_HaveExtension( extension ) ) + glRefConfig.framebufferBlit = qfalse; + glRefConfig.framebufferMultisample = qfalse; + if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension)) { - glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glRefConfig.maxRenderbufferSize); - glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glRefConfig.maxColorAttachments); + glRefConfig.framebufferObject = !!r_ext_framebuffer_object->integer; + glRefConfig.framebufferBlit = qtrue; + glRefConfig.framebufferMultisample = qtrue; - qglIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsRenderbufferEXT"); - qglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindRenderbufferEXT"); - qglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteRenderbuffersEXT"); - qglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenRenderbuffersEXT"); - qglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) SDL_GL_GetProcAddress("glRenderbufferStorageEXT"); - qglGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetRenderbufferParameterivEXT"); - qglIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glIsFramebufferEXT"); - qglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) SDL_GL_GetProcAddress("glBindFramebufferEXT"); - qglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glDeleteFramebuffersEXT"); - qglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) SDL_GL_GetProcAddress("glGenFramebuffersEXT"); - qglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT"); - qglFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture1DEXT"); - qglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture2DEXT"); - qglFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) SDL_GL_GetProcAddress("glFramebufferTexture3DEXT"); - qglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) SDL_GL_GetProcAddress("glFramebufferRenderbufferEXT"); - qglGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameterivEXT"); - qglGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC) SDL_GL_GetProcAddress("glGenerateMipmapEXT"); + qglGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glRefConfig.maxRenderbufferSize); + qglGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &glRefConfig.maxColorAttachments); - if(r_ext_framebuffer_object->value) - glRefConfig.framebufferObject = qtrue; + QGL_ARB_framebuffer_object_PROCS; ri.Printf(PRINT_ALL, result[glRefConfig.framebufferObject], extension); } @@ -582,78 +80,113 @@ void GLimp_InitExtraExtensions() ri.Printf(PRINT_ALL, result[2], extension); } - // GL_EXT_packed_depth_stencil - extension = "GL_EXT_packed_depth_stencil"; - glRefConfig.packedDepthStencil = qfalse; - if( GLimp_HaveExtension(extension)) + // OpenGL 3.0 - GL_ARB_vertex_array_object + extension = "GL_ARB_vertex_array_object"; + glRefConfig.vertexArrayObject = qfalse; + if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension)) { - glRefConfig.packedDepthStencil = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.packedDepthStencil], extension); + if (q_gl_version_at_least_3_0) + { + // force VAO, core context requires it + glRefConfig.vertexArrayObject = qtrue; + } + else + { + glRefConfig.vertexArrayObject = !!r_arb_vertex_array_object->integer; + } + + QGL_ARB_vertex_array_object_PROCS; + + ri.Printf(PRINT_ALL, result[glRefConfig.vertexArrayObject], extension); } else { ri.Printf(PRINT_ALL, result[2], extension); } - // GL_ARB_occlusion_query - extension = "GL_ARB_occlusion_query"; - glRefConfig.occlusionQuery = qfalse; - if (GLimp_HaveExtension(extension)) + // OpenGL 3.0 - GL_ARB_texture_float + extension = "GL_ARB_texture_float"; + glRefConfig.textureFloat = qfalse; + if (q_gl_version_at_least_3_0 || SDL_GL_ExtensionSupported(extension)) { - qglGenQueriesARB = (PFNGLGENQUERIESARBPROC) SDL_GL_GetProcAddress("glGenQueriesARB"); - qglDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC) SDL_GL_GetProcAddress("glDeleteQueriesARB"); - qglIsQueryARB = (PFNGLISQUERYARBPROC) SDL_GL_GetProcAddress("glIsQueryARB"); - qglBeginQueryARB = (PFNGLBEGINQUERYARBPROC) SDL_GL_GetProcAddress("glBeginQueryARB"); - qglEndQueryARB = (PFNGLENDQUERYARBPROC) SDL_GL_GetProcAddress("glEndQueryARB"); - qglGetQueryivARB = (PFNGLGETQUERYIVARBPROC) SDL_GL_GetProcAddress("glGetQueryivARB"); - qglGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectivARB"); - qglGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC) SDL_GL_GetProcAddress("glGetQueryObjectuivARB"); - glRefConfig.occlusionQuery = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.occlusionQuery], extension); + glRefConfig.textureFloat = !!r_ext_texture_float->integer; + + ri.Printf(PRINT_ALL, result[glRefConfig.textureFloat], extension); } else { ri.Printf(PRINT_ALL, result[2], extension); } - // GL_EXT_framebuffer_blit - extension = "GL_EXT_framebuffer_blit"; - glRefConfig.framebufferBlit = qfalse; - if (GLimp_HaveExtension(extension)) + // OpenGL 3.2 - GL_ARB_depth_clamp + extension = "GL_ARB_depth_clamp"; + glRefConfig.depthClamp = qfalse; + if (q_gl_version_at_least_3_2 || SDL_GL_ExtensionSupported(extension)) { - qglBlitFramebufferEXT = (void *)SDL_GL_GetProcAddress("glBlitFramebufferEXT"); - glRefConfig.framebufferBlit = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferBlit], extension); + glRefConfig.depthClamp = qtrue; + + ri.Printf(PRINT_ALL, result[glRefConfig.depthClamp], extension); } else { ri.Printf(PRINT_ALL, result[2], extension); } - // GL_ARB_texture_compression - extension = "GL_ARB_texture_compression"; - glRefConfig.arbTextureCompression = qfalse; - if (GLimp_HaveExtension(extension)) + // OpenGL 3.2 - GL_ARB_seamless_cube_map + extension = "GL_ARB_seamless_cube_map"; + glRefConfig.seamlessCubeMap = qfalse; + if (q_gl_version_at_least_3_2 || SDL_GL_ExtensionSupported(extension)) { - qglCompressedTexImage3DARB = (void *)SDL_GL_GetProcAddress("glCompressedTexImage3DARB"); - qglCompressedTexImage2DARB = (void *)SDL_GL_GetProcAddress("glCompressedTexImage2DARB"); - qglCompressedTexImage1DARB = (void *)SDL_GL_GetProcAddress("glCompressedTexImage1DARB"); - qglCompressedTexSubImage3DARB = (void *)SDL_GL_GetProcAddress("glCompressedTexSubImage3DARB"); - qglCompressedTexSubImage2DARB = (void *)SDL_GL_GetProcAddress("glCompressedTexSubImage2DARB"); - qglCompressedTexSubImage1DARB = (void *)SDL_GL_GetProcAddress("glCompressedTexSubImage1DARB"); - qglGetCompressedTexImageARB = (void *)SDL_GL_GetProcAddress("glGetCompressedTexImageARB"); - glRefConfig.arbTextureCompression = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.arbTextureCompression], extension); + glRefConfig.seamlessCubeMap = !!r_arb_seamless_cube_map->integer; + + ri.Printf(PRINT_ALL, result[glRefConfig.seamlessCubeMap], extension); + } + else + { + ri.Printf(PRINT_ALL, result[2], extension); } - // GL_EXT_framebuffer_multisample - extension = "GL_EXT_framebuffer_multisample"; - glRefConfig.framebufferMultisample = qfalse; - if (GLimp_HaveExtension(extension)) + // Determine GLSL version + if (1) { - qglRenderbufferStorageMultisampleEXT = (void *)SDL_GL_GetProcAddress("glRenderbufferStorageMultisampleEXT"); - glRefConfig.framebufferMultisample = qtrue; - ri.Printf(PRINT_ALL, result[glRefConfig.framebufferMultisample], extension); + char version[256]; + + Q_strncpyz(version, (char *)qglGetString(GL_SHADING_LANGUAGE_VERSION), sizeof(version)); + + sscanf(version, "%d.%d", &glRefConfig.glslMajorVersion, &glRefConfig.glslMinorVersion); + + ri.Printf(PRINT_ALL, "...using GLSL version %s\n", version); + } + + glRefConfig.memInfo = MI_NONE; + + // GL_NVX_gpu_memory_info + extension = "GL_NVX_gpu_memory_info"; + if( SDL_GL_ExtensionSupported( extension ) ) + { + glRefConfig.memInfo = MI_NVX; + + ri.Printf(PRINT_ALL, result[1], extension); + } + else + { + ri.Printf(PRINT_ALL, result[2], extension); + } + + // GL_ATI_meminfo + extension = "GL_ATI_meminfo"; + if( SDL_GL_ExtensionSupported( extension ) ) + { + if (glRefConfig.memInfo == MI_NONE) + { + glRefConfig.memInfo = MI_ATI; + + ri.Printf(PRINT_ALL, result[1], extension); + } + else + { + ri.Printf(PRINT_ALL, result[0], extension); + } } else { @@ -664,12 +197,14 @@ void GLimp_InitExtraExtensions() // GL_ARB_texture_compression_rgtc extension = "GL_ARB_texture_compression_rgtc"; - if (GLimp_HaveExtension(extension)) + if (SDL_GL_ExtensionSupported(extension)) { - if (r_ext_compressed_textures->integer && glRefConfig.arbTextureCompression) + qboolean useRgtc = r_ext_compressed_textures->integer >= 1; + + if (useRgtc) glRefConfig.textureCompression |= TCR_RGTC; - ri.Printf(PRINT_ALL, result[r_ext_compressed_textures->integer ? 1 : 0], extension); + ri.Printf(PRINT_ALL, result[useRgtc], extension); } else { @@ -680,115 +215,14 @@ void GLimp_InitExtraExtensions() // GL_ARB_texture_compression_bptc extension = "GL_ARB_texture_compression_bptc"; - if (GLimp_HaveExtension(extension)) + if (SDL_GL_ExtensionSupported(extension)) { - if (r_ext_compressed_textures->integer >= 2) + qboolean useBptc = r_ext_compressed_textures->integer >= 2; + + if (useBptc) glRefConfig.textureCompression |= TCR_BPTC; - ri.Printf(PRINT_ALL, result[(r_ext_compressed_textures->integer >= 2) ? 1 : 0], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_draw_buffers - extension = "GL_ARB_draw_buffers"; - qglDrawBuffersARB = NULL; - if( GLimp_HaveExtension( extension ) ) - { - qglDrawBuffersARB = (void *) SDL_GL_GetProcAddress("glDrawBuffersARB"); - - ri.Printf(PRINT_ALL, result[1], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_depth_clamp - extension = "GL_ARB_depth_clamp"; - glRefConfig.depthClamp = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - glRefConfig.depthClamp = qtrue; - ri.Printf(PRINT_ALL, result[1], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_seamless_cube_map - extension = "GL_ARB_seamless_cube_map"; - glRefConfig.seamlessCubeMap = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - if (r_arb_seamless_cube_map->integer) - glRefConfig.seamlessCubeMap = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.seamlessCubeMap], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_vertex_type_2_10_10_10_rev - extension = "GL_ARB_vertex_type_2_10_10_10_rev"; - glRefConfig.packedNormalDataType = GL_BYTE; - if( GLimp_HaveExtension( extension ) ) - { - if (r_arb_vertex_type_2_10_10_10_rev->integer) - glRefConfig.packedNormalDataType = GL_INT_2_10_10_10_REV; - - ri.Printf(PRINT_ALL, result[r_arb_vertex_type_2_10_10_10_rev->integer ? 1 : 0], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // use float lightmaps? - glRefConfig.floatLightmap = (glRefConfig.textureFloat && glRefConfig.halfFloatPixel && r_floatLightmap->integer && r_hdr->integer); - - // GL_ARB_vertex_array_object - extension = "GL_ARB_vertex_array_object"; - glRefConfig.vertexArrayObject = qfalse; - if( GLimp_HaveExtension( extension ) ) - { - qglBindVertexArrayARB = (void *) SDL_GL_GetProcAddress("glBindVertexArray"); - qglDeleteVertexArraysARB = (void *) SDL_GL_GetProcAddress("glDeleteVertexArrays"); - qglGenVertexArraysARB = (void *) SDL_GL_GetProcAddress("glGenVertexArrays"); - qglIsVertexArrayARB = (void *) SDL_GL_GetProcAddress("glIsVertexArray"); - - if (r_arb_vertex_array_object->integer) - glRefConfig.vertexArrayObject = qtrue; - - ri.Printf(PRINT_ALL, result[glRefConfig.vertexArrayObject ? 1 : 0], extension); - } - else - { - ri.Printf(PRINT_ALL, result[2], extension); - } - - // GL_ARB_half_float_vertex - extension = "GL_ARB_half_float_vertex"; - glRefConfig.packedTexcoordDataType = GL_FLOAT; - glRefConfig.packedTexcoordDataSize = sizeof(float) * 2; - glRefConfig.packedColorDataType = GL_FLOAT; - glRefConfig.packedColorDataSize = sizeof(float) * 4; - if( GLimp_HaveExtension( extension ) ) - { - if (r_arb_half_float_vertex->integer) - { - glRefConfig.packedTexcoordDataType = GL_HALF_FLOAT; - glRefConfig.packedTexcoordDataSize = sizeof(uint16_t) * 2; - glRefConfig.packedColorDataType = GL_HALF_FLOAT; - glRefConfig.packedColorDataSize = sizeof(uint16_t) * 4; - } - - ri.Printf(PRINT_ALL, result[r_arb_half_float_vertex->integer ? 1 : 0], extension); + ri.Printf(PRINT_ALL, result[useBptc], extension); } else { @@ -797,66 +231,23 @@ void GLimp_InitExtraExtensions() // GL_EXT_direct_state_access extension = "GL_EXT_direct_state_access"; - - qglBindMultiTexture = GLDSA_BindMultiTexture; - qglTextureParameterf = GLDSA_TextureParameterf; - qglTextureParameteri = GLDSA_TextureParameteri; - qglTextureImage2D = GLDSA_TextureImage2D; - qglTextureSubImage2D = GLDSA_TextureSubImage2D; - qglCopyTextureImage2D = GLDSA_CopyTextureImage2D; - qglCompressedTextureImage2D = GLDSA_CompressedTextureImage2D; - qglCompressedTextureSubImage2D = GLDSA_CompressedTextureSubImage2D; - qglGenerateTextureMipmap = GLDSA_GenerateTextureMipmap; - - qglProgramUniform1i = GLDSA_ProgramUniform1i; - qglProgramUniform1f = GLDSA_ProgramUniform1f; - qglProgramUniform2f = GLDSA_ProgramUniform2f; - qglProgramUniform3f = GLDSA_ProgramUniform3f; - qglProgramUniform4f = GLDSA_ProgramUniform4f; - qglProgramUniform1fv = GLDSA_ProgramUniform1fv; - qglProgramUniformMatrix4fv = GLDSA_ProgramUniformMatrix4fv; - - qglNamedRenderbufferStorage = GLDSA_NamedRenderbufferStorage; - qglNamedRenderbufferStorageMultisample = GLDSA_NamedRenderbufferStorageMultisample; - qglCheckNamedFramebufferStatus = GLDSA_CheckNamedFramebufferStatus; - qglNamedFramebufferTexture2D = GLDSA_NamedFramebufferTexture2D; - qglNamedFramebufferRenderbuffer = GLDSA_NamedFramebufferRenderbuffer; - glRefConfig.directStateAccess = qfalse; - if (GLimp_HaveExtension(extension)) + if (SDL_GL_ExtensionSupported(extension)) { - if (r_ext_direct_state_access->integer) + glRefConfig.directStateAccess = !!r_ext_direct_state_access->integer; + + // QGL_*_PROCS becomes several functions, do not remove {} + if (glRefConfig.directStateAccess) { - glRefConfig.directStateAccess = qtrue; - qglBindMultiTexture = (void *)SDL_GL_GetProcAddress("glBindMultiTextureEXT"); - qglTextureParameterf = (void *)SDL_GL_GetProcAddress("glTextureParameterfEXT"); - qglTextureParameteri = (void *)SDL_GL_GetProcAddress("glTextureParameteriEXT"); - qglTextureImage2D = (void *)SDL_GL_GetProcAddress("glTextureImage2DEXT"); - qglTextureSubImage2D = (void *)SDL_GL_GetProcAddress("glTextureSubImage2DEXT"); - qglCopyTextureImage2D = (void *)SDL_GL_GetProcAddress("glCopyTextureImage2DEXT"); - qglCompressedTextureImage2D = (void *)SDL_GL_GetProcAddress("glCompressedTextureImage2DEXT"); - qglCompressedTextureSubImage2D = (void *)SDL_GL_GetProcAddress("glCompressedTextureSubImage2DEXT"); - qglGenerateTextureMipmap = (void *)SDL_GL_GetProcAddress("glGenerateTextureMipmapEXT"); - - qglProgramUniform1i = (void *)SDL_GL_GetProcAddress("glProgramUniform1iEXT"); - qglProgramUniform1f = (void *)SDL_GL_GetProcAddress("glProgramUniform1fEXT"); - qglProgramUniform2f = (void *)SDL_GL_GetProcAddress("glProgramUniform2fEXT"); - qglProgramUniform3f = (void *)SDL_GL_GetProcAddress("glProgramUniform3fEXT"); - qglProgramUniform4f = (void *)SDL_GL_GetProcAddress("glProgramUniform4fEXT"); - qglProgramUniform1fv = (void *)SDL_GL_GetProcAddress("glProgramUniform1fvEXT"); - qglProgramUniformMatrix4fv = (void *)SDL_GL_GetProcAddress("glProgramUniformMatrix4fvEXT"); - - qglNamedRenderbufferStorage = (void *)SDL_GL_GetProcAddress("glNamedRenderbufferStorageEXT"); - qglNamedRenderbufferStorageMultisample = (void *)SDL_GL_GetProcAddress("glNamedRenderbufferStorageMultisampleEXT"); - qglCheckNamedFramebufferStatus = (void *)SDL_GL_GetProcAddress("glCheckNamedFramebufferStatusEXT"); - qglNamedFramebufferTexture2D = (void *)SDL_GL_GetProcAddress("glNamedFramebufferTexture2DEXT"); - qglNamedFramebufferRenderbuffer = (void *)SDL_GL_GetProcAddress("glNamedFramebufferRenderbufferEXT"); + QGL_EXT_direct_state_access_PROCS; } - ri.Printf(PRINT_ALL, result[glRefConfig.directStateAccess ? 1 : 0], extension); + ri.Printf(PRINT_ALL, result[glRefConfig.directStateAccess], extension); } else { ri.Printf(PRINT_ALL, result[2], extension); } + +#undef GLE } diff --git a/code/renderergl2/tr_extramath.c b/code/renderergl2/tr_extramath.c index bded7570..a6c2a0db 100644 --- a/code/renderergl2/tr_extramath.c +++ b/code/renderergl2/tr_extramath.c @@ -201,7 +201,7 @@ int NextPowerOfTwo(int in) union f32_u { float f; - uint32_t i; + uint32_t ui; struct { unsigned int fraction:23; unsigned int exponent:8; @@ -210,7 +210,7 @@ union f32_u { }; union f16_u { - uint16_t i; + uint16_t ui; struct { unsigned int fraction:10; unsigned int exponent:5; @@ -229,5 +229,19 @@ uint16_t FloatToHalf(float in) f16.pack.fraction = f32.pack.fraction >> 13; f16.pack.sign = f32.pack.sign; - return f16.i; + return f16.ui; +} + +float HalfToFloat(uint16_t in) +{ + union f32_u f32; + union f16_u f16; + + f16.ui = in; + + f32.pack.exponent = (int)(f16.pack.exponent) + 112; + f32.pack.fraction = f16.pack.fraction << 13; + f32.pack.sign = f16.pack.sign; + + return f32.f; } diff --git a/code/renderergl2/tr_extramath.h b/code/renderergl2/tr_extramath.h index 93271537..d9ce170c 100644 --- a/code/renderergl2/tr_extramath.h +++ b/code/renderergl2/tr_extramath.h @@ -98,5 +98,6 @@ void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, floa int NextPowerOfTwo(int in); unsigned short FloatToHalf(float in); +float HalfToFloat(unsigned short in); #endif diff --git a/code/renderergl2/tr_fbo.c b/code/renderergl2/tr_fbo.c index 80d59f62..26f50c3f 100644 --- a/code/renderergl2/tr_fbo.c +++ b/code/renderergl2/tr_fbo.c @@ -32,48 +32,38 @@ R_CheckFBO */ qboolean R_CheckFBO(const FBO_t * fbo) { - GLenum code = qglCheckNamedFramebufferStatus(fbo->frameBuffer, GL_FRAMEBUFFER_EXT); + GLenum code = qglCheckNamedFramebufferStatusEXT(fbo->frameBuffer, GL_FRAMEBUFFER); - if(code == GL_FRAMEBUFFER_COMPLETE_EXT) + if(code == GL_FRAMEBUFFER_COMPLETE) return qtrue; - // an error occured + // an error occurred switch (code) { - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + case GL_FRAMEBUFFER_UNSUPPORTED: ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Unsupported framebuffer format\n", fbo->name); break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete attachment\n", fbo->name); break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing attachment\n", fbo->name); break; - //case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: - // ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, duplicate attachment\n", fbo->name); - // break; - - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same dimensions\n", - fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, attached images must have same format\n", - fbo->name); - break; - - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing draw buffer\n", fbo->name); break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete, missing read buffer\n", fbo->name); break; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Framebuffer incomplete multisample\n", fbo->name); + break; + default: ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code); break; @@ -117,7 +107,7 @@ FBO_t *FBO_Create(const char *name, int width, int height) fbo->width = width; fbo->height = height; - qglGenFramebuffersEXT(1, &fbo->frameBuffer); + qglGenFramebuffers(1, &fbo->frameBuffer); return fbo; } @@ -145,7 +135,7 @@ void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample) case GL_RGBA32F_ARB: fbo->colorFormat = format; pRenderBuffer = &fbo->colorBuffers[index]; - attachment = GL_COLOR_ATTACHMENT0_EXT + index; + attachment = GL_COLOR_ATTACHMENT0 + index; break; case GL_DEPTH_COMPONENT: @@ -154,21 +144,21 @@ void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample) case GL_DEPTH_COMPONENT32_ARB: fbo->depthFormat = format; pRenderBuffer = &fbo->depthBuffer; - attachment = GL_DEPTH_ATTACHMENT_EXT; + attachment = GL_DEPTH_ATTACHMENT; break; case GL_STENCIL_INDEX: - case GL_STENCIL_INDEX1_EXT: - case GL_STENCIL_INDEX4_EXT: - case GL_STENCIL_INDEX8_EXT: - case GL_STENCIL_INDEX16_EXT: + case GL_STENCIL_INDEX1: + case GL_STENCIL_INDEX4: + case GL_STENCIL_INDEX8: + case GL_STENCIL_INDEX16: fbo->stencilFormat = format; pRenderBuffer = &fbo->stencilBuffer; - attachment = GL_STENCIL_ATTACHMENT_EXT; + attachment = GL_STENCIL_ATTACHMENT; break; - case GL_DEPTH_STENCIL_EXT: - case GL_DEPTH24_STENCIL8_EXT: + case GL_DEPTH_STENCIL: + case GL_DEPTH24_STENCIL8: fbo->packedDepthStencilFormat = format; pRenderBuffer = &fbo->packedDepthStencilBuffer; attachment = 0; // special for stencil and depth @@ -181,23 +171,23 @@ void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample) absent = *pRenderBuffer == 0; if (absent) - qglGenRenderbuffersEXT(1, pRenderBuffer); + qglGenRenderbuffers(1, pRenderBuffer); if (multisample && glRefConfig.framebufferMultisample) - qglNamedRenderbufferStorageMultisample(*pRenderBuffer, multisample, format, fbo->width, fbo->height); + qglNamedRenderbufferStorageMultisampleEXT(*pRenderBuffer, multisample, format, fbo->width, fbo->height); else - qglNamedRenderbufferStorage(*pRenderBuffer, format, fbo->width, fbo->height); + qglNamedRenderbufferStorageEXT(*pRenderBuffer, format, fbo->width, fbo->height); if(absent) { if (attachment == 0) { - qglNamedFramebufferRenderbuffer(fbo->frameBuffer, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); - qglNamedFramebufferRenderbuffer(fbo->frameBuffer, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); + qglNamedFramebufferRenderbufferEXT(fbo->frameBuffer, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *pRenderBuffer); + qglNamedFramebufferRenderbufferEXT(fbo->frameBuffer, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *pRenderBuffer); } else { - qglNamedFramebufferRenderbuffer(fbo->frameBuffer, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer); + qglNamedFramebufferRenderbufferEXT(fbo->frameBuffer, attachment, GL_RENDERBUFFER, *pRenderBuffer); } } } @@ -216,8 +206,8 @@ void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubem if (image->flags & IMGFLAG_CUBEMAP) target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cubemapside; - qglNamedFramebufferTexture2D(fbo->frameBuffer, attachment, target, image->texnum, 0); - index = attachment - GL_COLOR_ATTACHMENT0_EXT; + qglNamedFramebufferTexture2DEXT(fbo->frameBuffer, attachment, target, image->texnum, 0); + index = attachment - GL_COLOR_ATTACHMENT0; if (index >= 0 && index <= 15) fbo->colorImage[index] = image; } @@ -230,6 +220,12 @@ FBO_Bind */ void FBO_Bind(FBO_t * fbo) { + if (!glRefConfig.framebufferObject) + { + ri.Printf(PRINT_WARNING, "FBO_Bind() called without framebuffers enabled!\n"); + return; + } + if (glState.currentFBO == fbo) return; @@ -239,7 +235,7 @@ void FBO_Bind(FBO_t * fbo) GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo ? fbo->name : "NULL")); } - GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, fbo ? fbo->frameBuffer : 0); + GL_BindFramebuffer(GL_FRAMEBUFFER, fbo ? fbo->frameBuffer : 0); glState.currentFBO = fbo; } @@ -265,11 +261,11 @@ void FBO_Init(void) R_IssuePendingRenderCommands(); hdrFormat = GL_RGBA8; - if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat) + if (r_hdr->integer && glRefConfig.textureFloat) hdrFormat = GL_RGBA16F_ARB; if (glRefConfig.framebufferMultisample) - qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample); + qglGetIntegerv(GL_MAX_SAMPLES, &multisample); if (r_ext_framebuffer_multisample->integer < multisample) multisample = r_ext_framebuffer_multisample->integer; @@ -286,19 +282,19 @@ void FBO_Init(void) { tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample); - FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample); + FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24, 0, multisample); R_CheckFBO(tr.renderFbo); tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_AttachImage(tr.msaaResolveFbo, tr.renderImage, GL_COLOR_ATTACHMENT0_EXT, 0); - FBO_AttachImage(tr.msaaResolveFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0); + FBO_AttachImage(tr.msaaResolveFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0); + FBO_AttachImage(tr.msaaResolveFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.msaaResolveFbo); } else if (r_hdr->integer) { tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_AttachImage(tr.renderFbo, tr.renderImage, GL_COLOR_ATTACHMENT0_EXT, 0); - FBO_AttachImage(tr.renderFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0); + FBO_AttachImage(tr.renderFbo, tr.renderImage, GL_COLOR_ATTACHMENT0, 0); + FBO_AttachImage(tr.renderFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.renderFbo); } @@ -306,103 +302,117 @@ void FBO_Init(void) // this fixes the corrupt screen bug with r_hdr 1 on older hardware if (tr.renderFbo) { - GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, tr.renderFbo->frameBuffer); + GL_BindFramebuffer(GL_FRAMEBUFFER, tr.renderFbo->frameBuffer); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } - if (r_shadowBlur->integer) + if (tr.screenScratchImage) { tr.screenScratchFbo = FBO_Create("screenScratch", tr.screenScratchImage->width, tr.screenScratchImage->height); - FBO_AttachImage(tr.screenScratchFbo, tr.screenScratchImage, GL_COLOR_ATTACHMENT0_EXT, 0); - FBO_AttachImage(tr.screenScratchFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0); + FBO_AttachImage(tr.screenScratchFbo, tr.screenScratchImage, GL_COLOR_ATTACHMENT0, 0); + FBO_AttachImage(tr.screenScratchFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.screenScratchFbo); } - if (r_drawSunRays->integer) + if (tr.sunRaysImage) { tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0_EXT, 0); - FBO_AttachImage(tr.sunRaysFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0); + FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0, 0); + FBO_AttachImage(tr.sunRaysFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.sunRaysFbo); } - // FIXME: Don't use separate color/depth buffers for a shadow buffer if (MAX_DRAWN_PSHADOWS && tr.pshadowMaps[0]) { for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) { tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height); - FBO_AttachImage(tr.pshadowFbos[i], tr.pshadowMaps[i], GL_COLOR_ATTACHMENT0_EXT, 0); - FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0); + // FIXME: this next line wastes 16mb with 16x512x512 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments + FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0); + FBO_AttachImage(tr.pshadowFbos[i], tr.pshadowMaps[i], GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.pshadowFbos[i]); } } if (tr.sunShadowDepthImage[0]) { - for ( i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height); // FIXME: this next line wastes 16mb with 4x1024x1024 sun shadow maps, skip if OpenGL 4.3+ or ARB_framebuffer_no_attachments // This at least gets sun shadows working on older GPUs (Intel) FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0); - FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT_EXT, 0); + FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT, 0); R_CheckFBO(tr.sunShadowFbo[i]); } + } + if (tr.screenShadowImage) + { tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height); - FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0_EXT, 0); + FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.screenShadowFbo); } - for (i = 0; i < 2; i++) + if (tr.textureScratchImage[0]) { - tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height); - FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0_EXT, 0); - R_CheckFBO(tr.textureScratchFbo[i]); + for (i = 0; i < 2; i++) + { + tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height); + FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0, 0); + R_CheckFBO(tr.textureScratchFbo[i]); + } } + if (tr.calcLevelsImage) { tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height); - FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0); + FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.calcLevelsFbo); } + if (tr.targetLevelsImage) { tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height); - FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0); + FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.targetLevelsFbo); } - for (i = 0; i < 2; i++) + if (tr.quarterImage[0]) { - tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height); - FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0_EXT, 0); - R_CheckFBO(tr.quarterFbo[i]); + for (i = 0; i < 2; i++) + { + tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height); + FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0, 0); + R_CheckFBO(tr.quarterFbo[i]); + } } - if (r_ssao->integer) + if (tr.hdrDepthImage) { tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height); - FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0_EXT, 0); + FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.hdrDepthFbo); + } + if (tr.screenSsaoImage) + { tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height); - FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0_EXT, 0); + FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0, 0); R_CheckFBO(tr.screenSsaoFbo); } if (tr.renderCubeImage) { tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height); - FBO_AttachImage(tr.renderCubeFbo, tr.renderCubeImage, GL_COLOR_ATTACHMENT0_EXT, 0); + FBO_AttachImage(tr.renderCubeFbo, tr.renderCubeImage, GL_COLOR_ATTACHMENT0, 0); FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); R_CheckFBO(tr.renderCubeFbo); } GL_CheckErrors(); - GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + GL_BindFramebuffer(GL_FRAMEBUFFER, 0); glState.currentFBO = NULL; } @@ -430,17 +440,17 @@ void FBO_Shutdown(void) for(j = 0; j < glRefConfig.maxColorAttachments; j++) { if(fbo->colorBuffers[j]) - qglDeleteRenderbuffersEXT(1, &fbo->colorBuffers[j]); + qglDeleteRenderbuffers(1, &fbo->colorBuffers[j]); } if(fbo->depthBuffer) - qglDeleteRenderbuffersEXT(1, &fbo->depthBuffer); + qglDeleteRenderbuffers(1, &fbo->depthBuffer); if(fbo->stencilBuffer) - qglDeleteRenderbuffersEXT(1, &fbo->stencilBuffer); + qglDeleteRenderbuffers(1, &fbo->stencilBuffer); if(fbo->frameBuffer) - qglDeleteFramebuffersEXT(1, &fbo->frameBuffer); + qglDeleteFramebuffers(1, &fbo->frameBuffer); } } @@ -473,10 +483,9 @@ void R_FBOList_f(void) ri.Printf(PRINT_ALL, " %i FBOs\n", tr.numFBOs); } -void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend) +void FBO_BlitFromTexture(struct image_s *src, vec4_t inSrcTexCorners, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend) { - ivec4_t dstBox, srcBox; - vec2_t srcTexScale; + ivec4_t dstBox; vec4_t color; vec4_t quadVerts[4]; vec2_t texCoords[4]; @@ -491,49 +500,44 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS return; } - if (inSrcBox) + width = dst ? dst->width : glConfig.vidWidth; + height = dst ? dst->height : glConfig.vidHeight; + + if (inSrcTexCorners) { - VectorSet4(srcBox, inSrcBox[0], inSrcBox[1], inSrcBox[0] + inSrcBox[2], inSrcBox[1] + inSrcBox[3]); + VectorSet2(texCoords[0], inSrcTexCorners[0], inSrcTexCorners[1]); + VectorSet2(texCoords[1], inSrcTexCorners[2], inSrcTexCorners[1]); + VectorSet2(texCoords[2], inSrcTexCorners[2], inSrcTexCorners[3]); + VectorSet2(texCoords[3], inSrcTexCorners[0], inSrcTexCorners[3]); } else { - VectorSet4(srcBox, 0, 0, src->width, src->height); + VectorSet2(texCoords[0], 0.0f, 1.0f); + VectorSet2(texCoords[1], 1.0f, 1.0f); + VectorSet2(texCoords[2], 1.0f, 0.0f); + VectorSet2(texCoords[3], 0.0f, 0.0f); } // framebuffers are 0 bottom, Y up. if (inDstBox) { - if (dst) - { - dstBox[0] = inDstBox[0]; - dstBox[1] = dst->height - inDstBox[1] - inDstBox[3]; - dstBox[2] = inDstBox[0] + inDstBox[2]; - dstBox[3] = dst->height - inDstBox[1]; - } - else - { - dstBox[0] = inDstBox[0]; - dstBox[1] = glConfig.vidHeight - inDstBox[1] - inDstBox[3]; - dstBox[2] = inDstBox[0] + inDstBox[2]; - dstBox[3] = glConfig.vidHeight - inDstBox[1]; - } - } - else if (dst) - { - VectorSet4(dstBox, 0, dst->height, dst->width, 0); + dstBox[0] = inDstBox[0]; + dstBox[1] = height - inDstBox[1] - inDstBox[3]; + dstBox[2] = inDstBox[0] + inDstBox[2]; + dstBox[3] = height - inDstBox[1]; } else { - VectorSet4(dstBox, 0, glConfig.vidHeight, glConfig.vidWidth, 0); + VectorSet4(dstBox, 0, height, width, 0); } if (inSrcTexScale) { - VectorCopy2(inSrcTexScale, srcTexScale); + VectorCopy2(inSrcTexScale, invTexRes); } else { - srcTexScale[0] = srcTexScale[1] = 1.0f; + VectorSet2(invTexRes, 1.0f, 1.0f); } if (inColor) @@ -552,17 +556,6 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS FBO_Bind(dst); - if (glState.currentFBO) - { - width = glState.currentFBO->width; - height = glState.currentFBO->height; - } - else - { - width = glConfig.vidWidth; - height = glConfig.vidHeight; - } - qglViewport( 0, 0, width, height ); qglScissor( 0, 0, width, height ); @@ -572,18 +565,13 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS GL_BindToTMU(src, TB_COLORMAP); - VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0, 1); - VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0, 1); - VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0, 1); - VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0, 1); + VectorSet4(quadVerts[0], dstBox[0], dstBox[1], 0.0f, 1.0f); + VectorSet4(quadVerts[1], dstBox[2], dstBox[1], 0.0f, 1.0f); + VectorSet4(quadVerts[2], dstBox[2], dstBox[3], 0.0f, 1.0f); + VectorSet4(quadVerts[3], dstBox[0], dstBox[3], 0.0f, 1.0f); - texCoords[0][0] = srcBox[0] / (float)src->width; texCoords[0][1] = 1.0f - srcBox[1] / (float)src->height; - texCoords[1][0] = srcBox[2] / (float)src->width; texCoords[1][1] = 1.0f - srcBox[1] / (float)src->height; - texCoords[2][0] = srcBox[2] / (float)src->width; texCoords[2][1] = 1.0f - srcBox[3] / (float)src->height; - texCoords[3][0] = srcBox[0] / (float)src->width; texCoords[3][1] = 1.0f - srcBox[3] / (float)src->height; - - invTexRes[0] = 1.0f / src->width * srcTexScale[0]; - invTexRes[1] = 1.0f / src->height * srcTexScale[1]; + invTexRes[0] /= src->width; + invTexRes[1] /= src->height; GL_State( blend ); @@ -595,14 +583,14 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS GLSL_SetUniformVec2(shaderProgram, UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax); GLSL_SetUniformVec3(shaderProgram, UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear); - RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); + RB_InstantQuad2(quadVerts, texCoords); FBO_Bind(oldFbo); } void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend) { - ivec4_t srcBox; + vec4_t srcTexCorners; if (!src) { @@ -610,20 +598,19 @@ void FBO_Blit(FBO_t *src, ivec4_t inSrcBox, vec2_t srcTexScale, FBO_t *dst, ivec return; } - // framebuffers are 0 bottom, Y up. if (inSrcBox) { - srcBox[0] = inSrcBox[0]; - srcBox[1] = src->height - inSrcBox[1] - inSrcBox[3]; - srcBox[2] = inSrcBox[2]; - srcBox[3] = inSrcBox[3]; + srcTexCorners[0] = inSrcBox[0] / (float)src->width; + srcTexCorners[1] = (inSrcBox[1] + inSrcBox[3]) / (float)src->height; + srcTexCorners[2] = (inSrcBox[0] + inSrcBox[2]) / (float)src->width; + srcTexCorners[3] = inSrcBox[1] / (float)src->height; } else { - VectorSet4(srcBox, 0, src->height, src->width, -src->height); + VectorSet4(srcTexCorners, 0.0f, 0.0f, 1.0f, 1.0f); } - FBO_BlitFromTexture(src->colorImage[0], srcBox, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE); + FBO_BlitFromTexture(src->colorImage[0], srcTexCorners, srcTexScale, dst, dstBox, shaderProgram, color, blend | GLS_DEPTHTEST_DISABLE); } void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter) @@ -637,22 +624,15 @@ void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int bu return; } - // get to a neutral state first - //FBO_Bind(NULL); - srcFb = src ? src->frameBuffer : 0; dstFb = dst ? dst->frameBuffer : 0; if (!srcBox) { - if (src) - { - VectorSet4(srcBoxFinal, 0, 0, src->width, src->height); - } - else - { - VectorSet4(srcBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight); - } + int width = src ? src->width : glConfig.vidWidth; + int height = src ? src->height : glConfig.vidHeight; + + VectorSet4(srcBoxFinal, 0, 0, width, height); } else { @@ -661,26 +641,22 @@ void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int bu if (!dstBox) { - if (dst) - { - VectorSet4(dstBoxFinal, 0, 0, dst->width, dst->height); - } - else - { - VectorSet4(dstBoxFinal, 0, 0, glConfig.vidWidth, glConfig.vidHeight); - } + int width = dst ? dst->width : glConfig.vidWidth; + int height = dst ? dst->height : glConfig.vidHeight; + + VectorSet4(dstBoxFinal, 0, 0, width, height); } else { VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]); } - GL_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, srcFb); - GL_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, dstFb); - qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3], + GL_BindFramebuffer(GL_READ_FRAMEBUFFER, srcFb); + GL_BindFramebuffer(GL_DRAW_FRAMEBUFFER, dstFb); + qglBlitFramebuffer(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3], dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3], buffers, filter); - GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + GL_BindFramebuffer(GL_FRAMEBUFFER, 0); glState.currentFBO = NULL; } diff --git a/code/renderergl2/tr_fbo.h b/code/renderergl2/tr_fbo.h index 3f23a353..29d24d52 100644 --- a/code/renderergl2/tr_fbo.h +++ b/code/renderergl2/tr_fbo.h @@ -57,7 +57,7 @@ void FBO_Bind(FBO_t *fbo); void FBO_Init(void); void FBO_Shutdown(void); -void FBO_BlitFromTexture(struct image_s *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); +void FBO_BlitFromTexture(struct image_s *src, vec4_t inSrcTexCorners, vec2_t inSrcTexScale, FBO_t *dst, ivec4_t inDstBox, struct shaderProgram_s *shaderProgram, vec4_t inColor, int blend); void FBO_Blit(FBO_t *src, ivec4_t srcBox, vec2_t srcTexScale, FBO_t *dst, ivec4_t dstBox, struct shaderProgram_s *shaderProgram, vec4_t color, int blend); void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int buffers, int filter); diff --git a/code/renderergl2/tr_flares.c b/code/renderergl2/tr_flares.c index e1d46d54..fc83df7b 100644 --- a/code/renderergl2/tr_flares.c +++ b/code/renderergl2/tr_flares.c @@ -395,51 +395,51 @@ void RB_RenderFlare( flare_t *f ) { return; } - iColor[0] = color[0] * fogFactors[0]; - iColor[1] = color[1] * fogFactors[1]; - iColor[2] = color[2] * fogFactors[2]; + iColor[0] = color[0] * fogFactors[0] * 257; + iColor[1] = color[1] * fogFactors[1] * 257; + iColor[2] = color[2] * fogFactors[2] * 257; RB_BeginSurface( tr.flareShader, f->fogNum, 0 ); // FIXME: use quadstamp? tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; + tess.texCoords[tess.numVertexes][0] = 0; + tess.texCoords[tess.numVertexes][1] = 0; + tess.color[tess.numVertexes][0] = iColor[0]; + tess.color[tess.numVertexes][1] = iColor[1]; + tess.color[tess.numVertexes][2] = iColor[2]; + tess.color[tess.numVertexes][3] = 65535; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX - size; tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; + tess.texCoords[tess.numVertexes][0] = 0; + tess.texCoords[tess.numVertexes][1] = 1; + tess.color[tess.numVertexes][0] = iColor[0]; + tess.color[tess.numVertexes][1] = iColor[1]; + tess.color[tess.numVertexes][2] = iColor[2]; + tess.color[tess.numVertexes][3] = 65535; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY + size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; + tess.texCoords[tess.numVertexes][0] = 1; + tess.texCoords[tess.numVertexes][1] = 1; + tess.color[tess.numVertexes][0] = iColor[0]; + tess.color[tess.numVertexes][1] = iColor[1]; + tess.color[tess.numVertexes][2] = iColor[2]; + tess.color[tess.numVertexes][3] = 65535; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = f->windowX + size; tess.xyz[tess.numVertexes][1] = f->windowY - size; - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = iColor[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = iColor[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = iColor[2] / 255.0f; - tess.vertexColors[tess.numVertexes][3] = 1.0f; + tess.texCoords[tess.numVertexes][0] = 1; + tess.texCoords[tess.numVertexes][1] = 0; + tess.color[tess.numVertexes][0] = iColor[0]; + tess.color[tess.numVertexes][1] = iColor[1]; + tess.color[tess.numVertexes][2] = iColor[2]; + tess.color[tess.numVertexes][3] = 65535; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; @@ -526,10 +526,6 @@ void RB_RenderFlares (void) { return; // none visible } - if ( backEnd.viewParms.isPortal ) { - qglDisable (GL_CLIP_PLANE0); - } - Mat4Copy(glState.projection, oldprojection); Mat4Copy(glState.modelview, oldmodelview); Mat4Identity(matrix); diff --git a/code/renderergl2/tr_glsl.c b/code/renderergl2/tr_glsl.c index b825c19e..4ed49370 100644 --- a/code/renderergl2/tr_glsl.c +++ b/code/renderergl2/tr_glsl.c @@ -146,10 +146,21 @@ static uniformInfo_t uniformsInfo[] = { "u_PrimaryLightRadius", GLSL_FLOAT }, { "u_CubeMapInfo", GLSL_VEC4 }, + + { "u_AlphaTest", GLSL_INT }, + + { "u_BoneMatrix", GLSL_MAT16_BONEMATRIX }, }; +typedef enum +{ + GLSL_PRINTLOG_PROGRAM_INFO, + GLSL_PRINTLOG_SHADER_INFO, + GLSL_PRINTLOG_SHADER_SOURCE +} +glslPrintLog_t; -static void GLSL_PrintInfoLog(GLhandleARB object, qboolean developerOnly) +static void GLSL_PrintLog(GLuint programOrShader, glslPrintLog_t type, qboolean developerOnly) { char *msg; static char msgPart[1024]; @@ -157,64 +168,73 @@ static void GLSL_PrintInfoLog(GLhandleARB object, qboolean developerOnly) int i; int printLevel = developerOnly ? PRINT_DEVELOPER : PRINT_ALL; - qglGetObjectParameterivARB(object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength); + switch (type) + { + case GLSL_PRINTLOG_PROGRAM_INFO: + ri.Printf(printLevel, "Program info log:\n"); + qglGetProgramiv(programOrShader, GL_INFO_LOG_LENGTH, &maxLength); + break; + + case GLSL_PRINTLOG_SHADER_INFO: + ri.Printf(printLevel, "Shader info log:\n"); + qglGetShaderiv(programOrShader, GL_INFO_LOG_LENGTH, &maxLength); + break; + + case GLSL_PRINTLOG_SHADER_SOURCE: + ri.Printf(printLevel, "Shader source:\n"); + qglGetShaderiv(programOrShader, GL_SHADER_SOURCE_LENGTH, &maxLength); + break; + } if (maxLength <= 0) { - ri.Printf(printLevel, "No compile log.\n"); + ri.Printf(printLevel, "None.\n"); return; } - ri.Printf(printLevel, "compile log:\n"); + if (maxLength < 1023) + msg = msgPart; + else + msg = ri.Malloc(maxLength); + + switch (type) + { + case GLSL_PRINTLOG_PROGRAM_INFO: + qglGetProgramInfoLog(programOrShader, maxLength, &maxLength, msg); + break; + + case GLSL_PRINTLOG_SHADER_INFO: + qglGetShaderInfoLog(programOrShader, maxLength, &maxLength, msg); + break; + + case GLSL_PRINTLOG_SHADER_SOURCE: + qglGetShaderSource(programOrShader, maxLength, &maxLength, msg); + break; + } if (maxLength < 1023) { - qglGetInfoLogARB(object, maxLength, &maxLength, msgPart); - msgPart[maxLength + 1] = '\0'; ri.Printf(printLevel, "%s\n", msgPart); } else { - msg = ri.Malloc(maxLength); - - qglGetInfoLogARB(object, maxLength, &maxLength, msg); - - for(i = 0; i < maxLength; i += 1024) + for(i = 0; i < maxLength; i += 1023) { Q_strncpyz(msgPart, msg + i, sizeof(msgPart)); - ri.Printf(printLevel, "%s\n", msgPart); + ri.Printf(printLevel, "%s", msgPart); } + ri.Printf(printLevel, "\n"); + ri.Free(msg); } + } -static void GLSL_PrintShaderSource(GLhandleARB object) -{ - char *msg; - static char msgPart[1024]; - int maxLength = 0; - int i; - - qglGetObjectParameterivARB(object, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &maxLength); - - msg = ri.Malloc(maxLength); - - qglGetShaderSourceARB(object, maxLength, &maxLength, msg); - - for(i = 0; i < maxLength; i += 1024) - { - Q_strncpyz(msgPart, msg + i, sizeof(msgPart)); - ri.Printf(PRINT_ALL, "%s\n", msgPart); - } - - ri.Free(msg); -} - -static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, char *dest, int size ) +static void GLSL_GetShaderHeader( GLenum shaderType, const GLchar *extra, char *dest, int size ) { float fbufWidthScale, fbufHeightScale; @@ -223,9 +243,12 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, cha // HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones if(glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 30)) { - Q_strcat(dest, size, "#version 130\n"); + if (glRefConfig.glslMajorVersion > 1 || (glRefConfig.glslMajorVersion == 1 && glRefConfig.glslMinorVersion >= 50)) + Q_strcat(dest, size, "#version 150\n"); + else + Q_strcat(dest, size, "#version 130\n"); - if(shaderType == GL_VERTEX_SHADER_ARB) + if(shaderType == GL_VERTEX_SHADER) { Q_strcat(dest, size, "#define attribute in\n"); Q_strcat(dest, size, "#define varying out\n"); @@ -236,11 +259,15 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, cha Q_strcat(dest, size, "out vec4 out_Color;\n"); Q_strcat(dest, size, "#define gl_FragColor out_Color\n"); + Q_strcat(dest, size, "#define texture2D texture\n"); + Q_strcat(dest, size, "#define textureCubeLod textureLod\n"); + Q_strcat(dest, size, "#define shadow2D texture\n"); } } else { Q_strcat(dest, size, "#version 120\n"); + Q_strcat(dest, size, "#define shadow2D(a,b) shadow2D(a,b).r \n"); } // HACK: add some macros to avoid extra uniforms and save speed and code maintenance @@ -306,17 +333,6 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, cha AGEN_LIGHTING_SPECULAR, AGEN_PORTAL)); - Q_strcat(dest, size, - va("#ifndef texenv_t\n" - "#define texenv_t\n" - "#define TEXENV_MODULATE %i\n" - "#define TEXENV_ADD %i\n" - "#define TEXENV_REPLACE %i\n" - "#endif\n", - GL_MODULATE, - GL_ADD, - GL_REPLACE)); - fbufWidthScale = 1.0f / ((float)glConfig.vidWidth); fbufHeightScale = 1.0f / ((float)glConfig.vidHeight); Q_strcat(dest, size, @@ -325,6 +341,20 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, cha if (r_pbr->integer) Q_strcat(dest, size, "#define USE_PBR\n"); + if (r_cubeMapping->integer) + { + int cubeMipSize = r_cubemapSize->integer; + int numRoughnessMips = 0; + + while (cubeMipSize) + { + cubeMipSize >>= 1; + numRoughnessMips++; + } + numRoughnessMips = MAX(1, numRoughnessMips - 2); + Q_strcat(dest, size, va("#define ROUGHNESS_MIPS float(%d)\n", numRoughnessMips)); + } + if (extra) { Q_strcat(dest, size, extra); @@ -335,39 +365,36 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, cha Q_strcat(dest, size, "#line 0\n"); } -static int GLSL_CompileGPUShader(GLhandleARB program, GLhandleARB *prevShader, const GLcharARB *buffer, int size, GLenum shaderType) +static int GLSL_CompileGPUShader(GLuint program, GLuint *prevShader, const GLchar *buffer, int size, GLenum shaderType) { GLint compiled; - GLhandleARB shader; + GLuint shader; - shader = qglCreateShaderObjectARB(shaderType); + shader = qglCreateShader(shaderType); - qglShaderSourceARB(shader, 1, (const GLcharARB **)&buffer, &size); + qglShaderSource(shader, 1, (const GLchar **)&buffer, &size); // compile shader - qglCompileShaderARB(shader); + qglCompileShader(shader); // check if shader compiled - qglGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled); + qglGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if(!compiled) { - GLSL_PrintShaderSource(shader); - GLSL_PrintInfoLog(shader, qfalse); + GLSL_PrintLog(shader, GLSL_PRINTLOG_SHADER_SOURCE, qfalse); + GLSL_PrintLog(shader, GLSL_PRINTLOG_SHADER_INFO, qfalse); ri.Error(ERR_DROP, "Couldn't compile shader"); return 0; } - //GLSL_PrintInfoLog(shader, qtrue); - //GLSL_PrintShaderSource(shader); - if (*prevShader) { - qglDetachObjectARB(program, *prevShader); - qglDeleteObjectARB(*prevShader); + qglDetachShader(program, *prevShader); + qglDeleteShader(*prevShader); } // attach shader to program - qglAttachObjectARB(program, shader); + qglAttachShader(program, shader); *prevShader = shader; @@ -378,12 +405,12 @@ static int GLSL_LoadGPUShaderText(const char *name, const char *fallback, GLenum shaderType, char *dest, int destSize) { char filename[MAX_QPATH]; - GLcharARB *buffer = NULL; - const GLcharARB *shaderText = NULL; + GLchar *buffer = NULL; + const GLchar *shaderText = NULL; int size; int result; - if(shaderType == GL_VERTEX_SHADER_ARB) + if(shaderType == GL_VERTEX_SHADER) { Com_sprintf(filename, sizeof(filename), "glsl/%s_vp.glsl", name); } @@ -437,49 +464,33 @@ static int GLSL_LoadGPUShaderText(const char *name, const char *fallback, return result; } -static void GLSL_LinkProgram(GLhandleARB program) +static void GLSL_LinkProgram(GLuint program) { GLint linked; - qglLinkProgramARB(program); + qglLinkProgram(program); - qglGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linked); + qglGetProgramiv(program, GL_LINK_STATUS, &linked); if(!linked) { - GLSL_PrintInfoLog(program, qfalse); - ri.Printf(PRINT_ALL, "\n"); + GLSL_PrintLog(program, GLSL_PRINTLOG_PROGRAM_INFO, qfalse); ri.Error(ERR_DROP, "shaders failed to link"); } } -static void GLSL_ValidateProgram(GLhandleARB program) -{ - GLint validated; - - qglValidateProgramARB(program); - - qglGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated); - if(!validated) - { - GLSL_PrintInfoLog(program, qfalse); - ri.Printf(PRINT_ALL, "\n"); - ri.Error(ERR_DROP, "shaders failed to validate"); - } -} - -static void GLSL_ShowProgramUniforms(GLhandleARB program) +static void GLSL_ShowProgramUniforms(GLuint program) { int i, count, size; GLenum type; char uniformName[1000]; // query the number of active uniforms - qglGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count); + qglGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count); // Loop over each of the active uniforms, and set their value for(i = 0; i < count; i++) { - qglGetActiveUniformARB(program, i, sizeof(uniformName), NULL, &size, &type, uniformName); + qglGetActiveUniform(program, i, sizeof(uniformName), NULL, &size, &type, uniformName); ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName); } @@ -496,64 +507,70 @@ static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int Q_strncpyz(program->name, name, sizeof(program->name)); - program->program = qglCreateProgramObjectARB(); + program->program = qglCreateProgram(); program->attribs = attribs; - if (!(GLSL_CompileGPUShader(program->program, &program->vertexShader, vpCode, strlen(vpCode), GL_VERTEX_SHADER_ARB))) + if (!(GLSL_CompileGPUShader(program->program, &program->vertexShader, vpCode, strlen(vpCode), GL_VERTEX_SHADER))) { - ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_VERTEX_SHADER_ARB\n", name); - qglDeleteObjectARB(program->program); + ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_VERTEX_SHADER\n", name); + qglDeleteProgram(program->program); return 0; } if(fpCode) { - if(!(GLSL_CompileGPUShader(program->program, &program->fragmentShader, fpCode, strlen(fpCode), GL_FRAGMENT_SHADER_ARB))) + if(!(GLSL_CompileGPUShader(program->program, &program->fragmentShader, fpCode, strlen(fpCode), GL_FRAGMENT_SHADER))) { - ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_FRAGMENT_SHADER_ARB\n", name); - qglDeleteObjectARB(program->program); + ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_FRAGMENT_SHADER\n", name); + qglDeleteProgram(program->program); return 0; } } if(attribs & ATTR_POSITION) - qglBindAttribLocationARB(program->program, ATTR_INDEX_POSITION, "attr_Position"); + qglBindAttribLocation(program->program, ATTR_INDEX_POSITION, "attr_Position"); if(attribs & ATTR_TEXCOORD) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD, "attr_TexCoord0"); + qglBindAttribLocation(program->program, ATTR_INDEX_TEXCOORD, "attr_TexCoord0"); if(attribs & ATTR_LIGHTCOORD) - qglBindAttribLocationARB(program->program, ATTR_INDEX_LIGHTCOORD, "attr_TexCoord1"); + qglBindAttribLocation(program->program, ATTR_INDEX_LIGHTCOORD, "attr_TexCoord1"); // if(attribs & ATTR_TEXCOORD2) -// qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD2, "attr_TexCoord2"); +// qglBindAttribLocation(program->program, ATTR_INDEX_TEXCOORD2, "attr_TexCoord2"); // if(attribs & ATTR_TEXCOORD3) -// qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD3, "attr_TexCoord3"); +// qglBindAttribLocation(program->program, ATTR_INDEX_TEXCOORD3, "attr_TexCoord3"); if(attribs & ATTR_TANGENT) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT, "attr_Tangent"); + qglBindAttribLocation(program->program, ATTR_INDEX_TANGENT, "attr_Tangent"); if(attribs & ATTR_NORMAL) - qglBindAttribLocationARB(program->program, ATTR_INDEX_NORMAL, "attr_Normal"); + qglBindAttribLocation(program->program, ATTR_INDEX_NORMAL, "attr_Normal"); if(attribs & ATTR_COLOR) - qglBindAttribLocationARB(program->program, ATTR_INDEX_COLOR, "attr_Color"); + qglBindAttribLocation(program->program, ATTR_INDEX_COLOR, "attr_Color"); if(attribs & ATTR_PAINTCOLOR) - qglBindAttribLocationARB(program->program, ATTR_INDEX_PAINTCOLOR, "attr_PaintColor"); + qglBindAttribLocation(program->program, ATTR_INDEX_PAINTCOLOR, "attr_PaintColor"); if(attribs & ATTR_LIGHTDIRECTION) - qglBindAttribLocationARB(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection"); + qglBindAttribLocation(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection"); + + if(attribs & ATTR_BONE_INDEXES) + qglBindAttribLocation(program->program, ATTR_INDEX_BONE_INDEXES, "attr_BoneIndexes"); + + if(attribs & ATTR_BONE_WEIGHTS) + qglBindAttribLocation(program->program, ATTR_INDEX_BONE_WEIGHTS, "attr_BoneWeights"); if(attribs & ATTR_POSITION2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_POSITION2, "attr_Position2"); + qglBindAttribLocation(program->program, ATTR_INDEX_POSITION2, "attr_Position2"); if(attribs & ATTR_NORMAL2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_NORMAL2, "attr_Normal2"); + qglBindAttribLocation(program->program, ATTR_INDEX_NORMAL2, "attr_Normal2"); if(attribs & ATTR_TANGENT2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT2, "attr_Tangent2"); + qglBindAttribLocation(program->program, ATTR_INDEX_TANGENT2, "attr_Tangent2"); GLSL_LinkProgram(program->program); @@ -561,7 +578,7 @@ static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int } static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, - int attribs, qboolean fragmentShader, const GLcharARB *extra, qboolean addHeader, + int attribs, qboolean fragmentShader, const GLchar *extra, qboolean addHeader, const char *fallback_vp, const char *fallback_fp) { char vpCode[32000]; @@ -573,7 +590,7 @@ static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, size = sizeof(vpCode); if (addHeader) { - GLSL_GetShaderHeader(GL_VERTEX_SHADER_ARB, extra, vpCode, size); + GLSL_GetShaderHeader(GL_VERTEX_SHADER, extra, vpCode, size); postHeader = &vpCode[strlen(vpCode)]; size -= strlen(vpCode); } @@ -582,7 +599,7 @@ static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, postHeader = &vpCode[0]; } - if (!GLSL_LoadGPUShaderText(name, fallback_vp, GL_VERTEX_SHADER_ARB, postHeader, size)) + if (!GLSL_LoadGPUShaderText(name, fallback_vp, GL_VERTEX_SHADER, postHeader, size)) { return 0; } @@ -592,7 +609,7 @@ static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, size = sizeof(fpCode); if (addHeader) { - GLSL_GetShaderHeader(GL_FRAGMENT_SHADER_ARB, extra, fpCode, size); + GLSL_GetShaderHeader(GL_FRAGMENT_SHADER, extra, fpCode, size); postHeader = &fpCode[strlen(fpCode)]; size -= strlen(fpCode); } @@ -601,7 +618,7 @@ static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, postHeader = &fpCode[0]; } - if (!GLSL_LoadGPUShaderText(name, fallback_fp, GL_FRAGMENT_SHADER_ARB, postHeader, size)) + if (!GLSL_LoadGPUShaderText(name, fallback_fp, GL_FRAGMENT_SHADER, postHeader, size)) { return 0; } @@ -621,7 +638,7 @@ void GLSL_InitUniforms(shaderProgram_t *program) size = 0; for (i = 0; i < UNIFORM_COUNT; i++) { - uniforms[i] = qglGetUniformLocationARB(program->program, uniformsInfo[i].name); + uniforms[i] = qglGetUniformLocation(program->program, uniformsInfo[i].name); if (uniforms[i] == -1) continue; @@ -651,6 +668,9 @@ void GLSL_InitUniforms(shaderProgram_t *program) case GLSL_MAT16: size += sizeof(vec_t) * 16; break; + case GLSL_MAT16_BONEMATRIX: + size += sizeof(vec_t) * 16 * glRefConfig.glslMaxAnimatedBones; + break; default: break; } @@ -661,7 +681,6 @@ void GLSL_InitUniforms(shaderProgram_t *program) void GLSL_FinishGPUShader(shaderProgram_t *program) { - GLSL_ValidateProgram(program->program); GLSL_ShowProgramUniforms(program->program); GL_CheckErrors(); } @@ -687,7 +706,7 @@ void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value) *compare = value; - qglProgramUniform1i(program->program, uniforms[uniformNum], value); + qglProgramUniform1iEXT(program->program, uniforms[uniformNum], value); } void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value) @@ -711,7 +730,7 @@ void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat valu *compare = value; - qglProgramUniform1f(program->program, uniforms[uniformNum], value); + qglProgramUniform1fEXT(program->program, uniforms[uniformNum], value); } void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v) @@ -736,7 +755,7 @@ void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t compare[0] = v[0]; compare[1] = v[1]; - qglProgramUniform2f(program->program, uniforms[uniformNum], v[0], v[1]); + qglProgramUniform2fEXT(program->program, uniforms[uniformNum], v[0], v[1]); } void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v) @@ -760,7 +779,7 @@ void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t VectorCopy(v, compare); - qglProgramUniform3f(program->program, uniforms[uniformNum], v[0], v[1], v[2]); + qglProgramUniform3fEXT(program->program, uniforms[uniformNum], v[0], v[1], v[2]); } void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v) @@ -784,7 +803,7 @@ void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t VectorCopy4(v, compare); - qglProgramUniform4f(program->program, uniforms[uniformNum], v[0], v[1], v[2], v[3]); + qglProgramUniform4fEXT(program->program, uniforms[uniformNum], v[0], v[1], v[2], v[3]); } void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v) @@ -808,7 +827,7 @@ void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_ VectorCopy5(v, compare); - qglProgramUniform1fv(program->program, uniforms[uniformNum], 5, v); + qglProgramUniform1fvEXT(program->program, uniforms[uniformNum], 5, v); } void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix) @@ -832,7 +851,39 @@ void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t Mat4Copy(matrix, compare); - qglProgramUniformMatrix4fv(program->program, uniforms[uniformNum], 1, GL_FALSE, matrix); + qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], 1, GL_FALSE, matrix); +} + +void GLSL_SetUniformMat4BoneMatrix(shaderProgram_t *program, int uniformNum, /*const*/ mat4_t *matrix, int numMatricies) +{ + GLint *uniforms = program->uniforms; + vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); + + if (uniforms[uniformNum] == -1) { + return; + } + + if (uniformsInfo[uniformNum].type != GLSL_MAT16_BONEMATRIX) + { + ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4BoneMatrix: wrong type for uniform %i in program %s\n", uniformNum, program->name); + return; + } + + if (numMatricies > glRefConfig.glslMaxAnimatedBones) + { + ri.Printf( PRINT_WARNING, "GLSL_SetUniformMat4BoneMatrix: too many matricies (%d/%d) for uniform %i in program %s\n", + numMatricies, glRefConfig.glslMaxAnimatedBones, uniformNum, program->name); + return; + } + + if (!memcmp(matrix, compare, numMatricies * sizeof(mat4_t))) + { + return; + } + + Com_Memcpy(compare, matrix, numMatricies * sizeof(mat4_t)); + + qglProgramUniformMatrix4fvEXT(program->program, uniforms[uniformNum], numMatricies, GL_FALSE, &matrix[0][0]); } void GLSL_DeleteGPUShader(shaderProgram_t *program) @@ -841,17 +892,17 @@ void GLSL_DeleteGPUShader(shaderProgram_t *program) { if (program->vertexShader) { - qglDetachObjectARB(program->program, program->vertexShader); - qglDeleteObjectARB(program->vertexShader); + qglDetachShader(program->program, program->vertexShader); + qglDeleteShader(program->vertexShader); } if (program->fragmentShader) { - qglDetachObjectARB(program->program, program->fragmentShader); - qglDeleteObjectARB(program->fragmentShader); + qglDetachShader(program->program, program->fragmentShader); + qglDeleteShader(program->fragmentShader); } - qglDeleteObjectARB(program->program); + qglDeleteProgram(program->program); if (program->uniformBuffer) { @@ -878,6 +929,12 @@ void GLSL_InitGPUShaders(void) for (i = 0; i < GENERICDEF_COUNT; i++) { + if ((i & GENERICDEF_USE_VERTEX_ANIMATION) && (i & GENERICDEF_USE_BONE_ANIMATION)) + continue; + + if ((i & GENERICDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones) + continue; + attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR; extradefines[0] = '\0'; @@ -895,6 +952,11 @@ void GLSL_InitGPUShaders(void) Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n"); attribs |= ATTR_POSITION2 | ATTR_NORMAL2; } + else if (i & GENERICDEF_USE_BONE_ANIMATION) + { + Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones)); + attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS; + } if (i & GENERICDEF_USE_FOG) Q_strcat(extradefines, 1024, "#define USE_FOG\n"); @@ -920,7 +982,7 @@ void GLSL_InitGPUShaders(void) attribs = ATTR_POSITION | ATTR_TEXCOORD; - if (!GLSL_InitGPUShader(&tr.textureColorShader, "texturecolor", attribs, qtrue, NULL, qfalse, fallbackShader_texturecolor_vp, fallbackShader_texturecolor_fp)) + if (!GLSL_InitGPUShader(&tr.textureColorShader, "texturecolor", attribs, qtrue, extradefines, qtrue, fallbackShader_texturecolor_vp, fallbackShader_texturecolor_fp)) { ri.Error(ERR_FATAL, "Could not load texturecolor shader!"); } @@ -935,14 +997,28 @@ void GLSL_InitGPUShaders(void) for (i = 0; i < FOGDEF_COUNT; i++) { - attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; + if ((i & FOGDEF_USE_VERTEX_ANIMATION) && (i & FOGDEF_USE_BONE_ANIMATION)) + continue; + + if ((i & FOGDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones) + continue; + + attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD; extradefines[0] = '\0'; if (i & FOGDEF_USE_DEFORM_VERTEXES) Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n"); if (i & FOGDEF_USE_VERTEX_ANIMATION) + { Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n"); + attribs |= ATTR_POSITION2 | ATTR_NORMAL2; + } + else if (i & FOGDEF_USE_BONE_ANIMATION) + { + Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones)); + attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS; + } if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp)) { @@ -990,10 +1066,13 @@ void GLSL_InitGPUShaders(void) if ((i & LIGHTDEF_USE_PARALLAXMAP) && !r_parallaxMapping->integer) continue; - if (!lightType && (i & LIGHTDEF_USE_PARALLAXMAP)) + if ((i & LIGHTDEF_USE_SHADOWMAP) && (!lightType || !r_sunlightMode->integer)) continue; - if (!lightType && (i & LIGHTDEF_USE_SHADOWMAP)) + if ((i & LIGHTDEF_ENTITY_VERTEX_ANIMATION) && (i & LIGHTDEF_ENTITY_BONE_ANIMATION)) + continue; + + if ((i & LIGHTDEF_ENTITY_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones) continue; attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL; @@ -1006,9 +1085,6 @@ void GLSL_InitGPUShaders(void) if (glRefConfig.swizzleNormalmap) Q_strcat(extradefines, 1024, "#define SWIZZLE_NORMALMAP\n"); - if (r_hdr->integer && !glRefConfig.floatLightmap) - Q_strcat(extradefines, 1024, "#define RGBM_LIGHTMAP\n"); - if (lightType) { Q_strcat(extradefines, 1024, "#define USE_LIGHT\n"); @@ -1039,12 +1115,9 @@ void GLSL_InitGPUShaders(void) { Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n"); -#ifdef USE_VERT_TANGENT_SPACE - Q_strcat(extradefines, 1024, "#define USE_VERT_TANGENT_SPACE\n"); attribs |= ATTR_TANGENT; -#endif - if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer) + if ((i & LIGHTDEF_USE_PARALLAXMAP) && !(i & LIGHTDEF_ENTITY_VERTEX_ANIMATION) && !(i & LIGHTDEF_ENTITY_BONE_ANIMATION) && r_parallaxMapping->integer) { Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n"); if (r_parallaxMapping->integer > 1) @@ -1056,7 +1129,15 @@ void GLSL_InitGPUShaders(void) Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n"); if (r_cubeMapping->integer) + { Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n"); + if (r_cubeMapping->integer == 2) + Q_strcat(extradefines, 1024, "#define USE_BOX_CUBEMAP_PARALLAX\n"); + } + else if (r_deluxeSpecular->value > 0.000001f) + { + Q_strcat(extradefines, 1024, va("#define r_deluxeSpecular %f\n", r_deluxeSpecular->value)); + } switch (r_glossType->integer) { @@ -1092,17 +1173,21 @@ void GLSL_InitGPUShaders(void) Q_strcat(extradefines, 1024, "#define USE_TCMOD\n"); } - if (i & LIGHTDEF_ENTITY) + if (i & LIGHTDEF_ENTITY_VERTEX_ANIMATION) { Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n"); attribs |= ATTR_POSITION2 | ATTR_NORMAL2; -#ifdef USE_VERT_TANGENT_SPACE if (r_normalMapping->integer) { attribs |= ATTR_TANGENT2; } -#endif + } + else if (i & LIGHTDEF_ENTITY_BONE_ANIMATION) + { + Q_strcat(extradefines, 1024, "#define USE_MODELMATRIX\n"); + Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones)); + attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS; } if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp)) @@ -1125,20 +1210,41 @@ void GLSL_InitGPUShaders(void) numLightShaders++; } - attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; - - extradefines[0] = '\0'; - - if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp)) + for (i = 0; i < SHADOWMAPDEF_COUNT; i++) { - ri.Error(ERR_FATAL, "Could not load shadowfill shader!"); + if ((i & SHADOWMAPDEF_USE_VERTEX_ANIMATION) && (i & SHADOWMAPDEF_USE_BONE_ANIMATION)) + continue; + + if ((i & SHADOWMAPDEF_USE_BONE_ANIMATION) && !glRefConfig.glslMaxAnimatedBones) + continue; + + attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD; + + extradefines[0] = '\0'; + + if (i & SHADOWMAPDEF_USE_VERTEX_ANIMATION) + { + Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n"); + attribs |= ATTR_POSITION2 | ATTR_NORMAL2; + } + + if (i & SHADOWMAPDEF_USE_BONE_ANIMATION) + { + Q_strcat(extradefines, 1024, va("#define USE_BONE_ANIMATION\n#define MAX_GLSL_BONES %d\n", glRefConfig.glslMaxAnimatedBones)); + attribs |= ATTR_BONE_INDEXES | ATTR_BONE_WEIGHTS; + } + + if (!GLSL_InitGPUShader(&tr.shadowmapShader[i], "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp)) + { + ri.Error(ERR_FATAL, "Could not load shadowfill shader!"); + } + + GLSL_InitUniforms(&tr.shadowmapShader[i]); + GLSL_FinishGPUShader(&tr.shadowmapShader[i]); + + numEtcShaders++; } - GLSL_InitUniforms(&tr.shadowmapShader); - GLSL_FinishGPUShader(&tr.shadowmapShader); - - numEtcShaders++; - attribs = ATTR_POSITION | ATTR_NORMAL; extradefines[0] = '\0'; @@ -1284,7 +1390,7 @@ void GLSL_InitGPUShaders(void) numEtcShaders++; - for (i = 0; i < 2; i++) + for (i = 0; i < 4; i++) { attribs = ATTR_POSITION | ATTR_TEXCOORD; extradefines[0] = '\0'; @@ -1294,6 +1400,9 @@ void GLSL_InitGPUShaders(void) else Q_strcat(extradefines, 1024, "#define USE_HORIZONTAL_BLUR\n"); + if (!(i & 2)) + Q_strcat(extradefines, 1024, "#define USE_DEPTH\n"); + if (!GLSL_InitGPUShader(&tr.depthBlurShader[i], "depthBlur", attribs, qtrue, extradefines, qtrue, fallbackShader_depthblur_vp, fallbackShader_depthblur_fp)) { @@ -1343,7 +1452,7 @@ void GLSL_ShutdownGPUShaders(void) ri.Printf(PRINT_ALL, "------- GLSL_ShutdownGPUShaders -------\n"); for (i = 0; i < ATTR_INDEX_COUNT; i++) - qglDisableVertexAttribArrayARB(i); + qglDisableVertexAttribArray(i); GL_BindNullProgram(); @@ -1361,7 +1470,9 @@ void GLSL_ShutdownGPUShaders(void) for ( i = 0; i < LIGHTDEF_COUNT; i++) GLSL_DeleteGPUShader(&tr.lightallShader[i]); - GLSL_DeleteGPUShader(&tr.shadowmapShader); + for ( i = 0; i < SHADOWMAPDEF_COUNT; i++) + GLSL_DeleteGPUShader(&tr.shadowmapShader[i]); + GLSL_DeleteGPUShader(&tr.pshadowShader); GLSL_DeleteGPUShader(&tr.down4xShader); GLSL_DeleteGPUShader(&tr.bokehShader); @@ -1373,7 +1484,7 @@ void GLSL_ShutdownGPUShaders(void) GLSL_DeleteGPUShader(&tr.shadowmaskShader); GLSL_DeleteGPUShader(&tr.ssaoShader); - for ( i = 0; i < 2; i++) + for ( i = 0; i < 4; i++) GLSL_DeleteGPUShader(&tr.depthBlurShader[i]); } @@ -1389,7 +1500,7 @@ void GLSL_BindProgram(shaderProgram_t * program) GLimp_LogComment(va("--- GLSL_BindProgram( %s ) ---\n", name)); } - if (GL_UseProgramObject(programObject)) + if (GL_UseProgram(programObject)) backEnd.pc.c_glslShaderBinds++; } @@ -1437,6 +1548,10 @@ shaderProgram_t *GLSL_GetGenericShaderProgram(int stage) { shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; } + else if (glState.boneAnimation) + { + shaderAttribs |= GENERICDEF_USE_BONE_ANIMATION; + } if (pStage->bundle[0].numTexMods) { diff --git a/code/renderergl2/tr_image.c b/code/renderergl2/tr_image.c index 7f8f2460..d4cd7b11 100644 --- a/code/renderergl2/tr_image.c +++ b/code/renderergl2/tr_image.c @@ -116,8 +116,8 @@ void GL_TextureMode( const char *string ) { for ( i = 0 ; i < tr.numImages ; i++ ) { glt = tr.images[ i ]; if ( glt->flags & IMGFLAG_MIPMAP && !(glt->flags & IMGFLAG_CUBEMAP)) { - qglTextureParameterf(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTextureParameterf(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); + qglTextureParameterfEXT(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); + qglTextureParameterfEXT(glt->texnum, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); } } } @@ -150,12 +150,12 @@ void R_ImageList_f( void ) { int i; int estTotalSize = 0; - ri.Printf(PRINT_ALL, "\n -w-- -h-- type -size- --name-------\n"); + ri.Printf(PRINT_ALL, "\n -w-- -h-- -type-- -size- --name-------\n"); for ( i = 0 ; i < tr.numImages ; i++ ) { image_t *image = tr.images[i]; - char *format = "???? "; + char *format = "???? "; char *sizeSuffix; int estSize; int displaySize; @@ -165,95 +165,119 @@ void R_ImageList_f( void ) { switch(image->internalFormat) { case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - format = "sDXT1"; + format = "sDXT1 "; // 64 bits per 16 pixels, so 4 bits per pixel estSize /= 2; break; case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - format = "sDXT5"; + format = "sDXT5 "; // 128 bits per 16 pixels, so 1 byte per pixel break; case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: - format = "sBPTC"; + format = "sBPTC "; // 128 bits per 16 pixels, so 1 byte per pixel break; case GL_COMPRESSED_RG_RGTC2: - format = "RGTC2"; + format = "RGTC2 "; // 128 bits per 16 pixels, so 1 byte per pixel break; case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - format = "DXT1 "; + format = "DXT1 "; // 64 bits per 16 pixels, so 4 bits per pixel estSize /= 2; break; case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - format = "DXT1a"; + format = "DXT1a "; // 64 bits per 16 pixels, so 4 bits per pixel estSize /= 2; break; case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - format = "DXT5 "; + format = "DXT5 "; // 128 bits per 16 pixels, so 1 byte per pixel break; case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: - format = "BPTC "; + format = "BPTC "; // 128 bits per 16 pixels, so 1 byte per pixel break; case GL_RGB4_S3TC: - format = "S3TC "; + format = "S3TC "; // same as DXT1? estSize /= 2; break; + case GL_RGBA16F: + format = "RGBA16F"; + // 8 bytes per pixel + estSize *= 8; + break; + case GL_RGBA16: + format = "RGBA16 "; + // 8 bytes per pixel + estSize *= 8; + break; case GL_RGBA4: case GL_RGBA8: case GL_RGBA: - format = "RGBA "; + format = "RGBA "; // 4 bytes per pixel estSize *= 4; break; case GL_LUMINANCE8: - case GL_LUMINANCE16: case GL_LUMINANCE: - format = "L "; + format = "L "; // 1 byte per pixel? break; case GL_RGB5: case GL_RGB8: case GL_RGB: - format = "RGB "; + format = "RGB "; // 3 bytes per pixel? estSize *= 3; break; case GL_LUMINANCE8_ALPHA8: - case GL_LUMINANCE16_ALPHA16: case GL_LUMINANCE_ALPHA: - format = "LA "; + format = "LA "; // 2 bytes per pixel? estSize *= 2; break; case GL_SRGB_EXT: case GL_SRGB8_EXT: - format = "sRGB "; + format = "sRGB "; // 3 bytes per pixel? estSize *= 3; break; case GL_SRGB_ALPHA_EXT: case GL_SRGB8_ALPHA8_EXT: - format = "sRGBA"; + format = "sRGBA "; // 4 bytes per pixel? estSize *= 4; break; case GL_SLUMINANCE_EXT: case GL_SLUMINANCE8_EXT: - format = "sL "; + format = "sL "; // 1 byte per pixel? break; case GL_SLUMINANCE_ALPHA_EXT: case GL_SLUMINANCE8_ALPHA8_EXT: - format = "sLA "; + format = "sLA "; // 2 byte per pixel? estSize *= 2; break; + case GL_DEPTH_COMPONENT16: + format = "Depth16"; + // 2 bytes per pixel + estSize *= 2; + break; + case GL_DEPTH_COMPONENT24: + format = "Depth24"; + // 3 bytes per pixel + estSize *= 3; + break; + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT32: + format = "Depth32"; + // 4 bytes per pixel + estSize *= 4; + break; } // mipmap adds about 50% @@ -476,11 +500,11 @@ static void RGBAtoNormal(const byte *in, byte *out, int width, int height, qbool if (clampToEdge) { - src_x = CLAMP(src_x, 0, height - 1); + src_x = CLAMP(src_x, 0, width - 1); } else { - src_x = (src_x + height) % height; + src_x = (src_x + width) % width; } s[i++] = *(out + (src_y * width + src_x) * 4 + 3); @@ -1461,12 +1485,12 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou qboolean picmip = flags & IMGFLAG_PICMIP; qboolean mipmap = flags & IMGFLAG_MIPMAP; qboolean clampToEdge = flags & IMGFLAG_CLAMPTOEDGE; - qboolean notScaled; + qboolean scaled; // // convert to exact power of 2 sizes // - if (glRefConfig.textureNonPowerOfTwo && !mipmap) + if (!mipmap) { scaled_width = width; scaled_height = height; @@ -1572,7 +1596,7 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou scaled_width = MAX(1, scaled_width); scaled_height = MAX(1, scaled_height); - notScaled = (width == scaled_width) && (height == scaled_height); + scaled = (width != scaled_width) || (height != scaled_height); // // rescale texture to new size using existing mipmap functions @@ -1594,7 +1618,7 @@ static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inou *inout_width = width; *inout_height = height; - return notScaled; + return scaled; } @@ -1628,7 +1652,7 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picForm if(normalmap) { - if ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels)) + if ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels) && r_parallaxMapping->integer) { if (!forceNoCompression && glRefConfig.textureCompression & TCR_BPTC) { @@ -1698,10 +1722,8 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picForm { if(r_greyscale->integer) { - if(r_texturebits->integer == 16) + if(r_texturebits->integer == 16 || r_texturebits->integer == 32) internalFormat = GL_LUMINANCE8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16; else internalFormat = GL_LUMINANCE; } @@ -1737,10 +1759,8 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picForm { if(r_greyscale->integer) { - if(r_texturebits->integer == 16) + if(r_texturebits->integer == 16 || r_texturebits->integer == 32) internalFormat = GL_LUMINANCE8_ALPHA8; - else if(r_texturebits->integer == 32) - internalFormat = GL_LUMINANCE16_ALPHA16; else internalFormat = GL_LUMINANCE_ALPHA; } @@ -1818,9 +1838,9 @@ static void CompressMonoBlock(byte outdata[8], const byte indata[16]) } } -static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width, int height, int mip) +static void RawImage_UploadToRgtc2Texture(GLuint texture, int miplevel, int x, int y, int width, int height, byte *data) { - int wBlocks, hBlocks, y, x, size; + int wBlocks, hBlocks, iy, ix, size; byte *compressedData, *p; wBlocks = (width + 3) / 4; @@ -1828,16 +1848,16 @@ static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width, size = wBlocks * hBlocks * 16; p = compressedData = ri.Hunk_AllocateTempMemory(size); - for (y = 0; y < height; y += 4) + for (iy = 0; iy < height; iy += 4) { - int oh = MIN(4, height - y); + int oh = MIN(4, height - iy); - for (x = 0; x < width; x += 4) + for (ix = 0; ix < width; ix += 4) { byte workingData[16]; int component; - int ow = MIN(4, width - x); + int ow = MIN(4, width - ix); for (component = 0; component < 2; component++) { @@ -1845,7 +1865,7 @@ static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width, for (oy = 0; oy < oh; oy++) for (ox = 0; ox < ow; ox++) - workingData[oy * 4 + ox] = data[((y + oy) * width + x + ox) * 4 + component]; + workingData[oy * 4 + ox] = data[((iy + oy) * width + ix + ox) * 4 + component]; // dupe data to fill for (oy = 0; oy < 4; oy++) @@ -1858,7 +1878,8 @@ static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width, } } - qglCompressedTextureImage2D(texture, GL_TEXTURE_2D, mip, GL_COMPRESSED_RG_RGTC2, width, height, 0, size, compressedData); + // FIXME: Won't work for x/y that aren't multiples of 4. + qglCompressedTextureSubImage2DEXT(texture, GL_TEXTURE_2D, miplevel, x, y, width, height, GL_COMPRESSED_RG_RGTC2, size, compressedData); ri.Hunk_FreeTempMemory(compressedData); } @@ -1894,6 +1915,9 @@ static int CalculateMipSize(int width, int height, GLenum picFormat) case GL_SRGB8_ALPHA8_EXT: return numPixels * 4; + case GL_RGBA16: + return numPixels * 8; + default: ri.Printf(PRINT_ALL, "Unsupported texture format %08x\n", picFormat); return 0; @@ -1903,64 +1927,33 @@ static int CalculateMipSize(int width, int height, GLenum picFormat) } -static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int width, int height, GLenum target, GLenum picFormat, int numMips, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture ) +static GLenum PixelDataFormatFromInternalFormat(GLenum internalFormat) { - int dataFormat, dataType; - qboolean rgtc = (internalFormat == GL_COMPRESSED_RG_RGTC2); - qboolean compressed = (!(picFormat == GL_RGBA8) || (picFormat == GL_SRGB8_ALPHA8_EXT)); - qboolean mipmap = !!(flags & IMGFLAG_MIPMAP); - qboolean picmip = !!(flags & IMGFLAG_PICMIP); - int size, miplevel; - qboolean lastMip = qfalse; - switch (internalFormat) { case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16_ARB: case GL_DEPTH_COMPONENT24_ARB: case GL_DEPTH_COMPONENT32_ARB: - dataFormat = GL_DEPTH_COMPONENT; - dataType = GL_UNSIGNED_BYTE; - break; - case GL_RGBA16F_ARB: - dataFormat = GL_RGBA; - dataType = GL_HALF_FLOAT_ARB; - break; + return GL_DEPTH_COMPONENT; default: - dataFormat = GL_RGBA; - dataType = GL_UNSIGNED_BYTE; + return GL_RGBA; break; } +} - if (!data) - { - miplevel = 0; - do - { - lastMip = (width == 1 && height == 1) || !mipmap; - qglTextureImage2D(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, NULL); +static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int width, int height, GLenum target, GLenum picFormat, int numMips, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture ) +{ + GLenum dataFormat, dataType; + qboolean rgtc = internalFormat == GL_COMPRESSED_RG_RGTC2; + qboolean rgba8 = picFormat == GL_RGBA8 || picFormat == GL_SRGB8_ALPHA8_EXT; + qboolean rgba = rgba8 || picFormat == GL_RGBA16; + qboolean mipmap = !!(flags & IMGFLAG_MIPMAP); + int size, miplevel; + qboolean lastMip = qfalse; - width = MAX(1, width >> 1); - height = MAX(1, height >> 1); - miplevel++; - } - while (!lastMip); - - return; - } - - if (compressed && picmip) - { - for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--) - { - size = CalculateMipSize(width, height, picFormat); - x >>= 1; - y >>= 1; - width = MAX(1, width >> 1); - height = MAX(1, height >> 1); - data += size; - } - } + dataFormat = PixelDataFormatFromInternalFormat(internalFormat); + dataType = picFormat == GL_RGBA16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; miplevel = 0; do @@ -1968,26 +1961,29 @@ static void RawImage_UploadTexture(GLuint texture, byte *data, int x, int y, int lastMip = (width == 1 && height == 1) || !mipmap; size = CalculateMipSize(width, height, picFormat); - if (compressed) + if (!rgba) { - if (subtexture) - qglCompressedTextureSubImage2D(texture, target, miplevel, x, y, width, height, picFormat, size, data); - else - qglCompressedTextureImage2D(texture, target, miplevel, picFormat, width, height, 0, size, data); + qglCompressedTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, picFormat, size, data); } else { - if (miplevel != 0 && r_colorMipLevels->integer) + if (rgba8 && miplevel != 0 && r_colorMipLevels->integer) R_BlendOverTexture((byte *)data, width * height, mipBlendColors[miplevel]); - if (rgtc) - RawImage_UploadToRgtc2Texture(texture, data, width, height, miplevel); - else if (subtexture) - qglTextureSubImage2D(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data); + if (rgba8 && rgtc) + RawImage_UploadToRgtc2Texture(texture, miplevel, x, y, width, height, data); else - qglTextureImage2D(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data); + qglTextureSubImage2DEXT(texture, target, miplevel, x, y, width, height, dataFormat, dataType, data); + } - if (!lastMip && numMips < 2) + if (!lastMip && numMips < 2) + { + if (glRefConfig.framebufferObject) + { + qglGenerateTextureMipmapEXT(texture, target); + break; + } + else if (rgba8) { if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT) R_MipMapNormalHeight(data, data, width, height, glRefConfig.swizzleNormalmap); @@ -2018,135 +2014,76 @@ Upload32 =============== */ -static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image) +static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image, qboolean scaled) { - byte *resampledBuffer = NULL; int i, c; byte *scan; imgType_t type = image->type; imgFlags_t flags = image->flags; GLenum internalFormat = image->internalFormat; - qboolean subtexture = (x != 0) || (y != 0) || (width != image->width) || (height != image->height); - qboolean notScaled = qtrue; - qboolean compressed = (picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT); - qboolean mipmap = !!(flags & IMGFLAG_MIPMAP) && (!compressed || numMips > 1); + qboolean rgba8 = picFormat == GL_RGBA8 || picFormat == GL_SRGB8_ALPHA8_EXT; + qboolean mipmap = !!(flags & IMGFLAG_MIPMAP) && (rgba8 || numMips > 1); qboolean cubemap = !!(flags & IMGFLAG_CUBEMAP); - GLenum uploadTarget = cubemap ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : GL_TEXTURE_2D; - GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; - int depth = cubemap ? 6 : 1; - if (!data) + // These operations cannot be performed on non-rgba8 images. + if (rgba8 && !cubemap) { - RawImage_ScaleToPower2(NULL, &width, &height, type, flags, NULL); - for (i = 0; i < depth; i++) - RawImage_UploadTexture(image->texnum, NULL, 0, 0, width, height, uploadTarget + i, GL_RGBA8, 0, internalFormat, type, flags, qfalse); - goto done; - } - else if (!subtexture) - { - if (compressed || cubemap) + c = width*height; + scan = data; + + if (type == IMGTYPE_COLORALPHA) { - for (i = 0; i < depth; i++) + if( r_greyscale->integer ) { - int w2 = width, h2 = height; - RawImage_UploadTexture(image->texnum, data, 0, 0, width, height, uploadTarget + i, picFormat, numMips, internalFormat, type, flags, qfalse); - for (c = numMips; c; c--) + for ( i = 0; i < c; i++ ) { - data += CalculateMipSize(w2, h2, picFormat); - w2 = MAX(1, w2 >> 1); - h2 = MAX(1, h2 >> 1); + byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); + scan[i*4] = luma; + scan[i*4 + 1] = luma; + scan[i*4 + 2] = luma; } } - goto done; + else if( r_greyscale->value ) + { + for ( i = 0; i < c; i++ ) + { + float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); + scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value); + scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value); + scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value); + } + } + + // This corresponds to what the OpenGL1 renderer does. + if (!(flags & IMGFLAG_NOLIGHTSCALE) && (scaled || mipmap)) + R_LightScaleTexture(data, width, height, !mipmap); } - notScaled = RawImage_ScaleToPower2(&data, &width, &height, type, flags, &resampledBuffer); + + if (glRefConfig.swizzleNormalmap && (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)) + RawImage_SwizzleRA(data, width, height); } - c = width*height; - scan = data; - - if( r_greyscale->integer ) + if (cubemap) { - for ( i = 0; i < c; i++ ) + for (i = 0; i < 6; i++) { - byte luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = luma; - scan[i*4 + 1] = luma; - scan[i*4 + 2] = luma; + int w2 = width, h2 = height; + RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, picFormat, numMips, internalFormat, type, flags, qfalse); + for (c = numMips; c; c--) + { + data += CalculateMipSize(w2, h2, picFormat); + w2 = MAX(1, w2 >> 1); + h2 = MAX(1, h2 >> 1); + } } } - else if( r_greyscale->value ) - { - for ( i = 0; i < c; i++ ) - { - float luma = LUMA(scan[i*4], scan[i*4 + 1], scan[i*4 + 2]); - scan[i*4] = LERP(scan[i*4], luma, r_greyscale->value); - scan[i*4 + 1] = LERP(scan[i*4 + 1], luma, r_greyscale->value); - scan[i*4 + 2] = LERP(scan[i*4 + 2], luma, r_greyscale->value); - } - } - - if (glRefConfig.swizzleNormalmap && (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)) - RawImage_SwizzleRA(data, width, height); - - // This corresponds to what the OpenGL1 renderer does - if (!(flags & IMGFLAG_NOLIGHTSCALE) && (!notScaled || mipmap)) - R_LightScaleTexture(data, width, height, !mipmap); - - if (subtexture) - { - // FIXME: Incorrect if original texture was not a power of 2 texture or picmipped - RawImage_UploadTexture(image->texnum, data, x, y, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qtrue); - GL_CheckErrors(); - return; - } - - RawImage_UploadTexture(image->texnum, data, 0, 0, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qfalse); - -done: - - image->uploadWidth = width; - image->uploadHeight = height; - - if (mipmap) - { - if (textureFilterAnisotropic && !cubemap) - qglTextureParameteri(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (GLint)Com_Clamp(1, maxAnisotropy, r_ext_max_anisotropy->integer)); - - qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, gl_filter_min); - qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, gl_filter_max); - } else { - if (textureFilterAnisotropic && !cubemap) - qglTextureParameteri(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); - - qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - // Fix for sampling depth buffer on old nVidia cards - // from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844 - switch(internalFormat) - { - case GL_DEPTH_COMPONENT: - case GL_DEPTH_COMPONENT16_ARB: - case GL_DEPTH_COMPONENT24_ARB: - case GL_DEPTH_COMPONENT32_ARB: - qglTextureParameterf(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); - qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - break; - default: - break; + RawImage_UploadTexture(image->texnum, data, x, y, width, height, GL_TEXTURE_2D, picFormat, numMips, internalFormat, type, flags, qfalse); } GL_CheckErrors(); - - if ( resampledBuffer != NULL ) - ri.Hunk_FreeTempMemory( resampledBuffer ); } @@ -2158,10 +2095,18 @@ This is the only way any image_t are created ================ */ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLenum picFormat, int numMips, imgType_t type, imgFlags_t flags, int internalFormat ) { - image_t *image; - qboolean isLightmap = qfalse; - long hash; - int glWrapClampMode; + byte *resampledBuffer = NULL; + image_t *image; + qboolean isLightmap = qfalse, scaled = qfalse; + long hash; + int glWrapClampMode, mipWidth, mipHeight, miplevel; + qboolean rgba8 = picFormat == GL_RGBA8 || picFormat == GL_SRGB8_ALPHA8_EXT; + qboolean mipmap = !!(flags & IMGFLAG_MIPMAP); + qboolean cubemap = !!(flags & IMGFLAG_CUBEMAP); + qboolean picmip = !!(flags & IMGFLAG_PICMIP); + qboolean lastMip; + GLenum textureTarget = cubemap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + GLenum dataFormat; if (strlen(name) >= MAX_QPATH ) { ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name); @@ -2175,7 +2120,7 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe } image = tr.images[tr.numImages] = ri.Hunk_Alloc( sizeof( image_t ), h_low ); - image->texnum = 1024 + tr.numImages; + qglGenTextures(1, &image->texnum); tr.numImages++; image->type = type; @@ -2194,20 +2139,91 @@ image_t *R_CreateImage2( const char *name, byte *pic, int width, int height, GLe internalFormat = RawImage_GetFormat(pic, width * height, picFormat, isLightmap, image->type, image->flags); image->internalFormat = internalFormat; - - Upload32(pic, 0, 0, image->width, image->height, picFormat, numMips, image); - if (image->flags & IMGFLAG_CUBEMAP) + // Possibly scale image before uploading. + // if not rgba8 and uploading an image, skip picmips. + if (!cubemap) { - qglTextureParameterf(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, glWrapClampMode); - qglTextureParameterf(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, glWrapClampMode); - qglTextureParameteri(image->texnum, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, glWrapClampMode); + if (rgba8) + scaled = RawImage_ScaleToPower2(&pic, &width, &height, type, flags, &resampledBuffer); + else if (pic && picmip) + { + for (miplevel = r_picmip->integer; miplevel > 0 && numMips > 1; miplevel--, numMips--) + { + int size = CalculateMipSize(width, height, picFormat); + width = MAX(1, width >> 1); + height = MAX(1, height >> 1); + pic += size; + } + } } - else + + image->uploadWidth = width; + image->uploadHeight = height; + + // Allocate texture storage so we don't have to worry about it later. + dataFormat = PixelDataFormatFromInternalFormat(internalFormat); + mipWidth = width; + mipHeight = height; + miplevel = 0; + do { - qglTextureParameterf(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode); - qglTextureParameterf(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode); + lastMip = !mipmap || (mipWidth == 1 && mipHeight == 1); + if (cubemap) + { + int i; + + for (i = 0; i < 6; i++) + qglTextureImage2DEXT(image->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL); + } + else + { + qglTextureImage2DEXT(image->texnum, GL_TEXTURE_2D, miplevel, internalFormat, mipWidth, mipHeight, 0, dataFormat, GL_UNSIGNED_BYTE, NULL); + } + + mipWidth = MAX(1, mipWidth >> 1); + mipHeight = MAX(1, mipHeight >> 1); + miplevel++; } + while (!lastMip); + + // Upload data. + if (pic) + Upload32(pic, 0, 0, width, height, picFormat, numMips, image, scaled); + + if (resampledBuffer != NULL) + ri.Hunk_FreeTempMemory(resampledBuffer); + + // Set all necessary texture parameters. + qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_S, glWrapClampMode); + qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_T, glWrapClampMode); + + if (cubemap) + qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_WRAP_R, glWrapClampMode); + + if (textureFilterAnisotropic && !cubemap) + qglTextureParameteriEXT(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, + mipmap ? (GLint)Com_Clamp(1, maxAnisotropy, r_ext_max_anisotropy->integer) : 1); + + switch(internalFormat) + { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16_ARB: + case GL_DEPTH_COMPONENT24_ARB: + case GL_DEPTH_COMPONENT32_ARB: + // Fix for sampling depth buffer on old nVidia cards. + // from http://www.idevgames.com/forums/thread-4141-post-34844.html#pid34844 + qglTextureParameterfEXT(image->texnum, textureTarget, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); + qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + default: + qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, mipmap ? gl_filter_min : GL_LINEAR); + qglTextureParameterfEXT(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, mipmap ? gl_filter_max : GL_LINEAR); + break; + } + + GL_CheckErrors(); hash = generateHashValue(name); image->next = hashTable[hash]; @@ -2230,9 +2246,9 @@ image_t *R_CreateImage(const char *name, byte *pic, int width, int height, imgTy } -void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height ) +void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height, GLenum picFormat ) { - Upload32(pic, x, y, width, height, GL_RGBA8, 0, image); + Upload32(pic, x, y, width, height, picFormat, 0, image, qfalse); } //=================================================================== @@ -2250,10 +2266,10 @@ typedef struct // when there are multiple images of different formats available static imageExtToLoaderMap_t imageLoaders[ ] = { + { "png", R_LoadPNG }, { "tga", R_LoadTGA }, { "jpg", R_LoadJPG }, { "jpeg", R_LoadJPG }, - { "png", R_LoadPNG }, { "pcx", R_LoadPCX }, { "bmp", R_LoadBMP } }; @@ -2264,7 +2280,7 @@ static int numImageLoaders = ARRAY_LEN( imageLoaders ); ================= R_LoadImage -Loads any of the supported image types into a cannonical +Loads any of the supported image types into a canonical 32 bit format. ================= */ @@ -2735,19 +2751,11 @@ void R_CreateBuiltinImages( void ) { { int width, height, hdrFormat, rgbFormat; - if(glRefConfig.textureNonPowerOfTwo) - { - width = glConfig.vidWidth; - height = glConfig.vidHeight; - } - else - { - width = NextPowerOfTwo(glConfig.vidWidth); - height = NextPowerOfTwo(glConfig.vidHeight); - } + width = glConfig.vidWidth; + height = glConfig.vidHeight; hdrFormat = GL_RGBA8; - if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat) + if (r_hdr->integer && glRefConfig.textureFloat) hdrFormat = GL_RGBA16F_ARB; rgbFormat = GL_RGBA8; @@ -2758,37 +2766,22 @@ void R_CreateBuiltinImages( void ) { tr.screenScratchImage = R_CreateImage("screenScratch", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat); if (r_shadowBlur->integer || r_ssao->integer) - tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB); + tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_R32F); if (r_drawSunRays->integer) tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat); - if (glRefConfig.framebufferObject) - { - tr.renderDepthImage = R_CreateImage("*renderdepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - tr.textureDepthImage = R_CreateImage("*texturedepth", NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - } + tr.renderDepthImage = R_CreateImage("*renderdepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24); + tr.textureDepthImage = R_CreateImage("*texturedepth", NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24); { - unsigned short sdata[4]; void *p; - if (hdrFormat == GL_RGBA16F_ARB) - { - sdata[0] = FloatToHalf(0.0f); - sdata[1] = FloatToHalf(0.45f); - sdata[2] = FloatToHalf(1.0f); - sdata[3] = FloatToHalf(1.0f); - p = &sdata[0]; - } - else - { - data[0][0][0] = 0; - data[0][0][1] = 0.45f * 255; - data[0][0][2] = 255; - data[0][0][3] = 255; - p = data; - } + data[0][0][0] = 0; + data[0][0][1] = 0.45f * 255; + data[0][0][2] = 255; + data[0][0][3] = 255; + p = data; tr.calcLevelsImage = R_CreateImage("*calcLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); tr.targetLevelsImage = R_CreateImage("*targetLevels", p, 1, 1, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); @@ -2809,21 +2802,20 @@ void R_CreateBuiltinImages( void ) { tr.screenSsaoImage = R_CreateImage("*screenSsao", NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); } - if (r_shadows->integer == 4) + for( x = 0; x < MAX_DRAWN_PSHADOWS; x++) { - for( x = 0; x < MAX_DRAWN_PSHADOWS; x++) - { - tr.pshadowMaps[x] = R_CreateImage(va("*shadowmap%i", x), NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); - } + tr.pshadowMaps[x] = R_CreateImage(va("*shadowmap%i", x), NULL, PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24); + //qglTextureParameterfEXT(tr.pshadowMaps[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + //qglTextureParameterfEXT(tr.pshadowMaps[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } if (r_sunlightMode->integer) { for ( x = 0; x < 4; x++) { - tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24_ARB); - qglTextureParameterf(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - qglTextureParameterf(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + tr.sunShadowDepthImage[x] = R_CreateImage(va("*sunshadowdepth%i", x), NULL, r_shadowMapSize->integer, r_shadowMapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_DEPTH_COMPONENT24); + qglTextureParameterfEXT(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + qglTextureParameterfEXT(tr.sunShadowDepthImage[x]->texnum, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); } tr.screenShadowImage = R_CreateImage("*screenShadow", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); @@ -2848,11 +2840,7 @@ void R_SetColorMappings( void ) { int inf; // setup the overbright lighting -#if defined(USE_OVERBRIGHT) tr.overbrightBits = r_overBrightBits->integer; -#else - tr.overbrightBits = 0; -#endif // allow 2 overbright bits if ( tr.overbrightBits > 2 ) { @@ -2957,7 +2945,7 @@ SKINS CommaParse This is unfortunate, but the skin files aren't -compatable with our normal parsing rules. +compatible with our normal parsing rules. ================== */ static char *CommaParse( char **data_p ) { @@ -3065,6 +3053,7 @@ RE_RegisterSkin =============== */ qhandle_t RE_RegisterSkin( const char *name ) { + skinSurface_t parseSurfaces[MAX_SKIN_SURFACES]; qhandle_t hSkin; skin_t *skin; skinSurface_t *surf; @@ -3075,6 +3064,7 @@ qhandle_t RE_RegisterSkin( const char *name ) { char *text_p; char *token; char surfName[MAX_QPATH]; + int totalSurfaces; if ( !name || !name[0] ) { ri.Printf( PRINT_DEVELOPER, "Empty name passed to RE_RegisterSkin\n" ); @@ -3114,8 +3104,8 @@ qhandle_t RE_RegisterSkin( const char *name ) { // If not a .skin file, load as a single shader if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); + skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low ); + skin->surfaces[0].shader = R_FindShader( name, LIGHTMAP_NONE, qtrue ); return hSkin; } @@ -3125,6 +3115,7 @@ qhandle_t RE_RegisterSkin( const char *name ) { return 0; } + totalSurfaces = 0; text_p = text.c; while ( text_p && *text_p ) { // get surface name @@ -3148,25 +3139,32 @@ qhandle_t RE_RegisterSkin( const char *name ) { // parse the shader name token = CommaParse( &text_p ); - if ( skin->numSurfaces >= MD3_MAX_SURFACES ) { - ri.Printf( PRINT_WARNING, "WARNING: Ignoring surfaces in '%s', the max is %d surfaces!\n", name, MD3_MAX_SURFACES ); - break; + if ( skin->numSurfaces < MAX_SKIN_SURFACES ) { + surf = &parseSurfaces[skin->numSurfaces]; + Q_strncpyz( surf->name, surfName, sizeof( surf->name ) ); + surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue ); + skin->numSurfaces++; } - surf = skin->surfaces[ skin->numSurfaces ] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - Q_strncpyz( surf->name, surfName, sizeof( surf->name ) ); - surf->shader = R_FindShader( token, LIGHTMAP_NONE, qtrue ); - skin->numSurfaces++; + totalSurfaces++; } ri.FS_FreeFile( text.v ); + if ( totalSurfaces > MAX_SKIN_SURFACES ) { + ri.Printf( PRINT_WARNING, "WARNING: Ignoring excess surfaces (found %d, max is %d) in skin '%s'!\n", + totalSurfaces, MAX_SKIN_SURFACES, name ); + } // never let a skin have 0 shaders if ( skin->numSurfaces == 0 ) { return 0; // use default skin } + // copy surfaces to skin + skin->surfaces = ri.Hunk_Alloc( skin->numSurfaces * sizeof( skinSurface_t ), h_low ); + memcpy( skin->surfaces, parseSurfaces, skin->numSurfaces * sizeof( skinSurface_t ) ); + return hSkin; } @@ -3185,8 +3183,8 @@ void R_InitSkins( void ) { skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low ); Q_strncpyz( skin->name, "", sizeof( skin->name ) ); skin->numSurfaces = 1; - skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low ); - skin->surfaces[0]->shader = tr.defaultShader; + skin->surfaces = ri.Hunk_Alloc( sizeof( skinSurface_t ), h_low ); + skin->surfaces[0].shader = tr.defaultShader; } /* @@ -3215,10 +3213,10 @@ void R_SkinList_f( void ) { for ( i = 0 ; i < tr.numSkins ; i++ ) { skin = tr.skins[i]; - ri.Printf( PRINT_ALL, "%3i:%s\n", i, skin->name ); + ri.Printf( PRINT_ALL, "%3i:%s (%d surfaces)\n", i, skin->name, skin->numSurfaces ); for ( j = 0 ; j < skin->numSurfaces ; j++ ) { ri.Printf( PRINT_ALL, " %s = %s\n", - skin->surfaces[j]->name, skin->surfaces[j]->shader->name ); + skin->surfaces[j].name, skin->surfaces[j].shader->name ); } } ri.Printf (PRINT_ALL, "------------------\n"); diff --git a/code/renderergl2/tr_init.c b/code/renderergl2/tr_init.c index 05cd40e7..ce48925d 100644 --- a/code/renderergl2/tr_init.c +++ b/code/renderergl2/tr_init.c @@ -98,21 +98,13 @@ cvar_t *r_ext_texture_env_add; cvar_t *r_ext_texture_filter_anisotropic; cvar_t *r_ext_max_anisotropy; -cvar_t *r_ext_draw_range_elements; -cvar_t *r_ext_multi_draw_arrays; cvar_t *r_ext_framebuffer_object; cvar_t *r_ext_texture_float; -cvar_t *r_arb_half_float_pixel; -cvar_t *r_arb_half_float_vertex; cvar_t *r_ext_framebuffer_multisample; cvar_t *r_arb_seamless_cube_map; -cvar_t *r_arb_vertex_type_2_10_10_10_rev; cvar_t *r_arb_vertex_array_object; cvar_t *r_ext_direct_state_access; -cvar_t *r_mergeMultidraws; -cvar_t *r_mergeLeafSurfaces; - cvar_t *r_cameraExposure; cvar_t *r_externalGLSL; @@ -141,6 +133,7 @@ cvar_t *r_deluxeMapping; cvar_t *r_parallaxMapping; cvar_t *r_cubeMapping; cvar_t *r_cubemapSize; +cvar_t *r_deluxeSpecular; cvar_t *r_pbr; cvar_t *r_baseNormalX; cvar_t *r_baseNormalY; @@ -156,7 +149,6 @@ cvar_t *r_imageUpsampleMaxSize; cvar_t *r_imageUpsampleType; cvar_t *r_genNormalMaps; cvar_t *r_forceSun; -cvar_t *r_forceSunMapLightScale; cvar_t *r_forceSunLightScale; cvar_t *r_forceSunAmbientScale; cvar_t *r_sunlightMode; @@ -251,8 +243,6 @@ int max_polyverts; */ static void InitOpenGL( void ) { - char renderer_buffer[1024]; - // // initialize OS specific portions of the renderer // @@ -268,11 +258,10 @@ static void InitOpenGL( void ) { GLint temp; - GLimp_Init(); + GLimp_Init( qfalse ); GLimp_InitExtraExtensions(); - strcpy( renderer_buffer, glConfig.renderer_string ); - Q_strlwr( renderer_buffer ); + glConfig.textureEnvAddAvailable = qtrue; // OpenGL driver constants qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); @@ -283,6 +272,16 @@ static void InitOpenGL( void ) { glConfig.maxTextureSize = 0; } + + qglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &temp ); + glConfig.numTextureUnits = temp; + + // reserve 160 components for other uniforms + qglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS, &temp ); + glRefConfig.glslMaxAnimatedBones = Com_Clamp( 0, IQM_MAX_JOINTS, ( temp - 160 ) / 16 ); + if ( glRefConfig.glslMaxAnimatedBones < 12 ) { + glRefConfig.glslMaxAnimatedBones = 0; + } } // set default state @@ -952,12 +951,11 @@ void GL_SetDefaultState( void ) qglCullFace(GL_FRONT); - qglColor4f (1,1,1,1); - GL_BindNullTextures(); - GL_BindNullFramebuffers(); - qglEnable(GL_TEXTURE_2D); + if (glRefConfig.framebufferObject) + GL_BindNullFramebuffers(); + GL_TextureMode( r_textureMode->string ); //qglShadeModel( GL_SMOOTH ); @@ -974,10 +972,10 @@ void GL_SetDefaultState( void ) GL_BindNullProgram(); if (glRefConfig.vertexArrayObject) - qglBindVertexArrayARB(0); + qglBindVertexArray(0); - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + qglBindBuffer(GL_ARRAY_BUFFER, 0); + qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glState.currentVao = NULL; glState.vertexAttribsEnabled = 0; @@ -1041,10 +1039,24 @@ void GfxInfo_f( void ) ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); ri.Printf( PRINT_ALL, "GL_EXTENSIONS: " ); - R_PrintLongString( glConfig.extensions_string ); + if ( qglGetStringi ) + { + GLint numExtensions; + int i; + + qglGetIntegerv( GL_NUM_EXTENSIONS, &numExtensions ); + for ( i = 0; i < numExtensions; i++ ) + { + ri.Printf( PRINT_ALL, "%s ", qglGetStringi( GL_EXTENSIONS, i ) ); + } + } + else + { + R_PrintLongString( glConfig.extensions_string ); + } ri.Printf( PRINT_ALL, "\n" ); ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_SIZE: %d\n", glConfig.maxTextureSize ); - ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_UNITS_ARB: %d\n", glConfig.numTextureUnits ); + ri.Printf( PRINT_ALL, "GL_MAX_TEXTURE_IMAGE_UNITS: %d\n", glConfig.numTextureUnits ); ri.Printf( PRINT_ALL, "\nPIXELFORMAT: color(%d-bits) Z(%d-bit) stencil(%d-bits)\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits ); ri.Printf( PRINT_ALL, "MODE: %d, %d x %d %s hz:", r_mode->integer, glConfig.vidWidth, glConfig.vidHeight, fsstrings[r_fullscreen->integer == 1] ); if ( glConfig.displayFrequency ) @@ -1067,7 +1079,6 @@ void GfxInfo_f( void ) ri.Printf( PRINT_ALL, "texturemode: %s\n", r_textureMode->string ); ri.Printf( PRINT_ALL, "picmip: %d\n", r_picmip->integer ); ri.Printf( PRINT_ALL, "texture bits: %d\n", r_texturebits->integer ); - ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] ); ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] ); ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] ); ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression!=TC_NONE] ); @@ -1160,15 +1171,10 @@ void R_Register( void ) r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_texture_env_add = ri.Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_draw_range_elements = ri.Cvar_Get( "r_ext_draw_range_elements", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_ext_multi_draw_arrays = ri.Cvar_Get( "r_ext_multi_draw_arrays", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_framebuffer_object = ri.Cvar_Get( "r_ext_framebuffer_object", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_texture_float = ri.Cvar_Get( "r_ext_texture_float", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_arb_half_float_pixel = ri.Cvar_Get( "r_arb_half_float_pixel", "1", CVAR_ARCHIVE | CVAR_LATCH); - r_arb_half_float_vertex = ri.Cvar_Get( "r_arb_half_float_vertex", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_framebuffer_multisample = ri.Cvar_Get( "r_ext_framebuffer_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH); r_arb_seamless_cube_map = ri.Cvar_Get( "r_arb_seamless_cube_map", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_arb_vertex_type_2_10_10_10_rev = ri.Cvar_Get( "r_arb_vertex_type_2_10_10_10_rev", "1", CVAR_ARCHIVE | CVAR_LATCH); r_arb_vertex_array_object = ri.Cvar_Get( "r_arb_vertex_array_object", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_direct_state_access = ri.Cvar_Get("r_ext_direct_state_access", "1", CVAR_ARCHIVE | CVAR_LATCH); @@ -1220,7 +1226,7 @@ void R_Register( void ) r_forceAutoExposureMin = ri.Cvar_Get( "r_forceAutoExposureMin", "-2.0", CVAR_CHEAT ); r_forceAutoExposureMax = ri.Cvar_Get( "r_forceAutoExposureMax", "2.0", CVAR_CHEAT ); - r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "0", CVAR_CHEAT ); + r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "1", CVAR_CHEAT ); r_depthPrepass = ri.Cvar_Get( "r_depthPrepass", "1", CVAR_ARCHIVE ); r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE ); @@ -1231,6 +1237,7 @@ void R_Register( void ) r_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_cubeMapping = ri.Cvar_Get( "r_cubeMapping", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_cubemapSize = ri.Cvar_Get( "r_cubemapSize", "128", CVAR_ARCHIVE | CVAR_LATCH ); + r_deluxeSpecular = ri.Cvar_Get("r_deluxeSpecular", "0.3", CVAR_ARCHIVE | CVAR_LATCH); r_pbr = ri.Cvar_Get("r_pbr", "0", CVAR_ARCHIVE | CVAR_LATCH); r_baseNormalX = ri.Cvar_Get( "r_baseNormalX", "1.0", CVAR_ARCHIVE | CVAR_LATCH ); r_baseNormalY = ri.Cvar_Get( "r_baseNormalY", "1.0", CVAR_ARCHIVE | CVAR_LATCH ); @@ -1247,7 +1254,6 @@ void R_Register( void ) r_genNormalMaps = ri.Cvar_Get( "r_genNormalMaps", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_forceSun = ri.Cvar_Get( "r_forceSun", "0", CVAR_CHEAT ); - r_forceSunMapLightScale = ri.Cvar_Get( "r_forceSunMapLightScale", "1.0", CVAR_CHEAT ); r_forceSunLightScale = ri.Cvar_Get( "r_forceSunLightScale", "1.0", CVAR_CHEAT ); r_forceSunAmbientScale = ri.Cvar_Get( "r_forceSunAmbientScale", "0.5", CVAR_CHEAT ); r_drawSunRays = ri.Cvar_Get( "r_drawSunRays", "0", CVAR_ARCHIVE | CVAR_LATCH ); @@ -1303,8 +1309,6 @@ void R_Register( void ) r_directedScale = ri.Cvar_Get( "r_directedScale", "1", CVAR_CHEAT ); r_anaglyphMode = ri.Cvar_Get("r_anaglyphMode", "0", CVAR_ARCHIVE); - r_mergeMultidraws = ri.Cvar_Get("r_mergeMultidraws", "1", CVAR_ARCHIVE); - r_mergeLeafSurfaces = ri.Cvar_Get("r_mergeLeafSurfaces", "1", CVAR_ARCHIVE); // // temporary variables that can change at any time @@ -1380,7 +1384,7 @@ void R_InitQueries(void) return; if (r_drawSunRays->integer) - qglGenQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); + qglGenQueries(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); } void R_ShutDownQueries(void) @@ -1389,7 +1393,7 @@ void R_ShutDownQueries(void) return; if (r_drawSunRays->integer) - qglDeleteQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); + qglDeleteQueries(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); } /* @@ -1506,16 +1510,15 @@ void RE_Shutdown( qboolean destroyWindow ) { ri.Printf( PRINT_ALL, "RE_Shutdown( %i )\n", destroyWindow ); - ri.Cmd_RemoveCommand ("modellist"); - ri.Cmd_RemoveCommand ("screenshotJPEG"); - ri.Cmd_RemoveCommand ("screenshot"); - ri.Cmd_RemoveCommand ("imagelist"); - ri.Cmd_RemoveCommand ("shaderlist"); - ri.Cmd_RemoveCommand ("skinlist"); - ri.Cmd_RemoveCommand ("gfxinfo"); - ri.Cmd_RemoveCommand("minimize"); + ri.Cmd_RemoveCommand( "imagelist" ); + ri.Cmd_RemoveCommand( "shaderlist" ); + ri.Cmd_RemoveCommand( "skinlist" ); + ri.Cmd_RemoveCommand( "modellist" ); ri.Cmd_RemoveCommand( "modelist" ); - ri.Cmd_RemoveCommand( "shaderstate" ); + ri.Cmd_RemoveCommand( "screenshot" ); + ri.Cmd_RemoveCommand( "screenshotJPEG" ); + ri.Cmd_RemoveCommand( "gfxinfo" ); + ri.Cmd_RemoveCommand( "minimize" ); ri.Cmd_RemoveCommand( "gfxmeminfo" ); ri.Cmd_RemoveCommand( "exportCubemaps" ); @@ -1537,6 +1540,11 @@ void RE_Shutdown( qboolean destroyWindow ) { GLimp_Shutdown(); Com_Memset( &glConfig, 0, sizeof( glConfig ) ); + Com_Memset( &glRefConfig, 0, sizeof( glRefConfig ) ); + textureFilterAnisotropic = qfalse; + maxAnisotropy = 0; + displayAspect = 0.0f; + Com_Memset( &glState, 0, sizeof( glState ) ); } diff --git a/code/renderergl2/tr_light.c b/code/renderergl2/tr_light.c index a335eb6f..3ac2154e 100644 --- a/code/renderergl2/tr_light.c +++ b/code/renderergl2/tr_light.c @@ -99,7 +99,6 @@ void R_DlightBmodel( bmodel_t *bmodel ) { case SF_FACE: case SF_GRID: case SF_TRIANGLES: - case SF_VAO_MESH: ((srfBspSurface_t *)surf->data)->dlightBits = mask; break; @@ -139,7 +138,7 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) { float totalFactor; if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is + // separate lightOrigins are needed so an object that is // sinking into the ground can still be lit, and so // multi-part models can be lit identically VectorCopy( ent->e.lightingOrigin, lightOrigin ); @@ -201,10 +200,10 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) { continue; } - if (world->hdrLightGrid) + if (world->lightGrid16) { - float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6; - if (!(hdrData[0]+hdrData[1]+hdrData[2]+hdrData[3]+hdrData[4]+hdrData[5]) ) { + uint16_t *data16 = world->lightGrid16 + (int)(data - world->lightGridData) / 8 * 6; + if (!(data16[0]+data16[1]+data16[2]+data16[3]+data16[4]+data16[5])) { continue; // ignore samples in walls } } @@ -227,18 +226,18 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) { ent->directedLight[1] += factor * d4; ent->directedLight[2] += factor * d5; #else - if (world->hdrLightGrid) + if (world->lightGrid16) { // FIXME: this is hideous - float *hdrData = world->hdrLightGrid + (int)(data - world->lightGridData) / 8 * 6; + uint16_t *data16 = world->lightGrid16 + (int)(data - world->lightGridData) / 8 * 6; - ent->ambientLight[0] += factor * hdrData[0]; - ent->ambientLight[1] += factor * hdrData[1]; - ent->ambientLight[2] += factor * hdrData[2]; + ent->ambientLight[0] += factor * data16[0] / 257.0f; + ent->ambientLight[1] += factor * data16[1] / 257.0f; + ent->ambientLight[2] += factor * data16[2] / 257.0f; - ent->directedLight[0] += factor * hdrData[3]; - ent->directedLight[1] += factor * hdrData[4]; - ent->directedLight[2] += factor * hdrData[5]; + ent->directedLight[0] += factor * data16[3] / 257.0f; + ent->directedLight[1] += factor * data16[4] / 257.0f; + ent->directedLight[2] += factor * data16[5] / 257.0f; } else { @@ -336,7 +335,7 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { // trace a sample point down to find ambient light // if ( ent->e.renderfx & RF_LIGHTING_ORIGIN ) { - // seperate lightOrigins are needed so an object that is + // separate lightOrigins are needed so an object that is // sinking into the ground can still be lit, and so // multi-part models can be lit identically VectorCopy( ent->e.lightingOrigin, lightOrigin ); @@ -357,7 +356,7 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { } // bonus items and view weapons have a fixed minimum add - if ( !r_hdr->integer /* ent->e.renderfx & RF_MINLIGHT */ ) { + if ( 1 /* ent->e.renderfx & RF_MINLIGHT */ ) { // give everything a minimum light add ent->ambientLight[0] += tr.identityLight * 32; ent->ambientLight[1] += tr.identityLight * 32; @@ -385,16 +384,42 @@ void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ) { VectorMA( lightDir, d, dir, lightDir ); } - // clamp ambient - if ( !r_hdr->integer ) + // clamp lights + // FIXME: old renderer clamps (ambient + NL * directed) per vertex + // check if that's worth implementing { - for ( i = 0 ; i < 3 ; i++ ) { - if ( ent->ambientLight[i] > tr.identityLightByte ) { - ent->ambientLight[i] = tr.identityLightByte; - } + float r, g, b, max; + + r = ent->ambientLight[0]; + g = ent->ambientLight[1]; + b = ent->ambientLight[2]; + + max = MAX(MAX(r, g), b); + + if (max > 255.0f) + { + max = 255.0f / max; + ent->ambientLight[0] *= max; + ent->ambientLight[1] *= max; + ent->ambientLight[2] *= max; + } + + r = ent->directedLight[0]; + g = ent->directedLight[1]; + b = ent->directedLight[2]; + + max = MAX(MAX(r, g), b); + + if (max > 255.0f) + { + max = 255.0f / max; + ent->directedLight[0] *= max; + ent->directedLight[1] *= max; + ent->directedLight[2] *= max; } } + if ( r_debugLight->integer ) { LogLight( ent ); } diff --git a/code/renderergl2/tr_local.h b/code/renderergl2/tr_local.h index 78e37ecb..ea6d70fe 100644 --- a/code/renderergl2/tr_local.h +++ b/code/renderergl2/tr_local.h @@ -36,6 +36,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../renderercommon/iqm.h" #include "../renderercommon/qgl.h" +#define GLE(ret, name, ...) extern name##proc * qgl##name; +QGL_1_1_PROCS; +QGL_DESKTOP_1_1_PROCS; +QGL_1_3_PROCS; +QGL_1_5_PROCS; +QGL_2_0_PROCS; +QGL_3_0_PROCS; +QGL_ARB_occlusion_query_PROCS; +QGL_ARB_framebuffer_object_PROCS; +QGL_ARB_vertex_array_object_PROCS; +QGL_EXT_direct_state_access_PROCS; +#undef GLE + #define GL_INDEX_TYPE GL_UNSIGNED_INT typedef unsigned int glIndex_t; @@ -55,9 +68,6 @@ typedef unsigned int glIndex_t; #define MAX_DRAWN_PSHADOWS 16 // do not increase past 32, because bit flags are used on surfaces #define PSHADOW_MAP_SIZE 512 -#define USE_VERT_TANGENT_SPACE -#define USE_OVERBRIGHT - typedef struct cubemap_s { char name[MAX_QPATH]; vec3_t origin; @@ -474,37 +484,14 @@ typedef struct shader_s { void (*optimalStageIteratorFunc)( void ); - float clampTime; // time this shader is clamped to - float timeOffset; // current time offset for this shader + double clampTime; // time this shader is clamped to + double timeOffset; // current time offset for this shader struct shader_s *remappedShader; // current shader this one is remapped too struct shader_s *next; } shader_t; -static ID_INLINE qboolean ShaderRequiresCPUDeforms(const shader_t * shader) -{ - if(shader->numDeforms) - { - const deformStage_t *ds = &shader->deforms[0]; - - if (shader->numDeforms > 1) - return qtrue; - - switch (ds->deformation) - { - case DEFORM_WAVE: - case DEFORM_BULGE: - return qfalse; - - default: - return qtrue; - } - } - - return qfalse; -} - enum { ATTR_INDEX_POSITION = 0, @@ -567,16 +554,18 @@ enum GENERICDEF_USE_VERTEX_ANIMATION = 0x0004, GENERICDEF_USE_FOG = 0x0008, GENERICDEF_USE_RGBAGEN = 0x0010, - GENERICDEF_ALL = 0x001F, - GENERICDEF_COUNT = 0x0020, + GENERICDEF_USE_BONE_ANIMATION = 0x0020, + GENERICDEF_ALL = 0x003F, + GENERICDEF_COUNT = 0x0040, }; enum { FOGDEF_USE_DEFORM_VERTEXES = 0x0001, FOGDEF_USE_VERTEX_ANIMATION = 0x0002, - FOGDEF_ALL = 0x0003, - FOGDEF_COUNT = 0x0004, + FOGDEF_USE_BONE_ANIMATION = 0x0004, + FOGDEF_ALL = 0x0007, + FOGDEF_COUNT = 0x0008, }; enum @@ -592,12 +581,21 @@ enum LIGHTDEF_USE_LIGHT_VECTOR = 0x0002, LIGHTDEF_USE_LIGHT_VERTEX = 0x0003, LIGHTDEF_LIGHTTYPE_MASK = 0x0003, - LIGHTDEF_ENTITY = 0x0004, + LIGHTDEF_ENTITY_VERTEX_ANIMATION = 0x0004, LIGHTDEF_USE_TCGEN_AND_TCMOD = 0x0008, LIGHTDEF_USE_PARALLAXMAP = 0x0010, LIGHTDEF_USE_SHADOWMAP = 0x0020, - LIGHTDEF_ALL = 0x003F, - LIGHTDEF_COUNT = 0x0040 + LIGHTDEF_ENTITY_BONE_ANIMATION = 0x0040, + LIGHTDEF_ALL = 0x007F, + LIGHTDEF_COUNT = 0x0080 +}; + +enum +{ + SHADOWMAPDEF_USE_VERTEX_ANIMATION = 0x0001, + SHADOWMAPDEF_USE_BONE_ANIMATION = 0x0002, + SHADOWMAPDEF_ALL = 0x0003, + SHADOWMAPDEF_COUNT = 0x0004 }; enum @@ -608,7 +606,8 @@ enum GLSL_VEC2, GLSL_VEC3, GLSL_VEC4, - GLSL_MAT16 + GLSL_MAT16, + GLSL_MAT16_BONEMATRIX }; typedef enum @@ -697,6 +696,10 @@ typedef enum UNIFORM_CUBEMAPINFO, + UNIFORM_ALPHATEST, + + UNIFORM_BONEMATRIX, + UNIFORM_COUNT } uniform_t; @@ -706,9 +709,9 @@ typedef struct shaderProgram_s { char name[MAX_QPATH]; - GLhandleARB program; - GLhandleARB vertexShader; - GLhandleARB fragmentShader; + GLuint program; + GLuint vertexShader; + GLuint fragmentShader; uint32_t attribs; // vertex array attributes // uniform parameters @@ -734,7 +737,7 @@ typedef struct { byte areamask[MAX_MAP_AREA_BYTES]; qboolean areamaskModified; // qtrue if areamask changed since last scene - float floatTime; // tr.refdef.time / 1000.0 + double floatTime; // tr.refdef.time / 1000.0 float blurFactor; @@ -761,7 +764,6 @@ typedef struct { float sunDir[4]; float sunCol[4]; float sunAmbCol[4]; - float colorScale; float autoExposureMinMax[2]; float toneMinAvgMaxLinear[3]; @@ -770,6 +772,12 @@ typedef struct { //================================================================================= +// max surfaces per-skin +// This is an arbitry limit. Vanilla Q3 only supported 32 surfaces in skins but failed to +// enforce the maximum limit when reading skin files. It was possile to use more than 32 +// surfaces which accessed out of bounds memory past end of skin->surfaces hunk block. +#define MAX_SKIN_SURFACES 256 + // skins allow models to be retextured without modifying the model file typedef struct { char name[MAX_QPATH]; @@ -779,7 +787,7 @@ typedef struct { typedef struct skin_s { char name[MAX_QPATH]; // game path, including extension int numSurfaces; - skinSurface_t *surfaces[MD3_MAX_SURFACES]; + skinSurface_t *surfaces; // dynamically allocated array of surfaces } skin_t; @@ -854,8 +862,8 @@ typedef enum { SF_IQM, SF_FLARE, SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity - SF_VAO_MESH, SF_VAO_MDVMESH, + SF_VAO_IQM, SF_NUM_SURFACE_TYPES, SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int ) @@ -895,25 +903,19 @@ typedef struct vec3_t xyz; vec2_t st; vec2_t lightmap; - vec3_t normal; -#ifdef USE_VERT_TANGENT_SPACE - vec4_t tangent; -#endif - vec3_t lightdir; - vec4_t vertexColors; + int16_t normal[4]; + int16_t tangent[4]; + int16_t lightdir[4]; + uint16_t color[4]; #if DEBUG_OPTIMIZEVERTICES unsigned int id; #endif } srfVert_t; -#ifdef USE_VERT_TANGENT_SPACE -#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0}, {0, 0, 0, 0}} -#else -#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0, 0}} -#endif +#define srfVert_t_cleared(x) srfVert_t (x) = {{0, 0, 0}, {0, 0}, {0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}} -// srfBspSurface_t covers SF_GRID, SF_TRIANGLES, SF_POLY, and SF_VAO_MESH +// srfBspSurface_t covers SF_GRID, SF_TRIANGLES, and SF_POLY typedef struct srfBspSurface_s { surfaceType_t surfaceType; @@ -935,15 +937,6 @@ typedef struct srfBspSurface_s // vertexes int numVerts; srfVert_t *verts; - - // BSP VBO offsets - int firstVert; - int firstIndex; - glIndex_t minIndex; - glIndex_t maxIndex; - - // static render data - vao_t *vao; // SF_GRID specific variables after here @@ -971,28 +964,36 @@ typedef struct { int num_poses; struct srfIQModel_s *surfaces; + int *triangles; + + // vertex arrays float *positions; float *texcoords; float *normals; float *tangents; - byte *blendIndexes; + byte *colors; + int *influences; // [num_vertexes] indexes into influenceBlendVertexes + + // unique list of vertex blend indexes/weights for faster CPU vertex skinning + byte *influenceBlendIndexes; // [num_influences] union { float *f; byte *b; - } blendWeights; - byte *colors; - int *triangles; + } influenceBlendWeights; // [num_influences] // depending upon the exporter, blend indices and weights might be int/float // as opposed to the recommended byte/byte, for example Noesis exports // int/float whereas the official IQM tool exports byte/byte - byte blendWeightsType; // IQM_UBYTE or IQM_FLOAT + int blendWeightsType; // IQM_UBYTE or IQM_FLOAT + char *jointNames; int *jointParents; float *jointMats; float *poseMats; float *bounds; - char *names; + + int numVaoSurfaces; + struct srfVaoIQModel_s *vaoSurfaces; } iqmData_t; // inter-quake-model surface @@ -1003,8 +1004,24 @@ typedef struct srfIQModel_s { iqmData_t *data; int first_vertex, num_vertexes; int first_triangle, num_triangles; + int first_influence, num_influences; } srfIQModel_t; +typedef struct srfVaoIQModel_s +{ + surfaceType_t surfaceType; + + iqmData_t *iqmData; + struct srfIQModel_s *iqmSurface; + + // backEnd stats + int numIndexes; + int numVerts; + + // static render data + vao_t *vao; +} srfVaoIQModel_t; + typedef struct srfVaoMdvMesh_s { surfaceType_t surfaceType; @@ -1015,8 +1032,6 @@ typedef struct srfVaoMdvMesh_s // backEnd stats int numIndexes; int numVerts; - glIndex_t minIndex; - glIndex_t maxIndex; // static render data vao_t *vao; @@ -1145,15 +1160,8 @@ typedef struct { int *surfacesDlightBits; int *surfacesPshadowBits; - int numMergedSurfaces; - msurface_t *mergedSurfaces; - int *mergedSurfacesViewCount; - int *mergedSurfacesDlightBits; - int *mergedSurfacesPshadowBits; - int nummarksurfaces; int *marksurfaces; - int *viewSurfaces; int numfogs; fog_t *fogs; @@ -1163,7 +1171,7 @@ typedef struct { vec3_t lightGridInverseSize; int lightGridBounds[3]; byte *lightGridData; - float *hdrLightGrid; + uint16_t *lightGrid16; int numClusters; @@ -1201,11 +1209,8 @@ typedef struct typedef struct { vec3_t xyz; - vec3_t normal; -#ifdef USE_VERT_TANGENT_SPACE - vec3_t tangent; - vec3_t bitangent; -#endif + int16_t normal[4]; + int16_t tangent[4]; } mdvVertex_t; typedef struct @@ -1360,6 +1365,8 @@ typedef struct { uint32_t storedGlState; float vertexAttribsInterpolation; qboolean vertexAnimation; + int boneAnimation; // number of bones + mat4_t boneMatrix[IQM_MAX_JOINTS]; uint32_t vertexAttribsEnabled; // global if no VAOs, tess only otherwise FBO_t *currentFBO; vao_t *currentVao; @@ -1383,12 +1390,13 @@ typedef enum { // We can't change glConfig_t without breaking DLL/vms compatibility, so // store extensions we have here. typedef struct { - qboolean drawRangeElements; - qboolean multiDrawArrays; + qboolean intelGraphics; + qboolean occlusionQuery; int glslMajorVersion; int glslMinorVersion; + int glslMaxAnimatedBones; memInfo_t memInfo; @@ -1396,11 +1404,7 @@ typedef struct { int maxRenderbufferSize; int maxColorAttachments; - qboolean textureNonPowerOfTwo; qboolean textureFloat; - qboolean halfFloatPixel; - qboolean packedDepthStencil; - qboolean arbTextureCompression; textureCompressionRef_t textureCompression; qboolean swizzleNormalmap; @@ -1410,13 +1414,6 @@ typedef struct { qboolean depthClamp; qboolean seamlessCubeMap; - GLenum packedNormalDataType; - GLenum packedTexcoordDataType; - GLenum packedColorDataType; - int packedTexcoordDataSize; - int packedColorDataSize; - - qboolean floatLightmap; qboolean vertexArrayObject; qboolean directStateAccess; } glRefConfig_t; @@ -1434,9 +1431,6 @@ typedef struct { int c_staticVaoDraws; int c_dynamicVaoDraws; - int c_multidraws; - int c_multidrawsMerged; - int c_dlightVertexes; int c_dlightIndexes; @@ -1453,7 +1447,7 @@ typedef struct { int msec; // total msec for backend run } backEndCounters_t; -// all state modified by the back end is seperated +// all state modified by the back end is separated // from the front end state typedef struct { trRefdef_t refdef; @@ -1563,8 +1557,8 @@ typedef struct { image_t **lightmaps; image_t **deluxemaps; - int fatLightmapSize; - int fatLightmapStep; + int fatLightmapCols; + int fatLightmapRows; int numCubemaps; cubemap_t *cubemaps; @@ -1583,7 +1577,7 @@ typedef struct { shaderProgram_t fogShader[FOGDEF_COUNT]; shaderProgram_t dlightShader[DLIGHTDEF_COUNT]; shaderProgram_t lightallShader[LIGHTDEF_COUNT]; - shaderProgram_t shadowmapShader; + shaderProgram_t shadowmapShader[SHADOWMAPDEF_COUNT]; shaderProgram_t pshadowShader; shaderProgram_t down4xShader; shaderProgram_t bokehShader; @@ -1591,7 +1585,7 @@ typedef struct { shaderProgram_t calclevels4xShader[2]; shaderProgram_t shadowmaskShader; shaderProgram_t ssaoShader; - shaderProgram_t depthBlurShader[2]; + shaderProgram_t depthBlurShader[4]; shaderProgram_t testcubeShader; @@ -1609,7 +1603,6 @@ typedef struct { int viewCluster; - float mapLightScale; float sunShadowScale; qboolean sunShadows; @@ -1709,15 +1702,10 @@ extern cvar_t *r_showcluster; extern cvar_t *r_gamma; extern cvar_t *r_displayRefresh; // optional display refresh option -extern cvar_t *r_ext_draw_range_elements; -extern cvar_t *r_ext_multi_draw_arrays; extern cvar_t *r_ext_framebuffer_object; extern cvar_t *r_ext_texture_float; -extern cvar_t *r_arb_half_float_pixel; -extern cvar_t *r_arb_half_float_vertex; extern cvar_t *r_ext_framebuffer_multisample; extern cvar_t *r_arb_seamless_cube_map; -extern cvar_t *r_arb_vertex_type_2_10_10_10_rev; extern cvar_t *r_arb_vertex_array_object; extern cvar_t *r_ext_direct_state_access; @@ -1757,9 +1745,6 @@ extern cvar_t *r_skipBackEnd; extern cvar_t *r_anaglyphMode; -extern cvar_t *r_mergeMultidraws; -extern cvar_t *r_mergeLeafSurfaces; - extern cvar_t *r_externalGLSL; extern cvar_t *r_hdr; @@ -1788,6 +1773,7 @@ extern cvar_t *r_deluxeMapping; extern cvar_t *r_parallaxMapping; extern cvar_t *r_cubeMapping; extern cvar_t *r_cubemapSize; +extern cvar_t *r_deluxeSpecular; extern cvar_t *r_pbr; extern cvar_t *r_baseNormalX; extern cvar_t *r_baseNormalY; @@ -1803,7 +1789,6 @@ extern cvar_t *r_imageUpsampleMaxSize; extern cvar_t *r_imageUpsampleType; extern cvar_t *r_genNormalMaps; extern cvar_t *r_forceSun; -extern cvar_t *r_forceSunMapLightScale; extern cvar_t *r_forceSunLightScale; extern cvar_t *r_forceSunAmbientScale; extern cvar_t *r_sunlightMode; @@ -1836,6 +1821,32 @@ extern cvar_t *r_marksOnTriangleMeshes; //==================================================================== +static ID_INLINE qboolean ShaderRequiresCPUDeforms(const shader_t * shader) +{ + if(shader->numDeforms) + { + const deformStage_t *ds = &shader->deforms[0]; + + if (shader->numDeforms > 1) + return qtrue; + + switch (ds->deformation) + { + case DEFORM_WAVE: + case DEFORM_BULGE: + // need CPU deforms at high level-times to avoid floating point percision loss + return ( backEnd.refdef.floatTime != (float)backEnd.refdef.floatTime ); + + default: + return qtrue; + } + } + + return qfalse; +} + +//==================================================================== + void R_SwapBuffers( int ); void R_RenderView( viewParms_t *parms ); @@ -1860,7 +1871,7 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3); -void R_CalcTbnFromNormalAndTexDirs(vec3_t tangent, vec3_t bitangent, vec3_t normal, vec3_t sdir, vec3_t tdir); +vec_t R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, const vec3_t normal, const vec3_t sdir, const vec3_t tdir); qboolean R_CalcTangentVectors(srfVert_t * dv[3]); #define CULL_IN 0 // completely unclipped @@ -1943,7 +1954,7 @@ qboolean R_GetEntityToken( char *buffer, int size ); model_t *R_AllocModel( void ); void R_Init( void ); -void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height ); +void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height, GLenum picFormat ); void R_SetColorMappings( void ); void R_GammaCorrect( byte *buffer, int bufSize ); @@ -2001,31 +2012,29 @@ typedef struct stageVars vec2_t texcoords[NUM_TEXTURE_BUNDLES][SHADER_MAX_VERTEXES]; } stageVars_t; -#define MAX_MULTIDRAW_PRIMITIVES 256 - typedef struct shaderCommands_s { glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16); vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16); - uint32_t normal[SHADER_MAX_VERTEXES] QALIGN(16); -#ifdef USE_VERT_TANGENT_SPACE - uint32_t tangent[SHADER_MAX_VERTEXES] QALIGN(16); -#endif - vec2_t texCoords[SHADER_MAX_VERTEXES][2] QALIGN(16); - vec4_t vertexColors[SHADER_MAX_VERTEXES] QALIGN(16); - uint32_t lightdir[SHADER_MAX_VERTEXES] QALIGN(16); + int16_t normal[SHADER_MAX_VERTEXES][4] QALIGN(16); + int16_t tangent[SHADER_MAX_VERTEXES][4] QALIGN(16); + vec2_t texCoords[SHADER_MAX_VERTEXES] QALIGN(16); + vec2_t lightCoords[SHADER_MAX_VERTEXES] QALIGN(16); + uint16_t color[SHADER_MAX_VERTEXES][4] QALIGN(16); + int16_t lightdir[SHADER_MAX_VERTEXES][4] QALIGN(16); //int vertexDlightBits[SHADER_MAX_VERTEXES] QALIGN(16); void *attribPointers[ATTR_INDEX_COUNT]; vao_t *vao; qboolean useInternalVao; + qboolean useCacheVao; stageVars_t svars QALIGN(16); //color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16); shader_t *shader; - float shaderTime; + double shaderTime; int fogNum; int cubemapIndex; @@ -2035,14 +2044,6 @@ typedef struct shaderCommands_s int firstIndex; int numIndexes; int numVertexes; - glIndex_t minIndex; - glIndex_t maxIndex; - - int multiDrawPrimitives; - GLsizei multiDrawNumIndexes[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t *multiDrawFirstIndex[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t multiDrawMinIndex[MAX_MULTIDRAW_PRIMITIVES]; - glIndex_t multiDrawMaxIndex[MAX_MULTIDRAW_PRIMITIVES]; // info extracted from current shader int numPasses; @@ -2057,7 +2058,7 @@ void RB_EndSurface(void); void RB_CheckOverflow( int verts, int indexes ); #define RB_CHECKOVERFLOW(v,i) if (tess.numVertexes + (v) >= SHADER_MAX_VERTEXES || tess.numIndexes + (i) >= SHADER_MAX_INDEXES ) {RB_CheckOverflow(v,i);} -void R_DrawElementsVao( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ); +void R_DrawElements( int numIndexes, int firstIndex ); void RB_StageIteratorGeneric( void ); void RB_StageIteratorSky( void ); void RB_StageIteratorVertexLitTexture( void ); @@ -2151,11 +2152,10 @@ CURVE TESSELATION #define PATCH_STITCHING -srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, +void R_SubdividePatchToGrid( srfBspSurface_t *grid, int width, int height, srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); -srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ); -srfBspSurface_t *R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ); -void R_FreeSurfaceGridMesh( srfBspSurface_t *grid ); +void R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ); +void R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ); /* ============================================================ @@ -2177,12 +2177,11 @@ VERTEX BUFFER OBJECTS ============================================================ */ -int R_VaoPackTangent(byte *out, vec4_t v); -int R_VaoPackNormal(byte *out, vec3_t v); -int R_VaoPackTexCoord(byte *out, vec2_t st); -int R_VaoPackColors(byte *out, vec4_t color); -void R_VaoUnpackTangent(vec4_t v, uint32_t b); -void R_VaoUnpackNormal(vec3_t v, uint32_t b); +void R_VaoPackTangent(int16_t *out, vec4_t v); +void R_VaoPackNormal(int16_t *out, vec3_t v); +void R_VaoPackColor(uint16_t *out, vec4_t c); +void R_VaoUnpackTangent(vec4_t v, int16_t *pack); +void R_VaoUnpackNormal(vec3_t v, int16_t *pack); vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *indexes, int indexesSize, vaoUsage_t usage); vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int numIndexes, glIndex_t *inIndexes); @@ -2198,6 +2197,14 @@ void R_VaoList_f(void); void RB_UpdateTessVao(unsigned int attribBits); +void VaoCache_Commit(void); +void VaoCache_Init(void); +void VaoCache_BindVao(void); +void VaoCache_CheckAdd(qboolean *endSurface, qboolean *recycleVertexBuffer, qboolean *recycleIndexBuffer, int numVerts, int numIndexes); +void VaoCache_RecycleVertexBuffer(void); +void VaoCache_RecycleIndexBuffer(void); +void VaoCache_InitQueue(void); +void VaoCache_AddSurface(srfVert_t *verts, int numVerts, glIndex_t *indexes, int numIndexes); /* ============================================================ @@ -2219,6 +2226,7 @@ void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v); void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v); void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix); +void GLSL_SetUniformMat4BoneMatrix(shaderProgram_t *program, int uniformNum, /*const*/ mat4_t *matrix, int numMatricies); shaderProgram_t *GLSL_GetGenericShaderProgram(int stage); @@ -2273,6 +2281,7 @@ void RB_MDRSurfaceAnim( mdrSurface_t *surface ); qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name ); void R_AddIQMSurfaces( trRefEntity_t *ent ); void RB_IQMSurfaceAnim( surfaceType_t *surface ); +void RB_IQMSurfaceAnimVao( srfVaoIQModel_t *surface ); int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, int startFrame, int endFrame, float frac, const char *tagName ); diff --git a/code/renderergl2/tr_main.c b/code/renderergl2/tr_main.c index bd27018b..02f7d489 100644 --- a/code/renderergl2/tr_main.c +++ b/code/renderergl2/tr_main.c @@ -70,230 +70,11 @@ qboolean R_CompareVert(srfVert_t * v1, srfVert_t * v2, qboolean checkST) /* ============= -R_CalcNormalForTriangle +R_CalcTexDirs + +Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html ============= */ -void R_CalcNormalForTriangle(vec3_t normal, const vec3_t v0, const vec3_t v1, const vec3_t v2) -{ - vec3_t udir, vdir; - - // compute the face normal based on vertex points - VectorSubtract(v2, v0, udir); - VectorSubtract(v1, v0, vdir); - CrossProduct(udir, vdir, normal); - - VectorNormalize(normal); -} - -/* -============= -R_CalcTangentsForTriangle -http://members.rogers.com/deseric/tangentspace.htm -============= -*/ -void R_CalcTangentsForTriangle(vec3_t tangent, vec3_t bitangent, - const vec3_t v0, const vec3_t v1, const vec3_t v2, - const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - int i; - vec3_t planes[3]; - vec3_t u, v; - - for(i = 0; i < 3; i++) - { - VectorSet(u, v1[i] - v0[i], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[i] - v0[i], t2[0] - t0[0], t2[1] - t0[1]); - - VectorNormalize(u); - VectorNormalize(v); - - CrossProduct(u, v, planes[i]); - } - - //So your tangent space will be defined by this : - //Normal = Normal of the triangle or Tangent X Bitangent (careful with the cross product, - // you have to make sure the normal points in the right direction) - //Tangent = ( dp(Fx(s,t)) / ds, dp(Fy(s,t)) / ds, dp(Fz(s,t)) / ds ) or ( -Bx/Ax, -By/Ay, - Bz/Az ) - //Bitangent = ( dp(Fx(s,t)) / dt, dp(Fy(s,t)) / dt, dp(Fz(s,t)) / dt ) or ( -Cx/Ax, -Cy/Ay, -Cz/Az ) - - // tangent... - tangent[0] = -planes[0][1] / planes[0][0]; - tangent[1] = -planes[1][1] / planes[1][0]; - tangent[2] = -planes[2][1] / planes[2][0]; - VectorNormalize(tangent); - - // bitangent... - bitangent[0] = -planes[0][2] / planes[0][0]; - bitangent[1] = -planes[1][2] / planes[1][0]; - bitangent[2] = -planes[2][2] / planes[2][0]; - VectorNormalize(bitangent); -} - - - - -/* -============= -R_CalcTangentSpace -============= -*/ -void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - vec3_t cp, u, v; - vec3_t faceNormal; - - VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]); - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[0] = -cp[1] / cp[0]; - bitangent[0] = -cp[2] / cp[0]; - } - - u[0] = v1[1] - v0[1]; - v[0] = v2[1] - v0[1]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[1] = -cp[1] / cp[0]; - bitangent[1] = -cp[2] / cp[0]; - } - - u[0] = v1[2] - v0[2]; - v[0] = v2[2] - v0[2]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[2] = -cp[1] / cp[0]; - bitangent[2] = -cp[2] / cp[0]; - } - - VectorNormalize(tangent); - VectorNormalize(bitangent); - - // compute the face normal based on vertex points - if ( normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f ) - { - VectorSubtract(v2, v0, u); - VectorSubtract(v1, v0, v); - CrossProduct(u, v, faceNormal); - } - else - { - VectorCopy(normal, faceNormal); - } - - VectorNormalize(faceNormal); - -#if 1 - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent); - VectorNormalize(tangent); - - // compute the cross product B=NxT - //CrossProduct(normal, tangent, bitangent); -#else - // normal, compute the cross product N=TxB - CrossProduct(tangent, bitangent, normal); - VectorNormalize(normal); - - if(DotProduct(normal, faceNormal) < 0) - { - //VectorInverse(normal); - //VectorInverse(tangent); - //VectorInverse(bitangent); - - // compute the cross product T=BxN - CrossProduct(bitangent, faceNormal, tangent); - - // compute the cross product B=NxT - //CrossProduct(normal, tangent, bitangent); - } -#endif - - VectorCopy(faceNormal, normal); -} - -void R_CalcTangentSpaceFast(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - vec3_t cp, u, v; - vec3_t faceNormal; - - VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]); - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[0] = -cp[1] / cp[0]; - bitangent[0] = -cp[2] / cp[0]; - } - - u[0] = v1[1] - v0[1]; - v[0] = v2[1] - v0[1]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[1] = -cp[1] / cp[0]; - bitangent[1] = -cp[2] / cp[0]; - } - - u[0] = v1[2] - v0[2]; - v[0] = v2[2] - v0[2]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[2] = -cp[1] / cp[0]; - bitangent[2] = -cp[2] / cp[0]; - } - - VectorNormalizeFast(tangent); - VectorNormalizeFast(bitangent); - - // compute the face normal based on vertex points - VectorSubtract(v2, v0, u); - VectorSubtract(v1, v0, v); - CrossProduct(u, v, faceNormal); - - VectorNormalizeFast(faceNormal); - -#if 0 - // normal, compute the cross product N=TxB - CrossProduct(tangent, bitangent, normal); - VectorNormalizeFast(normal); - - if(DotProduct(normal, faceNormal) < 0) - { - VectorInverse(normal); - //VectorInverse(tangent); - //VectorInverse(bitangent); - - CrossProduct(normal, tangent, bitangent); - } - - VectorCopy(faceNormal, normal); -#else - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent); - VectorNormalizeFast(tangent); -#endif - - VectorCopy(faceNormal, normal); -} - -/* -http://www.terathon.com/code/tangent.html -*/ void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3) { @@ -312,13 +93,21 @@ void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2, t1 = w2[1] - w1[1]; t2 = w3[1] - w1[1]; - r = 1.0f / (s1 * t2 - s2 * t1); + r = s1 * t2 - s2 * t1; + if (r) r = 1.0f / r; VectorSet(sdir, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); VectorSet(tdir, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); } -void R_CalcTbnFromNormalAndTexDirs(vec3_t tangent, vec3_t bitangent, vec3_t normal, vec3_t sdir, vec3_t tdir) +/* +============= +R_CalcTangentSpace + +Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html +============= +*/ +vec_t R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, const vec3_t normal, const vec3_t sdir, const vec3_t tdir) { vec3_t n_cross_t; vec_t n_dot_t, handedness; @@ -332,114 +121,13 @@ void R_CalcTbnFromNormalAndTexDirs(vec3_t tangent, vec3_t bitangent, vec3_t norm CrossProduct(normal, sdir, n_cross_t); handedness = (DotProduct(n_cross_t, tdir) < 0.0f) ? -1.0f : 1.0f; - // Calculate bitangent - CrossProduct(normal, tangent, bitangent); - VectorScale(bitangent, handedness, bitangent); + // Calculate orthogonal bitangent, if necessary + if (bitangent) + CrossProduct(normal, tangent, bitangent); + + return handedness; } -void R_CalcTBN2(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t t1, const vec2_t t2, const vec2_t t3) -{ - vec3_t v2v1; - vec3_t v3v1; - - float c2c1_T; - float c2c1_B; - - float c3c1_T; - float c3c1_B; - - float denominator; - float scale1, scale2; - - vec3_t T, B, N, C; - - - // Calculate the tangent basis for each vertex of the triangle - // UPDATE: In the 3rd edition of the accompanying article, the for-loop located here has - // been removed as it was redundant (the entire TBN matrix was calculated three times - // instead of just one). - // - // Please note, that this function relies on the fact that the input geometry are triangles - // and the tangent basis for each vertex thus is identical! - // - - // Calculate the vectors from the current vertex to the two other vertices in the triangle - VectorSubtract(v2, v1, v2v1); - VectorSubtract(v3, v1, v3v1); - - // The equation presented in the article states that: - // c2c1_T = V2.texcoord.x - V1.texcoord.x - // c2c1_B = V2.texcoord.y - V1.texcoord.y - // c3c1_T = V3.texcoord.x - V1.texcoord.x - // c3c1_B = V3.texcoord.y - V1.texcoord.y - - // Calculate c2c1_T and c2c1_B - c2c1_T = t2[0] - t1[0]; - c2c1_B = t2[1] - t2[1]; - - // Calculate c3c1_T and c3c1_B - c3c1_T = t3[0] - t1[0]; - c3c1_B = t3[1] - t1[1]; - - denominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B; - //if(ROUNDOFF(fDenominator) == 0.0f) - if(denominator == 0.0f) - { - // We won't risk a divide by zero, so set the tangent matrix to the identity matrix - VectorSet(tangent, 1, 0, 0); - VectorSet(bitangent, 0, 1, 0); - VectorSet(normal, 0, 0, 1); - } - else - { - // Calculate the reciprocal value once and for all (to achieve speed) - scale1 = 1.0f / denominator; - - // T and B are calculated just as the equation in the article states - VectorSet(T, (c3c1_B * v2v1[0] - c2c1_B * v3v1[0]) * scale1, - (c3c1_B * v2v1[1] - c2c1_B * v3v1[1]) * scale1, - (c3c1_B * v2v1[2] - c2c1_B * v3v1[2]) * scale1); - - VectorSet(B, (-c3c1_T * v2v1[0] + c2c1_T * v3v1[0]) * scale1, - (-c3c1_T * v2v1[1] + c2c1_T * v3v1[1]) * scale1, - (-c3c1_T * v2v1[2] + c2c1_T * v3v1[2]) * scale1); - - // The normal N is calculated as the cross product between T and B - CrossProduct(T, B, N); - -#if 0 - VectorCopy(T, tangent); - VectorCopy(B, bitangent); - VectorCopy(N, normal); -#else - // Calculate the reciprocal value once and for all (to achieve speed) - scale2 = 1.0f / ((T[0] * B[1] * N[2] - T[2] * B[1] * N[0]) + - (B[0] * N[1] * T[2] - B[2] * N[1] * T[0]) + - (N[0] * T[1] * B[2] - N[2] * T[1] * B[0])); - - // Calculate the inverse if the TBN matrix using the formula described in the article. - // We store the basis vectors directly in the provided TBN matrix: pvTBNMatrix - CrossProduct(B, N, C); tangent[0] = C[0] * scale2; - CrossProduct(N, T, C); tangent[1] = -C[0] * scale2; - CrossProduct(T, B, C); tangent[2] = C[0] * scale2; - VectorNormalize(tangent); - - CrossProduct(B, N, C); bitangent[0] = -C[1] * scale2; - CrossProduct(N, T, C); bitangent[1] = C[1] * scale2; - CrossProduct(T, B, C); bitangent[2] = -C[1] * scale2; - VectorNormalize(bitangent); - - CrossProduct(B, N, C); normal[0] = C[2] * scale2; - CrossProduct(N, T, C); normal[1] = -C[2] * scale2; - CrossProduct(T, B, C); normal[2] = C[2] * scale2; - VectorNormalize(normal); -#endif - } -} - - -#ifdef USE_VERT_TANGENT_SPACE qboolean R_CalcTangentVectors(srfVert_t * dv[3]) { int i; @@ -455,7 +143,8 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3]) /* do each vertex */ for(i = 0; i < 3; i++) { - vec3_t bitangent, nxt; + vec4_t tangent; + vec3_t normal, bitangent, nxt; // calculate s tangent vector s = dv[i]->st[0] + 10.0f; @@ -464,12 +153,12 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3]) bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb; bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb; - dv[i]->tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; - dv[i]->tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; - dv[i]->tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; + tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; + tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; + tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; - VectorSubtract(dv[i]->tangent, dv[i]->xyz, dv[i]->tangent); - VectorNormalize(dv[i]->tangent); + VectorSubtract(tangent, dv[i]->xyz, tangent); + VectorNormalize(tangent); // calculate t tangent vector s = dv[i]->st[0]; @@ -486,8 +175,11 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3]) VectorNormalize(bitangent); // store bitangent handedness - CrossProduct(dv[i]->normal, dv[i]->tangent, nxt); - dv[i]->tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f; + R_VaoUnpackNormal(normal, dv[i]->normal); + CrossProduct(normal, tangent, nxt); + tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f; + + R_VaoPackTangent(dv[i]->tangent, tangent); // debug code //% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i, @@ -496,7 +188,6 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3]) return qtrue; } -#endif /* @@ -1642,8 +1333,8 @@ qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { return qfalse; // bad portal, no portalentity } - if (newParms.isMirror) - newParms.flags |= VPF_NOVIEWMODEL; + // Never draw viewmodels in portal or mirror views. + newParms.flags |= VPF_NOVIEWMODEL; R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); @@ -2024,6 +1715,9 @@ Visualization aid for movement clipping debugging ==================== */ void R_DebugGraphics( void ) { + if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { + return; + } if ( !r_debugSurface->integer ) { return; } @@ -2362,7 +2056,7 @@ void R_RenderPshadowMaps(const refdef_t *fd) VectorScale(lightDir, -1.0f, shadow->lightViewAxis[0]); VectorSet(up, 0, 0, -1); - if ( abs(DotProduct(up, shadow->lightViewAxis[0])) > 0.9f ) + if ( fabsf(DotProduct(up, shadow->lightViewAxis[0])) > 0.9f ) { VectorSet(up, -1, 0, 0); } @@ -2407,7 +2101,7 @@ void R_RenderPshadowMaps(const refdef_t *fd) if (glRefConfig.framebufferObject) shadowParms.targetFbo = tr.pshadowFbos[i]; - shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL; + shadowParms.flags = VPF_DEPTHSHADOW | VPF_NOVIEWMODEL; shadowParms.zFar = shadow->lightRadius; VectorCopy(shadow->lightOrigin, shadowParms.or.origin); @@ -2605,7 +2299,7 @@ void R_RenderSunShadowMaps(const refdef_t *fd, int level) } // Check if too close to parallel to light direction - if (abs(DotProduct(lightViewAxis[2], lightViewAxis[0])) > 0.9f) + if (fabsf(DotProduct(lightViewAxis[2], lightViewAxis[0])) > 0.9f) { if (level == 3 || lightViewIndependentOfCameraView) { @@ -2858,7 +2552,6 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene ) { refdef_t refdef; viewParms_t parms; - float oldColorScale = tr.refdef.colorScale; memset( &refdef, 0, sizeof( refdef ) ); refdef.rdflags = 0; @@ -2931,12 +2624,15 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene ) { vec3_t ambient, directed, lightDir; + float scale; + R_LightForPoint(tr.refdef.vieworg, ambient, directed, lightDir); - tr.refdef.colorScale = 1.0f; //766.0f / (directed[0] + directed[1] + directed[2] + 1.0f); + scale = directed[0] + directed[1] + directed[2] + ambient[0] + ambient[1] + ambient[2] + 1.0f; + // only print message for first side - if (directed[0] + directed[1] + directed[2] == 0 && cubemapSide == 0) + if (scale < 1.0001f && cubemapSide == 0) { - ri.Printf(PRINT_ALL, "cubemap %d %s (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, tr.cubemaps[cubemapIndex].name, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]); + ri.Printf(PRINT_ALL, "cubemap %d %s (%f, %f, %f) is outside the lightgrid or inside a wall!\n", cubemapIndex, tr.cubemaps[cubemapIndex].name, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]); } } @@ -2973,12 +2669,6 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene ) R_RenderView(&parms); - if (subscene) - { - tr.refdef.colorScale = oldColorScale; - } - else - { + if (!subscene) RE_EndScene(); - } } diff --git a/code/renderergl2/tr_marks.c b/code/renderergl2/tr_marks.c index 830d4d29..682c13d8 100644 --- a/code/renderergl2/tr_marks.c +++ b/code/renderergl2/tr_marks.c @@ -350,17 +350,21 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio // The offset is added in the vertex normal vector direction // so all triangles will still fit together. // The 2 unit offset should avoid pretty much all LOD problems. + vec3_t fNormal; numClipPoints = 3; dv = cv->verts + m * cv->width + n; VectorCopy(dv[0].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0]); + R_VaoUnpackNormal(fNormal, dv[0].normal); + VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); + R_VaoUnpackNormal(fNormal, dv[cv->width].normal); + VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]); VectorCopy(dv[1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2]); + R_VaoUnpackNormal(fNormal, dv[1].normal); + VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); @@ -380,11 +384,14 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio } VectorCopy(dv[1].xyz, clipPoints[0][0]); - VectorMA(clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0]); + R_VaoUnpackNormal(fNormal, dv[1].normal); + VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]); VectorCopy(dv[cv->width].xyz, clipPoints[0][1]); - VectorMA(clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1]); + R_VaoUnpackNormal(fNormal, dv[cv->width].normal); + VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]); VectorCopy(dv[cv->width+1].xyz, clipPoints[0][2]); - VectorMA(clipPoints[0][2], MARKER_OFFSET, dv[cv->width+1].normal, clipPoints[0][2]); + R_VaoUnpackNormal(fNormal, dv[cv->width + 1].normal); + VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]); // check the normal of this triangle VectorSubtract(clipPoints[0][0], clipPoints[0][1], v1); VectorSubtract(clipPoints[0][2], clipPoints[0][1], v2); @@ -441,8 +448,10 @@ int R_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projectio { for(j = 0; j < 3; j++) { + vec3_t fNormal; v = surf->verts[tri[j]].xyz; - VectorMA(v, MARKER_OFFSET, surf->verts[tri[j]].normal, clipPoints[0][j]); + R_VaoUnpackNormal(fNormal, surf->verts[tri[j]].normal); + VectorMA(v, MARKER_OFFSET, fNormal, clipPoints[0][j]); } // add the fragments of this face diff --git a/code/renderergl2/tr_mesh.c b/code/renderergl2/tr_mesh.c index 0d6844a4..4f2c6724 100644 --- a/code/renderergl2/tr_mesh.c +++ b/code/renderergl2/tr_mesh.c @@ -365,8 +365,8 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { shader = tr.defaultShader; for ( j = 0 ; j < skin->numSurfaces ; j++ ) { // the names have both been lowercased - if ( !strcmp( skin->surfaces[j]->name, surface->name ) ) { - shader = skin->surfaces[j]->shader; + if ( !strcmp( skin->surfaces[j].name, surface->name ) ) { + shader = skin->surfaces[j].shader; break; } } @@ -376,21 +376,34 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { else if (shader->defaultShader) { ri.Printf( PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name); } - //} else if ( surface->numShaders <= 0 ) { - //shader = tr.defaultShader; + } else if ( surface->numShaderIndexes <= 0 ) { + shader = tr.defaultShader; } else { - //md3Shader = (md3Shader_t *) ( (byte *)surface + surface->ofsShaders ); - //md3Shader += ent->e.skinNum % surface->numShaders; - //shader = tr.shaders[ md3Shader->shaderIndex ]; shader = tr.shaders[ surface->shaderIndexes[ ent->e.skinNum % surface->numShaderIndexes ] ]; } - // don't add third_person objects if not viewing through a portal - if(!personalModel) - { - srfVaoMdvMesh_t *vaoSurface = &model->vaoSurfaces[i]; + // we will add shadows even if the main object isn't visible in the view - R_AddDrawSurf((void *)vaoSurface, shader, fogNum, qfalse, qfalse, cubemapIndex ); + // stencil shadows can't do personal models unless I polyhedron clip + if ( !personalModel + && r_shadows->integer == 2 + && fogNum == 0 + && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) + && shader->sort == SS_OPAQUE ) { + R_AddDrawSurf( (void *)&model->vaoSurfaces[i], tr.shadowShader, 0, qfalse, qfalse, 0 ); + } + + // projection shadows work fine with personal models + if ( r_shadows->integer == 3 + && fogNum == 0 + && (ent->e.renderfx & RF_SHADOW_PLANE ) + && shader->sort == SS_OPAQUE ) { + R_AddDrawSurf( (void *)&model->vaoSurfaces[i], tr.projectionShadowShader, 0, qfalse, qfalse, 0 ); + } + + // don't add third_person objects if not viewing through a portal + if ( !personalModel ) { + R_AddDrawSurf((void *)&model->vaoSurfaces[i], shader, fogNum, qfalse, qfalse, cubemapIndex ); } surface++; diff --git a/code/renderergl2/tr_model.c b/code/renderergl2/tr_model.c index 897e202e..0fdf60d8 100644 --- a/code/renderergl2/tr_model.c +++ b/code/renderergl2/tr_model.c @@ -564,6 +564,7 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, { unsigned lat, lng; unsigned short normal; + vec3_t fNormal; v->xyz[0] = LittleShort(md3xyz->xyz[0]) * MD3_XYZ_SCALE; v->xyz[1] = LittleShort(md3xyz->xyz[1]) * MD3_XYZ_SCALE; @@ -580,9 +581,11 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, // decode Y as sin( lat ) * sin( long ) // decode Z as cos( long ) - v->normal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - v->normal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - v->normal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + fNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + fNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; + fNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + + R_VaoPackNormal(v->normal, fNormal); } // swap all the ST @@ -595,13 +598,15 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, st->st[1] = LittleFloat(md3st->st[1]); } -#ifdef USE_VERT_TANGENT_SPACE // calc tangent spaces { + vec3_t *sdirs = ri.Malloc(sizeof(*sdirs) * surf->numVerts * mdvModel->numFrames); + vec3_t *tdirs = ri.Malloc(sizeof(*tdirs) * surf->numVerts * mdvModel->numFrames); + for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++) { - VectorClear(v->tangent); - VectorClear(v->bitangent); + VectorClear(sdirs[j]); + VectorClear(tdirs[j]); } for(f = 0; f < mdvModel->numFrames; f++) @@ -626,29 +631,33 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, R_CalcTexDirs(sdir, tdir, v0, v1, v2, t0, t1, t2); - VectorAdd(sdir, surf->verts[index0].tangent, surf->verts[index0].tangent); - VectorAdd(sdir, surf->verts[index1].tangent, surf->verts[index1].tangent); - VectorAdd(sdir, surf->verts[index2].tangent, surf->verts[index2].tangent); - VectorAdd(tdir, surf->verts[index0].bitangent, surf->verts[index0].bitangent); - VectorAdd(tdir, surf->verts[index1].bitangent, surf->verts[index1].bitangent); - VectorAdd(tdir, surf->verts[index2].bitangent, surf->verts[index2].bitangent); + VectorAdd(sdir, sdirs[index0], sdirs[index0]); + VectorAdd(sdir, sdirs[index1], sdirs[index1]); + VectorAdd(sdir, sdirs[index2], sdirs[index2]); + VectorAdd(tdir, tdirs[index0], tdirs[index0]); + VectorAdd(tdir, tdirs[index1], tdirs[index1]); + VectorAdd(tdir, tdirs[index2], tdirs[index2]); } } for(j = 0, v = surf->verts; j < (surf->numVerts * mdvModel->numFrames); j++, v++) { - vec3_t sdir, tdir; + vec3_t normal; + vec4_t tangent; - VectorCopy(v->tangent, sdir); - VectorCopy(v->bitangent, tdir); + VectorNormalize(sdirs[j]); + VectorNormalize(tdirs[j]); - VectorNormalize(sdir); - VectorNormalize(tdir); + R_VaoUnpackNormal(normal, v->normal); - R_CalcTbnFromNormalAndTexDirs(v->tangent, v->bitangent, v->normal, sdir, tdir); + tangent[3] = R_CalcTangentSpace(tangent, NULL, normal, sdirs[j], tdirs[j]); + + R_VaoPackTangent(v->tangent, tangent); } + + ri.Free(sdirs); + ri.Free(tdirs); } -#endif // find the next surface md3Surf = (md3Surface_t *) ((byte *) md3Surf + md3Surf->ofsEnd); @@ -674,14 +683,12 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, { // vertex animation, store texcoords first, then position/normal/tangents offset_st = 0; - offset_xyz = surf->numVerts * glRefConfig.packedTexcoordDataSize; + offset_xyz = surf->numVerts * sizeof(vec2_t); offset_normal = offset_xyz + sizeof(vec3_t); - offset_tangent = offset_normal + sizeof(uint32_t); - stride_st = glRefConfig.packedTexcoordDataSize; - stride_xyz = sizeof(vec3_t) + sizeof(uint32_t); -#ifdef USE_VERT_TANGENT_SPACE - stride_xyz += sizeof(uint32_t); -#endif + offset_tangent = offset_normal + sizeof(int16_t) * 4; + stride_st = sizeof(vec2_t); + stride_xyz = sizeof(vec3_t) + sizeof(int16_t) * 4; + stride_xyz += sizeof(int16_t) * 4; stride_normal = stride_tangent = stride_xyz; dataSize = offset_xyz + surf->numVerts * mdvModel->numFrames * stride_xyz; @@ -691,13 +698,9 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, // no animation, interleave everything offset_xyz = 0; offset_st = offset_xyz + sizeof(vec3_t); - offset_normal = offset_st + glRefConfig.packedTexcoordDataSize; - offset_tangent = offset_normal + sizeof(uint32_t); -#ifdef USE_VERT_TANGENT_SPACE - stride_xyz = offset_tangent + sizeof(uint32_t); -#else - stride_xyz = offset_normal + sizeof(uint32_t); -#endif + offset_normal = offset_st + sizeof(vec2_t); + offset_tangent = offset_normal + sizeof(int16_t) * 4; + stride_xyz = offset_tangent + sizeof(int16_t) * 4; stride_st = stride_normal = stride_tangent = stride_xyz; dataSize = surf->numVerts * stride_xyz; @@ -711,31 +714,24 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, { st = surf->st; for ( j = 0 ; j < surf->numVerts ; j++, st++ ) { - dataOfs += R_VaoPackTexCoord(data + dataOfs, st->st); + memcpy(data + dataOfs, &st->st, sizeof(vec2_t)); + dataOfs += sizeof(st->st); } v = surf->verts; for ( j = 0; j < surf->numVerts * mdvModel->numFrames ; j++, v++ ) { -#ifdef USE_VERT_TANGENT_SPACE - vec3_t nxt; - vec4_t tangent; -#endif // xyz memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t)); dataOfs += sizeof(vec3_t); // normal - dataOfs += R_VaoPackNormal(data + dataOfs, v->normal); - -#ifdef USE_VERT_TANGENT_SPACE - CrossProduct(v->normal, v->tangent, nxt); - VectorCopy(v->tangent, tangent); - tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f; + memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4); + dataOfs += sizeof(int16_t) * 4; // tangent - dataOfs += R_VaoPackTangent(data + dataOfs, tangent); -#endif + memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4); + dataOfs += sizeof(int16_t) * 4; } } else @@ -744,28 +740,21 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, st = surf->st; for ( j = 0; j < surf->numVerts; j++, v++, st++ ) { -#ifdef USE_VERT_TANGENT_SPACE - vec3_t nxt; - vec4_t tangent; -#endif // xyz memcpy(data + dataOfs, &v->xyz, sizeof(vec3_t)); dataOfs += sizeof(v->xyz); // st - dataOfs += R_VaoPackTexCoord(data + dataOfs, st->st); + memcpy(data + dataOfs, &st->st, sizeof(vec2_t)); + dataOfs += sizeof(st->st); // normal - dataOfs += R_VaoPackNormal(data + dataOfs, v->normal); - -#ifdef USE_VERT_TANGENT_SPACE - CrossProduct(v->normal, v->tangent, nxt); - VectorCopy(v->tangent, tangent); - tangent[3] = (DotProduct(nxt, v->bitangent) < 0.0f) ? -1.0f : 1.0f; + memcpy(data + dataOfs, &v->normal, sizeof(int16_t) * 4); + dataOfs += sizeof(int16_t) * 4; // tangent - dataOfs += R_VaoPackTangent(data + dataOfs, tangent); -#endif + memcpy(data + dataOfs, &v->tangent, sizeof(int16_t) * 4); + dataOfs += sizeof(int16_t) * 4; } } @@ -775,17 +764,12 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, vaoSurf->numIndexes = surf->numIndexes; vaoSurf->numVerts = surf->numVerts; - vaoSurf->minIndex = 0; - vaoSurf->maxIndex = surf->numVerts - 1; - vaoSurf->vao = R_CreateVao(va("staticMD3Mesh_VAO '%s'", surf->name), data, dataSize, (byte *)surf->indexes, surf->numIndexes * sizeof(*surf->indexes), VAO_USAGE_STATIC); vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1; vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1; vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; -#ifdef USE_VERT_TANGENT_SPACE vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; -#endif vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3; vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2; @@ -793,9 +777,9 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4; vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT; - vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = glRefConfig.packedTexcoordDataType; - vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; - vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT; vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE; vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE; diff --git a/code/renderergl2/tr_model_iqm.c b/code/renderergl2/tr_model_iqm.c index 3cabca00..1a6e1e5a 100644 --- a/code/renderergl2/tr_model_iqm.c +++ b/code/renderergl2/tr_model_iqm.c @@ -33,11 +33,11 @@ static float identityMatrix[12] = { }; static qboolean IQM_CheckRange( iqmHeader_t *header, int offset, - int count,int size ) { + int count, int size ) { // return true if the range specified by offset, count and size // doesn't fit into the file return ( count <= 0 || - offset < 0 || + offset <= 0 || offset > header->filesize || offset + count * size < 0 || offset + count * size > header->filesize ); @@ -58,11 +58,6 @@ static void Matrix34Multiply( float *a, float *b, float *out ) { out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10]; out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; } -static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) { - out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; - out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; - out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; -} static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) { float unLerp = 1.0f - lerp; @@ -108,7 +103,7 @@ static void Matrix34Invert( float *inMat, float *outMat ) { vec3_t trans; float invSqrLen, *v; - + outMat[ 0] = inMat[ 0]; outMat[ 1] = inMat[ 4]; outMat[ 2] = inMat[ 8]; outMat[ 4] = inMat[ 1]; outMat[ 5] = inMat[ 5]; outMat[ 6] = inMat[ 9]; outMat[ 8] = inMat[ 2]; outMat[ 9] = inMat[ 6]; outMat[10] = inMat[10]; @@ -143,14 +138,21 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmBounds_t *bounds; unsigned short *framedata; char *str; - int i, j; + int i, j, k; float jointInvMats[IQM_MAX_JOINTS * 12] = {0.0f}; float *mat, *matInv; size_t size, joint_names; + byte *dataPtr; iqmData_t *iqmData; srfIQModel_t *surface; char meshName[MAX_QPATH]; - byte blendIndexesType, blendWeightsType; + int vertexArrayFormat[IQM_COLOR+1]; + int allocateInfluences; + byte *blendIndexes; + union { + byte *b; + float *f; + } blendWeights; if( filesize < sizeof(iqmHeader_t) ) { return qfalse; @@ -206,164 +208,235 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na return qfalse; } - blendIndexesType = blendWeightsType = IQM_UBYTE; - - // check and swap vertex arrays - if( IQM_CheckRange( header, header->ofs_vertexarrays, - header->num_vertexarrays, - sizeof(iqmVertexArray_t) ) ) { - return qfalse; + for ( i = 0; i < ARRAY_LEN( vertexArrayFormat ); i++ ) { + vertexArrayFormat[i] = -1; } - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n, *intPtr; - if( vertexarray->size <= 0 || vertexarray->size > 4 ) { + blendIndexes = NULL; + blendWeights.b = NULL; + + allocateInfluences = 0; + + if ( header->num_meshes ) + { + // check and swap vertex arrays + if( IQM_CheckRange( header, header->ofs_vertexarrays, + header->num_vertexarrays, + sizeof(iqmVertexArray_t) ) ) { + return qfalse; + } + vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); + for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { + int n, *intPtr; + + if( vertexarray->size <= 0 || vertexarray->size > 4 ) { + return qfalse; + } + + // total number of values + n = header->num_vertexes * vertexarray->size; + + switch( vertexarray->format ) { + case IQM_BYTE: + case IQM_UBYTE: + // 1 byte, no swapping necessary + if( IQM_CheckRange( header, vertexarray->offset, + n, sizeof(byte) ) ) { + return qfalse; + } + break; + case IQM_INT: + case IQM_UINT: + case IQM_FLOAT: + // 4-byte swap + if( IQM_CheckRange( header, vertexarray->offset, + n, sizeof(float) ) ) { + return qfalse; + } + intPtr = (int *)((byte *)header + vertexarray->offset); + for( j = 0; j < n; j++, intPtr++ ) { + LL( *intPtr ); + } + break; + default: + // not supported + return qfalse; + break; + } + + if( vertexarray->type < ARRAY_LEN( vertexArrayFormat ) ) { + vertexArrayFormat[vertexarray->type] = vertexarray->format; + } + + switch( vertexarray->type ) { + case IQM_POSITION: + case IQM_NORMAL: + if( vertexarray->format != IQM_FLOAT || + vertexarray->size != 3 ) { + return qfalse; + } + break; + case IQM_TANGENT: + if( vertexarray->format != IQM_FLOAT || + vertexarray->size != 4 ) { + return qfalse; + } + break; + case IQM_TEXCOORD: + if( vertexarray->format != IQM_FLOAT || + vertexarray->size != 2 ) { + return qfalse; + } + break; + case IQM_BLENDINDEXES: + if( (vertexarray->format != IQM_INT && + vertexarray->format != IQM_UBYTE) || + vertexarray->size != 4 ) { + return qfalse; + } + blendIndexes = (byte*)header + vertexarray->offset; + break; + case IQM_BLENDWEIGHTS: + if( (vertexarray->format != IQM_FLOAT && + vertexarray->format != IQM_UBYTE) || + vertexarray->size != 4 ) { + return qfalse; + } + if( vertexarray->format == IQM_FLOAT ) { + blendWeights.f = (float*)( (byte*)header + vertexarray->offset ); + } else { + blendWeights.b = (byte*)header + vertexarray->offset; + } + break; + case IQM_COLOR: + if( vertexarray->format != IQM_UBYTE || + vertexarray->size != 4 ) { + return qfalse; + } + break; + } + } + + // check for required vertex arrays + if( vertexArrayFormat[IQM_POSITION] == -1 || vertexArrayFormat[IQM_NORMAL] == -1 || vertexArrayFormat[IQM_TEXCOORD] == -1 ) { + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_POSITION, IQM_NORMAL, and/or IQM_TEXCOORD array.\n", mod_name ); return qfalse; } - // total number of values - n = header->num_vertexes * vertexarray->size; - - switch( vertexarray->format ) { - case IQM_BYTE: - case IQM_UBYTE: - // 1 byte, no swapping necessary - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(byte) ) ) { + if( header->num_joints ) { + if( vertexArrayFormat[IQM_BLENDINDEXES] == -1 || vertexArrayFormat[IQM_BLENDWEIGHTS] == -1 ) { + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_BLENDINDEXES and/or IQM_BLENDWEIGHTS array.\n", mod_name ); return qfalse; } - break; - case IQM_INT: - case IQM_UINT: - case IQM_FLOAT: - // 4-byte swap - if( IQM_CheckRange( header, vertexarray->offset, - n, sizeof(float) ) ) { - return qfalse; - } - intPtr = (int *)((byte *)header + vertexarray->offset); - for( j = 0; j < n; j++, intPtr++ ) { - LL( *intPtr ); - } - break; - default: - // not supported - return qfalse; - break; - } - - switch( vertexarray->type ) { - case IQM_POSITION: - case IQM_NORMAL: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 3 ) { - return qfalse; - } - break; - case IQM_TANGENT: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 4 ) { - return qfalse; - } - break; - case IQM_TEXCOORD: - if( vertexarray->format != IQM_FLOAT || - vertexarray->size != 2 ) { - return qfalse; - } - break; - case IQM_BLENDINDEXES: - if( (vertexarray->format != IQM_INT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendIndexesType = vertexarray->format; - break; - case IQM_BLENDWEIGHTS: - if( (vertexarray->format != IQM_FLOAT && - vertexarray->format != IQM_UBYTE) || - vertexarray->size != 4 ) { - return qfalse; - } - blendWeightsType = vertexarray->format; - break; - case IQM_COLOR: - if( vertexarray->format != IQM_UBYTE || - vertexarray->size != 4 ) { - return qfalse; - } - break; - } - } - - // check and swap triangles - if( IQM_CheckRange( header, header->ofs_triangles, - header->num_triangles, sizeof(iqmTriangle_t) ) ) { - return qfalse; - } - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - LL( triangle->vertex[0] ); - LL( triangle->vertex[1] ); - LL( triangle->vertex[2] ); - - if( triangle->vertex[0] > header->num_vertexes || - triangle->vertex[1] > header->num_vertexes || - triangle->vertex[2] > header->num_vertexes ) { - return qfalse; - } - } - - // check and swap meshes - if( IQM_CheckRange( header, header->ofs_meshes, - header->num_meshes, sizeof(iqmMesh_t) ) ) { - return qfalse; - } - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - for( i = 0; i < header->num_meshes; i++, mesh++) { - LL( mesh->name ); - LL( mesh->material ); - LL( mesh->first_vertex ); - LL( mesh->num_vertexes ); - LL( mesh->first_triangle ); - LL( mesh->num_triangles ); - - if ( mesh->name < header->num_text ) { - Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); } else { - meshName[0] = '\0'; + // ignore blend arrays if present + vertexArrayFormat[IQM_BLENDINDEXES] = -1; + vertexArrayFormat[IQM_BLENDWEIGHTS] = -1; } - // check ioq3 limits - if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", - mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", - mesh->num_vertexes ); - return qfalse; - } - if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) - { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", - mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", - mesh->num_triangles ); + // opengl2 renderer requires tangents + if( vertexArrayFormat[IQM_TANGENT] == -1 ) { + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s is missing IQM_TANGENT array.\n", mod_name ); return qfalse; } - if( mesh->first_vertex >= header->num_vertexes || - mesh->first_vertex + mesh->num_vertexes > header->num_vertexes || - mesh->first_triangle >= header->num_triangles || - mesh->first_triangle + mesh->num_triangles > header->num_triangles || - mesh->name >= header->num_text || - mesh->material >= header->num_text ) { + // check and swap triangles + if( IQM_CheckRange( header, header->ofs_triangles, + header->num_triangles, sizeof(iqmTriangle_t) ) ) { return qfalse; } + triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); + for( i = 0; i < header->num_triangles; i++, triangle++ ) { + LL( triangle->vertex[0] ); + LL( triangle->vertex[1] ); + LL( triangle->vertex[2] ); + + if( triangle->vertex[0] > header->num_vertexes || + triangle->vertex[1] > header->num_vertexes || + triangle->vertex[2] > header->num_vertexes ) { + return qfalse; + } + } + + // check and swap meshes + if( IQM_CheckRange( header, header->ofs_meshes, + header->num_meshes, sizeof(iqmMesh_t) ) ) { + return qfalse; + } + mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); + for( i = 0; i < header->num_meshes; i++, mesh++) { + LL( mesh->name ); + LL( mesh->material ); + LL( mesh->first_vertex ); + LL( mesh->num_vertexes ); + LL( mesh->first_triangle ); + LL( mesh->num_triangles ); + + if ( mesh->name < header->num_text ) { + Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); + } else { + meshName[0] = '\0'; + } + + // check ioq3 limits + if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) { + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", + mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", + mesh->num_vertexes ); + return qfalse; + } + if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) { + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", + mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", + mesh->num_triangles ); + return qfalse; + } + + if( mesh->first_vertex >= header->num_vertexes || + mesh->first_vertex + mesh->num_vertexes > header->num_vertexes || + mesh->first_triangle >= header->num_triangles || + mesh->first_triangle + mesh->num_triangles > header->num_triangles || + mesh->name >= header->num_text || + mesh->material >= header->num_text ) { + return qfalse; + } + + // find number of unique blend influences per mesh + if( header->num_joints ) { + for( j = 0; j < mesh->num_vertexes; j++ ) { + int vtx = mesh->first_vertex + j; + + for( k = 0; k < j; k++ ) { + int influence = mesh->first_vertex + k; + + if( *(int*)&blendIndexes[4*influence] != *(int*)&blendIndexes[4*vtx] ) { + continue; + } + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + if ( blendWeights.f[4*influence+0] == blendWeights.f[4*vtx+0] && + blendWeights.f[4*influence+1] == blendWeights.f[4*vtx+1] && + blendWeights.f[4*influence+2] == blendWeights.f[4*vtx+2] && + blendWeights.f[4*influence+3] == blendWeights.f[4*vtx+3] ) { + break; + } + } else { + if ( *(int*)&blendWeights.b[4*influence] == *(int*)&blendWeights.b[4*vtx] ) { + break; + } + } + } + + if ( k == j ) { + allocateInfluences++; + } + } + } + } } if( header->num_poses != header->num_joints && header->num_poses != 0 ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", + ri.Printf( PRINT_WARNING, "R_LoadIQM: %s has %d poses and %d joints, must have the same number or 0 poses\n", mod_name, header->num_poses, header->num_joints ); return qfalse; } @@ -460,26 +533,44 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na // allocate the model and copy the data size = sizeof(iqmData_t); - size += header->num_meshes * sizeof( srfIQModel_t ); - size += header->num_joints * 12 * sizeof( float ); // joint mats - size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats - if(header->ofs_bounds) - size += header->num_frames * 6 * sizeof(float); // model bounds - size += header->num_vertexes * 3 * sizeof(float); // positions - size += header->num_vertexes * 2 * sizeof(float); // texcoords - size += header->num_vertexes * 3 * sizeof(float); // normals - size += header->num_vertexes * 4 * sizeof(float); // tangents - size += header->num_vertexes * 4 * sizeof(byte); // blendIndexes - size += header->num_vertexes * 4 * sizeof(byte); // colors - size += header->num_joints * sizeof(int); // parents - size += header->num_triangles * 3 * sizeof(int); // triangles - size += joint_names; // joint names + if( header->num_meshes ) { + size += header->num_meshes * sizeof( srfIQModel_t ); // surfaces + size += header->num_triangles * 3 * sizeof(int); // triangles + size += header->num_vertexes * 3 * sizeof(float); // positions + size += header->num_vertexes * 2 * sizeof(float); // texcoords + size += header->num_vertexes * 3 * sizeof(float); // normals - // blendWeights - if (blendWeightsType == IQM_FLOAT) { - size += header->num_vertexes * 4 * sizeof(float); - } else { - size += header->num_vertexes * 4 * sizeof(byte); + if ( vertexArrayFormat[IQM_TANGENT] != -1 ) { + size += header->num_vertexes * 4 * sizeof(float); // tangents + } + + if ( vertexArrayFormat[IQM_COLOR] != -1 ) { + size += header->num_vertexes * 4 * sizeof(byte); // colors + } + + if ( allocateInfluences ) { + size += header->num_vertexes * sizeof(int); // influences + size += allocateInfluences * 4 * sizeof(byte); // influenceBlendIndexes + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_UBYTE ) { + size += allocateInfluences * 4 * sizeof(byte); // influenceBlendWeights + } else if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + size += allocateInfluences * 4 * sizeof(float); // influenceBlendWeights + } + } + } + if( header->num_joints ) { + size += joint_names; // joint names + size += header->num_joints * sizeof(int); // joint parents + size += header->num_joints * 12 * sizeof( float ); // joint mats + } + if( header->num_poses ) { + size += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats + } + if( header->ofs_bounds ) { + size += header->num_frames * 6 * sizeof(float); // model bounds + } else if( header->num_meshes && header->num_frames == 0 ) { + size += 6 * sizeof(float); // model bounds } mod->type = MOD_IQM; @@ -487,234 +578,323 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na mod->modelData = iqmData; // fill header - iqmData->num_vertexes = header->num_vertexes; - iqmData->num_triangles = header->num_triangles; + iqmData->num_vertexes = ( header->num_meshes > 0 ) ? header->num_vertexes : 0; + iqmData->num_triangles = ( header->num_meshes > 0 ) ? header->num_triangles : 0; iqmData->num_frames = header->num_frames; iqmData->num_surfaces = header->num_meshes; iqmData->num_joints = header->num_joints; - iqmData->num_poses = header->num_poses; - iqmData->blendWeightsType = blendWeightsType; - iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); - iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); - iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; - if(header->ofs_bounds) + iqmData->num_poses = header->num_poses; + iqmData->blendWeightsType = vertexArrayFormat[IQM_BLENDWEIGHTS]; + + dataPtr = (byte*)iqmData + sizeof(iqmData_t); + if( header->num_meshes ) { + iqmData->surfaces = (struct srfIQModel_s*)dataPtr; + dataPtr += header->num_meshes * sizeof( srfIQModel_t ); + + iqmData->triangles = (int*)dataPtr; + dataPtr += header->num_triangles * 3 * sizeof(int); // triangles + + iqmData->positions = (float*)dataPtr; + dataPtr += header->num_vertexes * 3 * sizeof(float); // positions + + iqmData->texcoords = (float*)dataPtr; + dataPtr += header->num_vertexes * 2 * sizeof(float); // texcoords + + iqmData->normals = (float*)dataPtr; + dataPtr += header->num_vertexes * 3 * sizeof(float); // normals + + if ( vertexArrayFormat[IQM_TANGENT] != -1 ) { + iqmData->tangents = (float*)dataPtr; + dataPtr += header->num_vertexes * 4 * sizeof(float); // tangents + } + + if ( vertexArrayFormat[IQM_COLOR] != -1 ) { + iqmData->colors = (byte*)dataPtr; + dataPtr += header->num_vertexes * 4 * sizeof(byte); // colors + } + + if ( allocateInfluences ) { + iqmData->influences = (int*)dataPtr; + dataPtr += header->num_vertexes * sizeof(int); // influences + + iqmData->influenceBlendIndexes = (byte*)dataPtr; + dataPtr += allocateInfluences * 4 * sizeof(byte); // influenceBlendIndexes + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_UBYTE ) { + iqmData->influenceBlendWeights.b = (byte*)dataPtr; + dataPtr += allocateInfluences * 4 * sizeof(byte); // influenceBlendWeights + } else if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + iqmData->influenceBlendWeights.f = (float*)dataPtr; + dataPtr += allocateInfluences * 4 * sizeof(float); // influenceBlendWeights + } + } + } + if( header->num_joints ) { + iqmData->jointNames = (char*)dataPtr; + dataPtr += joint_names; // joint names + + iqmData->jointParents = (int*)dataPtr; + dataPtr += header->num_joints * sizeof(int); // joint parents + + iqmData->jointMats = (float*)dataPtr; + dataPtr += header->num_joints * 12 * sizeof( float ); // joint mats + } + if( header->num_poses ) { + iqmData->poseMats = (float*)dataPtr; + dataPtr += header->num_poses * header->num_frames * 12 * sizeof( float ); // pose mats + } + if( header->ofs_bounds ) { + iqmData->bounds = (float*)dataPtr; + dataPtr += header->num_frames * 6 * sizeof(float); // model bounds + } else if( header->num_meshes && header->num_frames == 0 ) { + iqmData->bounds = (float*)dataPtr; + dataPtr += 6 * sizeof(float); // model bounds + } + + if( header->num_meshes ) { - iqmData->bounds = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->positions = iqmData->bounds + 6 * header->num_frames; - } - else - iqmData->positions = iqmData->poseMats + 12 * header->num_poses * header->num_frames; - iqmData->texcoords = iqmData->positions + 3 * header->num_vertexes; - iqmData->normals = iqmData->texcoords + 2 * header->num_vertexes; - iqmData->tangents = iqmData->normals + 3 * header->num_vertexes; - iqmData->blendIndexes = (byte *)(iqmData->tangents + 4 * header->num_vertexes); - - if(blendWeightsType == IQM_FLOAT) { - iqmData->blendWeights.f = (float *)(iqmData->blendIndexes + 4 * header->num_vertexes); - iqmData->colors = (byte *)(iqmData->blendWeights.f + 4 * header->num_vertexes); - } else { - iqmData->blendWeights.b = iqmData->blendIndexes + 4 * header->num_vertexes; - iqmData->colors = iqmData->blendWeights.b + 4 * header->num_vertexes; - } - - iqmData->jointParents = (int *)(iqmData->colors + 4 * header->num_vertexes); - iqmData->triangles = iqmData->jointParents + header->num_joints; - iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); - - if ( header->num_joints == 0 ) - iqmData->jointMats = NULL; - - if ( header->num_poses == 0 ) - iqmData->poseMats = NULL; - - // calculate joint matrices and their inverses - // joint inverses are needed only until the pose matrices are calculated - mat = iqmData->jointMats; - matInv = jointInvMats; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - float baseFrame[12], invBaseFrame[12]; - - JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame ); - Matrix34Invert( baseFrame, invBaseFrame ); - - if ( joint->parent >= 0 ) - { - Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); - mat += 12; - Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); - matInv += 12; - } - else - { - Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); - mat += 12; - Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); - matInv += 12; - } - } - - // calculate pose matrices - framedata = (unsigned short *)((byte *)header + header->ofs_frames); - mat = iqmData->poseMats; - for( i = 0; i < header->num_frames; i++ ) { - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( j = 0; j < header->num_poses; j++, pose++ ) { - vec3_t translate; - vec4_t rotate; - vec3_t scale; - float mat1[12], mat2[12]; - - translate[0] = pose->channeloffset[0]; - if( pose->mask & 0x001) - translate[0] += *framedata++ * pose->channelscale[0]; - translate[1] = pose->channeloffset[1]; - if( pose->mask & 0x002) - translate[1] += *framedata++ * pose->channelscale[1]; - translate[2] = pose->channeloffset[2]; - if( pose->mask & 0x004) - translate[2] += *framedata++ * pose->channelscale[2]; - - rotate[0] = pose->channeloffset[3]; - if( pose->mask & 0x008) - rotate[0] += *framedata++ * pose->channelscale[3]; - rotate[1] = pose->channeloffset[4]; - if( pose->mask & 0x010) - rotate[1] += *framedata++ * pose->channelscale[4]; - rotate[2] = pose->channeloffset[5]; - if( pose->mask & 0x020) - rotate[2] += *framedata++ * pose->channelscale[5]; - rotate[3] = pose->channeloffset[6]; - if( pose->mask & 0x040) - rotate[3] += *framedata++ * pose->channelscale[6]; - - scale[0] = pose->channeloffset[7]; - if( pose->mask & 0x080) - scale[0] += *framedata++ * pose->channelscale[7]; - scale[1] = pose->channeloffset[8]; - if( pose->mask & 0x100) - scale[1] += *framedata++ * pose->channelscale[8]; - scale[2] = pose->channeloffset[9]; - if( pose->mask & 0x200) - scale[2] += *framedata++ * pose->channelscale[9]; - - // construct transformation matrix - JointToMatrix( rotate, scale, translate, mat1 ); - - if( pose->parent >= 0 ) { - Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, - mat1, mat2 ); - } else { - Com_Memcpy( mat2, mat1, sizeof(mat1) ); - } - - Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); - mat += 12; + // register shaders + // overwrite the material offset with the shader index + mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); + surface = iqmData->surfaces; + str = (char *)header + header->ofs_text; + for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) { + surface->surfaceType = SF_IQM; + Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name)); + Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster + surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue ); + if( surface->shader->defaultShader ) + surface->shader = tr.defaultShader; + surface->data = iqmData; + surface->first_vertex = mesh->first_vertex; + surface->num_vertexes = mesh->num_vertexes; + surface->first_triangle = mesh->first_triangle; + surface->num_triangles = mesh->num_triangles; } - } - // register shaders - // overwrite the material offset with the shader index - mesh = (iqmMesh_t *)((byte *)header + header->ofs_meshes); - surface = iqmData->surfaces; - str = (char *)header + header->ofs_text; - for( i = 0; i < header->num_meshes; i++, mesh++, surface++ ) { - surface->surfaceType = SF_IQM; - Q_strncpyz(surface->name, str + mesh->name, sizeof (surface->name)); - Q_strlwr(surface->name); // lowercase the surface name so skin compares are faster - surface->shader = R_FindShader( str + mesh->material, LIGHTMAP_NONE, qtrue ); - if( surface->shader->defaultShader ) - surface->shader = tr.defaultShader; - surface->data = iqmData; - surface->first_vertex = mesh->first_vertex; - surface->num_vertexes = mesh->num_vertexes; - surface->first_triangle = mesh->first_triangle; - surface->num_triangles = mesh->num_triangles; - } + // copy triangles + triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); + for( i = 0; i < header->num_triangles; i++, triangle++ ) { + iqmData->triangles[3*i+0] = triangle->vertex[0]; + iqmData->triangles[3*i+1] = triangle->vertex[1]; + iqmData->triangles[3*i+2] = triangle->vertex[2]; + } - // copy vertexarrays and indexes - vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); - for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int n; + // copy vertexarrays and indexes + vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); + for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { + int n; - // total number of values - n = header->num_vertexes * vertexarray->size; + // skip disabled arrays + if( vertexarray->type < ARRAY_LEN( vertexArrayFormat ) + && vertexArrayFormat[vertexarray->type] == -1 ) + continue; - switch( vertexarray->type ) { - case IQM_POSITION: - Com_Memcpy( iqmData->positions, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_NORMAL: - Com_Memcpy( iqmData->normals, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TANGENT: - Com_Memcpy( iqmData->tangents, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_TEXCOORD: - Com_Memcpy( iqmData->texcoords, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - break; - case IQM_BLENDINDEXES: - if( blendIndexesType == IQM_INT ) { - int *data = (int*)((byte*)header + vertexarray->offset); - for ( j = 0; j < n; j++ ) { - iqmData->blendIndexes[j] = (byte)data[j]; + // total number of values + n = header->num_vertexes * vertexarray->size; + + switch( vertexarray->type ) { + case IQM_POSITION: + Com_Memcpy( iqmData->positions, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + break; + case IQM_NORMAL: + Com_Memcpy( iqmData->normals, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + break; + case IQM_TANGENT: + Com_Memcpy( iqmData->tangents, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + break; + case IQM_TEXCOORD: + Com_Memcpy( iqmData->texcoords, + (byte *)header + vertexarray->offset, + n * sizeof(float) ); + break; + case IQM_BLENDINDEXES: + case IQM_BLENDWEIGHTS: + break; + case IQM_COLOR: + Com_Memcpy( iqmData->colors, + (byte *)header + vertexarray->offset, + n * sizeof(byte) ); + break; + } + } + + // find unique blend influences per mesh + if( allocateInfluences ) { + int vtx, influence, totalInfluences = 0; + + surface = iqmData->surfaces; + for( i = 0; i < header->num_meshes; i++, surface++ ) { + surface->first_influence = totalInfluences; + surface->num_influences = 0; + + for( j = 0; j < surface->num_vertexes; j++ ) { + vtx = surface->first_vertex + j; + + for( k = 0; k < surface->num_influences; k++ ) { + influence = surface->first_influence + k; + + if( *(int*)&iqmData->influenceBlendIndexes[4*influence] != *(int*)&blendIndexes[4*vtx] ) { + continue; + } + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + if ( iqmData->influenceBlendWeights.f[4*influence+0] == blendWeights.f[4*vtx+0] && + iqmData->influenceBlendWeights.f[4*influence+1] == blendWeights.f[4*vtx+1] && + iqmData->influenceBlendWeights.f[4*influence+2] == blendWeights.f[4*vtx+2] && + iqmData->influenceBlendWeights.f[4*influence+3] == blendWeights.f[4*vtx+3] ) { + break; + } + } else { + if ( *(int*)&iqmData->influenceBlendWeights.b[4*influence] == *(int*)&blendWeights.b[4*vtx] ) { + break; + } + } + } + + iqmData->influences[vtx] = surface->first_influence + k; + + if( k == surface->num_influences ) { + influence = surface->first_influence + k; + + iqmData->influenceBlendIndexes[4*influence+0] = blendIndexes[4*vtx+0]; + iqmData->influenceBlendIndexes[4*influence+1] = blendIndexes[4*vtx+1]; + iqmData->influenceBlendIndexes[4*influence+2] = blendIndexes[4*vtx+2]; + iqmData->influenceBlendIndexes[4*influence+3] = blendIndexes[4*vtx+3]; + + if( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + iqmData->influenceBlendWeights.f[4*influence+0] = blendWeights.f[4*vtx+0]; + iqmData->influenceBlendWeights.f[4*influence+1] = blendWeights.f[4*vtx+1]; + iqmData->influenceBlendWeights.f[4*influence+2] = blendWeights.f[4*vtx+2]; + iqmData->influenceBlendWeights.f[4*influence+3] = blendWeights.f[4*vtx+3]; + } else { + iqmData->influenceBlendWeights.b[4*influence+0] = blendWeights.b[4*vtx+0]; + iqmData->influenceBlendWeights.b[4*influence+1] = blendWeights.b[4*vtx+1]; + iqmData->influenceBlendWeights.b[4*influence+2] = blendWeights.b[4*vtx+2]; + iqmData->influenceBlendWeights.b[4*influence+3] = blendWeights.b[4*vtx+3]; + } + + totalInfluences++; + surface->num_influences++; + } } - } else { - Com_Memcpy( iqmData->blendIndexes, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); } - break; - case IQM_BLENDWEIGHTS: - if( blendWeightsType == IQM_FLOAT ) { - Com_Memcpy( iqmData->blendWeights.f, - (byte *)header + vertexarray->offset, - n * sizeof(float) ); - } else { - Com_Memcpy( iqmData->blendWeights.b, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - } - break; - case IQM_COLOR: - Com_Memcpy( iqmData->colors, - (byte *)header + vertexarray->offset, - n * sizeof(byte) ); - break; } } - // copy joint parents - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - iqmData->jointParents[i] = joint->parent; + if( header->num_joints ) + { + // copy joint names + str = iqmData->jointNames; + joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); + for( i = 0; i < header->num_joints; i++, joint++ ) { + char *name = (char *)header + header->ofs_text + + joint->name; + int len = strlen( name ) + 1; + Com_Memcpy( str, name, len ); + str += len; + } + + // copy joint parents + joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); + for( i = 0; i < header->num_joints; i++, joint++ ) { + iqmData->jointParents[i] = joint->parent; + } + + // calculate joint matrices and their inverses + // joint inverses are needed only until the pose matrices are calculated + mat = iqmData->jointMats; + matInv = jointInvMats; + joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); + for( i = 0; i < header->num_joints; i++, joint++ ) { + float baseFrame[12], invBaseFrame[12]; + + JointToMatrix( joint->rotate, joint->scale, joint->translate, baseFrame ); + Matrix34Invert( baseFrame, invBaseFrame ); + + if ( joint->parent >= 0 ) + { + Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); + mat += 12; + Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); + matInv += 12; + } + else + { + Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); + mat += 12; + Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); + matInv += 12; + } + } } - // copy triangles - triangle = (iqmTriangle_t *)((byte *)header + header->ofs_triangles); - for( i = 0; i < header->num_triangles; i++, triangle++ ) { - iqmData->triangles[3*i+0] = triangle->vertex[0]; - iqmData->triangles[3*i+1] = triangle->vertex[1]; - iqmData->triangles[3*i+2] = triangle->vertex[2]; - } + if( header->num_poses ) + { + // calculate pose matrices + framedata = (unsigned short *)((byte *)header + header->ofs_frames); + mat = iqmData->poseMats; + for( i = 0; i < header->num_frames; i++ ) { + pose = (iqmPose_t *)((byte *)header + header->ofs_poses); + for( j = 0; j < header->num_poses; j++, pose++ ) { + vec3_t translate; + vec4_t rotate; + vec3_t scale; + float mat1[12], mat2[12]; - // copy joint names - str = iqmData->names; - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - for( i = 0; i < header->num_joints; i++, joint++ ) { - char *name = (char *)header + header->ofs_text + - joint->name; - int len = strlen( name ) + 1; - Com_Memcpy( str, name, len ); - str += len; + translate[0] = pose->channeloffset[0]; + if( pose->mask & 0x001) + translate[0] += *framedata++ * pose->channelscale[0]; + translate[1] = pose->channeloffset[1]; + if( pose->mask & 0x002) + translate[1] += *framedata++ * pose->channelscale[1]; + translate[2] = pose->channeloffset[2]; + if( pose->mask & 0x004) + translate[2] += *framedata++ * pose->channelscale[2]; + + rotate[0] = pose->channeloffset[3]; + if( pose->mask & 0x008) + rotate[0] += *framedata++ * pose->channelscale[3]; + rotate[1] = pose->channeloffset[4]; + if( pose->mask & 0x010) + rotate[1] += *framedata++ * pose->channelscale[4]; + rotate[2] = pose->channeloffset[5]; + if( pose->mask & 0x020) + rotate[2] += *framedata++ * pose->channelscale[5]; + rotate[3] = pose->channeloffset[6]; + if( pose->mask & 0x040) + rotate[3] += *framedata++ * pose->channelscale[6]; + + scale[0] = pose->channeloffset[7]; + if( pose->mask & 0x080) + scale[0] += *framedata++ * pose->channelscale[7]; + scale[1] = pose->channeloffset[8]; + if( pose->mask & 0x100) + scale[1] += *framedata++ * pose->channelscale[8]; + scale[2] = pose->channeloffset[9]; + if( pose->mask & 0x200) + scale[2] += *framedata++ * pose->channelscale[9]; + + // construct transformation matrix + JointToMatrix( rotate, scale, translate, mat1 ); + + if( pose->parent >= 0 ) { + Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, + mat1, mat2 ); + } else { + Com_Memcpy( mat2, mat1, sizeof(mat1) ); + } + + Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); + mat += 12; + } + } } // copy model bounds @@ -735,6 +915,179 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na bounds++; } } + else if( header->num_meshes && header->num_frames == 0 ) + { + mat = iqmData->bounds; + + ClearBounds( &iqmData->bounds[0], &iqmData->bounds[3] ); + for ( i = 0 ; i < header->num_vertexes ; i++ ) { + AddPointToBounds( &iqmData->positions[i*3], &iqmData->bounds[0], &iqmData->bounds[3] ); + } + } + + // Create VAO surfaces + if ( iqmData->num_surfaces && iqmData->num_joints <= glRefConfig.glslMaxAnimatedBones ) + { + srfVaoIQModel_t *vaoSurf; + srfIQModel_t *surf; + + iqmData->numVaoSurfaces = iqmData->num_surfaces; + iqmData->vaoSurfaces = ri.Hunk_Alloc(sizeof(*iqmData->vaoSurfaces) * iqmData->numVaoSurfaces, h_low); + + vaoSurf = iqmData->vaoSurfaces; + surf = iqmData->surfaces; + for (i = 0; i < iqmData->num_surfaces; i++, vaoSurf++, surf++) + { + uint32_t offset_xyz, offset_st, offset_normal, offset_tangent; + uint32_t offset_blendindexes, offset_blendweights, stride; + uint32_t dataSize, dataOfs; + uint8_t *data; + glIndex_t indexes[SHADER_MAX_INDEXES]; + glIndex_t *ptr; + int *tri; + + offset_xyz = 0; + offset_st = offset_xyz + sizeof(float) * 3; + offset_normal = offset_st + sizeof(float) * 2; + offset_tangent = offset_normal + sizeof(int16_t) * 4; + + if ( iqmData->num_joints ) + { + offset_blendindexes = offset_tangent + sizeof(int16_t) * 4; + offset_blendweights = offset_blendindexes + sizeof(byte) * 4; + + if ( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + stride = offset_blendweights + sizeof(float) * 4; + } else { + stride = offset_blendweights + sizeof(byte) * 4; + } + } + else + { + stride = offset_tangent + sizeof(int16_t) * 4; + } + + dataSize = surf->num_vertexes * stride; + + data = ri.Malloc(dataSize); + dataOfs = 0; + + for ( j = 0; j < surf->num_vertexes; j++ ) + { + int vtx = surf->first_vertex + j; + + // xyz + memcpy(data + dataOfs, &iqmData->positions[vtx*3], sizeof(float) * 3); + dataOfs += sizeof(float) * 3; + + // st + memcpy(data + dataOfs, &iqmData->texcoords[vtx*2], sizeof(float) * 2); + dataOfs += sizeof(float) * 2; + + // normal + R_VaoPackNormal((int16_t*)(data + dataOfs), &iqmData->normals[vtx*3]); + dataOfs += sizeof(int16_t) * 4; + + // tangent + R_VaoPackTangent((int16_t*)(data + dataOfs), &iqmData->tangents[vtx*4]); + dataOfs += sizeof(int16_t) * 4; + + if ( iqmData->num_joints ) + { + // blendindexes + memcpy(data + dataOfs, &blendIndexes[vtx*4], sizeof(byte) * 4); + dataOfs += sizeof(byte) * 4; + + // blendweights + if ( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + memcpy(data + dataOfs, &blendWeights.f[vtx*4], sizeof(float) * 4); + dataOfs += sizeof(float) * 4; + } else { + memcpy(data + dataOfs, &blendWeights.b[vtx*4], sizeof(byte) * 4); + dataOfs += sizeof(byte) * 4; + } + } + } + + tri = iqmData->triangles + 3 * surf->first_triangle; + ptr = indexes; + + for( j = 0; j < surf->num_triangles; j++ ) { + *ptr++ = (*tri++ - surf->first_vertex); + *ptr++ = (*tri++ - surf->first_vertex); + *ptr++ = (*tri++ - surf->first_vertex); + } + + vaoSurf->surfaceType = SF_VAO_IQM; + vaoSurf->iqmData = iqmData; + vaoSurf->iqmSurface = surf; + vaoSurf->numIndexes = surf->num_triangles * 3; + vaoSurf->numVerts = surf->num_vertexes; + + vaoSurf->vao = R_CreateVao(va("staticIQMMesh_VAO '%s'", surf->name), data, dataSize, (byte *)indexes, surf->num_triangles * 3 * sizeof(indexes[0]), VAO_USAGE_STATIC); + + vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_POSITION].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; + + vaoSurf->vao->attribs[ATTR_INDEX_POSITION].count = 3; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].count = 2; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].count = 4; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].count = 4; + + vaoSurf->vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT; + + vaoSurf->vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; + + vaoSurf->vao->attribs[ATTR_INDEX_POSITION].offset = offset_xyz; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].offset = offset_st; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].offset = offset_normal; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].offset = offset_tangent; + + vaoSurf->vao->attribs[ATTR_INDEX_POSITION].stride = stride; + vaoSurf->vao->attribs[ATTR_INDEX_TEXCOORD].stride = stride; + vaoSurf->vao->attribs[ATTR_INDEX_NORMAL ].stride = stride; + vaoSurf->vao->attribs[ATTR_INDEX_TANGENT ].stride = stride; + + if ( iqmData->num_joints ) + { + vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].enabled = 1; + vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].enabled = 1; + + vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].count = 4; + vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].count = 4; + + vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].type = GL_UNSIGNED_BYTE; + vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].normalized = GL_FALSE; + + if ( vertexArrayFormat[IQM_BLENDWEIGHTS] == IQM_FLOAT ) { + vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].type = GL_FLOAT; + vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].normalized = GL_FALSE; + } else { + vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].type = GL_UNSIGNED_BYTE; + vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].normalized = GL_TRUE; + } + + vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].offset = offset_blendindexes; + vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].offset = offset_blendweights; + + vaoSurf->vao->attribs[ATTR_INDEX_BONE_INDEXES].stride = stride; + vaoSurf->vao->attribs[ATTR_INDEX_BONE_WEIGHTS].stride = stride; + } + + Vao_SetVertexPointers(vaoSurf->vao); + + ri.Free(data); + } + } return qtrue; } @@ -837,6 +1190,7 @@ Add all surfaces of this model void R_AddIQMSurfaces( trRefEntity_t *ent ) { iqmData_t *data; srfIQModel_t *surface; + void *drawSurf; int i, j; qboolean personalModel; int cull; @@ -849,7 +1203,8 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { surface = data->surfaces; // don't add third_person objects if not in a portal - personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; + personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !(tr.viewParms.isPortal + || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW))); if ( ent->e.renderfx & RF_WRAP_FRAMES ) { ent->e.frame %= data->num_frames; @@ -906,9 +1261,9 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { for(j = 0; j < skin->numSurfaces; j++) { - if (!strcmp(skin->surfaces[j]->name, surface->name)) + if (!strcmp(skin->surfaces[j].name, surface->name)) { - shader = skin->surfaces[j]->shader; + shader = skin->surfaces[j].shader; break; } } @@ -916,6 +1271,12 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { shader = surface->shader; } + if ( data->numVaoSurfaces ) { + drawSurf = &data->vaoSurfaces[i]; + } else { + drawSurf = surface; + } + // we will add shadows even if the main object isn't visible in the view // stencil shadows can't do personal models unless I polyhedron clip @@ -924,7 +1285,7 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { && fogNum == 0 && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.shadowShader, 0, 0, 0, 0 ); + R_AddDrawSurf( drawSurf, tr.shadowShader, 0, 0, 0, 0 ); } // projection shadows work fine with personal models @@ -932,11 +1293,11 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { && fogNum == 0 && (ent->e.renderfx & RF_SHADOW_PLANE ) && shader->sort == SS_OPAQUE ) { - R_AddDrawSurf( (void *)surface, tr.projectionShadowShader, 0, 0, 0, 0 ); + R_AddDrawSurf( drawSurf, tr.projectionShadowShader, 0, 0, 0, 0 ); } if( !personalModel ) { - R_AddDrawSurf( (void *)surface, shader, fogNum, 0, 0, cubemapIndex ); + R_AddDrawSurf( drawSurf, shader, fogNum, 0, 0, cubemapIndex ); } surface++; @@ -950,18 +1311,6 @@ static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, int *joint = data->jointParents; int i; - if ( data->num_poses == 0 ) { - for( i = 0; i < data->num_joints; i++, joint++ ) { - if( *joint >= 0 ) { - Matrix34Multiply( mat + 12 * *joint, - identityMatrix, mat + 12*i ); - } else { - Com_Memcpy( mat + 12*i, identityMatrix, 12 * sizeof(float) ); - } - } - return; - } - if ( oldframe == frame ) { mat1 = data->poseMats + 12 * data->num_poses * frame; for( i = 0; i < data->num_poses; i++, joint++ ) { @@ -986,7 +1335,7 @@ static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, } else { InterpolateMatrix( mat1 + 12*i, mat2 + 12*i, - backlerp, mat ); + backlerp, mat + 12*i ); } } } @@ -997,6 +1346,11 @@ static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, float *mat1; int i; + if ( data->num_poses == 0 ) { + Com_Memcpy( mat, data->jointMats, data->num_joints * 12 * sizeof(float) ); + return; + } + ComputePoseMats( data, frame, oldframe, backlerp, mat ); for( i = 0; i < data->num_joints; i++ ) { @@ -1005,7 +1359,7 @@ static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, Com_Memcpy(outmat, mat1, sizeof(outmat)); - Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 ); + Matrix34Multiply( outmat, data->jointMats + 12*i, mat1 ); } } @@ -1020,16 +1374,21 @@ Compute vertices for this model surface void RB_IQMSurfaceAnim( surfaceType_t *surface ) { srfIQModel_t *surf = (srfIQModel_t *)surface; iqmData_t *data = surf->data; - float jointMats[IQM_MAX_JOINTS * 12]; + float poseMats[IQM_MAX_JOINTS * 12]; + float influenceVtxMat[SHADER_MAX_VERTEXES * 12]; + float influenceNrmMat[SHADER_MAX_VERTEXES * 9]; int i; + float *xyz; + float *normal; + float *tangent; + float *texCoords; + byte *color; vec4_t *outXYZ; - uint32_t *outNormal; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *outTangent; -#endif - vec2_t (*outTexCoord)[2]; - vec4_t *outColor; + int16_t *outNormal; + int16_t *outTangent; + vec2_t *outTexCoord; + uint16_t *outColor; int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0; int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0; @@ -1041,111 +1400,181 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 ); - outXYZ = &tess.xyz[tess.numVertexes]; - outNormal = &tess.normal[tess.numVertexes]; -#ifdef USE_VERT_TANGENT_SPACE - outTangent = &tess.tangent[tess.numVertexes]; -#endif - outTexCoord = &tess.texCoords[tess.numVertexes]; - outColor = &tess.vertexColors[tess.numVertexes]; + xyz = &data->positions[surf->first_vertex * 3]; + normal = &data->normals[surf->first_vertex * 3]; + tangent = &data->tangents[surf->first_vertex * 4]; + texCoords = &data->texcoords[surf->first_vertex * 2]; - // compute interpolated joint matrices - if ( data->num_poses > 0 ) { - ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); + if ( data->colors ) { + color = &data->colors[surf->first_vertex * 4]; + } else { + color = NULL; } - // transform vertexes and fill other data - for( i = 0; i < surf->num_vertexes; - i++, outXYZ++, outNormal++, outTexCoord++, outColor++ ) { - int j, k; - float vtxMat[12]; - float nrmMat[9]; - int vtx = i + surf->first_vertex; - float blendWeights[4]; - int numWeights; + outXYZ = &tess.xyz[tess.numVertexes]; + outNormal = tess.normal[tess.numVertexes]; + outTangent = tess.tangent[tess.numVertexes]; + outTexCoord = &tess.texCoords[tess.numVertexes]; + outColor = tess.color[tess.numVertexes]; - for ( numWeights = 0; numWeights < 4; numWeights++ ) { - if ( data->blendWeightsType == IQM_FLOAT ) - blendWeights[numWeights] = data->blendWeights.f[4*vtx + numWeights]; - else - blendWeights[numWeights] = (float)data->blendWeights.b[4*vtx + numWeights] / 255.0f; + if ( data->num_poses > 0 ) { + // compute interpolated joint matrices + ComputePoseMats( data, frame, oldframe, backlerp, poseMats ); - if ( blendWeights[numWeights] <= 0 ) - break; - } + // compute vertex blend influence matricies + for( i = 0; i < surf->num_influences; i++ ) { + int influence = surf->first_influence + i; + float *vtxMat = &influenceVtxMat[12*i]; + float *nrmMat = &influenceNrmMat[9*i]; + int j; + float blendWeights[4]; + int numWeights; - if ( data->num_poses == 0 || numWeights == 0 ) { - // no blend joint, use identity matrix. - Com_Memcpy( vtxMat, identityMatrix, 12 * sizeof (float) ); - } else { - // compute the vertex matrix by blending the up to - // four blend weights - Com_Memset( vtxMat, 0, 12 * sizeof (float) ); - for( j = 0; j < numWeights; j++ ) { - for( k = 0; k < 12; k++ ) { - vtxMat[k] += blendWeights[j] * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + for ( numWeights = 0; numWeights < 4; numWeights++ ) { + if ( data->blendWeightsType == IQM_FLOAT ) + blendWeights[numWeights] = data->influenceBlendWeights.f[4*influence + numWeights]; + else + blendWeights[numWeights] = (float)data->influenceBlendWeights.b[4*influence + numWeights] / 255.0f; + + if ( blendWeights[numWeights] <= 0.0f ) + break; + } + + if ( numWeights == 0 ) { + // no blend joint, use identity matrix. + vtxMat[0] = identityMatrix[0]; + vtxMat[1] = identityMatrix[1]; + vtxMat[2] = identityMatrix[2]; + vtxMat[3] = identityMatrix[3]; + vtxMat[4] = identityMatrix[4]; + vtxMat[5] = identityMatrix[5]; + vtxMat[6] = identityMatrix[6]; + vtxMat[7] = identityMatrix[7]; + vtxMat[8] = identityMatrix[8]; + vtxMat[9] = identityMatrix[9]; + vtxMat[10] = identityMatrix[10]; + vtxMat[11] = identityMatrix[11]; + } else { + // compute the vertex matrix by blending the up to + // four blend weights + vtxMat[0] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 0]; + vtxMat[1] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 1]; + vtxMat[2] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 2]; + vtxMat[3] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 3]; + vtxMat[4] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 4]; + vtxMat[5] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 5]; + vtxMat[6] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 6]; + vtxMat[7] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 7]; + vtxMat[8] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 8]; + vtxMat[9] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 9]; + vtxMat[10] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 10]; + vtxMat[11] = blendWeights[0] * poseMats[12 * data->influenceBlendIndexes[4*influence + 0] + 11]; + + for( j = 1; j < numWeights; j++ ) { + vtxMat[0] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 0]; + vtxMat[1] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 1]; + vtxMat[2] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 2]; + vtxMat[3] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 3]; + vtxMat[4] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 4]; + vtxMat[5] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 5]; + vtxMat[6] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 6]; + vtxMat[7] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 7]; + vtxMat[8] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 8]; + vtxMat[9] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 9]; + vtxMat[10] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 10]; + vtxMat[11] += blendWeights[j] * poseMats[12 * data->influenceBlendIndexes[4*influence + j] + 11]; } } + + // compute the normal matrix as transpose of the adjoint + // of the vertex matrix + nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9]; + nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10]; + nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8]; + nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10]; + nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8]; + nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9]; + nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5]; + nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6]; + nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4]; } - // compute the normal matrix as transpose of the adjoint - // of the vertex matrix - nrmMat[ 0] = vtxMat[ 5]*vtxMat[10] - vtxMat[ 6]*vtxMat[ 9]; - nrmMat[ 1] = vtxMat[ 6]*vtxMat[ 8] - vtxMat[ 4]*vtxMat[10]; - nrmMat[ 2] = vtxMat[ 4]*vtxMat[ 9] - vtxMat[ 5]*vtxMat[ 8]; - nrmMat[ 3] = vtxMat[ 2]*vtxMat[ 9] - vtxMat[ 1]*vtxMat[10]; - nrmMat[ 4] = vtxMat[ 0]*vtxMat[10] - vtxMat[ 2]*vtxMat[ 8]; - nrmMat[ 5] = vtxMat[ 1]*vtxMat[ 8] - vtxMat[ 0]*vtxMat[ 9]; - nrmMat[ 6] = vtxMat[ 1]*vtxMat[ 6] - vtxMat[ 2]*vtxMat[ 5]; - nrmMat[ 7] = vtxMat[ 2]*vtxMat[ 4] - vtxMat[ 0]*vtxMat[ 6]; - nrmMat[ 8] = vtxMat[ 0]*vtxMat[ 5] - vtxMat[ 1]*vtxMat[ 4]; + // transform vertexes and fill other data + for( i = 0; i < surf->num_vertexes; + i++, xyz+=3, normal+=3, tangent+=4, texCoords+=2, + outXYZ++, outNormal+=4, outTangent+=4, outTexCoord++ ) { + int influence = data->influences[surf->first_vertex + i] - surf->first_influence; + float *vtxMat = &influenceVtxMat[12*influence]; + float *nrmMat = &influenceNrmMat[9*influence]; - (*outTexCoord)[0][0] = data->texcoords[2*vtx + 0]; - (*outTexCoord)[0][1] = data->texcoords[2*vtx + 1]; - (*outTexCoord)[1][0] = (*outTexCoord)[0][0]; - (*outTexCoord)[1][1] = (*outTexCoord)[0][1]; + (*outTexCoord)[0] = texCoords[0]; + (*outTexCoord)[1] = texCoords[1]; - (*outXYZ)[0] = - vtxMat[ 0] * data->positions[3*vtx+0] + - vtxMat[ 1] * data->positions[3*vtx+1] + - vtxMat[ 2] * data->positions[3*vtx+2] + - vtxMat[ 3]; - (*outXYZ)[1] = - vtxMat[ 4] * data->positions[3*vtx+0] + - vtxMat[ 5] * data->positions[3*vtx+1] + - vtxMat[ 6] * data->positions[3*vtx+2] + - vtxMat[ 7]; - (*outXYZ)[2] = - vtxMat[ 8] * data->positions[3*vtx+0] + - vtxMat[ 9] * data->positions[3*vtx+1] + - vtxMat[10] * data->positions[3*vtx+2] + - vtxMat[11]; - (*outXYZ)[3] = 1.0f; + (*outXYZ)[0] = + vtxMat[ 0] * xyz[0] + + vtxMat[ 1] * xyz[1] + + vtxMat[ 2] * xyz[2] + + vtxMat[ 3]; + (*outXYZ)[1] = + vtxMat[ 4] * xyz[0] + + vtxMat[ 5] * xyz[1] + + vtxMat[ 6] * xyz[2] + + vtxMat[ 7]; + (*outXYZ)[2] = + vtxMat[ 8] * xyz[0] + + vtxMat[ 9] * xyz[1] + + vtxMat[10] * xyz[2] + + vtxMat[11]; - { - vec3_t normal; - vec4_t tangent; + { + vec3_t unpackedNormal; + vec4_t unpackedTangent; - normal[0] = DotProduct(&nrmMat[0], &data->normals[3*vtx]); - normal[1] = DotProduct(&nrmMat[3], &data->normals[3*vtx]); - normal[2] = DotProduct(&nrmMat[6], &data->normals[3*vtx]); + unpackedNormal[0] = DotProduct(&nrmMat[0], normal); + unpackedNormal[1] = DotProduct(&nrmMat[3], normal); + unpackedNormal[2] = DotProduct(&nrmMat[6], normal); - R_VaoPackNormal((byte *)outNormal, normal); + R_VaoPackNormal(outNormal, unpackedNormal); -#ifdef USE_VERT_TANGENT_SPACE - tangent[0] = DotProduct(&nrmMat[0], &data->tangents[4*vtx]); - tangent[1] = DotProduct(&nrmMat[3], &data->tangents[4*vtx]); - tangent[2] = DotProduct(&nrmMat[6], &data->tangents[4*vtx]); - tangent[3] = data->tangents[4*vtx+3]; + unpackedTangent[0] = DotProduct(&nrmMat[0], tangent); + unpackedTangent[1] = DotProduct(&nrmMat[3], tangent); + unpackedTangent[2] = DotProduct(&nrmMat[6], tangent); + unpackedTangent[3] = tangent[3]; - R_VaoPackTangent((byte *)outTangent++, tangent); -#endif + R_VaoPackTangent(outTangent, unpackedTangent); + } } + } else { + // copy vertexes and fill other data + for( i = 0; i < surf->num_vertexes; + i++, xyz+=3, normal+=3, tangent+=4, texCoords+=2, + outXYZ++, outNormal+=4, outTangent+=4, outTexCoord++ ) { + (*outTexCoord)[0] = texCoords[0]; + (*outTexCoord)[1] = texCoords[1]; - (*outColor)[0] = data->colors[4*vtx+0] / 255.0f; - (*outColor)[1] = data->colors[4*vtx+1] / 255.0f; - (*outColor)[2] = data->colors[4*vtx+2] / 255.0f; - (*outColor)[3] = data->colors[4*vtx+3] / 255.0f; + (*outXYZ)[0] = xyz[0]; + (*outXYZ)[1] = xyz[1]; + (*outXYZ)[2] = xyz[2]; + + R_VaoPackNormal(outNormal, normal); + R_VaoPackTangent(outTangent, tangent); + } + } + + if ( color ) { + for( i = 0; i < surf->num_vertexes; i++, color+=4, outColor+=4 ) { + outColor[0] = color[0] * 257; + outColor[1] = color[1] * 257; + outColor[2] = color[2] * 257; + outColor[3] = color[3] * 257; + } + } else { + for( i = 0; i < surf->num_vertexes; i++, outColor+=4 ) { + outColor[0] = 0; + outColor[1] = 0; + outColor[2] = 0; + outColor[3] = 0; + } } tri = data->triangles + 3 * surf->first_triangle; @@ -1162,12 +1591,79 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { tess.numVertexes += surf->num_vertexes; } +/* +================= +RB_IQMSurfaceAnimVao +================= +*/ +void RB_IQMSurfaceAnimVao(srfVaoIQModel_t * surface) +{ + iqmData_t *data = surface->iqmData; + + if (ShaderRequiresCPUDeforms(tess.shader)) + { + RB_IQMSurfaceAnim((surfaceType_t*)surface->iqmSurface); + return; + } + + if(!surface->vao) + return; + + //RB_CheckVao(surface->vao); + RB_EndSurface(); + RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); + + R_BindVao(surface->vao); + + tess.useInternalVao = qfalse; + + tess.numIndexes = surface->numIndexes; + tess.numVertexes = surface->numVerts; + + glState.boneAnimation = data->num_poses; + + if ( glState.boneAnimation ) { + float jointMats[IQM_MAX_JOINTS * 12]; + int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0; + int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0; + float backlerp = backEnd.currentEntity->e.backlerp; + int i; + + // compute interpolated joint matrices + ComputePoseMats( surface->iqmData, frame, oldframe, backlerp, jointMats ); + + // convert row-major order 3x4 matrix to column-major order 4x4 matrix + for ( i = 0; i < data->num_poses; i++ ) { + glState.boneMatrix[i][0] = jointMats[i*12+0]; + glState.boneMatrix[i][1] = jointMats[i*12+4]; + glState.boneMatrix[i][2] = jointMats[i*12+8]; + glState.boneMatrix[i][3] = 0.0f; + glState.boneMatrix[i][4] = jointMats[i*12+1]; + glState.boneMatrix[i][5] = jointMats[i*12+5]; + glState.boneMatrix[i][6] = jointMats[i*12+9]; + glState.boneMatrix[i][7] = 0.0f; + glState.boneMatrix[i][8] = jointMats[i*12+2]; + glState.boneMatrix[i][9] = jointMats[i*12+6]; + glState.boneMatrix[i][10] = jointMats[i*12+10]; + glState.boneMatrix[i][11] = 0.0f; + glState.boneMatrix[i][12] = jointMats[i*12+3]; + glState.boneMatrix[i][13] = jointMats[i*12+7]; + glState.boneMatrix[i][14] = jointMats[i*12+11]; + glState.boneMatrix[i][15] = 1.0f; + } + } + + RB_EndSurface(); + + glState.boneAnimation = 0; +} + int R_IQMLerpTag( orientation_t *tag, iqmData_t *data, int startFrame, int endFrame, float frac, const char *tagName ) { float jointMats[IQM_MAX_JOINTS * 12]; int joint; - char *names = data->names; + char *names = data->jointNames; // get joint number by reading the joint names for( joint = 0; joint < data->num_joints; joint++ ) { diff --git a/code/renderergl2/tr_postprocess.c b/code/renderergl2/tr_postprocess.c index 1952ae96..9931757b 100644 --- a/code/renderergl2/tr_postprocess.c +++ b/code/renderergl2/tr_postprocess.c @@ -82,7 +82,7 @@ void RB_ToneMap(FBO_t *hdrFbo, ivec4_t hdrBox, FBO_t *ldrFbo, ivec4_t ldrBox, in // tonemap color[0] = color[1] = - color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); + color[2] = pow(2, r_cameraExposure->value - autoExposure); //exp2(r_cameraExposure->value); color[3] = 1.0f; if (autoExposure) @@ -227,6 +227,7 @@ void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha) { ivec4_t srcBox, dstBox; + int srcWidth, srcHeight; vec4_t color; const float inc = 1.f / passes; const float mul = powf(stretch, inc); @@ -235,10 +236,10 @@ static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretc alpha *= inc; VectorSet4(color, alpha, alpha, alpha, 1.0f); - if (srcFbo) - VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height); - else - VectorSet4(srcBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight); + srcWidth = srcFbo ? srcFbo->width : glConfig.vidWidth; + srcHeight = srcFbo ? srcFbo->height : glConfig.vidHeight; + + VectorSet4(srcBox, 0, 0, srcWidth, srcHeight); VectorSet4(dstBox, x, y, w, h); FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0); @@ -251,20 +252,10 @@ static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretc float s0 = xcenter * (1.f - iscale); float t0 = (1.0f - ycenter) * (1.f - iscale); - if (srcFbo) - { - srcBox[0] = s0 * srcFbo->width; - srcBox[1] = t0 * srcFbo->height; - srcBox[2] = iscale * srcFbo->width; - srcBox[3] = iscale * srcFbo->height; - } - else - { - srcBox[0] = s0 * glConfig.vidWidth; - srcBox[1] = t0 * glConfig.vidHeight; - srcBox[2] = iscale * glConfig.vidWidth; - srcBox[3] = iscale * glConfig.vidHeight; - } + srcBox[0] = s0 * srcWidth; + srcBox[1] = t0 * srcHeight; + srcBox[2] = iscale * srcWidth; + srcBox[3] = iscale * srcHeight; FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); @@ -291,7 +282,7 @@ static qboolean RB_UpdateSunFlareVis(void) for (iter=0 ; ; ++iter) { GLint available = 0; - qglGetQueryObjectivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + qglGetQueryObjectiv(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE, &available); if (available) break; } @@ -299,7 +290,7 @@ static qboolean RB_UpdateSunFlareVis(void) ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter); } - qglGetQueryObjectuivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_ARB, &sampleCount); + qglGetQueryObjectuiv(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT, &sampleCount); return sampleCount > 0; } @@ -349,23 +340,15 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox) { float mul = 1.f; ivec4_t rayBox, quarterBox; + int srcWidth = srcFbo ? srcFbo->width : glConfig.vidWidth; + int srcHeight = srcFbo ? srcFbo->height : glConfig.vidHeight; VectorSet4(color, mul, mul, mul, 1); - if (srcFbo) - { - rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcFbo->width; - rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcFbo->height; - rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcFbo->width; - rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcFbo->height; - } - else - { - rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / glConfig.vidWidth; - rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / glConfig.vidHeight; - rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / glConfig.vidWidth; - rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / glConfig.vidHeight; - } + rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcWidth; + rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcHeight; + rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcWidth; + rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcHeight; quarterBox[0] = 0; quarterBox[1] = tr.quarterFbo[0]->height; @@ -483,10 +466,8 @@ void RB_GaussianBlur(float blur) FBO_FastBlit(tr.quarterFbo[0], NULL, tr.textureScratchFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); // set the alpha channel - VectorSet4(srcBox, 0, 0, tr.whiteImage->width, tr.whiteImage->height); - VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height); qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - FBO_BlitFromTexture(tr.whiteImage, srcBox, NULL, tr.textureScratchFbo[0], dstBox, NULL, color, GLS_DEPTHTEST_DISABLE); + FBO_BlitFromTexture(tr.whiteImage, NULL, NULL, tr.textureScratchFbo[0], NULL, NULL, color, GLS_DEPTHTEST_DISABLE); qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // blur the tiny buffer horizontally and vertically diff --git a/code/renderergl2/tr_scene.c b/code/renderergl2/tr_scene.c index 410f81e4..aea153e1 100644 --- a/code/renderergl2/tr_scene.c +++ b/code/renderergl2/tr_scene.c @@ -329,18 +329,12 @@ void RE_BeginScene(const refdef_t *fd) VectorCopy(tr.sunDirection, tr.refdef.sunDir); if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){ - tr.refdef.colorScale = 1.0f; VectorSet(tr.refdef.sunCol, 0, 0, 0); VectorSet(tr.refdef.sunAmbCol, 0, 0, 0); } else { -#if defined(USE_OVERBRIGHT) - float scale = (1 << (r_mapOverBrightBits->integer - tr.overbrightBits)) / 255.0f; -#else float scale = (1 << r_mapOverBrightBits->integer) / 255.0f; -#endif - tr.refdef.colorScale = r_forceSun->integer ? r_forceSunMapLightScale->value : tr.mapLightScale; if (r_forceSun->integer) VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol); @@ -406,7 +400,7 @@ void RE_BeginScene(const refdef_t *fd) // derived info - tr.refdef.floatTime = tr.refdef.time * 0.001f; + tr.refdef.floatTime = tr.refdef.time * 0.001; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData->drawSurfs; @@ -441,7 +435,7 @@ void RE_BeginScene(const refdef_t *fd) } -void RE_EndScene() +void RE_EndScene(void) { // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; @@ -497,7 +491,7 @@ void RE_RenderScene( const refdef_t *fd ) { // playing with even more shadows if(glRefConfig.framebufferObject && r_sunlightMode->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows)) { - if (r_shadowCascadeZFar != 0) + if (r_shadowCascadeZFar->integer != 0) { R_RenderSunShadowMaps(fd, 0); R_RenderSunShadowMaps(fd, 1); diff --git a/code/renderergl2/tr_shade.c b/code/renderergl2/tr_shade.c index ca2a02b6..5300898c 100644 --- a/code/renderergl2/tr_shade.c +++ b/code/renderergl2/tr_shade.c @@ -22,9 +22,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_shade.c #include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif /* @@ -41,42 +38,9 @@ R_DrawElements ================== */ -void R_DrawElementsVao( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex ) +void R_DrawElements( int numIndexes, int firstIndex ) { - if (glRefConfig.drawRangeElements) - qglDrawRangeElementsEXT(GL_TRIANGLES, minIndex, maxIndex, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); - else - qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); - -} - - -static void R_DrawMultiElementsVao( int multiDrawPrimitives, glIndex_t *multiDrawMinIndex, glIndex_t *multiDrawMaxIndex, - GLsizei *multiDrawNumIndexes, glIndex_t **multiDrawFirstIndex) -{ - if (glRefConfig.multiDrawArrays && multiDrawPrimitives > 1) - { - qglMultiDrawElementsEXT(GL_TRIANGLES, multiDrawNumIndexes, GL_INDEX_TYPE, (const GLvoid **)multiDrawFirstIndex, multiDrawPrimitives); - } - else - { - int i; - - if (glRefConfig.drawRangeElements) - { - for (i = 0; i < multiDrawPrimitives; i++) - { - qglDrawRangeElementsEXT(GL_TRIANGLES, multiDrawMinIndex[i], multiDrawMaxIndex[i], multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]); - } - } - else - { - for (i = 0; i < multiDrawPrimitives; i++) - { - qglDrawElements(GL_TRIANGLES, multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]); - } - } - } + qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(glIndex_t))); } @@ -98,7 +62,7 @@ R_BindAnimatedImageToTMU ================= */ static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) { - int index; + int64_t index; if ( bundle->isVideoMap ) { ri.CIN_RunCinematic(bundle->videoMapHandle); @@ -114,13 +78,18 @@ static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) { // it is necessary to do this messy calc to make sure animations line up // exactly with waveforms of the same frequency - index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); + index = tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE; index >>= FUNCTABLE_SIZE2; if ( index < 0 ) { index = 0; // may happen with shader time offsets } - index %= bundle->numImageAnimations; + + // Windows x86 doesn't load renderer DLL with 64 bit modulus + //index %= bundle->numImageAnimations; + while ( index >= bundle->numImageAnimations ) { + index -= bundle->numImageAnimations; + } GL_BindToTMU( bundle->image[ index ], tmu ); } @@ -148,15 +117,9 @@ static void DrawTris (shaderCommands_t *input) { GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); VectorSet4(color, 1, 1, 1, 1); GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0); - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } + R_DrawElements(input->numIndexes, input->firstIndex); } qglDepthRange( 0, 1 ); @@ -190,7 +153,6 @@ void RB_BeginSurface( shader_t *shader, int fogNum, int cubemapIndex ) { tess.numIndexes = 0; tess.firstIndex = 0; tess.numVertexes = 0; - tess.multiDrawPrimitives = 0; tess.shader = state; tess.fogNum = fogNum; tess.cubemapIndex = cubemapIndex; @@ -200,6 +162,7 @@ void RB_BeginSurface( shader_t *shader, int fogNum, int cubemapIndex ) { tess.numPasses = state->numUnfoggedPasses; tess.currentStageIteratorFunc = state->optimalStageIteratorFunc; tess.useInternalVao = qtrue; + tess.useCacheVao = qfalse; tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) { @@ -375,7 +338,7 @@ static void ProjectDlightTexture( void ) { vec4_t vector; if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light + continue; // this surface definitely doesn't have any of this light } dl = &backEnd.refdef.dlights[l]; @@ -423,15 +386,9 @@ static void ProjectDlightTexture( void ) { GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); } - if (tess.multiDrawPrimitives) - { - shaderCommands_t *input = &tess; - R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - } + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 1); + + R_DrawElements(tess.numIndexes, tess.firstIndex); backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes; @@ -447,16 +404,15 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t || ((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_SRC_COLOR) || ((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR); -#if defined(USE_OVERBRIGHT) - float exactLight = 1.0f; -#else - qboolean isWorldDraw = !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL); - float exactLight = (isBlend || !isWorldDraw) ? 1.0f : (float)(1 << r_mapOverBrightBits->integer); -#endif + qboolean is2DDraw = backEnd.currentEntity == &backEnd.entity2D; + + float overbright = (isBlend || is2DDraw) ? 1.0f : (float)(1 << tr.overbrightBits); + + fog_t *fog; baseColor[0] = baseColor[1] = - baseColor[2] = exactLight; + baseColor[2] = baseColor[3] = 1.0f; vertColor[0] = @@ -469,11 +425,6 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t // switch ( pStage->rgbGen ) { - case CGEN_IDENTITY_LIGHTING: - baseColor[0] = - baseColor[1] = - baseColor[2] = tr.identityLight; - break; case CGEN_EXACT_VERTEX: case CGEN_EXACT_VERTEX_LIT: baseColor[0] = @@ -483,7 +434,7 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor[0] = vertColor[1] = - vertColor[2] = exactLight; + vertColor[2] = overbright; vertColor[3] = 1.0f; break; case CGEN_CONST: @@ -493,47 +444,33 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t baseColor[3] = pStage->constantColor[3] / 255.0f; break; case CGEN_VERTEX: - baseColor[0] = + case CGEN_VERTEX_LIT: + baseColor[0] = baseColor[1] = baseColor[2] = baseColor[3] = 0.0f; vertColor[0] = vertColor[1] = - vertColor[2] = tr.identityLight; + vertColor[2] = vertColor[3] = 1.0f; break; - case CGEN_VERTEX_LIT: - baseColor[0] = - baseColor[1] = - baseColor[2] = - baseColor[3] = 0.0f; - - vertColor[0] = - vertColor[1] = - vertColor[2] = - vertColor[3] = tr.identityLight; - break; case CGEN_ONE_MINUS_VERTEX: baseColor[0] = baseColor[1] = - baseColor[2] = tr.identityLight; + baseColor[2] = 1.0f; vertColor[0] = vertColor[1] = - vertColor[2] = -tr.identityLight; + vertColor[2] = -1.0f; break; case CGEN_FOG: - { - fog_t *fog; + fog = tr.world->fogs + tess.fogNum; - fog = tr.world->fogs + tess.fogNum; - - baseColor[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f; - baseColor[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f; - baseColor[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f; - baseColor[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; - } + baseColor[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f; + baseColor[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f; + baseColor[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f; + baseColor[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; break; case CGEN_WAVEFORM: baseColor[0] = @@ -560,6 +497,11 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t break; case CGEN_IDENTITY: case CGEN_LIGHTING_DIFFUSE: + baseColor[0] = + baseColor[1] = + baseColor[2] = overbright; + break; + case CGEN_IDENTITY_LIGHTING: case CGEN_BAD: break; } @@ -610,19 +552,6 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t break; } - // multiply color by overbrightbits if this isn't a blend - if (tr.overbrightBits && !isBlend) - { - float scale = 1 << tr.overbrightBits; - - baseColor[0] *= scale; - baseColor[1] *= scale; - baseColor[2] *= scale; - vertColor[0] *= scale; - vertColor[1] *= scale; - vertColor[2] *= scale; - } - // FIXME: find some way to implement this. #if 0 // if in greyscale rendering mode turn all color values into greyscale. @@ -740,7 +669,7 @@ static void ForwardDlight( void ) { vec4_t texOffTurb; if ( !( tess.dlightBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this light + continue; // this surface definitely doesn't have any of this light } dl = &backEnd.refdef.dlights[l]; @@ -822,6 +751,7 @@ static void ForwardDlight( void ) { // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0); GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); @@ -872,14 +802,7 @@ static void ForwardDlight( void ) { // draw // - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } + R_DrawElements(input->numIndexes, input->firstIndex); backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes; @@ -910,7 +833,7 @@ static void ProjectPshadowVBOGLSL( void ) { vec4_t vector; if ( !( tess.pshadowBits & ( 1 << l ) ) ) { - continue; // this surface definately doesn't have any of this shadow + continue; // this surface definitely doesn't have any of this shadow } ps = &backEnd.refdef.pshadows[l]; @@ -941,6 +864,7 @@ static void ProjectPshadowVBOGLSL( void ) { // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0); GL_BindToTMU( tr.pshadowMaps[l], TB_DIFFUSEMAP ); @@ -948,14 +872,7 @@ static void ProjectPshadowVBOGLSL( void ) { // draw // - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } + R_DrawElements(input->numIndexes, input->firstIndex); backEnd.pc.c_totalIndexes += tess.numIndexes; //backEnd.pc.c_dlightIndexes += tess.numIndexes; @@ -991,6 +908,8 @@ static void RB_FogPass( void ) { if (glState.vertexAnimation) index |= FOGDEF_USE_VERTEX_ANIMATION; + else if (glState.boneAnimation) + index |= FOGDEF_USE_BONE_ANIMATION; sp = &tr.fogShader[index]; } @@ -1004,6 +923,11 @@ static void RB_FogPass( void ) { GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); + + if (glState.boneAnimation) + { + GLSL_SetUniformMat4BoneMatrix(sp, UNIFORM_BONEMATRIX, glState.boneMatrix, glState.boneAnimation); + } GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) @@ -1029,16 +953,9 @@ static void RB_FogPass( void ) { } else { GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); } + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0); - if (tess.multiDrawPrimitives) - { - shaderCommands_t *input = &tess; - R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - } + R_DrawElements(tess.numIndexes, tess.firstIndex); } @@ -1052,9 +969,7 @@ static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input ) if (vertexAttribs & ATTR_NORMAL) { vertexAttribs |= ATTR_NORMAL2; -#ifdef USE_VERT_TANGENT_SPACE vertexAttribs |= ATTR_TANGENT2; -#endif } } @@ -1071,6 +986,8 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) int deformGen; vec5_t deformParams; + qboolean renderToCubemap = tr.renderCubeFbo && glState.currentFBO == tr.renderCubeFbo; + ComputeDeformValues(&deformGen, deformParams); ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); @@ -1095,7 +1012,14 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) { - index |= LIGHTDEF_ENTITY; + if (glState.boneAnimation) + { + index |= LIGHTDEF_ENTITY_BONE_ANIMATION; + } + else + { + index |= LIGHTDEF_ENTITY_VERTEX_ANIMATION; + } } if (pStage->stateBits & GLS_ATEST_BITS) @@ -1118,6 +1042,10 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; } + else if (glState.boneAnimation) + { + shaderAttribs |= GENERICDEF_USE_BONE_ANIMATION; + } if (pStage->stateBits & GLS_ATEST_BITS) { @@ -1133,7 +1061,14 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) { - index |= LIGHTDEF_ENTITY; + if (glState.boneAnimation) + { + index |= LIGHTDEF_ENTITY_BONE_ANIMATION; + } + else + { + index |= LIGHTDEF_ENTITY_VERTEX_ANIMATION; + } } if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (index & LIGHTDEF_LIGHTTYPE_MASK)) @@ -1141,9 +1076,9 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) index |= LIGHTDEF_USE_SHADOWMAP; } - if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP) + if (r_lightmap->integer && ((index & LIGHTDEF_LIGHTTYPE_MASK) == LIGHTDEF_USE_LIGHTMAP)) { - index = LIGHTDEF_USE_LIGHTMAP; + index = LIGHTDEF_USE_TCGEN_AND_TCMOD; } sp = &pStage->glslShaderGroup[index]; @@ -1164,6 +1099,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); + + if (glState.boneAnimation) + { + GLSL_SetUniformMat4BoneMatrix(sp, UNIFORM_BONEMATRIX, glState.boneMatrix, glState.boneAnimation); + } GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) @@ -1179,6 +1119,23 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) } GL_State( pStage->stateBits ); + if ((pStage->stateBits & GLS_ATEST_BITS) == GLS_ATEST_GT_0) + { + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 1); + } + else if ((pStage->stateBits & GLS_ATEST_BITS) == GLS_ATEST_LT_80) + { + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 2); + } + else if ((pStage->stateBits & GLS_ATEST_BITS) == GLS_ATEST_GE_80) + { + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 3); + } + else + { + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0); + } + { vec4_t baseColor; @@ -1186,13 +1143,6 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) ComputeShaderColors(pStage, baseColor, vertColor, pStage->stateBits); - if ((backEnd.refdef.colorScale != 1.0f) && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)) - { - // use VectorScale to only scale first three values, not alpha - VectorScale(baseColor, backEnd.refdef.colorScale, baseColor); - VectorScale(vertColor, backEnd.refdef.colorScale, vertColor); - } - GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); } @@ -1232,25 +1182,51 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); } - ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); - GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); - - GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); - if (pStage->bundle[0].tcGen == TCGEN_VECTOR) + if (r_lightmap->integer) { - vec3_t vec; + vec4_t v; + VectorSet4(v, 1.0f, 0.0f, 0.0f, 1.0f); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, v); + VectorSet4(v, 0.0f, 0.0f, 0.0f, 0.0f); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, v); - VectorCopy(pStage->bundle[0].tcGenVectors[0], vec); - GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR0, vec); - VectorCopy(pStage->bundle[0].tcGenVectors[1], vec); - GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec); + GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, TCGEN_LIGHTMAP); + } + else + { + ComputeTexMods(pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); + + GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); + if (pStage->bundle[0].tcGen == TCGEN_VECTOR) + { + vec3_t vec; + + VectorCopy(pStage->bundle[0].tcGenVectors[0], vec); + GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR0, vec); + VectorCopy(pStage->bundle[0].tcGenVectors[1], vec); + GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec); + } } GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale); - GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, pStage->specularScale); + + { + vec4_t specularScale; + Vector4Copy(pStage->specularScale, specularScale); + + if (renderToCubemap) + { + // force specular to nonmetal if rendering cubemaps + if (r_pbr->integer) + specularScale[1] = 0.0f; + } + + GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, specularScale); + } //GLSL_SetUniformFloat(sp, UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale); @@ -1271,7 +1247,9 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK)) { - GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP); + // FIXME: screenShadowImage is NULL if no framebuffers + if (tr.screenShadowImage) + GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP); GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol); if (r_pbr->integer) { @@ -1294,7 +1272,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) { - if (i == TB_LIGHTMAP) + if (i == TB_COLORMAP) R_BindAnimatedImageToTMU( &pStage->bundle[TB_LIGHTMAP], i); else GL_BindToTMU( tr.whiteImage, i ); @@ -1304,7 +1282,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) { - if (i == TB_LIGHTMAP) + if (i == TB_COLORMAP) R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], i); else GL_BindToTMU( tr.whiteImage, i ); @@ -1383,7 +1361,9 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) vec4_t vec; cubemap_t *cubemap = &tr.cubemaps[input->cubemapIndex - 1]; - GL_BindToTMU( cubemap->image, TB_CUBEMAP); + // FIXME: cubemap image could be NULL if cubemap isn't renderer or loaded + if (cubemap->image) + GL_BindToTMU( cubemap->image, TB_CUBEMAP); VectorSubtract(cubemap->origin, backEnd.viewParms.or.origin, vec); vec[3] = 1.0f; @@ -1396,14 +1376,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) // // draw // - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } + R_DrawElements(input->numIndexes, input->firstIndex); // allow skipping out to show just lightmaps during development if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) @@ -1425,7 +1398,16 @@ static void RB_RenderShadowmap( shaderCommands_t *input ) ComputeDeformValues(&deformGen, deformParams); { - shaderProgram_t *sp = &tr.shadowmapShader; + shaderProgram_t *sp = &tr.shadowmapShader[0]; + + if (glState.vertexAnimation) + { + sp = &tr.shadowmapShader[SHADOWMAPDEF_USE_VERTEX_ANIMATION]; + } + else if (glState.boneAnimation) + { + sp = &tr.shadowmapShader[SHADOWMAPDEF_USE_BONE_ANIMATION]; + } vec4_t vector; @@ -1437,6 +1419,11 @@ static void RB_RenderShadowmap( shaderCommands_t *input ) GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); + if (glState.boneAnimation) + { + GLSL_SetUniformMat4BoneMatrix(sp, UNIFORM_BONEMATRIX, glState.boneMatrix, glState.boneAnimation); + } + GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { @@ -1450,6 +1437,7 @@ static void RB_RenderShadowmap( shaderCommands_t *input ) GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar); GL_State( 0 ); + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0); // // do multitexture @@ -1460,14 +1448,7 @@ static void RB_RenderShadowmap( shaderCommands_t *input ) // draw // - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVao(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVao(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } + R_DrawElements(input->numIndexes, input->firstIndex); } } } @@ -1603,7 +1584,7 @@ void RB_StageIteratorGeneric( void ) // // now do any dynamic lighting needed // - if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE + if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE && r_lightmap->integer == 0 && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) { if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader && (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer) @@ -1632,7 +1613,6 @@ void RB_StageIteratorGeneric( void ) } } - /* ** RB_EndSurface */ @@ -1662,6 +1642,12 @@ void RB_EndSurface( void ) { return; } + if (tess.useCacheVao) + { + // upload indexes now + VaoCache_Commit(); + } + // // update performance counters // @@ -1688,7 +1674,6 @@ void RB_EndSurface( void ) { tess.numIndexes = 0; tess.numVertexes = 0; tess.firstIndex = 0; - tess.multiDrawPrimitives = 0; GLimp_LogComment( "----------\n" ); } diff --git a/code/renderergl2/tr_shade_calc.c b/code/renderergl2/tr_shade_calc.c index bb16bb0d..15cfb9c6 100644 --- a/code/renderergl2/tr_shade_calc.c +++ b/code/renderergl2/tr_shade_calc.c @@ -22,12 +22,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_shade_calc.c #include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif -#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ri.ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) +#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ( (int64_t) ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude)) static float *TableForFunc( genFunc_t func ) { @@ -116,16 +113,16 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) vec3_t offset; float scale; float *xyz = ( float * ) tess.xyz; - uint32_t *normal = tess.normal; + int16_t *normal = tess.normal[0]; float *table; if ( ds->deformationWave.frequency == 0 ) { scale = EvalWaveForm( &ds->deformationWave ); - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) { - R_VaoUnpackNormal(offset, *normal); + R_VaoUnpackNormal(offset, normal); xyz[0] += offset[0] * scale; xyz[1] += offset[1] * scale; @@ -136,7 +133,7 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) { table = TableForFunc( ds->deformationWave.func ); - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) { float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread; @@ -145,7 +142,7 @@ void RB_CalcDeformVertexes( deformStage_t *ds ) ds->deformationWave.phase + off, ds->deformationWave.frequency ); - R_VaoUnpackNormal(offset, *normal); + R_VaoUnpackNormal(offset, normal); xyz[0] += offset[0] * scale; xyz[1] += offset[1] * scale; @@ -165,12 +162,12 @@ void RB_CalcDeformNormals( deformStage_t *ds ) { int i; float scale; float *xyz = ( float * ) tess.xyz; - uint32_t *normal = tess.normal; + int16_t *normal = tess.normal[0]; - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal++ ) { + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) { vec3_t fNormal; - R_VaoUnpackNormal(fNormal, *normal); + R_VaoUnpackNormal(fNormal, normal); scale = 0.98f; scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale, @@ -189,7 +186,7 @@ void RB_CalcDeformNormals( deformStage_t *ds ) { VectorNormalizeFast( fNormal ); - R_VaoPackNormal((byte *)normal, fNormal); + R_VaoPackNormal(normal, fNormal); } } @@ -203,17 +200,17 @@ void RB_CalcBulgeVertexes( deformStage_t *ds ) { int i; const float *st = ( const float * ) tess.texCoords[0]; float *xyz = ( float * ) tess.xyz; - uint32_t *normal = tess.normal; - float now; + int16_t *normal = tess.normal[0]; + double now; - now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f; + now = backEnd.refdef.time * 0.001 * ds->bulgeSpeed; - for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal++ ) { - int off; + for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 2, normal += 4 ) { + int64_t off; float scale; vec3_t fNormal; - R_VaoUnpackNormal(fNormal, *normal); + R_VaoUnpackNormal(fNormal, normal); off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now ); @@ -350,7 +347,7 @@ static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) { ===================== AutospriteDeform -Assuming all the triangles for this shader are independant +Assuming all the triangles for this shader are independent quads, rebuild them as forward facing sprites ===================== */ @@ -384,6 +381,7 @@ static void AutospriteDeform( void ) { } for ( i = 0 ; i < oldVerts ; i+=4 ) { + vec4_t color; // find the midpoint xyz = tess.xyz[i]; @@ -414,7 +412,8 @@ static void AutospriteDeform( void ) { VectorScale(up, axisLength, up); } - RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] ); + VectorScale4(tess.color[i], 1.0f / 65535.0f, color); + RB_AddQuadStamp( mid, left, up, color ); } } @@ -774,8 +773,8 @@ void RB_CalcScaleTexMatrix( const float scale[2], float *matrix ) */ void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix ) { - float timeScale = tess.shaderTime; - float adjustedScrollS, adjustedScrollT; + double timeScale = tess.shaderTime; + double adjustedScrollS, adjustedScrollT; adjustedScrollS = scrollSpeed[0] * timeScale; adjustedScrollT = scrollSpeed[1] * timeScale; @@ -803,9 +802,9 @@ void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix ) */ void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix ) { - float timeScale = tess.shaderTime; - float degs; - int index; + double timeScale = tess.shaderTime; + double degs; + int64_t index; float sinValue, cosValue; degs = -degsPerSecond * timeScale; diff --git a/code/renderergl2/tr_shader.c b/code/renderergl2/tr_shader.c index 0ef90211..0cd78a78 100644 --- a/code/renderergl2/tr_shader.c +++ b/code/renderergl2/tr_shader.c @@ -744,6 +744,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) // else if ( !Q_stricmp( token, "animMap" ) ) { + int totalImages = 0; + token = COM_ParseExt( text, qfalse ); if ( !token[0] ) { @@ -778,6 +780,12 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) } stage->bundle[0].numImageAnimations++; } + totalImages++; + } + + if ( totalImages > MAX_IMAGE_ANIMATIONS ) { + ri.Printf( PRINT_WARNING, "WARNING: ignoring excess images for 'animMap' (found %d, max is %d) in shader '%s'\n", + totalImages, MAX_IMAGE_ANIMATIONS, shader.name ); } } else if ( !Q_stricmp( token, "videoMap" ) ) @@ -792,6 +800,8 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) if (stage->bundle[0].videoMapHandle != -1) { stage->bundle[0].isVideoMap = qtrue; stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle]; + } else { + ri.Printf( PRINT_WARNING, "WARNING: could not load '%s' for 'videoMap' keyword in shader '%s'\n", token, shader.name ); } } // @@ -1105,6 +1115,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) stage->specularScale[1] = (stage->specularScale[0] < 0.5f) ? 0.0f : 1.0f; stage->specularScale[0] = smoothness; } + else { // two values, rgb then gloss stage->specularScale[3] = stage->specularScale[1]; @@ -1123,7 +1134,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) continue; } - stage->specularScale[2] = atof( token ); + stage->specularScale[3] = atof( token ); } // @@ -1826,11 +1837,13 @@ static qboolean ParseShader( char **text ) if (isGL2Sun) { - token = COM_ParseExt( text, qfalse ); - tr.mapLightScale = atof(token); - token = COM_ParseExt( text, qfalse ); tr.sunShadowScale = atof(token); + + // parse twice, since older shaders may include mapLightScale before sunShadowScale + token = COM_ParseExt( text, qfalse ); + if (token[0]) + tr.sunShadowScale = atof(token); } SkipRestOfLine( text ); @@ -2118,12 +2131,10 @@ static void ComputeVertexAttribs(void) { shader.vertexAttribs |= ATTR_NORMAL; -#ifdef USE_VERT_TANGENT_SPACE if ((pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && !(r_normalMapping->integer == 0 && r_specularMapping->integer == 0)) { shader.vertexAttribs |= ATTR_TANGENT; } -#endif switch (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) { @@ -2222,7 +2233,7 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse, defs |= LIGHTDEF_USE_LIGHT_VERTEX; } - if (r_deluxeMapping->integer && tr.worldDeluxeMapping && lightmap) + if (r_deluxeMapping->integer && tr.worldDeluxeMapping && lightmap && shader.lightmapIndex >= 0) { //ri.Printf(PRINT_ALL, ", deluxemap"); diffuse->bundle[TB_DELUXEMAP] = lightmap->bundle[0]; @@ -2245,12 +2256,24 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse, { char normalName[MAX_QPATH]; image_t *normalImg; - imgFlags_t normalFlags = (diffuseImg->flags & ~(IMGFLAG_GENNORMALMAP | IMGFLAG_SRGB)) | IMGFLAG_NOLIGHTSCALE; + imgFlags_t normalFlags = (diffuseImg->flags & ~IMGFLAG_GENNORMALMAP) | IMGFLAG_NOLIGHTSCALE; + // try a normalheight image first COM_StripExtension(diffuseImg->imgName, normalName, MAX_QPATH); - Q_strcat(normalName, MAX_QPATH, "_n"); + Q_strcat(normalName, MAX_QPATH, "_nh"); - normalImg = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags); + normalImg = R_FindImageFile(normalName, IMGTYPE_NORMALHEIGHT, normalFlags); + + if (normalImg) + { + parallax = qtrue; + } + else + { + // try a normal image ("_n" suffix) + normalName[strlen(normalName) - 1] = '\0'; + normalImg = R_FindImageFile(normalName, IMGTYPE_NORMAL, normalFlags); + } if (normalImg) { @@ -2279,7 +2302,7 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse, { char specularName[MAX_QPATH]; image_t *specularImg; - imgFlags_t specularFlags = (diffuseImg->flags & ~(IMGFLAG_GENNORMALMAP | IMGFLAG_SRGB)) | IMGFLAG_NOLIGHTSCALE; + imgFlags_t specularFlags = (diffuseImg->flags & ~IMGFLAG_GENNORMALMAP) | IMGFLAG_NOLIGHTSCALE; COM_StripExtension(diffuseImg->imgName, specularName, MAX_QPATH); Q_strcat(specularName, MAX_QPATH, "_s"); @@ -2399,6 +2422,8 @@ static int CollapseStagesToGLSL(void) if (!skip) { + qboolean usedLightmap = qfalse; + for (i = 0; i < MAX_SHADER_STAGES; i++) { shaderStage_t *pStage = &stages[i]; @@ -2457,7 +2482,16 @@ static int CollapseStagesToGLSL(void) case ST_COLORMAP: if (pStage2->bundle[0].tcGen == TCGEN_LIGHTMAP) { - lightmap = pStage2; + int blendBits = pStage->stateBits & ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS ); + + // Only add lightmap to blendfunc filter stage if it's the first time lightmap is used + // otherwise it will cause the shader to be darkened by the lightmap multiple times. + if (!usedLightmap || (blendBits != (GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO) + && blendBits != (GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR))) + { + lightmap = pStage2; + usedLightmap = qtrue; + } } break; @@ -2772,7 +2806,7 @@ static shader_t *GeneratePermanentShader( void ) { VertexLightingCollapse If vertex lighting is enabled, only render a single -pass, trying to guess which is the correct one to best aproximate +pass, trying to guess which is the correct one to best approximate what it is supposed to look like. ================= */ @@ -3050,9 +3084,7 @@ static shader_t *FinishShader( void ) { // // look for multitexture potential // - if ( qglActiveTextureARB ) { - stage = CollapseStagesToGLSL(); - } + stage = CollapseStagesToGLSL(); if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) { if (vertexLightmap) { @@ -3194,18 +3226,18 @@ be defined for every single image used in the game, three default shader behaviors can be auto-created for any image: If lightmapIndex == LIGHTMAP_NONE, then the image will have -dynamic diffuse lighting applied to it, as apropriate for most +dynamic diffuse lighting applied to it, as appropriate for most entity skin surfaces. If lightmapIndex == LIGHTMAP_2D, then the image will be used for 2D rendering unless an explicit shader is found If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use -the vertex rgba modulate values, as apropriate for misc_model +the vertex rgba modulate values, as appropriate for misc_model pre-lit surfaces. Other lightmapIndex values will have a lightmap stage created -and src*dest blending applied with the texture, as apropriate for +and src*dest blending applied with the texture, as appropriate for most world construction surfaces. =============== diff --git a/code/renderergl2/tr_shadows.c b/code/renderergl2/tr_shadows.c index 76371752..697800c1 100644 --- a/code/renderergl2/tr_shadows.c +++ b/code/renderergl2/tr_shadows.c @@ -43,8 +43,8 @@ typedef struct { static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS]; static int numEdgeDefs[SHADER_MAX_VERTEXES]; -static int facing[SHADER_MAX_INDEXES/3]; -static vec3_t shadowXyz[SHADER_MAX_VERTEXES]; +//static int facing[SHADER_MAX_INDEXES/3]; +//static vec3_t shadowXyz[SHADER_MAX_VERTEXES]; void R_AddEdgeDef( int i1, int i2, int facing ) { int c; @@ -60,6 +60,8 @@ void R_AddEdgeDef( int i1, int i2, int facing ) { } void R_RenderShadowEdges( void ) { + // FIXME: implement this +#if 0 int i; #if 0 @@ -138,6 +140,7 @@ void R_RenderShadowEdges( void ) { } } #endif +#endif } /* @@ -153,6 +156,8 @@ triangleFromEdge[ v1 ][ v2 ] ================= */ void RB_ShadowTessEnd( void ) { + // FIXME: implement this +#if 0 int i; int numTris; vec3_t lightDir; @@ -162,7 +167,7 @@ void RB_ShadowTessEnd( void ) { return; } - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); + VectorCopy( backEnd.currentEntity->modelLightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { @@ -230,6 +235,7 @@ void RB_ShadowTessEnd( void ) { // reenable writing to the color buffer qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); +#endif } @@ -244,6 +250,8 @@ overlap and double darken. ================= */ void RB_ShadowFinish( void ) { + // FIXME: implement this +#if 0 if ( r_shadows->integer != 2 ) { return; } @@ -253,7 +261,6 @@ void RB_ShadowFinish( void ) { qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_NOTEQUAL, 0, 255 ); - qglDisable (GL_CLIP_PLANE0); GL_Cull( CT_TWO_SIDED ); GL_BindToTMU( tr.whiteImage, TB_COLORMAP ); @@ -275,6 +282,7 @@ void RB_ShadowFinish( void ) { qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); +#endif } @@ -302,7 +310,7 @@ void RB_ProjectionShadowDeform( void ) { groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane; - VectorCopy( backEnd.currentEntity->lightDir, lightDir ); + VectorCopy( backEnd.currentEntity->modelLightDir, lightDir ); d = DotProduct( lightDir, ground ); // don't let the shadows get too long or go negative if ( d < 0.5 ) { diff --git a/code/renderergl2/tr_sky.c b/code/renderergl2/tr_sky.c index 840d0149..94f68d26 100644 --- a/code/renderergl2/tr_sky.c +++ b/code/renderergl2/tr_sky.c @@ -366,8 +366,6 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max int s, t; int firstVertex = tess.numVertexes; //int firstIndex = tess.numIndexes; - int minIndex = tess.minIndex; - int maxIndex = tess.maxIndex; vec4_t color; //tess.numVertexes = 0; @@ -386,8 +384,8 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2]; tess.xyz[tess.numVertexes][3] = 1.0; - tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; - tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; + tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0]; + tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1]; tess.numVertexes++; @@ -417,9 +415,6 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max } } - tess.minIndex = firstVertex; - tess.maxIndex = tess.numVertexes; - // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD); /* @@ -448,7 +443,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max color[0] = color[1] = - color[2] = backEnd.refdef.colorScale; + color[2] = color[3] = 1.0f; GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color); @@ -463,9 +458,11 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max VectorSet4(vector, 0.0, 0.0, 0.0, 0.0); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); + + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0); } - R_DrawElementsVao(tess.numIndexes - tess.firstIndex, tess.firstIndex, tess.minIndex, tess.maxIndex); + R_DrawElements(tess.numIndexes - tess.firstIndex, tess.firstIndex); //qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t))); @@ -475,8 +472,6 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max tess.numIndexes = tess.firstIndex; tess.numVertexes = firstVertex; tess.firstIndex = 0; - tess.minIndex = minIndex; - tess.maxIndex = maxIndex; } static void DrawSkyBox( shader_t *shader ) @@ -563,8 +558,8 @@ static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean ad for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) { VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; - tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; + tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0]; + tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1]; tess.numVertexes++; @@ -871,6 +866,7 @@ void RB_StageIteratorSky( void ) { mat4_t oldmodelview; GL_State( 0 ); + GL_Cull( CT_FRONT_SIDED ); //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); { diff --git a/code/renderergl2/tr_surface.c b/code/renderergl2/tr_surface.c index 72cd610e..3151638a 100644 --- a/code/renderergl2/tr_surface.c +++ b/code/renderergl2/tr_surface.c @@ -21,9 +21,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // tr_surf.c #include "tr_local.h" -#if idppc_altivec && !defined(MACOS_X) -#include -#endif /* @@ -68,7 +65,7 @@ void RB_CheckOverflow( int verts, int indexes ) { void RB_CheckVao(vao_t *vao) { - if (vao != glState.currentVao || tess.multiDrawPrimitives >= MAX_MULTIDRAW_PRIMITIVES) + if (vao != glState.currentVao) { RB_EndSurface(); RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); @@ -88,7 +85,8 @@ RB_AddQuadStampExt */ void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], float s1, float t1, float s2, float t2 ) { vec3_t normal; - uint32_t pNormal; + int16_t iNormal[4]; + uint16_t iColor[4]; int ndx; RB_CheckVao(tess.vao); @@ -126,31 +124,35 @@ void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], // constant normal all the way around VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal ); - R_VaoPackNormal((byte *)&pNormal, normal); - tess.normal[ndx] = - tess.normal[ndx+1] = - tess.normal[ndx+2] = - tess.normal[ndx+3] = pNormal; + R_VaoPackNormal(iNormal, normal); + + VectorCopy4(iNormal, tess.normal[ndx]); + VectorCopy4(iNormal, tess.normal[ndx + 1]); + VectorCopy4(iNormal, tess.normal[ndx + 2]); + VectorCopy4(iNormal, tess.normal[ndx + 3]); // standard square texture coordinates - VectorSet2(tess.texCoords[ndx ][0], s1, t1); - VectorSet2(tess.texCoords[ndx ][1], s1, t1); + VectorSet2(tess.texCoords[ndx], s1, t1); + VectorSet2(tess.lightCoords[ndx], s1, t1); - VectorSet2(tess.texCoords[ndx+1][0], s2, t1); - VectorSet2(tess.texCoords[ndx+1][1], s2, t1); + VectorSet2(tess.texCoords[ndx+1], s2, t1); + VectorSet2(tess.lightCoords[ndx+1], s2, t1); - VectorSet2(tess.texCoords[ndx+2][0], s2, t2); - VectorSet2(tess.texCoords[ndx+2][1], s2, t2); + VectorSet2(tess.texCoords[ndx+2], s2, t2); + VectorSet2(tess.lightCoords[ndx+2], s2, t2); - VectorSet2(tess.texCoords[ndx+3][0], s1, t2); - VectorSet2(tess.texCoords[ndx+3][1], s1, t2); + VectorSet2(tess.texCoords[ndx+3], s1, t2); + VectorSet2(tess.lightCoords[ndx+3], s1, t2); // constant color all the way around // should this be identity and let the shader specify from entity? - VectorCopy4(color, tess.vertexColors[ndx]); - VectorCopy4(color, tess.vertexColors[ndx+1]); - VectorCopy4(color, tess.vertexColors[ndx+2]); - VectorCopy4(color, tess.vertexColors[ndx+3]); + + R_VaoPackColor(iColor, color); + + VectorCopy4(iColor, tess.color[ndx]); + VectorCopy4(iColor, tess.color[ndx + 1]); + VectorCopy4(iColor, tess.color[ndx + 2]); + VectorCopy4(iColor, tess.color[ndx + 3]); tess.numVertexes += 4; tess.numIndexes += 6; @@ -182,19 +184,19 @@ void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4]) tess.firstIndex = 0; VectorCopy4(quadVerts[0], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[0], tess.texCoords[tess.numVertexes][0]); + VectorCopy2(texCoords[0], tess.texCoords[tess.numVertexes]); tess.numVertexes++; VectorCopy4(quadVerts[1], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[1], tess.texCoords[tess.numVertexes][0]); + VectorCopy2(texCoords[1], tess.texCoords[tess.numVertexes]); tess.numVertexes++; VectorCopy4(quadVerts[2], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[2], tess.texCoords[tess.numVertexes][0]); + VectorCopy2(texCoords[2], tess.texCoords[tess.numVertexes]); tess.numVertexes++; VectorCopy4(quadVerts[3], tess.xyz[tess.numVertexes]); - VectorCopy2(texCoords[3], tess.texCoords[tess.numVertexes][0]); + VectorCopy2(texCoords[3], tess.texCoords[tess.numVertexes]); tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; @@ -203,18 +205,14 @@ void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4]) tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; - tess.minIndex = 0; - tess.maxIndex = 3; RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD); - R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); + R_DrawElements(tess.numIndexes, tess.firstIndex); tess.numIndexes = 0; tess.numVertexes = 0; tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; } @@ -293,12 +291,12 @@ static void RB_SurfacePolychain( srfPoly_t *p ) { numv = tess.numVertexes; for ( i = 0; i < p->numVerts; i++ ) { VectorCopy( p->verts[i].xyz, tess.xyz[numv] ); - tess.texCoords[numv][0][0] = p->verts[i].st[0]; - tess.texCoords[numv][0][1] = p->verts[i].st[1]; - tess.vertexColors[numv][0] = p->verts[ i ].modulate[0] / 255.0f; - tess.vertexColors[numv][1] = p->verts[ i ].modulate[1] / 255.0f; - tess.vertexColors[numv][2] = p->verts[ i ].modulate[2] / 255.0f; - tess.vertexColors[numv][3] = p->verts[ i ].modulate[3] / 255.0f; + tess.texCoords[numv][0] = p->verts[i].st[0]; + tess.texCoords[numv][1] = p->verts[i].st[1]; + tess.color[numv][0] = (int)p->verts[i].modulate[0] * 257; + tess.color[numv][1] = (int)p->verts[i].modulate[1] * 257; + tess.color[numv][2] = (int)p->verts[i].modulate[2] * 257; + tess.color[numv][3] = (int)p->verts[i].modulate[3] * 257; numv++; } @@ -320,13 +318,11 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn glIndex_t *inIndex; srfVert_t *dv; float *xyz, *texCoords, *lightCoords; - uint32_t *lightdir; - uint32_t *normal; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *tangent; -#endif + int16_t *lightdir; + int16_t *normal; + int16_t *tangent; glIndex_t *outIndex; - float *color; + uint16_t *color; RB_CheckVao(tess.vao); @@ -350,51 +346,49 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn if ( tess.shader->vertexAttribs & ATTR_NORMAL ) { dv = verts; - normal = &tess.normal[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, normal++ ) - R_VaoPackNormal((byte *)normal, dv->normal); + normal = tess.normal[ tess.numVertexes ]; + for ( i = 0 ; i < numVerts ; i++, dv++, normal+=4 ) + VectorCopy4(dv->normal, normal); } -#ifdef USE_VERT_TANGENT_SPACE if ( tess.shader->vertexAttribs & ATTR_TANGENT ) { dv = verts; - tangent = &tess.tangent[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, tangent++ ) - R_VaoPackTangent((byte *)tangent, dv->tangent); + tangent = tess.tangent[ tess.numVertexes ]; + for ( i = 0 ; i < numVerts ; i++, dv++, tangent+=4 ) + VectorCopy4(dv->tangent, tangent); } -#endif if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) { dv = verts; - texCoords = tess.texCoords[ tess.numVertexes ][0]; - for ( i = 0 ; i < numVerts ; i++, dv++, texCoords+=4 ) + texCoords = tess.texCoords[tess.numVertexes]; + for ( i = 0 ; i < numVerts ; i++, dv++, texCoords+=2 ) VectorCopy2(dv->st, texCoords); } if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD ) { dv = verts; - lightCoords = tess.texCoords[ tess.numVertexes ][1]; - for ( i = 0 ; i < numVerts ; i++, dv++, lightCoords+=4 ) + lightCoords = tess.lightCoords[ tess.numVertexes ]; + for ( i = 0 ; i < numVerts ; i++, dv++, lightCoords+=2 ) VectorCopy2(dv->lightmap, lightCoords); } if ( tess.shader->vertexAttribs & ATTR_COLOR ) { dv = verts; - color = tess.vertexColors[ tess.numVertexes ]; + color = tess.color[ tess.numVertexes ]; for ( i = 0 ; i < numVerts ; i++, dv++, color+=4 ) - VectorCopy4(dv->vertexColors, color); + VectorCopy4(dv->color, color); } if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) { dv = verts; - lightdir = &tess.lightdir[ tess.numVertexes ]; - for ( i = 0 ; i < numVerts ; i++, dv++, lightdir++ ) - R_VaoPackNormal((byte *)lightdir, dv->lightdir); + lightdir = tess.lightdir[ tess.numVertexes ]; + for ( i = 0 ; i < numVerts ; i++, dv++, lightdir+=4 ) + VectorCopy4(dv->lightdir, lightdir); } #if 0 // nothing even uses vertex dlightbits @@ -409,118 +403,59 @@ static void RB_SurfaceVertsAndIndexes( int numVerts, srfVert_t *verts, int numIn tess.numVertexes += numVerts; } -static qboolean RB_SurfaceVao(vao_t *vao, int numVerts, int numIndexes, int firstIndex, int minIndex, int maxIndex, int dlightBits, int pshadowBits, qboolean shaderCheck) +static qboolean RB_SurfaceVaoCached(int numVerts, srfVert_t *verts, int numIndexes, glIndex_t *indexes, int dlightBits, int pshadowBits) { - int i, mergeForward, mergeBack; - GLvoid *firstIndexOffset, *lastIndexOffset; + qboolean recycleVertexBuffer = qfalse; + qboolean recycleIndexBuffer = qfalse; + qboolean endSurface = qfalse; - if (!vao) - { + if (!(!ShaderRequiresCPUDeforms(tess.shader) && !tess.shader->isSky && !tess.shader->isPortal)) return qfalse; - } - if (shaderCheck && !(!ShaderRequiresCPUDeforms(tess.shader) && !tess.shader->isSky && !tess.shader->isPortal)) - { + if (!numIndexes || !numVerts) return qfalse; - } - RB_CheckVao(vao); + VaoCache_BindVao(); tess.dlightBits |= dlightBits; tess.pshadowBits |= pshadowBits; - // merge this into any existing multidraw primitives - mergeForward = -1; - mergeBack = -1; - firstIndexOffset = BUFFER_OFFSET(firstIndex * sizeof(glIndex_t)); - lastIndexOffset = BUFFER_OFFSET((firstIndex + numIndexes) * sizeof(glIndex_t)); + VaoCache_CheckAdd(&endSurface, &recycleVertexBuffer, &recycleIndexBuffer, numVerts, numIndexes); - if (tess.multiDrawPrimitives && r_mergeMultidraws->integer) + if (endSurface) { - i = 0; - - if (r_mergeMultidraws->integer == 1) - { - // lazy merge, only check the last primitive - i = tess.multiDrawPrimitives - 1; - } - - for (; i < tess.multiDrawPrimitives; i++) - { - if (firstIndexOffset == tess.multiDrawFirstIndex[i] + tess.multiDrawNumIndexes[i]) - { - mergeBack = i; - - if (mergeForward != -1) - break; - } - - if (lastIndexOffset == tess.multiDrawFirstIndex[i]) - { - mergeForward = i; - - if (mergeBack != -1) - break; - } - } + RB_EndSurface(); + RB_BeginSurface(tess.shader, tess.fogNum, tess.cubemapIndex); } - if (mergeBack != -1 && mergeForward == -1) - { - tess.multiDrawNumIndexes[mergeBack] += numIndexes; - tess.multiDrawMinIndex[mergeBack] = MIN(tess.multiDrawMinIndex[mergeBack], minIndex); - tess.multiDrawMaxIndex[mergeBack] = MAX(tess.multiDrawMaxIndex[mergeBack], maxIndex); - backEnd.pc.c_multidrawsMerged++; - } - else if (mergeBack == -1 && mergeForward != -1) - { - tess.multiDrawNumIndexes[mergeForward] += numIndexes; - tess.multiDrawFirstIndex[mergeForward] = firstIndexOffset; - tess.multiDrawMinIndex[mergeForward] = MIN(tess.multiDrawMinIndex[mergeForward], minIndex); - tess.multiDrawMaxIndex[mergeForward] = MAX(tess.multiDrawMaxIndex[mergeForward], maxIndex); - backEnd.pc.c_multidrawsMerged++; - } - else if (mergeBack != -1 && mergeForward != -1) - { - tess.multiDrawNumIndexes[mergeBack] += numIndexes + tess.multiDrawNumIndexes[mergeForward]; - tess.multiDrawMinIndex[mergeBack] = MIN(tess.multiDrawMinIndex[mergeBack], MIN(tess.multiDrawMinIndex[mergeForward], minIndex)); - tess.multiDrawMaxIndex[mergeBack] = MAX(tess.multiDrawMaxIndex[mergeBack], MAX(tess.multiDrawMaxIndex[mergeForward], maxIndex)); - tess.multiDrawPrimitives--; + if (recycleVertexBuffer) + VaoCache_RecycleVertexBuffer(); - if (mergeForward != tess.multiDrawPrimitives) - { - tess.multiDrawNumIndexes[mergeForward] = tess.multiDrawNumIndexes[tess.multiDrawPrimitives]; - tess.multiDrawFirstIndex[mergeForward] = tess.multiDrawFirstIndex[tess.multiDrawPrimitives]; - tess.multiDrawMinIndex[mergeForward] = tess.multiDrawMinIndex[tess.multiDrawPrimitives]; - tess.multiDrawMaxIndex[mergeForward] = tess.multiDrawMaxIndex[tess.multiDrawPrimitives]; - } - backEnd.pc.c_multidrawsMerged += 2; - } - else //if (mergeBack == -1 && mergeForward == -1) - { - tess.multiDrawNumIndexes[tess.multiDrawPrimitives] = numIndexes; - tess.multiDrawFirstIndex[tess.multiDrawPrimitives] = firstIndexOffset; - tess.multiDrawMinIndex[tess.multiDrawPrimitives] = minIndex; - tess.multiDrawMaxIndex[tess.multiDrawPrimitives] = maxIndex; - tess.multiDrawPrimitives++; - } + if (recycleIndexBuffer) + VaoCache_RecycleIndexBuffer(); - backEnd.pc.c_multidraws++; + if (!tess.numVertexes) + VaoCache_InitQueue(); - tess.numIndexes += numIndexes; + VaoCache_AddSurface(verts, numVerts, indexes, numIndexes); + + tess.numIndexes += numIndexes; tess.numVertexes += numVerts; + tess.useInternalVao = qfalse; + tess.useCacheVao = qtrue; return qtrue; } + /* ============= RB_SurfaceTriangles ============= */ static void RB_SurfaceTriangles( srfBspSurface_t *srf ) { - if( RB_SurfaceVao (srf->vao, srf->numVerts, srf->numIndexes, - srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) + if (RB_SurfaceVaoCached(srf->numVerts, srf->verts, srf->numIndexes, + srf->indexes, srf->dlightBits, srf->pshadowBits)) { return; } @@ -583,8 +518,6 @@ static void RB_SurfaceBeam( void ) tess.numVertexes = 0; tess.numIndexes = 0; tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; for ( i = 0; i <= NUM_BEAM_SEGS; i++ ) { VectorCopy(start_points[ i % NUM_BEAM_SEGS ], tess.xyz[tess.numVertexes++]); @@ -601,9 +534,6 @@ static void RB_SurfaceBeam( void ) tess.indexes[tess.numIndexes++] = 1 + (i + 1) * 2; } - tess.minIndex = 0; - tess.maxIndex = tess.numVertexes; - // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function RB_UpdateTessVao(ATTR_POSITION); @@ -613,13 +543,13 @@ static void RB_SurfaceBeam( void ) GLSL_SetUniformVec4(sp, UNIFORM_COLOR, colorRed); - R_DrawElementsVao(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); + GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0); + + R_DrawElements(tess.numIndexes, tess.firstIndex); tess.numIndexes = 0; tess.numVertexes = 0; tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; } //================================================================================ @@ -640,36 +570,36 @@ static void DoRailCore( const vec3_t start, const vec3_t end, const vec3_t up, f // FIXME: use quad stamp? VectorMA( start, spanWidth, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25 / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25 / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25 / 255.0f; + tess.texCoords[tess.numVertexes][0] = 0; + tess.texCoords[tess.numVertexes][1] = 0; + tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 0.25f * 257.0f; + tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 0.25f * 257.0f; + tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 0.25f * 257.0f; tess.numVertexes++; VectorMA( start, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; + tess.texCoords[tess.numVertexes][0] = 0; + tess.texCoords[tess.numVertexes][1] = 1; + tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257; + tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257; + tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257; tess.numVertexes++; VectorMA( end, spanWidth, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; + tess.texCoords[tess.numVertexes][0] = t; + tess.texCoords[tess.numVertexes][1] = 0; + tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257; + tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257; + tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257; tess.numVertexes++; VectorMA( end, spanWidth2, up, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = t; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; + tess.texCoords[tess.numVertexes][0] = t; + tess.texCoords[tess.numVertexes][1] = 1; + tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257; + tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257; + tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257; tess.numVertexes++; tess.indexes[tess.numIndexes++] = vbase; @@ -724,11 +654,11 @@ static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, cons for ( j = 0; j < 4; j++ ) { VectorCopy( pos[j], tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = ( j < 2 ); - tess.texCoords[tess.numVertexes][0][1] = ( j && j != 3 ); - tess.vertexColors[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] / 255.0f; - tess.vertexColors[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] / 255.0f; - tess.vertexColors[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] / 255.0f; + tess.texCoords[tess.numVertexes][0] = (j < 2); + tess.texCoords[tess.numVertexes][1] = (j && j != 3); + tess.color[tess.numVertexes][0] = backEnd.currentEntity->e.shaderRGBA[0] * 257; + tess.color[tess.numVertexes][1] = backEnd.currentEntity->e.shaderRGBA[1] * 257; + tess.color[tess.numVertexes][2] = backEnd.currentEntity->e.shaderRGBA[2] * 257; tess.numVertexes++; VectorAdd( pos[j], dir, pos[j] ); @@ -841,308 +771,19 @@ static void RB_SurfaceLightningBolt( void ) { } } -#if 0 -/* -** VectorArrayNormalize -* -* The inputs to this routing seem to always be close to length = 1.0 (about 0.6 to 2.0) -* This means that we don't have to worry about zero length or enormously long vectors. -*/ -static void VectorArrayNormalize(vec4_t *normals, unsigned int count) + +static void LerpMeshVertexes(mdvSurface_t *surf, float backlerp) { -// assert(count); - -#if idppc - { - register float half = 0.5; - register float one = 1.0; - float *components = (float *)normals; - - // Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, - // runs *much* faster than calling sqrt(). We'll use a single Newton-Raphson - // refinement step to get a little more precision. This seems to yeild results - // that are correct to 3 decimal places and usually correct to at least 4 (sometimes 5). - // (That is, for the given input range of about 0.6 to 2.0). - do { - float x, y, z; - float B, y0, y1; - - x = components[0]; - y = components[1]; - z = components[2]; - components += 4; - B = x*x + y*y + z*z; - -#ifdef __GNUC__ - asm("frsqrte %0,%1" : "=f" (y0) : "f" (B)); -#else - y0 = __frsqrte(B); -#endif - y1 = y0 + half*y0*(one - B*y0*y0); - - x = x * y1; - y = y * y1; - components[-4] = x; - z = z * y1; - components[-3] = y; - components[-2] = z; - } while(count--); - } -#else // No assembly version for this architecture, or C_ONLY defined - // given the input, it's safe to call VectorNormalizeFast - while (count--) { - VectorNormalizeFast(normals[0]); - normals++; - } -#endif - -} -#endif - - - -/* -** LerpMeshVertexes -*/ -#if 0 -#if idppc_altivec -static void LerpMeshVertexes_altivec(md3Surface_t *surf, float backlerp) -{ - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale QALIGN(16); - float newXyzScale QALIGN(16); - float oldNormalScale QALIGN(16); - float newNormalScale QALIGN(16); - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - vector signed short newNormalsVec0; - vector signed short newNormalsVec1; - vector signed int newNormalsIntVec; - vector float newNormalsFloatVec; - vector float newXyzScaleVec; - vector unsigned char newNormalsLoadPermute; - vector unsigned char newNormalsStorePermute; - vector float zero; - - newNormalsStorePermute = vec_lvsl(0,(float *)&newXyzScaleVec); - newXyzScaleVec = *(vector float *)&newXyzScale; - newXyzScaleVec = vec_perm(newXyzScaleVec,newXyzScaleVec,newNormalsStorePermute); - newXyzScaleVec = vec_splat(newXyzScaleVec,0); - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - zero = (vector float)vec_splat_s8(0); - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - newNormalsLoadPermute = vec_lvsl(0,newXyz); - newNormalsStorePermute = vec_lvsr(0,outXyz); - newNormalsVec0 = vec_ld(0,newXyz); - newNormalsVec1 = vec_ld(16,newXyz); - newNormalsVec0 = vec_perm(newNormalsVec0,newNormalsVec1,newNormalsLoadPermute); - newNormalsIntVec = vec_unpackh(newNormalsVec0); - newNormalsFloatVec = vec_ctf(newNormalsIntVec,0); - newNormalsFloatVec = vec_madd(newNormalsFloatVec,newXyzScaleVec,zero); - newNormalsFloatVec = vec_perm(newNormalsFloatVec,newNormalsFloatVec,newNormalsStorePermute); - //outXyz[0] = newXyz[0] * newXyzScale; - //outXyz[1] = newXyz[1] * newXyzScale; - //outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - vec_ste(newNormalsFloatVec,0,outXyz); - vec_ste(newNormalsFloatVec,4,outXyz); - vec_ste(newNormalsFloatVec,8,outXyz); - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -} -#endif -#endif - -static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) -{ -#if 0 - short *oldXyz, *newXyz, *oldNormals, *newNormals; - float *outXyz, *outNormal; - float oldXyzScale, newXyzScale; - float oldNormalScale, newNormalScale; - int vertNum; - unsigned lat, lng; - int numVerts; - - outXyz = tess.xyz[tess.numVertexes]; - outNormal = tess.normal[tess.numVertexes]; - - newXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.frame * surf->numVerts * 4); - newNormals = newXyz + 3; - - newXyzScale = MD3_XYZ_SCALE * (1.0 - backlerp); - newNormalScale = 1.0 - backlerp; - - numVerts = surf->numVerts; - - if ( backlerp == 0 ) { - // - // just copy the vertexes - // - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - newXyz += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - - outXyz[0] = newXyz[0] * newXyzScale; - outXyz[1] = newXyz[1] * newXyzScale; - outXyz[2] = newXyz[2] * newXyzScale; - - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= (FUNCTABLE_SIZE/256); - lng *= (FUNCTABLE_SIZE/256); - - // decode X as cos( lat ) * sin( long ) - // decode Y as sin( lat ) * sin( long ) - // decode Z as cos( long ) - - outNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - outNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - outNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - } - } else { - // - // interpolate and copy the vertex and normal - // - oldXyz = (short *)((byte *)surf + surf->ofsXyzNormals) - + (backEnd.currentEntity->e.oldframe * surf->numVerts * 4); - oldNormals = oldXyz + 3; - - oldXyzScale = MD3_XYZ_SCALE * backlerp; - oldNormalScale = backlerp; - - for (vertNum=0 ; vertNum < numVerts ; vertNum++, - oldXyz += 4, newXyz += 4, oldNormals += 4, newNormals += 4, - outXyz += 4, outNormal += 4) - { - vec3_t uncompressedOldNormal, uncompressedNewNormal; - - // interpolate the xyz - outXyz[0] = oldXyz[0] * oldXyzScale + newXyz[0] * newXyzScale; - outXyz[1] = oldXyz[1] * oldXyzScale + newXyz[1] * newXyzScale; - outXyz[2] = oldXyz[2] * oldXyzScale + newXyz[2] * newXyzScale; - - // FIXME: interpolate lat/long instead? - lat = ( newNormals[0] >> 8 ) & 0xff; - lng = ( newNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - uncompressedNewNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedNewNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedNewNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - lat = ( oldNormals[0] >> 8 ) & 0xff; - lng = ( oldNormals[0] & 0xff ); - lat *= 4; - lng *= 4; - - uncompressedOldNormal[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; - uncompressedOldNormal[1] = tr.sinTable[lat] * tr.sinTable[lng]; - uncompressedOldNormal[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; - - outNormal[0] = uncompressedOldNormal[0] * oldNormalScale + uncompressedNewNormal[0] * newNormalScale; - outNormal[1] = uncompressedOldNormal[1] * oldNormalScale + uncompressedNewNormal[1] * newNormalScale; - outNormal[2] = uncompressedOldNormal[2] * oldNormalScale + uncompressedNewNormal[2] * newNormalScale; - -// VectorNormalize (outNormal); - } - VectorArrayNormalize((vec4_t *)tess.normal[tess.numVertexes], numVerts); - } -#endif float *outXyz; - uint32_t *outNormal; + int16_t *outNormal, *outTangent; mdvVertex_t *newVerts; int vertNum; newVerts = surf->verts + backEnd.currentEntity->e.frame * surf->numVerts; - outXyz = tess.xyz[tess.numVertexes]; - outNormal = &tess.normal[tess.numVertexes]; + outXyz = tess.xyz[tess.numVertexes]; + outNormal = tess.normal[tess.numVertexes]; + outTangent = tess.tangent[tess.numVertexes]; if (backlerp == 0) { @@ -1152,16 +793,14 @@ static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) { - vec3_t normal; - VectorCopy(newVerts->xyz, outXyz); - VectorCopy(newVerts->normal, normal); - - R_VaoPackNormal((byte *)outNormal, normal); + VectorCopy4(newVerts->normal, outNormal); + VectorCopy4(newVerts->tangent, outTangent); newVerts++; outXyz += 4; - outNormal++; + outNormal += 4; + outTangent += 4; } } else @@ -1176,37 +815,28 @@ static void LerpMeshVertexes_scalar(mdvSurface_t *surf, float backlerp) for (vertNum=0 ; vertNum < surf->numVerts ; vertNum++) { - vec3_t normal; - VectorLerp(newVerts->xyz, oldVerts->xyz, backlerp, outXyz); - VectorLerp(newVerts->normal, oldVerts->normal, backlerp, normal); - VectorNormalize(normal); - R_VaoPackNormal((byte *)outNormal, normal); + outNormal[0] = (int16_t)(newVerts->normal[0] * (1.0f - backlerp) + oldVerts->normal[0] * backlerp); + outNormal[1] = (int16_t)(newVerts->normal[1] * (1.0f - backlerp) + oldVerts->normal[1] * backlerp); + outNormal[2] = (int16_t)(newVerts->normal[2] * (1.0f - backlerp) + oldVerts->normal[2] * backlerp); + outNormal[3] = 0; + + outTangent[0] = (int16_t)(newVerts->tangent[0] * (1.0f - backlerp) + oldVerts->tangent[0] * backlerp); + outTangent[1] = (int16_t)(newVerts->tangent[1] * (1.0f - backlerp) + oldVerts->tangent[1] * backlerp); + outTangent[2] = (int16_t)(newVerts->tangent[2] * (1.0f - backlerp) + oldVerts->tangent[2] * backlerp); + outTangent[3] = newVerts->tangent[3]; newVerts++; oldVerts++; outXyz += 4; - outNormal++; + outNormal += 4; + outTangent += 4; } } } -static void LerpMeshVertexes(mdvSurface_t *surf, float backlerp) -{ -#if 0 -#if idppc_altivec - if (com_altivec->integer) { - // must be in a seperate function or G3 systems will crash. - LerpMeshVertexes_altivec( surf, backlerp ); - return; - } -#endif // idppc_altivec -#endif - LerpMeshVertexes_scalar( surf, backlerp ); -} - /* ============= @@ -1243,8 +873,8 @@ static void RB_SurfaceMesh(mdvSurface_t *surface) { numVerts = surface->numVerts; for ( j = 0; j < numVerts; j++ ) { - tess.texCoords[Doug + j][0][0] = texCoords[j].st[0]; - tess.texCoords[Doug + j][0][1] = texCoords[j].st[1]; + tess.texCoords[Doug + j][0] = texCoords[j].st[0]; + tess.texCoords[Doug + j][1] = texCoords[j].st[1]; // FIXME: fill in lightmapST for completeness? } @@ -1259,8 +889,8 @@ RB_SurfaceFace ============== */ static void RB_SurfaceFace( srfBspSurface_t *srf ) { - if( RB_SurfaceVao (srf->vao, srf->numVerts, srf->numIndexes, - srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) + if (RB_SurfaceVaoCached(srf->numVerts, srf->verts, srf->numIndexes, + srf->indexes, srf->dlightBits, srf->pshadowBits)) { return; } @@ -1311,12 +941,10 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) { int i, j; float *xyz; float *texCoords, *lightCoords; - uint32_t *normal; -#ifdef USE_VERT_TANGENT_SPACE - uint32_t *tangent; -#endif - float *color; - uint32_t *lightdir; + int16_t *normal; + int16_t *tangent; + uint16_t *color; + int16_t *lightdir; srfVert_t *dv; int rows, irows, vrows; int used; @@ -1329,8 +957,8 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) { int pshadowBits; //int *vDlightBits; - if( RB_SurfaceVao (srf->vao, srf->numVerts, srf->numIndexes, - srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) + if (RB_SurfaceVaoCached(srf->numVerts, srf->verts, srf->numIndexes, + srf->indexes, srf->dlightBits, srf->pshadowBits)) { return; } @@ -1401,14 +1029,12 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) { numVertexes = tess.numVertexes; xyz = tess.xyz[numVertexes]; - normal = &tess.normal[numVertexes]; -#ifdef USE_VERT_TANGENT_SPACE - tangent = &tess.tangent[numVertexes]; -#endif - texCoords = tess.texCoords[numVertexes][0]; - lightCoords = tess.texCoords[numVertexes][1]; - color = tess.vertexColors[numVertexes]; - lightdir = &tess.lightdir[numVertexes]; + normal = tess.normal[numVertexes]; + tangent = tess.tangent[numVertexes]; + texCoords = tess.texCoords[numVertexes]; + lightCoords = tess.lightCoords[numVertexes]; + color = tess.color[numVertexes]; + lightdir = tess.lightdir[numVertexes]; //vDlightBits = &tess.vertexDlightBits[numVertexes]; for ( i = 0 ; i < rows ; i++ ) { @@ -1424,36 +1050,38 @@ static void RB_SurfaceGrid( srfBspSurface_t *srf ) { if ( tess.shader->vertexAttribs & ATTR_NORMAL ) { - R_VaoPackNormal((byte *)normal++, dv->normal); + VectorCopy4(dv->normal, normal); + normal += 4; } -#ifdef USE_VERT_TANGENT_SPACE if ( tess.shader->vertexAttribs & ATTR_TANGENT ) { - R_VaoPackTangent((byte *)tangent++, dv->tangent); + VectorCopy4(dv->tangent, tangent); + tangent += 4; } -#endif + if ( tess.shader->vertexAttribs & ATTR_TEXCOORD ) { VectorCopy2(dv->st, texCoords); - texCoords += 4; + texCoords += 2; } if ( tess.shader->vertexAttribs & ATTR_LIGHTCOORD ) { VectorCopy2(dv->lightmap, lightCoords); - lightCoords += 4; + lightCoords += 2; } if ( tess.shader->vertexAttribs & ATTR_COLOR ) { - VectorCopy4(dv->vertexColors, color); + VectorCopy4(dv->color, color); color += 4; } if ( tess.shader->vertexAttribs & ATTR_LIGHTDIRECTION ) { - R_VaoPackNormal((byte *)lightdir++, dv->lightdir); + VectorCopy4(dv->lightdir, lightdir); + lightdir += 4; } //*vDlightBits++ = dlightBits; @@ -1578,12 +1206,6 @@ static void RB_SurfaceFlare(srfFlare_t *surf) RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal); } -static void RB_SurfaceVaoMesh(srfBspSurface_t * srf) -{ - RB_SurfaceVao (srf->vao, srf->numVerts, srf->numIndexes, srf->firstIndex, - srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qfalse ); -} - void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface) { //mdvModel_t *mdvModel; @@ -1592,6 +1214,12 @@ void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface) GLimp_LogComment("--- RB_SurfaceVaoMdvMesh ---\n"); + if (ShaderRequiresCPUDeforms(tess.shader)) + { + RB_SurfaceMesh(surface->mdvSurface); + return; + } + if(!surface->vao) return; @@ -1605,8 +1233,6 @@ void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface) tess.numIndexes = surface->numIndexes; tess.numVertexes = surface->numVerts; - tess.minIndex = surface->minIndex; - tess.maxIndex = surface->maxIndex; //mdvModel = surface->mdvModel; //mdvSurface = surface->mdvSurface; @@ -1624,43 +1250,43 @@ void RB_SurfaceVaoMdvMesh(srfVaoMdvMesh_t * surface) if (glRefConfig.vertexArrayObject) { - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, surface->vao->vertexesVBO); + qglBindBuffer(GL_ARRAY_BUFFER, surface->vao->vertexesVBO); } frameOffset = refEnt->frame * surface->vao->frameSize; attribIndex = ATTR_INDEX_POSITION; vAtb = &surface->vao->attribs[attribIndex]; - qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); + qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); attribIndex = ATTR_INDEX_NORMAL; vAtb = &surface->vao->attribs[attribIndex]; - qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); + qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); attribIndex = ATTR_INDEX_TANGENT; vAtb = &surface->vao->attribs[attribIndex]; - qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); + qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); frameOffset = refEnt->oldframe * surface->vao->frameSize; attribIndex = ATTR_INDEX_POSITION2; vAtb = &surface->vao->attribs[attribIndex]; - qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); + qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); attribIndex = ATTR_INDEX_NORMAL2; vAtb = &surface->vao->attribs[attribIndex]; - qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); + qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); attribIndex = ATTR_INDEX_TANGENT2; vAtb = &surface->vao->attribs[attribIndex]; - qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); + qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset + frameOffset)); if (!glRefConfig.vertexArrayObject) { attribIndex = ATTR_INDEX_TEXCOORD; vAtb = &surface->vao->attribs[attribIndex]; - qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); + qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); } } @@ -1686,6 +1312,6 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY - (void(*)(void*))RB_SurfaceVaoMesh, // SF_VAO_MESH, (void(*)(void*))RB_SurfaceVaoMdvMesh, // SF_VAO_MDVMESH + (void(*)(void*))RB_IQMSurfaceAnimVao, // SF_VAO_IQM }; diff --git a/code/renderergl2/tr_vbo.c b/code/renderergl2/tr_vbo.c index 8f9ba66f..df64f8bc 100644 --- a/code/renderergl2/tr_vbo.c +++ b/code/renderergl2/tr_vbo.c @@ -23,167 +23,45 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" -union pack10_u { - struct { - signed int x:10; - signed int y:10; - signed int z:10; - signed int w:2; - } pack; - uint32_t i; -}; - -union pack8_u { - struct { - signed int x:8; - signed int y:8; - signed int z:8; - signed int w:8; - } pack; - uint32_t i; -}; - - -int R_VaoPackTangent(byte *out, vec4_t v) +void R_VaoPackTangent(int16_t *out, vec4_t v) { - if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV) - { - union pack10_u *num = (union pack10_u *)out; - - num->pack.x = v[0] * 511.0f; - num->pack.y = v[1] * 511.0f; - num->pack.z = v[2] * 511.0f; - num->pack.w = v[3]; - } - else - { - union pack8_u *num = (union pack8_u *)out; - - num->pack.x = v[0] * 127.0f; - num->pack.y = v[1] * 127.0f; - num->pack.z = v[2] * 127.0f; - num->pack.w = v[3] * 127.0f; - } - - return 4; + out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f); + out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f); + out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f); + out[3] = v[3] * 32767.0f + (v[3] > 0.0f ? 0.5f : -0.5f); } -int R_VaoPackNormal(byte *out, vec3_t v) +void R_VaoPackNormal(int16_t *out, vec3_t v) { - if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV) - { - union pack10_u *num = (union pack10_u *)out; - - num->pack.x = v[0] * 511.0f; - num->pack.y = v[1] * 511.0f; - num->pack.z = v[2] * 511.0f; - num->pack.w = 0; - } - else - { - union pack8_u *num = (union pack8_u *)out; - - num->pack.x = v[0] * 127.0f; - num->pack.y = v[1] * 127.0f; - num->pack.z = v[2] * 127.0f; - num->pack.w = 0; - } - - return 4; + out[0] = v[0] * 32767.0f + (v[0] > 0.0f ? 0.5f : -0.5f); + out[1] = v[1] * 32767.0f + (v[1] > 0.0f ? 0.5f : -0.5f); + out[2] = v[2] * 32767.0f + (v[2] > 0.0f ? 0.5f : -0.5f); + out[3] = 0; } -int R_VaoPackTexCoord(byte *out, vec2_t st) +void R_VaoPackColor(uint16_t *out, vec4_t c) { - if (glRefConfig.packedTexcoordDataType == GL_HALF_FLOAT) - { - uint16_t *num = (uint16_t *)out; - - *num++ = FloatToHalf(st[0]); - *num++ = FloatToHalf(st[1]); - - return sizeof(*num) * 2; - } - else - { - float *num = (float *)out; - - *num++ = st[0]; - *num++ = st[1]; - - return sizeof(*num) * 2; - } + out[0] = c[0] * 65535.0f + 0.5f; + out[1] = c[1] * 65535.0f + 0.5f; + out[2] = c[2] * 65535.0f + 0.5f; + out[3] = c[3] * 65535.0f + 0.5f; } -int R_VaoPackColors(byte *out, vec4_t color) +void R_VaoUnpackTangent(vec4_t v, int16_t *pack) { - if (glRefConfig.packedTexcoordDataType == GL_HALF_FLOAT) - { - uint16_t *num = (uint16_t *)out; - - *num++ = FloatToHalf(color[0]); - *num++ = FloatToHalf(color[1]); - *num++ = FloatToHalf(color[2]); - *num++ = FloatToHalf(color[3]); - - return sizeof(*num) * 4; - } - else - { - float *num = (float *)out; - - *num++ = color[0]; - *num++ = color[1]; - *num++ = color[2]; - *num++ = color[3]; - - return sizeof(*num) * 4; - } + v[0] = pack[0] / 32767.0f; + v[1] = pack[1] / 32767.0f; + v[2] = pack[2] / 32767.0f; + v[3] = pack[3] / 32767.0f; } - -void R_VaoUnpackTangent(vec4_t v, uint32_t b) +void R_VaoUnpackNormal(vec3_t v, int16_t *pack) { - if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV) - { - union pack10_u *num = (union pack10_u *)&b; - - v[0] = num->pack.x / 511.0f; - v[1] = num->pack.y / 511.0f; - v[2] = num->pack.z / 511.0f; - v[3] = num->pack.w; - } - else - { - union pack8_u *num = (union pack8_u *)&b; - - v[0] = num->pack.x / 127.0f; - v[1] = num->pack.y / 127.0f; - v[2] = num->pack.z / 127.0f; - v[3] = num->pack.w / 127.0f; - } + v[0] = pack[0] / 32767.0f; + v[1] = pack[1] / 32767.0f; + v[2] = pack[2] / 32767.0f; } -void R_VaoUnpackNormal(vec3_t v, uint32_t b) -{ - if (glRefConfig.packedNormalDataType == GL_INT_2_10_10_10_REV) - { - union pack10_u *num = (union pack10_u *)&b; - - v[0] = num->pack.x / 511.0f; - v[1] = num->pack.y / 511.0f; - v[2] = num->pack.z / 511.0f; - } - else - { - union pack8_u *num = (union pack8_u *)&b; - - v[0] = num->pack.x / 127.0f; - v[1] = num->pack.y / 127.0f; - v[2] = num->pack.z / 127.0f; - } -} - - void Vao_SetVertexPointers(vao_t *vao) { int attribIndex; @@ -196,9 +74,9 @@ void Vao_SetVertexPointers(vao_t *vao) if (vAtb->enabled) { - qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); + qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); if (glRefConfig.vertexArrayObject || !(glState.vertexAttribsEnabled & attribBit)) - qglEnableVertexAttribArrayARB(attribIndex); + qglEnableVertexAttribArray(attribIndex); if (!glRefConfig.vertexArrayObject || vao == tess.vao) glState.vertexAttribsEnabled |= attribBit; @@ -208,7 +86,7 @@ void Vao_SetVertexPointers(vao_t *vao) // don't disable vertex attribs when using vertex array objects // Vao_SetVertexPointers is only called during init when using VAOs, and vertex attribs start disabled anyway if (!glRefConfig.vertexArrayObject && (glState.vertexAttribsEnabled & attribBit)) - qglDisableVertexAttribArrayARB(attribIndex); + qglDisableVertexAttribArray(attribIndex); if (!glRefConfig.vertexArrayObject || vao == tess.vao) glState.vertexAttribsEnabled &= ~attribBit; @@ -229,15 +107,15 @@ vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *ind switch (usage) { case VAO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; + glUsage = GL_STATIC_DRAW; break; case VAO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; + glUsage = GL_DYNAMIC_DRAW; break; default: - Com_Error(ERR_FATAL, "bad vaoUsage_t given: %i", usage); + ri.Error(ERR_FATAL, "bad vaoUsage_t given: %i", usage); return NULL; } @@ -262,25 +140,25 @@ vao_t *R_CreateVao(const char *name, byte *vertexes, int vertexesSize, byte *ind if (glRefConfig.vertexArrayObject) { - qglGenVertexArraysARB(1, &vao->vao); - qglBindVertexArrayARB(vao->vao); + qglGenVertexArrays(1, &vao->vao); + qglBindVertexArray(vao->vao); } vao->vertexesSize = vertexesSize; - qglGenBuffersARB(1, &vao->vertexesVBO); + qglGenBuffers(1, &vao->vertexesVBO); - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage); + qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO); + qglBufferData(GL_ARRAY_BUFFER, vertexesSize, vertexes, glUsage); vao->indexesSize = indexesSize; - qglGenBuffersARB(1, &vao->indexesIBO); + qglGenBuffers(1, &vao->indexesIBO); - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); + qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); + qglBufferData(GL_ELEMENT_ARRAY_BUFFER, indexesSize, indexes, glUsage); glState.currentVao = vao; @@ -304,7 +182,7 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num int dataSize; int dataOfs; - int glUsage = GL_STATIC_DRAW_ARB; + int glUsage = GL_STATIC_DRAW; if(!numVertexes || !numIndexes) return NULL; @@ -330,9 +208,7 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num // since these vertex attributes are never altered, interleave them vao->attribs[ATTR_INDEX_POSITION ].enabled = 1; vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; -#ifdef USE_VERT_TANGENT_SPACE vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; -#endif vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1; vao->attribs[ATTR_INDEX_COLOR ].enabled = 1; @@ -347,30 +223,28 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; - vao->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; - vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; - vao->attribs[ATTR_INDEX_TEXCOORD ].type = glRefConfig.packedTexcoordDataType; - vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = glRefConfig.packedTexcoordDataType; - vao->attribs[ATTR_INDEX_COLOR ].type = glRefConfig.packedColorDataType; - vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType; + vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT; + vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT; + vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT; + vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT; + vao->attribs[ATTR_INDEX_COLOR ].type = GL_UNSIGNED_SHORT; + vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT; vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE; - vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_FALSE; + vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; vao->attribs[ATTR_INDEX_POSITION ].offset = 0; dataSize = sizeof(verts[0].xyz); - vao->attribs[ATTR_INDEX_NORMAL ].offset = dataSize; dataSize += sizeof(uint32_t); -#ifdef USE_VERT_TANGENT_SPACE - vao->attribs[ATTR_INDEX_TANGENT ].offset = dataSize; dataSize += sizeof(uint32_t); -#endif - vao->attribs[ATTR_INDEX_TEXCOORD ].offset = dataSize; dataSize += glRefConfig.packedTexcoordDataSize; - vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = dataSize; dataSize += glRefConfig.packedTexcoordDataSize; - vao->attribs[ATTR_INDEX_COLOR ].offset = dataSize; dataSize += glRefConfig.packedColorDataSize; - vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(uint32_t); + vao->attribs[ATTR_INDEX_NORMAL ].offset = dataSize; dataSize += sizeof(verts[0].normal); + vao->attribs[ATTR_INDEX_TANGENT ].offset = dataSize; dataSize += sizeof(verts[0].tangent); + vao->attribs[ATTR_INDEX_TEXCOORD ].offset = dataSize; dataSize += sizeof(verts[0].st); + vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = dataSize; dataSize += sizeof(verts[0].lightmap); + vao->attribs[ATTR_INDEX_COLOR ].offset = dataSize; dataSize += sizeof(verts[0].color); + vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = dataSize; dataSize += sizeof(verts[0].lightdir); vao->attribs[ATTR_INDEX_POSITION ].stride = dataSize; vao->attribs[ATTR_INDEX_NORMAL ].stride = dataSize; @@ -383,8 +257,8 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num if (glRefConfig.vertexArrayObject) { - qglGenVertexArraysARB(1, &vao->vao); - qglBindVertexArrayARB(vao->vao); + qglGenVertexArrays(1, &vao->vao); + qglBindVertexArray(vao->vao); } @@ -400,41 +274,45 @@ vao_t *R_CreateVao2(const char *name, int numVertexes, srfVert_t *verts, int num dataOfs += sizeof(verts[i].xyz); // normal - dataOfs += R_VaoPackNormal(data + dataOfs, verts[i].normal); + memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal)); + dataOfs += sizeof(verts[i].normal); -#ifdef USE_VERT_TANGENT_SPACE // tangent - dataOfs += R_VaoPackTangent(data + dataOfs, verts[i].tangent); -#endif + memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent)); + dataOfs += sizeof(verts[i].tangent); // texcoords - dataOfs += R_VaoPackTexCoord(data + dataOfs, verts[i].st); + memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); + dataOfs += sizeof(verts[i].st); // lightmap texcoords - dataOfs += R_VaoPackTexCoord(data + dataOfs, verts[i].lightmap); + memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); + dataOfs += sizeof(verts[i].lightmap); // colors - dataOfs += R_VaoPackColors(data + dataOfs, verts[i].vertexColors); + memcpy(data + dataOfs, &verts[i].color, sizeof(verts[i].color)); + dataOfs += sizeof(verts[i].color); // light directions - dataOfs += R_VaoPackNormal(data + dataOfs, verts[i].lightdir); + memcpy(data + dataOfs, &verts[i].lightdir, sizeof(verts[i].lightdir)); + dataOfs += sizeof(verts[i].lightdir); } vao->vertexesSize = dataSize; - qglGenBuffersARB(1, &vao->vertexesVBO); + qglGenBuffers(1, &vao->vertexesVBO); - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vao->vertexesSize, data, glUsage); + qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO); + qglBufferData(GL_ARRAY_BUFFER, vao->vertexesSize, data, glUsage); // create IBO vao->indexesSize = numIndexes * sizeof(glIndex_t); - qglGenBuffersARB(1, &vao->indexesIBO); + qglGenBuffers(1, &vao->indexesIBO); - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesSize, indexes, glUsage); + qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); + qglBufferData(GL_ELEMENT_ARRAY_BUFFER, vao->indexesSize, indexes, glUsage); Vao_SetVertexPointers(vao); @@ -480,20 +358,20 @@ void R_BindVao(vao_t * vao) if (glRefConfig.vertexArrayObject) { - qglBindVertexArrayARB(vao->vao); + qglBindVertexArray(vao->vao); - // why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel? - if (1) - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); + // Intel Graphics doesn't save GL_ELEMENT_ARRAY_BUFFER binding with VAO binding. + if (glRefConfig.intelGraphics || vao == tess.vao) + qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); // tess VAO always has buffers bound if (vao == tess.vao) - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); + qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO); } else { - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vao->vertexesVBO); - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vao->indexesIBO); + qglBindBuffer(GL_ARRAY_BUFFER, vao->vertexesVBO); + qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vao->indexesIBO); // tess VAO doesn't have vertex pointers set until data is uploaded if (vao != tess.vao) @@ -515,15 +393,15 @@ void R_BindNullVao(void) { if (glRefConfig.vertexArrayObject) { - qglBindVertexArrayARB(0); + qglBindVertexArray(0); // why you no save GL_ELEMENT_ARRAY_BUFFER binding, Intel? - if (1) qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + if (1) qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } else { - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + qglBindBuffer(GL_ARRAY_BUFFER, 0); + qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } glState.currentVao = NULL; } @@ -548,11 +426,10 @@ void R_InitVaos(void) vertexesSize = sizeof(tess.xyz[0]); vertexesSize += sizeof(tess.normal[0]); -#ifdef USE_VERT_TANGENT_SPACE vertexesSize += sizeof(tess.tangent[0]); -#endif - vertexesSize += sizeof(tess.vertexColors[0]); - vertexesSize += sizeof(tess.texCoords[0][0]) * 2; + vertexesSize += sizeof(tess.color[0]); + vertexesSize += sizeof(tess.texCoords[0]); + vertexesSize += sizeof(tess.lightCoords[0]); vertexesSize += sizeof(tess.lightdir[0]); vertexesSize *= SHADER_MAX_VERTEXES; @@ -564,9 +441,7 @@ void R_InitVaos(void) tess.vao->attribs[ATTR_INDEX_POSITION ].enabled = 1; tess.vao->attribs[ATTR_INDEX_NORMAL ].enabled = 1; -#ifdef USE_VERT_TANGENT_SPACE tess.vao->attribs[ATTR_INDEX_TANGENT ].enabled = 1; -#endif tess.vao->attribs[ATTR_INDEX_TEXCOORD ].enabled = 1; tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].enabled = 1; tess.vao->attribs[ATTR_INDEX_COLOR ].enabled = 1; @@ -581,57 +456,51 @@ void R_InitVaos(void) tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; tess.vao->attribs[ATTR_INDEX_POSITION ].type = GL_FLOAT; - tess.vao->attribs[ATTR_INDEX_NORMAL ].type = glRefConfig.packedNormalDataType; - tess.vao->attribs[ATTR_INDEX_TANGENT ].type = glRefConfig.packedNormalDataType; + tess.vao->attribs[ATTR_INDEX_NORMAL ].type = GL_SHORT; + tess.vao->attribs[ATTR_INDEX_TANGENT ].type = GL_SHORT; tess.vao->attribs[ATTR_INDEX_TEXCOORD ].type = GL_FLOAT; tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].type = GL_FLOAT; - tess.vao->attribs[ATTR_INDEX_COLOR ].type = GL_FLOAT; - tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = glRefConfig.packedNormalDataType; + tess.vao->attribs[ATTR_INDEX_COLOR ].type = GL_UNSIGNED_SHORT; + tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT; tess.vao->attribs[ATTR_INDEX_POSITION ].normalized = GL_FALSE; tess.vao->attribs[ATTR_INDEX_NORMAL ].normalized = GL_TRUE; tess.vao->attribs[ATTR_INDEX_TANGENT ].normalized = GL_TRUE; tess.vao->attribs[ATTR_INDEX_TEXCOORD ].normalized = GL_FALSE; tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].normalized = GL_FALSE; - tess.vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_FALSE; + tess.vao->attribs[ATTR_INDEX_COLOR ].normalized = GL_TRUE; tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; - tess.vao->attribs[ATTR_INDEX_POSITION ].offset = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES; - tess.vao->attribs[ATTR_INDEX_NORMAL ].offset = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES; -#ifdef USE_VERT_TANGENT_SPACE - tess.vao->attribs[ATTR_INDEX_TANGENT ].offset = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES; -#endif - // these next two are actually interleaved - tess.vao->attribs[ATTR_INDEX_TEXCOORD ].offset = offset; - tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = offset + sizeof(tess.texCoords[0][0]); - offset += sizeof(tess.texCoords[0][0]) * 2 * SHADER_MAX_VERTEXES; - - tess.vao->attribs[ATTR_INDEX_COLOR ].offset = offset; offset += sizeof(tess.vertexColors[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_POSITION ].offset = offset; offset += sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_NORMAL ].offset = offset; offset += sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_TANGENT ].offset = offset; offset += sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_TEXCOORD ].offset = offset; offset += sizeof(tess.texCoords[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].offset = offset; offset += sizeof(tess.lightCoords[0]) * SHADER_MAX_VERTEXES; + tess.vao->attribs[ATTR_INDEX_COLOR ].offset = offset; offset += sizeof(tess.color[0]) * SHADER_MAX_VERTEXES; tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = offset; tess.vao->attribs[ATTR_INDEX_POSITION ].stride = sizeof(tess.xyz[0]); tess.vao->attribs[ATTR_INDEX_NORMAL ].stride = sizeof(tess.normal[0]); -#ifdef USE_VERT_TANGENT_SPACE tess.vao->attribs[ATTR_INDEX_TANGENT ].stride = sizeof(tess.tangent[0]); -#endif - tess.vao->attribs[ATTR_INDEX_COLOR ].stride = sizeof(tess.vertexColors[0]); - tess.vao->attribs[ATTR_INDEX_TEXCOORD ].stride = sizeof(tess.texCoords[0][0]) * 2; - tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].stride = sizeof(tess.texCoords[0][0]) * 2; + tess.vao->attribs[ATTR_INDEX_TEXCOORD ].stride = sizeof(tess.texCoords[0]); + tess.vao->attribs[ATTR_INDEX_LIGHTCOORD ].stride = sizeof(tess.lightCoords[0]); + tess.vao->attribs[ATTR_INDEX_COLOR ].stride = sizeof(tess.color[0]); tess.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = sizeof(tess.lightdir[0]); tess.attribPointers[ATTR_INDEX_POSITION] = tess.xyz; - tess.attribPointers[ATTR_INDEX_TEXCOORD] = tess.texCoords; tess.attribPointers[ATTR_INDEX_NORMAL] = tess.normal; -#ifdef USE_VERT_TANGENT_SPACE tess.attribPointers[ATTR_INDEX_TANGENT] = tess.tangent; -#endif - tess.attribPointers[ATTR_INDEX_COLOR] = tess.vertexColors; + tess.attribPointers[ATTR_INDEX_TEXCOORD] = tess.texCoords; + tess.attribPointers[ATTR_INDEX_LIGHTCOORD] = tess.lightCoords; + tess.attribPointers[ATTR_INDEX_COLOR] = tess.color; tess.attribPointers[ATTR_INDEX_LIGHTDIRECTION] = tess.lightdir; Vao_SetVertexPointers(tess.vao); R_BindNullVao(); + VaoCache_Init(); + GL_CheckErrors(); } @@ -654,16 +523,16 @@ void R_ShutdownVaos(void) vao = tr.vaos[i]; if(vao->vao) - qglDeleteVertexArraysARB(1, &vao->vao); + qglDeleteVertexArrays(1, &vao->vao); if(vao->vertexesVBO) { - qglDeleteBuffersARB(1, &vao->vertexesVBO); + qglDeleteBuffers(1, &vao->vertexesVBO); } if(vao->indexesIBO) { - qglDeleteBuffersARB(1, &vao->indexesIBO); + qglDeleteBuffers(1, &vao->indexesIBO); } } @@ -737,7 +606,7 @@ void RB_UpdateTessVao(unsigned int attribBits) R_BindVao(tess.vao); // orphan old vertex buffer so we don't stall on it - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, tess.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW_ARB); + qglBufferData(GL_ARRAY_BUFFER, tess.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW); // if nothing to set, set everything if(!(attribBits & ATTR_BITS)) @@ -745,14 +614,6 @@ void RB_UpdateTessVao(unsigned int attribBits) attribUpload = attribBits; - if((attribUpload & ATTR_TEXCOORD) || (attribUpload & ATTR_LIGHTCOORD)) - { - // these are interleaved, so we update both if either need it - // this translates to updating ATTR_TEXCOORD twice as large as it needs - attribUpload &= ~ATTR_LIGHTCOORD; - attribUpload |= ATTR_TEXCOORD; - } - for (attribIndex = 0; attribIndex < ATTR_INDEX_COUNT; attribIndex++) { uint32_t attribBit = 1 << attribIndex; @@ -761,17 +622,17 @@ void RB_UpdateTessVao(unsigned int attribBits) if (attribUpload & attribBit) { // note: tess has a VBO where stride == size - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, vAtb->offset, tess.numVertexes * vAtb->stride, tess.attribPointers[attribIndex]); + qglBufferSubData(GL_ARRAY_BUFFER, vAtb->offset, tess.numVertexes * vAtb->stride, tess.attribPointers[attribIndex]); } if (attribBits & attribBit) { if (!glRefConfig.vertexArrayObject) - qglVertexAttribPointerARB(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); + qglVertexAttribPointer(attribIndex, vAtb->count, vAtb->type, vAtb->normalized, vAtb->stride, BUFFER_OFFSET(vAtb->offset)); if (!(glState.vertexAttribsEnabled & attribBit)) { - qglEnableVertexAttribArrayARB(attribIndex); + qglEnableVertexAttribArray(attribIndex); glState.vertexAttribsEnabled |= attribBit; } } @@ -779,15 +640,329 @@ void RB_UpdateTessVao(unsigned int attribBits) { if ((glState.vertexAttribsEnabled & attribBit)) { - qglDisableVertexAttribArrayARB(attribIndex); + qglDisableVertexAttribArray(attribIndex); glState.vertexAttribsEnabled &= ~attribBit; } } } // orphan old index buffer so we don't stall on it - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, tess.vao->indexesSize, NULL, GL_DYNAMIC_DRAW_ARB); + qglBufferData(GL_ELEMENT_ARRAY_BUFFER, tess.vao->indexesSize, NULL, GL_DYNAMIC_DRAW); - qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); + qglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); } } + +// FIXME: This sets a limit of 65536 verts/262144 indexes per static surface +// This is higher than the old vq3 limits but is worth noting +#define VAOCACHE_QUEUE_MAX_SURFACES (1 << 10) +#define VAOCACHE_QUEUE_MAX_VERTEXES (1 << 16) +#define VAOCACHE_QUEUE_MAX_INDEXES (VAOCACHE_QUEUE_MAX_VERTEXES * 4) + +typedef struct queuedSurface_s +{ + srfVert_t *vertexes; + int numVerts; + glIndex_t *indexes; + int numIndexes; +} +queuedSurface_t; + +static struct +{ + queuedSurface_t surfaces[VAOCACHE_QUEUE_MAX_SURFACES]; + int numSurfaces; + + srfVert_t vertexes[VAOCACHE_QUEUE_MAX_VERTEXES]; + int vertexCommitSize; + + glIndex_t indexes[VAOCACHE_QUEUE_MAX_INDEXES]; + int indexCommitSize; +} +vcq; + +#define VAOCACHE_MAX_SURFACES (1 << 16) +#define VAOCACHE_MAX_BATCHES (1 << 10) + +// srfVert_t is 60 bytes +// assuming each vert is referenced 4 times, need 16 bytes (4 glIndex_t) per vert +// -> need about 4/15ths the space for indexes as vertexes +#if GL_INDEX_TYPE == GL_UNSIGNED_SHORT +#define VAOCACHE_VERTEX_BUFFER_SIZE (sizeof(srfVert_t) * USHRT_MAX) +#define VAOCACHE_INDEX_BUFFER_SIZE (sizeof(glIndex_t) * USHRT_MAX * 4) +#else // GL_UNSIGNED_INT +#define VAOCACHE_VERTEX_BUFFER_SIZE (16 * 1024 * 1024) +#define VAOCACHE_INDEX_BUFFER_SIZE (5 * 1024 * 1024) +#endif + +typedef struct buffered_s +{ + void *data; + int size; + int bufferOffset; +} +buffered_t; + +static struct +{ + vao_t *vao; + buffered_t surfaceIndexSets[VAOCACHE_MAX_SURFACES]; + int numSurfaces; + + int batchLengths[VAOCACHE_MAX_BATCHES]; + int numBatches; + + int vertexOffset; + int indexOffset; +} +vc; + +void VaoCache_Commit(void) +{ + buffered_t *indexSet; + int *batchLength; + queuedSurface_t *surf, *end = vcq.surfaces + vcq.numSurfaces; + + R_BindVao(vc.vao); + + // Search for a matching batch + // FIXME: Use faster search + indexSet = vc.surfaceIndexSets; + batchLength = vc.batchLengths; + for (; batchLength < vc.batchLengths + vc.numBatches; batchLength++) + { + if (*batchLength == vcq.numSurfaces) + { + buffered_t *indexSet2 = indexSet; + for (surf = vcq.surfaces; surf < end; surf++, indexSet2++) + { + if (surf->indexes != indexSet2->data || (surf->numIndexes * sizeof(glIndex_t)) != indexSet2->size) + break; + } + + if (surf == end) + break; + } + + indexSet += *batchLength; + } + + // If found, use it + if (indexSet < vc.surfaceIndexSets + vc.numSurfaces) + { + tess.firstIndex = indexSet->bufferOffset / sizeof(glIndex_t); + //ri.Printf(PRINT_ALL, "firstIndex %d numIndexes %d as %d\n", tess.firstIndex, tess.numIndexes, (int)(batchLength - vc.batchLengths)); + //ri.Printf(PRINT_ALL, "vc.numSurfaces %d vc.numBatches %d\n", vc.numSurfaces, vc.numBatches); + } + // If not, rebuffer the batch + // FIXME: keep track of the vertexes so we don't have to reupload them every time + else + { + srfVert_t *dstVertex = vcq.vertexes; + glIndex_t *dstIndex = vcq.indexes; + + batchLength = vc.batchLengths + vc.numBatches; + *batchLength = vcq.numSurfaces; + vc.numBatches++; + + tess.firstIndex = vc.indexOffset / sizeof(glIndex_t); + vcq.vertexCommitSize = 0; + vcq.indexCommitSize = 0; + for (surf = vcq.surfaces; surf < end; surf++) + { + glIndex_t *srcIndex = surf->indexes; + int vertexesSize = surf->numVerts * sizeof(srfVert_t); + int indexesSize = surf->numIndexes * sizeof(glIndex_t); + int i, indexOffset = (vc.vertexOffset + vcq.vertexCommitSize) / sizeof(srfVert_t); + + Com_Memcpy(dstVertex, surf->vertexes, vertexesSize); + dstVertex += surf->numVerts; + + vcq.vertexCommitSize += vertexesSize; + + indexSet = vc.surfaceIndexSets + vc.numSurfaces; + indexSet->data = surf->indexes; + indexSet->size = indexesSize; + indexSet->bufferOffset = vc.indexOffset + vcq.indexCommitSize; + vc.numSurfaces++; + + for (i = 0; i < surf->numIndexes; i++) + *dstIndex++ = *srcIndex++ + indexOffset; + + vcq.indexCommitSize += indexesSize; + } + + //ri.Printf(PRINT_ALL, "committing %d to %d, %d to %d as %d\n", vcq.vertexCommitSize, vc.vertexOffset, vcq.indexCommitSize, vc.indexOffset, (int)(batchLength - vc.batchLengths)); + + if (vcq.vertexCommitSize) + { + qglBindBuffer(GL_ARRAY_BUFFER, vc.vao->vertexesVBO); + qglBufferSubData(GL_ARRAY_BUFFER, vc.vertexOffset, vcq.vertexCommitSize, vcq.vertexes); + vc.vertexOffset += vcq.vertexCommitSize; + } + + if (vcq.indexCommitSize) + { + qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesIBO); + qglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, vc.indexOffset, vcq.indexCommitSize, vcq.indexes); + vc.indexOffset += vcq.indexCommitSize; + } + } +} + +void VaoCache_Init(void) +{ + vc.vao = R_CreateVao("VaoCache", NULL, VAOCACHE_VERTEX_BUFFER_SIZE, NULL, VAOCACHE_INDEX_BUFFER_SIZE, VAO_USAGE_DYNAMIC); + + vc.vao->attribs[ATTR_INDEX_POSITION].enabled = 1; + vc.vao->attribs[ATTR_INDEX_TEXCOORD].enabled = 1; + vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].enabled = 1; + vc.vao->attribs[ATTR_INDEX_NORMAL].enabled = 1; + vc.vao->attribs[ATTR_INDEX_TANGENT].enabled = 1; + vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].enabled = 1; + vc.vao->attribs[ATTR_INDEX_COLOR].enabled = 1; + + vc.vao->attribs[ATTR_INDEX_POSITION].count = 3; + vc.vao->attribs[ATTR_INDEX_TEXCOORD].count = 2; + vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].count = 2; + vc.vao->attribs[ATTR_INDEX_NORMAL].count = 4; + vc.vao->attribs[ATTR_INDEX_TANGENT].count = 4; + vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].count = 4; + vc.vao->attribs[ATTR_INDEX_COLOR].count = 4; + + vc.vao->attribs[ATTR_INDEX_POSITION].type = GL_FLOAT; + vc.vao->attribs[ATTR_INDEX_TEXCOORD].type = GL_FLOAT; + vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].type = GL_FLOAT; + vc.vao->attribs[ATTR_INDEX_NORMAL].type = GL_SHORT; + vc.vao->attribs[ATTR_INDEX_TANGENT].type = GL_SHORT; + vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].type = GL_SHORT; + vc.vao->attribs[ATTR_INDEX_COLOR].type = GL_UNSIGNED_SHORT; + + vc.vao->attribs[ATTR_INDEX_POSITION].normalized = GL_FALSE; + vc.vao->attribs[ATTR_INDEX_TEXCOORD].normalized = GL_FALSE; + vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].normalized = GL_FALSE; + vc.vao->attribs[ATTR_INDEX_NORMAL].normalized = GL_TRUE; + vc.vao->attribs[ATTR_INDEX_TANGENT].normalized = GL_TRUE; + vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].normalized = GL_TRUE; + vc.vao->attribs[ATTR_INDEX_COLOR].normalized = GL_TRUE; + + vc.vao->attribs[ATTR_INDEX_POSITION].offset = offsetof(srfVert_t, xyz); + vc.vao->attribs[ATTR_INDEX_TEXCOORD].offset = offsetof(srfVert_t, st); + vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].offset = offsetof(srfVert_t, lightmap); + vc.vao->attribs[ATTR_INDEX_NORMAL].offset = offsetof(srfVert_t, normal); + vc.vao->attribs[ATTR_INDEX_TANGENT].offset = offsetof(srfVert_t, tangent); + vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].offset = offsetof(srfVert_t, lightdir); + vc.vao->attribs[ATTR_INDEX_COLOR].offset = offsetof(srfVert_t, color); + + vc.vao->attribs[ATTR_INDEX_POSITION].stride = sizeof(srfVert_t); + vc.vao->attribs[ATTR_INDEX_TEXCOORD].stride = sizeof(srfVert_t); + vc.vao->attribs[ATTR_INDEX_LIGHTCOORD].stride = sizeof(srfVert_t); + vc.vao->attribs[ATTR_INDEX_NORMAL].stride = sizeof(srfVert_t); + vc.vao->attribs[ATTR_INDEX_TANGENT].stride = sizeof(srfVert_t); + vc.vao->attribs[ATTR_INDEX_LIGHTDIRECTION].stride = sizeof(srfVert_t); + vc.vao->attribs[ATTR_INDEX_COLOR].stride = sizeof(srfVert_t); + + Vao_SetVertexPointers(vc.vao); + + vc.numSurfaces = 0; + vc.numBatches = 0; + vc.vertexOffset = 0; + vc.indexOffset = 0; + vcq.vertexCommitSize = 0; + vcq.indexCommitSize = 0; + vcq.numSurfaces = 0; +} + +void VaoCache_BindVao(void) +{ + R_BindVao(vc.vao); +} + +void VaoCache_CheckAdd(qboolean *endSurface, qboolean *recycleVertexBuffer, qboolean *recycleIndexBuffer, int numVerts, int numIndexes) +{ + int vertexesSize = sizeof(srfVert_t) * numVerts; + int indexesSize = sizeof(glIndex_t) * numIndexes; + + if (vc.vao->vertexesSize < vc.vertexOffset + vcq.vertexCommitSize + vertexesSize) + { + //ri.Printf(PRINT_ALL, "out of space in vertex cache: %d < %d + %d + %d\n", vc.vao->vertexesSize, vc.vertexOffset, vcq.vertexCommitSize, vertexesSize); + *recycleVertexBuffer = qtrue; + *recycleIndexBuffer = qtrue; + *endSurface = qtrue; + } + + if (vc.vao->indexesSize < vc.indexOffset + vcq.indexCommitSize + indexesSize) + { + //ri.Printf(PRINT_ALL, "out of space in index cache\n"); + *recycleIndexBuffer = qtrue; + *endSurface = qtrue; + } + + if (vc.numSurfaces + vcq.numSurfaces >= VAOCACHE_MAX_SURFACES) + { + //ri.Printf(PRINT_ALL, "out of surfaces in index cache\n"); + *recycleIndexBuffer = qtrue; + *endSurface = qtrue; + } + + if (vc.numBatches >= VAOCACHE_MAX_BATCHES) + { + //ri.Printf(PRINT_ALL, "out of batches in index cache\n"); + *recycleIndexBuffer = qtrue; + *endSurface = qtrue; + } + + if (vcq.numSurfaces >= VAOCACHE_QUEUE_MAX_SURFACES) + { + //ri.Printf(PRINT_ALL, "out of queued surfaces\n"); + *endSurface = qtrue; + } + + if (VAOCACHE_QUEUE_MAX_VERTEXES * sizeof(srfVert_t) < vcq.vertexCommitSize + vertexesSize) + { + //ri.Printf(PRINT_ALL, "out of queued vertexes\n"); + *endSurface = qtrue; + } + + if (VAOCACHE_QUEUE_MAX_INDEXES * sizeof(glIndex_t) < vcq.indexCommitSize + indexesSize) + { + //ri.Printf(PRINT_ALL, "out of queued indexes\n"); + *endSurface = qtrue; + } +} + +void VaoCache_RecycleVertexBuffer(void) +{ + qglBindBuffer(GL_ARRAY_BUFFER, vc.vao->vertexesVBO); + qglBufferData(GL_ARRAY_BUFFER, vc.vao->vertexesSize, NULL, GL_DYNAMIC_DRAW); + vc.vertexOffset = 0; +} + +void VaoCache_RecycleIndexBuffer(void) +{ + qglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesIBO); + qglBufferData(GL_ELEMENT_ARRAY_BUFFER, vc.vao->indexesSize, NULL, GL_DYNAMIC_DRAW); + vc.indexOffset = 0; + vc.numSurfaces = 0; + vc.numBatches = 0; +} + +void VaoCache_InitQueue(void) +{ + vcq.vertexCommitSize = 0; + vcq.indexCommitSize = 0; + vcq.numSurfaces = 0; +} + +void VaoCache_AddSurface(srfVert_t *verts, int numVerts, glIndex_t *indexes, int numIndexes) +{ + queuedSurface_t *queueEntry = vcq.surfaces + vcq.numSurfaces; + queueEntry->vertexes = verts; + queueEntry->numVerts = numVerts; + queueEntry->indexes = indexes; + queueEntry->numIndexes = numIndexes; + vcq.numSurfaces++; + + vcq.vertexCommitSize += sizeof(srfVert_t) * numVerts; + vcq.indexCommitSize += sizeof(glIndex_t) * numIndexes; +} diff --git a/code/renderergl2/tr_world.c b/code/renderergl2/tr_world.c index 98b1c811..f9a24424 100644 --- a/code/renderergl2/tr_world.c +++ b/code/renderergl2/tr_world.c @@ -36,7 +36,7 @@ static qboolean R_CullSurface( msurface_t *surf ) { return qfalse; } - if ( *surf->data == SF_GRID && r_nocurves->integer ) { + if ( r_nocurves->integer && *surf->data == SF_GRID ) { return qtrue; } @@ -213,7 +213,6 @@ static int R_DlightSurface( msurface_t *surf, int dlightBits ) { case SF_FACE: case SF_GRID: case SF_TRIANGLES: - case SF_VAO_MESH: ((srfBspSurface_t *)surf->data)->dlightBits = dlightBits; break; @@ -299,7 +298,6 @@ static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) { case SF_FACE: case SF_GRID: case SF_TRIANGLES: - case SF_VAO_MESH: ((srfBspSurface_t *)surf->data)->pshadowBits = pshadowBits; break; @@ -401,11 +399,11 @@ void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) { R_RecursiveWorldNode ================ */ -static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits, int pshadowBits ) { +static void R_RecursiveWorldNode( mnode_t *node, uint32_t planeBits, uint32_t dlightBits, uint32_t pshadowBits ) { do { - int newDlights[2]; - unsigned int newPShadows[2]; + uint32_t newDlights[2]; + uint32_t newPShadows[2]; // if the node wasn't marked as potentially visible, exit // pvs is skipped for depth shadows @@ -561,43 +559,23 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits, tr.viewParms.visBounds[1][2] = node->maxs[2]; } - // add merged and unmerged surfaces - if (tr.world->viewSurfaces && !r_nocurves->integer) - view = tr.world->viewSurfaces + node->firstmarksurface; - else - view = tr.world->marksurfaces + node->firstmarksurface; + // add surfaces + view = tr.world->marksurfaces + node->firstmarksurface; c = node->nummarksurfaces; while (c--) { // just mark it as visible, so we don't jump out of the cache derefencing the surface surf = *view; - if (surf < 0) + if (tr.world->surfacesViewCount[surf] != tr.viewCount) { - if (tr.world->mergedSurfacesViewCount[-surf - 1] != tr.viewCount) - { - tr.world->mergedSurfacesViewCount[-surf - 1] = tr.viewCount; - tr.world->mergedSurfacesDlightBits[-surf - 1] = dlightBits; - tr.world->mergedSurfacesPshadowBits[-surf - 1] = pshadowBits; - } - else - { - tr.world->mergedSurfacesDlightBits[-surf - 1] |= dlightBits; - tr.world->mergedSurfacesPshadowBits[-surf - 1] |= pshadowBits; - } + tr.world->surfacesViewCount[surf] = tr.viewCount; + tr.world->surfacesDlightBits[surf] = dlightBits; + tr.world->surfacesPshadowBits[surf] = pshadowBits; } else { - if (tr.world->surfacesViewCount[surf] != tr.viewCount) - { - tr.world->surfacesViewCount[surf] = tr.viewCount; - tr.world->surfacesDlightBits[surf] = dlightBits; - tr.world->surfacesPshadowBits[surf] = pshadowBits; - } - else - { - tr.world->surfacesDlightBits[surf] |= dlightBits; - tr.world->surfacesPshadowBits[surf] |= pshadowBits; - } + tr.world->surfacesDlightBits[surf] |= dlightBits; + tr.world->surfacesPshadowBits[surf] |= pshadowBits; } view++; } @@ -761,7 +739,7 @@ R_AddWorldSurfaces ============= */ void R_AddWorldSurfaces (void) { - int planeBits, dlightBits, pshadowBits; + uint32_t planeBits, dlightBits, pshadowBits; if ( !r_drawworld->integer ) { return; @@ -782,12 +760,12 @@ void R_AddWorldSurfaces (void) { ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] ); // perform frustum culling and flag all the potentially visible surfaces - if ( tr.refdef.num_dlights > 32 ) { - tr.refdef.num_dlights = 32 ; + if ( tr.refdef.num_dlights > MAX_DLIGHTS ) { + tr.refdef.num_dlights = MAX_DLIGHTS ; } - if ( tr.refdef.num_pshadows > 32 ) { - tr.refdef.num_pshadows = 32 ; + if ( tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS ) { + tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS; } planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15; @@ -799,12 +777,12 @@ void R_AddWorldSurfaces (void) { } else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) ) { - dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; - pshadowBits = ( 1 << tr.refdef.num_pshadows ) - 1; + dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1; + pshadowBits = ( 1ULL << tr.refdef.num_pshadows ) - 1; } else { - dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; + dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1; pshadowBits = 0; } @@ -825,14 +803,6 @@ void R_AddWorldSurfaces (void) { R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] ); tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i]; } - for (i = 0; i < tr.world->numMergedSurfaces; i++) - { - if (tr.world->mergedSurfacesViewCount[i] != tr.viewCount) - continue; - - R_AddWorldSurface( tr.world->mergedSurfaces + i, tr.world->mergedSurfacesDlightBits[i], tr.world->mergedSurfacesPshadowBits[i] ); - tr.refdef.dlightMask |= tr.world->mergedSurfacesDlightBits[i]; - } tr.refdef.dlightMask = ~tr.refdef.dlightMask; } diff --git a/code/sdl/sdl_glimp.c b/code/sdl/sdl_glimp.c index 7ac87893..9777a2cb 100644 --- a/code/sdl/sdl_glimp.c +++ b/code/sdl/sdl_glimp.c @@ -53,6 +53,9 @@ cvar_t *r_allowResize; // make window resizable cvar_t *r_centerWindow; cvar_t *r_sdlDriver; +int qglMajorVersion, qglMinorVersion; +int qglesMajorVersion, qglesMinorVersion; + void (APIENTRYP qglActiveTextureARB) (GLenum texture); void (APIENTRYP qglClientActiveTextureARB) (GLenum texture); void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t); @@ -60,6 +63,23 @@ void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t); void (APIENTRYP qglLockArraysEXT) (GLint first, GLsizei count); void (APIENTRYP qglUnlockArraysEXT) (void); +#define GLE(ret, name, ...) name##proc * qgl##name; +QGL_1_1_PROCS; +QGL_1_1_FIXED_FUNCTION_PROCS; +QGL_DESKTOP_1_1_PROCS; +QGL_DESKTOP_1_1_FIXED_FUNCTION_PROCS; +QGL_ES_1_1_PROCS; +QGL_ES_1_1_FIXED_FUNCTION_PROCS; +QGL_1_3_PROCS; +QGL_1_5_PROCS; +QGL_2_0_PROCS; +QGL_3_0_PROCS; +QGL_ARB_occlusion_query_PROCS; +QGL_ARB_framebuffer_object_PROCS; +QGL_ARB_vertex_array_object_PROCS; +QGL_EXT_direct_state_access_PROCS; +#undef GLE + /* =============== GLimp_Shutdown @@ -210,12 +230,144 @@ static void GLimp_DetectAvailableModes(void) SDL_free( modes ); } +/* +=============== +GLimp_GetProcAddresses + +Get addresses for OpenGL functions. +=============== +*/ +static qboolean GLimp_GetProcAddresses( qboolean fixedFunction ) { + qboolean success = qtrue; + const char *version; + +#ifdef __SDL_NOGETPROCADDR__ +#define GLE( ret, name, ... ) qgl##name = gl#name; +#else +#define GLE( ret, name, ... ) qgl##name = (name##proc *) SDL_GL_GetProcAddress("gl" #name); \ + if ( qgl##name == NULL ) { \ + ri.Printf( PRINT_ALL, "ERROR: Missing OpenGL function %s\n", "gl" #name ); \ + success = qfalse; \ + } +#endif + + // OpenGL 1.0 and OpenGL ES 1.0 + GLE(const GLubyte *, GetString, GLenum name) + + if ( !qglGetString ) { + Com_Error( ERR_FATAL, "glGetString is NULL" ); + } + + version = (const char *)qglGetString( GL_VERSION ); + + if ( !version ) { + Com_Error( ERR_FATAL, "GL_VERSION is NULL\n" ); + } + + if ( Q_stricmpn( "OpenGL ES", version, 9 ) == 0 ) { + char profile[6]; // ES, ES-CM, or ES-CL + sscanf( version, "OpenGL %5s %d.%d", profile, &qglesMajorVersion, &qglesMinorVersion ); + // common lite profile (no floating point) is not supported + if ( Q_stricmp( profile, "ES-CL" ) == 0 ) { + qglesMajorVersion = 0; + qglesMinorVersion = 0; + } + } else { + sscanf( version, "%d.%d", &qglMajorVersion, &qglMinorVersion ); + } + + if ( fixedFunction ) { + if ( QGL_VERSION_ATLEAST( 1, 2 ) ) { + QGL_1_1_PROCS; + QGL_1_1_FIXED_FUNCTION_PROCS; + QGL_DESKTOP_1_1_PROCS; + QGL_DESKTOP_1_1_FIXED_FUNCTION_PROCS; + } else if ( qglesMajorVersion == 1 && qglesMinorVersion >= 1 ) { + // OpenGL ES 1.1 (2.0 is not backward compatible) + QGL_1_1_PROCS; + QGL_1_1_FIXED_FUNCTION_PROCS; + QGL_ES_1_1_PROCS; + QGL_ES_1_1_FIXED_FUNCTION_PROCS; + // error so this doesn't segfault due to NULL desktop GL functions being used + Com_Error( ERR_FATAL, "Unsupported OpenGL Version: %s\n", version ); + } else { + Com_Error( ERR_FATAL, "Unsupported OpenGL Version (%s), OpenGL 1.2 is required\n", version ); + } + } else { + if ( QGL_VERSION_ATLEAST( 2, 0 ) ) { + QGL_1_1_PROCS; + QGL_DESKTOP_1_1_PROCS; + QGL_1_3_PROCS; + QGL_1_5_PROCS; + QGL_2_0_PROCS; + } else if ( QGLES_VERSION_ATLEAST( 2, 0 ) ) { + QGL_1_1_PROCS; + QGL_ES_1_1_PROCS; + QGL_1_3_PROCS; + QGL_1_5_PROCS; + QGL_2_0_PROCS; + // error so this doesn't segfault due to NULL desktop GL functions being used + Com_Error( ERR_FATAL, "Unsupported OpenGL Version: %s\n", version ); + } else { + Com_Error( ERR_FATAL, "Unsupported OpenGL Version (%s), OpenGL 2.0 is required\n", version ); + } + } + + if ( QGL_VERSION_ATLEAST( 3, 0 ) || QGLES_VERSION_ATLEAST( 3, 0 ) ) { + QGL_3_0_PROCS; + } + +#undef GLE + + return success; +} + +/* +=============== +GLimp_ClearProcAddresses + +Clear addresses for OpenGL functions. +=============== +*/ +static void GLimp_ClearProcAddresses( void ) { +#define GLE( ret, name, ... ) qgl##name = NULL; + + qglMajorVersion = 0; + qglMinorVersion = 0; + qglesMajorVersion = 0; + qglesMinorVersion = 0; + + QGL_1_1_PROCS; + QGL_1_1_FIXED_FUNCTION_PROCS; + QGL_DESKTOP_1_1_PROCS; + QGL_DESKTOP_1_1_FIXED_FUNCTION_PROCS; + QGL_ES_1_1_PROCS; + QGL_ES_1_1_FIXED_FUNCTION_PROCS; + QGL_1_3_PROCS; + QGL_1_5_PROCS; + QGL_2_0_PROCS; + QGL_3_0_PROCS; + QGL_ARB_occlusion_query_PROCS; + QGL_ARB_framebuffer_object_PROCS; + QGL_ARB_vertex_array_object_PROCS; + QGL_EXT_direct_state_access_PROCS; + + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + qglMultiTexCoord2fARB = NULL; + + qglLockArraysEXT = NULL; + qglUnlockArraysEXT = NULL; + +#undef GLE +} + /* =============== GLimp_SetMode =============== */ -static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) +static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder, qboolean fixedFunction) { const char *glstring; int perChannelColorBits; @@ -309,6 +461,7 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) // Destroy existing state if it exists if( SDL_glContext != NULL ) { + GLimp_ClearProcAddresses(); SDL_GL_DeleteContext( SDL_glContext ); SDL_glContext = NULL; } @@ -349,6 +502,7 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) for (i = 0; i < 16; i++) { int testColorBits, testDepthBits, testStencilBits; + int realColorBits[3]; // 0 - default // 1 - minus colorBits @@ -477,10 +631,82 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) SDL_SetWindowIcon( SDL_window, icon ); - if( ( SDL_glContext = SDL_GL_CreateContext( SDL_window ) ) == NULL ) + if (!fixedFunction) { - ri.Printf( PRINT_DEVELOPER, "SDL_GL_CreateContext failed: %s\n", SDL_GetError( ) ); - continue; + int profileMask, majorVersion, minorVersion; + SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profileMask); + SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion); + SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion); + + ri.Printf(PRINT_ALL, "Trying to get an OpenGL 3.2 core context\n"); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + if ((SDL_glContext = SDL_GL_CreateContext(SDL_window)) == NULL) + { + ri.Printf(PRINT_ALL, "SDL_GL_CreateContext failed: %s\n", SDL_GetError()); + ri.Printf(PRINT_ALL, "Reverting to default context\n"); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profileMask); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion); + } + else + { + const char *renderer; + + ri.Printf(PRINT_ALL, "SDL_GL_CreateContext succeeded.\n"); + + if ( GLimp_GetProcAddresses( fixedFunction ) ) + { + renderer = (const char *)qglGetString(GL_RENDERER); + } + else + { + ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() failed for OpenGL 3.2 core context\n" ); + renderer = NULL; + } + + if (!renderer || (strstr(renderer, "Software Renderer") || strstr(renderer, "Software Rasterizer"))) + { + if ( renderer ) + ri.Printf(PRINT_ALL, "GL_RENDERER is %s, rejecting context\n", renderer); + + GLimp_ClearProcAddresses(); + SDL_GL_DeleteContext(SDL_glContext); + SDL_glContext = NULL; + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profileMask); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorVersion); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorVersion); + } + } + } + else + { + SDL_glContext = NULL; + } + + if ( !SDL_glContext ) + { + if( ( SDL_glContext = SDL_GL_CreateContext( SDL_window ) ) == NULL ) + { + ri.Printf( PRINT_DEVELOPER, "SDL_GL_CreateContext failed: %s\n", SDL_GetError( ) ); + SDL_DestroyWindow( SDL_window ); + SDL_window = NULL; + continue; + } + + if ( !GLimp_GetProcAddresses( fixedFunction ) ) + { + ri.Printf( PRINT_ALL, "GLimp_GetProcAddresses() failed\n" ); + GLimp_ClearProcAddresses(); + SDL_GL_DeleteContext( SDL_glContext ); + SDL_glContext = NULL; + SDL_DestroyWindow( SDL_window ); + SDL_window = NULL; + continue; + } } qglClearColor( 0, 0, 0, 1 ); @@ -492,9 +718,13 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) ri.Printf( PRINT_DEVELOPER, "SDL_GL_SetSwapInterval failed: %s\n", SDL_GetError( ) ); } - glConfig.colorBits = testColorBits; - glConfig.depthBits = testDepthBits; - glConfig.stencilBits = testStencilBits; + SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &realColorBits[0] ); + SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &realColorBits[1] ); + SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &realColorBits[2] ); + SDL_GL_GetAttribute( SDL_GL_DEPTH_SIZE, &glConfig.depthBits ); + SDL_GL_GetAttribute( SDL_GL_STENCIL_SIZE, &glConfig.stencilBits ); + + glConfig.colorBits = realColorBits[0] + realColorBits[1] + realColorBits[2]; ri.Printf( PRINT_ALL, "Using %d color bits, %d depth, %d stencil display.\n", glConfig.colorBits, glConfig.depthBits, glConfig.stencilBits ); @@ -522,7 +752,7 @@ static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) GLimp_StartDriverAndSetMode =============== */ -static qboolean GLimp_StartDriverAndSetMode(int mode, qboolean fullscreen, qboolean noborder) +static qboolean GLimp_StartDriverAndSetMode(int mode, qboolean fullscreen, qboolean noborder, qboolean gl3Core) { rserr_t err; @@ -557,7 +787,7 @@ static qboolean GLimp_StartDriverAndSetMode(int mode, qboolean fullscreen, qbool fullscreen = qtrue; } - err = GLimp_SetMode(mode, fullscreen, noborder); + err = GLimp_SetMode(mode, fullscreen, noborder, gl3Core); switch ( err ) { @@ -574,22 +804,13 @@ static qboolean GLimp_StartDriverAndSetMode(int mode, qboolean fullscreen, qbool return qtrue; } -static qboolean GLimp_HaveExtension(const char *ext) -{ - const char *ptr = Q_stristr( glConfig.extensions_string, ext ); - if (ptr == NULL) - return qfalse; - ptr += strlen(ext); - return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string. -} - /* =============== GLimp_InitExtensions =============== */ -static void GLimp_InitExtensions( void ) +static void GLimp_InitExtensions( qboolean fixedFunction ) { if ( !r_allowExtensions->integer ) { @@ -602,8 +823,8 @@ static void GLimp_InitExtensions( void ) glConfig.textureCompression = TC_NONE; // GL_EXT_texture_compression_s3tc - if ( GLimp_HaveExtension( "GL_ARB_texture_compression" ) && - GLimp_HaveExtension( "GL_EXT_texture_compression_s3tc" ) ) + if ( SDL_GL_ExtensionSupported( "GL_ARB_texture_compression" ) && + SDL_GL_ExtensionSupported( "GL_EXT_texture_compression_s3tc" ) ) { if ( r_ext_compressed_textures->value ) { @@ -623,7 +844,7 @@ static void GLimp_InitExtensions( void ) // GL_S3_s3tc ... legacy extension before GL_EXT_texture_compression_s3tc. if (glConfig.textureCompression == TC_NONE) { - if ( GLimp_HaveExtension( "GL_S3_s3tc" ) ) + if ( SDL_GL_ExtensionSupported( "GL_S3_s3tc" ) ) { if ( r_ext_compressed_textures->value ) { @@ -641,92 +862,95 @@ static void GLimp_InitExtensions( void ) } } - - // GL_EXT_texture_env_add - glConfig.textureEnvAddAvailable = qfalse; - if ( GLimp_HaveExtension( "EXT_texture_env_add" ) ) + // OpenGL 1 fixed function pipeline + if ( fixedFunction ) { - if ( r_ext_texture_env_add->integer ) + // GL_EXT_texture_env_add + glConfig.textureEnvAddAvailable = qfalse; + if ( SDL_GL_ExtensionSupported( "GL_EXT_texture_env_add" ) ) { - glConfig.textureEnvAddAvailable = qtrue; - ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); - } - else - { - glConfig.textureEnvAddAvailable = qfalse; - ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); - } - } - else - { - ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); - } - - // GL_ARB_multitexture - qglMultiTexCoord2fARB = NULL; - qglActiveTextureARB = NULL; - qglClientActiveTextureARB = NULL; - if ( GLimp_HaveExtension( "GL_ARB_multitexture" ) ) - { - if ( r_ext_multitexture->value ) - { - qglMultiTexCoord2fARB = SDL_GL_GetProcAddress( "glMultiTexCoord2fARB" ); - qglActiveTextureARB = SDL_GL_GetProcAddress( "glActiveTextureARB" ); - qglClientActiveTextureARB = SDL_GL_GetProcAddress( "glClientActiveTextureARB" ); - - if ( qglActiveTextureARB ) + if ( r_ext_texture_env_add->integer ) { - GLint glint = 0; - qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &glint ); - glConfig.numTextureUnits = (int) glint; - if ( glConfig.numTextureUnits > 1 ) - { - ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); - } - else - { - qglMultiTexCoord2fARB = NULL; - qglActiveTextureARB = NULL; - qglClientActiveTextureARB = NULL; - ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); - } + glConfig.textureEnvAddAvailable = qtrue; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); + } + else + { + glConfig.textureEnvAddAvailable = qfalse; + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); } } else { - ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); } - } - else - { - ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); - } - // GL_EXT_compiled_vertex_array - if ( GLimp_HaveExtension( "GL_EXT_compiled_vertex_array" ) ) - { - if ( r_ext_compiled_vertex_array->value ) + // GL_ARB_multitexture + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + if ( SDL_GL_ExtensionSupported( "GL_ARB_multitexture" ) ) { - ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); - qglLockArraysEXT = ( void ( APIENTRY * )( GLint, GLint ) ) SDL_GL_GetProcAddress( "glLockArraysEXT" ); - qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) SDL_GL_GetProcAddress( "glUnlockArraysEXT" ); - if (!qglLockArraysEXT || !qglUnlockArraysEXT) + if ( r_ext_multitexture->value ) { - ri.Error (ERR_FATAL, "bad getprocaddress"); + qglMultiTexCoord2fARB = SDL_GL_GetProcAddress( "glMultiTexCoord2fARB" ); + qglActiveTextureARB = SDL_GL_GetProcAddress( "glActiveTextureARB" ); + qglClientActiveTextureARB = SDL_GL_GetProcAddress( "glClientActiveTextureARB" ); + + if ( qglActiveTextureARB ) + { + GLint glint = 0; + qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &glint ); + glConfig.numTextureUnits = (int) glint; + if ( glConfig.numTextureUnits > 1 ) + { + ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + } + else + { + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); + } + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); } } else { - ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } + + // GL_EXT_compiled_vertex_array + if ( SDL_GL_ExtensionSupported( "GL_EXT_compiled_vertex_array" ) ) + { + if ( r_ext_compiled_vertex_array->value ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); + qglLockArraysEXT = ( void ( APIENTRY * )( GLint, GLint ) ) SDL_GL_GetProcAddress( "glLockArraysEXT" ); + qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) SDL_GL_GetProcAddress( "glUnlockArraysEXT" ); + if (!qglLockArraysEXT || !qglUnlockArraysEXT) + { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); } - } - else - { - ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); } textureFilterAnisotropic = qfalse; - if ( GLimp_HaveExtension( "GL_EXT_texture_filter_anisotropic" ) ) + if ( SDL_GL_ExtensionSupported( "GL_EXT_texture_filter_anisotropic" ) ) { if ( r_ext_texture_filter_anisotropic->integer ) { qglGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint *)&maxAnisotropy ); @@ -761,7 +985,7 @@ This routine is responsible for initializing the OS specific portions of OpenGL =============== */ -void GLimp_Init( void ) +void GLimp_Init( qboolean fixedFunction ) { ri.Printf( PRINT_DEVELOPER, "Glimp_Init( )\n" ); @@ -781,13 +1005,13 @@ void GLimp_Init( void ) ri.Sys_GLimpInit( ); // Create the window and set up the context - if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, r_noborder->integer)) + if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, r_noborder->integer, fixedFunction)) goto success; // Try again, this time in a platform specific "safe mode" ri.Sys_GLimpSafeInit( ); - if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, qfalse)) + if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, qfalse, fixedFunction)) goto success; // Finally, try the default screen resolution @@ -796,7 +1020,7 @@ void GLimp_Init( void ) ri.Printf( PRINT_ALL, "Setting r_mode %d failed, falling back on r_mode %d\n", r_mode->integer, R_MODE_FALLBACK ); - if(GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, qfalse, qfalse)) + if(GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, qfalse, qfalse, fixedFunction)) goto success; } @@ -818,10 +1042,40 @@ success: if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n') glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0; Q_strncpyz( glConfig.version_string, (char *) qglGetString (GL_VERSION), sizeof( glConfig.version_string ) ); - Q_strncpyz( glConfig.extensions_string, (char *) qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); + + // manually create extension list if using OpenGL 3 + if ( qglGetStringi ) + { + int i, numExtensions, extensionLength, listLength; + const char *extension; + + qglGetIntegerv( GL_NUM_EXTENSIONS, &numExtensions ); + listLength = 0; + + for ( i = 0; i < numExtensions; i++ ) + { + extension = (char *) qglGetStringi( GL_EXTENSIONS, i ); + extensionLength = strlen( extension ); + + if ( ( listLength + extensionLength + 1 ) >= sizeof( glConfig.extensions_string ) ) + break; + + if ( i > 0 ) { + Q_strcat( glConfig.extensions_string, sizeof( glConfig.extensions_string ), " " ); + listLength++; + } + + Q_strcat( glConfig.extensions_string, sizeof( glConfig.extensions_string ), extension ); + listLength += extensionLength; + } + } + else + { + Q_strncpyz( glConfig.extensions_string, (char *) qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); + } // initialize extensions - GLimp_InitExtensions( ); + GLimp_InitExtensions( fixedFunction ); ri.Cvar_Get( "r_availableModes", "", CVAR_ROM ); diff --git a/code/sdl/sdl_input.c b/code/sdl/sdl_input.c index 2afa2c16..2ad324e3 100644 --- a/code/sdl/sdl_input.c +++ b/code/sdl/sdl_input.c @@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static cvar_t *in_keyboardDebug = NULL; +static SDL_GameController *gamepad = NULL; static SDL_Joystick *stick = NULL; static qboolean mouseAvailable = qfalse; @@ -50,6 +51,8 @@ static cvar_t *in_joystickUseAnalog = NULL; static int vidRestartTime = 0; +static int in_eventTime = 0; + static SDL_Window *SDL_window = NULL; #define CTRL(a) ((a)-'a'+1) @@ -135,8 +138,7 @@ static qboolean IN_IsConsoleKey( keyNum_t key, int character ) if( !token[ 0 ] ) break; - if( strlen( token ) == 4 ) - charCode = Com_HexStrToInt( token ); + charCode = Com_HexStrToInt( token ); if( charCode > 0 ) { @@ -191,7 +193,18 @@ static keyNum_t IN_TranslateSDLToQ3Key( SDL_Keysym *keysym, qboolean down ) { keyNum_t key = 0; - if( keysym->sym >= SDLK_SPACE && keysym->sym < SDLK_DELETE ) + if( keysym->scancode >= SDL_SCANCODE_1 && keysym->scancode <= SDL_SCANCODE_0 ) + { + // Always map the number keys as such even if they actually map + // to other characters (eg, "1" is "&" on an AZERTY keyboard). + // This is required for SDL before 2.0.6, except on Windows + // which already had this behavior. + if( keysym->scancode == SDL_SCANCODE_0 ) + key = '0'; + else + key = '1' + keysym->scancode - SDL_SCANCODE_1; + } + else if( keysym->sym >= SDLK_SPACE && keysym->sym < SDLK_DELETE ) { // These happen to match the ASCII chars key = (int)keysym->sym; @@ -247,7 +260,7 @@ static keyNum_t IN_TranslateSDLToQ3Key( SDL_Keysym *keysym, qboolean down ) case SDLK_LCTRL: case SDLK_RCTRL: key = K_CTRL; break; -#ifdef MACOS_X +#ifdef __APPLE__ case SDLK_RGUI: case SDLK_LGUI: key = K_COMMAND; break; #else @@ -279,6 +292,15 @@ static keyNum_t IN_TranslateSDLToQ3Key( SDL_Keysym *keysym, qboolean down ) case SDLK_CAPSLOCK: key = K_CAPSLOCK; break; default: + if( !( keysym->sym & SDLK_SCANCODE_MASK ) && keysym->scancode <= 95 ) + { + // Map Unicode characters to 95 world keys using the key's scan code. + // FIXME: There aren't enough world keys to cover all the scancodes. + // Maybe create a map of scancode to quake key at start up and on + // key map change; allocate world key numbers as needed similar + // to SDL 1.2. + key = K_WORLD_0 + (int)keysym->scancode; + } break; } } @@ -319,7 +341,7 @@ static void IN_GobbleMotionEvents( void ) IN_ActivateMouse =============== */ -static void IN_ActivateMouse( void ) +static void IN_ActivateMouse( qboolean isFullscreen ) { if (!mouseAvailable || !SDL_WasInit( SDL_INIT_VIDEO ) ) return; @@ -333,14 +355,17 @@ static void IN_ActivateMouse( void ) } // in_nograb makes no sense in fullscreen mode - if( !Cvar_VariableIntegerValue("r_fullscreen") ) + if( !isFullscreen ) { if( in_nograb->modified || !mouseActive ) { - if( in_nograb->integer ) + if( in_nograb->integer ) { + SDL_SetRelativeMouseMode( SDL_FALSE ); SDL_SetWindowGrab( SDL_window, SDL_FALSE ); - else + } else { + SDL_SetRelativeMouseMode( SDL_TRUE ); SDL_SetWindowGrab( SDL_window, SDL_TRUE ); + } in_nograb->modified = qfalse; } @@ -354,15 +379,15 @@ static void IN_ActivateMouse( void ) IN_DeactivateMouse =============== */ -static void IN_DeactivateMouse( void ) +static void IN_DeactivateMouse( qboolean isFullscreen ) { if( !SDL_WasInit( SDL_INIT_VIDEO ) ) return; // Always show the cursor when the mouse is disabled, // but not when fullscreen - if( !Cvar_VariableIntegerValue("r_fullscreen") ) - SDL_ShowCursor( 1 ); + if( !isFullscreen ) + SDL_ShowCursor( SDL_TRUE ); if( !mouseAvailable ) return; @@ -410,7 +435,7 @@ static int hat_keys[16] = { struct { - qboolean buttons[16]; // !!! FIXME: these might be too many. + qboolean buttons[SDL_CONTROLLER_BUTTON_MAX + 1]; // +1 because old max was 16, current SDL_CONTROLLER_BUTTON_MAX is 15 unsigned int oldaxes; int oldaaxes[MAX_JOYSTICK_AXIS]; unsigned int oldhats; @@ -428,12 +453,20 @@ static void IN_InitJoystick( void ) int total = 0; char buf[16384] = ""; + if (gamepad) + SDL_GameControllerClose(gamepad); + if (stick != NULL) SDL_JoystickClose(stick); stick = NULL; + gamepad = NULL; memset(&stick_state, '\0', sizeof (stick_state)); + // SDL 2.0.4 requires SDL_INIT_JOYSTICK to be initialized separately from + // SDL_INIT_GAMECONTROLLER for SDL_JoystickOpen() to work correctly, + // despite https://wiki.libsdl.org/SDL_Init (retrieved 2016-08-16) + // indicating SDL_INIT_JOYSTICK should be initialized automatically. if (!SDL_WasInit(SDL_INIT_JOYSTICK)) { Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n"); @@ -445,6 +478,17 @@ static void IN_InitJoystick( void ) Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) passed.\n"); } + if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER)) + { + Com_DPrintf("Calling SDL_Init(SDL_INIT_GAMECONTROLLER)...\n"); + if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) + { + Com_DPrintf("SDL_Init(SDL_INIT_GAMECONTROLLER) failed: %s\n", SDL_GetError()); + return; + } + Com_DPrintf("SDL_Init(SDL_INIT_GAMECONTROLLER) passed.\n"); + } + total = SDL_NumJoysticks(); Com_DPrintf("%d possible joysticks\n", total); @@ -459,7 +503,7 @@ static void IN_InitJoystick( void ) if( !in_joystick->integer ) { Com_DPrintf( "Joystick is not active.\n" ); - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); return; } @@ -472,10 +516,13 @@ static void IN_InitJoystick( void ) stick = SDL_JoystickOpen( in_joystickNo->integer ); if (stick == NULL) { - Com_DPrintf( "No joystick opened.\n" ); + Com_DPrintf( "No joystick opened: %s\n", SDL_GetError() ); return; } + if (SDL_IsGameController(in_joystickNo->integer)) + gamepad = SDL_GameControllerOpen(in_joystickNo->integer); + Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer ); Com_DPrintf( "Name: %s\n", SDL_JoystickNameForIndex(in_joystickNo->integer) ); Com_DPrintf( "Axes: %d\n", SDL_JoystickNumAxes(stick) ); @@ -483,8 +530,10 @@ static void IN_InitJoystick( void ) Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) ); Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) ); Com_DPrintf( "Use Analog: %s\n", in_joystickUseAnalog->integer ? "Yes" : "No" ); + Com_DPrintf( "Is gamepad: %s\n", gamepad ? "Yes" : "No" ); SDL_JoystickEventState(SDL_QUERY); + SDL_GameControllerEventState(SDL_QUERY); } /* @@ -494,18 +543,226 @@ IN_ShutdownJoystick */ static void IN_ShutdownJoystick( void ) { + if ( !SDL_WasInit( SDL_INIT_GAMECONTROLLER ) ) + return; + if ( !SDL_WasInit( SDL_INIT_JOYSTICK ) ) return; + if (gamepad) + { + SDL_GameControllerClose(gamepad); + gamepad = NULL; + } + if (stick) { SDL_JoystickClose(stick); stick = NULL; } + SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } + +static qboolean KeyToAxisAndSign(int keynum, int *outAxis, int *outSign) +{ + char *bind; + + if (!keynum) + return qfalse; + + bind = Key_GetBinding(keynum); + + if (!bind || *bind != '+') + return qfalse; + + *outSign = 0; + + if (Q_stricmp(bind, "+forward") == 0) + { + *outAxis = j_forward_axis->integer; + *outSign = j_forward->value > 0.0f ? 1 : -1; + } + else if (Q_stricmp(bind, "+back") == 0) + { + *outAxis = j_forward_axis->integer; + *outSign = j_forward->value > 0.0f ? -1 : 1; + } + else if (Q_stricmp(bind, "+moveleft") == 0) + { + *outAxis = j_side_axis->integer; + *outSign = j_side->value > 0.0f ? -1 : 1; + } + else if (Q_stricmp(bind, "+moveright") == 0) + { + *outAxis = j_side_axis->integer; + *outSign = j_side->value > 0.0f ? 1 : -1; + } + else if (Q_stricmp(bind, "+lookup") == 0) + { + *outAxis = j_pitch_axis->integer; + *outSign = j_pitch->value > 0.0f ? -1 : 1; + } + else if (Q_stricmp(bind, "+lookdown") == 0) + { + *outAxis = j_pitch_axis->integer; + *outSign = j_pitch->value > 0.0f ? 1 : -1; + } + else if (Q_stricmp(bind, "+left") == 0) + { + *outAxis = j_yaw_axis->integer; + *outSign = j_yaw->value > 0.0f ? 1 : -1; + } + else if (Q_stricmp(bind, "+right") == 0) + { + *outAxis = j_yaw_axis->integer; + *outSign = j_yaw->value > 0.0f ? -1 : 1; + } + else if (Q_stricmp(bind, "+moveup") == 0) + { + *outAxis = j_up_axis->integer; + *outSign = j_up->value > 0.0f ? 1 : -1; + } + else if (Q_stricmp(bind, "+movedown") == 0) + { + *outAxis = j_up_axis->integer; + *outSign = j_up->value > 0.0f ? -1 : 1; + } + + return *outSign != 0; +} + +/* +=============== +IN_GamepadMove +=============== +*/ +static void IN_GamepadMove( void ) +{ + int i; + int translatedAxes[MAX_JOYSTICK_AXIS]; + qboolean translatedAxesSet[MAX_JOYSTICK_AXIS]; + + SDL_GameControllerUpdate(); + + // check buttons + for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++) + { + qboolean pressed = SDL_GameControllerGetButton(gamepad, SDL_CONTROLLER_BUTTON_A + i); + if (pressed != stick_state.buttons[i]) + { + Com_QueueEvent(in_eventTime, SE_KEY, K_PAD0_A + i, pressed, 0, NULL); + stick_state.buttons[i] = pressed; + } + } + + // must defer translated axes until all real axes are processed + // must be done this way to prevent a later mapped axis from zeroing out a previous one + if (in_joystickUseAnalog->integer) + { + for (i = 0; i < MAX_JOYSTICK_AXIS; i++) + { + translatedAxes[i] = 0; + translatedAxesSet[i] = qfalse; + } + } + + // check axes + for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; i++) + { + int axis = SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_LEFTX + i); + int oldAxis = stick_state.oldaaxes[i]; + + // Smoothly ramp from dead zone to maximum value + float f = ((float)abs(axis) / 32767.0f - in_joystickThreshold->value) / (1.0f - in_joystickThreshold->value); + + if (f < 0.0f) + f = 0.0f; + + axis = (int)(32767 * ((axis < 0) ? -f : f)); + + if (axis != oldAxis) + { + const int negMap[SDL_CONTROLLER_AXIS_MAX] = { K_PAD0_LEFTSTICK_LEFT, K_PAD0_LEFTSTICK_UP, K_PAD0_RIGHTSTICK_LEFT, K_PAD0_RIGHTSTICK_UP, 0, 0 }; + const int posMap[SDL_CONTROLLER_AXIS_MAX] = { K_PAD0_LEFTSTICK_RIGHT, K_PAD0_LEFTSTICK_DOWN, K_PAD0_RIGHTSTICK_RIGHT, K_PAD0_RIGHTSTICK_DOWN, K_PAD0_LEFTTRIGGER, K_PAD0_RIGHTTRIGGER }; + + qboolean posAnalog = qfalse, negAnalog = qfalse; + int negKey = negMap[i]; + int posKey = posMap[i]; + + if (in_joystickUseAnalog->integer) + { + int posAxis = 0, posSign = 0, negAxis = 0, negSign = 0; + + // get axes and axes signs for keys if available + posAnalog = KeyToAxisAndSign(posKey, &posAxis, &posSign); + negAnalog = KeyToAxisAndSign(negKey, &negAxis, &negSign); + + // positive to negative/neutral -> keyup if axis hasn't yet been set + if (posAnalog && !translatedAxesSet[posAxis] && oldAxis > 0 && axis <= 0) + { + translatedAxes[posAxis] = 0; + translatedAxesSet[posAxis] = qtrue; + } + + // negative to positive/neutral -> keyup if axis hasn't yet been set + if (negAnalog && !translatedAxesSet[negAxis] && oldAxis < 0 && axis >= 0) + { + translatedAxes[negAxis] = 0; + translatedAxesSet[negAxis] = qtrue; + } + + // negative/neutral to positive -> keydown + if (posAnalog && axis > 0) + { + translatedAxes[posAxis] = axis * posSign; + translatedAxesSet[posAxis] = qtrue; + } + + // positive/neutral to negative -> keydown + if (negAnalog && axis < 0) + { + translatedAxes[negAxis] = -axis * negSign; + translatedAxesSet[negAxis] = qtrue; + } + } + + // keyups first so they get overridden by keydowns later + + // positive to negative/neutral -> keyup + if (!posAnalog && posKey && oldAxis > 0 && axis <= 0) + Com_QueueEvent(in_eventTime, SE_KEY, posKey, qfalse, 0, NULL); + + // negative to positive/neutral -> keyup + if (!negAnalog && negKey && oldAxis < 0 && axis >= 0) + Com_QueueEvent(in_eventTime, SE_KEY, negKey, qfalse, 0, NULL); + + // negative/neutral to positive -> keydown + if (!posAnalog && posKey && oldAxis <= 0 && axis > 0) + Com_QueueEvent(in_eventTime, SE_KEY, posKey, qtrue, 0, NULL); + + // positive/neutral to negative -> keydown + if (!negAnalog && negKey && oldAxis >= 0 && axis < 0) + Com_QueueEvent(in_eventTime, SE_KEY, negKey, qtrue, 0, NULL); + + stick_state.oldaaxes[i] = axis; + } + } + + // set translated axes + if (in_joystickUseAnalog->integer) + { + for (i = 0; i < MAX_JOYSTICK_AXIS; i++) + { + if (translatedAxesSet[i]) + Com_QueueEvent(in_eventTime, SE_JOYSTICK_AXIS, i, translatedAxes[i], 0, NULL); + } + } +} + + /* =============== IN_JoyMove @@ -518,6 +775,12 @@ static void IN_JoyMove( void ) int total = 0; int i = 0; + if (gamepad) + { + IN_GamepadMove(); + return; + } + if (!stick) return; @@ -545,7 +808,7 @@ static void IN_JoyMove( void ) balldx *= 2; if (abs(balldy) > 1) balldy *= 2; - Com_QueueEvent( 0, SE_MOUSE, balldx, balldy, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_MOUSE, balldx, balldy, 0, NULL ); } } @@ -560,7 +823,7 @@ static void IN_JoyMove( void ) qboolean pressed = (SDL_JoystickGetButton(stick, i) != 0); if (pressed != stick_state.buttons[i]) { - Com_QueueEvent( 0, SE_KEY, K_JOY1 + i, pressed, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, K_JOY1 + i, pressed, 0, NULL ); stick_state.buttons[i] = pressed; } } @@ -585,32 +848,32 @@ static void IN_JoyMove( void ) // release event switch( ((Uint8 *)&stick_state.oldhats)[i] ) { case SDL_HAT_UP: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); break; case SDL_HAT_RIGHT: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); break; case SDL_HAT_DOWN: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); break; case SDL_HAT_LEFT: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); break; case SDL_HAT_RIGHTUP: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); break; case SDL_HAT_RIGHTDOWN: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL ); break; case SDL_HAT_LEFTUP: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); break; case SDL_HAT_LEFTDOWN: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL ); break; default: break; @@ -618,32 +881,32 @@ static void IN_JoyMove( void ) // press event switch( ((Uint8 *)&hats)[i] ) { case SDL_HAT_UP: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); break; case SDL_HAT_RIGHT: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); break; case SDL_HAT_DOWN: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); break; case SDL_HAT_LEFT: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); break; case SDL_HAT_RIGHTUP: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); break; case SDL_HAT_RIGHTDOWN: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL ); break; case SDL_HAT_LEFTUP: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); break; case SDL_HAT_LEFTDOWN: - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL ); break; default: break; @@ -671,7 +934,7 @@ static void IN_JoyMove( void ) if ( axis != stick_state.oldaaxes[i] ) { - Com_QueueEvent( 0, SE_JOYSTICK_AXIS, i, axis, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_JOYSTICK_AXIS, i, axis, 0, NULL ); stick_state.oldaaxes[i] = axis; } } @@ -697,11 +960,11 @@ static void IN_JoyMove( void ) { for( i = 0; i < 16; i++ ) { if( ( axes & ( 1 << i ) ) && !( stick_state.oldaxes & ( 1 << i ) ) ) { - Com_QueueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, joy_keys[i], qtrue, 0, NULL ); } if( !( axes & ( 1 << i ) ) && ( stick_state.oldaxes & ( 1 << i ) ) ) { - Com_QueueEvent( 0, SE_KEY, joy_keys[i], qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, joy_keys[i], qfalse, 0, NULL ); } } } @@ -733,19 +996,19 @@ static void IN_ProcessEvents( void ) break; if( ( key = IN_TranslateSDLToQ3Key( &e.key.keysym, qtrue ) ) ) - Com_QueueEvent( 0, SE_KEY, key, qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, key, qtrue, 0, NULL ); if( key == K_BACKSPACE ) - Com_QueueEvent( 0, SE_CHAR, CTRL('h'), 0, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_CHAR, CTRL('h'), 0, 0, NULL ); else if( keys[K_CTRL].down && key >= 'a' && key <= 'z' ) - Com_QueueEvent( 0, SE_CHAR, CTRL(key), 0, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_CHAR, CTRL(key), 0, 0, NULL ); lastKeyDown = key; break; case SDL_KEYUP: if( ( key = IN_TranslateSDLToQ3Key( &e.key.keysym, qfalse ) ) ) - Com_QueueEvent( 0, SE_KEY, key, qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, key, qfalse, 0, NULL ); lastKeyDown = 0; break; @@ -790,11 +1053,11 @@ static void IN_ProcessEvents( void ) { if( IN_IsConsoleKey( 0, utf32 ) ) { - Com_QueueEvent( 0, SE_KEY, K_CONSOLE, qtrue, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, K_CONSOLE, qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, K_CONSOLE, qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, K_CONSOLE, qfalse, 0, NULL ); } else - Com_QueueEvent( 0, SE_CHAR, utf32, 0, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_CHAR, utf32, 0, 0, NULL ); } } } @@ -805,7 +1068,7 @@ static void IN_ProcessEvents( void ) { if( !e.motion.xrel && !e.motion.yrel ) break; - Com_QueueEvent( 0, SE_MOUSE, e.motion.xrel, e.motion.yrel, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_MOUSE, e.motion.xrel, e.motion.yrel, 0, NULL ); } break; @@ -822,7 +1085,7 @@ static void IN_ProcessEvents( void ) case SDL_BUTTON_X2: b = K_MOUSE5; break; default: b = K_AUX1 + ( e.button.button - SDL_BUTTON_X2 + 1 ) % 16; break; } - Com_QueueEvent( 0, SE_KEY, b, + Com_QueueEvent( in_eventTime, SE_KEY, b, ( e.type == SDL_MOUSEBUTTONDOWN ? qtrue : qfalse ), 0, NULL ); } break; @@ -830,16 +1093,22 @@ static void IN_ProcessEvents( void ) case SDL_MOUSEWHEEL: if( e.wheel.y > 0 ) { - Com_QueueEvent( 0, SE_KEY, K_MWHEELUP, qtrue, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, K_MWHEELUP, qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL ); } else if( e.wheel.y < 0 ) { - Com_QueueEvent( 0, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL ); - Com_QueueEvent( 0, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL ); + Com_QueueEvent( in_eventTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL ); } break; + case SDL_CONTROLLERDEVICEADDED: + case SDL_CONTROLLERDEVICEREMOVED: + if (in_joystick->integer) + IN_InitJoystick(); + break; + case SDL_QUIT: Cbuf_ExecuteText(EXEC_NOW, "quit Closed window\n"); break; @@ -854,6 +1123,12 @@ static void IN_ProcessEvents( void ) width = e.window.data1; height = e.window.data2; + // ignore this event on fullscreen + if( cls.glconfig.isFullscreen ) + { + break; + } + // check if size actually changed if( cls.glconfig.vidWidth == width && cls.glconfig.vidHeight == height ) { @@ -899,26 +1174,32 @@ void IN_Frame( void ) // If not DISCONNECTED (main menu) or ACTIVE (in game), we're loading loading = ( clc.state != CA_DISCONNECTED && clc.state != CA_ACTIVE ); + // update isFullscreen since it might of changed since the last vid_restart + cls.glconfig.isFullscreen = Cvar_VariableIntegerValue( "r_fullscreen" ) != 0; + if( !cls.glconfig.isFullscreen && ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) { // Console is down in windowed mode - IN_DeactivateMouse( ); + IN_DeactivateMouse( cls.glconfig.isFullscreen ); } else if( !cls.glconfig.isFullscreen && loading ) { // Loading in windowed mode - IN_DeactivateMouse( ); + IN_DeactivateMouse( cls.glconfig.isFullscreen ); } else if( !( SDL_GetWindowFlags( SDL_window ) & SDL_WINDOW_INPUT_FOCUS ) ) { // Window not got focus - IN_DeactivateMouse( ); + IN_DeactivateMouse( cls.glconfig.isFullscreen ); } else - IN_ActivateMouse( ); + IN_ActivateMouse( cls.glconfig.isFullscreen ); IN_ProcessEvents( ); + // Set event time for next frame to earliest possible time an event could happen + in_eventTime = Sys_Milliseconds( ); + // In case we had to delay actual restart of video system if( ( vidRestartTime != 0 ) && ( vidRestartTime < Sys_Milliseconds( ) ) ) { @@ -958,7 +1239,7 @@ void IN_Init( void *windowData ) SDL_StartTextInput( ); mouseAvailable = ( in_mouse->value != 0 ); - IN_DeactivateMouse( ); + IN_DeactivateMouse( Cvar_VariableIntegerValue( "r_fullscreen" ) != 0 ); appState = SDL_GetWindowFlags( SDL_window ); Cvar_SetValue( "com_unfocused", !( appState & SDL_WINDOW_INPUT_FOCUS ) ); @@ -977,7 +1258,7 @@ void IN_Shutdown( void ) { SDL_StopTextInput( ); - IN_DeactivateMouse( ); + IN_DeactivateMouse( Cvar_VariableIntegerValue( "r_fullscreen" ) != 0 ); mouseAvailable = qfalse; IN_ShutdownJoystick( ); diff --git a/code/sdl/sdl_snd.c b/code/sdl/sdl_snd.c index 609aed9e..eb0dd58f 100644 --- a/code/sdl/sdl_snd.c +++ b/code/sdl/sdl_snd.c @@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/q_shared.h" #include "../client/snd_local.h" +#include "../client/client.h" qboolean snd_inited = qfalse; @@ -44,6 +45,17 @@ cvar_t *s_sdlMixSamps; static int dmapos = 0; static int dmasize = 0; +static SDL_AudioDeviceID sdlPlaybackDevice; + +#if defined USE_VOIP && SDL_VERSION_ATLEAST( 2, 0, 5 ) +#define USE_SDL_AUDIO_CAPTURE + +static SDL_AudioDeviceID sdlCaptureDevice; +static cvar_t *s_sdlCapture; +static float sdlMasterGain = 1.0f; +#endif + + /* =============== SNDDMA_AudioCallback @@ -83,6 +95,40 @@ static void SNDDMA_AudioCallback(void *userdata, Uint8 *stream, int len) if (dmapos >= dmasize) dmapos = 0; + +#ifdef USE_SDL_AUDIO_CAPTURE + if (sdlMasterGain != 1.0f) + { + int i; + if (dma.isfloat && (dma.samplebits == 32)) + { + float *ptr = (float *) stream; + len /= sizeof (*ptr); + for (i = 0; i < len; i++, ptr++) + { + *ptr *= sdlMasterGain; + } + } + else if (dma.samplebits == 16) + { + Sint16 *ptr = (Sint16 *) stream; + len /= sizeof (*ptr); + for (i = 0; i < len; i++, ptr++) + { + *ptr = (Sint16) (((float) *ptr) * sdlMasterGain); + } + } + else if (dma.samplebits == 8) + { + Uint8 *ptr = (Uint8 *) stream; + len /= sizeof (*ptr); + for (i = 0; i < len; i++, ptr++) + { + *ptr = (Uint8) (((float) *ptr) * sdlMasterGain); + } + } + } +#endif } static struct @@ -96,7 +142,9 @@ static struct { AUDIO_U16LSB, "AUDIO_U16LSB" }, { AUDIO_S16LSB, "AUDIO_S16LSB" }, { AUDIO_U16MSB, "AUDIO_U16MSB" }, - { AUDIO_S16MSB, "AUDIO_S16MSB" } + { AUDIO_S16MSB, "AUDIO_S16MSB" }, + { AUDIO_F32LSB, "AUDIO_F32LSB" }, + { AUDIO_F32MSB, "AUDIO_F32MSB" } }; static int formatToStringTableSize = ARRAY_LEN( formatToStringTable ); @@ -154,13 +202,10 @@ qboolean SNDDMA_Init(void) Com_Printf( "SDL_Init( SDL_INIT_AUDIO )... " ); - if (!SDL_WasInit(SDL_INIT_AUDIO)) + if (SDL_Init(SDL_INIT_AUDIO) != 0) { - if (SDL_Init(SDL_INIT_AUDIO) != 0) - { - Com_Printf( "FAILED (%s)\n", SDL_GetError( ) ); - return qfalse; - } + Com_Printf( "FAILED (%s)\n", SDL_GetError( ) ); + return qfalse; } Com_Printf( "OK\n" ); @@ -198,9 +243,10 @@ qboolean SNDDMA_Init(void) desired.channels = (int) s_sdlChannels->value; desired.callback = SNDDMA_AudioCallback; - if (SDL_OpenAudio(&desired, &obtained) == -1) + sdlPlaybackDevice = SDL_OpenAudioDevice(NULL, SDL_FALSE, &desired, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE); + if (sdlPlaybackDevice == 0) { - Com_Printf("SDL_OpenAudio() failed: %s\n", SDL_GetError()); + Com_Printf("SDL_OpenAudioDevice() failed: %s\n", SDL_GetError()); SDL_QuitSubSystem(SDL_INIT_AUDIO); return qfalse; } @@ -218,26 +264,58 @@ qboolean SNDDMA_Init(void) if (!tmp) tmp = (obtained.samples * obtained.channels) * 10; - if (tmp & (tmp - 1)) // not a power of two? Seems to confuse something. - { - int val = 1; - while (val < tmp) - val <<= 1; - - tmp = val; - } + // samples must be divisible by number of channels + tmp -= tmp % obtained.channels; dmapos = 0; - dma.samplebits = obtained.format & 0xFF; // first byte of format is bits. + dma.samplebits = SDL_AUDIO_BITSIZE(obtained.format); + dma.isfloat = SDL_AUDIO_ISFLOAT(obtained.format); dma.channels = obtained.channels; dma.samples = tmp; + dma.fullsamples = dma.samples / dma.channels; dma.submission_chunk = 1; dma.speed = obtained.freq; dmasize = (dma.samples * (dma.samplebits/8)); dma.buffer = calloc(1, dmasize); +#ifdef USE_SDL_AUDIO_CAPTURE + // !!! FIXME: some of these SDL_OpenAudioDevice() values should be cvars. + s_sdlCapture = Cvar_Get( "s_sdlCapture", "1", CVAR_ARCHIVE | CVAR_LATCH ); + // !!! FIXME: pulseaudio capture records audio the entire time the program is running. https://bugzilla.libsdl.org/show_bug.cgi?id=4087 + if (Q_stricmp(SDL_GetCurrentAudioDriver(), "pulseaudio") == 0) + { + Com_Printf("SDL audio capture support disabled for pulseaudio (https://bugzilla.libsdl.org/show_bug.cgi?id=4087)\n"); + } + else if (!s_sdlCapture->integer) + { + Com_Printf("SDL audio capture support disabled by user ('+set s_sdlCapture 1' to enable)\n"); + } +#if USE_MUMBLE + else if (cl_useMumble->integer) + { + Com_Printf("SDL audio capture support disabled for Mumble support\n"); + } +#endif + else + { + /* !!! FIXME: list available devices and let cvar specify one, like OpenAL does */ + SDL_AudioSpec spec; + SDL_zero(spec); + spec.freq = 48000; + spec.format = AUDIO_S16SYS; + spec.channels = 1; + spec.samples = VOIP_MAX_PACKET_SAMPLES * 4; + sdlCaptureDevice = SDL_OpenAudioDevice(NULL, SDL_TRUE, &spec, NULL, 0); + Com_Printf( "SDL capture device %s.\n", + (sdlCaptureDevice == 0) ? "failed to open" : "opened"); + } + + sdlMasterGain = 1.0f; +#endif + Com_Printf("Starting SDL audio callback...\n"); - SDL_PauseAudio(0); // start callback. + SDL_PauseAudioDevice(sdlPlaybackDevice, 0); // start callback. + // don't unpause the capture device; we'll do that in StartCapture. Com_Printf("SDL audio initialized.\n"); snd_inited = qtrue; @@ -261,15 +339,30 @@ SNDDMA_Shutdown */ void SNDDMA_Shutdown(void) { - Com_Printf("Closing SDL audio device...\n"); - SDL_PauseAudio(1); - SDL_CloseAudio(); + if (sdlPlaybackDevice != 0) + { + Com_Printf("Closing SDL audio playback device...\n"); + SDL_CloseAudioDevice(sdlPlaybackDevice); + Com_Printf("SDL audio playback device closed.\n"); + sdlPlaybackDevice = 0; + } + +#ifdef USE_SDL_AUDIO_CAPTURE + if (sdlCaptureDevice) + { + Com_Printf("Closing SDL audio capture device...\n"); + SDL_CloseAudioDevice(sdlCaptureDevice); + Com_Printf("SDL audio capture device closed.\n"); + sdlCaptureDevice = 0; + } +#endif + SDL_QuitSubSystem(SDL_INIT_AUDIO); free(dma.buffer); dma.buffer = NULL; dmapos = dmasize = 0; snd_inited = qfalse; - Com_Printf("SDL audio device shut down.\n"); + Com_Printf("SDL audio shut down.\n"); } /* @@ -281,7 +374,7 @@ Send sound to device if buffer isn't really the dma buffer */ void SNDDMA_Submit(void) { - SDL_UnlockAudio(); + SDL_UnlockAudioDevice(sdlPlaybackDevice); } /* @@ -291,5 +384,62 @@ SNDDMA_BeginPainting */ void SNDDMA_BeginPainting (void) { - SDL_LockAudio(); + SDL_LockAudioDevice(sdlPlaybackDevice); } + + +#ifdef USE_VOIP +void SNDDMA_StartCapture(void) +{ +#ifdef USE_SDL_AUDIO_CAPTURE + if (sdlCaptureDevice) + { + SDL_ClearQueuedAudio(sdlCaptureDevice); + SDL_PauseAudioDevice(sdlCaptureDevice, 0); + } +#endif +} + +int SNDDMA_AvailableCaptureSamples(void) +{ +#ifdef USE_SDL_AUDIO_CAPTURE + // divided by 2 to convert from bytes to (mono16) samples. + return sdlCaptureDevice ? (SDL_GetQueuedAudioSize(sdlCaptureDevice) / 2) : 0; +#else + return 0; +#endif +} + +void SNDDMA_Capture(int samples, byte *data) +{ +#ifdef USE_SDL_AUDIO_CAPTURE + // multiplied by 2 to convert from (mono16) samples to bytes. + if (sdlCaptureDevice) + { + SDL_DequeueAudio(sdlCaptureDevice, data, samples * 2); + } + else +#endif + { + SDL_memset(data, '\0', samples * 2); + } +} + +void SNDDMA_StopCapture(void) +{ +#ifdef USE_SDL_AUDIO_CAPTURE + if (sdlCaptureDevice) + { + SDL_PauseAudioDevice(sdlCaptureDevice, 1); + } +#endif +} + +void SNDDMA_MasterGain( float val ) +{ +#ifdef USE_SDL_AUDIO_CAPTURE + sdlMasterGain = val; +#endif +} +#endif + diff --git a/code/server/server.h b/code/server/server.h index 39d6f4d3..ec1620aa 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -135,9 +135,9 @@ typedef struct client_s { char userinfo[MAX_INFO_STRING]; // name, etc char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS]; - int reliableSequence; // last added reliable message, not necesarily sent or acknowledged yet + int reliableSequence; // last added reliable message, not necessarily sent or acknowledged yet int reliableAcknowledge; // last acknowledged reliable message - int reliableSent; // last sent reliable message, not necesarily acknowledged yet + int reliableSent; // last sent reliable message, not necessarily acknowledged yet int messageAcknowledge; int gamestateMessageNum; // netchan->outgoingSequence of gamestate @@ -241,8 +241,10 @@ typedef struct { int nextHeartbeatTime; challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting netadr_t redirectAddress; // for rcon return messages - - netadr_t authorizeAddress; // for rcon return messages +#ifndef STANDALONE + netadr_t authorizeAddress; // authorize server address +#endif + int masterResolveTime[MAX_MASTER_SERVERS]; // next svs.time that server should do dns lookup for master server } serverStatic_t; #define SERVER_MAXBANS 1024 diff --git a/code/server/sv_bot.c b/code/server/sv_bot.c index d92dfcaf..58503542 100644 --- a/code/server/sv_bot.c +++ b/code/server/sv_bot.c @@ -543,7 +543,7 @@ void SV_BotInitBotLib(void) { // file system access botlib_import.FS_FOpenFile = FS_FOpenFileByMode; - botlib_import.FS_Read = FS_Read2; + botlib_import.FS_Read = FS_Read; botlib_import.FS_Write = FS_Write; botlib_import.FS_FCloseFile = FS_FCloseFile; botlib_import.FS_Seek = FS_Seek; diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index 506afcca..2ba8194d 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -1260,6 +1260,7 @@ static void SV_ConSay_f(void) { strcat(text, p); + Com_Printf("%s\n", text); SV_SendServerCommand(NULL, "chat \"%s\"", text); } @@ -1299,6 +1300,7 @@ static void SV_ConTell_f(void) { strcat(text, p); + Com_Printf("%s\n", text); SV_SendServerCommand(cl, "chat \"%s\"", text); } @@ -1364,6 +1366,7 @@ static void SV_ConSayto_f(void) { strcat(text, p); + Com_Printf("%s\n", text); SV_SendServerCommand(saytocl, "chat \"%s\"", text); } @@ -1480,7 +1483,7 @@ SV_CompletePlayerName static void SV_CompletePlayerName( char *args, int argNum ) { if( argNum == 2 ) { char names[MAX_CLIENTS][MAX_NAME_LENGTH]; - char *namesPtr[MAX_CLIENTS]; + const char *namesPtr[MAX_CLIENTS]; client_t *cl; int i; int nameCount; diff --git a/code/server/sv_client.c b/code/server/sv_client.c index d45c49d7..62d6456e 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -140,7 +140,7 @@ void SV_GetChallenge(netadr_t from) } // always generate a new challenge number, so the client cannot circumvent sv_maxping - challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time; + challenge->challenge = ( ((unsigned int)rand() << 16) ^ (unsigned int)rand() ) ^ svs.time; challenge->wasrefused = qfalse; challenge->time = svs.time; @@ -176,15 +176,13 @@ void SV_GetChallenge(netadr_t from) else { // otherwise send their ip to the authorize server - cvar_t *fs; - char game[1024]; + const char *game; Com_DPrintf( "sending getIpAuthorize for %s\n", NET_AdrToString( from )); - strcpy(game, BASEGAME); - fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); - if (fs && fs->string[0] != 0) { - strcpy(game, fs->string); + game = Cvar_VariableString( "fs_game" ); + if (game[0] == 0) { + game = BASEGAME; } // the 0 is for backwards compatibility with obsolete sv_allowanonymous flags @@ -488,7 +486,7 @@ void SV_DirectConnect( netadr_t from ) { // check for privateClient password password = Info_ValueForKey( userinfo, "password" ); - if ( !strcmp( password, sv_privatePassword->string ) ) { + if ( *password && !strcmp( password, sv_privatePassword->string ) ) { startIndex = 0; } else { // skip past the reserved slots @@ -673,12 +671,7 @@ void SV_DropClient( client_t *drop, const char *reason ) { if ( isBot ) { SV_BotFreeClient( drop - svs.clients ); - } - // nuke user info - SV_SetUserinfo( drop - svs.clients, "" ); - - if ( isBot ) { // bots shouldn't go zombie, as there's no real net connection. drop->state = CS_FREE; } else { @@ -686,6 +679,9 @@ void SV_DropClient( client_t *drop, const char *reason ) { drop->state = CS_ZOMBIE; // become free in a few seconds } + // nuke user info + SV_SetUserinfo( drop - svs.clients, "" ); + // if this was the last client on the server, send a heartbeat // to the master so it is known the server is empty // send a heartbeat now so the master will get up to date info @@ -1950,7 +1946,7 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) { } // if we can tell that the client has dropped the last // gamestate we sent them, resend it - if ( cl->messageAcknowledge > cl->gamestateMessageNum ) { + if ( cl->state != CS_ACTIVE && cl->messageAcknowledge > cl->gamestateMessageNum ) { Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name ); SV_SendClientGameState( cl ); } diff --git a/code/server/sv_game.c b/code/server/sv_game.c index ebfa726c..161d975e 100644 --- a/code/server/sv_game.c +++ b/code/server/sv_game.c @@ -325,7 +325,7 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { case G_FS_FOPEN_FILE: return FS_FOpenFileByMode( VMA(1), VMA(2), args[3] ); case G_FS_READ: - FS_Read2( VMA(1), args[2], args[3] ); + FS_Read( VMA(1), args[2], args[3] ); return 0; case G_FS_WRITE: FS_Write( VMA(1), args[2], args[3] ); @@ -465,7 +465,13 @@ intptr_t SV_GameSystemCalls( intptr_t *args ) { case BOTLIB_GET_CONSOLE_MESSAGE: return SV_BotGetConsoleMessage( args[1], VMA(2), args[3] ); case BOTLIB_USER_COMMAND: - SV_ClientThink( &svs.clients[args[1]], VMA(2) ); + { + int clientNum = args[1]; + + if ( clientNum >= 0 && clientNum < sv_maxclients->integer ) { + SV_ClientThink( &svs.clients[clientNum], VMA(2) ); + } + } return 0; case BOTLIB_AAS_BBOX_AREAS: diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 82db240f..2d1b7163 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -128,7 +128,7 @@ void SV_SetConfigstring (int index, const char *val) { // spawning a new server if ( sv.state == SS_GAME || sv.restarting ) { - // send the data to all relevent clients + // send the data to all relevant clients for (i = 0, client = svs.clients; i < sv_maxclients->integer ; i++, client++) { if ( client->state < CS_ACTIVE ) { if ( client->state == CS_PRIMED ) @@ -374,16 +374,12 @@ static void SV_ClearServer(void) { /* ================ -SV_TouchCGame - - touch the cgame.vm so that a pure client can load it if it's in a seperate pk3 +SV_TouchFile ================ */ -static void SV_TouchCGame(void) { +static void SV_TouchFile( const char *filename ) { fileHandle_t f; - char filename[MAX_QPATH]; - Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", "cgame" ); FS_FOpenFileRead( filename, &f, qfalse ); if ( f ) { FS_FCloseFile( f ); @@ -468,7 +464,7 @@ void SV_SpawnServer( char *server, qboolean killBots ) { Cvar_Set("cl_paused", "0"); // get a new checksum feed and restart the file system - sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds(); + sv.checksumFeed = ( ((unsigned int)rand() << 16) ^ (unsigned int)rand() ) ^ Com_Milliseconds(); FS_Restart( sv.checksumFeed ); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); @@ -574,11 +570,11 @@ void SV_SpawnServer( char *server, qboolean killBots ) { p = FS_LoadedPakNames(); Cvar_Set( "sv_pakNames", p ); - // if a dedicated pure server we need to touch the cgame because it could be in a - // seperate pk3 file and the client will need to load the latest cgame.qvm - if ( com_dedicated->integer ) { - SV_TouchCGame(); - } + // we need to touch the cgame and ui qvm because they could be in + // separate pk3 files and the client will need to download the pk3 + // files with the latest cgame and ui qvm to pass the pure check + SV_TouchFile( "vm/cgame.qvm" ); + SV_TouchFile( "vm/ui.qvm" ); } else { Cvar_Set( "sv_paks", "" ); diff --git a/code/server/sv_main.c b/code/server/sv_main.c index 993910fe..4d94c1e3 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -209,7 +209,7 @@ void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) { Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) ); } - // send the data to all relevent clients + // send the data to all relevant clients for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) { SV_AddServerCommand( client, (char *)message ); } @@ -236,6 +236,7 @@ but not on every player enter or exit. ================ */ #define HEARTBEAT_MSEC 300*1000 +#define MASTERDNS_MSEC 24*60*60*1000 void SV_MasterHeartbeat(const char *message) { static netadr_t adr[MAX_MASTER_SERVERS][2]; // [2] for v4 and v6 address for the same address string. @@ -264,12 +265,12 @@ void SV_MasterHeartbeat(const char *message) if(!sv_master[i]->string[0]) continue; - // see if we haven't already resolved the name - // resolving usually causes hitches on win95, so only - // do it when needed - if(sv_master[i]->modified || (adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD)) + // see if we haven't already resolved the name or if it's been over 24 hours + // resolving usually causes hitches on win95, so only do it when needed + if (sv_master[i]->modified || svs.time > svs.masterResolveTime[i]) { sv_master[i]->modified = qfalse; + svs.masterResolveTime[i] = svs.time + MASTERDNS_MSEC; if(netenabled & NET_ENABLEV4) { @@ -304,16 +305,11 @@ void SV_MasterHeartbeat(const char *message) else Com_Printf( "%s has no IPv6 address.\n", sv_master[i]->string); } + } - if(adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD) - { - // if the address failed to resolve, clear it - // so we don't take repeated dns hits - Com_Printf("Couldn't resolve address: %s\n", sv_master[i]->string); - Cvar_Set(sv_master[i]->name, ""); - sv_master[i]->modified = qfalse; - continue; - } + if(adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD) + { + continue; } diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index 2237abd3..ec760713 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -87,7 +87,7 @@ static void SV_EmitPacketEntities( clientSnapshot_t *from, clientSnapshot_t *to, if ( newnum == oldnum ) { // delta update from old position // because the force parm is qfalse, this will not result - // in any bytes being emited if the entity has not changed at all + // in any bytes being emitted if the entity has not changed at all MSG_WriteDeltaEntity (msg, oldent, newent, qfalse ); oldindex++; newindex++; @@ -653,6 +653,9 @@ void SV_SendClientMessages(void) if(!c->state) continue; // not connected + if(svs.time - c->lastSnapshotTime < c->snapshotMsec * com_timescale->value) + continue; // It's not time yet + if(*c->downloadName) continue; // Client is downloading, don't send snapshots @@ -666,10 +669,6 @@ void SV_SendClientMessages(void) (sv_lanForceRate->integer && Sys_IsLANAddress(c->netchan.remoteAddress)))) { // rate control for clients not on LAN - - if(svs.time - c->lastSnapshotTime < c->snapshotMsec * com_timescale->value) - continue; // It's not time yet - if(SV_RateMsec(c) > 0) { // Not enough time since last packet passed through the line diff --git a/code/sys/con_log.c b/code/sys/con_log.c index c3a4a5b8..bc1c5aef 100644 --- a/code/sys/con_log.c +++ b/code/sys/con_log.c @@ -121,7 +121,7 @@ unsigned int CON_LogRead( char *out, unsigned int outSize ) } Com_Memcpy( out, consoleLog + readPos, firstChunk ); - Com_Memcpy( out + firstChunk, out, secondChunk ); + Com_Memcpy( out + firstChunk, consoleLog, secondChunk ); readPos = ( readPos + outSize ) % MAX_LOG; diff --git a/code/sys/con_tty.c b/code/sys/con_tty.c index 9a6ee95c..58f178ad 100644 --- a/code/sys/con_tty.c +++ b/code/sys/con_tty.c @@ -73,20 +73,6 @@ static int hist_current = -1, hist_count = 0; #define TTY_CONSOLE_PROMPT "]" #endif -/* -================== -CON_FlushIn - -Flush stdin, I suspect some terminals are sending a LOT of shit -FIXME relevant? -================== -*/ -static void CON_FlushIn( void ) -{ - char key; - while (read(STDIN_FILENO, &key, 1)!=-1); -} - /* ================== CON_Back @@ -378,7 +364,7 @@ char *CON_Input( void ) { #ifndef DEDICATED // if not in the game explicitly prepend a slash if needed - if (clc.state != CA_ACTIVE && TTY_con.cursor && + if (clc.state != CA_ACTIVE && con_autochat->integer && TTY_con.cursor && TTY_con.buffer[0] != '/' && TTY_con.buffer[0] != '\\') { memmove(TTY_con.buffer + 1, TTY_con.buffer, sizeof(TTY_con.buffer) - 1); @@ -389,7 +375,11 @@ char *CON_Input( void ) if (TTY_con.buffer[0] == '/' || TTY_con.buffer[0] == '\\') { Q_strncpyz(text, TTY_con.buffer + 1, sizeof(text)); } else if (TTY_con.cursor) { - Com_sprintf(text, sizeof(text), "cmd say %s", TTY_con.buffer); + if (con_autochat->integer) { + Com_sprintf(text, sizeof(text), "cmd say %s", TTY_con.buffer); + } else { + Q_strncpyz(text, TTY_con.buffer, sizeof(text)); + } } else { text[0] = '\0'; } @@ -437,7 +427,7 @@ char *CON_Input( void ) TTY_con = *history; CON_Show(); } - CON_FlushIn(); + tcflush(STDIN_FILENO, TCIFLUSH); return NULL; break; case 'B': @@ -451,7 +441,7 @@ char *CON_Input( void ) Field_Clear(&TTY_con); } CON_Show(); - CON_FlushIn(); + tcflush(STDIN_FILENO, TCIFLUSH); return NULL; break; case 'C': @@ -463,7 +453,7 @@ char *CON_Input( void ) } } Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase); - CON_FlushIn(); + tcflush(STDIN_FILENO, TCIFLUSH); return NULL; } if (TTY_con.cursor >= sizeof(text) - 1) diff --git a/code/sys/sys_autoupdater.c b/code/sys/sys_autoupdater.c new file mode 100644 index 00000000..2f59e071 --- /dev/null +++ b/code/sys/sys_autoupdater.c @@ -0,0 +1,86 @@ +/* +The code in this file is in the public domain. The rest of ioquake3 +is licensed under the GPLv2. Do not mingle code, please! +*/ + +#ifdef USE_AUTOUPDATER +# ifndef AUTOUPDATER_BIN +# error The build system should have defined AUTOUPDATER_BIN +# endif + +# ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN 1 +# include +# else +# include +# endif + +# include +# include +#endif + +void Sys_LaunchAutoupdater(int argc, char **argv) +{ +#ifdef USE_AUTOUPDATER + #ifdef _WIN32 + { + /* We don't need the Unix pipe() tapdance here because Windows lets children wait on parent processes. */ + PROCESS_INFORMATION procinfo; + STARTUPINFO startinfo; + char cmdline[128]; + memset(&procinfo, '\0', sizeof (procinfo)); + memset(&startinfo, '\0', sizeof (startinfo)); + startinfo.cb = sizeof (startinfo); + sprintf(cmdline, "" AUTOUPDATER_BIN " --waitpid %u", (unsigned int) GetCurrentProcessId()); + + if (CreateProcessA(AUTOUPDATER_BIN, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startinfo, &procinfo)) + { + /* close handles now so child cleans up immediately if nothing to do */ + CloseHandle(procinfo.hProcess); + CloseHandle(procinfo.hThread); + } + } + #else + int updater_pipes[2]; + if (pipe(updater_pipes) == 0) + { + pid_t pid = fork(); + if (pid == -1) /* failure, oh well. */ + { + close(updater_pipes[0]); + close(updater_pipes[1]); + } + else if (pid == 0) /* child process */ + { + close(updater_pipes[1]); /* don't need write end. */ + if (dup2(updater_pipes[0], 3) != -1) + { + char pidstr[64]; + char *ptr = strrchr(argv[0], '/'); + if (ptr) + *ptr = '\0'; + if (chdir(argv[0]) == -1) { + _exit(1); /* oh well. */ + } + #ifdef __APPLE__ + if (chdir("../..") == -1) { /* put this at base of app bundle so paths make sense later. */ + _exit(1); /* oh well. */ + } + #endif + snprintf(pidstr, sizeof (pidstr), "%lld", (long long) getppid()); + execl(AUTOUPDATER_BIN, AUTOUPDATER_BIN, "--waitpid", pidstr, NULL); + } + _exit(0); /* oh well. */ + } + else /* parent process */ + { + /* leave the write end open until we terminate so updater can block on it. */ + close(updater_pipes[0]); + } + } + #endif +#endif + + (void) argc; (void) argv; /* possibly unused. Pacify compilers. */ +} + diff --git a/code/sys/sys_local.h b/code/sys/sys_local.h index f8bd5b46..cd7fbe7f 100644 --- a/code/sys/sys_local.h +++ b/code/sys/sys_local.h @@ -23,16 +23,22 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/q_shared.h" #include "../qcommon/qcommon.h" +#ifndef DEDICATED +#ifdef USE_LOCAL_HEADERS +# include "SDL_version.h" +#else +# include +#endif + // Require a minimum version of SDL #define MINSDL_MAJOR 2 #define MINSDL_MINOR 0 +#if SDL_VERSION_ATLEAST( 2, 0, 5 ) +#define MINSDL_PATCH 5 +#else #define MINSDL_PATCH 0 - -// Input subsystem -void IN_Init( void *windowData ); -void IN_Frame( void ); -void IN_Shutdown( void ); -void IN_Restart( void ); +#endif +#endif // Console void CON_Shutdown( void ); @@ -44,7 +50,7 @@ unsigned int CON_LogSize( void ); unsigned int CON_LogWrite( const char *in ); unsigned int CON_LogRead( char *out, unsigned int outSize ); -#ifdef MACOS_X +#ifdef __APPLE__ char *Sys_StripAppBundle( char *pwd ); #endif diff --git a/code/sys/sys_main.c b/code/sys/sys_main.c index 60cdb50c..40b07e5d 100644 --- a/code/sys/sys_main.c +++ b/code/sys/sys_main.c @@ -112,6 +112,14 @@ Restart the input subsystem */ void Sys_In_Restart_f( void ) { +#ifndef DEDICATED + if( !SDL_WasInit( SDL_INIT_VIDEO ) ) + { + Com_Printf( "in_restart: Cannot restart input while video is shutdown\n" ); + return; + } +#endif + IN_Restart( ); } @@ -167,16 +175,29 @@ char *Sys_GetClipboardData(void) Sys_PIDFileName ================= */ -static char *Sys_PIDFileName( void ) +static char *Sys_PIDFileName( const char *gamedir ) { const char *homePath = Cvar_VariableString( "fs_homepath" ); if( *homePath != '\0' ) - return va( "%s/%s", homePath, PID_FILENAME ); + return va( "%s/%s/%s", homePath, gamedir, PID_FILENAME ); return NULL; } +/* +================= +Sys_RemovePIDFile +================= +*/ +void Sys_RemovePIDFile( const char *gamedir ) +{ + char *pidFile = Sys_PIDFileName( gamedir ); + + if( pidFile != NULL ) + remove( pidFile ); +} + /* ================= Sys_WritePIDFile @@ -184,9 +205,9 @@ Sys_WritePIDFile Return qtrue if there is an existing stale PID file ================= */ -qboolean Sys_WritePIDFile( void ) +static qboolean Sys_WritePIDFile( const char *gamedir ) { - char *pidFile = Sys_PIDFileName( ); + char *pidFile = Sys_PIDFileName( gamedir ); FILE *f; qboolean stale = qfalse; @@ -212,6 +233,10 @@ qboolean Sys_WritePIDFile( void ) stale = qtrue; } + if( FS_CreatePath( pidFile ) ) { + return 0; + } + if( ( f = fopen( pidFile, "w" ) ) != NULL ) { fprintf( f, "%d", Sys_PID( ) ); @@ -223,6 +248,31 @@ qboolean Sys_WritePIDFile( void ) return stale; } +/* +================= +Sys_InitPIDFile +================= +*/ +void Sys_InitPIDFile( const char *gamedir ) { + if( Sys_WritePIDFile( gamedir ) ) { +#ifndef DEDICATED + char message[1024]; + char modName[MAX_OSPATH]; + + FS_GetModDescription( gamedir, modName, sizeof ( modName ) ); + Q_CleanStr( modName ); + + Com_sprintf( message, sizeof (message), "The last time %s ran, " + "it didn't exit properly. This may be due to inappropriate video " + "settings. Would you like to start with \"safe\" video settings?", modName ); + + if( Sys_Dialog( DT_YES_NO, message, "Abnormal Exit" ) == DR_YES ) { + Cvar_Set( "com_abnormalExit", "1" ); + } +#endif + } +} + /* ================= Sys_Exit @@ -238,13 +288,10 @@ static __attribute__ ((noreturn)) void Sys_Exit( int exitCode ) SDL_Quit( ); #endif - if( exitCode < 2 ) + if( exitCode < 2 && com_fullyInitialized ) { // Normal exit - char *pidFile = Sys_PIDFileName( ); - - if( pidFile != NULL ) - remove( pidFile ); + Sys_RemovePIDFile( FS_GetCurrentGameDir() ); } NET_Shutdown( ); @@ -274,10 +321,12 @@ cpuFeatures_t Sys_GetProcessorFeatures( void ) cpuFeatures_t features = 0; #ifndef DEDICATED - if( SDL_HasRDTSC( ) ) features |= CF_RDTSC; - if( SDL_HasMMX( ) ) features |= CF_MMX; - if( SDL_HasSSE( ) ) features |= CF_SSE; - if( SDL_HasSSE2( ) ) features |= CF_SSE2; + if( SDL_HasRDTSC( ) ) features |= CF_RDTSC; + if( SDL_Has3DNow( ) ) features |= CF_3DNOW; + if( SDL_HasMMX( ) ) features |= CF_MMX; + if( SDL_HasSSE( ) ) features |= CF_SSE; + if( SDL_HasSSE2( ) ) features |= CF_SSE2; + if( SDL_HasAltiVec( ) ) features |= CF_ALTIVEC; #endif return features; @@ -457,25 +506,43 @@ from executable path, then fs_basepath. void *Sys_LoadDll(const char *name, qboolean useSystemLib) { - void *dllhandle; - + void *dllhandle = NULL; + + if(!Sys_DllExtension(name)) + { + Com_Printf("Refusing to attempt to load library \"%s\": Extension not allowed.\n", name); + return NULL; + } + if(useSystemLib) + { Com_Printf("Trying to load \"%s\"...\n", name); + dllhandle = Sys_LoadLibrary(name); + } - if(!useSystemLib || !(dllhandle = Sys_LoadLibrary(name))) + if(!dllhandle) { const char *topDir; char libPath[MAX_OSPATH]; + int len; topDir = Sys_BinaryPath(); if(!*topDir) topDir = "."; - Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, topDir); - Com_sprintf(libPath, sizeof(libPath), "%s%c%s", topDir, PATH_SEP, name); + len = Com_sprintf(libPath, sizeof(libPath), "%s%c%s", topDir, PATH_SEP, name); + if(len < sizeof(libPath)) + { + Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, topDir); + dllhandle = Sys_LoadLibrary(libPath); + } + else + { + Com_Printf("Skipping trying to load \"%s\" from \"%s\", file name is too long.\n", name, topDir); + } - if(!(dllhandle = Sys_LoadLibrary(libPath))) + if(!dllhandle) { const char *basePath = Cvar_VariableString("fs_basepath"); @@ -484,9 +551,16 @@ void *Sys_LoadDll(const char *name, qboolean useSystemLib) if(FS_FilenameCompare(topDir, basePath)) { - Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, basePath); - Com_sprintf(libPath, sizeof(libPath), "%s%c%s", basePath, PATH_SEP, name); - dllhandle = Sys_LoadLibrary(libPath); + len = Com_sprintf(libPath, sizeof(libPath), "%s%c%s", basePath, PATH_SEP, name); + if(len < sizeof(libPath)) + { + Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, basePath); + dllhandle = Sys_LoadLibrary(libPath); + } + else + { + Com_Printf("Skipping trying to load \"%s\" from \"%s\", file name is too long.\n", name, basePath); + } } if(!dllhandle) @@ -513,6 +587,12 @@ void *Sys_LoadGameDll(const char *name, assert(name); + if(!Sys_DllExtension(name)) + { + Com_Printf("Refusing to attempt to load library \"%s\": Extension not allowed.\n", name); + return NULL; + } + Com_Printf( "Loading DLL file: %s\n", name); libHandle = Sys_LoadLibrary(name); @@ -551,7 +631,7 @@ void Sys_ParseArgs( int argc, char **argv ) if( !strcmp( argv[1], "--version" ) || !strcmp( argv[1], "-v" ) ) { - const char* date = __DATE__; + const char* date = PRODUCT_DATE; #ifdef DEDICATED fprintf( stdout, Q3_VERSION " dedicated server (%s)\n", date ); #else @@ -563,7 +643,7 @@ void Sys_ParseArgs( int argc, char **argv ) } #ifndef DEFAULT_BASEDIR -# ifdef MACOS_X +# ifdef __APPLE__ # define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_BinaryPath()) # else # define DEFAULT_BASEDIR Sys_BinaryPath() @@ -611,6 +691,9 @@ int main( int argc, char **argv ) int i; char commandLine[ MAX_STRING_CHARS ] = { 0 }; + extern void Sys_LaunchAutoupdater(int argc, char **argv); + Sys_LaunchAutoupdater(argc, argv); + #ifndef DEDICATED // SDL version check @@ -644,7 +727,7 @@ int main( int argc, char **argv ) // Set the initial time base Sys_Milliseconds( ); -#ifdef MACOS_X +#ifdef __APPLE__ // This is passed if we are launched by double-clicking if ( argc >= 2 && Q_strncmp ( argv[1], "-psn", 4 ) == 0 ) argc = 1; @@ -669,11 +752,10 @@ int main( int argc, char **argv ) Q_strcat( commandLine, sizeof( commandLine ), " " ); } + CON_Init( ); Com_Init( commandLine ); NET_Init( ); - CON_Init( ); - signal( SIGILL, Sys_SigHandler ); signal( SIGFPE, Sys_SigHandler ); signal( SIGSEGV, Sys_SigHandler ); @@ -682,7 +764,6 @@ int main( int argc, char **argv ) while( 1 ) { - IN_Frame( ); Com_Frame( ); } diff --git a/code/sys/sys_osx.m b/code/sys/sys_osx.m index 30bf9322..b0ecf6a5 100644 --- a/code/sys/sys_osx.m +++ b/code/sys/sys_osx.m @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#ifndef MACOS_X +#ifndef __APPLE__ #error This file is for Mac OS X only. You probably should not compile it. #endif diff --git a/code/sys/sys_unix.c b/code/sys/sys_unix.c index cf980eba..1043b9a4 100644 --- a/code/sys/sys_unix.c +++ b/code/sys/sys_unix.c @@ -47,6 +47,9 @@ static char homePath[ MAX_OSPATH ] = { 0 }; // Used to store the Steam Quake 3 installation path static char steamPath[ MAX_OSPATH ] = { 0 }; +// Used to store the GOG Quake 3 installation path +static char gogPath[ MAX_OSPATH ] = { 0 }; + /* ================== Sys_DefaultHomePath @@ -61,7 +64,7 @@ char *Sys_DefaultHomePath(void) if( ( p = getenv( "HOME" ) ) != NULL ) { Com_sprintf(homePath, sizeof(homePath), "%s%c", p, PATH_SEP); -#ifdef MACOS_X +#ifdef __APPLE__ Q_strcat(homePath, sizeof(homePath), "Library/Application Support/"); @@ -94,7 +97,7 @@ char *Sys_SteamPath( void ) if( ( p = getenv( "HOME" ) ) != NULL ) { -#ifdef MACOS_X +#ifdef __APPLE__ char *steamPathEnd = "/Library/Application Support/Steam/SteamApps/common/" STEAMPATH_NAME; #else char *steamPathEnd = "/.steam/steam/SteamApps/common/" STEAMPATH_NAME; @@ -106,6 +109,17 @@ char *Sys_SteamPath( void ) return steamPath; } +/* +================ +Sys_GogPath +================ +*/ +char *Sys_GogPath( void ) +{ + // GOG also doesn't let you install Quake 3 on Mac/Linux + return gogPath; +} + /* ================ Sys_Milliseconds @@ -481,7 +495,7 @@ void Sys_FreeFileList( char **list ) ================== Sys_Sleep -Block execution for msec or until input is recieved. +Block execution for msec or until input is received. ================== */ void Sys_Sleep( int msec ) @@ -577,7 +591,7 @@ void Sys_ErrorDialog( const char *error ) close( f ); } -#ifndef MACOS_X +#ifndef __APPLE__ static char execBuffer[ 1024 ]; static char *execBufferPointer; static char *execArgv[ 16 ]; @@ -898,3 +912,52 @@ qboolean Sys_PIDIsRunning( int pid ) { return kill( pid, 0 ) == 0; } + +/* +================= +Sys_DllExtension + +Check if filename should be allowed to be loaded as a DLL. +================= +*/ +qboolean Sys_DllExtension( const char *name ) { + const char *p; + char c = 0; + + if ( COM_CompareExtension( name, DLL_EXT ) ) { + return qtrue; + } + +#ifdef __APPLE__ + // Allow system frameworks without dylib extensions + // i.e., /System/Library/Frameworks/OpenAL.framework/OpenAL + if ( strncmp( name, "/System/Library/Frameworks/", 27 ) == 0 ) { + return qtrue; + } +#endif + + // Check for format of filename.so.1.2.3 + p = strstr( name, DLL_EXT "." ); + + if ( p ) { + p += strlen( DLL_EXT ); + + // Check if .so is only followed for periods and numbers. + while ( *p ) { + c = *p; + + if ( !isdigit( c ) && c != '.' ) { + return qfalse; + } + + p++; + } + + // Don't allow filename to end in a period. file.so., file.so.0., etc + if ( c != '.' ) { + return qtrue; + } + } + + return qfalse; +} diff --git a/code/sys/sys_win32.c b/code/sys/sys_win32.c index da7241a7..ee026bd8 100644 --- a/code/sys/sys_win32.c +++ b/code/sys/sys_win32.c @@ -39,12 +39,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include +#ifndef KEY_WOW64_32KEY +#define KEY_WOW64_32KEY 0x0200 +#endif + // Used to determine where to store user-specific files static char homePath[ MAX_OSPATH ] = { 0 }; // Used to store the Steam Quake 3 installation path static char steamPath[ MAX_OSPATH ] = { 0 }; +// Used to store the GOG Quake 3 installation path +static char gogPath[ MAX_OSPATH ] = { 0 }; + #ifndef DEDICATED static UINT timerResolution = 0; #endif @@ -148,6 +155,8 @@ char *Sys_SteamPath( void ) pathLen = MAX_OSPATH; if (RegQueryValueEx(steamRegKey, "InstallLocation", NULL, NULL, (LPBYTE)steamPath, &pathLen)) steamPath[0] = '\0'; + + RegCloseKey(steamRegKey); } #endif @@ -161,6 +170,8 @@ char *Sys_SteamPath( void ) if (steamPath[0]) finishPath = qtrue; + + RegCloseKey(steamRegKey); } #endif @@ -179,6 +190,38 @@ char *Sys_SteamPath( void ) return steamPath; } +/* +================ +Sys_GogPath +================ +*/ +char *Sys_GogPath( void ) +{ +#ifdef GOGPATH_ID + HKEY gogRegKey; + DWORD pathLen = MAX_OSPATH; + + if (!gogPath[0] && !RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\GOG.com\\Games\\" GOGPATH_ID, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &gogRegKey)) + { + pathLen = MAX_OSPATH; + if (RegQueryValueEx(gogRegKey, "PATH", NULL, NULL, (LPBYTE)gogPath, &pathLen)) + gogPath[0] = '\0'; + + RegCloseKey(gogRegKey); + } + + if (gogPath[0]) + { + if (pathLen == MAX_OSPATH) + pathLen--; + + gogPath[pathLen] = '\0'; + } +#endif + + return gogPath; +} + /* ================ Sys_Milliseconds @@ -314,6 +357,14 @@ Sys_FOpen ============== */ FILE *Sys_FOpen( const char *ospath, const char *mode ) { + size_t length; + + // Windows API ignores all trailing spaces and periods which can get around Quake 3 file system restrictions. + length = strlen( ospath ); + if ( length == 0 || ospath[length-1] == ' ' || ospath[length-1] == '.' ) { + return NULL; + } + return fopen( ospath, mode ); } @@ -799,3 +850,14 @@ qboolean Sys_PIDIsRunning( int pid ) return qfalse; } + +/* +================= +Sys_DllExtension + +Check if filename should be allowed to be loaded as a DLL. +================= +*/ +qboolean Sys_DllExtension( const char *name ) { + return COM_CompareExtension( name, DLL_EXT ); +} diff --git a/code/sys/win_manifest.xml b/code/sys/win_manifest.xml new file mode 100644 index 00000000..dccbcf56 --- /dev/null +++ b/code/sys/win_manifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True/PM + PerMonitorV2, PerMonitor + + + diff --git a/code/sys/win_resource.rc b/code/sys/win_resource.rc index b1c39d50..b9c8c6ea 100644 --- a/code/sys/win_resource.rc +++ b/code/sys/win_resource.rc @@ -70,6 +70,12 @@ BEGIN IDS_STRING1 "Quake3" END +///////////////////////////////////////////////////////////////////////////// +// +// Application Manifest +// +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "win_manifest.xml" + #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/code/tools/asm/cmdlib.c b/code/tools/asm/cmdlib.c index d130d8df..7d79e2c5 100644 --- a/code/tools/asm/cmdlib.c +++ b/code/tools/asm/cmdlib.c @@ -734,7 +734,7 @@ int LoadFile( const char *filename, void **bufferptr ) ============== LoadFileBlock - -rounds up memory allocation to 4K boundry +rounds up memory allocation to 4K boundary - ============== */ @@ -810,7 +810,7 @@ void DefaultExtension (char *path, const char *extension) { char *src; // -// if path doesnt have a .EXT, append extension +// if path doesn't have a .EXT, append extension // (extension should include the .) // src = path + strlen(path) - 1; diff --git a/code/tools/asm/cmdlib.h b/code/tools/asm/cmdlib.h index c2e6dd88..3233abd6 100644 --- a/code/tools/asm/cmdlib.h +++ b/code/tools/asm/cmdlib.h @@ -59,7 +59,7 @@ typedef unsigned char byte; #define MAX_OS_PATH 1024 #define MEM_BLOCKSIZE 4096 -// the dec offsetof macro doesnt work very well... +// the dec offsetof macro doesn't work very well... #define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) diff --git a/code/tools/asm/notes.txt b/code/tools/asm/notes.txt index 63297f30..571f8cac 100644 --- a/code/tools/asm/notes.txt +++ b/code/tools/asm/notes.txt @@ -1,5 +1,5 @@ -don't do any paramter conversion (double to float, etc) +don't do any parameter conversion (double to float, etc) diff --git a/code/tools/asm/q3asm.c b/code/tools/asm/q3asm.c index 191a9db6..c4e1413d 100644 --- a/code/tools/asm/q3asm.c +++ b/code/tools/asm/q3asm.c @@ -477,7 +477,7 @@ static unsigned int HashString (const char *key) acc = (acc << 2) | (acc >> 30); acc &= 0xffffffffU; } - return abs(acc); + return acc; } @@ -788,7 +788,7 @@ HackToSegment BIG HACK: I want to put all 32 bit values in the data segment so they can be byte swapped, and all char data in the lit -segment, but switch jump tables are emited in the lit segment and +segment, but switch jump tables are emitted in the lit segment and initialized strng variables are put in the data segment. I can change segments here, but I also need to fixup the @@ -1129,7 +1129,7 @@ STAT("BYTE"); return 0; } - // code labels are emited as instruction counts, not byte offsets, + // code labels are emitted as instruction counts, not byte offsets, // because the physical size of the code will change with // different run time compilers and we want to minimize the // size of the required translation table @@ -1564,7 +1564,7 @@ int main( int argc, char **argv ) { if ( !strcmp( argv[i], "-o" ) ) { if ( i == argc - 1 ) { - Error( "-o must preceed a filename" ); + Error( "-o must precede a filename" ); } /* Timbo of Tremulous pointed out -o not working; stock ID q3asm folded in the change. Yay. */ strcpy( outputFilename, argv[ i+1 ] ); @@ -1574,7 +1574,7 @@ int main( int argc, char **argv ) { if ( !strcmp( argv[i], "-f" ) ) { if ( i == argc - 1 ) { - Error( "-f must preceed a filename" ); + Error( "-f must precede a filename" ); } ParseOptionFile( argv[ i+1 ] ); i++; diff --git a/code/tools/lcc/cpp/tokens.c b/code/tools/lcc/cpp/tokens.c index 3570896c..964453c3 100644 --- a/code/tools/lcc/cpp/tokens.c +++ b/code/tools/lcc/cpp/tokens.c @@ -315,7 +315,7 @@ puttokens(Tokenrow *trp) if (wbp >= &wbuf[OBS]) { write(1, wbuf, OBS); if (wbp > &wbuf[OBS]) - memcpy(wbuf, wbuf+OBS, wbp - &wbuf[OBS]); + memmove(wbuf, wbuf+OBS, wbp - &wbuf[OBS]); wbp -= OBS; } } diff --git a/code/tools/lcc/cpp/unix.c b/code/tools/lcc/cpp/unix.c index 75e5b6d3..bac841d8 100644 --- a/code/tools/lcc/cpp/unix.c +++ b/code/tools/lcc/cpp/unix.c @@ -106,7 +106,7 @@ char *basepath( char *fname ) all and others do a terrible job (like calling malloc) */ // -- ouch, that hurts -- ln /* always use the system memmove() on Mac OS X. --ryan. */ -#if !defined(MACOS_X) && !defined(_MSC_VER) +#if !defined(__APPLE__) && !defined(_MSC_VER) #ifdef memmove #undef memmove #endif diff --git a/code/tools/lcc/doc/4.html b/code/tools/lcc/doc/4.html index 0b4b36d2..c1cd8daa 100644 --- a/code/tools/lcc/doc/4.html +++ b/code/tools/lcc/doc/4.html @@ -41,7 +41,7 @@ and insisted that pointers fit in unsigned integers (see Sec. 5.1 of A Ret C Compiler). These assumptions simplified the compiler, and were suitable for 32-bit architectures. But on 64-bit architectures, such as the DEC ALPHA, it's natural to have four sizes of integers and perhaps three sizes of floats, and on 16-bit -architectures, 32-bit pointers don't fit in unsigned integers. Also, the 3.x constaints +architectures, 32-bit pointers don't fit in unsigned integers. Also, the 3.x constraints limited the use of lcc's back ends for other languages, such as Java.

Version 4.x removes all of these restrictions: It supports any number of sizes for diff --git a/code/tools/lcc/etc/bytecode.c b/code/tools/lcc/etc/bytecode.c index a5855de3..6e580228 100644 --- a/code/tools/lcc/etc/bytecode.c +++ b/code/tools/lcc/etc/bytecode.c @@ -34,8 +34,10 @@ void UpdatePaths( const char *lccBinary ) { char basepath[ 1024 ]; char *p; + size_t basepathsz = sizeof( basepath ) - 1; - strncpy( basepath, lccBinary, 1024 ); + strncpy( basepath, lccBinary, basepathsz ); + basepath[basepathsz] = 0; p = strrchr( basepath, PATH_SEP ); if( p ) diff --git a/code/tools/lcc/etc/lcc.c b/code/tools/lcc/etc/lcc.c index aa3e7894..a12799b6 100644 --- a/code/tools/lcc/etc/lcc.c +++ b/code/tools/lcc/etc/lcc.c @@ -636,7 +636,7 @@ static void opt(char *arg) { clist = append(&arg[3], clist); return; } - break; /* and fall thru */ + break; /* and fall through */ case 'a': alist = append(&arg[3], alist); return; diff --git a/code/tools/lcc/src/enode.c b/code/tools/lcc/src/enode.c index 4a37618c..d59c31bf 100644 --- a/code/tools/lcc/src/enode.c +++ b/code/tools/lcc/src/enode.c @@ -401,7 +401,7 @@ Tree addrof(Tree p) { Symbol t1 = q->u.sym; q->u.sym = 0; q = idtree(t1); - /* fall thru */ + /* fall through */ } case INDIR: if (p == q) diff --git a/code/tools/lcc/src/error.c b/code/tools/lcc/src/error.c index 2187c101..52ca11f5 100644 --- a/code/tools/lcc/src/error.c +++ b/code/tools/lcc/src/error.c @@ -80,7 +80,7 @@ int fatal(const char *name, const char *fmt, int n) { return 0; } -/* printtoken - print current token preceeded by a space */ +/* printtoken - print current token preceded by a space */ static void printtoken(void) { switch (t) { case ID: fprint(stderr, " `%s'", token); break; diff --git a/code/tools/lcc/src/gen.c b/code/tools/lcc/src/gen.c index 4ee170d9..1413a787 100644 --- a/code/tools/lcc/src/gen.c +++ b/code/tools/lcc/src/gen.c @@ -292,7 +292,7 @@ static void dumptree(Node p) { dumptree(p->kids[0]); break; } - /* else fall thru */ + /* else fall through */ case EQ: case NE: case GT: case GE: case LE: case LT: case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH: case ADD: case SUB: case DIV: case MUL: case MOD: diff --git a/code/tools/lcc/src/init.c b/code/tools/lcc/src/init.c index 172d7c04..2f015b40 100644 --- a/code/tools/lcc/src/init.c +++ b/code/tools/lcc/src/init.c @@ -40,7 +40,7 @@ static int genconst(Tree e, int def) { if (isarith(e->type)) error("cast from `%t' to `%t' is illegal in constant expressions\n", e->kids[0]->type, e->type); - /* fall thru */ + /* fall through */ case CVI: case CVU: case CVF: e = e->kids[0]; continue; diff --git a/code/tools/lcc/src/tree.c b/code/tools/lcc/src/tree.c index d2b6a917..e8e9e1f4 100644 --- a/code/tools/lcc/src/tree.c +++ b/code/tools/lcc/src/tree.c @@ -86,7 +86,7 @@ static Tree root1(Tree p) { warning("reference to `%t' elided\n", p->type); if (isptr(p->kids[0]->type) && isvolatile(p->kids[0]->type->type)) warning("reference to `volatile %t' elided\n", p->type); - /* fall thru */ + /* fall through */ case CVI: case CVF: case CVU: case CVP: case NEG: case BCOM: case FIELD: if (warn++ == 0) diff --git a/jenkins-ci-build.sh b/jenkins-ci-build.sh index 31bdd97f..e28c80a5 100755 --- a/jenkins-ci-build.sh +++ b/jenkins-ci-build.sh @@ -8,7 +8,6 @@ cd ${MASTER_DIR} if [ "${OPTIONS}" == "all_options" ]; then - export USE_CODEC_VORBIS=1 export USE_FREETYPE=1 fi diff --git a/make-macosx-app.sh b/make-macosx-app.sh index 82eb623a..1fd81653 100755 --- a/make-macosx-app.sh +++ b/make-macosx-app.sh @@ -255,18 +255,20 @@ done echo "" # make the application bundle directories -if [ ! -d ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$BASEDIR ]; then - mkdir -p ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$BASEDIR || exit 1; +if [ ! -d "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$BASEDIR" ]; then + mkdir -p "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$BASEDIR" || exit 1; fi -if [ ! -d ${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} ]; then - mkdir -p ${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} || exit 1; +if [ ! -d "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" ]; then + mkdir -p "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" || exit 1; fi # copy and generate some application bundle resources -cp code/libs/macosx/*.dylib ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH} -cp ${ICNSDIR}/${ICNS} ${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/$ICNS || exit 1; -echo -n ${PKGINFO} > ${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/PkgInfo || exit 1; -echo " +cp code/libs/macosx/*.dylib "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}" +cp ${ICNSDIR}/${ICNS} "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/$ICNS" || exit 1; +echo -n ${PKGINFO} > "${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/PkgInfo" || exit 1; + +# create Info.Plist +PLIST=" @@ -293,14 +295,44 @@ echo " CGDisableCoalescedUpdates LSMinimumSystemVersion - ${MACOSX_DEPLOYMENT_TARGET} + ${MACOSX_DEPLOYMENT_TARGET}" + +if [ -n "${MACOSX_DEPLOYMENT_TARGET_PPC}" ] || [ -n "${MACOSX_DEPLOYMENT_TARGET_X86}" ] || [ -n "${MACOSX_DEPLOYMENT_TARGET_X86_64}" ]; then + PLIST="${PLIST} + LSMinimumSystemVersionByArchitecture + " + + if [ -n "${MACOSX_DEPLOYMENT_TARGET_PPC}" ]; then + PLIST="${PLIST} + ppc + ${MACOSX_DEPLOYMENT_TARGET_PPC}" + fi + + if [ -n "${MACOSX_DEPLOYMENT_TARGET_X86}" ]; then + PLIST="${PLIST} + i386 + ${MACOSX_DEPLOYMENT_TARGET_X86}" + fi + + if [ -n "${MACOSX_DEPLOYMENT_TARGET_X86_64}" ]; then + PLIST="${PLIST} + x86_64 + ${MACOSX_DEPLOYMENT_TARGET_X86_64}" + fi + + PLIST="${PLIST} + " +fi + +PLIST="${PLIST} NSHumanReadableCopyright Reaction Copyright © 2000-2012 Boomstick Studios. NSPrincipalClass NSApplication -" > ${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Info.plist +" +echo -e "${PLIST}" > "${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Info.plist" # action takes care of generating universal binaries if lipo is available # otherwise, it falls back to using a simple copy, expecting the first item in @@ -332,19 +364,19 @@ function action() # # executables -action ${BUNDLEBINDIR}/${EXECUTABLE_NAME} "${IOQ3_CLIENT_ARCHS}" -action ${BUNDLEBINDIR}/${DEDICATED_NAME} "${IOQ3_SERVER_ARCHS}" +action "${BUNDLEBINDIR}/${EXECUTABLE_NAME}" "${IOQ3_CLIENT_ARCHS}" +action "${BUNDLEBINDIR}/${DEDICATED_NAME}" "${IOQ3_SERVER_ARCHS}" # renderers -action ${BUNDLEBINDIR}/${RENDERER_OPENGL1_NAME} "${IOQ3_RENDERER_GL1_ARCHS}" -action ${BUNDLEBINDIR}/${RENDERER_OPENGL2_NAME} "${IOQ3_RENDERER_GL2_ARCHS}" +action "${BUNDLEBINDIR}/${RENDERER_OPENGL1_NAME}" "${IOQ3_RENDERER_GL1_ARCHS}" +action "${BUNDLEBINDIR}/${RENDERER_OPENGL2_NAME}" "${IOQ3_RENDERER_GL2_ARCHS}" symlinkArch "${RENDERER_OPENGL}1" "${RENDERER_OPENGL}1" "_" "${BUNDLEBINDIR}" symlinkArch "${RENDERER_OPENGL}2" "${RENDERER_OPENGL}2" "_" "${BUNDLEBINDIR}" # game -action ${BUNDLEBINDIR}/${BASEDIR}/${CGAME_NAME} "${IOQ3_CGAME_ARCHS}" -action ${BUNDLEBINDIR}/${BASEDIR}/${GAME_NAME} "${IOQ3_GAME_ARCHS}" -action ${BUNDLEBINDIR}/${BASEDIR}/${UI_NAME} "${IOQ3_UI_ARCHS}" +action "${BUNDLEBINDIR}/${BASEDIR}/${CGAME_NAME}" "${IOQ3_CGAME_ARCHS}" +action "${BUNDLEBINDIR}/${BASEDIR}/${GAME_NAME}" "${IOQ3_GAME_ARCHS}" +action "${BUNDLEBINDIR}/${BASEDIR}/${UI_NAME}" "${IOQ3_UI_ARCHS}" symlinkArch "${CGAME}" "${CGAME}" "" "${BUNDLEBINDIR}/${BASEDIR}" symlinkArch "${GAME}" "${GAME}" "" "${BUNDLEBINDIR}/${BASEDIR}" symlinkArch "${UI}" "${UI}" "" "${BUNDLEBINDIR}/${BASEDIR}" diff --git a/make-macosx-ub.sh b/make-macosx-ub.sh index bd7c9b91..fd472f9b 100755 --- a/make-macosx-ub.sh +++ b/make-macosx-ub.sh @@ -7,7 +7,7 @@ if [ ! -f Makefile ]; then exit 1 fi -# we want to use the oldest available SDK for max compatiblity. However 10.4 and older +# we want to use the oldest available SDK for max compatibility. However 10.4 and older # can not build 64bit binaries, making 10.5 the minimum version. This has been tested # with xcode 3.1 (xcode31_2199_developerdvd.dmg). It contains the 10.5 SDK and a decent # enough gcc to actually compile ioquake3 @@ -15,37 +15,55 @@ fi unset X86_64_SDK unset X86_64_CFLAGS -unset X86_64_LDFLAGS +unset X86_64_MACOSX_VERSION_MIN unset X86_SDK unset X86_CFLAGS -unset X86_LDFLAGS -unset PPC_64_SDK +unset X86_MACOSX_VERSION_MIN +unset PPC_SDK unset PPC_CFLAGS -unset PPC_LDFLAGS +unset PPC_MACOSX_VERSION_MIN if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then X86_64_SDK=/Developer/SDKs/MacOSX10.5.sdk - X86_64_CFLAGS="-arch x86_64 -isysroot /Developer/SDKs/MacOSX10.5.sdk \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1050" - X86_64_LDFLAGS=" -mmacosx-version-min=10.5" + X86_64_CFLAGS="-isysroot /Developer/SDKs/MacOSX10.5.sdk" + X86_64_MACOSX_VERSION_MIN="10.5" X86_SDK=/Developer/SDKs/MacOSX10.5.sdk - X86_CFLAGS="-arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1050" - X86_LDFLAGS=" -mmacosx-version-min=10.5" + X86_CFLAGS="-isysroot /Developer/SDKs/MacOSX10.5.sdk" + X86_MACOSX_VERSION_MIN="10.5" PPC_SDK=/Developer/SDKs/MacOSX10.5.sdk - PPC_CFLAGS="-arch ppc -isysroot /Developer/SDKs/MacOSX10.5.sdk \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1050" - PPC_LDFLAGS=" -mmacosx-version-min=10.5" + PPC_CFLAGS="-isysroot /Developer/SDKs/MacOSX10.5.sdk" + PPC_MACOSX_VERSION_MIN="10.5" fi +# SDL 2.0.5+ (x86, x86_64) only supports MacOSX 10.6 and later +if [ -d /Developer/SDKs/MacOSX10.6.sdk ]; then + X86_64_SDK=/Developer/SDKs/MacOSX10.6.sdk + X86_64_CFLAGS="-isysroot /Developer/SDKs/MacOSX10.6.sdk" + X86_64_MACOSX_VERSION_MIN="10.6" + + X86_SDK=/Developer/SDKs/MacOSX10.6.sdk + X86_CFLAGS="-isysroot /Developer/SDKs/MacOSX10.6.sdk" + X86_MACOSX_VERSION_MIN="10.6" +else + # Don't try to compile with 10.5 version min + X86_64_SDK= + X86_SDK= +fi +# end SDL 2.0.5 + if [ -z $X86_64_SDK ] || [ -z $X86_SDK ] || [ -z $PPC_SDK ]; then echo "\ ERROR: This script is for building a Universal Binary. You cannot build for a different architecture unless you have the proper Mac OS X SDKs installed. If you just want to to compile for your own system run - 'make-macosx.sh' instead of this script." + 'make-macosx.sh' instead of this script. + + In order to build a binary with maximum compatibility you must + build on Mac OS X 10.6 and have the MacOSX10.5 and MacOSX10.6 + SDKs installed from the Xcode install disk Packages folder." + exit 1 fi @@ -54,15 +72,6 @@ echo "Building X86 Client/Dedicated Server against \"$X86_SDK\"" echo "Building PPC Client/Dedicated Server against \"$PPC_SDK\"" echo -if [ "$X86_64_SDK" != "/Developer/SDKs/MacOSX10.5.sdk" ] || \ - [ "$X86_SDK" != "/Developer/SDKs/MacOSX10.5.sdk" ]; then - echo "\ -WARNING: in order to build a binary with maximum compatibility you must - build on Mac OS X 10.5 using Xcode 3.1 and have the MacOSX10.5 - SDKs installed from the Xcode install disk Packages folder." -sleep 3 -fi - # For parallel make on multicore boxes... NCPU=`sysctl -n hw.ncpu` @@ -70,7 +79,7 @@ NCPU=`sysctl -n hw.ncpu` #if [ -d build/release-release-x86_64 ]; then # rm -r build/release-darwin-x86_64 #fi -(ARCH=x86_64 CC=gcc-4.0 CFLAGS=$X86_64_CFLAGS LDFLAGS=$X86_64_LDFLAGS make -j$NCPU) || exit 1; +(ARCH=x86_64 CC=gcc-4.0 CFLAGS=$X86_64_CFLAGS MACOSX_VERSION_MIN=$X86_64_MACOSX_VERSION_MIN make -j$NCPU) || exit 1; echo;echo @@ -78,7 +87,7 @@ echo;echo #if [ -d build/release-darwin-x86 ]; then # rm -r build/release-darwin-x86 #fi -(ARCH=x86 CC=gcc-4.0 CFLAGS=$X86_CFLAGS LDFLAGS=$X86_LDFLAGS make -j$NCPU) || exit 1; +(ARCH=x86 CC=gcc-4.0 CFLAGS=$X86_CFLAGS MACOSX_VERSION_MIN=$X86_MACOSX_VERSION_MIN make -j$NCPU) || exit 1; echo;echo @@ -86,9 +95,13 @@ echo;echo #if [ -d build/release-darwin-ppc ]; then # rm -r build/release-darwin-ppc #fi -(ARCH=ppc CC=gcc-4.0 CFLAGS=$PPC_CFLAGS LDFLAGS=$PPC_LDFLAGS make -j$NCPU) || exit 1; +(ARCH=ppc CC=gcc-4.0 CFLAGS=$PPC_CFLAGS MACOSX_VERSION_MIN=$PPC_MACOSX_VERSION_MIN make -j$NCPU) || exit 1; echo # use the following shell script to build a universal application bundle +export MACOSX_DEPLOYMENT_TARGET="10.5" +export MACOSX_DEPLOYMENT_TARGET_PPC="$PPC_MACOSX_VERSION_MIN" +export MACOSX_DEPLOYMENT_TARGET_X86="$X86_MACOSX_VERSION_MIN" +export MACOSX_DEPLOYMENT_TARGET_X86_64="$X86_64_MACOSX_VERSION_MIN" "./make-macosx-app.sh" release diff --git a/make-macosx.sh b/make-macosx.sh index 035b3998..be1ae774 100644 --- a/make-macosx.sh +++ b/make-macosx.sh @@ -14,7 +14,6 @@ fi if [ "$1" == "x86" ]; then BUILDARCH=x86 - DARWIN_GCC_ARCH=i386 elif [ "$1" == "x86_64" ]; then BUILDARCH=x86_64 elif [ "$1" == "ppc" ]; then @@ -25,10 +24,6 @@ else exit 1 fi -if [ -z "$DARWIN_GCC_ARCH" ]; then - DARWIN_GCC_ARCH=${BUILDARCH} -fi - CC=gcc-4.0 DESTDIR=build/release-darwin-${BUILDARCH} @@ -38,7 +33,7 @@ if [ ! -f Makefile ]; then exit 1 fi -# we want to use the oldest available SDK for max compatiblity. However 10.4 and older +# we want to use the oldest available SDK for max compatibility. However 10.4 and older # can not build 64bit binaries, making 10.5 the minimum version. This has been tested # with xcode 3.1 (xcode31_2199_developerdvd.dmg). It contains the 10.5 SDK and a decent # enough gcc to actually compile ioquake3 @@ -46,13 +41,22 @@ fi unset ARCH_SDK unset ARCH_CFLAGS -unset ARCH_LDFLAGS +unset ARCH_MACOSX_VERSION_MIN -if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then - ARCH_SDK=/Developer/SDKs/MacOSX10.5.sdk - ARCH_CFLAGS="-arch ${DARWIN_GCC_ARCH} -isysroot /Developer/SDKs/MacOSX10.5.sdk \ - -DMAC_OS_X_VERSION_MIN_REQUIRED=1050" - ARCH_LDFLAGS=" -mmacosx-version-min=10.5" +# SDL 2.0.1 (ppc) supports MacOSX 10.5 +# SDL 2.0.5+ (x86, x86_64) supports MacOSX 10.6 and later +if [ $BUILDARCH = "ppc" ]; then + if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then + ARCH_SDK=/Developer/SDKs/MacOSX10.5.sdk + ARCH_CFLAGS="-isysroot /Developer/SDKs/MacOSX10.5.sdk" + fi + ARCH_MACOSX_VERSION_MIN="10.5" +elif [ -d /Developer/SDKs/MacOSX10.6.sdk ]; then + ARCH_SDK=/Developer/SDKs/MacOSX10.6.sdk + ARCH_CFLAGS="-isysroot /Developer/SDKs/MacOSX10.6.sdk" + ARCH_MACOSX_VERSION_MIN="10.6" +else + ARCH_MACOSX_VERSION_MIN="10.7" fi @@ -71,7 +75,11 @@ NCPU=`sysctl -n hw.ncpu` #if [ -d build/release-darwin-${BUILDARCH} ]; then # rm -r build/release-darwin-${BUILDARCH} #fi -(ARCH=${BUILDARCH} CFLAGS=$ARCH_CFLAGS LDFLAGS=$ARCH_LDFLAGS make -j$NCPU) || exit 1; +(ARCH=${BUILDARCH} CFLAGS=$ARCH_CFLAGS MACOSX_VERSION_MIN=$ARCH_MACOSX_VERSION_MIN make -j$NCPU) || exit 1; # use the following shell script to build an application bundle +export MACOSX_DEPLOYMENT_TARGET="${ARCH_MACOSX_VERSION_MIN}" +export MACOSX_DEPLOYMENT_TARGET_PPC= +export MACOSX_DEPLOYMENT_TARGET_X86= +export MACOSX_DEPLOYMENT_TARGET_X86_64= "./make-macosx-app.sh" release ${BUILDARCH} diff --git a/misc/nsis/Makefile b/misc/nsis/Makefile index a79e4e15..3875e4e5 100644 --- a/misc/nsis/Makefile +++ b/misc/nsis/Makefile @@ -4,6 +4,9 @@ endif ifndef RELEASE RELEASE=0 endif +ifndef PLATFORM +PLATFORM=mingw32 +endif ifndef ARCH ARCH=x86 endif @@ -28,8 +31,20 @@ endif ifndef USE_INTERNAL_JPEG USE_INTERNAL_JPEG=1 endif - -SDLDLL=SDL.dll +ifndef SDLDLL + ifeq ($(ARCH),x86_64) + SDLDLL=SDL264.dll + else + SDLDLL=SDL2.dll + endif +endif +ifndef OPENALDLL + ifeq ($(ARCH),x86_64) + OPENALDLL=OpenAL64.dll + else + OPENALDLL=OpenAL32.dll + endif +endif DEFINES= ifeq ($(USE_RENDERER_DLOPEN),1) @@ -55,7 +70,7 @@ endif all: ioquake3-$(VERSION)-$(RELEASE).$(ARCH).exe ioquake3.$(ARCH).nsi: ioquake3.nsi.in - sed 's/XXXVERSIONXXX/$(VERSION)/;s/XXXRELEASEXXX/$(RELEASE)/;s/x86/$(ARCH)/g;s/SDL.dll/$(SDLDLL)/' < $< > $@ + sed 's/XXXVERSIONXXX/$(VERSION)/;s/XXXRELEASEXXX/$(RELEASE)/;s/mingw32/$(PLATFORM)/g;s/x86/$(ARCH)/g;s/SDL2.dll/$(SDLDLL)/g;s/OpenAL32.dll/$(OPENALDLL)/g' < $< > $@ ioquake3-$(VERSION)-$(RELEASE).$(ARCH).exe: ioquake3.$(ARCH).nsi makensis $(DEFINES) ioquake3.$(ARCH).nsi diff --git a/misc/nsis/ioquake3.nsi.in b/misc/nsis/ioquake3.nsi.in index c30391b8..de029e64 100644 --- a/misc/nsis/ioquake3.nsi.in +++ b/misc/nsis/ioquake3.nsi.in @@ -5,7 +5,7 @@ ; This file is used to automatically build the installers in the ; openSUSE build service, don't break this! ; -; you have to copy SDL.dll and OpenAL32.dll here manually +; you have to copy OpenAL32.dll here manually !define MULTIUSER_MUI !define MULTIUSER_EXECUTIONLEVEL Highest @@ -97,7 +97,7 @@ Section "ioquake3 (required)" !endif File "../../COPYING.txt" - File "/oname=README.txt" "../../README" + File "/oname=README.txt" "../../README.md" File "../../id-readme.txt" File "../../voip-readme.txt" @@ -132,11 +132,11 @@ Section "Start Menu Shortcuts" SectionEnd -Section "SDL.dll" +Section "SDL2.dll" SetOutPath $INSTDIR - File "SDL.dll" + File "../../build/release-mingw32-x86/SDL2.dll" SectionEnd @@ -199,7 +199,7 @@ Section "Uninstall" Delete $INSTDIR\jpeg8c.dll !endif - Delete $INSTDIR\SDL.dll + Delete $INSTDIR\SDL2.dll !ifdef USE_OPENAL_DLOPEN Delete $INSTDIR\OpenAL32.dll !endif diff --git a/misc/setup/Solaris_pkg.sh b/misc/setup/Solaris_pkg.sh index 650d2854..306dbcaa 100644 --- a/misc/setup/Solaris_pkg.sh +++ b/misc/setup/Solaris_pkg.sh @@ -11,7 +11,7 @@ fi if [ "X`uname -m`" = "Xi86pc" ]; then - ARCH=i386 + ARCH=x86 else ARCH=sparc fi @@ -94,7 +94,7 @@ if [ -d ${BUILD_DIR} ]; then fi done - for EXEC_SO in cgamesparc.so qagamesparc.so uisparc.so cgamei386.so qagamei386.so uii386.so + for EXEC_SO in cgamesparc.so qagamesparc.so uisparc.so cgamex86.so qagamex86.so uix86.so do if [ -f ${BUILD_DIR}/baseq3/${EXEC_SO} ]; then ${INSTALL_BIN} ${BUILD_DIR}/baseq3/${EXEC_SO} ${PKG_BUILD_DIR}/baseq3/${EXEC_SO} diff --git a/misc/setup/doit b/misc/setup/doit index 2e082ba7..010dc480 100755 --- a/misc/setup/doit +++ b/misc/setup/doit @@ -46,8 +46,8 @@ archs=() for arch in $topdir/build/release-*; do arch=${arch##*-} case "$arch" in - i386) echo "define(HAVE_I386,yes)dnl" >> defines.m4 - copystartscript x86 + x86) echo "define(HAVE_X86,yes)dnl" >> defines.m4 + copystartscript $arch ;; x86_64) echo "define(HAVE_X86_64,yes)dnl" >> defines.m4 copystartscript $arch diff --git a/misc/setup/ioq3demo.sh b/misc/setup/ioq3demo.sh index 05df7ff8..b7102241 100644 --- a/misc/setup/ioq3demo.sh +++ b/misc/setup/ioq3demo.sh @@ -38,8 +38,8 @@ export LD_LIBRARY_PATH archs=`uname -m` case "$archs" in - i?86) archs=i386 ;; - x86_64) archs="x86_64 i386" ;; + i?86) archs=x86 ;; + x86_64) archs="x86_64 x86" ;; ppc64) archs="ppc64 ppc" ;; esac diff --git a/misc/setup/ioquake3.SlackBuild b/misc/setup/ioquake3.SlackBuild index 187d58b5..e48d0d37 100644 --- a/misc/setup/ioquake3.SlackBuild +++ b/misc/setup/ioquake3.SlackBuild @@ -24,9 +24,9 @@ PKG_VERSION=$VERSION ARCH=${ARCH:-i586} if [ "$ARCH" = "i?86" ]; then - ARCHSUFFIX="i386" + ARCHSUFFIX="x86" elif [ "$ARCH" = "x86_64" ]; then - ARCHSUFFIX="64" + ARCHSUFFIX="x86_64" fi BUILD=${BUILD:-1_io} diff --git a/misc/setup/ioquake3.sh b/misc/setup/ioquake3.sh index fbef5676..6ebc4d17 100644 --- a/misc/setup/ioquake3.sh +++ b/misc/setup/ioquake3.sh @@ -38,8 +38,8 @@ export LD_LIBRARY_PATH archs=`uname -m` case "$archs" in - i?86) archs=i386 ;; - x86_64) archs="x86_64 i386" ;; + i?86) archs=x86 ;; + x86_64) archs="x86_64 x86" ;; ppc64) archs="ppc64 ppc" ;; esac diff --git a/misc/setup/pkg/ioq3ded.sh b/misc/setup/pkg/ioq3ded.sh index 511f4fb5..2df63682 100644 --- a/misc/setup/pkg/ioq3ded.sh +++ b/misc/setup/pkg/ioq3ded.sh @@ -13,7 +13,7 @@ fi export LD_LIBRARY_PATH COMPILE_PLATFORM=`uname|sed -e 's/_.*//'|tr '[:upper:]' '[:lower:]'` -COMPILE_ARCH=`uname -p | sed -e 's/i.86/i386/'` +COMPILE_ARCH=`uname -p | sed -e 's/i.86/x86/'` EXEC_REL=release diff --git a/misc/setup/pkg/ioquake3.sh b/misc/setup/pkg/ioquake3.sh index 29a050b7..fdc78160 100644 --- a/misc/setup/pkg/ioquake3.sh +++ b/misc/setup/pkg/ioquake3.sh @@ -13,7 +13,7 @@ fi export LD_LIBRARY_PATH COMPILE_PLATFORM=`uname|sed -e 's/_.*//'|tr '[:upper:]' '[:lower:]'` -COMPILE_ARCH=`uname -p | sed -e 's/i.86/i386/'` +COMPILE_ARCH=`uname -p | sed -e 's/i.86/x86/'` EXEC_REL=release diff --git a/misc/setup/preuninstall.sh b/misc/setup/preuninstall.sh index e6a413d2..c45a331c 100755 --- a/misc/setup/preuninstall.sh +++ b/misc/setup/preuninstall.sh @@ -1,5 +1,5 @@ #!/bin/sh -rmdir --ignore-fail-on-non-empty demoq3 missionpack >& /dev/null +rmdir --ignore-fail-on-non-empty demoq3 missionpack >/dev/null 2>&1 if test -e "$SETUP_INSTALLPATH"/ioquake3.desktop.in; then xdg_desktop_menu=`which xdg-desktop-menu 2>/dev/null` if test "x$xdg_desktop_menu" = x; then diff --git a/misc/setup/setup.xml.in b/misc/setup/setup.xml.in index b8201018..4b076755 100644 --- a/misc/setup/setup.xml.in +++ b/misc/setup/setup.xml.in @@ -24,12 +24,12 @@ ifelse(HAVE_X86_64,yes,dnl you need the binaries to play the game )dnl -ifelse(HAVE_I386,yes,dnl +ifelse(HAVE_X86,yes,dnl diff --git a/opengl2-readme.md b/opengl2-readme.md index d2757d4b..7e572611 100644 --- a/opengl2-readme.md +++ b/opengl2-readme.md @@ -1,4 +1,4 @@ -OpenGL2 +# OpenGL2 OpenGL2 is an alternate renderer for ioquake3. It aims to implement modern @@ -136,7 +136,7 @@ Cvars for HDR and tonemapping: r_hdr, r_postprocess, and r_toneMap. 0 - No. 1 - Yes. (default) - + * `r_forceAutoExposure` - Cheat. Override built-in and map auto exposure settings and use cvars r_forceAutoExposureMin and @@ -230,7 +230,7 @@ Cvars for advanced material usage: Cvars for image interpolation and generation: -* `r_imageUpsample` - Use interpolation to artifically increase +* `r_imageUpsample` - Use interpolation to artificially increase the resolution of all textures. Looks good in certain circumstances. 0 - No. (default) @@ -252,7 +252,7 @@ Cvars for image interpolation and generation: FCBI without second derivatives) 2 - Okay but slow (normal FCBI) -* `r_genNormalMaps* - Naively generate normal maps for all +* `r_genNormalMaps` - Naively generate normal maps for all textures. 0 - Don't. (default) 1 - Do. @@ -264,10 +264,6 @@ Cvars for the sunlight and cascaded shadow maps: 1 - Do. 2 - Sunrise, sunset. -* `r_forceSunMapLightScale` - Cheat. Scale map brightness by this factor - when r_forceSun 1. - 1.0 - Default - * `r_forceSunLightScale` - Cheat. Scale sun brightness by this factor when r_forceSun 1. 1.0 - Default @@ -306,23 +302,6 @@ Cvars for the sunlight and cascaded shadow maps: Cvars that you probably don't care about or shouldn't mess with: -* `r_mergeMultidraws` - Optimize number of calls to - glMultiDrawElements(). - 0 - Don't. - 1 - Do some. (default) - 2 - Do more than necessary (eats CPU). - -* `r_mergeLeafSurfaces` - Merge surfaces that share common materials - and a common leaf. Speeds up rendering. - 0 - Don't. - 1 - Do. (default) - -* `r_recalcMD3Normals` - Recalculate the normals when loading an MD3. - Fixes normal maps in some cases but looks - ugly in others. - 0 - Don't. (default) - 1 - Do. - * `r_depthPrepass` - Do a depth-only pass before rendering. Speeds up rendering in cases where advanced features are used. Required for @@ -398,7 +377,7 @@ The first thing to notice is that this is basically the same as old Quake 3 shader files. The next thing to notice are the new keywords. Here is what they mean: - stage + `stage ` - State how this imagemap will be used by OpenGL2: diffuseMap - Standard, same as no stage entry normalMap - Image will be used as a normal map @@ -407,7 +386,7 @@ they mean: specularMap - Image will be used as a specular map with alpha treated as shininess. - specularReflectance + `specularReflectance ` - State how metallic this material is. Metals typically have a high specular and a low diffuse, so this is typically high for them, and low for other materials, such as plastic. For typical values for various @@ -415,18 +394,18 @@ they mean: down to the reflection calculator and look up its reflectance. Default is 0.04, since most materials aren't metallic. - specularExponent + `specularExponent ` - State how shiny this material is. Note that this is modulated by the alpha channel of the specular map, so if it were set to 16, and the alpha channel of the specular map was set to 0.5, then the shininess would be set to 8. Default 256. - normalScale + `normalScale ` - State the X and Y scales of the normal map. This is useful for increasing or decreasing the "strength" of the normal map, or entering negative values to flip the X and/or Y values. Default 1 1. - parallaxDepth + `parallaxDepth ` - State the maximum depth of the parallax map. This is a fairly sensitive value, and I recommend the default or lower. Default 0.05. @@ -506,8 +485,7 @@ and is the equivalent for 'exactVertex'. This adds a new keyword to sky materials, q3gl2_sun. The syntax is: - q3gl2_sun - + q3gl2_sun Note the first six parameters are the same as in q3map_sun or q3map_sunExt, and the last two indicate scaling factors for the map brightness and an ambient @@ -519,21 +497,21 @@ There are currently two ways to use this in your own (and other people's) maps. 'q3gl2_sun' line after your 'q3map_sun' line in your sky material, like so: - textures/skies/bluesky - { - qer_editorimage textures/skies/bluesky.jpg + textures/skies/bluesky + { + qer_editorimage textures/skies/bluesky.jpg - surfaceparm nomarks - surfaceparm noimpact - surfaceparm nolightmap - surfaceparm sky - q3map_sunExt 240 238 200 100 195 35 3 16 - q3gl2_sun 240 238 200 50 195 35 1.0 0.2 - q3map_skylight 50 16 - q3map_lightimage $whiteimage + surfaceparm nomarks + surfaceparm noimpact + surfaceparm nolightmap + surfaceparm sky + q3map_sunExt 240 238 200 100 195 35 3 16 + q3gl2_sun 240 238 200 50 195 35 0.2 + q3map_skylight 50 16 + q3map_lightimage $whiteimage - skyparms env/bluesky - - - } + skyparms env/bluesky - - + } The advantages with this method are that your map will continue to work with the old renderer with the sunlight baked into the lightmap, and it @@ -543,20 +521,20 @@ There are currently two ways to use this in your own (and other people's) maps. 2. Set r_sunlightMode to 2 and use 'q3gl2_sun' instead of 'q3map_sun' or 'q3map_sunExt', like so: - textures/skies/bluesky - { - qer_editorimage textures/skies/bluesky.jpg + textures/skies/bluesky + { + qer_editorimage textures/skies/bluesky.jpg - surfaceparm nomarks - surfaceparm noimpact - surfaceparm nolightmap - surfaceparm sky - q3gl2_sun 240 238 200 50 195 35 0.5 0.2 - q3map_skylight 50 16 - q3map_lightimage $whiteimage + surfaceparm nomarks + surfaceparm noimpact + surfaceparm nolightmap + surfaceparm sky + q3gl2_sun 240 238 200 50 195 35 0.2 + q3map_skylight 50 16 + q3map_lightimage $whiteimage - skyparms env/bluesky - - - } + skyparms env/bluesky - - + } The advantages with this method are that you don't get the artifacts that characterize the other method, and your map compiles a lot faster without @@ -571,8 +549,7 @@ There are currently two ways to use this in your own (and other people's) maps. This adds a new keyword to sky materials, q3gl2_tonemap. The syntax is: - q3gl2_tonemap - + q3gl2_tonemap Each of these settings corresponds to a matching cvar, so you can view and adjust the effect before settling on fixed settings.