summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2016-04-09 17:57:28 +0100
committerTim Angus <tim@ngus.net>2016-04-09 17:57:28 +0100
commitf45fbef604e05144057dec8d1dbfc5d4f5a2a822 (patch)
tree152d2a428b078f7a89756ea9e156695fc69f1686
parent7f9e97d611b4b267d9dd913144cb9632f96c90c2 (diff)
parent87abdd914988724e164ffb16380ad26be8420b84 (diff)
Merge branch 'master' into gpp
-rw-r--r--.gitignore2
-rw-r--r--Makefile142
-rwxr-xr-xmake-macosx-app.sh2
-rw-r--r--misc/last-merged-ioq3-revision2
-rw-r--r--src/asm/snapvector.asm4
-rw-r--r--src/client/cl_avi.c11
-rw-r--r--src/client/cl_cgame.c36
-rw-r--r--src/client/cl_cin.c4
-rw-r--r--src/client/cl_curl.c74
-rw-r--r--src/client/cl_input.c14
-rw-r--r--src/client/cl_main.c234
-rw-r--r--src/client/cl_parse.c105
-rw-r--r--src/client/client.h21
-rw-r--r--src/client/snd_openal.c8
-rw-r--r--src/qcommon/cm_patch.c16
-rw-r--r--src/qcommon/cmd.c8
-rw-r--r--src/qcommon/common.c174
-rw-r--r--src/qcommon/cvar.c3
-rw-r--r--src/qcommon/files.c9
-rw-r--r--src/qcommon/json.h353
-rw-r--r--src/qcommon/q_platform.h39
-rw-r--r--src/qcommon/q_shared.c2
-rw-r--r--src/qcommon/qcommon.h11
-rw-r--r--src/qcommon/vm_x86.c20
-rw-r--r--src/renderercommon/qgl.h57
-rw-r--r--src/renderercommon/tr_common.h14
-rw-r--r--src/renderercommon/tr_image_jpg.c59
-rw-r--r--src/renderergl1/tr_backend.c2
-rw-r--r--src/renderergl1/tr_cmds.c21
-rw-r--r--src/renderergl1/tr_image.c10
-rw-r--r--src/renderergl1/tr_light.c8
-rw-r--r--src/renderergl1/tr_local.h14
-rw-r--r--src/renderergl1/tr_main.c22
-rw-r--r--src/renderergl1/tr_shader.c17
-rw-r--r--src/renderergl2/glsl/calclevels4x_fp.glsl4
-rw-r--r--src/renderergl2/glsl/depthblur_fp.glsl76
-rw-r--r--src/renderergl2/glsl/depthblur_vp.glsl6
-rw-r--r--src/renderergl2/glsl/lightall_fp.glsl342
-rw-r--r--src/renderergl2/glsl/lightall_vp.glsl21
-rw-r--r--src/renderergl2/glsl/ssao_fp.glsl54
-rw-r--r--src/renderergl2/glsl/tonemap_fp.glsl11
-rw-r--r--src/renderergl2/tr_backend.c439
-rw-r--r--src/renderergl2/tr_bsp.c166
-rw-r--r--src/renderergl2/tr_cmds.c21
-rw-r--r--src/renderergl2/tr_dsa.c287
-rw-r--r--src/renderergl2/tr_dsa.h80
-rw-r--r--src/renderergl2/tr_extensions.c135
-rw-r--r--src/renderergl2/tr_fbo.c461
-rw-r--r--src/renderergl2/tr_fbo.h3
-rw-r--r--src/renderergl2/tr_glsl.c161
-rw-r--r--src/renderergl2/tr_image.c894
-rw-r--r--src/renderergl2/tr_image_dds.c498
-rw-r--r--src/renderergl2/tr_init.c77
-rw-r--r--src/renderergl2/tr_light.c14
-rw-r--r--src/renderergl2/tr_local.h62
-rw-r--r--src/renderergl2/tr_main.c36
-rw-r--r--src/renderergl2/tr_postprocess.c120
-rw-r--r--src/renderergl2/tr_scene.c21
-rw-r--r--src/renderergl2/tr_shade.c144
-rw-r--r--src/renderergl2/tr_shader.c135
-rw-r--r--src/renderergl2/tr_shadows.c4
-rw-r--r--src/renderergl2/tr_sky.c2
-rw-r--r--src/renderergl2/tr_surface.c4
-rw-r--r--src/sdl/sdl_gamma.c5
-rw-r--r--src/sdl/sdl_glimp.c42
-rw-r--r--src/sdl/sdl_input.c10
-rw-r--r--src/sdl/sdl_snd.c2
-rw-r--r--src/server/server.h3
-rw-r--r--src/server/sv_client.c22
-rw-r--r--src/server/sv_init.c3
-rw-r--r--src/server/sv_main.c5
-rw-r--r--src/server/sv_snapshot.c2
-rw-r--r--src/sys/sys_main.c10
-rw-r--r--src/sys/sys_unix.c4
-rw-r--r--src/sys/sys_win32.c11
-rw-r--r--src/tools/lcc/cpp/unix.c3
76 files changed, 3762 insertions, 2156 deletions
diff --git a/.gitignore b/.gitignore
index cf567edb..ecb8d2c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,3 +38,5 @@ profile
# Microsoft Visual Studio
####################
*.sdf
+*.opensdf
+*.suo
diff --git a/Makefile b/Makefile
index 2112370e..9ab4227a 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@
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/)
+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
@@ -55,6 +55,13 @@ PLATFORM=$(COMPILE_PLATFORM)
endif
export PLATFORM
+ifeq ($(PLATFORM),mingw32)
+ MINGW=1
+endif
+ifeq ($(PLATFORM),mingw64)
+ MINGW=1
+endif
+
ifeq ($(COMPILE_ARCH),i86pc)
COMPILE_ARCH=x86
endif
@@ -150,7 +157,7 @@ USE_CURL=1
endif
ifndef USE_CURL_DLOPEN
- ifeq ($(PLATFORM),mingw32)
+ ifdef MINGW
USE_CURL_DLOPEN=0
else
USE_CURL_DLOPEN=1
@@ -181,10 +188,6 @@ ifndef USE_INTERNAL_LIBS
USE_INTERNAL_LIBS=1
endif
-ifndef USE_INTERNAL_SPEEX
-USE_INTERNAL_SPEEX=$(USE_INTERNAL_LIBS)
-endif
-
ifndef USE_INTERNAL_OGG
USE_INTERNAL_OGG=$(USE_INTERNAL_LIBS)
endif
@@ -239,7 +242,6 @@ CGDIR=$(MOUNT_DIR)/cgame
NDIR=$(MOUNT_DIR)/null
UIDIR=$(MOUNT_DIR)/ui
JPDIR=$(MOUNT_DIR)/jpeg-8c
-SPEEXDIR=$(MOUNT_DIR)/libspeex
OGGDIR=$(MOUNT_DIR)/libogg-1.3.1
VORBISDIR=$(MOUNT_DIR)/libvorbis-1.3.4
OPUSDIR=$(MOUNT_DIR)/opus-1.1
@@ -297,30 +299,18 @@ endif
# SETUP AND BUILD -- LINUX
#############################################################################
-## Defaults
-LIB=lib
-
INSTALL=install
MKDIR=mkdir
EXTRA_FILES=
CLIENT_EXTRA_FILES=
-ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu"))
-
- ifeq ($(ARCH),x86_64)
- LIB=lib64
- else
- ifeq ($(ARCH),ppc64)
- LIB=lib64
- else
- ifeq ($(ARCH),s390x)
- LIB=lib64
- endif
- endif
- endif
+ifneq (,$(findstring "$(COMPILE_PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu"))
+ TOOLS_CFLAGS += -DARCH_STRING=\"$(COMPILE_ARCH)\"
+endif
+ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu" "gnu"))
BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \
- -pipe -DUSE_ICON
+ -pipe -DUSE_ICON -DARCH_STRING=\\\"$(ARCH)\\\"
CLIENT_CFLAGS += $(SDL_CFLAGS)
OPTIMIZEVM = -O3
@@ -493,7 +483,7 @@ else # ifeq darwin
# SETUP AND BUILD -- MINGW32
#############################################################################
-ifeq ($(PLATFORM),mingw32)
+ifdef MINGW
ifeq ($(CROSS_COMPILING),1)
# If CC is already set to something generic, we probably want to use
@@ -507,7 +497,7 @@ ifeq ($(PLATFORM),mingw32)
MINGW_PREFIXES=amd64-mingw32msvc x86_64-w64-mingw32
endif
ifeq ($(ARCH),x86)
- MINGW_PREFIXES=i586-mingw32msvc i686-w64-mingw32
+ MINGW_PREFIXES=i586-mingw32msvc i686-w64-mingw32 i686-pc-mingw32
endif
ifndef CC
@@ -639,7 +629,7 @@ ifeq ($(PLATFORM),mingw32)
SDLDLL=SDL2.dll
endif
-else # ifeq mingw32
+else # ifdef MINGW
#############################################################################
# SETUP AND BUILD -- FREEBSD
@@ -800,6 +790,7 @@ else # ifeq netbsd
#############################################################################
ifeq ($(PLATFORM),irix64)
+ LIB=lib
ARCH=mips
@@ -890,7 +881,7 @@ else # ifeq sunos
endif #Linux
endif #darwin
-endif #mingw32
+endif #MINGW
endif #FreeBSD
endif #OpenBSD
endif #NetBSD
@@ -966,8 +957,18 @@ ifeq ($(USE_CURL),1)
endif
endif
+ifeq ($(USE_VOIP),1)
+ CLIENT_CFLAGS += -DUSE_VOIP
+ SERVER_CFLAGS += -DUSE_VOIP
+ NEED_OPUS=1
+endif
+
ifeq ($(USE_CODEC_OPUS),1)
CLIENT_CFLAGS += -DUSE_CODEC_OPUS
+ NEED_OPUS=1
+endif
+
+ifeq ($(NEED_OPUS),1)
ifeq ($(USE_INTERNAL_OPUS),1)
OPUS_CFLAGS = -DOPUS_BUILD -DHAVE_LRINTF -DFLOATING_POINT -DUSE_ALLOCA \
-I$(OPUSDIR)/include -I$(OPUSDIR)/celt -I$(OPUSDIR)/silk \
@@ -1013,19 +1014,6 @@ ifeq ($(USE_MUMBLE),1)
CLIENT_CFLAGS += -DUSE_MUMBLE
endif
-ifeq ($(USE_VOIP),1)
- CLIENT_CFLAGS += -DUSE_VOIP
- SERVER_CFLAGS += -DUSE_VOIP
- ifeq ($(USE_INTERNAL_SPEEX),1)
- SPEEX_CFLAGS += -DFLOATING_POINT -DUSE_ALLOCA -I$(SPEEXDIR)/include
- else
- SPEEX_CFLAGS ?= $(shell pkg-config --silence-errors --cflags speex speexdsp || true)
- SPEEX_LIBS ?= $(shell pkg-config --silence-errors --libs speex speexdsp || echo -lspeex -lspeexdsp)
- endif
- CLIENT_CFLAGS += $(SPEEX_CFLAGS)
- CLIENT_LIBS += $(SPEEX_LIBS)
-endif
-
ifeq ($(USE_INTERNAL_ZLIB),1)
ZLIB_CFLAGS = -DNO_GZIP -I$(ZDIR)
else
@@ -1183,7 +1171,7 @@ ifeq ($(BUILD_MASTER_SERVER),1)
endif
ifneq ($(call bin_path, tput),)
- TERM_COLUMNS=$(shell echo $$((`tput cols`-4)))
+ TERM_COLUMNS=$(shell if c=`tput cols`; then echo $$(($$c-4)); else echo 76; fi)
else
TERM_COLUMNS=76
endif
@@ -1213,7 +1201,7 @@ endif
NAKED_TARGETS=$(shell echo $(TARGETS) | sed -e "s!$(B)/!!g")
-print_list=@for i in $(1); \
+print_list=-@for i in $(1); \
do \
echo " $$i"; \
done
@@ -1536,7 +1524,7 @@ Q3OBJ = \
$(B)/client/con_log.o \
$(B)/client/sys_main.o
-ifeq ($(PLATFORM),mingw32)
+ifdef MINGW
Q3OBJ += \
$(B)/client/con_passive.o
else
@@ -1550,6 +1538,7 @@ Q3R2OBJ = \
$(B)/renderergl2/tr_bsp.o \
$(B)/renderergl2/tr_cmds.o \
$(B)/renderergl2/tr_curve.o \
+ $(B)/renderergl2/tr_dsa.o \
$(B)/renderergl2/tr_extramath.o \
$(B)/renderergl2/tr_extensions.o \
$(B)/renderergl2/tr_fbo.o \
@@ -1557,11 +1546,12 @@ Q3R2OBJ = \
$(B)/renderergl2/tr_font.o \
$(B)/renderergl2/tr_glsl.o \
$(B)/renderergl2/tr_image.o \
- $(B)/renderergl2/tr_image_png.o \
- $(B)/renderergl2/tr_image_jpg.o \
$(B)/renderergl2/tr_image_bmp.o \
- $(B)/renderergl2/tr_image_tga.o \
+ $(B)/renderergl2/tr_image_jpg.o \
$(B)/renderergl2/tr_image_pcx.o \
+ $(B)/renderergl2/tr_image_png.o \
+ $(B)/renderergl2/tr_image_tga.o \
+ $(B)/renderergl2/tr_image_dds.o \
$(B)/renderergl2/tr_init.o \
$(B)/renderergl2/tr_light.o \
$(B)/renderergl2/tr_main.o \
@@ -1623,11 +1613,11 @@ Q3ROBJ = \
$(B)/renderergl1/tr_flares.o \
$(B)/renderergl1/tr_font.o \
$(B)/renderergl1/tr_image.o \
- $(B)/renderergl1/tr_image_png.o \
- $(B)/renderergl1/tr_image_jpg.o \
$(B)/renderergl1/tr_image_bmp.o \
- $(B)/renderergl1/tr_image_tga.o \
+ $(B)/renderergl1/tr_image_jpg.o \
$(B)/renderergl1/tr_image_pcx.o \
+ $(B)/renderergl1/tr_image_png.o \
+ $(B)/renderergl1/tr_image_tga.o \
$(B)/renderergl1/tr_init.o \
$(B)/renderergl1/tr_light.o \
$(B)/renderergl1/tr_main.o \
@@ -1725,53 +1715,7 @@ ifeq ($(ARCH),x86_64)
$(B)/client/ftola.o
endif
-ifeq ($(USE_VOIP),1)
-ifeq ($(USE_INTERNAL_SPEEX),1)
-Q3OBJ += \
- $(B)/client/bits.o \
- $(B)/client/buffer.o \
- $(B)/client/cb_search.o \
- $(B)/client/exc_10_16_table.o \
- $(B)/client/exc_10_32_table.o \
- $(B)/client/exc_20_32_table.o \
- $(B)/client/exc_5_256_table.o \
- $(B)/client/exc_5_64_table.o \
- $(B)/client/exc_8_128_table.o \
- $(B)/client/fftwrap.o \
- $(B)/client/filterbank.o \
- $(B)/client/filters.o \
- $(B)/client/gain_table.o \
- $(B)/client/gain_table_lbr.o \
- $(B)/client/hexc_10_32_table.o \
- $(B)/client/hexc_table.o \
- $(B)/client/high_lsp_tables.o \
- $(B)/client/jitter.o \
- $(B)/client/kiss_fft.o \
- $(B)/client/kiss_fftr.o \
- $(B)/client/lpc.o \
- $(B)/client/lsp.o \
- $(B)/client/lsp_tables_nb.o \
- $(B)/client/ltp.o \
- $(B)/client/mdf.o \
- $(B)/client/modes.o \
- $(B)/client/modes_wb.o \
- $(B)/client/nb_celp.o \
- $(B)/client/preprocess.o \
- $(B)/client/quant_lsp.o \
- $(B)/client/resample.o \
- $(B)/client/sb_celp.o \
- $(B)/client/smallft.o \
- $(B)/client/speex.o \
- $(B)/client/speex_callbacks.o \
- $(B)/client/speex_header.o \
- $(B)/client/stereo.o \
- $(B)/client/vbr.o \
- $(B)/client/vq.o \
- $(B)/client/window.o
-endif
-endif
-
-ifeq ($(USE_CODEC_OPUS),1)
+ifeq ($(NEED_OPUS),1)
ifeq ($(USE_INTERNAL_OPUS),1)
Q3OBJ += \
$(B)/client/opus/analysis.o \
@@ -1980,7 +1924,7 @@ ifeq ($(HAVE_VM_COMPILED),true)
endif
endif
-ifeq ($(PLATFORM),mingw32)
+ifdef MINGW
Q3OBJ += \
$(B)/client/win_resource.o \
$(B)/client/sys_win32.o
@@ -2119,7 +2063,7 @@ ifeq ($(HAVE_VM_COMPILED),true)
endif
endif
-ifeq ($(PLATFORM),mingw32)
+ifdef MINGW
Q3DOBJ += \
$(B)/ded/win_resource.o \
$(B)/ded/sys_win32.o \
diff --git a/make-macosx-app.sh b/make-macosx-app.sh
index 13f6f70d..cea20967 100755
--- a/make-macosx-app.sh
+++ b/make-macosx-app.sh
@@ -42,7 +42,7 @@ if [ "$2" != "" ]; then
elif [ "$2" == "ppc" ]; then
CURRENT_ARCH="ppc"
else
- echo "Invalid architecture: $1"
+ echo "Invalid architecture: $2"
echo "Valid architectures are:"
echo " x86"
echo " x86_64"
diff --git a/misc/last-merged-ioq3-revision b/misc/last-merged-ioq3-revision
index cc9c1499..4cdf56c4 100644
--- a/misc/last-merged-ioq3-revision
+++ b/misc/last-merged-ioq3-revision
@@ -1 +1 @@
-708fe6937a7bf4a838766d1c3a07552160ab4f1e
+1f6703821f11be9c711c6ee42371ab290dd12776
diff --git a/src/asm/snapvector.asm b/src/asm/snapvector.asm
index 2836d4a8..59949f0f 100644
--- a/src/asm/snapvector.asm
+++ b/src/asm/snapvector.asm
@@ -36,10 +36,6 @@ ENDIF
ssemask DWORD 0FFFFFFFFh, 0FFFFFFFFh, 0FFFFFFFFh, 00000000h
ssecw DWORD 00001F80h
-IFNDEF idx64
- fpucw WORD 037Fh
-ENDIF
-
.code
IFDEF idx64
diff --git a/src/client/cl_avi.c b/src/client/cl_avi.c
index 723fbfa4..e4593923 100644
--- a/src/client/cl_avi.c
+++ b/src/client/cl_avi.c
@@ -124,17 +124,6 @@ static ID_INLINE void WRITE_2BYTES( int x )
/*
===============
-WRITE_1BYTES
-===============
-*/
-static ID_INLINE void WRITE_1BYTES( int x )
-{
- buffer[ bufIndex ] = x;
- bufIndex += 1;
-}
-
-/*
-===============
START_CHUNK
===============
*/
diff --git a/src/client/cl_cgame.c b/src/client/cl_cgame.c
index 1c7d91cc..23f3010c 100644
--- a/src/client/cl_cgame.c
+++ b/src/client/cl_cgame.c
@@ -956,37 +956,27 @@ void CL_FirstSnapshot( void ) {
#endif
#ifdef USE_VOIP
- if (!clc.speexInitialized) {
+ if (!clc.voipCodecInitialized) {
int i;
- speex_bits_init(&clc.speexEncoderBits);
- speex_bits_reset(&clc.speexEncoderBits);
+ int error;
- clc.speexEncoder = speex_encoder_init(&speex_nb_mode);
+ clc.opusEncoder = opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, &error);
- speex_encoder_ctl(clc.speexEncoder, SPEEX_GET_FRAME_SIZE,
- &clc.speexFrameSize);
- speex_encoder_ctl(clc.speexEncoder, SPEEX_GET_SAMPLING_RATE,
- &clc.speexSampleRate);
-
- clc.speexPreprocessor = speex_preprocess_state_init(clc.speexFrameSize,
- clc.speexSampleRate);
-
- i = 1;
- speex_preprocess_ctl(clc.speexPreprocessor,
- SPEEX_PREPROCESS_SET_DENOISE, &i);
-
- i = 1;
- speex_preprocess_ctl(clc.speexPreprocessor,
- SPEEX_PREPROCESS_SET_AGC, &i);
+ if ( error ) {
+ Com_DPrintf("VoIP: Error opus_encoder_create %d\n", error);
+ return;
+ }
for (i = 0; i < MAX_CLIENTS; i++) {
- speex_bits_init(&clc.speexDecoderBits[i]);
- speex_bits_reset(&clc.speexDecoderBits[i]);
- clc.speexDecoder[i] = speex_decoder_init(&speex_nb_mode);
+ clc.opusDecoder[i] = opus_decoder_create(48000, 1, &error);
+ if ( error ) {
+ Com_DPrintf("VoIP: Error opus_decoder_create(%d) %d\n", i, error);
+ return;
+ }
clc.voipIgnore[i] = qfalse;
clc.voipGain[i] = 1.0f;
}
- clc.speexInitialized = qtrue;
+ clc.voipCodecInitialized = qtrue;
clc.voipMuteAll = qfalse;
Cmd_AddCommand ("voip", CL_Voip_f);
Cvar_Set("cl_voipSendTarget", "spatial");
diff --git a/src/client/cl_cin.c b/src/client/cl_cin.c
index 78a237ed..74660ed5 100644
--- a/src/client/cl_cin.c
+++ b/src/client/cl_cin.c
@@ -95,8 +95,8 @@ typedef struct {
qboolean looping, holdAtEnd, dirty, alterGameState, silent, shader;
fileHandle_t iFile;
e_status status;
- unsigned int startTime;
- unsigned int lastTime;
+ int startTime;
+ int lastTime;
long tfps;
long RoQPlayed;
long ROQSize;
diff --git a/src/client/cl_curl.c b/src/client/cl_curl.c
index 8d083877..166fb1dc 100644
--- a/src/client/cl_curl.c
+++ b/src/client/cl_curl.c
@@ -178,12 +178,20 @@ void CL_cURL_Shutdown( void )
void CL_cURL_Cleanup(void)
{
if(clc.downloadCURLM) {
+ CURLMcode result;
+
if(clc.downloadCURL) {
- qcurl_multi_remove_handle(clc.downloadCURLM,
+ result = qcurl_multi_remove_handle(clc.downloadCURLM,
clc.downloadCURL);
+ if(result != CURLM_OK) {
+ Com_DPrintf("qcurl_multi_remove_handle failed: %s\n", qcurl_multi_strerror(result));
+ }
qcurl_easy_cleanup(clc.downloadCURL);
}
- qcurl_multi_cleanup(clc.downloadCURLM);
+ result = qcurl_multi_cleanup(clc.downloadCURLM);
+ if(result != CURLM_OK) {
+ Com_DPrintf("CL_cURL_Cleanup: qcurl_multi_cleanup failed: %s\n", qcurl_multi_strerror(result));
+ }
clc.downloadCURLM = NULL;
clc.downloadCURL = NULL;
}
@@ -210,8 +218,36 @@ static size_t CL_cURL_CallbackWrite(void *buffer, size_t size, size_t nmemb,
return size*nmemb;
}
+CURLcode qcurl_easy_setopt_warn(CURL *curl, CURLoption option, ...)
+{
+ CURLcode result;
+
+ va_list argp;
+ va_start(argp, option);
+
+ if(option < CURLOPTTYPE_OBJECTPOINT) {
+ long longValue = va_arg(argp, long);
+ result = qcurl_easy_setopt(curl, option, longValue);
+ } else if(option < CURLOPTTYPE_OFF_T) {
+ void *pointerValue = va_arg(argp, void *);
+ result = qcurl_easy_setopt(curl, option, pointerValue);
+ } else {
+ curl_off_t offsetValue = va_arg(argp, curl_off_t);
+ result = qcurl_easy_setopt(curl, option, offsetValue);
+ }
+
+ if(result != CURLE_OK) {
+ Com_DPrintf("qcurl_easy_setopt failed: %s\n", qcurl_easy_strerror(result));
+ }
+ va_end(argp);
+
+ return result;
+}
+
void CL_cURL_BeginDownload( const char *localName, const char *remoteURL )
{
+ CURLMcode result;
+
clc.cURLUsed = qtrue;
Com_Printf("URL: %s\n", remoteURL);
Com_DPrintf("***** CL_cURL_BeginDownload *****\n"
@@ -247,23 +283,23 @@ void CL_cURL_BeginDownload( const char *localName, const char *remoteURL )
}
if(com_developer->integer)
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_VERBOSE, 1);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_URL, clc.downloadURL);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_TRANSFERTEXT, 0);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_REFERER,
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_VERBOSE, 1);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_URL, clc.downloadURL);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_TRANSFERTEXT, 0);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_REFERER,
va("Tremulous://%s", NET_AdrToString(clc.serverAddress)));
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_USERAGENT, va("%s %s",
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_USERAGENT, va("%s %s",
Q3_VERSION, qcurl_version()));
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEFUNCTION,
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_WRITEFUNCTION,
CL_cURL_CallbackWrite);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_WRITEDATA, &clc.download);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_NOPROGRESS, 0);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSFUNCTION,
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_WRITEDATA, &clc.download);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_NOPROGRESS, 0);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_PROGRESSFUNCTION,
CL_cURL_CallbackProgress);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_PROGRESSDATA, NULL);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_FAILONERROR, 1);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_FOLLOWLOCATION, 1);
- qcurl_easy_setopt(clc.downloadCURL, CURLOPT_MAXREDIRS, 5);
+ qcurl_easy_setopt_warn(clc.downloadCURL, CURLOPT_PROGRESSDATA, NULL);
+ 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);
clc.downloadCURLM = qcurl_multi_init();
if(!clc.downloadCURLM) {
qcurl_easy_cleanup(clc.downloadCURL);
@@ -272,7 +308,13 @@ void CL_cURL_BeginDownload( const char *localName, const char *remoteURL )
"failed");
return;
}
- qcurl_multi_add_handle(clc.downloadCURLM, clc.downloadCURL);
+ result = qcurl_multi_add_handle(clc.downloadCURLM, clc.downloadCURL);
+ if(result != CURLM_OK) {
+ qcurl_easy_cleanup(clc.downloadCURL);
+ clc.downloadCURL = NULL;
+ Com_Error(ERR_DROP,"CL_cURL_BeginDownload: qcurl_multi_add_handle() failed: %s", qcurl_multi_strerror(result));
+ return;
+ }
if(!(clc.sv_allowDownload & DLF_NO_DISCONNECT) &&
!clc.cURLDisconnected) {
diff --git a/src/client/cl_input.c b/src/client/cl_input.c
index e09d7d75..7a917df2 100644
--- a/src/client/cl_input.c
+++ b/src/client/cl_input.c
@@ -605,10 +605,10 @@ usercmd_t CL_CreateCmd( void ) {
// draw debug graphs of turning for mouse testing
if ( cl_debugMove->integer ) {
if ( cl_debugMove->integer == 1 ) {
- SCR_DebugGraph( abs(cl.viewangles[YAW] - oldAngles[YAW]) );
+ SCR_DebugGraph( fabs(cl.viewangles[YAW] - oldAngles[YAW]) );
}
if ( cl_debugMove->integer == 2 ) {
- SCR_DebugGraph( abs(cl.viewangles[PITCH] - oldAngles[PITCH]) );
+ SCR_DebugGraph( fabs(cl.viewangles[PITCH] - oldAngles[PITCH]) );
}
}
@@ -633,6 +633,12 @@ void CL_CreateNewCommands( void ) {
frame_msec = com_frameTime - old_com_frameTime;
+ // if running over 1000fps, act as if each frame is 1ms
+ // prevents divisions by zero
+ if ( frame_msec < 1 ) {
+ frame_msec = 1;
+ }
+
// if running less than 5fps, truncate the extra time to prevent
// unexpected moves after a hitch
if ( frame_msec > 200 ) {
@@ -789,7 +795,7 @@ void CL_WritePacket( void ) {
{
if((clc.voipFlags & VOIP_SPATIAL) || Com_IsVoipTarget(clc.voipTargets, sizeof(clc.voipTargets), -1))
{
- MSG_WriteByte (&buf, clc_voip);
+ MSG_WriteByte (&buf, clc_voipOpus);
MSG_WriteByte (&buf, clc.voipOutgoingGeneration);
MSG_WriteLong (&buf, clc.voipOutgoingSequence);
MSG_WriteByte (&buf, clc.voipOutgoingDataFrames);
@@ -810,7 +816,7 @@ void CL_WritePacket( void ) {
MSG_Init (&fakemsg, fakedata, sizeof (fakedata));
MSG_Bitstream (&fakemsg);
MSG_WriteLong (&fakemsg, clc.reliableAcknowledge);
- MSG_WriteByte (&fakemsg, svc_voip);
+ MSG_WriteByte (&fakemsg, svc_voipOpus);
MSG_WriteShort (&fakemsg, clc.clientNum);
MSG_WriteByte (&fakemsg, clc.voipOutgoingGeneration);
MSG_WriteLong (&fakemsg, clc.voipOutgoingSequence);
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index 34eb95af..dc177cf7 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -45,6 +45,7 @@ cvar_t *cl_voipSendTarget;
cvar_t *cl_voipGainDuringCapture;
cvar_t *cl_voipCaptureMult;
cvar_t *cl_voipShowMeter;
+cvar_t *cl_voipProtocol;
cvar_t *cl_voip;
#endif
@@ -149,7 +150,6 @@ typedef struct serverStatus_s
} serverStatus_t;
serverStatus_t cl_serverStatusList[MAX_SERVERSTATUSREQUESTS];
-int serverStatusCount;
#if defined __USEA3D && defined __A3D_GEOM
void hA3Dg_ExportRenderGeom (refexport_t *incoming_re);
@@ -251,8 +251,8 @@ void CL_Voip_f( void )
if (clc.state != CA_ACTIVE)
reason = "Not connected to a server";
- else if (!clc.speexInitialized)
- reason = "Speex not initialized";
+ else if (!clc.voipCodecInitialized)
+ reason = "Voip codec not initialized";
else if (!clc.voipEnabled)
reason = "Server doesn't support VoIP";
@@ -305,6 +305,8 @@ void CL_VoipNewGeneration(void)
clc.voipOutgoingGeneration = 1;
clc.voipPower = 0.0f;
clc.voipOutgoingSequence = 0;
+
+ opus_encoder_ctl(clc.opusEncoder, OPUS_RESET_STATE);
}
/*
@@ -393,7 +395,7 @@ void CL_VoipParseTargets(void)
===============
CL_CaptureVoip
-Record more audio from the hardware if required and encode it into Speex
+Record more audio from the hardware if required and encode it into Opus
data for later transmission.
===============
*/
@@ -423,11 +425,12 @@ void CL_CaptureVoip(void)
Com_Printf("Until then, VoIP is disabled.\n");
Cvar_Set("cl_voip", "0");
}
+ Cvar_Set("cl_voipProtocol", cl_voip->integer ? "opus" : "");
cl_voip->modified = qfalse;
cl_rate->modified = qfalse;
}
- if (!clc.speexInitialized)
+ if (!clc.voipCodecInitialized)
return; // just in case this gets called at a bad time.
if (clc.voipOutgoingDataSize > 0)
@@ -480,80 +483,67 @@ void CL_CaptureVoip(void)
if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio?
int samples = S_AvailableCaptureSamples();
- const int mult = (finalFrame) ? 1 : 4; // 4 == 80ms of audio.
+ const int packetSamples = (finalFrame) ? VOIP_MAX_FRAME_SAMPLES : VOIP_MAX_PACKET_SAMPLES;
// enough data buffered in audio hardware to process yet?
- if (samples >= (clc.speexFrameSize * mult)) {
- // audio capture is always MONO16 (and that's what speex wants!).
- // 2048 will cover 12 uncompressed frames in narrowband mode.
- static int16_t sampbuffer[2048];
+ if (samples >= packetSamples) {
+ // audio capture is always MONO16.
+ static int16_t sampbuffer[VOIP_MAX_PACKET_SAMPLES];
float voipPower = 0.0f;
- int speexFrames = 0;
- int wpos = 0;
- int pos = 0;
+ int voipFrames;
+ int i, bytes;
- if (samples > (clc.speexFrameSize * 4))
- samples = (clc.speexFrameSize * 4);
+ if (samples > VOIP_MAX_PACKET_SAMPLES)
+ samples = VOIP_MAX_PACKET_SAMPLES;
// !!! FIXME: maybe separate recording from encoding, so voipPower
// !!! FIXME: updates faster than 4Hz?
- samples -= samples % clc.speexFrameSize;
- S_Capture(samples, (byte *) sampbuffer); // grab from audio card.
-
- // this will probably generate multiple speex packets each time.
- while (samples > 0) {
- int16_t *sampptr = &sampbuffer[pos];
- int i, bytes;
+ samples -= samples % VOIP_MAX_FRAME_SAMPLES;
+ if (samples != 120 && samples != 240 && samples != 480 && samples != 960 && samples != 1920 && samples != 2880 ) {
+ Com_Printf("Voip: bad number of samples %d\n", samples);
+ return;
+ }
+ voipFrames = samples / VOIP_MAX_FRAME_SAMPLES;
- // preprocess samples to remove noise...
- speex_preprocess_run(clc.speexPreprocessor, sampptr);
+ S_Capture(samples, (byte *) sampbuffer); // grab from audio card.
- // check the "power" of this packet...
- for (i = 0; i < clc.speexFrameSize; i++) {
- const float flsamp = (float) sampptr[i];
- const float s = fabs(flsamp);
- voipPower += s * s;
- sampptr[i] = (int16_t) ((flsamp) * audioMult);
- }
+ // check the "power" of this packet...
+ for (i = 0; i < samples; i++) {
+ const float flsamp = (float) sampbuffer[i];
+ const float s = fabs(flsamp);
+ voipPower += s * s;
+ sampbuffer[i] = (int16_t) ((flsamp) * audioMult);
+ }
- // encode raw audio samples into Speex data...
- speex_bits_reset(&clc.speexEncoderBits);
- speex_encode_int(clc.speexEncoder, sampptr,
- &clc.speexEncoderBits);
- bytes = speex_bits_write(&clc.speexEncoderBits,
- (char *) &clc.voipOutgoingData[wpos+1],
- sizeof (clc.voipOutgoingData) - (wpos+1));
- assert((bytes > 0) && (bytes < 256));
- clc.voipOutgoingData[wpos] = (byte) bytes;
- wpos += bytes + 1;
-
- // look at the data for the next packet...
- pos += clc.speexFrameSize;
- samples -= clc.speexFrameSize;
- speexFrames++;
+ // encode raw audio samples into Opus data...
+ bytes = opus_encode(clc.opusEncoder, sampbuffer, samples,
+ (unsigned char *) clc.voipOutgoingData,
+ sizeof (clc.voipOutgoingData));
+ if ( bytes <= 0 ) {
+ Com_DPrintf("VoIP: Error encoding %d samples\n", samples);
+ bytes = 0;
}
clc.voipPower = (voipPower / (32768.0f * 32768.0f *
- ((float) (clc.speexFrameSize * speexFrames)))) *
- 100.0f;
+ ((float) samples))) * 100.0f;
if ((useVad) && (clc.voipPower < cl_voipVADThreshold->value)) {
CL_VoipNewGeneration(); // no "talk" for at least 1/4 second.
} else {
- clc.voipOutgoingDataSize = wpos;
- clc.voipOutgoingDataFrames = speexFrames;
+ clc.voipOutgoingDataSize = bytes;
+ clc.voipOutgoingDataFrames = voipFrames;
Com_DPrintf("VoIP: Send %d frames, %d bytes, %f power\n",
- speexFrames, wpos, clc.voipPower);
+ voipFrames, bytes, clc.voipPower);
#if 0
static FILE *encio = NULL;
if (encio == NULL) encio = fopen("voip-outgoing-encoded.bin", "wb");
- if (encio != NULL) { fwrite(clc.voipOutgoingData, wpos, 1, encio); fflush(encio); }
+ if (encio != NULL) { fwrite(clc.voipOutgoingData, bytes, 1, encio); fflush(encio); }
static FILE *decio = NULL;
if (decio == NULL) decio = fopen("voip-outgoing-decoded.bin", "wb");
- if (decio != NULL) { fwrite(sampbuffer, speexFrames * clc.speexFrameSize * 2, 1, decio); fflush(decio); }
+ if (decio != NULL) { fwrite(sampbuffer, voipFrames * VOIP_MAX_FRAME_SAMPLES * 2, 1, decio); fflush(decio); }
#endif
}
}
@@ -1420,14 +1410,11 @@ void CL_Disconnect( qboolean showMainMenu ) {
cl_voipUseVAD->integer = tmp;
}
- if (clc.speexInitialized) {
+ if (clc.voipCodecInitialized) {
int i;
- speex_bits_destroy(&clc.speexEncoderBits);
- speex_encoder_destroy(clc.speexEncoder);
- speex_preprocess_state_destroy(clc.speexPreprocessor);
+ opus_encoder_destroy(clc.opusEncoder);
for (i = 0; i < MAX_CLIENTS; i++) {
- speex_bits_destroy(&clc.speexDecoderBits[i]);
- speex_decoder_destroy(clc.speexDecoder[i]);
+ opus_decoder_destroy(clc.opusDecoder[i]);
}
}
Cmd_RemoveCommand ("voip");
@@ -1732,6 +1719,50 @@ static void CL_CompleteRcon( char *args, int argNum )
}
/*
+==================
+CL_CompletePlayerName
+==================
+*/
+static void CL_CompletePlayerName( char *args, int argNum )
+{
+ if( argNum == 2 )
+ {
+ char names[MAX_CLIENTS][MAX_NAME_LENGTH];
+ char *namesPtr[MAX_CLIENTS];
+ int i;
+ int clientCount;
+ int nameCount;
+ const char *info;
+ const char *name;
+
+ //configstring
+ info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SERVERINFO];
+ clientCount = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
+
+ nameCount = 0;
+
+ for( i = 0; i < clientCount; i++ ) {
+ if( i == clc.clientNum )
+ continue;
+
+ info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_PLAYERS+i];
+
+ name = Info_ValueForKey( info, "n" );
+ if( name[0] == '\0' )
+ continue;
+ Q_strncpyz( names[nameCount], name, sizeof(names[nameCount]) );
+ Q_CleanStr( names[nameCount] );
+
+ namesPtr[nameCount] = names[nameCount];
+ nameCount++;
+ }
+ qsort( (void*)namesPtr, nameCount, sizeof( namesPtr[0] ), Com_strCompare );
+
+ Field_CompletePlayerName( namesPtr, nameCount );
+ }
+}
+
+/*
=====================
CL_Rcon_f
@@ -1743,7 +1774,7 @@ void CL_Rcon_f( void ) {
char message[MAX_RCON_MESSAGE];
netadr_t to;
- if ( !rcon_client_password->string ) {
+ if ( !rcon_client_password->string[0] ) {
Com_Printf ("You must set 'rconpassword' before\n"
"issuing an rcon command.\n");
return;
@@ -2312,9 +2343,9 @@ Resend a connect message if the last one has timed out
=================
*/
void CL_CheckForResend( void ) {
- int port, i;
+ int port;
char info[MAX_INFO_STRING];
- char data[MAX_INFO_STRING];
+ char data[MAX_INFO_STRING + 10];
// don't send anything if playing back a demo
if ( clc.demoplaying ) {
@@ -2355,19 +2386,8 @@ void CL_CheckForResend( void ) {
Info_SetValueForKey( info, "qport", va("%i", port ) );
Info_SetValueForKey( info, "challenge", va("%i", clc.challenge ) );
- strcpy(data, "connect ");
- // TTimo adding " " around the userinfo string to avoid truncated userinfo on the server
- // (Com_TokenizeString tokenizes around spaces)
- data[8] = '"';
-
- for(i=0;i<strlen(info);i++) {
- data[9+i] = info[i]; // + (clc.challenge)&0x3;
- }
- data[9+i] = '"';
- data[10+i] = 0;
-
- // NOTE TTimo don't forget to set the right data length!
- NET_OutOfBandData( NS_CLIENT, clc.serverAddress, (byte *) &data[0], i+10 );
+ Com_sprintf( data, sizeof(data), "connect \"%s\"", info );
+ NET_OutOfBandData( NS_CLIENT, clc.serverAddress, (byte *) data, strlen ( data ) );
// the most current userinfo has been sent, so watch for any
// newer changes to userinfo variables
cvar_modifiedFlags &= ~CVAR_USERINFO;
@@ -3474,6 +3494,56 @@ static void CL_GenerateQKey(void)
}
}
+void CL_Sayto_f( void ) {
+ char *rawname;
+ char name[MAX_NAME_LENGTH];
+ char cleanName[MAX_NAME_LENGTH];
+ const char *info;
+ int count;
+ int i;
+ int clientNum;
+ char *p;
+
+ if ( Cmd_Argc() < 3 ) {
+ Com_Printf ("sayto <player name> <text>\n");
+ return;
+ }
+
+ rawname = Cmd_Argv(1);
+
+ Com_FieldStringToPlayerName( name, MAX_NAME_LENGTH, rawname );
+
+ info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SERVERINFO];
+ count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
+
+ clientNum = -1;
+ for( i = 0; i < count; i++ ) {
+
+ info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_PLAYERS+i];
+ Q_strncpyz( cleanName, Info_ValueForKey( info, "n" ), sizeof(cleanName) );
+ Q_CleanStr( cleanName );
+
+ if ( !Q_stricmp( cleanName, name ) ) {
+ clientNum = i;
+ break;
+ }
+ }
+ if( clientNum <= -1 )
+ {
+ Com_Printf ("No such player name: %s.\n", name);
+ return;
+ }
+
+ p = Cmd_ArgsFrom(2);
+
+ if ( *p == '"' ) {
+ p++;
+ p[strlen(p)-1] = 0;
+ }
+
+ CL_AddReliableCommand(va("tell %i \"%s\"", clientNum, p ), qfalse);
+}
+
/*
====================
CL_Init
@@ -3624,9 +3694,9 @@ void CL_Init( void ) {
cl_voipVADThreshold = Cvar_Get ("cl_voipVADThreshold", "0.25", CVAR_ARCHIVE);
cl_voipShowMeter = Cvar_Get ("cl_voipShowMeter", "1", CVAR_ARCHIVE);
- // This is a protocol version number.
- cl_voip = Cvar_Get ("cl_voip", "1", CVAR_USERINFO | CVAR_ARCHIVE);
+ cl_voip = Cvar_Get ("cl_voip", "1", CVAR_ARCHIVE);
Cvar_CheckRange( cl_voip, 0, 1, qtrue );
+ cl_voipProtocol = Cvar_Get ("cl_voipProtocol", cl_voip->integer ? "opus" : "", CVAR_USERINFO | CVAR_ROM);
#endif
@@ -3663,6 +3733,10 @@ void CL_Init( void ) {
Cmd_AddCommand ("model", CL_SetModel_f );
Cmd_AddCommand ("video", CL_Video_f );
Cmd_AddCommand ("stopvideo", CL_StopVideo_f );
+ if( !com_dedicated->integer ) {
+ Cmd_AddCommand ("sayto", CL_Sayto_f );
+ Cmd_SetCommandCompletionFunc( "sayto", CL_CompletePlayerName );
+ }
CL_InitRef();
SCR_Init ();
@@ -3918,11 +3992,7 @@ serverStatus_t *CL_GetServerStatus( netadr_t from ) {
oldestTime = cl_serverStatusList[i].startTime;
}
}
- if (oldest != -1) {
- return &cl_serverStatusList[oldest];
- }
- serverStatusCount++;
- return &cl_serverStatusList[serverStatusCount & (MAX_SERVERSTATUSREQUESTS-1)];
+ return &cl_serverStatusList[oldest];
}
/*
diff --git a/src/client/cl_parse.c b/src/client/cl_parse.c
index a8b68ca5..981d21c6 100644
--- a/src/client/cl_parse.c
+++ b/src/client/cl_parse.c
@@ -35,7 +35,8 @@ char *svc_strings[256] = {
"svc_download",
"svc_snapshot",
"svc_EOF",
- "svc_voip",
+ "svc_voipSpeex",
+ "svc_voipOpus",
};
void SHOWNET( msg_t *msg, char *s) {
@@ -354,8 +355,8 @@ void CL_SystemInfoChanged( void ) {
cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );
#ifdef USE_VOIP
- s = Info_ValueForKey( systemInfo, "sv_voip" );
- clc.voipEnabled = atoi(s);
+ s = Info_ValueForKey( systemInfo, "sv_voipProtocol" );
+ clc.voipEnabled = !Q_stricmp(s, "opus");
#endif
// don't set any vars when playing a demo
@@ -674,13 +675,13 @@ static void CL_PlayVoip(int sender, int samplecnt, const byte *data, int flags)
{
if(flags & VOIP_DIRECT)
{
- S_RawSamples(sender + 1, samplecnt, clc.speexSampleRate, 2, 1,
+ S_RawSamples(sender + 1, samplecnt, 48000, 2, 1,
data, clc.voipGain[sender], -1);
}
if(flags & VOIP_SPATIAL)
{
- S_RawSamples(sender + MAX_CLIENTS + 1, samplecnt, clc.speexSampleRate, 2, 1,
+ S_RawSamples(sender + MAX_CLIENTS + 1, samplecnt, 48000, 2, 1,
data, 1.0f, sender);
}
}
@@ -693,8 +694,8 @@ A VoIP message has been received from the server
=====================
*/
static
-void CL_ParseVoip ( msg_t *msg ) {
- static short decoded[4096]; // !!! FIXME: don't hardcode.
+void CL_ParseVoip ( msg_t *msg, qboolean ignoreData ) {
+ static short decoded[VOIP_MAX_PACKET_SAMPLES*4]; // !!! FIXME: don't hard code
const int sender = MSG_ReadShort(msg);
const int generation = MSG_ReadByte(msg);
@@ -702,7 +703,8 @@ void CL_ParseVoip ( msg_t *msg ) {
const int frames = MSG_ReadByte(msg);
const int packetsize = MSG_ReadShort(msg);
const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT);
- char encoded[1024];
+ unsigned char encoded[4000];
+ int numSamples;
int seqdiff;
int written = 0;
int i;
@@ -732,14 +734,15 @@ void CL_ParseVoip ( msg_t *msg ) {
return; // overlarge packet, bail.
}
- if (!clc.speexInitialized) {
- MSG_ReadData(msg, encoded, packetsize); // skip payload.
- return; // can't handle VoIP without libspeex!
+ MSG_ReadData(msg, encoded, packetsize);
+
+ if (ignoreData) {
+ return; // just ignore legacy speex voip data
+ } else if (!clc.voipCodecInitialized) {
+ return; // can't handle VoIP without libopus!
} else if (sender >= MAX_CLIENTS) {
- MSG_ReadData(msg, encoded, packetsize); // skip payload.
return; // bogus sender.
} else if (CL_ShouldIgnoreVoipSender(sender)) {
- MSG_ReadData(msg, encoded, packetsize); // skip payload.
return; // Channel is muted, bail.
}
@@ -752,70 +755,59 @@ void CL_ParseVoip ( msg_t *msg ) {
// This is a new "generation" ... a new recording started, reset the bits.
if (generation != clc.voipIncomingGeneration[sender]) {
Com_DPrintf("VoIP: new generation %d!\n", generation);
- speex_bits_reset(&clc.speexDecoderBits[sender]);
+ opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
clc.voipIncomingGeneration[sender] = generation;
seqdiff = 0;
} else if (seqdiff < 0) { // we're ahead of the sequence?!
// This shouldn't happen unless the packet is corrupted or something.
Com_DPrintf("VoIP: misordered sequence! %d < %d!\n",
sequence, clc.voipIncomingSequence[sender]);
- // reset the bits just in case.
- speex_bits_reset(&clc.speexDecoderBits[sender]);
+ // reset the decoder just in case.
+ opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
seqdiff = 0;
- } else if (seqdiff * clc.speexFrameSize * 2 >= sizeof (decoded)) { // dropped more than we can handle?
+ } else if (seqdiff * VOIP_MAX_PACKET_SAMPLES*2 >= sizeof (decoded)) { // dropped more than we can handle?
// just start over.
Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n",
seqdiff, sender);
- speex_bits_reset(&clc.speexDecoderBits[sender]);
+ opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
seqdiff = 0;
}
if (seqdiff != 0) {
Com_DPrintf("VoIP: Dropped %d frames from client #%d\n",
seqdiff, sender);
- // tell speex that we're missing frames...
+ // tell opus that we're missing frames...
for (i = 0; i < seqdiff; i++) {
- assert((written + clc.speexFrameSize) * 2 < sizeof (decoded));
- speex_decode_int(clc.speexDecoder[sender], NULL, decoded + written);
- written += clc.speexFrameSize;
+ assert((written + VOIP_MAX_PACKET_SAMPLES) * 2 < sizeof (decoded));
+ numSamples = opus_decode(clc.opusDecoder[sender], NULL, 0, decoded + written, VOIP_MAX_PACKET_SAMPLES, 0);
+ if ( numSamples <= 0 ) {
+ Com_DPrintf("VoIP: Error decoding frame %d from client #%d\n", i, sender);
+ continue;
+ }
+ written += numSamples;
}
}
- for (i = 0; i < frames; i++) {
- const int len = MSG_ReadByte(msg);
- if (len < 0) {
- Com_DPrintf("VoIP: Short packet!\n");
- break;
- }
- MSG_ReadData(msg, encoded, len);
+ numSamples = opus_decode(clc.opusDecoder[sender], encoded, packetsize, decoded + written, ARRAY_LEN(decoded) - written, 0);
- // shouldn't happen, but just in case...
- if ((written + clc.speexFrameSize) * 2 > sizeof (decoded)) {
- Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
- written * 2, written, i);
-
- CL_PlayVoip(sender, written, (const byte *) decoded, flags);
- written = 0;
- }
-
- speex_bits_read_from(&clc.speexDecoderBits[sender], encoded, len);
- speex_decode_int(clc.speexDecoder[sender],
- &clc.speexDecoderBits[sender], decoded + written);
+ if ( numSamples <= 0 ) {
+ Com_DPrintf("VoIP: Error decoding voip data from client #%d\n", sender);
+ numSamples = 0;
+ }
- #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); }
- 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); }
- #endif
+ #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); }
+ 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); }
+ #endif
- written += clc.speexFrameSize;
- }
+ written += numSamples;
Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
- written * 2, written, i);
+ written * 2, written, frames);
if(written > 0)
CL_PlayVoip(sender, written, (const byte *) decoded, flags);
@@ -918,9 +910,14 @@ void CL_ParseServerMessage( msg_t *msg ) {
case svc_download:
CL_ParseDownload( msg );
break;
- case svc_voip:
+ case svc_voipSpeex:
+#ifdef USE_VOIP
+ CL_ParseVoip( msg, qtrue );
+#endif
+ break;
+ case svc_voipOpus:
#ifdef USE_VOIP
- CL_ParseVoip( msg );
+ CL_ParseVoip( msg, !clc.voipEnabled );
#endif
break;
}
diff --git a/src/client/client.h b/src/client/client.h
index 541dca40..b4016467 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -36,8 +36,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif /* USE_CURL */
#ifdef USE_VOIP
-#include "speex/speex.h"
-#include "speex/speex_preprocess.h"
+#include <opus.h>
#endif
// file full of random crap that gets used to create cl_guid
@@ -241,14 +240,11 @@ typedef struct {
#ifdef USE_VOIP
qboolean voipEnabled;
- qboolean speexInitialized;
- int speexFrameSize;
- int speexSampleRate;
+ qboolean voipCodecInitialized;
// incoming data...
// !!! FIXME: convert from parallel arrays to array of a struct.
- SpeexBits speexDecoderBits[MAX_CLIENTS];
- void *speexDecoder[MAX_CLIENTS];
+ OpusDecoder *opusDecoder[MAX_CLIENTS];
byte voipIncomingGeneration[MAX_CLIENTS];
int voipIncomingSequence[MAX_CLIENTS];
float voipGain[MAX_CLIENTS];
@@ -260,9 +256,7 @@ typedef struct {
// then we are sending to clientnum i.
uint8_t voipTargets[(MAX_CLIENTS + 7) / 8];
uint8_t voipFlags;
- SpeexPreprocessState *speexPreprocessor;
- SpeexBits speexEncoderBits;
- void *speexEncoder;
+ OpusEncoder *opusEncoder;
int voipOutgoingDataSize;
int voipOutgoingDataFrames;
int voipOutgoingSequence;
@@ -449,6 +443,13 @@ extern cvar_t *cl_voipGainDuringCapture;
extern cvar_t *cl_voipCaptureMult;
extern cvar_t *cl_voipShowMeter;
extern cvar_t *cl_voip;
+
+// 20ms at 48k
+#define VOIP_MAX_FRAME_SAMPLES ( 20 * 48 )
+
+// 3 frame is 60ms of audio, the max opus will encode at once
+#define VOIP_MAX_PACKET_FRAMES 3
+#define VOIP_MAX_PACKET_SAMPLES ( VOIP_MAX_FRAME_SAMPLES * VOIP_MAX_PACKET_FRAMES )
#endif
//=================================================
diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c
index d90e6d23..b5c89918 100644
--- a/src/client/snd_openal.c
+++ b/src/client/snd_openal.c
@@ -2700,16 +2700,12 @@ qboolean S_AL_Init( soundInterface_t *si )
s_alAvailableInputDevices = Cvar_Get("s_alAvailableInputDevices", inputdevicenames, CVAR_ROM | CVAR_NORESTART);
- // !!! FIXME: 8000Hz is what Speex narrowband mode needs, but we
- // !!! FIXME: should probably open the capture device after
- // !!! FIXME: initializing Speex so we can change to wideband
- // !!! FIXME: if we like.
Com_Printf("OpenAL default capture device is '%s'\n", defaultinputdevice ? defaultinputdevice : "none");
- alCaptureDevice = qalcCaptureOpenDevice(inputdevice, 8000, AL_FORMAT_MONO16, 4096);
+ alCaptureDevice = qalcCaptureOpenDevice(inputdevice, 48000, AL_FORMAT_MONO16, VOIP_MAX_PACKET_SAMPLES*4);
if( !alCaptureDevice && inputdevice )
{
Com_Printf( "Failed to open OpenAL Input device '%s', trying default.\n", inputdevice );
- alCaptureDevice = qalcCaptureOpenDevice(NULL, 8000, AL_FORMAT_MONO16, 4096);
+ alCaptureDevice = qalcCaptureOpenDevice(NULL, 48000, AL_FORMAT_MONO16, VOIP_MAX_PACKET_SAMPLES*4);
}
Com_Printf( "OpenAL capture device %s.\n",
(alCaptureDevice == NULL) ? "failed to open" : "opened");
diff --git a/src/qcommon/cm_patch.c b/src/qcommon/cm_patch.c
index 5a66b1b0..5f55e9d4 100644
--- a/src/qcommon/cm_patch.c
+++ b/src/qcommon/cm_patch.c
@@ -419,7 +419,7 @@ static int numPlanes;
static patchPlane_t planes[MAX_PATCH_PLANES];
static int numFacets;
-static facet_t facets[MAX_PATCH_PLANES]; //maybe MAX_FACETS ??
+static facet_t facets[MAX_FACETS];
#define NORMAL_EPSILON 0.0001
#define DIST_EPSILON 0.02
@@ -877,7 +877,10 @@ void CM_AddFacetBevels( facet_t *facet ) {
}
if ( i == facet->numBorders ) {
- if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
+ if ( facet->numBorders >= 4 + 6 + 16 ) {
+ Com_Printf( "ERROR: too many bevels\n" );
+ continue;
+ }
facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
facet->borderNoAdjust[facet->numBorders] = 0;
facet->borderInward[facet->numBorders] = flipped;
@@ -939,7 +942,10 @@ void CM_AddFacetBevels( facet_t *facet ) {
}
if ( i == facet->numBorders ) {
- if (facet->numBorders > 4 + 6 + 16) Com_Printf("ERROR: too many bevels\n");
+ if ( facet->numBorders >= 4 + 6 + 16 ) {
+ Com_Printf( "ERROR: too many bevels\n" );
+ continue;
+ }
facet->borderPlanes[facet->numBorders] = CM_FindPlane2(plane, &flipped);
for ( k = 0 ; k < facet->numBorders ; k++ ) {
@@ -977,6 +983,10 @@ void CM_AddFacetBevels( facet_t *facet ) {
#ifndef BSPC
//add opposite plane
+ if ( facet->numBorders >= 4 + 6 + 16 ) {
+ Com_Printf( "ERROR: too many bevels\n" );
+ return;
+ }
facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
facet->borderNoAdjust[facet->numBorders] = 0;
facet->borderInward[facet->numBorders] = qtrue;
diff --git a/src/qcommon/cmd.c b/src/qcommon/cmd.c
index 44a6f0ea..48489eff 100644
--- a/src/qcommon/cmd.c
+++ b/src/qcommon/cmd.c
@@ -706,6 +706,7 @@ void Cmd_SetCommandCompletionFunc( const char *command, completionFunc_t complet
for( cmd = cmd_functions; cmd; cmd = cmd->next ) {
if( !Q_stricmp( command, cmd->name ) ) {
cmd->complete = complete;
+ return;
}
}
}
@@ -782,8 +783,11 @@ void Cmd_CompleteArgument( const char *command, char *args, int argNum ) {
cmd_function_t *cmd;
for( cmd = cmd_functions; cmd; cmd = cmd->next ) {
- if( !Q_stricmp( command, cmd->name ) && cmd->complete ) {
- cmd->complete( args, argNum );
+ if( !Q_stricmp( command, cmd->name ) ) {
+ if ( cmd->complete ) {
+ cmd->complete( args, argNum );
+ }
+ return;
}
}
}
diff --git a/src/qcommon/common.c b/src/qcommon/common.c
index fef14331..11e723c1 100644
--- a/src/qcommon/common.c
+++ b/src/qcommon/common.c
@@ -3421,3 +3421,177 @@ qboolean Com_IsVoipTarget(uint8_t *voipTargets, int voipTargetsSize, int clientN
return qfalse;
}
+
+/*
+===============
+Field_CompletePlayerName
+===============
+*/
+static qboolean Field_CompletePlayerNameFinal( qboolean whitespace )
+{
+ int completionOffset;
+
+ if( matchCount == 0 )
+ return qtrue;
+
+ completionOffset = strlen( completionField->buffer ) - strlen( completionString );
+
+ Q_strncpyz( &completionField->buffer[ completionOffset ], shortestMatch,
+ sizeof( completionField->buffer ) - completionOffset );
+
+ completionField->cursor = strlen( completionField->buffer );
+
+ if( matchCount == 1 && whitespace )
+ {
+ Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
+ completionField->cursor++;
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+static void Name_PlayerNameCompletion( const char **names, int nameCount, void(*callback)(const char *s) )
+{
+ int i;
+
+ for( i = 0; i < nameCount; i++ ) {
+ callback( names[ i ] );
+ }
+}
+
+qboolean Com_FieldStringToPlayerName( char *name, int length, const char *rawname )
+{
+ char hex[5];
+ int i;
+ int ch;
+
+ if( name == NULL || rawname == NULL )
+ return qfalse;
+
+ if( length <= 0 )
+ return qtrue;
+
+ for( i = 0; *rawname && i + 1 <= length; rawname++, i++ ) {
+ if( *rawname == '\\' ) {
+ Q_strncpyz( hex, rawname + 1, sizeof(hex) );
+ ch = Com_HexStrToInt( hex );
+ if( ch > -1 ) {
+ name[i] = ch;
+ rawname += 4; //hex string length, 0xXX
+ } else {
+ name[i] = *rawname;
+ }
+ } else {
+ name[i] = *rawname;
+ }
+ }
+ name[i] = '\0';
+
+ return qtrue;
+}
+
+qboolean Com_PlayerNameToFieldString( char *str, int length, const char *name )
+{
+ const char *p;
+ int i;
+ int x1, x2;
+
+ if( str == NULL || name == NULL )
+ return qfalse;
+
+ if( length <= 0 )
+ return qtrue;
+
+ *str = '\0';
+ p = name;
+
+ for( i = 0; *p != '\0'; i++, p++ )
+ {
+ if( i + 1 >= length )
+ break;
+
+ if( *p <= ' ' )
+ {
+ if( i + 5 + 1 >= length )
+ break;
+
+ x1 = *p >> 4;
+ x2 = *p & 15;
+
+ str[i+0] = '\\';
+ str[i+1] = '0';
+ str[i+2] = 'x';
+ str[i+3] = x1 > 9 ? x1 - 10 + 'a' : x1 + '0';
+ str[i+4] = x2 > 9 ? x2 - 10 + 'a' : x2 + '0';
+
+ i += 4;
+ } else {
+ str[i] = *p;
+ }
+ }
+ str[i] = '\0';
+
+ return qtrue;
+}
+
+void Field_CompletePlayerName( char **names, int nameCount )
+{
+ qboolean whitespace;
+
+ matchCount = 0;
+ shortestMatch[ 0 ] = 0;
+
+ if( nameCount <= 0 )
+ return;
+
+ Name_PlayerNameCompletion( names, nameCount, FindMatches );
+
+ if( completionString[0] == '\0' )
+ {
+ Com_PlayerNameToFieldString( shortestMatch, sizeof( shortestMatch ), names[ 0 ] );
+ }
+
+ //allow to tab player names
+ //if full player name switch to next player name
+ if( completionString[0] != '\0'
+ && Q_stricmp( shortestMatch, completionString ) == 0
+ && nameCount > 1 )
+ {
+ int i;
+
+ for( i = 0; i < nameCount; i++ ) {
+ if( Q_stricmp( names[ i ], completionString ) == 0 )
+ {
+ i++;
+ if( i >= nameCount )
+ {
+ i = 0;
+ }
+
+ Com_PlayerNameToFieldString( shortestMatch, sizeof( shortestMatch ), names[ i ] );
+ break;
+ }
+ }
+ }
+
+ if( matchCount > 1 )
+ {
+ Com_Printf( "]%s\n", completionField->buffer );
+
+ Name_PlayerNameCompletion( names, nameCount, PrintMatches );
+ }
+
+ whitespace = nameCount == 1? qtrue: qfalse;
+ if( !Field_CompletePlayerNameFinal( whitespace ) )
+ {
+
+ }
+}
+
+int QDECL Com_strCompare( const void *a, const void *b )
+{
+ const char **pa = (const char **)a;
+ const char **pb = (const char **)b;
+ return strcmp( *pa, *pb );
+}
diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c
index 336f45b0..d22679e8 100644
--- a/src/qcommon/cvar.c
+++ b/src/qcommon/cvar.c
@@ -1118,6 +1118,9 @@ cvar_t *Cvar_Unset(cvar_t *cv)
{
cvar_t *next = cv->next;
+ // note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
+ cvar_modifiedFlags |= cv->flags;
+
if(cv->name)
Z_Free(cv->name);
if(cv->string)
diff --git a/src/qcommon/files.c b/src/qcommon/files.c
index 0dd8e08a..c4c07242 100644
--- a/src/qcommon/files.c
+++ b/src/qcommon/files.c
@@ -511,7 +511,9 @@ qboolean FS_CreatePath (char *OSPath) {
// Skip creation of the root directory as it will always be there
ofs = strchr( path, PATH_SEP );
- ofs++;
+ if ( ofs != NULL ) {
+ ofs++;
+ }
for (; ofs != NULL && *ofs ; ofs++) {
if (*ofs == PATH_SEP) {
@@ -2453,9 +2455,8 @@ int FS_GetModList( char *listbuf, int bufsize ) {
pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );
pFiles1 = Sys_ListFiles( fs_basepath->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
pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1 );
+
nPotential = Sys_CountFileList(pFiles);
for ( i = 0 ; i < nPotential ; i++ ) {
@@ -2703,7 +2704,7 @@ void FS_Path_f( void ) {
searchpath_t *s;
int i;
- Com_Printf ("Current search path:\n");
+ Com_Printf ("We are looking in the current search path:\n");
for (s = fs_searchpaths; s; s = s->next) {
if (s->pack) {
Com_Printf ("%s (%i files)\n", s->pack->pakFilename, s->pack->numfiles);
diff --git a/src/qcommon/json.h b/src/qcommon/json.h
new file mode 100644
index 00000000..cfc5b3ca
--- /dev/null
+++ b/src/qcommon/json.h
@@ -0,0 +1,353 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+===========================================================================
+*/
+
+#ifndef JSON_H
+#define JSON_H
+
+enum
+{
+ JSONTYPE_STRING, // string
+ JSONTYPE_OBJECT, // object
+ JSONTYPE_ARRAY, // array
+ JSONTYPE_VALUE, // number, true, false, or null
+ JSONTYPE_ERROR // out of data
+};
+
+// --------------------------------------------------------------------------
+// Array Functions
+// --------------------------------------------------------------------------
+
+// Get pointer to first value in array
+// When given pointer to an array, returns pointer to the first
+// returns NULL if array is empty or not an array.
+const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd);
+
+// Get pointer to next value in array
+// When given pointer to a value, returns pointer to the next value
+// returns NULL when no next value.
+const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd);
+
+// Get pointers to values in an array
+// returns 0 if not an array, array is empty, or out of data
+// returns number of values in the array and copies into index if successful
+unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes);
+
+// Get pointer to indexed value from array
+// returns NULL if not an array, no index, or out of data
+const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index);
+
+// --------------------------------------------------------------------------
+// Object Functions
+// --------------------------------------------------------------------------
+
+// Get pointer to named value from object
+// returns NULL if not an object, name not found, or out of data
+const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name);
+
+// --------------------------------------------------------------------------
+// Value Functions
+// --------------------------------------------------------------------------
+
+// Get type of value
+// returns JSONTYPE_ERROR if out of data
+unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd);
+
+// Get value as string
+// returns 0 if out of data
+// returns length and copies into string if successful, including terminating nul.
+// string values are stripped of enclosing quotes but not escaped
+unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen);
+
+// Get value as appropriate type
+// returns 0 if value is false, value is null, or out of data
+// returns 1 if value is true
+// returns value otherwise
+double JSON_ValueGetDouble(const char *json, const char *jsonEnd);
+float JSON_ValueGetFloat(const char *json, const char *jsonEnd);
+int JSON_ValueGetInt(const char *json, const char *jsonEnd);
+
+#endif
+
+#ifdef JSON_IMPLEMENTATION
+#include <stdio.h>
+
+// --------------------------------------------------------------------------
+// Internal Functions
+// --------------------------------------------------------------------------
+
+static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd);
+static const char *JSON_SkipString(const char *json, const char *jsonEnd);
+static const char *JSON_SkipStruct(const char *json, const char *jsonEnd);
+static const char *JSON_SkipValue(const char *json, const char *jsonEnd);
+static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd);
+
+#define IS_SEPARATOR(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' || (x) == '\r' || (x) == ',' || (x) == ':')
+#define IS_STRUCT_OPEN(x) ((x) == '{' || (x) == '[')
+#define IS_STRUCT_CLOSE(x) ((x) == '}' || (x) == ']')
+
+static const char *JSON_SkipSeparators(const char *json, const char *jsonEnd)
+{
+ while (json < jsonEnd && IS_SEPARATOR(*json))
+ json++;
+
+ return json;
+}
+
+static const char *JSON_SkipString(const char *json, const char *jsonEnd)
+{
+ for (json++; json < jsonEnd && *json != '"'; json++)
+ if (*json == '\\')
+ json++;
+
+ return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
+}
+
+static const char *JSON_SkipStruct(const char *json, const char *jsonEnd)
+{
+ json = JSON_SkipSeparators(json + 1, jsonEnd);
+ while (json < jsonEnd && !IS_STRUCT_CLOSE(*json))
+ json = JSON_SkipValueAndSeparators(json, jsonEnd);
+
+ return (json + 1 > jsonEnd) ? jsonEnd : json + 1;
+}
+
+static const char *JSON_SkipValue(const char *json, const char *jsonEnd)
+{
+ if (json >= jsonEnd)
+ return jsonEnd;
+ else if (*json == '"')
+ json = JSON_SkipString(json, jsonEnd);
+ else if (IS_STRUCT_OPEN(*json))
+ json = JSON_SkipStruct(json, jsonEnd);
+ else
+ {
+ while (json < jsonEnd && !IS_SEPARATOR(*json) && !IS_STRUCT_CLOSE(*json))
+ json++;
+ }
+
+ return json;
+}
+
+static const char *JSON_SkipValueAndSeparators(const char *json, const char *jsonEnd)
+{
+ json = JSON_SkipValue(json, jsonEnd);
+ return JSON_SkipSeparators(json, jsonEnd);
+}
+
+// returns 0 if value requires more parsing, 1 if no more data/false/null, 2 if true
+static unsigned int JSON_NoParse(const char *json, const char *jsonEnd)
+{
+ if (!json || json >= jsonEnd || *json == 'f' || *json == 'n')
+ return 1;
+
+ if (*json == 't')
+ return 2;
+
+ return 0;
+}
+
+// --------------------------------------------------------------------------
+// Array Functions
+// --------------------------------------------------------------------------
+
+const char *JSON_ArrayGetFirstValue(const char *json, const char *jsonEnd)
+{
+ if (!json || json >= jsonEnd || !IS_STRUCT_OPEN(*json))
+ return NULL;
+
+ json = JSON_SkipSeparators(json + 1, jsonEnd);
+
+ return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
+}
+
+const char *JSON_ArrayGetNextValue(const char *json, const char *jsonEnd)
+{
+ if (!json || json >= jsonEnd || IS_STRUCT_CLOSE(*json))
+ return NULL;
+
+ json = JSON_SkipValueAndSeparators(json, jsonEnd);
+
+ return (json >= jsonEnd || IS_STRUCT_CLOSE(*json)) ? NULL : json;
+}
+
+unsigned int JSON_ArrayGetIndex(const char *json, const char *jsonEnd, const char **indexes, unsigned int numIndexes)
+{
+ unsigned int length = 0;
+
+ for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
+ {
+ if (indexes && numIndexes)
+ {
+ *indexes++ = json;
+ numIndexes--;
+ }
+ length++;
+ }
+
+ return length;
+}
+
+const char *JSON_ArrayGetValue(const char *json, const char *jsonEnd, unsigned int index)
+{
+ for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json && index; json = JSON_ArrayGetNextValue(json, jsonEnd))
+ index--;
+
+ return json;
+}
+
+// --------------------------------------------------------------------------
+// Object Functions
+// --------------------------------------------------------------------------
+
+const char *JSON_ObjectGetNamedValue(const char *json, const char *jsonEnd, const char *name)
+{
+ unsigned int nameLen = strlen(name);
+
+ for (json = JSON_ArrayGetFirstValue(json, jsonEnd); json; json = JSON_ArrayGetNextValue(json, jsonEnd))
+ {
+ if (*json == '"')
+ {
+ const char *thisNameStart, *thisNameEnd;
+
+ thisNameStart = json + 1;
+ json = JSON_SkipString(json, jsonEnd);
+ thisNameEnd = json - 1;
+ json = JSON_SkipSeparators(json, jsonEnd);
+
+ if ((unsigned int)(thisNameEnd - thisNameStart) == nameLen)
+ if (strncmp(thisNameStart, name, nameLen) == 0)
+ return json;
+ }
+ }
+
+ return NULL;
+}
+
+// --------------------------------------------------------------------------
+// Value Functions
+// --------------------------------------------------------------------------
+
+unsigned int JSON_ValueGetType(const char *json, const char *jsonEnd)
+{
+ if (!json || json >= jsonEnd)
+ return JSONTYPE_ERROR;
+ else if (*json == '"')
+ return JSONTYPE_STRING;
+ else if (*json == '{')
+ return JSONTYPE_OBJECT;
+ else if (*json == '[')
+ return JSONTYPE_ARRAY;
+
+ return JSONTYPE_VALUE;
+}
+
+unsigned int JSON_ValueGetString(const char *json, const char *jsonEnd, char *outString, unsigned int stringLen)
+{
+ const char *stringEnd, *stringStart;
+
+ if (!json)
+ {
+ *outString = '\0';
+ return 0;
+ }
+
+ stringStart = json;
+ stringEnd = JSON_SkipValue(stringStart, jsonEnd);
+ if (stringEnd >= jsonEnd)
+ {
+ *outString = '\0';
+ return 0;
+ }
+
+ // skip enclosing quotes if they exist
+ if (*stringStart == '"')
+ stringStart++;
+
+ if (*(stringEnd - 1) == '"')
+ stringEnd--;
+
+ stringLen--;
+ if (stringLen > stringEnd - stringStart)
+ stringLen = stringEnd - stringStart;
+
+ json = stringStart;
+ while (stringLen--)
+ *outString++ = *json++;
+ *outString = '\0';
+
+ return stringEnd - stringStart;
+}
+
+double JSON_ValueGetDouble(const char *json, const char *jsonEnd)
+{
+ char cValue[256];
+ double dValue = 0.0;
+ unsigned int np = JSON_NoParse(json, jsonEnd);
+
+ if (np)
+ return (double)(np - 1);
+
+ if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+ return 0.0;
+
+ sscanf(cValue, "%lf", &dValue);
+
+ return dValue;
+}
+
+float JSON_ValueGetFloat(const char *json, const char *jsonEnd)
+{
+ char cValue[256];
+ float fValue = 0.0f;
+ unsigned int np = JSON_NoParse(json, jsonEnd);
+
+ if (np)
+ return (float)(np - 1);
+
+ if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+ return 0.0f;
+
+ sscanf(cValue, "%f", &fValue);
+
+ return fValue;
+}
+
+int JSON_ValueGetInt(const char *json, const char *jsonEnd)
+{
+ char cValue[256];
+ int iValue = 0;
+ unsigned int np = JSON_NoParse(json, jsonEnd);
+
+ if (np)
+ return np - 1;
+
+ if (!JSON_ValueGetString(json, jsonEnd, cValue, 256))
+ return 0;
+
+ sscanf(cValue, "%d", &iValue);
+
+ return iValue;
+}
+
+#undef IS_SEPARATOR
+#undef IS_STRUCT_OPEN
+#undef IS_STRUCT_CLOSE
+
+#endif
diff --git a/src/qcommon/q_platform.h b/src/qcommon/q_platform.h
index 39d1672c..34a93626 100644
--- a/src/qcommon/q_platform.h
+++ b/src/qcommon/q_platform.h
@@ -170,50 +170,29 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//================================================================= LINUX ===
-#if defined(__linux__) || defined(__FreeBSD_kernel__)
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
#include <endian.h>
#if defined(__linux__)
#define OS_STRING "linux"
-#else
+#elif defined(__FreeBSD_kernel__)
#define OS_STRING "kFreeBSD"
+#else
+#define OS_STRING "GNU"
#endif
#define ID_INLINE inline
#define PATH_SEP '/'
-#if defined __i386__
-#define ARCH_STRING "x86"
-#elif defined __x86_64__
+#if !defined(ARCH_STRING)
+# error ARCH_STRING should be defined by the Makefile
+#endif
+
+#if defined __x86_64__
#undef idx64
#define idx64 1
-#define ARCH_STRING "x86_64"
-#elif defined __powerpc64__
-#define ARCH_STRING "ppc64"
-#elif defined __powerpc__
-#define ARCH_STRING "ppc"
-#elif defined __s390__
-#define ARCH_STRING "s390"
-#elif defined __s390x__
-#define ARCH_STRING "s390x"
-#elif defined __ia64__
-#define ARCH_STRING "ia64"
-#elif defined __alpha__
-#define ARCH_STRING "alpha"
-#elif defined __sparc__
-#define ARCH_STRING "sparc"
-#elif defined __arm__
-#define ARCH_STRING "arm"
-#elif defined __cris__
-#define ARCH_STRING "cris"
-#elif defined __hppa__
-#define ARCH_STRING "hppa"
-#elif defined __mips__
-#define ARCH_STRING "mips"
-#elif defined __sh__
-#define ARCH_STRING "sh"
#endif
#if __FLOAT_WORD_ORDER == __BIG_ENDIAN
diff --git a/src/qcommon/q_shared.c b/src/qcommon/q_shared.c
index f226603d..f5888633 100644
--- a/src/qcommon/q_shared.c
+++ b/src/qcommon/q_shared.c
@@ -1276,7 +1276,7 @@ void Info_RemoveKey_Big( char *s, const char *key ) {
if (!strcmp (key, pkey) )
{
- strcpy (start, s); // remove this part
+ memmove(start, s, strlen(s) + 1); // remove this part
return;
}
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index 9dd6df43..ef8fcbd5 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -279,7 +279,8 @@ enum svc_ops_e {
svc_EOF,
// new commands, supported only by ioquake3 protocol but not legacy
- svc_voip, // not wrapped in USE_VOIP, so this value is reserved.
+ svc_voipSpeex, // not wrapped in USE_VOIP, so this value is reserved.
+ svc_voipOpus, //
};
@@ -295,7 +296,8 @@ enum clc_ops_e {
clc_EOF,
// new commands, supported only by ioquake3 protocol but not legacy
- clc_voip, // not wrapped in USE_VOIP, so this value is reserved.
+ clc_voipSpeex, // not wrapped in USE_VOIP, so this value is reserved.
+ clc_voipOpus, //
};
/*
@@ -740,6 +742,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 );
/*
==============================================================
@@ -815,6 +818,10 @@ void Com_StartupVariable( const char *match );
// if match is NULL, all set commands will be executed, otherwise
// only a set with the exact name. Only used during startup.
+qboolean Com_PlayerNameToFieldString( char *str, int length, const char *name );
+qboolean Com_FieldStringToPlayerName( char *name, int length, const char *rawname );
+int QDECL Com_strCompare( const void *a, const void *b );
+
extern cvar_t *com_developer;
extern cvar_t *com_dedicated;
diff --git a/src/qcommon/vm_x86.c b/src/qcommon/vm_x86.c
index 2056785d..cdf8ad56 100644
--- a/src/qcommon/vm_x86.c
+++ b/src/qcommon/vm_x86.c
@@ -204,19 +204,25 @@ static void EmitRexString(byte rex, const char *string)
#define MASK_REG(modrm, mask) \
- EmitString("81"); \
- EmitString((modrm)); \
- Emit4((mask))
+ do { \
+ EmitString("81"); \
+ EmitString((modrm)); \
+ Emit4((mask)); \
+ } while(0)
// add bl, bytes
#define STACK_PUSH(bytes) \
- EmitString("80 C3"); \
- Emit1(bytes)
+ do { \
+ EmitString("80 C3"); \
+ Emit1(bytes); \
+ } while(0)
// sub bl, bytes
#define STACK_POP(bytes) \
- EmitString("80 EB"); \
- Emit1(bytes)
+ do { \
+ EmitString("80 EB"); \
+ Emit1(bytes); \
+ } while(0)
static void EmitCommand(ELastCommand command)
{
diff --git a/src/renderercommon/qgl.h b/src/renderercommon/qgl.h
index 559c4387..bf48cc62 100644
--- a/src/renderercommon/qgl.h
+++ b/src/renderercommon/qgl.h
@@ -928,12 +928,12 @@ extern void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLs
#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9
#endif
-#ifndef GL_EXT_texture_compression_latc
-#define GL_EXT_texture_compression_latc
-#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70
-#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71
-#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72
-#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73
+#ifndef GL_ARB_texture_compression_rgtc
+#define GL_ARB_texture_compression_rgtc
+#define GL_COMPRESSED_RED_RGTC1 0x8DBB
+#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
+#define GL_COMPRESSED_RG_RGTC2 0x8DBD
+#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
#endif
#ifndef GL_ARB_texture_compression_bptc
@@ -987,6 +987,51 @@ extern GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array);
#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);
+
+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);
+
+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
diff --git a/src/renderercommon/tr_common.h b/src/renderercommon/tr_common.h
index fe44f784..0dc5653d 100644
--- a/src/renderercommon/tr_common.h
+++ b/src/renderercommon/tr_common.h
@@ -130,6 +130,20 @@ void R_DoneFreeType( void );
void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font);
/*
+=============================================================
+
+IMAGE LOADERS
+
+=============================================================
+*/
+
+void R_LoadBMP( const char *name, byte **pic, int *width, int *height );
+void R_LoadJPG( const char *name, byte **pic, int *width, int *height );
+void R_LoadPCX( const char *name, byte **pic, int *width, int *height );
+void R_LoadPNG( const char *name, byte **pic, int *width, int *height );
+void R_LoadTGA( const char *name, byte **pic, int *width, int *height );
+
+/*
====================================================================
IMPLEMENTATION SPECIFIC FUNCTIONS
diff --git a/src/renderercommon/tr_image_jpg.c b/src/renderercommon/tr_image_jpg.c
index 2bbcb365..3e369c20 100644
--- a/src/renderercommon/tr_image_jpg.c
+++ b/src/renderercommon/tr_image_jpg.c
@@ -21,6 +21,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
+#include <setjmp.h>
+
#include "tr_common.h"
/*
@@ -43,16 +45,27 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# endif
#endif
-static void __attribute__((__noreturn__)) R_JPGErrorExit(j_common_ptr cinfo)
+/* Catching errors, as done in libjpeg's example.c */
+typedef struct q_jpeg_error_mgr_s
+{
+ struct jpeg_error_mgr pub; /* "public" fields */
+
+ jmp_buf setjmp_buffer; /* for return to caller */
+} q_jpeg_error_mgr_t;
+
+static void R_JPGErrorExit(j_common_ptr cinfo)
{
char buffer[JMSG_LENGTH_MAX];
+
+ /* cinfo->err really points to a q_jpeg_error_mgr_s struct, so coerce pointer */
+ q_jpeg_error_mgr_t *jerr = (q_jpeg_error_mgr_t *)cinfo->err;
(*cinfo->err->format_message) (cinfo, buffer);
-
- /* Let the memory manager delete any temp files before we die */
- jpeg_destroy(cinfo);
-
- ri.Error(ERR_FATAL, "%s", buffer);
+
+ ri.Printf(PRINT_ALL, "Error: %s", buffer);
+
+ /* Return control to the setjmp point */
+ longjmp(jerr->setjmp_buffer, 1);
}
static void R_JPGOutputMessage(j_common_ptr cinfo)
@@ -84,7 +97,7 @@ void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *heigh
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
- struct jpeg_error_mgr jerr;
+ q_jpeg_error_mgr_t jerr;
/* More stuff */
JSAMPARRAY buffer; /* Output row buffer */
unsigned int row_stride; /* physical row width in output buffer */
@@ -116,10 +129,24 @@ void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *heigh
* This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo.
*/
- cinfo.err = jpeg_std_error(&jerr);
+ cinfo.err = jpeg_std_error(&jerr.pub);
cinfo.err->error_exit = R_JPGErrorExit;
cinfo.err->output_message = R_JPGOutputMessage;
+ /* Establish the setjmp return context for R_JPGErrorExit to use. */
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_decompress(&cinfo);
+ ri.FS_FreeFile(fbuffer.v);
+
+ /* Append the filename to the error for easier debugging */
+ ri.Printf(PRINT_ALL, ", loading file %s\n", filename);
+ return;
+ }
+
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
@@ -362,17 +389,29 @@ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
int image_width, int image_height, byte *image_buffer, int padding)
{
struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
+ q_jpeg_error_mgr_t jerr;
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
my_dest_ptr dest;
int row_stride; /* physical row width in image buffer */
size_t outcount;
/* Step 1: allocate and initialize JPEG compression object */
- cinfo.err = jpeg_std_error(&jerr);
+ cinfo.err = jpeg_std_error(&jerr.pub);
cinfo.err->error_exit = R_JPGErrorExit;
cinfo.err->output_message = R_JPGOutputMessage;
+ /* Establish the setjmp return context for R_JPGErrorExit to use. */
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object and return.
+ */
+ jpeg_destroy_compress(&cinfo);
+
+ ri.Printf(PRINT_ALL, "\n");
+ return 0;
+ }
+
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
diff --git a/src/renderergl1/tr_backend.c b/src/renderergl1/tr_backend.c
index 18a033b6..7cd455e8 100644
--- a/src/renderergl1/tr_backend.c
+++ b/src/renderergl1/tr_backend.c
@@ -496,8 +496,6 @@ void RB_BeginDrawingView (void) {
}
-#define MAC_EVENT_PUMP_MSEC 5
-
/*
==================
RB_RenderDrawSurfList
diff --git a/src/renderergl1/tr_cmds.c b/src/renderergl1/tr_cmds.c
index 23aa9897..d92a8b94 100644
--- a/src/renderergl1/tr_cmds.c
+++ b/src/renderergl1/tr_cmds.c
@@ -115,20 +115,20 @@ void R_IssuePendingRenderCommands( void ) {
/*
============
-R_GetCommandBuffer
+R_GetCommandBufferReserved
make sure there is enough command space
============
*/
-void *R_GetCommandBuffer( int bytes ) {
+void *R_GetCommandBufferReserved( int bytes, int reservedBytes ) {
renderCommandList_t *cmdList;
cmdList = &backEndData->commands;
bytes = PAD(bytes, sizeof(void *));
// always leave room for the end of list command
- if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) {
- if ( bytes > MAX_RENDER_COMMANDS - 4 ) {
+ if ( cmdList->used + bytes + sizeof( int ) + reservedBytes > MAX_RENDER_COMMANDS ) {
+ if ( bytes > MAX_RENDER_COMMANDS - sizeof( int ) ) {
ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
}
// if we run out of room, just start dropping commands
@@ -140,6 +140,17 @@ void *R_GetCommandBuffer( int bytes ) {
return cmdList->cmds + cmdList->used - bytes;
}
+/*
+=============
+R_GetCommandBuffer
+
+returns NULL if there is not enough space for important commands
+=============
+*/
+void *R_GetCommandBuffer( int bytes ) {
+ return R_GetCommandBufferReserved( bytes, PAD( sizeof( swapBuffersCommand_t ), sizeof(void *) ) );
+}
+
/*
=============
@@ -540,7 +551,7 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
if ( !tr.registered ) {
return;
}
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
+ cmd = R_GetCommandBufferReserved( sizeof( *cmd ), 0 );
if ( !cmd ) {
return;
}
diff --git a/src/renderergl1/tr_image.c b/src/renderergl1/tr_image.c
index 6f58a5b2..2ed43ef0 100644
--- a/src/renderergl1/tr_image.c
+++ b/src/renderergl1/tr_image.c
@@ -558,6 +558,7 @@ static void Upload32( unsigned *data,
qboolean mipmap,
qboolean picmip,
qboolean lightMap,
+ qboolean allowCompression,
int *format,
int *pUploadWidth, int *pUploadHeight )
{
@@ -693,11 +694,11 @@ static void Upload32( unsigned *data,
}
else
{
- if ( glConfig.textureCompression == TC_S3TC_ARB )
+ if ( allowCompression && glConfig.textureCompression == TC_S3TC_ARB )
{
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
}
- else if ( glConfig.textureCompression == TC_S3TC )
+ else if ( allowCompression && glConfig.textureCompression == TC_S3TC )
{
internalFormat = GL_RGB4_S3TC;
}
@@ -893,6 +894,7 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height,
image->flags & IMGFLAG_MIPMAP,
image->flags & IMGFLAG_PICMIP,
isLightmap,
+ !(image->flags & IMGFLAG_NO_COMPRESSION),
&image->internalFormat,
&image->uploadWidth,
&image->uploadHeight );
@@ -1556,7 +1558,7 @@ 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] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
return hSkin;
}
@@ -1627,7 +1629,7 @@ void R_InitSkins( void ) {
skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name ) );
skin->numSurfaces = 1;
- skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low );
+ skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
skin->surfaces[0]->shader = tr.defaultShader;
}
diff --git a/src/renderergl1/tr_light.c b/src/renderergl1/tr_light.c
index 779451f1..35233739 100644
--- a/src/renderergl1/tr_light.c
+++ b/src/renderergl1/tr_light.c
@@ -152,7 +152,7 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
frac[i] = v - pos[i];
if ( pos[i] < 0 ) {
pos[i] = 0;
- } else if ( pos[i] >= tr.world->lightGridBounds[i] - 1 ) {
+ } else if ( pos[i] > tr.world->lightGridBounds[i] - 1 ) {
pos[i] = tr.world->lightGridBounds[i] - 1;
}
}
@@ -183,6 +183,9 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
data = gridData;
for ( j = 0 ; j < 3 ; j++ ) {
if ( i & (1<<j) ) {
+ if ( pos[j] + 1 > tr.world->lightGridBounds[j] - 1 ) {
+ break; // ignore values outside lightgrid
+ }
factor *= frac[j];
data += gridStep[j];
} else {
@@ -190,6 +193,9 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent ) {
}
}
+ if ( j != 3 ) {
+ continue;
+ }
if ( !(data[0]+data[1]+data[2]) ) {
continue; // ignore samples in walls
}
diff --git a/src/renderergl1/tr_local.h b/src/renderergl1/tr_local.h
index 6264af82..0d8131ec 100644
--- a/src/renderergl1/tr_local.h
+++ b/src/renderergl1/tr_local.h
@@ -1406,20 +1406,6 @@ int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
/*
=============================================================
-
-IMAGE LOADERS
-
-=============================================================
-*/
-
-void R_LoadBMP( const char *name, byte **pic, int *width, int *height );
-void R_LoadJPG( const char *name, byte **pic, int *width, int *height );
-void R_LoadPCX( const char *name, byte **pic, int *width, int *height );
-void R_LoadPNG( const char *name, byte **pic, int *width, int *height );
-void R_LoadTGA( const char *name, byte **pic, int *width, int *height );
-
-/*
-=============================================================
=============================================================
*/
void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
diff --git a/src/renderergl1/tr_main.c b/src/renderergl1/tr_main.c
index 500bb788..7df28230 100644
--- a/src/renderergl1/tr_main.c
+++ b/src/renderergl1/tr_main.c
@@ -1012,6 +1012,10 @@ int R_SpriteFogNum( trRefEntity_t *ent ) {
return 0;
}
+ if ( ent->e.renderfx & RF_CROSSHAIR ) {
+ return 0;
+ }
+
for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
fog = &tr.world->fogs[i];
for ( j = 0 ; j < 3 ; j++ ) {
@@ -1143,13 +1147,6 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
return;
}
- // if we overflowed MAX_DRAWSURFS, the drawsurfs
- // wrapped around in the buffer and we will be missing
- // the first surfaces, not the last ones
- if ( numDrawSurfs > MAX_DRAWSURFS ) {
- numDrawSurfs = MAX_DRAWSURFS;
- }
-
// sort the drawsurfs by sort type, then orientation, then shader
R_RadixSort( drawSurfs, numDrawSurfs );
@@ -1358,6 +1355,7 @@ or a mirror / remote location
*/
void R_RenderView (viewParms_t *parms) {
int firstDrawSurf;
+ int numDrawSurfs;
if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
return;
@@ -1380,7 +1378,15 @@ void R_RenderView (viewParms_t *parms) {
R_GenerateDrawSurfs();
- R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
+ // if we overflowed MAX_DRAWSURFS, the drawsurfs
+ // wrapped around in the buffer and we will be missing
+ // the first surfaces, not the last ones
+ numDrawSurfs = tr.refdef.numDrawSurfs;
+ if ( numDrawSurfs > MAX_DRAWSURFS ) {
+ numDrawSurfs = MAX_DRAWSURFS;
+ }
+
+ R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, numDrawSurfs - firstDrawSurf );
// draw main system development information (surface outlines, etc)
R_DebugGraphics();
diff --git a/src/renderergl1/tr_shader.c b/src/renderergl1/tr_shader.c
index 2a66afd0..34d6d64e 100644
--- a/src/renderergl1/tr_shader.c
+++ b/src/renderergl1/tr_shader.c
@@ -1569,6 +1569,23 @@ static qboolean ParseShader( char **text )
return qfalse;
}
+ if ( r_greyscale->integer )
+ {
+ float luminance;
+
+ luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
+ VectorSet( shader.fogParms.color, luminance, luminance, luminance );
+ }
+ else if ( r_greyscale->value )
+ {
+ float luminance;
+
+ luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
+ shader.fogParms.color[0] = LERP( shader.fogParms.color[0], luminance, r_greyscale->value );
+ shader.fogParms.color[1] = LERP( shader.fogParms.color[1], luminance, r_greyscale->value );
+ shader.fogParms.color[2] = LERP( shader.fogParms.color[2], luminance, r_greyscale->value );
+ }
+
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
{
diff --git a/src/renderergl2/glsl/calclevels4x_fp.glsl b/src/renderergl2/glsl/calclevels4x_fp.glsl
index 1de59e9f..8246c4b3 100644
--- a/src/renderergl2/glsl/calclevels4x_fp.glsl
+++ b/src/renderergl2/glsl/calclevels4x_fp.glsl
@@ -14,8 +14,8 @@ vec3 GetValues(vec2 offset, vec3 current)
#ifdef FIRST_PASS
- #if defined(r_framebufferGamma)
- minAvgMax = pow(minAvgMax, vec3(r_framebufferGamma));
+ #if defined(USE_PBR)
+ minAvgMax *= minAvgMax;
#endif
float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001);
diff --git a/src/renderergl2/glsl/depthblur_fp.glsl b/src/renderergl2/glsl/depthblur_fp.glsl
index 93895b4e..d71b3487 100644
--- a/src/renderergl2/glsl/depthblur_fp.glsl
+++ b/src/renderergl2/glsl/depthblur_fp.glsl
@@ -1,58 +1,82 @@
uniform sampler2D u_ScreenImageMap;
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;
+//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[3] = float[3](0.60, 0.19, 0.0066);
-#define GAUSS_SIZE 4
+#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)
{
- float scale = 1.0 / 256.0;
+
+#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];
float total = gauss[0];
+#else
+ vec4 result = texture2D(imageMap, tex);
+ float total = 1.0;
+#endif
+ float zLimit = 5.0 / zFar;
int i, j;
for (i = 0; i < 2; i++)
{
- for (j = 1; j < GAUSS_SIZE; j++)
+ 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)
- {
- 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
+ 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/src/renderergl2/glsl/depthblur_vp.glsl b/src/renderergl2/glsl/depthblur_vp.glsl
index 9c46a79f..9c47660c 100644
--- a/src/renderergl2/glsl/depthblur_vp.glsl
+++ b/src/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/src/renderergl2/glsl/lightall_fp.glsl b/src/renderergl2/glsl/lightall_fp.glsl
index d1182781..64cae3fa 100644
--- a/src/renderergl2/glsl/lightall_fp.glsl
+++ b/src/renderergl2/glsl/lightall_fp.glsl
@@ -29,11 +29,6 @@ uniform samplerCube u_CubeMap;
uniform vec4 u_EnableTextures;
#endif
-#if defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT)
-uniform vec3 u_DirectedLight;
-uniform vec3 u_AmbientLight;
-#endif
-
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
uniform vec3 u_PrimaryLightColor;
uniform vec3 u_PrimaryLightAmbient;
@@ -53,6 +48,9 @@ uniform vec4 u_CubeMapInfo;
varying vec4 var_TexCoords;
varying vec4 var_Color;
+#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
+varying vec4 var_ColorAmbient;
+#endif
#if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT))
#if defined(USE_VERT_TANGENT_SPACE)
@@ -150,156 +148,35 @@ float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)
}
#endif
-vec3 CalcDiffuse(vec3 diffuseAlbedo, vec3 N, vec3 L, vec3 E, float NE, float NL, float shininess)
+vec3 CalcDiffuse(vec3 diffuseAlbedo, float NH, float EH, float roughness)
{
- #if defined(USE_OREN_NAYAR) || defined(USE_TRIACE_OREN_NAYAR)
- float gamma = dot(E, L) - NE * NL;
- float B = 2.22222 + 0.1 * shininess;
-
- #if defined(USE_OREN_NAYAR)
- float A = 1.0 - 1.0 / (2.0 + 0.33 * shininess);
- gamma = clamp(gamma, 0.0, 1.0);
- #endif
-
- #if defined(USE_TRIACE_OREN_NAYAR)
- float A = 1.0 - 1.0 / (2.0 + 0.65 * shininess);
-
- if (gamma >= 0.0)
- #endif
- {
- B = max(B * max(NL, NE), EPSILON);
- }
-
- return diffuseAlbedo * (A + gamma / B);
- #else
- return diffuseAlbedo;
- #endif
-}
-
-vec3 EnvironmentBRDF(float gloss, float NE, vec3 specular)
-{
- #if 1
- // from http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
- vec4 t = vec4( 1.0/0.96, 0.475, (0.0275 - 0.25 * 0.04)/0.96,0.25 ) * gloss;
- t += vec4( 0.0, 0.0, (0.015 - 0.75 * 0.04)/0.96,0.75 );
- float a0 = t.x * min( t.y, exp2( -9.28 * NE ) ) + t.z;
- float a1 = t.w;
- return clamp( a0 + specular * ( a1 - a0 ), 0.0, 1.0 );
- #elif 0
- // from http://seblagarde.wordpress.com/2011/08/17/hello-world/
- return specular + CalcFresnel(NE) * clamp(vec3(gloss) - specular, 0.0, 1.0);
- #else
- // from http://advances.realtimerendering.com/s2011/Lazarov-Physically-Based-Lighting-in-Black-Ops%20%28Siggraph%202011%20Advances%20in%20Real-Time%20Rendering%20Course%29.pptx
- return mix(specular.rgb, vec3(1.0), CalcFresnel(NE) / (4.0 - 3.0 * gloss));
- #endif
-}
-
-float CalcBlinn(float NH, float shininess)
-{
-#if defined(USE_BLINN) || defined(USE_BLINN_FRESNEL)
- // Normalized Blinn-Phong
- float norm = shininess * 0.125 + 1.0;
-#elif defined(USE_MCAULEY)
- // Cook-Torrance as done by Stephen McAuley
- // http://blog.selfshadow.com/publications/s2012-shading-course/mcauley/s2012_pbs_farcry3_notes_v2.pdf
- float norm = shininess * 0.25 + 0.125;
-#elif defined(USE_GOTANDA)
- // Neumann-Neumann as done by Yoshiharu Gotanda
- // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf
- float norm = shininess * 0.124858 + 0.269182;
-#elif defined(USE_LAZAROV)
- // Cook-Torrance as done by Dimitar Lazarov
- // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
- float norm = shininess * 0.125 + 0.25;
-#else
- float norm = 1.0;
-#endif
-
-#if 0
- // from http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/
- float a = shininess + 0.775;
- return norm * exp(a * NH - a);
+#if defined(USE_BURLEY)
+ // modified from https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf
+ float fd90 = -0.5 + EH * EH * roughness;
+ float burley = 1.0 + fd90 * 0.04 / NH;
+ burley *= burley;
+ return diffuseAlbedo * burley;
#else
- return norm * pow(NH, shininess);
-#endif
-}
-
-float CalcGGX(float NH, float gloss)
-{
- // from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
- float a_sq = exp2(gloss * -13.0 + 1.0);
- float d = ((NH * NH) * (a_sq - 1.0) + 1.0);
- return a_sq / (d * d);
-}
-
-float CalcFresnel(float EH)
-{
-#if 1
- // From http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
- // not accurate, but fast
- return exp2(-10.0 * EH);
-#elif 0
- // From http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/
- return exp2((-5.55473 * EH - 6.98316) * EH);
-#elif 0
- float blend = 1.0 - EH;
- float blend2 = blend * blend;
- blend *= blend2 * blend2;
-
- return blend;
-#else
- return pow(1.0 - EH, 5.0);
+ return diffuseAlbedo;
#endif
}
-float CalcVisibility(float NH, float NL, float NE, float EH, float gloss)
+vec3 EnvironmentBRDF(float roughness, float NE, vec3 specular)
{
-#if defined(USE_GOTANDA)
- // Neumann-Neumann as done by Yoshiharu Gotanda
- // http://research.tri-ace.com/Data/s2012_beyond_CourseNotes.pdf
- return 1.0 / max(max(NL, NE), EPSILON);
-#elif defined(USE_LAZAROV)
- // Cook-Torrance as done by Dimitar Lazarov
- // http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf
- float k = min(1.0, gloss + 0.545);
- return 1.0 / (k * (EH * EH - 1.0) + 1.0);
-#elif defined(USE_GGX)
- float roughness = exp2(gloss * -6.5);
-
- // Modified from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
- // NL, NE in numerator factored out from cook-torrance
- float k = roughness + 1.0;
- k *= k * 0.125;
-
- float k2 = 1.0 - k;
-
- float invGeo1 = NL * k2 + k;
- float invGeo2 = NE * k2 + k;
-
- return 1.0 / (invGeo1 * invGeo2);
-#else
- return 1.0;
-#endif
+ // from http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
+ float v = 1.0 - max(roughness, NE);
+ v *= v * v;
+ return vec3(v) + specular;
}
-
-vec3 CalcSpecular(vec3 specular, float NH, float NL, float NE, float EH, float gloss, float shininess)
+vec3 CalcSpecular(vec3 specular, float NH, float EH, float roughness)
{
-#if defined(USE_GGX)
- float distrib = CalcGGX(NH, gloss);
-#else
- float distrib = CalcBlinn(NH, shininess);
-#endif
-
-#if defined(USE_BLINN)
- vec3 fSpecular = specular;
-#else
- vec3 fSpecular = mix(specular, vec3(1.0), CalcFresnel(EH));
-#endif
-
- float vis = CalcVisibility(NH, NL, NE, EH, gloss);
-
- return fSpecular * (distrib * vis);
+ // from http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
+ float rr = roughness*roughness;
+ float rrrr = rr*rr;
+ float d = (NH * NH) * (rrrr - 1.0) + 1.0;
+ float v = (EH * EH) * (roughness + 0.5);
+ return specular * (rrrr / (4.0 * d * d * v));
}
@@ -341,7 +218,7 @@ mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv )
void main()
{
- vec3 viewDir, lightColor, ambientColor;
+ vec3 viewDir, lightColor, ambientColor, reflectance;
vec3 L, N, E, H;
float NL, NH, NE, EH, attenuation;
@@ -353,21 +230,20 @@ void main()
mat3 tangentToWorld = cotangent_frame(var_Normal, -var_ViewDir, var_TexCoords.xy);
viewDir = var_ViewDir;
#endif
-
E = normalize(viewDir);
-
- L = var_LightDir.xyz;
- #if defined(USE_DELUXEMAP)
- L += (texture2D(u_DeluxeMap, var_TexCoords.zw).xyz - vec3(0.5)) * u_EnableTextures.y;
- #endif
- float sqrLightDist = dot(L, L);
#endif
+ lightColor = var_Color.rgb;
+
#if defined(USE_LIGHTMAP)
vec4 lightmapColor = texture2D(u_LightMap, var_TexCoords.zw);
#if defined(RGBM_LIGHTMAP)
lightmapColor.rgb *= lightmapColor.a;
#endif
+ #if defined(USE_PBR) && !defined(USE_FAST_LIGHT)
+ lightmapColor.rgb *= lightmapColor.rgb;
+ #endif
+ lightColor *= lightmapColor.rgb;
#endif
vec2 texCoords = var_TexCoords.xy;
@@ -383,17 +259,16 @@ void main()
vec4 diffuse = texture2D(u_DiffuseMap, texCoords);
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
- #if defined(USE_LIGHTMAP)
- lightColor = lightmapColor.rgb * var_Color.rgb;
- ambientColor = vec3(0.0);
- attenuation = 1.0;
- #elif defined(USE_LIGHT_VECTOR)
- lightColor = u_DirectedLight * var_Color.rgb;
- ambientColor = u_AmbientLight * var_Color.rgb;
+ L = var_LightDir.xyz;
+ #if defined(USE_DELUXEMAP)
+ L += (texture2D(u_DeluxeMap, var_TexCoords.zw).xyz - vec3(0.5)) * u_EnableTextures.y;
+ #endif
+ float sqrLightDist = dot(L, L);
+ L /= sqrt(sqrLightDist);
+
+ #if defined(USE_LIGHT_VECTOR)
attenuation = CalcLightAttenuation(float(var_LightDir.w > 0.0), var_LightDir.w / sqrLightDist);
- #elif defined(USE_LIGHT_VERTEX)
- lightColor = var_Color.rgb;
- ambientColor = vec3(0.0);
+ #else
attenuation = 1.0;
#endif
@@ -411,33 +286,20 @@ void main()
#endif
N = normalize(N);
- L /= sqrt(sqrLightDist);
#if defined(USE_SHADOWMAP)
vec2 shadowTex = gl_FragCoord.xy * r_FBufScale;
float shadowValue = texture2D(u_ShadowMap, shadowTex).r;
// surfaces not facing the light are always shadowed
- shadowValue *= float(dot(var_Normal.xyz, var_PrimaryLightDir.xyz) > 0.0);
+ shadowValue *= clamp(dot(N, var_PrimaryLightDir.xyz), 0.0, 1.0);
#if defined(SHADOWMAP_MODULATE)
- //vec3 shadowColor = min(u_PrimaryLightAmbient, lightColor);
- vec3 shadowColor = u_PrimaryLightAmbient * lightColor;
-
- #if 0
- // Only shadow when the world light is parallel to the primary light
- shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDir.xyz), 0.0, 1.0);
- #endif
- lightColor = mix(shadowColor, lightColor, shadowValue);
+ lightColor *= shadowValue * (1.0 - u_PrimaryLightAmbient.r) + u_PrimaryLightAmbient.r;
#endif
#endif
- #if defined(r_lightGamma)
- lightColor = pow(lightColor, vec3(r_lightGamma));
- ambientColor = pow(ambientColor, vec3(r_lightGamma));
- #endif
-
- #if defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX)
+ #if !defined(USE_LIGHT_VECTOR)
ambientColor = lightColor;
float surfNL = clamp(dot(var_Normal.xyz, L), 0.0, 1.0);
@@ -447,10 +309,10 @@ void main()
// Recover any unused light as ambient, in case attenuation is over 4x or
// light is below the surface
- ambientColor = clamp(ambientColor - lightColor * surfNL, 0.0, 1.0);
+ ambientColor = max(ambientColor - lightColor * surfNL, vec3(0.0));
+ #else
+ ambientColor = var_ColorAmbient.rgb;
#endif
-
- vec3 reflectance;
NL = clamp(dot(N, L), 0.0, 1.0);
NE = clamp(dot(N, E), 0.0, 1.0);
@@ -460,70 +322,47 @@ void main()
#else
vec4 specular = vec4(1.0);
#endif
-
specular *= u_SpecularScale;
- #if defined(r_materialGamma)
- diffuse.rgb = pow(diffuse.rgb, vec3(r_materialGamma));
- specular.rgb = pow(specular.rgb, vec3(r_materialGamma));
+ #if defined(USE_PBR)
+ diffuse.rgb *= diffuse.rgb;
#endif
+ #if defined(USE_PBR)
+ // diffuse rgb is base color
+ // specular red is gloss
+ // specular green is metallicness
+ float gloss = specular.r;
+ 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
+ // specular alpha is gloss
float gloss = specular.a;
- float shininess = exp2(gloss * 13.0);
-
- #if defined(SPECULAR_IS_METALLIC)
- // diffuse is actually base color, and red of specular is metallicness
- float metallic = specular.r;
- specular.rgb = (0.96 * metallic) * diffuse.rgb + vec3(0.04);
- diffuse.rgb *= 1.0 - metallic;
- #else
// adjust diffuse by specular reflectance, to maintain energy conservation
diffuse.rgb *= vec3(1.0) - specular.rgb;
#endif
- reflectance = CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess);
-
- #if defined(r_deluxeSpecular) || defined(USE_LIGHT_VECTOR)
- float adjGloss = gloss;
- float adjShininess = shininess;
-
- #if !defined(USE_LIGHT_VECTOR)
- adjGloss *= r_deluxeSpecular;
- adjShininess = exp2(adjGloss * 13.0);
- #endif
-
- 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_LIGHT_VECTOR)
- reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess) * r_deluxeSpecular;
- #else
- reflectance += CalcSpecular(specular.rgb, NH, NL, NE, EH, adjGloss, adjShininess);
- #endif
+ #if defined(GLOSS_IS_GLOSS)
+ float roughness = exp2(-3.0 * gloss);
+ #elif defined(GLOSS_IS_SMOOTHNESS)
+ float roughness = 1.0 - gloss;
+ #elif defined(GLOSS_IS_ROUGHNESS)
+ float roughness = gloss;
+ #elif defined(GLOSS_IS_SHININESS)
+ float roughness = pow(2.0 / (8190.0 * gloss + 2.0), 0.25);
#endif
- gl_FragColor.rgb = lightColor * reflectance * (attenuation * NL);
-
-#if 0
- vec3 aSpecular = EnvironmentBRDF(gloss, NE, specular.rgb);
-
- // do ambient as two hemisphere lights, one straight up one straight down
- float hemiDiffuseUp = N.z * 0.5 + 0.5;
- float hemiDiffuseDown = 1.0 - hemiDiffuseUp;
- float hemiSpecularUp = mix(hemiDiffuseUp, float(N.z >= 0.0), gloss);
- float hemiSpecularDown = 1.0 - hemiSpecularUp;
+ reflectance = CalcDiffuse(diffuse.rgb, NH, EH, roughness);
- gl_FragColor.rgb += ambientColor * 0.75 * (diffuse.rgb * hemiDiffuseUp + aSpecular * hemiSpecularUp);
- gl_FragColor.rgb += ambientColor * 0.25 * (diffuse.rgb * hemiDiffuseDown + aSpecular * hemiSpecularDown);
-#else
- gl_FragColor.rgb += ambientColor * (diffuse.rgb + specular.rgb);
-#endif
+ gl_FragColor.rgb = lightColor * reflectance * (attenuation * NL);
+ gl_FragColor.rgb += ambientColor * diffuse.rgb;
#if defined(USE_CUBEMAP)
- reflectance = EnvironmentBRDF(gloss, NE, specular.rgb);
+ reflectance = EnvironmentBRDF(roughness, NE, specular.rgb);
vec3 R = reflect(E, N);
@@ -531,15 +370,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 - gloss * 7.0).rgb * u_EnableTextures.w;
+ vec3 cubeLightColor = textureCubeLod(u_CubeMap, R + parallax, 7.0 * roughness).rgb * u_EnableTextures.w;
// normalize cubemap based on lowest 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);
//cubeLightColor /= dot(cubeLightDiffuse, vec3(0.2125, 0.7154, 0.0721));
- #if defined(r_framebufferGamma)
- cubeLightColor = pow(cubeLightColor, vec3(r_framebufferGamma));
+ #if defined(USE_PBR)
+ cubeLightColor *= cubeLightColor;
#endif
// multiply cubemap values by lighting
@@ -549,7 +388,7 @@ void main()
gl_FragColor.rgb += cubeLightColor * reflectance;
#endif
- #if defined(USE_PRIMARY_LIGHT)
+ #if defined(USE_PRIMARY_LIGHT) || defined(SHADOWMAP_MODULATE)
vec3 L2, H2;
float NL2, EH2, NH2;
@@ -560,20 +399,19 @@ void main()
//L2 /= sqrt(sqrLightDist);
NL2 = clamp(dot(N, L2), 0.0, 1.0);
-
H2 = normalize(L2 + E);
EH2 = clamp(dot(E, H2), 0.0, 1.0);
NH2 = clamp(dot(N, H2), 0.0, 1.0);
- reflectance = CalcDiffuse(diffuse.rgb, N, L2, E, NE, NL2, shininess);
- reflectance += CalcSpecular(specular.rgb, NH2, NL2, NE, EH2, gloss, shininess);
-
- lightColor = u_PrimaryLightColor * var_Color.rgb;
+ reflectance = CalcSpecular(specular.rgb, NH2, EH2, roughness);
- #if defined(r_lightGamma)
- lightColor = pow(lightColor, vec3(r_lightGamma));
+ // bit of a hack, with modulated shadowmaps, ignore diffuse
+ #if !defined(SHADOWMAP_MODULATE)
+ reflectance += CalcDiffuse(diffuse.rgb, NH2, EH2, roughness);
#endif
+ lightColor = u_PrimaryLightColor;
+
#if defined(USE_SHADOWMAP)
lightColor *= shadowValue;
#endif
@@ -583,28 +421,16 @@ void main()
gl_FragColor.rgb += lightColor * reflectance * NL2;
#endif
-#else
- lightColor = var_Color.rgb;
-
- #if defined(USE_LIGHTMAP)
- lightColor *= lightmapColor.rgb;
- #endif
- #if defined(r_lightGamma)
- lightColor = pow(lightColor, vec3(r_lightGamma));
+ #if defined(USE_PBR)
+ gl_FragColor.rgb = sqrt(gl_FragColor.rgb);
#endif
- #if defined(r_materialGamma)
- diffuse.rgb = pow(diffuse.rgb, vec3(r_materialGamma));
- #endif
+#else
gl_FragColor.rgb = diffuse.rgb * lightColor;
#endif
-#if defined(r_framebufferGamma)
- gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1.0 / r_framebufferGamma));
-#endif
-
gl_FragColor.a = diffuse.a * var_Color.a;
}
diff --git a/src/renderergl2/glsl/lightall_vp.glsl b/src/renderergl2/glsl/lightall_vp.glsl
index 59051d7c..783885e9 100644
--- a/src/renderergl2/glsl/lightall_vp.glsl
+++ b/src/renderergl2/glsl/lightall_vp.glsl
@@ -57,10 +57,8 @@ uniform float u_VertexLerp;
#if defined(USE_LIGHT_VECTOR)
uniform vec4 u_LightOrigin;
uniform float u_LightRadius;
- #if defined(USE_FAST_LIGHT)
uniform vec3 u_DirectedLight;
uniform vec3 u_AmbientLight;
- #endif
#endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
@@ -71,6 +69,9 @@ uniform float u_PrimaryLightRadius;
varying vec4 var_TexCoords;
varying vec4 var_Color;
+#if defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT)
+varying vec4 var_ColorAmbient;
+#endif
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
#if defined(USE_VERT_TANGENT_SPACE)
@@ -208,12 +209,24 @@ void main()
var_Color = u_VertColor * attr_Color + u_BaseColor;
-#if defined(USE_LIGHT_VECTOR) && defined(USE_FAST_LIGHT)
+#if defined(USE_LIGHT_VECTOR)
+ #if defined(USE_FAST_LIGHT)
float sqrLightDist = dot(L, L);
- float attenuation = CalcLightAttenuation(u_LightOrigin.w, u_LightRadius * u_LightRadius / sqrLightDist);
float NL = clamp(dot(normalize(normal), L) / sqrt(sqrLightDist), 0.0, 1.0);
+ float attenuation = CalcLightAttenuation(u_LightOrigin.w, u_LightRadius * u_LightRadius / sqrLightDist);
var_Color.rgb *= u_DirectedLight * (attenuation * NL) + u_AmbientLight;
+ #else
+ var_ColorAmbient.rgb = u_AmbientLight * var_Color.rgb;
+ var_Color.rgb *= u_DirectedLight;
+ #if defined(USE_PBR)
+ var_ColorAmbient.rgb *= var_ColorAmbient.rgb;
+ #endif
+ #endif
+#endif
+
+#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) && defined(USE_PBR)
+ var_Color.rgb *= var_Color.rgb;
#endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
diff --git a/src/renderergl2/glsl/ssao_fp.glsl b/src/renderergl2/glsl/ssao_fp.glsl
index 6263284c..93f61859 100644
--- a/src/renderergl2/glsl/ssao_fp.glsl
+++ b/src/renderergl2/glsl/ssao_fp.glsl
@@ -1,6 +1,6 @@
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;
@@ -11,6 +11,7 @@ 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)
);
+#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 +40,47 @@ 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;
- float sampleZ = zFar * getLinearDepth(depthMap, tex, zFarDivZNear);
+ float sampleZ = getLinearDepth(depthMap, tex, zFarDivZNear);
+ float scaleZ = zFarDivZNear * sampleZ;
- vec2 expectedSlope = vec2(dFdx(sampleZ), dFdy(sampleZ)) / vec2(dFdx(tex.x), dFdy(tex.y));
-
- if (length(expectedSlope) > 5000.0)
+ 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);
-
- if (abs(sampleZ - sampleZ2) > 20.0)
- result += 1.0;
- else
- {
- float expectedZ = sampleZ + dot(expectedSlope, offset);
- result += step(expectedZ - 1.0, sampleZ2);
- }
+ float sampleDiff = getLinearDepth(depthMap, tex + offset, zFarDivZNear) - sampleZ;
+
+ 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/src/renderergl2/glsl/tonemap_fp.glsl b/src/renderergl2/glsl/tonemap_fp.glsl
index 1368c5bd..9e24e24a 100644
--- a/src/renderergl2/glsl/tonemap_fp.glsl
+++ b/src/renderergl2/glsl/tonemap_fp.glsl
@@ -28,8 +28,8 @@ void main()
{
vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color;
-#if defined(r_framebufferGamma)
- color.rgb = pow(color.rgb, vec3(r_framebufferGamma));
+#if defined(USE_PBR)
+ color.rgb *= color.rgb;
#endif
vec3 minAvgMax = texture2D(u_LevelsMap, var_TexCoords).rgb;
@@ -46,9 +46,12 @@ void main()
color.rgb = clamp(color.rgb * var_InvWhite, 0.0, 1.0);
-#if defined(r_tonemapGamma)
- color.rgb = pow(color.rgb, vec3(1.0 / r_tonemapGamma));
+#if defined(USE_PBR)
+ color.rgb = sqrt(color.rgb);
#endif
+ // add a bit of dither to reduce banding
+ color.rgb += vec3(1.0/510.0 * mod(gl_FragCoord.x + gl_FragCoord.y, 2.0) - 1.0/1020.0);
+
gl_FragColor = color;
}
diff --git a/src/renderergl2/tr_backend.c b/src/renderergl2/tr_backend.c
index 6c03db3c..0e331752 100644
--- a/src/renderergl2/tr_backend.c
+++ b/src/renderergl2/tr_backend.c
@@ -21,6 +21,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
+#include "tr_fbo.h"
+#include "tr_dsa.h"
backEndData_t *backEndData;
backEndState_t backEnd;
@@ -37,80 +39,27 @@ static float s_flipMatrix[16] = {
/*
-** GL_Bind
-*/
-void GL_Bind( image_t *image ) {
- int texnum;
-
- if ( !image ) {
- ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" );
- texnum = tr.defaultImage->texnum;
- } else {
- texnum = image->texnum;
- }
-
- if ( r_nobind->integer && tr.dlightImage ) { // performance evaluation option
- texnum = tr.dlightImage->texnum;
- }
-
- if ( glState.currenttextures[glState.currenttmu] != texnum ) {
- if ( image ) {
- image->frameUsed = tr.frameCount;
- }
- glState.currenttextures[glState.currenttmu] = texnum;
- if (image && image->flags & IMGFLAG_CUBEMAP)
- qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum );
- else
- qglBindTexture( GL_TEXTURE_2D, texnum );
- }
-}
-
-/*
-** GL_SelectTexture
-*/
-void GL_SelectTexture( int unit )
-{
- if ( glState.currenttmu == unit )
- {
- return;
- }
-
- if (!(unit >= 0 && unit <= 31))
- ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit );
-
- if (!qglActiveTextureARB)
- ri.Error( ERR_DROP, "GL_SelectTexture: multitexture disabled" );
-
- qglActiveTextureARB( GL_TEXTURE0_ARB + unit );
-
- glState.currenttmu = unit;
-}
-
-/*
** GL_BindToTMU
*/
void GL_BindToTMU( image_t *image, int tmu )
{
- int texnum;
- int oldtmu = glState.currenttmu;
+ GLuint texture = (tmu == TB_COLORMAP) ? tr.defaultImage->texnum : 0;
+ GLenum target = GL_TEXTURE_2D;
- if (!image)
- texnum = 0;
- else
- texnum = image->texnum;
-
- if ( glState.currenttextures[tmu] != texnum ) {
- GL_SelectTexture( tmu );
- if (image)
- image->frameUsed = tr.frameCount;
- glState.currenttextures[tmu] = texnum;
+ if (image)
+ {
+ if (image->flags & IMGFLAG_CUBEMAP)
+ target = GL_TEXTURE_CUBE_MAP;
- if (image && (image->flags & IMGFLAG_CUBEMAP))
- qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum );
- else
- qglBindTexture( GL_TEXTURE_2D, texnum );
- GL_SelectTexture( oldtmu );
+ image->frameUsed = tr.frameCount;
+ texture = image->texnum;
+ }
+ else
+ {
+ ri.Printf(PRINT_WARNING, "GL_BindToTMU: NULL image\n");
}
+
+ GL_BindMultiTexture(GL_TEXTURE0_ARB + tmu, target, texture);
}
@@ -143,39 +92,6 @@ void GL_Cull( int cullType ) {
}
/*
-** GL_TexEnv
-*/
-void GL_TexEnv( int env )
-{
- if ( env == glState.texEnv[glState.currenttmu] )
- {
- return;
- }
-
- glState.texEnv[glState.currenttmu] = env;
-
-
- switch ( env )
- {
- case GL_MODULATE:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
- break;
- case GL_REPLACE:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
- break;
- case GL_DECAL:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
- break;
- case GL_ADD:
- qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
- break;
- default:
- ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed", env );
- break;
- }
-}
-
-/*
** GL_State
**
** This routine is responsible for setting the most commonly changed state
@@ -463,30 +379,20 @@ void RB_BeginDrawingView (void) {
if (glRefConfig.framebufferObject)
{
+ FBO_t *fbo = backEnd.viewParms.targetFbo;
+
// FIXME: HUGE HACK: render to the screen fbo if we've already postprocessed the frame and aren't drawing more world
// drawing more world check is in case of double renders, such as skyportals
- if (backEnd.viewParms.targetFbo == NULL)
+ if (fbo == NULL && !(backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)))
+ fbo = tr.renderFbo;
+
+ if (tr.renderCubeFbo && fbo == tr.renderCubeFbo)
{
- if (!tr.renderFbo || (backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)))
- {
- FBO_Bind(NULL);
- }
- else
- {
- FBO_Bind(tr.renderFbo);
- }
+ cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
+ FBO_AttachImage(fbo, cubemap->image, GL_COLOR_ATTACHMENT0_EXT, backEnd.viewParms.targetFboLayer);
}
- else
- {
- FBO_Bind(backEnd.viewParms.targetFbo);
- // FIXME: hack for cubemap testing
- if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
- {
- //qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0);
- qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex]->texnum, 0);
- }
- }
+ FBO_Bind(fbo);
}
//
@@ -550,8 +456,6 @@ void RB_BeginDrawingView (void) {
}
-#define MAC_EVENT_PUMP_MSEC 5
-
/*
==================
RB_RenderDrawSurfList
@@ -857,6 +761,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
}
RE_UploadCinematic (w, h, cols, rows, data, client, dirty);
+ GL_BindToTMU(tr.scratchImage[client], TB_COLORMAP);
if ( r_speeds->integer ) {
end = ri.Milliseconds();
@@ -866,14 +771,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
// FIXME: HUGE hack
if (glRefConfig.framebufferObject)
{
- if (!tr.renderFbo || backEnd.framePostProcessed)
- {
- FBO_Bind(NULL);
- }
- else
- {
- FBO_Bind(tr.renderFbo);
- }
+ FBO_Bind(backEnd.framePostProcessed ? NULL : tr.renderFbo);
}
RB_SetGL2D();
@@ -897,23 +795,30 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
}
void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
+ GLuint texture;
+
+ if (!tr.scratchImage[client])
+ {
+ ri.Printf(PRINT_WARNING, "RE_UploadCinematic: scratch images not initialized\n");
+ return;
+ }
- GL_Bind( tr.scratchImage[client] );
+ texture = tr.scratchImage[client]->texnum;
// 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 );
+ 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);
} 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 );
+ qglTextureSubImage2D(texture, GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data);
}
}
}
@@ -952,16 +857,7 @@ const void *RB_StretchPic ( const void *data ) {
// FIXME: HUGE hack
if (glRefConfig.framebufferObject)
- {
- if (!tr.renderFbo || backEnd.framePostProcessed)
- {
- FBO_Bind(NULL);
- }
- else
- {
- FBO_Bind(tr.renderFbo);
- }
- }
+ FBO_Bind(backEnd.framePostProcessed ? NULL : tr.renderFbo);
RB_SetGL2D();
@@ -1061,6 +957,9 @@ const void *RB_DrawSurfs( const void *data ) {
if (glRefConfig.framebufferObject && !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL) && (r_depthPrepass->integer || (backEnd.viewParms.flags & VPF_DEPTHSHADOW)))
{
FBO_t *oldFbo = glState.currentFBO;
+ vec4_t viewInfo;
+
+ VectorSet4(viewInfo, backEnd.viewParms.zFar / r_znear->value, backEnd.viewParms.zFar, 0.0, 0.0);
backEnd.depthFill = qtrue;
qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
@@ -1073,17 +972,20 @@ const void *RB_DrawSurfs( const void *data ) {
// 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)
+ else if (tr.renderFbo == NULL && tr.renderDepthImage)
{
// If we're rendering directly to the screen, copy the depth to a texture
- GL_BindToTMU(tr.renderDepthImage, 0);
- qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0);
+ qglCopyTextureImage2D(tr.renderDepthImage->texnum, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0);
}
- if (r_ssao->integer)
+ if (tr.hdrDepthFbo)
{
// 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);
+ vec4_t srcTexCoords;
+
+ 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)
@@ -1148,15 +1050,12 @@ const void *RB_DrawSurfs( const void *data ) {
GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg);
{
- vec4_t viewInfo;
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);
- float zmin = r_znear->value;
-
VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector);
GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector);
VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector);
@@ -1164,13 +1063,38 @@ const void *RB_DrawSurfs( const void *data ) {
VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector);
GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector);
- VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
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)
@@ -1178,6 +1102,10 @@ const void *RB_DrawSurfs( const void *data ) {
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);
@@ -1199,20 +1127,14 @@ const void *RB_DrawSurfs( const void *data ) {
GL_BindToTMU(tr.hdrDepthImage, TB_COLORMAP);
- {
- vec4_t viewInfo;
-
- float zmax = backEnd.viewParms.zFar;
- float zmin = r_znear->value;
-
- VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
- GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo);
- }
+ 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);
@@ -1223,16 +1145,7 @@ const void *RB_DrawSurfs( const void *data ) {
GL_BindToTMU(tr.quarterImage[0], TB_COLORMAP);
GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
- {
- vec4_t viewInfo;
-
- float zmax = backEnd.viewParms.zFar;
- float zmin = r_znear->value;
-
- VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
- GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
- }
+ GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo);
RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
@@ -1247,16 +1160,7 @@ const void *RB_DrawSurfs( const void *data ) {
GL_BindToTMU(tr.quarterImage[1], TB_COLORMAP);
GL_BindToTMU(tr.hdrDepthImage, TB_LIGHTMAP);
- {
- vec4_t viewInfo;
-
- float zmax = backEnd.viewParms.zFar;
- float zmin = r_znear->value;
-
- VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0);
-
- GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
- }
+ GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo);
RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes);
@@ -1314,11 +1218,11 @@ const void *RB_DrawSurfs( const void *data ) {
if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
{
+ cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
+
FBO_Bind(NULL);
- GL_SelectTexture(TB_CUBEMAP);
- GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP);
- qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP);
- GL_SelectTexture(0);
+ if (cubemap && cubemap->image)
+ qglGenerateTextureMipmap(cubemap->image->texnum, GL_TEXTURE_CUBE_MAP);
}
return (const void *)(cmd + 1);
@@ -1395,7 +1299,7 @@ void RB_ShowImages( void ) {
{
vec4_t quadVerts[4];
- GL_Bind(image);
+ GL_BindToTMU(image, TB_COLORMAP);
VectorSet4(quadVerts[0], x, y, 0, 1);
VectorSet4(quadVerts[1], x + w, y, 0, 1);
@@ -1571,21 +1475,18 @@ const void *RB_CapShadowMap(const void *data)
if (cmd->map != -1)
{
- GL_SelectTexture(0);
if (cmd->cubeSide != -1)
{
if (tr.shadowCubemaps[cmd->map])
{
- GL_Bind(tr.shadowCubemaps[cmd->map]);
- qglCopyTexImage2D(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);
+ 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);
}
}
else
{
if (tr.pshadowMaps[cmd->map])
{
- GL_Bind(tr.pshadowMaps[cmd->map]);
- qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0);
+ 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);
}
}
}
@@ -1644,10 +1545,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);
}
@@ -1658,7 +1555,7 @@ const void *RB_PostProcess(const void *data)
if (srcFbo)
{
- if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer) && qglActiveTextureARB)
+ if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer))
{
autoExposure = r_autoExposure->integer || r_forceAutoExposure->integer;
RB_ToneMap(srcFbo, srcBox, NULL, dstBox, autoExposure);
@@ -1688,6 +1585,71 @@ 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;
@@ -1727,7 +1689,7 @@ const void *RB_PostProcess(const void *data)
{
VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256);
//FBO_BlitFromTexture(tr.renderCubeImage, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0);
- FBO_BlitFromTexture(tr.cubemaps[cubemapIndex - 1], NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0);
+ FBO_BlitFromTexture(tr.cubemaps[cubemapIndex - 1].image, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0);
}
}
#endif
@@ -1737,6 +1699,74 @@ const void *RB_PostProcess(const void *data)
return (const void *)(cmd + 1);
}
+// FIXME: put this function declaration elsewhere
+void R_SaveDDS(const char *filename, byte *pic, int width, int height, int depth);
+
+/*
+=============
+RB_ExportCubemaps
+
+=============
+*/
+const void *RB_ExportCubemaps(const void *data)
+{
+ const exportCubemapsCommand_t *cmd = data;
+
+ // finish any 2D drawing if needed
+ if (tess.numIndexes)
+ RB_EndSurface();
+
+ if (!glRefConfig.framebufferObject || !tr.world || tr.numCubemaps == 0)
+ {
+ // do nothing
+ ri.Printf(PRINT_ALL, "Nothing to export!\n");
+ return (const void *)(cmd + 1);
+ }
+
+ if (cmd)
+ {
+ FBO_t *oldFbo = glState.currentFBO;
+ int sideSize = r_cubemapSize->integer * r_cubemapSize->integer * 4;
+ byte *cubemapPixels = ri.Malloc(sideSize * 6);
+ int i, j;
+
+ FBO_Bind(tr.renderCubeFbo);
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ char filename[MAX_QPATH];
+ cubemap_t *cubemap = &tr.cubemaps[i];
+ byte *p = cubemapPixels;
+
+ for (j = 0; j < 6; j++)
+ {
+ FBO_AttachImage(tr.renderCubeFbo, cubemap->image, GL_COLOR_ATTACHMENT0_EXT, j);
+ qglReadPixels(0, 0, r_cubemapSize->integer, r_cubemapSize->integer, GL_RGBA, GL_UNSIGNED_BYTE, p);
+ p += sideSize;
+ }
+
+ if (cubemap->name[0])
+ {
+ COM_StripExtension(cubemap->name, filename, MAX_QPATH);
+ Q_strcat(filename, MAX_QPATH, ".dds");
+ }
+ else
+ {
+ Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/%03d.dds", tr.world->baseName, i);
+ }
+
+ R_SaveDDS(filename, cubemapPixels, r_cubemapSize->integer, r_cubemapSize->integer, 6);
+ ri.Printf(PRINT_ALL, "Saved cubemap %d as %s\n", i, filename);
+ }
+
+ FBO_Bind(oldFbo);
+
+ ri.Free(cubemapPixels);
+ }
+
+ return (const void *)(cmd + 1);
+}
+
/*
====================
@@ -1785,6 +1815,9 @@ void RB_ExecuteRenderCommands( const void *data ) {
case RC_POSTPROCESS:
data = RB_PostProcess(data);
break;
+ case RC_EXPORT_CUBEMAPS:
+ data = RB_ExportCubemaps(data);
+ break;
case RC_END_OF_LIST:
default:
// finish any 2D drawing if needed
diff --git a/src/renderergl2/tr_bsp.c b/src/renderergl2/tr_bsp.c
index beb07fe3..8429d8cb 100644
--- a/src/renderergl2/tr_bsp.c
+++ b/src/renderergl2/tr_bsp.c
@@ -24,6 +24,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h"
+#define JSON_IMPLEMENTATION
+#include "../qcommon/json.h"
+#undef JSON_IMPLEMENTATION
+
/*
Loads and prepares a map file for scene rendering.
@@ -102,7 +106,11 @@ 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;
@@ -137,7 +145,9 @@ static void R_ColorShiftLightingFloats(float in[4], float out[4], float scale )
{
float r, g, b;
- scale *= pow(2.0f, r_mapOverBrightBits->integer - tr.overbrightBits);
+#if defined(USE_OVERBRIGHT)
+ scale *= 1 << (r_mapOverBrightBits->integer - tr.overbrightBits);
+#endif
r = in[0] * scale;
g = in[1] * scale;
@@ -2756,7 +2766,11 @@ void R_LoadLightGrid( lump_t *l ) {
if (hdrLightGrid)
{
- float lightScale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits);
+#if defined(USE_OVERBRIGHT)
+ float lightScale = 1 << (r_mapOverBrightBits->integer - tr.overbrightBits);
+#else
+ float lightScale = 1.0f;
+#endif
//ri.Printf(PRINT_ALL, "found!\n");
@@ -2963,6 +2977,78 @@ qboolean R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int *numSp
return qtrue;
}
+void R_LoadEnvironmentJson(const char *baseName)
+{
+ char filename[MAX_QPATH];
+
+ union {
+ char *c;
+ void *v;
+ } buffer;
+ char *bufferEnd;
+
+ const char *cubemapArrayJson;
+ int filelen, i;
+
+ Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/env.json", baseName);
+
+ filelen = ri.FS_ReadFile(filename, &buffer.v);
+ if (!buffer.c)
+ return;
+ bufferEnd = buffer.c + filelen;
+
+ if (JSON_ValueGetType(buffer.c, bufferEnd) != JSONTYPE_OBJECT)
+ {
+ ri.Printf(PRINT_ALL, "Bad %s: does not start with a object\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ cubemapArrayJson = JSON_ObjectGetNamedValue(buffer.c, bufferEnd, "Cubemaps");
+ if (!cubemapArrayJson)
+ {
+ ri.Printf(PRINT_ALL, "Bad %s: no Cubemaps\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ if (JSON_ValueGetType(cubemapArrayJson, bufferEnd) != JSONTYPE_ARRAY)
+ {
+ ri.Printf(PRINT_ALL, "Bad %s: Cubemaps not an array\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ tr.numCubemaps = JSON_ArrayGetIndex(cubemapArrayJson, bufferEnd, NULL, 0);
+ tr.cubemaps = ri.Hunk_Alloc(tr.numCubemaps * sizeof(*tr.cubemaps), h_low);
+ memset(tr.cubemaps, 0, tr.numCubemaps * sizeof(*tr.cubemaps));
+
+ for (i = 0; i < tr.numCubemaps; i++)
+ {
+ cubemap_t *cubemap = &tr.cubemaps[i];
+ const char *cubemapJson, *keyValueJson, *indexes[3];
+ int j;
+
+ cubemapJson = JSON_ArrayGetValue(cubemapArrayJson, bufferEnd, i);
+
+ keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Name");
+ if (!JSON_ValueGetString(keyValueJson, bufferEnd, cubemap->name, MAX_QPATH))
+ cubemap->name[0] = '\0';
+
+ keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Position");
+ JSON_ArrayGetIndex(keyValueJson, bufferEnd, indexes, 3);
+ for (j = 0; j < 3; j++)
+ cubemap->origin[j] = JSON_ValueGetFloat(indexes[j], bufferEnd);
+
+ cubemap->parallaxRadius = 1000.0f;
+ keyValueJson = JSON_ObjectGetNamedValue(cubemapJson, bufferEnd, "Radius");
+ if (keyValueJson)
+ cubemap->parallaxRadius = JSON_ValueGetFloat(keyValueJson, bufferEnd);
+ }
+
+ ri.FS_FreeFile(buffer.v);
+}
+
void R_LoadCubemapEntities(char *cubemapEntityName)
{
char spawnVarChars[2048];
@@ -2987,33 +3073,45 @@ void R_LoadCubemapEntities(char *cubemapEntityName)
return;
tr.numCubemaps = numCubemaps;
- tr.cubemapOrigins = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemapOrigins), h_low);
- tr.cubemaps = ri.Hunk_Alloc( tr.numCubemaps * sizeof(*tr.cubemaps), h_low);
+ tr.cubemaps = ri.Hunk_Alloc(tr.numCubemaps * sizeof(*tr.cubemaps), h_low);
+ memset(tr.cubemaps, 0, tr.numCubemaps * sizeof(*tr.cubemaps));
numCubemaps = 0;
while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars))
{
int i;
+ char name[MAX_QPATH];
qboolean isCubemap = qfalse;
- qboolean positionSet = qfalse;
+ qboolean originSet = qfalse;
vec3_t origin;
+ float parallaxRadius = 1000.0f;
+ name[0] = '\0';
for (i = 0; i < numSpawnVars; i++)
{
if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName))
isCubemap = qtrue;
+ if (!Q_stricmp(spawnVars[i][0], "name"))
+ Q_strncpyz(name, spawnVars[i][1], MAX_QPATH);
+
if (!Q_stricmp(spawnVars[i][0], "origin"))
{
sscanf(spawnVars[i][1], "%f %f %f", &origin[0], &origin[1], &origin[2]);
- positionSet = qtrue;
+ originSet = qtrue;
+ }
+ else if (!Q_stricmp(spawnVars[i][0], "radius"))
+ {
+ sscanf(spawnVars[i][1], "%f", &parallaxRadius);
}
}
- if (isCubemap && positionSet)
+ if (isCubemap && originSet)
{
- //ri.Printf(PRINT_ALL, "cubemap at %f %f %f\n", origin[0], origin[1], origin[2]);
- VectorCopy(origin, tr.cubemapOrigins[numCubemaps]);
+ cubemap_t *cubemap = &tr.cubemaps[numCubemaps];
+ Q_strncpyz(cubemap->name, name, MAX_QPATH);
+ VectorCopy(origin, cubemap->origin);
+ cubemap->parallaxRadius = parallaxRadius;
numCubemaps++;
}
}
@@ -3053,23 +3151,41 @@ void R_AssignCubemapsToWorldSurfaces(void)
}
-void R_RenderAllCubemaps(void)
+void R_LoadCubemaps(void)
{
- int i, j;
+ int i;
+ imgFlags_t flags = IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_NOLIGHTSCALE | IMGFLAG_CUBEMAP;
for (i = 0; i < tr.numCubemaps; i++)
{
- tr.cubemaps[i] = R_CreateImage(va("*cubeMap%d", i), NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, GL_RGBA8);
+ char filename[MAX_QPATH];
+ cubemap_t *cubemap = &tr.cubemaps[i];
+
+ Com_sprintf(filename, MAX_QPATH, "cubemaps/%s/%03d.dds", tr.world->baseName, i);
+
+ cubemap->image = R_FindImageFile(filename, IMGTYPE_COLORALPHA, flags);
}
-
+}
+
+
+void R_RenderMissingCubemaps(void)
+{
+ int i, j;
+ imgFlags_t flags = IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_NOLIGHTSCALE | IMGFLAG_CUBEMAP;
+
for (i = 0; i < tr.numCubemaps; i++)
{
- for (j = 0; j < 6; j++)
+ if (!tr.cubemaps[i].image)
{
- RE_ClearScene();
- R_RenderCubemapSide(i, j, qfalse);
- R_IssuePendingRenderCommands();
- R_InitNextFrame();
+ tr.cubemaps[i].image = R_CreateImage(va("*cubeMap%d", i), NULL, r_cubemapSize->integer, r_cubemapSize->integer, IMGTYPE_COLORALPHA, flags, GL_RGBA8);
+
+ for (j = 0; j < 6; j++)
+ {
+ RE_ClearScene();
+ R_RenderCubemapSide(i, j, qfalse);
+ R_IssuePendingRenderCommands();
+ R_InitNextFrame();
+ }
}
}
}
@@ -3386,7 +3502,14 @@ void RE_LoadWorldMap( const char *name ) {
// load cubemaps
if (r_cubeMapping->integer)
{
- R_LoadCubemapEntities("misc_cubemap");
+ // Try loading an env.json file first
+ R_LoadEnvironmentJson(s_worldData.baseName);
+
+ if (!tr.numCubemaps)
+ {
+ R_LoadCubemapEntities("misc_cubemap");
+ }
+
if (!tr.numCubemaps)
{
// use deathmatch spawn points as cubemaps
@@ -3410,10 +3533,11 @@ void RE_LoadWorldMap( const char *name ) {
// make sure the VAO glState entry is safe
R_BindNullVao();
- // Render all cubemaps
+ // Render or load all cubemaps
if (r_cubeMapping->integer && tr.numCubemaps)
{
- R_RenderAllCubemaps();
+ R_LoadCubemaps();
+ R_RenderMissingCubemaps();
}
ri.FS_FreeFile( buffer.v );
diff --git a/src/renderergl2/tr_cmds.c b/src/renderergl2/tr_cmds.c
index 07fe146f..5d27c52d 100644
--- a/src/renderergl2/tr_cmds.c
+++ b/src/renderergl2/tr_cmds.c
@@ -122,20 +122,20 @@ void R_IssuePendingRenderCommands( void ) {
/*
============
-R_GetCommandBuffer
+R_GetCommandBufferReserved
make sure there is enough command space
============
*/
-void *R_GetCommandBuffer( int bytes ) {
+void *R_GetCommandBufferReserved( int bytes, int reservedBytes ) {
renderCommandList_t *cmdList;
cmdList = &backEndData->commands;
bytes = PAD(bytes, sizeof(void *));
// always leave room for the end of list command
- if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) {
- if ( bytes > MAX_RENDER_COMMANDS - 4 ) {
+ if ( cmdList->used + bytes + sizeof( int ) + reservedBytes > MAX_RENDER_COMMANDS ) {
+ if ( bytes > MAX_RENDER_COMMANDS - sizeof( int ) ) {
ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
}
// if we run out of room, just start dropping commands
@@ -147,6 +147,17 @@ void *R_GetCommandBuffer( int bytes ) {
return cmdList->cmds + cmdList->used - bytes;
}
+/*
+=============
+R_GetCommandBuffer
+
+returns NULL if there is not enough space for important commands
+=============
+*/
+void *R_GetCommandBuffer( int bytes ) {
+ return R_GetCommandBufferReserved( bytes, PAD( sizeof( swapBuffersCommand_t ), sizeof(void *) ) );
+}
+
/*
=============
@@ -611,7 +622,7 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
if ( !tr.registered ) {
return;
}
- cmd = R_GetCommandBuffer( sizeof( *cmd ) );
+ cmd = R_GetCommandBufferReserved( sizeof( *cmd ), 0 );
if ( !cmd ) {
return;
}
diff --git a/src/renderergl2/tr_dsa.c b/src/renderergl2/tr_dsa.c
new file mode 100644
index 00000000..9cd481bd
--- /dev/null
+++ b/src/renderergl2/tr_dsa.c
@@ -0,0 +1,287 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+===========================================================================
+*/
+
+#include "tr_local.h"
+
+#include "tr_dsa.h"
+
+static struct
+{
+ GLuint textures[NUM_TEXTURE_BUNDLES];
+ GLenum texunit;
+
+ GLuint program;
+
+ GLuint drawFramebuffer;
+ GLuint readFramebuffer;
+ GLuint renderbuffer;
+}
+glDsaState;
+
+void GL_BindNullTextures()
+{
+ int i;
+
+ if (glRefConfig.directStateAccess)
+ {
+ for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
+ {
+ qglBindMultiTexture(GL_TEXTURE0_ARB + i, GL_TEXTURE_2D, 0);
+ glDsaState.textures[i] = 0;
+ }
+ }
+ else
+ {
+ for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
+ {
+ qglActiveTextureARB(GL_TEXTURE0_ARB + i);
+ qglBindTexture(GL_TEXTURE_2D, 0);
+ glDsaState.textures[i] = 0;
+ }
+
+ qglActiveTextureARB(GL_TEXTURE0_ARB);
+ glDsaState.texunit = GL_TEXTURE0_ARB;
+ }
+}
+
+int GL_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture)
+{
+ GLuint tmu = texunit - GL_TEXTURE0_ARB;
+
+ if (glDsaState.textures[tmu] == texture)
+ return 0;
+
+ if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
+ target = GL_TEXTURE_CUBE_MAP;
+
+ qglBindMultiTexture(texunit, target, texture);
+ glDsaState.textures[tmu] = texture;
+ return 1;
+}
+
+GLvoid APIENTRY GLDSA_BindMultiTexture(GLenum texunit, GLenum target, GLuint texture)
+{
+ if (glDsaState.texunit != texunit)
+ {
+ qglActiveTextureARB(texunit);
+ glDsaState.texunit = texunit;
+ }
+
+ qglBindTexture(target, texture);
+}
+
+GLvoid APIENTRY GLDSA_TextureParameterf(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)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglTexParameteri(target, pname, param);
+}
+
+GLvoid APIENTRY GLDSA_TextureImage2D(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,
+ 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)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+}
+
+GLvoid APIENTRY GLDSA_CompressedTextureImage2D(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);
+}
+
+GLvoid APIENTRY GLDSA_CompressedTextureSubImage2D(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);
+}
+
+GLvoid APIENTRY GLDSA_GenerateTextureMipmap(GLuint texture, GLenum target)
+{
+ GL_BindMultiTexture(glDsaState.texunit, target, texture);
+ qglGenerateMipmapEXT(target);
+}
+
+void GL_BindNullProgram()
+{
+ qglUseProgramObjectARB(0);
+ glDsaState.program = 0;
+}
+
+int GL_UseProgramObject(GLuint program)
+{
+ if (glDsaState.program == program)
+ return 0;
+
+ qglUseProgramObjectARB(program);
+ glDsaState.program = program;
+ return 1;
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform1i(GLuint program, GLint location, GLint v0)
+{
+ GL_UseProgramObject(program);
+ qglUniform1iARB(location, v0);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform1f(GLuint program, GLint location, GLfloat v0)
+{
+ GL_UseProgramObject(program);
+ qglUniform1fARB(location, v0);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform2f(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1)
+{
+ GL_UseProgramObject(program);
+ qglUniform2fARB(location, v0, v1);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform3f(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1, GLfloat v2)
+{
+ GL_UseProgramObject(program);
+ qglUniform3fARB(location, v0, v1, v2);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform4f(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
+{
+ GL_UseProgramObject(program);
+ qglUniform4fARB(location, v0, v1, v2, v3);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniform1fv(GLuint program, GLint location,
+ GLsizei count, const GLfloat *value)
+{
+ GL_UseProgramObject(program);
+ qglUniform1fvARB(location, count, value);
+}
+
+GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fv(GLuint program, GLint location,
+ GLsizei count, GLboolean transpose,
+ const GLfloat *value)
+{
+ GL_UseProgramObject(program);
+ qglUniformMatrix4fvARB(location, count, transpose, value);
+}
+
+void GL_BindNullFramebuffers()
+{
+ qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ glDsaState.drawFramebuffer = glDsaState.readFramebuffer = 0;
+ qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
+ glDsaState.renderbuffer = 0;
+}
+
+void GL_BindFramebuffer(GLenum target, GLuint framebuffer)
+{
+ switch (target)
+ {
+ case GL_FRAMEBUFFER_EXT:
+ if (framebuffer != glDsaState.drawFramebuffer || framebuffer != glDsaState.readFramebuffer)
+ {
+ qglBindFramebufferEXT(target, framebuffer);
+ glDsaState.drawFramebuffer = glDsaState.readFramebuffer = framebuffer;
+ }
+ break;
+
+ case GL_DRAW_FRAMEBUFFER_EXT:
+ if (framebuffer != glDsaState.drawFramebuffer)
+ {
+ qglBindFramebufferEXT(target, framebuffer);
+ glDsaState.drawFramebuffer = framebuffer;
+ }
+ break;
+
+ case GL_READ_FRAMEBUFFER_EXT:
+ if (framebuffer != glDsaState.readFramebuffer)
+ {
+ qglBindFramebufferEXT(target, framebuffer);
+ glDsaState.readFramebuffer = framebuffer;
+ }
+ break;
+ }
+}
+
+void GL_BindRenderbuffer(GLuint renderbuffer)
+{
+ if (renderbuffer != glDsaState.renderbuffer)
+ {
+ qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer);
+ glDsaState.renderbuffer = renderbuffer;
+ }
+}
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorage(GLuint renderbuffer,
+ GLenum internalformat, GLsizei width, GLsizei height)
+{
+ GL_BindRenderbuffer(renderbuffer);
+ qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalformat, width, height);
+}
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisample(GLuint renderbuffer,
+ GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ GL_BindRenderbuffer(renderbuffer);
+ qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, internalformat, width, height);
+}
+
+GLenum APIENTRY GLDSA_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target)
+{
+ GL_BindFramebuffer(target, framebuffer);
+ return qglCheckFramebufferStatusEXT(target);
+}
+
+GLvoid APIENTRY GLDSA_NamedFramebufferTexture2D(GLuint framebuffer,
+ GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+ GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer);
+ qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, textarget, texture, level);
+}
+
+GLvoid APIENTRY GLDSA_NamedFramebufferRenderbuffer(GLuint framebuffer,
+ GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+ GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer);
+ qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, renderbuffertarget, renderbuffer);
+}
diff --git a/src/renderergl2/tr_dsa.h b/src/renderergl2/tr_dsa.h
new file mode 100644
index 00000000..e820fe00
--- /dev/null
+++ b/src/renderergl2/tr_dsa.h
@@ -0,0 +1,80 @@
+/*
+===========================================================================
+Copyright (C) 2016 James Canete
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+===========================================================================
+*/
+
+#ifndef __TR_DSA_H__
+#define __TR_DSA_H__
+
+#include "../renderercommon/qgl.h"
+
+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,
+ 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,
+ 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,
+ GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+GLvoid APIENTRY GLDSA_CompressedTextureSubImage2D(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);
+
+void GL_BindNullProgram(void);
+int GL_UseProgramObject(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,
+ GLfloat v0, GLfloat v1);
+GLvoid APIENTRY GLDSA_ProgramUniform3f(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1, GLfloat v2);
+GLvoid APIENTRY GLDSA_ProgramUniform4f(GLuint program, GLint location,
+ GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+GLvoid APIENTRY GLDSA_ProgramUniform1fv(GLuint program, GLint location,
+ GLsizei count, const GLfloat *value);
+GLvoid APIENTRY GLDSA_ProgramUniformMatrix4fv(GLuint program, GLint location,
+ GLsizei count, GLboolean transpose,
+ const GLfloat *value);
+
+void GL_BindNullFramebuffers(void);
+void GL_BindFramebuffer(GLenum target, GLuint framebuffer);
+void GL_BindRenderbuffer(GLuint renderbuffer);
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorage(GLuint renderbuffer,
+ GLenum internalformat, GLsizei width, GLsizei height);
+
+GLvoid APIENTRY GLDSA_NamedRenderbufferStorageMultisample(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 attachment, GLenum textarget, GLuint texture, GLint level);
+GLvoid APIENTRY GLDSA_NamedFramebufferRenderbuffer(GLuint framebuffer,
+ GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+
+
+#endif
diff --git a/src/renderergl2/tr_extensions.c b/src/renderergl2/tr_extensions.c
index 811b8377..2972aaef 100644
--- a/src/renderergl2/tr_extensions.c
+++ b/src/renderergl2/tr_extensions.c
@@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
#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);
@@ -184,6 +185,50 @@ 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 );
@@ -585,6 +630,22 @@ void GLimp_InitExtraExtensions()
ri.Printf(PRINT_ALL, result[2], extension);
}
+ // GL_ARB_texture_compression
+ extension = "GL_ARB_texture_compression";
+ glRefConfig.arbTextureCompression = qfalse;
+ if (GLimp_HaveExtension(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);
+ }
+
// GL_EXT_framebuffer_multisample
extension = "GL_EXT_framebuffer_multisample";
glRefConfig.framebufferMultisample = qfalse;
@@ -601,12 +662,12 @@ void GLimp_InitExtraExtensions()
glRefConfig.textureCompression = TCR_NONE;
- // GL_EXT_texture_compression_latc
- extension = "GL_EXT_texture_compression_latc";
+ // GL_ARB_texture_compression_rgtc
+ extension = "GL_ARB_texture_compression_rgtc";
if (GLimp_HaveExtension(extension))
{
- if (r_ext_compressed_textures->integer)
- glRefConfig.textureCompression |= TCR_LATC;
+ if (r_ext_compressed_textures->integer && glRefConfig.arbTextureCompression)
+ glRefConfig.textureCompression |= TCR_RGTC;
ri.Printf(PRINT_ALL, result[r_ext_compressed_textures->integer ? 1 : 0], extension);
}
@@ -615,6 +676,8 @@ void GLimp_InitExtraExtensions()
ri.Printf(PRINT_ALL, result[2], extension);
}
+ glRefConfig.swizzleNormalmap = r_ext_compressed_textures->integer && !(glRefConfig.textureCompression & TCR_RGTC);
+
// GL_ARB_texture_compression_bptc
extension = "GL_ARB_texture_compression_bptc";
if (GLimp_HaveExtension(extension))
@@ -732,4 +795,68 @@ void GLimp_InitExtraExtensions()
ri.Printf(PRINT_ALL, result[2], extension);
}
+ // 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 (r_ext_direct_state_access->integer)
+ {
+ 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");
+ }
+
+ ri.Printf(PRINT_ALL, result[glRefConfig.directStateAccess ? 1 : 0], extension);
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, result[2], extension);
+ }
}
diff --git a/src/renderergl2/tr_fbo.c b/src/renderergl2/tr_fbo.c
index f02e6cc7..9ba63441 100644
--- a/src/renderergl2/tr_fbo.c
+++ b/src/renderergl2/tr_fbo.c
@@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_fbo.c
#include "tr_local.h"
+#include "tr_dsa.h"
+
/*
=============
R_CheckFBO
@@ -30,26 +32,14 @@ R_CheckFBO
*/
qboolean R_CheckFBO(const FBO_t * fbo)
{
- int code;
- int id;
-
- qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &id);
- qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
-
- code = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ GLenum code = qglCheckNamedFramebufferStatus(fbo->frameBuffer, GL_FRAMEBUFFER_EXT);
if(code == GL_FRAMEBUFFER_COMPLETE_EXT)
- {
- qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
return qtrue;
- }
// an error occured
switch (code)
{
- case GL_FRAMEBUFFER_COMPLETE_EXT:
- break;
-
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) Unsupported framebuffer format\n", fbo->name);
break;
@@ -86,13 +76,9 @@ qboolean R_CheckFBO(const FBO_t * fbo)
default:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code);
- //ri.Error(ERR_FATAL, "R_CheckFBO: (%s) unknown error 0x%X", fbo->name, code);
- //assert(0);
break;
}
- qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
-
return qfalse;
}
@@ -136,6 +122,11 @@ FBO_t *FBO_Create(const char *name, int width, int height)
return fbo;
}
+/*
+=================
+FBO_CreateBuffer
+=================
+*/
void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
{
uint32_t *pRenderBuffer;
@@ -192,115 +183,45 @@ void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
if (absent)
qglGenRenderbuffersEXT(1, pRenderBuffer);
- qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *pRenderBuffer);
if (multisample && glRefConfig.framebufferMultisample)
- {
- qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, multisample, format, fbo->width, fbo->height);
- }
+ qglNamedRenderbufferStorageMultisample(*pRenderBuffer, multisample, format, fbo->width, fbo->height);
else
- {
- qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fbo->width, fbo->height);
- }
+ qglNamedRenderbufferStorage(*pRenderBuffer, format, fbo->width, fbo->height);
if(absent)
{
if (attachment == 0)
{
- qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
- qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
+ qglNamedFramebufferRenderbuffer(fbo->frameBuffer, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
+ qglNamedFramebufferRenderbuffer(fbo->frameBuffer, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
}
else
- qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer);
+ {
+ qglNamedFramebufferRenderbuffer(fbo->frameBuffer, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer);
+ }
}
}
/*
=================
-R_AttachFBOTexture1D
-=================
-*/
-void R_AttachFBOTexture1D(int texId, int index)
-{
- if(index < 0 || index >= glRefConfig.maxColorAttachments)
- {
- ri.Printf(PRINT_WARNING, "R_AttachFBOTexture1D: invalid attachment index %i\n", index);
- return;
- }
-
- qglFramebufferTexture1DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_1D, texId, 0);
-}
-
-/*
-=================
-R_AttachFBOTexture2D
+FBO_AttachImage
=================
*/
-void R_AttachFBOTexture2D(int target, int texId, int index)
+void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside)
{
- if(target != GL_TEXTURE_2D && (target < GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB || target > GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB))
- {
- ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid target %i\n", target);
- return;
- }
+ GLenum target = GL_TEXTURE_2D;
+ int index;
- if(index < 0 || index >= glRefConfig.maxColorAttachments)
- {
- ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid attachment index %i\n", index);
- return;
- }
+ if (image->flags & IMGFLAG_CUBEMAP)
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cubemapside;
- qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, texId, 0);
+ qglNamedFramebufferTexture2D(fbo->frameBuffer, attachment, target, image->texnum, 0);
+ index = attachment - GL_COLOR_ATTACHMENT0_EXT;
+ if (index >= 0 && index <= 15)
+ fbo->colorImage[index] = image;
}
-/*
-=================
-R_AttachFBOTexture3D
-=================
-*/
-void R_AttachFBOTexture3D(int texId, int index, int zOffset)
-{
- if(index < 0 || index >= glRefConfig.maxColorAttachments)
- {
- ri.Printf(PRINT_WARNING, "R_AttachFBOTexture3D: invalid attachment index %i\n", index);
- return;
- }
-
- qglFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, GL_TEXTURE_3D_EXT, texId, 0, zOffset);
-}
-
-/*
-=================
-R_AttachFBOTextureDepth
-=================
-*/
-void R_AttachFBOTextureDepth(int texId)
-{
- qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
-}
-
-/*
-=================
-R_AttachFBOTexturePackedDepthStencil
-=================
-*/
-void R_AttachFBOTexturePackedDepthStencil(int texId)
-{
- qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
- qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texId, 0);
-}
-
-void FBO_AttachTextureImage(image_t *img, int index)
-{
- if (!glState.currentFBO)
- {
- ri.Printf(PRINT_WARNING, "FBO: attempted to attach a texture image with no FBO bound!\n");
- return;
- }
-
- R_AttachFBOTexture2D(GL_TEXTURE_2D, img->texnum, index);
- glState.currentFBO->colorImage[index] = img;
-}
/*
============
@@ -315,38 +236,10 @@ void FBO_Bind(FBO_t * fbo)
if (r_logFile->integer)
{
// don't just call LogComment, or we will get a call to va() every frame!
- if (fbo)
- GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo->name));
- else
- GLimp_LogComment("--- FBO_Bind ( NULL ) ---\n");
- }
-
- if (!fbo)
- {
- qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- //qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
- glState.currentFBO = NULL;
-
- return;
+ GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo ? fbo->name : "NULL"));
}
-
- qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
-
- /*
- if(fbo->colorBuffers[0])
- {
- qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->colorBuffers[0]);
- }
- */
-
- /*
- if(fbo->depthBuffer)
- {
- qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo->depthBuffer);
- qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthBuffer);
- }
- */
+ GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, fbo ? fbo->frameBuffer : 0);
glState.currentFBO = fbo;
}
@@ -358,8 +251,7 @@ FBO_Init
void FBO_Init(void)
{
int i;
- // int width, height, hdrFormat, multisample;
- int hdrFormat, multisample;
+ int hdrFormat, multisample = 0;
ri.Printf(PRINT_ALL, "------- FBO_Init -------\n");
@@ -372,73 +264,41 @@ void FBO_Init(void)
R_IssuePendingRenderCommands();
-/* if(glRefConfig.textureNonPowerOfTwo)
- {
- width = glConfig.vidWidth;
- height = glConfig.vidHeight;
- }
- else
- {
- width = NextPowerOfTwo(glConfig.vidWidth);
- height = NextPowerOfTwo(glConfig.vidHeight);
- } */
-
hdrFormat = GL_RGBA8;
if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat)
- {
hdrFormat = GL_RGBA16F_ARB;
- }
- qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample);
+ if (glRefConfig.framebufferMultisample)
+ qglGetIntegerv(GL_MAX_SAMPLES_EXT, &multisample);
if (r_ext_framebuffer_multisample->integer < multisample)
- {
multisample = r_ext_framebuffer_multisample->integer;
- }
if (multisample < 2 || !glRefConfig.framebufferBlit)
multisample = 0;
if (multisample != r_ext_framebuffer_multisample->integer)
- {
ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample);
- }
// only create a render FBO if we need to resolve MSAA or do HDR
// otherwise just render straight to the screen (tr.renderFbo = NULL)
if (multisample && glRefConfig.framebufferMultisample)
{
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
- FBO_Bind(tr.renderFbo);
-
FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, multisample);
FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample);
-
R_CheckFBO(tr.renderFbo);
-
tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height);
- FBO_Bind(tr.msaaResolveFbo);
-
- //FBO_CreateBuffer(tr.msaaResolveFbo, hdrFormat, 0, 0);
- FBO_AttachTextureImage(tr.renderImage, 0);
-
- //FBO_CreateBuffer(tr.msaaResolveFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
- R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
-
+ FBO_AttachImage(tr.msaaResolveFbo, tr.renderImage, GL_COLOR_ATTACHMENT0_EXT, 0);
+ FBO_AttachImage(tr.msaaResolveFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
R_CheckFBO(tr.msaaResolveFbo);
}
else if (r_hdr->integer)
{
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
- FBO_Bind(tr.renderFbo);
-
- //FBO_CreateBuffer(tr.renderFbo, hdrFormat, 0, 0);
- FBO_AttachTextureImage(tr.renderImage, 0);
-
- //FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
- R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
-
+ FBO_AttachImage(tr.renderFbo, tr.renderImage, GL_COLOR_ATTACHMENT0_EXT, 0);
+ FBO_AttachImage(tr.renderFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
R_CheckFBO(tr.renderFbo);
}
@@ -446,20 +306,23 @@ void FBO_Init(void)
// this fixes the corrupt screen bug with r_hdr 1 on older hardware
if (tr.renderFbo)
{
- FBO_Bind(tr.renderFbo);
+ GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, tr.renderFbo->frameBuffer);
qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
- FBO_Bind(NULL);
}
- if (r_drawSunRays->integer)
+ if (tr.screenScratchImage)
{
- tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
- FBO_Bind(tr.sunRaysFbo);
-
- FBO_AttachTextureImage(tr.sunRaysImage, 0);
-
- R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
+ 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);
+ R_CheckFBO(tr.screenScratchFbo);
+ }
+ 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);
R_CheckFBO(tr.sunRaysFbo);
}
@@ -469,121 +332,92 @@ void FBO_Init(void)
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_Bind(tr.pshadowFbos[i]);
-
- //FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0);
- FBO_AttachTextureImage(tr.pshadowMaps[i], 0);
-
+ FBO_AttachImage(tr.pshadowFbos[i], tr.pshadowMaps[i], GL_COLOR_ATTACHMENT0_EXT, 0);
FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0);
- //R_AttachFBOTextureDepth(tr.textureDepthImage->texnum);
-
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);
- FBO_Bind(tr.sunShadowFbo[i]);
-
- //FBO_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0);
- //FBO_AttachTextureImage(tr.sunShadowImage, 0);
- qglDrawBuffer(GL_NONE);
- qglReadBuffer(GL_NONE);
-
- //FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
- R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum);
-
+ // 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);
R_CheckFBO(tr.sunShadowFbo[i]);
-
}
+ }
+ if (tr.screenShadowImage)
+ {
tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
- FBO_Bind(tr.screenShadowFbo);
-
- FBO_AttachTextureImage(tr.screenShadowImage, 0);
-
+ FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0_EXT, 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_Bind(tr.textureScratchFbo[i]);
-
- //FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0);
- FBO_AttachTextureImage(tr.textureScratchImage[i], 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_EXT, 0);
+ R_CheckFBO(tr.textureScratchFbo[i]);
+ }
}
+ if (tr.calcLevelsImage)
{
tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
- FBO_Bind(tr.calcLevelsFbo);
-
- //FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0);
- FBO_AttachTextureImage(tr.calcLevelsImage, 0);
-
+ FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0);
R_CheckFBO(tr.calcLevelsFbo);
}
+ if (tr.targetLevelsImage)
{
tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
- FBO_Bind(tr.targetLevelsFbo);
-
- //FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0);
- FBO_AttachTextureImage(tr.targetLevelsImage, 0);
-
+ FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 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_Bind(tr.quarterFbo[i]);
-
- //FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0);
- FBO_AttachTextureImage(tr.quarterImage[i], 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_EXT, 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_Bind(tr.hdrDepthFbo);
-
- FBO_AttachTextureImage(tr.hdrDepthImage, 0);
-
+ FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0_EXT, 0);
R_CheckFBO(tr.hdrDepthFbo);
+ }
+ if (tr.screenSsaoImage)
+ {
tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
- FBO_Bind(tr.screenSsaoFbo);
-
- FBO_AttachTextureImage(tr.screenSsaoImage, 0);
-
+ FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0_EXT, 0);
R_CheckFBO(tr.screenSsaoFbo);
}
if (tr.renderCubeImage)
{
tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height);
- FBO_Bind(tr.renderCubeFbo);
-
- //FBO_AttachTextureImage(tr.renderCubeImage, 0);
- R_AttachFBOTexture2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, tr.renderCubeImage->texnum, 0);
- glState.currentFBO->colorImage[0] = tr.renderCubeImage;
-
+ FBO_AttachImage(tr.renderCubeFbo, tr.renderCubeImage, GL_COLOR_ATTACHMENT0_EXT, 0);
FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
-
R_CheckFBO(tr.renderCubeFbo);
}
GL_CheckErrors();
- FBO_Bind(NULL);
+ GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+ glState.currentFBO = NULL;
}
/*
@@ -653,10 +487,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];
@@ -666,51 +499,49 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS
int width, height;
if (!src)
+ {
+ ri.Printf(PRINT_WARNING, "Tried to blit from a NULL texture!\n");
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)
@@ -729,17 +560,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 );
@@ -749,18 +569,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 );
@@ -772,14 +587,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)
{
@@ -787,20 +602,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)
@@ -814,22 +628,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
{
@@ -838,26 +645,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]);
}
- qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, srcFb);
- qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dstFb);
+ GL_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, srcFb);
+ GL_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, dstFb);
qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3],
dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3],
buffers, filter);
- qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glState.currentFBO = NULL;
}
diff --git a/src/renderergl2/tr_fbo.h b/src/renderergl2/tr_fbo.h
index 530fee5c..cb14af6b 100644
--- a/src/renderergl2/tr_fbo.h
+++ b/src/renderergl2/tr_fbo.h
@@ -52,11 +52,12 @@ typedef struct FBO_s
int height;
} FBO_t;
+void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside);
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/src/renderergl2/tr_glsl.c b/src/renderergl2/tr_glsl.c
index f526b8c6..683e173d 100644
--- a/src/renderergl2/tr_glsl.c
+++ b/src/renderergl2/tr_glsl.c
@@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_glsl.c
#include "tr_local.h"
-void GLSL_BindNullProgram(void);
+#include "tr_dsa.h"
extern const char *fallbackShader_bokeh_vp;
extern const char *fallbackShader_bokeh_fp;
@@ -322,17 +322,8 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, cha
Q_strcat(dest, size,
va("#ifndef r_FBufScale\n#define r_FBufScale vec2(%f, %f)\n#endif\n", fbufWidthScale, fbufHeightScale));
- if (r_materialGamma->value != 1.0f)
- Q_strcat(dest, size, va("#ifndef r_materialGamma\n#define r_materialGamma %f\n#endif\n", r_materialGamma->value));
-
- if (r_lightGamma->value != 1.0f)
- Q_strcat(dest, size, va("#ifndef r_lightGamma\n#define r_lightGamma %f\n#endif\n", r_lightGamma->value));
-
- if (r_framebufferGamma->value != 1.0f)
- Q_strcat(dest, size, va("#ifndef r_framebufferGamma\n#define r_framebufferGamma %f\n#endif\n", r_framebufferGamma->value));
-
- if (r_tonemapGamma->value != 1.0f)
- Q_strcat(dest, size, va("#ifndef r_tonemapGamma\n#define r_tonemapGamma %f\n#endif\n", r_tonemapGamma->value));
+ if (r_pbr->integer)
+ Q_strcat(dest, size, "#define USE_PBR\n");
if (extra)
{
@@ -482,11 +473,6 @@ static void GLSL_ShowProgramUniforms(GLhandleARB program)
GLenum type;
char uniformName[1000];
- // install the executables in the program object as part of current state.
- qglUseProgramObjectARB(program);
-
- // check for GL Errors
-
// query the number of active uniforms
qglGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count);
@@ -497,8 +483,6 @@ static void GLSL_ShowProgramUniforms(GLhandleARB program)
ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName);
}
-
- qglUseProgramObjectARB(0);
}
static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int attribs, const char *vpCode, const char *fpCode)
@@ -703,7 +687,7 @@ void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value)
*compare = value;
- qglUniform1iARB(uniforms[uniformNum], value);
+ qglProgramUniform1i(program->program, uniforms[uniformNum], value);
}
void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value)
@@ -727,7 +711,7 @@ void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat valu
*compare = value;
- qglUniform1fARB(uniforms[uniformNum], value);
+ qglProgramUniform1f(program->program, uniforms[uniformNum], value);
}
void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v)
@@ -752,7 +736,7 @@ void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t
compare[0] = v[0];
compare[1] = v[1];
- qglUniform2fARB(uniforms[uniformNum], v[0], v[1]);
+ qglProgramUniform2f(program->program, uniforms[uniformNum], v[0], v[1]);
}
void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v)
@@ -776,7 +760,7 @@ void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t
VectorCopy(v, compare);
- qglUniform3fARB(uniforms[uniformNum], v[0], v[1], v[2]);
+ qglProgramUniform3f(program->program, uniforms[uniformNum], v[0], v[1], v[2]);
}
void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v)
@@ -800,7 +784,7 @@ void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t
VectorCopy4(v, compare);
- qglUniform4fARB(uniforms[uniformNum], v[0], v[1], v[2], v[3]);
+ qglProgramUniform4f(program->program, uniforms[uniformNum], v[0], v[1], v[2], v[3]);
}
void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v)
@@ -824,7 +808,7 @@ void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_
VectorCopy5(v, compare);
- qglUniform1fvARB(uniforms[uniformNum], 5, v);
+ qglProgramUniform1fv(program->program, uniforms[uniformNum], 5, v);
}
void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t matrix)
@@ -848,7 +832,7 @@ void GLSL_SetUniformMat4(shaderProgram_t *program, int uniformNum, const mat4_t
Mat4Copy(matrix, compare);
- qglUniformMatrix4fvARB(uniforms[uniformNum], 1, GL_FALSE, matrix);
+ qglProgramUniformMatrix4fv(program->program, uniforms[uniformNum], 1, GL_FALSE, matrix);
}
void GLSL_DeleteGPUShader(shaderProgram_t *program)
@@ -925,10 +909,8 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.genericShader[i]);
- qglUseProgramObjectARB(tr.genericShader[i].program);
GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.genericShader[i]);
@@ -945,9 +927,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.textureColorShader);
- qglUseProgramObjectARB(tr.textureColorShader.program);
GLSL_SetUniformInt(&tr.textureColorShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.textureColorShader);
@@ -993,9 +973,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.dlightShader[i]);
- qglUseProgramObjectARB(tr.dlightShader[i].program);
GLSL_SetUniformInt(&tr.dlightShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.dlightShader[i]);
@@ -1022,16 +1000,10 @@ void GLSL_InitGPUShaders(void)
extradefines[0] = '\0';
- if (r_deluxeSpecular->value > 0.000001f)
- Q_strcat(extradefines, 1024, va("#define r_deluxeSpecular %f\n", r_deluxeSpecular->value));
-
- if (r_specularIsMetallic->value)
- Q_strcat(extradefines, 1024, "#define SPECULAR_IS_METALLIC\n");
-
if (r_dlightMode->integer >= 2)
Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n");
- if (1)
+ if (glRefConfig.swizzleNormalmap)
Q_strcat(extradefines, 1024, "#define SWIZZLE_NORMALMAP\n");
if (r_hdr->integer && !glRefConfig.floatLightmap)
@@ -1067,12 +1039,6 @@ void GLSL_InitGPUShaders(void)
{
Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n");
- if (r_normalMapping->integer == 2)
- Q_strcat(extradefines, 1024, "#define USE_OREN_NAYAR\n");
-
- if (r_normalMapping->integer == 3)
- Q_strcat(extradefines, 1024, "#define USE_TRIACE_OREN_NAYAR\n");
-
#ifdef USE_VERT_TANGENT_SPACE
Q_strcat(extradefines, 1024, "#define USE_VERT_TANGENT_SPACE\n");
attribs |= ATTR_TANGENT;
@@ -1087,36 +1053,27 @@ void GLSL_InitGPUShaders(void)
}
if (r_specularMapping->integer)
- {
Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n");
- switch (r_specularMapping->integer)
- {
- case 1:
- default:
- Q_strcat(extradefines, 1024, "#define USE_BLINN\n");
- break;
-
- case 2:
- Q_strcat(extradefines, 1024, "#define USE_BLINN_FRESNEL\n");
- break;
-
- case 3:
- Q_strcat(extradefines, 1024, "#define USE_MCAULEY\n");
- break;
-
- case 4:
- Q_strcat(extradefines, 1024, "#define USE_GOTANDA\n");
- break;
-
- case 5:
- Q_strcat(extradefines, 1024, "#define USE_LAZAROV\n");
- break;
- }
- }
-
if (r_cubeMapping->integer)
Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n");
+
+ switch (r_glossType->integer)
+ {
+ case 0:
+ default:
+ Q_strcat(extradefines, 1024, "#define GLOSS_IS_GLOSS\n");
+ break;
+ case 1:
+ Q_strcat(extradefines, 1024, "#define GLOSS_IS_SMOOTHNESS\n");
+ break;
+ case 2:
+ Q_strcat(extradefines, 1024, "#define GLOSS_IS_ROUGHNESS\n");
+ break;
+ case 3:
+ Q_strcat(extradefines, 1024, "#define GLOSS_IS_SHININESS\n");
+ break;
+ }
}
if (i & LIGHTDEF_USE_SHADOWMAP)
@@ -1155,7 +1112,6 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.lightallShader[i]);
- qglUseProgramObjectARB(tr.lightallShader[i].program);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_NORMALMAP, TB_NORMALMAP);
@@ -1163,7 +1119,6 @@ void GLSL_InitGPUShaders(void)
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP, TB_SHADOWMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP, TB_CUBEMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.lightallShader[i]);
@@ -1196,9 +1151,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.pshadowShader);
- qglUseProgramObjectARB(tr.pshadowShader.program);
GLSL_SetUniformInt(&tr.pshadowShader, UNIFORM_SHADOWMAP, TB_DIFFUSEMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.pshadowShader);
@@ -1215,9 +1168,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.down4xShader);
- qglUseProgramObjectARB(tr.down4xShader.program);
GLSL_SetUniformInt(&tr.down4xShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.down4xShader);
@@ -1234,9 +1185,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.bokehShader);
- qglUseProgramObjectARB(tr.bokehShader.program);
GLSL_SetUniformInt(&tr.bokehShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.bokehShader);
@@ -1253,10 +1202,8 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.tonemapShader);
- qglUseProgramObjectARB(tr.tonemapShader.program);
GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_LEVELSMAP, TB_LEVELSMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.tonemapShader);
@@ -1278,9 +1225,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.calclevels4xShader[i]);
- qglUseProgramObjectARB(tr.calclevels4xShader[i].program);
GLSL_SetUniformInt(&tr.calclevels4xShader[i], UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.calclevels4xShader[i]);
@@ -1311,13 +1256,11 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.shadowmaskShader);
- qglUseProgramObjectARB(tr.shadowmaskShader.program);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP, TB_SHADOWMAP);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP2, TB_SHADOWMAP2);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP3, TB_SHADOWMAP3);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP4, TB_SHADOWMAP4);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.shadowmaskShader);
@@ -1334,16 +1277,14 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.ssaoShader);
- qglUseProgramObjectARB(tr.ssaoShader.program);
GLSL_SetUniformInt(&tr.ssaoShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.ssaoShader);
numEtcShaders++;
- for (i = 0; i < 2; i++)
+ for (i = 0; i < 4; i++)
{
attribs = ATTR_POSITION | ATTR_TEXCOORD;
extradefines[0] = '\0';
@@ -1353,6 +1294,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))
{
@@ -1361,10 +1305,8 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.depthBlurShader[i]);
- qglUseProgramObjectARB(tr.depthBlurShader[i].program);
GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENIMAGEMAP, TB_COLORMAP);
GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.depthBlurShader[i]);
@@ -1382,9 +1324,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.testcubeShader);
- qglUseProgramObjectARB(tr.testcubeShader.program);
GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
- qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.testcubeShader);
@@ -1408,7 +1348,7 @@ void GLSL_ShutdownGPUShaders(void)
for (i = 0; i < ATTR_INDEX_COUNT; i++)
qglDisableVertexAttribArrayARB(i);
- GLSL_BindNullProgram();
+ GL_BindNullProgram();
for ( i = 0; i < GENERICDEF_COUNT; i++)
GLSL_DeleteGPUShader(&tr.genericShader[i]);
@@ -1436,49 +1376,24 @@ 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]);
-
- glState.currentProgram = 0;
- qglUseProgramObjectARB(0);
}
void GLSL_BindProgram(shaderProgram_t * program)
{
- if(!program)
- {
- GLSL_BindNullProgram();
- return;
- }
+ GLuint programObject = program ? program->program : 0;
+ char *name = program ? program->name : "NULL";
if(r_logFile->integer)
{
// don't just call LogComment, or we will get a call to va() every frame!
- GLimp_LogComment(va("--- GL_BindProgram( %s ) ---\n", program->name));
+ GLimp_LogComment(va("--- GLSL_BindProgram( %s ) ---\n", name));
}
- if(glState.currentProgram != program)
- {
- qglUseProgramObjectARB(program->program);
- glState.currentProgram = program;
+ if (GL_UseProgramObject(programObject))
backEnd.pc.c_glslShaderBinds++;
- }
-}
-
-
-void GLSL_BindNullProgram(void)
-{
- if(r_logFile->integer)
- {
- GLimp_LogComment("--- GL_BindNullProgram ---\n");
- }
-
- if(glState.currentProgram)
- {
- qglUseProgramObjectARB(0);
- glState.currentProgram = NULL;
- }
}
diff --git a/src/renderergl2/tr_image.c b/src/renderergl2/tr_image.c
index 08894a4a..331e7f61 100644
--- a/src/renderergl2/tr_image.c
+++ b/src/renderergl2/tr_image.c
@@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_image.c
#include "tr_local.h"
+#include "tr_dsa.h"
+
static byte s_intensitytable[256];
static unsigned char s_gammatable[256];
@@ -114,10 +116,9 @@ void GL_TextureMode( const char *string ) {
// change all the existing mipmap texture objects
for ( i = 0 ; i < tr.numImages ; i++ ) {
glt = tr.images[ i ];
- if ( glt->flags & IMGFLAG_MIPMAP ) {
- GL_Bind (glt);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ 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);
}
}
}
@@ -177,15 +178,20 @@ void R_ImageList_f( void ) {
format = "sBPTC";
// 128 bits per 16 pixels, so 1 byte per pixel
break;
- case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
- format = "LATC ";
+ case GL_COMPRESSED_RG_RGTC2:
+ format = "RGTC2";
// 128 bits per 16 pixels, so 1 byte per pixel
break;
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
format = "DXT1 ";
// 64 bits per 16 pixels, so 4 bits per pixel
estSize /= 2;
break;
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ format = "DXT1a";
+ // 64 bits per 16 pixels, so 4 bits per pixel
+ estSize /= 2;
+ break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
format = "DXT5 ";
// 128 bits per 16 pixels, so 1 byte per pixel
@@ -1332,41 +1338,6 @@ static void R_MipMapsRGB( byte *in, int inWidth, int inHeight)
}
-static void R_MipMapLuminanceAlpha (const byte *in, byte *out, int width, int height)
-{
- int i, j, row;
-
- if ( width == 1 && height == 1 ) {
- return;
- }
-
- row = width * 4;
- width >>= 1;
- height >>= 1;
-
- if ( width == 0 || height == 0 ) {
- width += height; // get largest
- for (i=0 ; i<width ; i++, out+=4, in+=8 ) {
- out[0] =
- out[1] =
- out[2] = (in[0] + in[4]) >> 1;
- out[3] = (in[3] + in[7]) >> 1;
- }
- return;
- }
-
- for (i=0 ; i<height ; i++, in+=row) {
- for (j=0 ; j<width ; j++, out+=4, in+=8) {
- out[0] =
- out[1] =
- out[2] = (in[0] + in[4] + in[row ] + in[row+4]) >> 2;
- out[3] = (in[3] + in[7] + in[row+3] + in[row+7]) >> 2;
- }
- }
-
-}
-
-
static void R_MipMapNormalHeight (const byte *in, byte *out, int width, int height, qboolean swizzle)
{
int i, j;
@@ -1482,7 +1453,7 @@ RawImage_ScaleToPower2
===============
*/
-static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_height, int *inout_scaled_width, int *inout_scaled_height, imgType_t type, imgFlags_t flags, byte **resampledBuffer)
+static qboolean RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_height, imgType_t type, imgFlags_t flags, byte **resampledBuffer)
{
int width = *inout_width;
int height = *inout_height;
@@ -1491,6 +1462,7 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he
qboolean picmip = flags & IMGFLAG_PICMIP;
qboolean mipmap = flags & IMGFLAG_MIPMAP;
qboolean clampToEdge = flags & IMGFLAG_CLAMPTOEDGE;
+ qboolean notScaled;
//
// convert to exact power of 2 sizes
@@ -1537,22 +1509,9 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he
*resampledBuffer = ri.Hunk_AllocateTempMemory( finalwidth * finalheight * 4 );
if (scaled_width != width || scaled_height != height)
- {
ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height);
- }
else
- {
- byte *inbyte, *outbyte;
- int i;
-
- inbyte = *data;
- outbyte = *resampledBuffer;
-
- for (i = width * height * 4; i > 0; i--)
- {
- *outbyte++ = *inbyte++;
- }
- }
+ Com_Memcpy(*resampledBuffer, *data, width * height * 4);
if (type == IMGTYPE_COLORALPHA)
RGBAtoYCoCgA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height);
@@ -1566,34 +1525,29 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he
}
if (type == IMGTYPE_COLORALPHA)
- {
YCoCgAtoRGBA(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height);
- }
else if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
- {
FillInNormalizedZ(*resampledBuffer, *resampledBuffer, scaled_width, scaled_height);
- }
-
//endTime = ri.Milliseconds();
//ri.Printf(PRINT_ALL, "upsampled %dx%d to %dx%d in %dms\n", width, height, scaled_width, scaled_height, endTime - startTime);
*data = *resampledBuffer;
- width = scaled_width;
- height = scaled_height;
}
- else if ( scaled_width != width || scaled_height != height ) {
+ else if ( scaled_width != width || scaled_height != height )
+ {
if (data && resampledBuffer)
{
*resampledBuffer = ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 );
ResampleTexture (*data, width, height, *resampledBuffer, scaled_width, scaled_height);
*data = *resampledBuffer;
}
- width = scaled_width;
- height = scaled_height;
}
+ width = scaled_width;
+ height = scaled_height;
+
//
// perform optional picmip operation
//
@@ -1603,16 +1557,6 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he
}
//
- // clamp to minimum size
- //
- if (scaled_width < 1) {
- scaled_width = 1;
- }
- if (scaled_height < 1) {
- scaled_height = 1;
- }
-
- //
// clamp to the current upper OpenGL limit
// scale both axis down equally so we don't have to
// deal with a half mip resampling
@@ -1623,10 +1567,35 @@ static void RawImage_ScaleToPower2( byte **data, int *inout_width, int *inout_he
scaled_height >>= 1;
}
- *inout_width = width;
- *inout_height = height;
- *inout_scaled_width = scaled_width;
- *inout_scaled_height = scaled_height;
+ //
+ // clamp to minimum size
+ //
+ scaled_width = MAX(1, scaled_width);
+ scaled_height = MAX(1, scaled_height);
+
+ notScaled = (width == scaled_width) && (height == scaled_height);
+
+ //
+ // rescale texture to new size using existing mipmap functions
+ //
+ if (data)
+ {
+ while (width > scaled_width || height > scaled_height)
+ {
+ if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
+ R_MipMapNormalHeight(*data, *data, width, height, qfalse);
+ else
+ R_MipMapsRGB(*data, width, height);
+
+ width = MAX(1, width >> 1);
+ height = MAX(1, height >> 1);
+ }
+ }
+
+ *inout_width = width;
+ *inout_height = height;
+
+ return notScaled;
}
@@ -1648,22 +1617,25 @@ static qboolean RawImage_HasAlpha(const byte *scan, int numPixels)
return qfalse;
}
-static GLenum RawImage_GetFormat(const byte *data, int numPixels, qboolean lightMap, imgType_t type, imgFlags_t flags)
+static GLenum RawImage_GetFormat(const byte *data, int numPixels, GLenum picFormat, qboolean lightMap, imgType_t type, imgFlags_t flags)
{
int samples = 3;
GLenum internalFormat = GL_RGB;
qboolean forceNoCompression = (flags & IMGFLAG_NO_COMPRESSION);
qboolean normalmap = (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT);
+ if (picFormat != GL_RGBA8)
+ return picFormat;
+
if(normalmap)
{
- if ((!RawImage_HasAlpha(data, numPixels) || (type == IMGTYPE_NORMAL)) && !forceNoCompression && (glRefConfig.textureCompression & TCR_LATC))
+ if ((type == IMGTYPE_NORMALHEIGHT) && RawImage_HasAlpha(data, numPixels))
{
- internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT;
- }
- else
- {
- if ( !forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB )
+ if (!forceNoCompression && glRefConfig.textureCompression & TCR_BPTC)
+ {
+ internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
+ }
+ else if (!forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB)
{
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
@@ -1680,6 +1652,33 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, qboolean light
internalFormat = GL_RGBA;
}
}
+ else
+ {
+ if (!forceNoCompression && glRefConfig.textureCompression & TCR_RGTC)
+ {
+ internalFormat = GL_COMPRESSED_RG_RGTC2;
+ }
+ else if (!forceNoCompression && glRefConfig.textureCompression & TCR_BPTC)
+ {
+ internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
+ }
+ else if (!forceNoCompression && glConfig.textureCompression == TC_S3TC_ARB)
+ {
+ internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ }
+ else if (r_texturebits->integer == 16)
+ {
+ internalFormat = GL_RGB5;
+ }
+ else if (r_texturebits->integer == 32)
+ {
+ internalFormat = GL_RGB8;
+ }
+ else
+ {
+ internalFormat = GL_RGB;
+ }
+ }
}
else if(lightMap)
{
@@ -1775,12 +1774,147 @@ static GLenum RawImage_GetFormat(const byte *data, int numPixels, qboolean light
return internalFormat;
}
+static void CompressMonoBlock(byte outdata[8], const byte indata[16])
+{
+ int hi, lo, diff, bias, outbyte, shift, i;
+ byte *p = outdata;
+
+ hi = lo = indata[0];
+ for (i = 1; i < 16; i++)
+ {
+ hi = MAX(indata[i], hi);
+ lo = MIN(indata[i], lo);
+ }
+
+ *p++ = hi;
+ *p++ = lo;
+
+ diff = hi - lo;
+
+ if (diff == 0)
+ {
+ outbyte = (hi == 255) ? 255 : 0;
+
+ for (i = 0; i < 6; i++)
+ *p++ = outbyte;
+
+ return;
+ }
+
+ bias = diff / 2 - lo * 7;
+ outbyte = shift = 0;
+ for (i = 0; i < 16; i++)
+ {
+ const byte fixIndex[8] = { 1, 7, 6, 5, 4, 3, 2, 0 };
+ byte index = fixIndex[(indata[i] * 7 + bias) / diff];
-static void RawImage_UploadTexture( byte *data, int x, int y, int width, int height, GLenum internalFormat, imgType_t type, imgFlags_t flags, qboolean subtexture )
+ outbyte |= index << shift;
+ shift += 3;
+ if (shift >= 8)
+ {
+ *p++ = outbyte & 0xff;
+ shift -= 8;
+ outbyte >>= 8;
+ }
+ }
+}
+
+static void RawImage_UploadToRgtc2Texture(GLuint texture, byte *data, int width, int height, int mip)
{
- int dataFormat, dataType;
+ int wBlocks, hBlocks, y, x, size;
+ byte *compressedData, *p;
- switch(internalFormat)
+ wBlocks = (width + 3) / 4;
+ hBlocks = (height + 3) / 4;
+ size = wBlocks * hBlocks * 16;
+
+ p = compressedData = ri.Hunk_AllocateTempMemory(size);
+ for (y = 0; y < height; y += 4)
+ {
+ int oh = MIN(4, height - y);
+
+ for (x = 0; x < width; x += 4)
+ {
+ byte workingData[16];
+ int component;
+
+ int ow = MIN(4, width - x);
+
+ for (component = 0; component < 2; component++)
+ {
+ int ox, oy;
+
+ for (oy = 0; oy < oh; oy++)
+ for (ox = 0; ox < ow; ox++)
+ workingData[oy * 4 + ox] = data[((y + oy) * width + x + ox) * 4 + component];
+
+ // dupe data to fill
+ for (oy = 0; oy < 4; oy++)
+ for (ox = (oy < oh) ? ow : 0; ox < 4; ox++)
+ workingData[oy * 4 + ox] = workingData[(oy % oh) * 4 + ox % ow];
+
+ CompressMonoBlock(p, workingData);
+ p += 8;
+ }
+ }
+ }
+
+ qglCompressedTextureImage2D(texture, GL_TEXTURE_2D, mip, GL_COMPRESSED_RG_RGTC2, width, height, 0, size, compressedData);
+
+ ri.Hunk_FreeTempMemory(compressedData);
+}
+
+static int CalculateMipSize(int width, int height, GLenum picFormat)
+{
+ int numBlocks = ((width + 3) / 4) * ((height + 3) / 4);
+ int numPixels = width * height;
+
+ switch (picFormat)
+ {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RED_RGTC1:
+ case GL_COMPRESSED_SIGNED_RED_RGTC1:
+ return numBlocks * 8;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ case GL_COMPRESSED_RG_RGTC2:
+ case GL_COMPRESSED_SIGNED_RG_RGTC2:
+ case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB:
+ case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB:
+ case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB:
+ case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB:
+ return numBlocks * 16;
+
+ case GL_RGBA8:
+ case GL_SRGB8_ALPHA8_EXT:
+ return numPixels * 4;
+
+ default:
+ ri.Printf(PRINT_ALL, "Unsupported texture format %08x\n", picFormat);
+ return 0;
+ }
+
+ return 0;
+}
+
+
+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 )
+{
+ 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:
@@ -1799,60 +1933,83 @@ static void RawImage_UploadTexture( byte *data, int x, int y, int width, int hei
break;
}
- if ( subtexture )
- qglTexSubImage2D( GL_TEXTURE_2D, 0, x, y, width, height, dataFormat, dataType, data );
- else
- qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, dataFormat, dataType, data );
+ if (!data)
+ {
+ miplevel = 0;
+ do
+ {
+ lastMip = (width == 1 && height == 1) || !mipmap;
+ qglTextureImage2D(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, NULL);
+
+ width = MAX(1, width >> 1);
+ height = MAX(1, height >> 1);
+ miplevel++;
+ }
+ while (!lastMip);
+
+ return;
+ }
- if (flags & IMGFLAG_MIPMAP)
+ if (compressed && picmip)
{
- int miplevel;
+ 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;
+ }
+ }
- miplevel = 0;
- while (width > 1 || height > 1)
+ miplevel = 0;
+ do
+ {
+ lastMip = (width == 1 && height == 1) || !mipmap;
+ size = CalculateMipSize(width, height, picFormat);
+
+ if (compressed)
{
- if (data)
+ if (subtexture)
+ qglCompressedTextureSubImage2D(texture, target, miplevel, x, y, width, height, picFormat, size, data);
+ else
+ qglCompressedTextureImage2D(texture, target, miplevel, picFormat, width, height, 0, size, data);
+ }
+ else
+ {
+ if (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);
+ else
+ qglTextureImage2D(texture, target, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data);
+
+ if (!lastMip && numMips < 2)
{
if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
- {
- if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT)
- {
- R_MipMapLuminanceAlpha( data, data, width, height );
- }
- else
- {
- R_MipMapNormalHeight( data, data, width, height, qtrue);
- }
- }
+ R_MipMapNormalHeight(data, data, width, height, glRefConfig.swizzleNormalmap);
else
- {
- R_MipMapsRGB( data, width, height );
- }
+ R_MipMapsRGB(data, width, height);
}
-
- width >>= 1;
- height >>= 1;
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
- miplevel++;
+ }
- if ( data && r_colorMipLevels->integer )
- R_BlendOverTexture( (byte *)data, width * height, mipBlendColors[miplevel] );
+ x >>= 1;
+ y >>= 1;
+ width = MAX(1, width >> 1);
+ height = MAX(1, height >> 1);
+ miplevel++;
- if ( subtexture )
- {
- x >>= 1;
- y >>= 1;
- qglTexSubImage2D( GL_TEXTURE_2D, miplevel, x, y, width, height, dataFormat, dataType, data );
- }
- else
- {
- qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, width, height, 0, dataFormat, dataType, data );
- }
+ if (numMips > 1)
+ {
+ data += size;
+ numMips--;
}
}
+ while (!lastMip);
}
@@ -1862,23 +2019,51 @@ Upload32
===============
*/
-static void Upload32( byte *data, int width, int height, imgType_t type, imgFlags_t flags,
- qboolean lightMap, GLenum internalFormat, int *pUploadWidth, int *pUploadHeight)
+static void Upload32(byte *data, int x, int y, int width, int height, GLenum picFormat, int numMips, image_t *image)
{
- byte *scaledBuffer = NULL;
byte *resampledBuffer = NULL;
- int scaled_width, scaled_height;
int i, c;
byte *scan;
- RawImage_ScaleToPower2(&data, &width, &height, &scaled_width, &scaled_height, type, flags, &resampledBuffer);
-
- scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height );
+ 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 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)
+ {
+ 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)
+ {
+ for (i = 0; i < depth; i++)
+ {
+ 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--)
+ {
+ data += CalculateMipSize(w2, h2, picFormat);
+ w2 = MAX(1, w2 >> 1);
+ h2 = MAX(1, h2 >> 1);
+ }
+ }
+ goto done;
+ }
+ notScaled = RawImage_ScaleToPower2(&data, &width, &height, type, flags, &resampledBuffer);
+ }
- //
- // scan the texture for each channel's max values
- // and verify if the alpha channel is being used or not
- //
c = width*height;
scan = data;
@@ -1903,137 +2088,44 @@ static void Upload32( byte *data, int width, int height, imgType_t type, imgFlag
}
}
- // normals are always swizzled
- if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
- {
+ if (glRefConfig.swizzleNormalmap && (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT))
RawImage_SwizzleRA(data, width, height);
- }
- // LATC2 is only used for normals
- if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT)
- {
- byte *in = data;
- int c = width * height;
- while (c--)
- {
- in[0] = in[1];
- in[2] = in[1];
- in += 4;
- }
- }
-
- // copy or resample data as appropriate for first MIP level
- if ( ( scaled_width == width ) &&
- ( scaled_height == height ) ) {
- if (!(flags & IMGFLAG_MIPMAP))
- {
- RawImage_UploadTexture( data, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse );
- //qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
- *pUploadWidth = scaled_width;
- *pUploadHeight = scaled_height;
+ // This corresponds to what the OpenGL1 renderer does
+ if (!(flags & IMGFLAG_NOLIGHTSCALE) && (!notScaled || mipmap))
+ R_LightScaleTexture(data, width, height, !mipmap);
- goto done;
- }
- Com_Memcpy (scaledBuffer, data, width*height*4);
- }
- else
+ if (subtexture)
{
- // use the normal mip-mapping function to go down from here
- while ( width > scaled_width || height > scaled_height ) {
-
- if (type == IMGTYPE_NORMAL || type == IMGTYPE_NORMALHEIGHT)
- {
- if (internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT)
- {
- R_MipMapLuminanceAlpha( data, data, width, height );
- }
- else
- {
- R_MipMapNormalHeight( data, data, width, height, qtrue);
- }
- }
- else
- {
- R_MipMapsRGB( data, width, height );
- }
-
- width >>= 1;
- height >>= 1;
- if ( width < 1 ) {
- width = 1;
- }
- if ( height < 1 ) {
- height = 1;
- }
- }
- Com_Memcpy( scaledBuffer, data, width * height * 4 );
+ // 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;
}
- if (!(flags & IMGFLAG_NOLIGHTSCALE))
- R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !(flags & IMGFLAG_MIPMAP) );
-
- *pUploadWidth = scaled_width;
- *pUploadHeight = scaled_height;
-
- RawImage_UploadTexture(scaledBuffer, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse);
+ RawImage_UploadTexture(image->texnum, data, 0, 0, width, height, uploadTarget, GL_RGBA8, 0, internalFormat, type, flags, qfalse);
done:
- if (flags & IMGFLAG_MIPMAP)
- {
- if ( glConfig.textureFilterAnisotropic )
- qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
- (GLint)Com_Clamp( 1, glConfig.maxAnisotropy, r_ext_max_anisotropy->integer ) );
-
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
- }
- else
- {
- if ( glConfig.textureFilterAnisotropic )
- qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 );
-
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- }
-
- GL_CheckErrors();
-
- if ( scaledBuffer != 0 )
- ri.Hunk_FreeTempMemory( scaledBuffer );
- if ( resampledBuffer != 0 )
- ri.Hunk_FreeTempMemory( resampledBuffer );
-}
-
-
-static void EmptyTexture( int width, int height, imgType_t type, imgFlags_t flags,
- qboolean lightMap, GLenum internalFormat, int *pUploadWidth, int *pUploadHeight )
-{
- int scaled_width, scaled_height;
-
- RawImage_ScaleToPower2(NULL, &width, &height, &scaled_width, &scaled_height, type, flags, NULL);
-
- *pUploadWidth = scaled_width;
- *pUploadHeight = scaled_height;
-
- RawImage_UploadTexture(NULL, 0, 0, scaled_width, scaled_height, internalFormat, type, flags, qfalse);
+ image->uploadWidth = width;
+ image->uploadHeight = height;
- if (flags & IMGFLAG_MIPMAP)
+ if (mipmap)
{
- if ( glConfig.textureFilterAnisotropic )
- qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
- (GLint)Com_Clamp( 1, glConfig.maxAnisotropy, r_ext_max_anisotropy->integer ) );
+ if (glConfig.textureFilterAnisotropic && !cubemap)
+ qglTextureParameteri(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT,
+ (GLint)Com_Clamp(1, glConfig.maxAnisotropy, r_ext_max_anisotropy->integer));
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
+ qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MIN_FILTER, gl_filter_min);
+ qglTextureParameterf(image->texnum, textureTarget, GL_TEXTURE_MAG_FILTER, gl_filter_max);
}
else
{
- if ( glConfig.textureFilterAnisotropic )
- qglTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1 );
+ if (glConfig.textureFilterAnisotropic && !cubemap)
+ qglTextureParameteri(image->texnum, textureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ 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
@@ -2044,26 +2136,29 @@ static void EmptyTexture( int width, int height, imgType_t type, imgFlags_t flag
case GL_DEPTH_COMPONENT16_ARB:
case GL_DEPTH_COMPONENT24_ARB:
case GL_DEPTH_COMPONENT32_ARB:
- qglTexParameterf(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE );
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ 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;
}
GL_CheckErrors();
+
+ if ( resampledBuffer != NULL )
+ ri.Hunk_FreeTempMemory( resampledBuffer );
}
/*
================
-R_CreateImage
+R_CreateImage2
This is the only way any image_t are created
================
*/
-image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat ) {
+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;
@@ -2097,81 +2192,24 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT
glWrapClampMode = GL_REPEAT;
if (!internalFormat)
- {
- if (image->flags & IMGFLAG_CUBEMAP)
- internalFormat = GL_RGBA8;
- else
- internalFormat = RawImage_GetFormat(pic, width * height, isLightmap, image->type, image->flags);
- }
+ internalFormat = RawImage_GetFormat(pic, width * height, picFormat, isLightmap, image->type, image->flags);
image->internalFormat = internalFormat;
-
- // lightmaps are always allocated on TMU 1
- if ( qglActiveTextureARB && isLightmap ) {
- image->TMU = 1;
- } else {
- image->TMU = 0;
- }
-
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( image->TMU );
- }
+ Upload32(pic, 0, 0, image->width, image->height, picFormat, numMips, image);
if (image->flags & IMGFLAG_CUBEMAP)
{
- GL_Bind(image);
- qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
-
- qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- if (image->flags & IMGFLAG_MIPMAP)
- {
- qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- }
- else
- {
- qglTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
-
- qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
- qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
- qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
- qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
- qglTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
- qglTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pic);
-
- if (image->flags & IMGFLAG_MIPMAP)
- qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP);
-
- image->uploadWidth = width;
- image->uploadHeight = height;
+ 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);
}
else
{
- GL_Bind(image);
-
- if (pic)
- {
- Upload32( pic, image->width, image->height, image->type, image->flags,
- isLightmap, image->internalFormat, &image->uploadWidth,
- &image->uploadHeight );
- }
- else
- {
- EmptyTexture(image->width, image->height, image->type, image->flags,
- isLightmap, image->internalFormat, &image->uploadWidth,
- &image->uploadHeight );
- }
-
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode );
- qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode );
+ qglTextureParameterf(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapClampMode);
+ qglTextureParameterf(image->texnum, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapClampMode);
}
- GL_SelectTexture( 0 );
-
hash = generateHashValue(name);
image->next = hashTable[hash];
hashTable[hash] = image;
@@ -2179,114 +2217,30 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgT
return image;
}
-void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height )
-{
- byte *scaledBuffer = NULL;
- byte *resampledBuffer = NULL;
- int scaled_width, scaled_height, scaled_x, scaled_y;
- byte *data = pic;
-
- // normals are always swizzled
- if (image->type == IMGTYPE_NORMAL || image->type == IMGTYPE_NORMALHEIGHT)
- {
- RawImage_SwizzleRA(pic, width, height);
- }
-
- // LATC2 is only used for normals
- if (image->internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT)
- {
- byte *in = data;
- int c = width * height;
- while (c--)
- {
- in[0] = in[1];
- in[2] = in[1];
- in += 4;
- }
- }
-
-
- RawImage_ScaleToPower2(&pic, &width, &height, &scaled_width, &scaled_height, image->type, image->flags, &resampledBuffer);
-
- scaledBuffer = ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height );
-
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( image->TMU );
- }
-
- GL_Bind(image);
-
- // copy or resample data as appropriate for first MIP level
- if ( ( scaled_width == width ) &&
- ( scaled_height == height ) ) {
- if (!(image->flags & IMGFLAG_MIPMAP))
- {
- scaled_x = x * scaled_width / width;
- scaled_y = y * scaled_height / height;
- RawImage_UploadTexture( data, scaled_x, scaled_y, scaled_width, scaled_height, image->internalFormat, image->type, image->flags, qtrue );
- //qglTexSubImage2D( GL_TEXTURE_2D, 0, scaled_x, scaled_y, scaled_width, scaled_height, GL_RGBA, GL_UNSIGNED_BYTE, data );
-
- GL_CheckErrors();
- goto done;
- }
- Com_Memcpy (scaledBuffer, data, width*height*4);
- }
- else
- {
- // use the normal mip-mapping function to go down from here
- while ( width > scaled_width || height > scaled_height ) {
-
- if (image->type == IMGTYPE_NORMAL || image->type == IMGTYPE_NORMALHEIGHT)
- {
- if (image->internalFormat == GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT)
- {
- R_MipMapLuminanceAlpha( data, data, width, height );
- }
- else
- {
- R_MipMapNormalHeight( data, data, width, height, qtrue);
- }
- }
- else
- {
- R_MipMapsRGB( data, width, height );
- }
-
- width >>= 1;
- height >>= 1;
- x >>= 1;
- y >>= 1;
- if ( width < 1 ) {
- width = 1;
- }
- if ( height < 1 ) {
- height = 1;
- }
- }
- Com_Memcpy( scaledBuffer, data, width * height * 4 );
- }
- if (!(image->flags & IMGFLAG_NOLIGHTSCALE))
- R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, !(image->flags & IMGFLAG_MIPMAP) );
-
- scaled_x = x * scaled_width / width;
- scaled_y = y * scaled_height / height;
- RawImage_UploadTexture( (byte *)data, scaled_x, scaled_y, scaled_width, scaled_height, image->internalFormat, image->type, image->flags, qtrue );
+/*
+================
+R_CreateImage
-done:
-
- GL_SelectTexture( 0 );
+Wrapper for R_CreateImage2(), for the old parameters.
+================
+*/
+image_t *R_CreateImage(const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat)
+{
+ return R_CreateImage2(name, pic, width, height, GL_RGBA8, 0, type, flags, internalFormat);
+}
- GL_CheckErrors();
- if ( scaledBuffer != 0 )
- ri.Hunk_FreeTempMemory( scaledBuffer );
- if ( resampledBuffer != 0 )
- ri.Hunk_FreeTempMemory( resampledBuffer );
+void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height )
+{
+ Upload32(pic, x, y, width, height, GL_RGBA8, 0, image);
}
//===================================================================
+// Prototype for dds loader function which isn't common to both renderers
+void R_LoadDDS(const char *filename, byte **pic, int *width, int *height, GLenum *picFormat, int *numMips);
+
typedef struct
{
char *ext;
@@ -2315,7 +2269,7 @@ Loads any of the supported image types into a cannonical
32 bit format.
=================
*/
-void R_LoadImage( const char *name, byte **pic, int *width, int *height )
+void R_LoadImage( const char *name, byte **pic, int *width, int *height, GLenum *picFormat, int *numMips )
{
qboolean orgNameFailed = qfalse;
int orgLoader = -1;
@@ -2327,11 +2281,28 @@ void R_LoadImage( const char *name, byte **pic, int *width, int *height )
*pic = NULL;
*width = 0;
*height = 0;
+ *picFormat = GL_RGBA8;
+ *numMips = 0;
Q_strncpyz( localName, name, MAX_QPATH );
ext = COM_GetExtension( localName );
+ // If compressed textures are enabled, try loading a DDS first, it'll load fastest
+ if (r_ext_compressed_textures->integer)
+ {
+ char ddsName[MAX_QPATH];
+
+ COM_StripExtension(name, ddsName, MAX_QPATH);
+ Q_strcat(ddsName, MAX_QPATH, ".dds");
+
+ R_LoadDDS(ddsName, pic, width, height, picFormat, numMips);
+
+ // If loaded, we're done.
+ if (*pic)
+ return;
+ }
+
if( *ext )
{
// Look for the correct loader and use it
@@ -2403,7 +2374,10 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
image_t *image;
int width, height;
byte *pic;
+ GLenum picFormat;
+ int picNumMips;
long hash;
+ imgFlags_t checkFlagsTrue, checkFlagsFalse;
if (!name) {
return NULL;
@@ -2429,12 +2403,15 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
//
// load the pic from disk
//
- R_LoadImage( name, &pic, &width, &height );
+ R_LoadImage( name, &pic, &width, &height, &picFormat, &picNumMips );
if ( pic == NULL ) {
return NULL;
}
- if (r_normalMapping->integer && !(type == IMGTYPE_NORMAL) && (flags & IMGFLAG_PICMIP) && (flags & IMGFLAG_MIPMAP) && (flags & IMGFLAG_GENNORMALMAP))
+ checkFlagsTrue = IMGFLAG_PICMIP | IMGFLAG_MIPMAP | IMGFLAG_GENNORMALMAP;
+ checkFlagsFalse = IMGFLAG_CUBEMAP;
+ if (r_normalMapping->integer && (picFormat == GL_RGBA8) && (type == IMGTYPE_COLORALPHA) &&
+ ((flags & checkFlagsTrue) == checkFlagsTrue) && !(flags & checkFlagsFalse))
{
char normalName[MAX_QPATH];
image_t *normalImage;
@@ -2537,7 +2514,21 @@ image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags )
}
}
- image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 );
+ // force mipmaps off if image is compressed but doesn't have enough mips
+ if ((flags & IMGFLAG_MIPMAP) && picFormat != GL_RGBA8 && picFormat != GL_SRGB8_ALPHA8_EXT)
+ {
+ int wh = MAX(width, height);
+ int neededMips = 0;
+ while (wh)
+ {
+ neededMips++;
+ wh >>= 1;
+ }
+ if (neededMips > picNumMips)
+ flags &= ~IMGFLAG_MIPMAP;
+ }
+
+ image = R_CreateImage2( ( char * ) name, pic, width, height, picFormat, picNumMips, type, flags, 0 );
ri.Free( pic );
return image;
}
@@ -2764,6 +2755,12 @@ void R_CreateBuiltinImages( void ) {
tr.renderImage = R_CreateImage("_render", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat);
+ if (r_shadowBlur->integer)
+ 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);
+
if (r_drawSunRays->integer)
tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, rgbFormat);
@@ -2811,7 +2808,6 @@ void R_CreateBuiltinImages( void ) {
if (r_ssao->integer)
{
tr.screenSsaoImage = R_CreateImage("*screenSsao", NULL, width / 2, height / 2, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
- tr.hdrDepthImage = R_CreateImage("*hdrDepth", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_INTENSITY32F_ARB);
}
if (r_shadows->integer == 4)
@@ -2827,11 +2823,8 @@ void R_CreateBuiltinImages( void ) {
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);
- GL_Bind(tr.sunShadowDepthImage[x]);
- 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_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
- qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ 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.screenShadowImage = R_CreateImage("*screenShadow", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8);
@@ -2839,7 +2832,7 @@ void R_CreateBuiltinImages( void ) {
if (r_cubeMapping->integer)
{
- tr.renderCubeImage = R_CreateImage("*renderCube", NULL, CUBE_MAP_SIZE, CUBE_MAP_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat);
+ tr.renderCubeImage = R_CreateImage("*renderCube", NULL, r_cubemapSize->integer, r_cubemapSize->integer, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE | IMGFLAG_MIPMAP | IMGFLAG_CUBEMAP, rgbFormat);
}
}
}
@@ -2856,7 +2849,11 @@ 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 ) {
@@ -2865,6 +2862,11 @@ void R_SetColorMappings( void ) {
tr.overbrightBits = 0;
}
+ // don't allow more overbright bits than map overbright bits
+ if ( tr.overbrightBits > r_mapOverBrightBits->integer ) {
+ tr.overbrightBits = r_mapOverBrightBits->integer;
+ }
+
tr.identityLight = 1.0f / ( 1 << tr.overbrightBits );
tr.identityLightByte = 255 * tr.identityLight;
@@ -2940,15 +2942,7 @@ void R_DeleteTextures( void ) {
tr.numImages = 0;
- Com_Memset( glState.currenttextures, 0, sizeof( glState.currenttextures ) );
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( 1 );
- qglBindTexture( GL_TEXTURE_2D, 0 );
- GL_SelectTexture( 0 );
- qglBindTexture( GL_TEXTURE_2D, 0 );
- } else {
- qglBindTexture( GL_TEXTURE_2D, 0 );
- }
+ GL_BindNullTextures();
}
/*
@@ -3121,7 +3115,7 @@ 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] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
skin->surfaces[0]->shader = R_FindShader( name, LIGHTMAP_NONE, qtrue );
return hSkin;
}
@@ -3192,7 +3186,7 @@ void R_InitSkins( void ) {
skin = tr.skins[0] = ri.Hunk_Alloc( sizeof( skin_t ), h_low );
Q_strncpyz( skin->name, "<default skin>", sizeof( skin->name ) );
skin->numSurfaces = 1;
- skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces ), h_low );
+ skin->surfaces[0] = ri.Hunk_Alloc( sizeof( *skin->surfaces[0] ), h_low );
skin->surfaces[0]->shader = tr.defaultShader;
}
diff --git a/src/renderergl2/tr_image_dds.c b/src/renderergl2/tr_image_dds.c
new file mode 100644
index 00000000..b509014d
--- /dev/null
+++ b/src/renderergl2/tr_image_dds.c
@@ -0,0 +1,498 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+ 2015 James Canete
+
+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
+===========================================================================
+*/
+
+#include "../renderercommon/tr_common.h"
+
+typedef unsigned int ui32_t;
+
+typedef struct ddsHeader_s
+{
+ ui32_t headerSize;
+ ui32_t flags;
+ ui32_t height;
+ ui32_t width;
+ ui32_t pitchOrFirstMipSize;
+ ui32_t volumeDepth;
+ ui32_t numMips;
+ ui32_t reserved1[11];
+ ui32_t always_0x00000020;
+ ui32_t pixelFormatFlags;
+ ui32_t fourCC;
+ ui32_t rgbBitCount;
+ ui32_t rBitMask;
+ ui32_t gBitMask;
+ ui32_t bBitMask;
+ ui32_t aBitMask;
+ ui32_t caps;
+ ui32_t caps2;
+ ui32_t caps3;
+ ui32_t caps4;
+ ui32_t reserved2;
+}
+ddsHeader_t;
+
+// flags:
+#define _DDSFLAGS_REQUIRED 0x001007
+#define _DDSFLAGS_PITCH 0x8
+#define _DDSFLAGS_MIPMAPCOUNT 0x20000
+#define _DDSFLAGS_FIRSTMIPSIZE 0x80000
+#define _DDSFLAGS_VOLUMEDEPTH 0x800000
+
+// pixelFormatFlags:
+#define DDSPF_ALPHAPIXELS 0x1
+#define DDSPF_ALPHA 0x2
+#define DDSPF_FOURCC 0x4
+#define DDSPF_RGB 0x40
+#define DDSPF_YUV 0x200
+#define DDSPF_LUMINANCE 0x20000
+
+// caps:
+#define DDSCAPS_COMPLEX 0x8
+#define DDSCAPS_MIPMAP 0x400000
+#define DDSCAPS_REQUIRED 0x1000
+
+// caps2:
+#define DDSCAPS2_CUBEMAP 0xFE00
+#define DDSCAPS2_VOLUME 0x200000
+
+typedef struct ddsHeaderDxt10_s
+{
+ ui32_t dxgiFormat;
+ ui32_t dimensions;
+ ui32_t miscFlags;
+ ui32_t arraySize;
+ ui32_t miscFlags2;
+}
+ddsHeaderDxt10_t;
+
+// dxgiFormat
+// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb173059%28v=vs.85%29.aspx
+typedef enum DXGI_FORMAT {
+ DXGI_FORMAT_UNKNOWN = 0,
+ DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
+ DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
+ DXGI_FORMAT_R32G32B32A32_UINT = 3,
+ DXGI_FORMAT_R32G32B32A32_SINT = 4,
+ DXGI_FORMAT_R32G32B32_TYPELESS = 5,
+ DXGI_FORMAT_R32G32B32_FLOAT = 6,
+ DXGI_FORMAT_R32G32B32_UINT = 7,
+ DXGI_FORMAT_R32G32B32_SINT = 8,
+ DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
+ DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
+ DXGI_FORMAT_R16G16B16A16_UNORM = 11,
+ DXGI_FORMAT_R16G16B16A16_UINT = 12,
+ DXGI_FORMAT_R16G16B16A16_SNORM = 13,
+ DXGI_FORMAT_R16G16B16A16_SINT = 14,
+ DXGI_FORMAT_R32G32_TYPELESS = 15,
+ DXGI_FORMAT_R32G32_FLOAT = 16,
+ DXGI_FORMAT_R32G32_UINT = 17,
+ DXGI_FORMAT_R32G32_SINT = 18,
+ DXGI_FORMAT_R32G8X24_TYPELESS = 19,
+ DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
+ DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
+ DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
+ DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
+ DXGI_FORMAT_R10G10B10A2_UNORM = 24,
+ DXGI_FORMAT_R10G10B10A2_UINT = 25,
+ DXGI_FORMAT_R11G11B10_FLOAT = 26,
+ DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
+ DXGI_FORMAT_R8G8B8A8_UNORM = 28,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
+ DXGI_FORMAT_R8G8B8A8_UINT = 30,
+ DXGI_FORMAT_R8G8B8A8_SNORM = 31,
+ DXGI_FORMAT_R8G8B8A8_SINT = 32,
+ DXGI_FORMAT_R16G16_TYPELESS = 33,
+ DXGI_FORMAT_R16G16_FLOAT = 34,
+ DXGI_FORMAT_R16G16_UNORM = 35,
+ DXGI_FORMAT_R16G16_UINT = 36,
+ DXGI_FORMAT_R16G16_SNORM = 37,
+ DXGI_FORMAT_R16G16_SINT = 38,
+ DXGI_FORMAT_R32_TYPELESS = 39,
+ DXGI_FORMAT_D32_FLOAT = 40,
+ DXGI_FORMAT_R32_FLOAT = 41,
+ DXGI_FORMAT_R32_UINT = 42,
+ DXGI_FORMAT_R32_SINT = 43,
+ DXGI_FORMAT_R24G8_TYPELESS = 44,
+ DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
+ DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
+ DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
+ DXGI_FORMAT_R8G8_TYPELESS = 48,
+ DXGI_FORMAT_R8G8_UNORM = 49,
+ DXGI_FORMAT_R8G8_UINT = 50,
+ DXGI_FORMAT_R8G8_SNORM = 51,
+ DXGI_FORMAT_R8G8_SINT = 52,
+ DXGI_FORMAT_R16_TYPELESS = 53,
+ DXGI_FORMAT_R16_FLOAT = 54,
+ DXGI_FORMAT_D16_UNORM = 55,
+ DXGI_FORMAT_R16_UNORM = 56,
+ DXGI_FORMAT_R16_UINT = 57,
+ DXGI_FORMAT_R16_SNORM = 58,
+ DXGI_FORMAT_R16_SINT = 59,
+ DXGI_FORMAT_R8_TYPELESS = 60,
+ DXGI_FORMAT_R8_UNORM = 61,
+ DXGI_FORMAT_R8_UINT = 62,
+ DXGI_FORMAT_R8_SNORM = 63,
+ DXGI_FORMAT_R8_SINT = 64,
+ DXGI_FORMAT_A8_UNORM = 65,
+ DXGI_FORMAT_R1_UNORM = 66,
+ DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
+ DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
+ DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
+ DXGI_FORMAT_BC1_TYPELESS = 70,
+ DXGI_FORMAT_BC1_UNORM = 71,
+ DXGI_FORMAT_BC1_UNORM_SRGB = 72,
+ DXGI_FORMAT_BC2_TYPELESS = 73,
+ DXGI_FORMAT_BC2_UNORM = 74,
+ DXGI_FORMAT_BC2_UNORM_SRGB = 75,
+ DXGI_FORMAT_BC3_TYPELESS = 76,
+ DXGI_FORMAT_BC3_UNORM = 77,
+ DXGI_FORMAT_BC3_UNORM_SRGB = 78,
+ DXGI_FORMAT_BC4_TYPELESS = 79,
+ DXGI_FORMAT_BC4_UNORM = 80,
+ DXGI_FORMAT_BC4_SNORM = 81,
+ DXGI_FORMAT_BC5_TYPELESS = 82,
+ DXGI_FORMAT_BC5_UNORM = 83,
+ DXGI_FORMAT_BC5_SNORM = 84,
+ DXGI_FORMAT_B5G6R5_UNORM = 85,
+ DXGI_FORMAT_B5G5R5A1_UNORM = 86,
+ DXGI_FORMAT_B8G8R8A8_UNORM = 87,
+ DXGI_FORMAT_B8G8R8X8_UNORM = 88,
+ DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,
+ DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,
+ DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,
+ DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,
+ DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,
+ DXGI_FORMAT_BC6H_TYPELESS = 94,
+ DXGI_FORMAT_BC6H_UF16 = 95,
+ DXGI_FORMAT_BC6H_SF16 = 96,
+ DXGI_FORMAT_BC7_TYPELESS = 97,
+ DXGI_FORMAT_BC7_UNORM = 98,
+ DXGI_FORMAT_BC7_UNORM_SRGB = 99,
+ DXGI_FORMAT_AYUV = 100,
+ DXGI_FORMAT_Y410 = 101,
+ DXGI_FORMAT_Y416 = 102,
+ DXGI_FORMAT_NV12 = 103,
+ DXGI_FORMAT_P010 = 104,
+ DXGI_FORMAT_P016 = 105,
+ DXGI_FORMAT_420_OPAQUE = 106,
+ DXGI_FORMAT_YUY2 = 107,
+ DXGI_FORMAT_Y210 = 108,
+ DXGI_FORMAT_Y216 = 109,
+ DXGI_FORMAT_NV11 = 110,
+ DXGI_FORMAT_AI44 = 111,
+ DXGI_FORMAT_IA44 = 112,
+ DXGI_FORMAT_P8 = 113,
+ DXGI_FORMAT_A8P8 = 114,
+ DXGI_FORMAT_B4G4R4A4_UNORM = 115,
+ DXGI_FORMAT_FORCE_UINT = 0xffffffffUL
+} DXGI_FORMAT;
+
+#define EncodeFourCC(x) ((((ui32_t)((x)[0])) ) | \
+ (((ui32_t)((x)[1])) << 8 ) | \
+ (((ui32_t)((x)[2])) << 16) | \
+ (((ui32_t)((x)[3])) << 24) )
+
+
+void R_LoadDDS ( const char *filename, byte **pic, int *width, int *height, GLenum *picFormat, int *numMips )
+{
+ union {
+ byte *b;
+ void *v;
+ } buffer;
+ int len;
+ ddsHeader_t *ddsHeader = NULL;
+ ddsHeaderDxt10_t *ddsHeaderDxt10 = NULL;
+ byte *data;
+
+ if (!picFormat)
+ {
+ ri.Printf(PRINT_ERROR, "R_LoadDDS() called without picFormat parameter!");
+ return;
+ }
+
+ if (width)
+ *width = 0;
+ if (height)
+ *height = 0;
+ if (picFormat)
+ *picFormat = GL_RGBA8;
+ if (numMips)
+ *numMips = 1;
+
+ *pic = NULL;
+
+ //
+ // load the file
+ //
+ len = ri.FS_ReadFile( ( char * ) filename, &buffer.v);
+ if (!buffer.b || len < 0) {
+ return;
+ }
+
+ //
+ // reject files that are too small to hold even a header
+ //
+ if (len < 4 + sizeof(*ddsHeader))
+ {
+ ri.Printf(PRINT_ALL, "File %s is too small to be a DDS file.\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ //
+ // reject files that don't start with "DDS "
+ //
+ if (*((ui32_t *)(buffer.b)) != EncodeFourCC("DDS "))
+ {
+ ri.Printf(PRINT_ALL, "File %s is not a DDS file.\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ //
+ // parse header and dx10 header if available
+ //
+ ddsHeader = (ddsHeader_t *)(buffer.b + 4);
+ if ((ddsHeader->pixelFormatFlags & DDSPF_FOURCC) && ddsHeader->fourCC == EncodeFourCC("DX10"))
+ {
+ if (len < 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10))
+ {
+ ri.Printf(PRINT_ALL, "File %s indicates a DX10 header it is too small to contain.\n", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+
+ ddsHeaderDxt10 = (ddsHeaderDxt10_t *)(buffer.b + 4 + sizeof(ddsHeader_t));
+ data = buffer.b + 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10);
+ len -= 4 + sizeof(*ddsHeader) + sizeof(*ddsHeaderDxt10);
+ }
+ else
+ {
+ data = buffer.b + 4 + sizeof(*ddsHeader);
+ len -= 4 + sizeof(*ddsHeader);
+ }
+
+ if (width)
+ *width = ddsHeader->width;
+ if (height)
+ *height = ddsHeader->height;
+
+ if (numMips)
+ {
+ if (ddsHeader->flags & _DDSFLAGS_MIPMAPCOUNT)
+ *numMips = ddsHeader->numMips;
+ else
+ *numMips = 1;
+ }
+
+ // FIXME: handle cube map
+ //if ((ddsHeader->caps2 & DDSCAPS2_CUBEMAP) == DDSCAPS2_CUBEMAP)
+
+ //
+ // Convert DXGI format/FourCC into OpenGL format
+ //
+ if (ddsHeaderDxt10)
+ {
+ switch (ddsHeaderDxt10->dxgiFormat)
+ {
+ case DXGI_FORMAT_BC1_TYPELESS:
+ case DXGI_FORMAT_BC1_UNORM:
+ // FIXME: check for GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+ *picFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ break;
+
+ case DXGI_FORMAT_BC1_UNORM_SRGB:
+ // FIXME: check for GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
+ *picFormat = GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
+ break;
+
+ case DXGI_FORMAT_BC2_TYPELESS:
+ case DXGI_FORMAT_BC2_UNORM:
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ break;
+
+ case DXGI_FORMAT_BC2_UNORM_SRGB:
+ *picFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
+ break;
+
+ case DXGI_FORMAT_BC3_TYPELESS:
+ case DXGI_FORMAT_BC3_UNORM:
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ break;
+
+ case DXGI_FORMAT_BC3_UNORM_SRGB:
+ *picFormat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
+ break;
+
+ case DXGI_FORMAT_BC4_TYPELESS:
+ case DXGI_FORMAT_BC4_UNORM:
+ *picFormat = GL_COMPRESSED_RED_RGTC1;
+ break;
+
+ case DXGI_FORMAT_BC4_SNORM:
+ *picFormat = GL_COMPRESSED_SIGNED_RED_RGTC1;
+ break;
+
+ case DXGI_FORMAT_BC5_TYPELESS:
+ case DXGI_FORMAT_BC5_UNORM:
+ *picFormat = GL_COMPRESSED_RG_RGTC2;
+ break;
+
+ case DXGI_FORMAT_BC5_SNORM:
+ *picFormat = GL_COMPRESSED_SIGNED_RG_RGTC2;
+ break;
+
+ case DXGI_FORMAT_BC6H_TYPELESS:
+ case DXGI_FORMAT_BC6H_UF16:
+ *picFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB;
+ break;
+
+ case DXGI_FORMAT_BC6H_SF16:
+ *picFormat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB;
+ break;
+
+ case DXGI_FORMAT_BC7_TYPELESS:
+ case DXGI_FORMAT_BC7_UNORM:
+ *picFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
+ break;
+
+ case DXGI_FORMAT_BC7_UNORM_SRGB:
+ *picFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB;
+ break;
+
+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+ *picFormat = GL_SRGB8_ALPHA8_EXT;
+ break;
+
+ case DXGI_FORMAT_R8G8B8A8_UNORM:
+ case DXGI_FORMAT_R8G8B8A8_SNORM:
+ *picFormat = GL_RGBA8;
+ break;
+
+ default:
+ ri.Printf(PRINT_ALL, "DDS File %s has unsupported DXGI format %d.", filename, ddsHeaderDxt10->dxgiFormat);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ break;
+ }
+ }
+ else
+ {
+ if (ddsHeader->pixelFormatFlags & DDSPF_FOURCC)
+ {
+ if (ddsHeader->fourCC == EncodeFourCC("DXT1"))
+ *picFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("DXT2"))
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("DXT3"))
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("DXT4"))
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("DXT5"))
+ *picFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ else if (ddsHeader->fourCC == EncodeFourCC("ATI1"))
+ *picFormat = GL_COMPRESSED_RED_RGTC1;
+ else if (ddsHeader->fourCC == EncodeFourCC("BC4U"))
+ *picFormat = GL_COMPRESSED_RED_RGTC1;
+ else if (ddsHeader->fourCC == EncodeFourCC("BC4S"))
+ *picFormat = GL_COMPRESSED_SIGNED_RED_RGTC1;
+ else if (ddsHeader->fourCC == EncodeFourCC("ATI2"))
+ *picFormat = GL_COMPRESSED_RG_RGTC2;
+ else if (ddsHeader->fourCC == EncodeFourCC("BC5U"))
+ *picFormat = GL_COMPRESSED_RG_RGTC2;
+ else if (ddsHeader->fourCC == EncodeFourCC("BC5S"))
+ *picFormat = GL_COMPRESSED_SIGNED_RG_RGTC2;
+ else
+ {
+ ri.Printf(PRINT_ALL, "DDS File %s has unsupported FourCC.", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+ }
+ else if (ddsHeader->pixelFormatFlags == (DDSPF_RGB | DDSPF_ALPHAPIXELS)
+ && ddsHeader->rgbBitCount == 32
+ && ddsHeader->rBitMask == 0x000000ff
+ && ddsHeader->gBitMask == 0x0000ff00
+ && ddsHeader->bBitMask == 0x00ff0000
+ && ddsHeader->aBitMask == 0xff000000)
+ {
+ *picFormat = GL_RGBA8;
+ }
+ else
+ {
+ ri.Printf(PRINT_ALL, "DDS File %s has unsupported RGBA format.", filename);
+ ri.FS_FreeFile(buffer.v);
+ return;
+ }
+ }
+
+ *pic = ri.Malloc(len);
+ Com_Memcpy(*pic, data, len);
+
+ ri.FS_FreeFile(buffer.v);
+}
+
+void R_SaveDDS(const char *filename, byte *pic, int width, int height, int depth)
+{
+ byte *data;
+ ddsHeader_t *ddsHeader;
+ int picSize, size;
+
+ if (!depth)
+ depth = 1;
+
+ picSize = width * height * depth * 4;
+ size = 4 + sizeof(*ddsHeader) + picSize;
+ data = ri.Malloc(size);
+
+ data[0] = 'D';
+ data[1] = 'D';
+ data[2] = 'S';
+ data[3] = ' ';
+
+ ddsHeader = (ddsHeader_t *)(data + 4);
+ memset(ddsHeader, 0, sizeof(ddsHeader_t));
+
+ ddsHeader->headerSize = 0x7c;
+ ddsHeader->flags = _DDSFLAGS_REQUIRED;
+ ddsHeader->height = height;
+ ddsHeader->width = width;
+ ddsHeader->always_0x00000020 = 0x00000020;
+ ddsHeader->caps = DDSCAPS_COMPLEX | DDSCAPS_REQUIRED;
+
+ if (depth == 6)
+ ddsHeader->caps2 = DDSCAPS2_CUBEMAP;
+
+ ddsHeader->pixelFormatFlags = DDSPF_RGB | DDSPF_ALPHAPIXELS;
+ ddsHeader->rgbBitCount = 32;
+ ddsHeader->rBitMask = 0x000000ff;
+ ddsHeader->gBitMask = 0x0000ff00;
+ ddsHeader->bBitMask = 0x00ff0000;
+ ddsHeader->aBitMask = 0xff000000;
+
+ Com_Memcpy(data + 4 + sizeof(*ddsHeader), pic, picSize);
+
+ ri.FS_WriteFile(filename, data, size);
+
+ ri.Free(data);
+}
diff --git a/src/renderergl2/tr_init.c b/src/renderergl2/tr_init.c
index ea62249a..4f0a53f4 100644
--- a/src/renderergl2/tr_init.c
+++ b/src/renderergl2/tr_init.c
@@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h"
+#include "tr_dsa.h"
+
glconfig_t glConfig;
glRefConfig_t glRefConfig;
qboolean textureFilterAnisotropic = qfalse;
@@ -105,6 +107,7 @@ 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;
@@ -128,11 +131,6 @@ cvar_t *r_forceAutoExposure;
cvar_t *r_forceAutoExposureMin;
cvar_t *r_forceAutoExposureMax;
-cvar_t *r_materialGamma;
-cvar_t *r_lightGamma;
-cvar_t *r_framebufferGamma;
-cvar_t *r_tonemapGamma;
-
cvar_t *r_depthPrepass;
cvar_t *r_ssao;
@@ -141,13 +139,14 @@ cvar_t *r_specularMapping;
cvar_t *r_deluxeMapping;
cvar_t *r_parallaxMapping;
cvar_t *r_cubeMapping;
-cvar_t *r_deluxeSpecular;
-cvar_t *r_specularIsMetallic;
+cvar_t *r_cubemapSize;
+cvar_t *r_pbr;
cvar_t *r_baseNormalX;
cvar_t *r_baseNormalY;
cvar_t *r_baseParallax;
cvar_t *r_baseSpecular;
cvar_t *r_baseGloss;
+cvar_t *r_glossType;
cvar_t *r_mergeLightmaps;
cvar_t *r_dlightMode;
cvar_t *r_pshadowDist;
@@ -163,6 +162,7 @@ cvar_t *r_sunlightMode;
cvar_t *r_drawSunRays;
cvar_t *r_sunShadows;
cvar_t *r_shadowFilter;
+cvar_t *r_shadowBlur;
cvar_t *r_shadowMapSize;
cvar_t *r_shadowCascadeZNear;
cvar_t *r_shadowCascadeZFar;
@@ -383,6 +383,7 @@ byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *pa
buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1);
bufstart = PADP((intptr_t) buffer + *offset, packAlign);
+
qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart);
*offset = bufstart - buffer;
@@ -760,6 +761,35 @@ void R_ScreenShotJPEG_f (void) {
/*
==================
+R_ExportCubemaps
+==================
+*/
+void R_ExportCubemaps(void)
+{
+ exportCubemapsCommand_t *cmd;
+
+ cmd = R_GetCommandBuffer(sizeof(*cmd));
+ if (!cmd) {
+ return;
+ }
+ cmd->commandId = RC_EXPORT_CUBEMAPS;
+}
+
+
+/*
+==================
+R_ExportCubemaps_f
+==================
+*/
+void R_ExportCubemaps_f(void)
+{
+ R_ExportCubemaps();
+}
+
+//============================================================================
+
+/*
+==================
RB_TakeVideoFrameCmd
==================
*/
@@ -852,19 +882,11 @@ void GL_SetDefaultState( void )
qglColor4f (1,1,1,1);
- // initialize downstream texture unit if we're running
- // in a multitexture environment
- if ( qglActiveTextureARB ) {
- GL_SelectTexture( 1 );
- GL_TextureMode( r_textureMode->string );
- GL_TexEnv( GL_MODULATE );
- qglDisable( GL_TEXTURE_2D );
- GL_SelectTexture( 0 );
- }
+ GL_BindNullTextures();
+ GL_BindNullFramebuffers();
qglEnable(GL_TEXTURE_2D);
GL_TextureMode( r_textureMode->string );
- GL_TexEnv( GL_MODULATE );
//qglShadeModel( GL_SMOOTH );
qglDepthFunc( GL_LEQUAL );
@@ -877,8 +899,7 @@ void GL_SetDefaultState( void )
glState.faceCulling = CT_TWO_SIDED;
glState.faceCullFront = qtrue;
- glState.currentProgram = 0;
- qglUseProgramObjectARB(0);
+ GL_BindNullProgram();
if (glRefConfig.vertexArrayObject)
qglBindVertexArrayARB(0);
@@ -1077,6 +1098,7 @@ void R_Register( void )
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);
r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic",
"0", CVAR_ARCHIVE | CVAR_LATCH );
@@ -1115,7 +1137,7 @@ void R_Register( void )
r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_postProcess = ri.Cvar_Get( "r_postProcess", "1", CVAR_ARCHIVE );
- r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE | CVAR_LATCH );
+ r_toneMap = ri.Cvar_Get( "r_toneMap", "1", CVAR_ARCHIVE );
r_forceToneMap = ri.Cvar_Get( "r_forceToneMap", "0", CVAR_CHEAT );
r_forceToneMapMin = ri.Cvar_Get( "r_forceToneMapMin", "-8.0", CVAR_CHEAT );
r_forceToneMapAvg = ri.Cvar_Get( "r_forceToneMapAvg", "-2.0", CVAR_CHEAT );
@@ -1128,11 +1150,6 @@ void R_Register( void )
r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "0", CVAR_CHEAT );
- r_materialGamma = ri.Cvar_Get( "r_materialGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
- r_lightGamma = ri.Cvar_Get( "r_lightGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
- r_framebufferGamma = ri.Cvar_Get( "r_framebufferGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
- r_tonemapGamma = ri.Cvar_Get( "r_tonemapGamma", "1.0", CVAR_ARCHIVE | CVAR_LATCH );
-
r_depthPrepass = ri.Cvar_Get( "r_depthPrepass", "1", CVAR_ARCHIVE );
r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE );
@@ -1141,13 +1158,14 @@ void R_Register( void )
r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_ARCHIVE | CVAR_LATCH );
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_deluxeSpecular = ri.Cvar_Get( "r_deluxeSpecular", "0.3", CVAR_ARCHIVE | CVAR_LATCH );
- r_specularIsMetallic = ri.Cvar_Get( "r_specularIsMetallic", "0", CVAR_ARCHIVE | CVAR_LATCH );
+ r_cubemapSize = ri.Cvar_Get( "r_cubemapSize", "128", 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 );
r_baseParallax = ri.Cvar_Get( "r_baseParallax", "0.05", CVAR_ARCHIVE | CVAR_LATCH );
r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH );
r_baseGloss = ri.Cvar_Get( "r_baseGloss", "0.3", CVAR_ARCHIVE | CVAR_LATCH );
+ r_glossType = ri.Cvar_Get("r_glossType", "1", CVAR_ARCHIVE | CVAR_LATCH);
r_dlightMode = ri.Cvar_Get( "r_dlightMode", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE );
r_mergeLightmaps = ri.Cvar_Get( "r_mergeLightmaps", "1", CVAR_ARCHIVE | CVAR_LATCH );
@@ -1165,7 +1183,8 @@ void R_Register( void )
r_sunShadows = ri.Cvar_Get( "r_sunShadows", "1", CVAR_ARCHIVE | CVAR_LATCH );
r_shadowFilter = ri.Cvar_Get( "r_shadowFilter", "1", CVAR_ARCHIVE | CVAR_LATCH );
- r_shadowMapSize = ri.Cvar_Get( "r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH );
+ r_shadowBlur = ri.Cvar_Get("r_shadowBlur", "0", CVAR_ARCHIVE | CVAR_LATCH);
+ r_shadowMapSize = ri.Cvar_Get("r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH);
r_shadowCascadeZNear = ri.Cvar_Get( "r_shadowCascadeZNear", "8", CVAR_ARCHIVE | CVAR_LATCH );
r_shadowCascadeZFar = ri.Cvar_Get( "r_shadowCascadeZFar", "1024", CVAR_ARCHIVE | CVAR_LATCH );
r_shadowCascadeZBias = ri.Cvar_Get( "r_shadowCascadeZBias", "0", CVAR_ARCHIVE | CVAR_LATCH );
@@ -1277,6 +1296,7 @@ void R_Register( void )
ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f );
ri.Cmd_AddCommand( "minimize", GLimp_Minimize );
ri.Cmd_AddCommand( "gfxmeminfo", GfxMemInfo_f );
+ ri.Cmd_AddCommand( "exportCubemaps", R_ExportCubemaps_f );
}
void R_InitQueries(void)
@@ -1418,6 +1438,7 @@ void RE_Shutdown( qboolean destroyWindow ) {
ri.Cmd_RemoveCommand("minimize");
ri.Cmd_RemoveCommand( "shaderstate" );
ri.Cmd_RemoveCommand( "gfxmeminfo" );
+ ri.Cmd_RemoveCommand( "exportCubemaps" );
if ( tr.registered ) {
diff --git a/src/renderergl2/tr_light.c b/src/renderergl2/tr_light.c
index 5993959e..7c661dd5 100644
--- a/src/renderergl2/tr_light.c
+++ b/src/renderergl2/tr_light.c
@@ -157,7 +157,7 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) {
frac[i] = v - pos[i];
if ( pos[i] < 0 ) {
pos[i] = 0;
- } else if ( pos[i] >= world->lightGridBounds[i] - 1 ) {
+ } else if ( pos[i] > world->lightGridBounds[i] - 1 ) {
pos[i] = world->lightGridBounds[i] - 1;
}
}
@@ -181,18 +181,15 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) {
byte *data;
int lat, lng;
vec3_t normal;
- qboolean ignore;
#if idppc
float d0, d1, d2, d3, d4, d5;
#endif
factor = 1.0;
data = gridData;
- ignore = qfalse;
for ( j = 0 ; j < 3 ; j++ ) {
if ( i & (1<<j) ) {
- if ((pos[j] + 1) >= world->lightGridBounds[j] - 1)
- {
- ignore = qtrue; // ignore values outside lightgrid
+ if ( pos[j] + 1 > world->lightGridBounds[j] - 1 ) {
+ break; // ignore values outside lightgrid
}
factor *= frac[j];
data += gridStep[j];
@@ -201,8 +198,9 @@ static void R_SetupEntityLightingGrid( trRefEntity_t *ent, world_t *world ) {
}
}
- if ( ignore )
+ if ( j != 3 ) {
continue;
+ }
if (world->hdrLightGrid)
{
@@ -474,7 +472,7 @@ int R_CubemapForPoint( vec3_t point )
vec3_t diff;
vec_t length;
- VectorSubtract(point, tr.cubemapOrigins[i], diff);
+ VectorSubtract(point, tr.cubemaps[i].origin, diff);
length = DotProduct(diff, diff);
if (shortest > length)
diff --git a/src/renderergl2/tr_local.h b/src/renderergl2/tr_local.h
index 95d87165..5af67a13 100644
--- a/src/renderergl2/tr_local.h
+++ b/src/renderergl2/tr_local.h
@@ -55,10 +55,16 @@ typedef unsigned int glIndex_t;
#define MAX_CALC_PSHADOWS 64
#define MAX_DRAWN_PSHADOWS 16 // do not increase past 32, because bit flags are used on surfaces
#define PSHADOW_MAP_SIZE 512
-#define CUBE_MAP_MIPS 7
-#define CUBE_MAP_SIZE (1 << CUBE_MAP_MIPS)
#define USE_VERT_TANGENT_SPACE
+#define USE_OVERBRIGHT
+
+typedef struct cubemap_s {
+ char name[MAX_QPATH];
+ vec3_t origin;
+ float parallaxRadius;
+ image_t *image;
+} cubemap_t;
typedef struct dlight_s {
vec3_t origin;
@@ -1347,8 +1353,6 @@ typedef struct {
// the renderer front end should never modify glstate_t
typedef struct {
- int currenttextures[NUM_TEXTURE_BUNDLES];
- int currenttmu;
qboolean finishCalled;
int texEnv[2];
int faceCulling;
@@ -1358,7 +1362,6 @@ typedef struct {
float vertexAttribsInterpolation;
qboolean vertexAnimation;
uint32_t vertexAttribsEnabled; // global if no VAOs, tess only otherwise
- shaderProgram_t *currentProgram;
FBO_t *currentFBO;
vao_t *currentVao;
mat4_t modelview;
@@ -1374,7 +1377,7 @@ typedef enum {
typedef enum {
TCR_NONE = 0x0000,
- TCR_LATC = 0x0001,
+ TCR_RGTC = 0x0001,
TCR_BPTC = 0x0002,
} textureCompressionRef_t;
@@ -1398,7 +1401,9 @@ typedef struct {
qboolean textureFloat;
qboolean halfFloatPixel;
qboolean packedDepthStencil;
+ qboolean arbTextureCompression;
textureCompressionRef_t textureCompression;
+ qboolean swizzleNormalmap;
qboolean framebufferMultisample;
qboolean framebufferBlit;
@@ -1414,6 +1419,7 @@ typedef struct {
qboolean floatLightmap;
qboolean vertexArrayObject;
+ qboolean directStateAccess;
} glRefConfig_t;
@@ -1515,6 +1521,7 @@ typedef struct {
image_t *sunRaysImage;
image_t *renderDepthImage;
image_t *pshadowMaps[MAX_DRAWN_PSHADOWS];
+ image_t *screenScratchImage;
image_t *textureScratchImage[2];
image_t *quarterImage[2];
image_t *calcLevelsImage;
@@ -1533,6 +1540,7 @@ typedef struct {
FBO_t *sunRaysFbo;
FBO_t *depthFbo;
FBO_t *pshadowFbos[MAX_DRAWN_PSHADOWS];
+ FBO_t *screenScratchFbo;
FBO_t *textureScratchFbo[2];
FBO_t *quarterFbo[2];
FBO_t *calcLevelsFbo;
@@ -1560,8 +1568,7 @@ typedef struct {
int fatLightmapStep;
int numCubemaps;
- vec3_t *cubemapOrigins;
- image_t **cubemaps;
+ cubemap_t *cubemaps;
trRefEntity_t *currentEntity;
trRefEntity_t worldEntity; // point currentEntity at this when rendering world
@@ -1585,7 +1592,7 @@ typedef struct {
shaderProgram_t calclevels4xShader[2];
shaderProgram_t shadowmaskShader;
shaderProgram_t ssaoShader;
- shaderProgram_t depthBlurShader[2];
+ shaderProgram_t depthBlurShader[4];
shaderProgram_t testcubeShader;
@@ -1714,6 +1721,7 @@ 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;
extern cvar_t *r_nobind; // turns off binding to appropriate textures
extern cvar_t *r_singleShader; // make most world faces use default shader
@@ -1773,11 +1781,6 @@ extern cvar_t *r_forceAutoExposureMax;
extern cvar_t *r_cameraExposure;
-extern cvar_t *r_materialGamma;
-extern cvar_t *r_lightGamma;
-extern cvar_t *r_framebufferGamma;
-extern cvar_t *r_tonemapGamma;
-
extern cvar_t *r_depthPrepass;
extern cvar_t *r_ssao;
@@ -1786,13 +1789,14 @@ extern cvar_t *r_specularMapping;
extern cvar_t *r_deluxeMapping;
extern cvar_t *r_parallaxMapping;
extern cvar_t *r_cubeMapping;
-extern cvar_t *r_deluxeSpecular;
-extern cvar_t *r_specularIsMetallic;
+extern cvar_t *r_cubemapSize;
+extern cvar_t *r_pbr;
extern cvar_t *r_baseNormalX;
extern cvar_t *r_baseNormalY;
extern cvar_t *r_baseParallax;
extern cvar_t *r_baseSpecular;
extern cvar_t *r_baseGloss;
+extern cvar_t *r_glossType;
extern cvar_t *r_dlightMode;
extern cvar_t *r_pshadowDist;
extern cvar_t *r_mergeLightmaps;
@@ -1808,6 +1812,7 @@ extern cvar_t *r_sunlightMode;
extern cvar_t *r_drawSunRays;
extern cvar_t *r_sunShadows;
extern cvar_t *r_shadowFilter;
+extern cvar_t *r_shadowBlur;
extern cvar_t *r_shadowMapSize;
extern cvar_t *r_shadowCascadeZNear;
extern cvar_t *r_shadowCascadeZFar;
@@ -1877,17 +1882,14 @@ void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
/*
** GL wrapper/helper functions
*/
-void GL_Bind( image_t *image );
void GL_BindToTMU( image_t *image, int tmu );
void GL_SetDefaultState (void);
-void GL_SelectTexture( int unit );
void GL_TextureMode( const char *string );
void GL_CheckErrs( char *file, int line );
#define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__)
void GL_State( unsigned long stateVector );
void GL_SetProjectionMatrix(mat4_t matrix);
void GL_SetModelviewMatrix(mat4_t matrix);
-void GL_TexEnv( int env );
void GL_Cull( int cullType );
#define GLS_SRCBLEND_ZERO 0x00000001
@@ -2211,7 +2213,6 @@ void GLSL_InitGPUShaders(void);
void GLSL_ShutdownGPUShaders(void);
void GLSL_VertexAttribPointers(uint32_t attribBits);
void GLSL_BindProgram(shaderProgram_t * program);
-void GLSL_BindNullProgram(void);
void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value);
void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value);
@@ -2280,20 +2281,6 @@ int R_IQMLerpTag( orientation_t *tag, iqmData_t *data,
/*
=============================================================
-
-IMAGE LOADERS
-
-=============================================================
-*/
-
-void R_LoadBMP( const char *name, byte **pic, int *width, int *height );
-void R_LoadJPG( const char *name, byte **pic, int *width, int *height );
-void R_LoadPCX( const char *name, byte **pic, int *width, int *height );
-void R_LoadPNG( const char *name, byte **pic, int *width, int *height );
-void R_LoadTGA( const char *name, byte **pic, int *width, int *height );
-
-/*
-=============================================================
=============================================================
*/
void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
@@ -2427,6 +2414,10 @@ typedef struct {
viewParms_t viewParms;
} postProcessCommand_t;
+typedef struct {
+ int commandId;
+} exportCubemapsCommand_t;
+
typedef enum {
RC_END_OF_LIST,
RC_SET_COLOR,
@@ -2439,7 +2430,8 @@ typedef enum {
RC_COLORMASK,
RC_CLEARDEPTH,
RC_CAPSHADOWMAP,
- RC_POSTPROCESS
+ RC_POSTPROCESS,
+ RC_EXPORT_CUBEMAPS
} renderCommand_t;
diff --git a/src/renderergl2/tr_main.c b/src/renderergl2/tr_main.c
index 132ef309..9751ecb3 100644
--- a/src/renderergl2/tr_main.c
+++ b/src/renderergl2/tr_main.c
@@ -1680,6 +1680,10 @@ int R_SpriteFogNum( trRefEntity_t *ent ) {
return 0;
}
+ if ( ent->e.renderfx & RF_CROSSHAIR ) {
+ return 0;
+ }
+
for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
fog = &tr.world->fogs[i];
for ( j = 0 ; j < 3 ; j++ ) {
@@ -1817,13 +1821,6 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
return;
}
- // if we overflowed MAX_DRAWSURFS, the drawsurfs
- // wrapped around in the buffer and we will be missing
- // the first surfaces, not the last ones
- if ( numDrawSurfs > MAX_DRAWSURFS ) {
- numDrawSurfs = MAX_DRAWSURFS;
- }
-
// sort the drawsurfs by sort type, then orientation, then shader
R_RadixSort( drawSurfs, numDrawSurfs );
@@ -2034,7 +2031,7 @@ void R_DebugGraphics( void ) {
R_IssuePendingRenderCommands();
- GL_Bind( tr.whiteImage);
+ GL_BindToTMU(tr.whiteImage, TB_COLORMAP);
GL_Cull( CT_FRONT_SIDED );
ri.CM_DrawDebugSurface( R_DebugPolygon );
}
@@ -2050,6 +2047,7 @@ or a mirror / remote location
*/
void R_RenderView (viewParms_t *parms) {
int firstDrawSurf;
+ int numDrawSurfs;
if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
return;
@@ -2072,7 +2070,15 @@ void R_RenderView (viewParms_t *parms) {
R_GenerateDrawSurfs();
- R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
+ // if we overflowed MAX_DRAWSURFS, the drawsurfs
+ // wrapped around in the buffer and we will be missing
+ // the first surfaces, not the last ones
+ numDrawSurfs = tr.refdef.numDrawSurfs;
+ if ( numDrawSurfs > MAX_DRAWSURFS ) {
+ numDrawSurfs = MAX_DRAWSURFS;
+ }
+
+ R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, numDrawSurfs - firstDrawSurf );
// draw main system development information (surface outlines, etc)
R_DebugGraphics();
@@ -2857,7 +2863,7 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
memset( &refdef, 0, sizeof( refdef ) );
refdef.rdflags = 0;
- VectorCopy(tr.cubemapOrigins[cubemapIndex], refdef.vieworg);
+ VectorCopy(tr.cubemaps[cubemapIndex].origin, refdef.vieworg);
switch(cubemapSide)
{
@@ -2926,12 +2932,16 @@ 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;
+
+ tr.refdef.colorScale = 1.0f; //766.0f / scale;
// 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 (%f, %f, %f) is outside the lightgrid!\n", cubemapIndex, 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]);
}
}
diff --git a/src/renderergl2/tr_postprocess.c b/src/renderergl2/tr_postprocess.c
index 35982fce..c4e51554 100644
--- a/src/renderergl2/tr_postprocess.c
+++ b/src/renderergl2/tr_postprocess.c
@@ -183,7 +183,7 @@ void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float
FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0);
}
- FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0);
+ FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, NULL, NULL, 0);
}
#else // higher quality blur, but slower
else if (blur > 1.0f)
@@ -217,7 +217,7 @@ void RB_BokehBlur(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, float
FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
}
- FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0);
+ FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, NULL, NULL, 0);
}
#endif
}
@@ -227,54 +227,40 @@ 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);
float scale;
- {
- vec2_t texScale;
-
- texScale[0] =
- texScale[1] = 1.0f;
+ alpha *= inc;
+ VectorSet4(color, alpha, alpha, alpha, 1.0f);
- alpha *= inc;
- VectorSet4(color, alpha, alpha, alpha, 1.0f);
+ srcWidth = srcFbo ? srcFbo->width : glConfig.vidWidth;
+ srcHeight = srcFbo ? srcFbo->height : glConfig.vidHeight;
- VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
- VectorSet4(dstBox, x, y, w, h);
- FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0);
+ VectorSet4(srcBox, 0, 0, srcWidth, srcHeight);
- --passes;
- scale = mul;
- while (passes > 0)
- {
- float iscale = 1.f / scale;
- float s0 = xcenter * (1.f - iscale);
- float t0 = (1.0f - ycenter) * (1.f - iscale);
- float s1 = iscale + s0;
- float t1 = iscale + t0;
+ VectorSet4(dstBox, x, y, w, h);
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0);
- if (srcFbo)
- {
- srcBox[0] = s0 * srcFbo->width;
- srcBox[1] = t0 * srcFbo->height;
- srcBox[2] = (s1 - s0) * srcFbo->width;
- srcBox[3] = (t1 - t0) * srcFbo->height;
- }
- else
- {
- srcBox[0] = s0 * glConfig.vidWidth;
- srcBox[1] = t0 * glConfig.vidHeight;
- srcBox[2] = (s1 - s0) * glConfig.vidWidth;
- srcBox[3] = (t1 - t0) * glConfig.vidHeight;
- }
+ --passes;
+ scale = mul;
+ while (passes > 0)
+ {
+ float iscale = 1.f / scale;
+ float s0 = xcenter * (1.f - iscale);
+ float t0 = (1.0f - ycenter) * (1.f - iscale);
+
+ srcBox[0] = s0 * srcWidth;
+ srcBox[1] = t0 * srcHeight;
+ srcBox[2] = iscale * srcWidth;
+ srcBox[3] = iscale * srcHeight;
- FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
- scale *= mul;
- --passes;
- }
+ scale *= mul;
+ --passes;
}
}
@@ -329,7 +315,7 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
// From RB_DrawSun()
{
float dist;
- mat4_t trans, model, mvp;
+ mat4_t trans, model;
Mat4Translation( backEnd.viewParms.or.origin, trans );
Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model );
@@ -353,28 +339,16 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
// initialize quarter buffers
{
float mul = 1.f;
- vec2_t texScale;
ivec4_t rayBox, quarterBox;
-
- texScale[0] =
- texScale[1] = 1.0f;
+ 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;
@@ -408,14 +382,10 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
// add result back on top of the main buffer
{
float mul = 1.f;
- vec2_t texScale;
-
- texScale[0] =
- texScale[1] = 1.0f;
VectorSet4(color, mul, mul, mul, 1);
- FBO_Blit(tr.quarterFbo[0], NULL, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
+ FBO_Blit(tr.quarterFbo[0], NULL, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
}
}
@@ -443,31 +413,27 @@ static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean h
{
ivec4_t srcBox, dstBox;
vec4_t color;
- vec2_t texScale;
-
- texScale[0] =
- texScale[1] = 1.0f;
VectorSet4(color, weights[0], weights[0], weights[0], 1.0f);
VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->height);
- FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0 );
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0);
VectorSet4(color, weights[1], weights[1], weights[1], 1.0f);
dx = offsets[1] * xmul;
dy = offsets[1] * ymul;
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
- FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
- FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
VectorSet4(color, weights[2], weights[2], weights[2], 1.0f);
dx = offsets[2] * xmul;
dy = offsets[2] * ymul;
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height);
- FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
VectorSet4(srcBox, -dx, -dy, srcFbo->width, srcFbo->height);
- FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
+ FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
}
}
@@ -492,10 +458,6 @@ void RB_GaussianBlur(float blur)
{
ivec4_t srcBox, dstBox;
vec4_t color;
- vec2_t texScale;
-
- texScale[0] =
- texScale[1] = 1.0f;
VectorSet4(color, 1, 1, 1, 1);
@@ -504,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, texScale, tr.textureScratchFbo[0], dstBox, &tr.textureColorShader, 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
@@ -518,6 +478,6 @@ void RB_GaussianBlur(float blur)
VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
color[3] = factor;
- FBO_Blit(tr.textureScratchFbo[0], srcBox, texScale, NULL, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
+ FBO_Blit(tr.textureScratchFbo[0], srcBox, NULL, NULL, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
}
}
diff --git a/src/renderergl2/tr_scene.c b/src/renderergl2/tr_scene.c
index 51bb412e..24108046 100644
--- a/src/renderergl2/tr_scene.c
+++ b/src/renderergl2/tr_scene.c
@@ -336,31 +336,30 @@ void RE_BeginScene(const refdef_t *fd)
}
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);
+ else
+ VectorScale(tr.sunLight, scale, tr.refdef.sunCol);
+
if (r_sunlightMode->integer == 1)
{
- tr.refdef.sunCol[0] =
- tr.refdef.sunCol[1] =
- tr.refdef.sunCol[2] = 1.0f;
-
tr.refdef.sunAmbCol[0] =
tr.refdef.sunAmbCol[1] =
tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale;
}
else
{
- float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8);
if (r_forceSun->integer)
- {
- VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol);
VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol);
- }
else
- {
- VectorScale(tr.sunLight, scale, tr.refdef.sunCol);
VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol);
- }
}
}
diff --git a/src/renderergl2/tr_shade.c b/src/renderergl2/tr_shade.c
index 9853313c..2578420c 100644
--- a/src/renderergl2/tr_shade.c
+++ b/src/renderergl2/tr_shade.c
@@ -102,11 +102,9 @@ static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
int index;
if ( bundle->isVideoMap ) {
- int oldtmu = glState.currenttmu;
- GL_SelectTexture(tmu);
ri.CIN_RunCinematic(bundle->videoMapHandle);
ri.CIN_UploadCinematic(bundle->videoMapHandle);
- GL_SelectTexture(oldtmu);
+ GL_BindToTMU(tr.scratchImage[bundle->videoMapHandle], tmu);
return;
}
@@ -137,7 +135,7 @@ Draws triangle outlines for debugging
================
*/
static void DrawTris (shaderCommands_t *input) {
- GL_Bind( tr.whiteImage );
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
qglDepthRange( 0, 0 );
@@ -415,7 +413,7 @@ static void ProjectDlightTexture( void ) {
vector[3] = scale;
GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector);
- GL_Bind( tr.dlightImage );
+ GL_BindToTMU( tr.dlightImage, TB_COLORMAP );
// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
// where they aren't rendered
@@ -445,9 +443,22 @@ static void ProjectDlightTexture( void ) {
static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor, int blend )
{
+ qboolean isBlend = ((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_DST_COLOR)
+ || ((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR)
+ || ((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_SRC_COLOR)
+ || ((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);
+ qboolean isWorldDraw = !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL);
+ float scale = 1.0f;
+
+#if defined(USE_OVERBRIGHT)
+ float exactLight = 1.0f;
+#else
+ float exactLight = (isBlend || !isWorldDraw) ? 1.0f : (float)(1 << r_mapOverBrightBits->integer);
+#endif
+
baseColor[0] =
baseColor[1] =
- baseColor[2] =
+ baseColor[2] = exactLight;
baseColor[3] = 1.0f;
vertColor[0] =
@@ -474,7 +485,7 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t
vertColor[0] =
vertColor[1] =
- vertColor[2] =
+ vertColor[2] = exactLight;
vertColor[3] = 1.0f;
break;
case CGEN_CONST:
@@ -601,21 +612,16 @@ 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
- && !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_DST_COLOR)
- && !((blend & GLS_SRCBLEND_BITS) == GLS_SRCBLEND_ONE_MINUS_DST_COLOR)
- && !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_SRC_COLOR)
- && !((blend & GLS_DSTBLEND_BITS) == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR))
+ if (tr.overbrightBits && !isBlend)
+ scale *= 1 << tr.overbrightBits;
+
+ if ((backEnd.refdef.colorScale != 1.0f) && !isBlend && isWorldDraw)
+ scale *= backEnd.refdef.colorScale;
+
+ if (scale != 1.0f)
{
- float scale = 1 << tr.overbrightBits;
-
- baseColor[0] *= scale;
- baseColor[1] *= scale;
- baseColor[2] *= scale;
- vertColor[0] *= scale;
- vertColor[1] *= scale;
- vertColor[2] *= scale;
+ VectorScale(baseColor, scale, baseColor);
+ VectorScale(vertColor, scale, vertColor);
}
// FIXME: find some way to implement this.
@@ -855,11 +861,7 @@ static void ForwardDlight( void ) {
}
if (r_dlightMode->integer >= 2)
- {
- GL_SelectTexture(TB_SHADOWMAP);
- GL_Bind(tr.shadowCubemaps[l]);
- GL_SelectTexture(0);
- }
+ GL_BindToTMU(tr.shadowCubemaps[l], TB_SHADOWMAP);
ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb );
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
@@ -1070,6 +1072,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);
@@ -1140,9 +1144,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];
@@ -1185,13 +1189,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);
}
@@ -1231,25 +1228,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);
+ if (r_lightmap->integer)
+ {
+ 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);
- GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);
- if (pStage->bundle[0].tcGen == TCGEN_VECTOR)
+ GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, TCGEN_LIGHTMAP);
+ }
+ else
{
- vec3_t vec;
+ 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);
+ 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, pStage->specularScale);
+ }
//GLSL_SetUniformFloat(sp, UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale);
@@ -1259,7 +1282,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
if ( backEnd.depthFill )
{
if (!(pStage->stateBits & GLS_ATEST_BITS))
- GL_BindToTMU( tr.whiteImage, 0 );
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 )
R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP );
}
@@ -1272,7 +1295,19 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
{
GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP);
GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol);
- GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, backEnd.refdef.sunCol);
+ if (r_pbr->integer)
+ {
+ vec3_t color;
+
+ color[0] = backEnd.refdef.sunCol[0] * backEnd.refdef.sunCol[0];
+ color[1] = backEnd.refdef.sunCol[1] * backEnd.refdef.sunCol[1];
+ color[2] = backEnd.refdef.sunCol[2] * backEnd.refdef.sunCol[2];
+ GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, color);
+ }
+ else
+ {
+ GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, backEnd.refdef.sunCol);
+ }
GLSL_SetUniformVec4(sp, UNIFORM_PRIMARYLIGHTORIGIN, backEnd.refdef.sunDir);
}
@@ -1281,7 +1316,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 );
@@ -1291,7 +1326,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 );
@@ -1368,15 +1403,14 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex && r_cubeMapping->integer)
{
vec4_t vec;
+ cubemap_t *cubemap = &tr.cubemaps[input->cubemapIndex - 1];
- GL_BindToTMU( tr.cubemaps[input->cubemapIndex - 1], TB_CUBEMAP);
+ GL_BindToTMU( cubemap->image, TB_CUBEMAP);
- vec[0] = tr.cubemapOrigins[input->cubemapIndex - 1][0] - backEnd.viewParms.or.origin[0];
- vec[1] = tr.cubemapOrigins[input->cubemapIndex - 1][1] - backEnd.viewParms.or.origin[1];
- vec[2] = tr.cubemapOrigins[input->cubemapIndex - 1][2] - backEnd.viewParms.or.origin[2];
+ VectorSubtract(cubemap->origin, backEnd.viewParms.or.origin, vec);
vec[3] = 1.0f;
- VectorScale4(vec, 1.0f / 1000.0f, vec);
+ VectorScale4(vec, 1.0f / cubemap->parallaxRadius, vec);
GLSL_SetUniformVec4(sp, UNIFORM_CUBEMAPINFO, vec);
}
diff --git a/src/renderergl2/tr_shader.c b/src/renderergl2/tr_shader.c
index 4143b246..2cac0495 100644
--- a/src/renderergl2/tr_shader.c
+++ b/src/renderergl2/tr_shader.c
@@ -935,9 +935,18 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular reflectance in shader '%s'\n", shader.name );
continue;
}
- stage->specularScale[0] =
- stage->specularScale[1] =
- stage->specularScale[2] = atof( token );
+
+ if (r_pbr->integer)
+ {
+ // interpret specularReflectance < 0.5 as nonmetal
+ stage->specularScale[1] = (atof(token) < 0.5f) ? 0.0f : 1.0f;
+ }
+ else
+ {
+ stage->specularScale[0] =
+ stage->specularScale[1] =
+ stage->specularScale[2] = atof( token );
+ }
}
//
// specularExponent <value>
@@ -955,17 +964,23 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
exponent = atof( token );
- // Change shininess to gloss
- // FIXME: assumes max exponent of 8192 and min of 1, must change here if altered in lightall_fp.glsl
- exponent = CLAMP(exponent, 1.0, 8192.0);
-
- stage->specularScale[3] = log(exponent) / log(8192.0);
+ if (r_pbr->integer)
+ stage->specularScale[0] = 1.0f - powf(2.0f / (exponent + 2.0), 0.25);
+ else
+ {
+ // Change shininess to gloss
+ // Assumes max exponent of 8190 and min of 0, must change here if altered in lightall_fp.glsl
+ exponent = CLAMP(exponent, 0.0f, 8190.0f);
+ stage->specularScale[3] = (log2f(exponent + 2.0f) - 1.0f) / 12.0f;
+ }
}
//
// gloss <value>
//
else if (!Q_stricmp(token, "gloss"))
{
+ float gloss;
+
token = COM_ParseExt(text, qfalse);
if ( token[0] == 0 )
{
@@ -973,7 +988,38 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
continue;
}
- stage->specularScale[3] = atof( token );
+ gloss = atof(token);
+
+ if (r_pbr->integer)
+ stage->specularScale[0] = 1.0f - exp2f(-3.0f * gloss);
+ else
+ stage->specularScale[3] = gloss;
+ }
+ //
+ // roughness <value>
+ //
+ else if (!Q_stricmp(token, "roughness"))
+ {
+ float roughness;
+
+ token = COM_ParseExt(text, qfalse);
+ if (token[0] == 0)
+ {
+ ri.Printf(PRINT_WARNING, "WARNING: missing parameter for roughness in shader '%s'\n", shader.name);
+ continue;
+ }
+
+ roughness = atof(token);
+
+ if (r_pbr->integer)
+ stage->specularScale[0] = 1.0 - roughness;
+ else
+ {
+ if (roughness >= 0.125)
+ stage->specularScale[3] = log2f(1.0f / roughness) / 3.0f;
+ else
+ stage->specularScale[3] = 1.0f;
+ }
}
//
// parallaxDepth <value>
@@ -1026,6 +1072,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
}
//
// specularScale <rgb> <gloss>
+ // or specularScale <metallic> <smoothness> with r_pbr 1
// or specularScale <r> <g> <b>
// or specularScale <r> <g> <b> <gloss>
//
@@ -1052,10 +1099,19 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
token = COM_ParseExt(text, qfalse);
if ( token[0] == 0 )
{
- // two values, rgb then gloss
- stage->specularScale[3] = stage->specularScale[1];
- stage->specularScale[1] =
- stage->specularScale[2] = stage->specularScale[0];
+ if (r_pbr->integer)
+ {
+ // two values, metallic then smoothness
+ float smoothness = stage->specularScale[1];
+ stage->specularScale[1] = (stage->specularScale[0] < 0.5f) ? 0.0f : 1.0f;
+ stage->specularScale[0] = smoothness;
+ }
+ {
+ // two values, rgb then gloss
+ stage->specularScale[3] = stage->specularScale[1];
+ stage->specularScale[1] =
+ stage->specularScale[2] = stage->specularScale[0];
+ }
continue;
}
@@ -1857,6 +1913,23 @@ static qboolean ParseShader( char **text )
return qfalse;
}
+ if ( r_greyscale->integer )
+ {
+ float luminance;
+
+ luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
+ VectorSet( shader.fogParms.color, luminance, luminance, luminance );
+ }
+ else if ( r_greyscale->value )
+ {
+ float luminance;
+
+ luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
+ shader.fogParms.color[0] = LERP( shader.fogParms.color[0], luminance, r_greyscale->value );
+ shader.fogParms.color[1] = LERP( shader.fogParms.color[1], luminance, r_greyscale->value );
+ shader.fogParms.color[2] = LERP( shader.fogParms.color[2], luminance, r_greyscale->value );
+ }
+
token = COM_ParseExt( text, qfalse );
if ( !token[0] )
{
@@ -2196,12 +2269,33 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse,
if (r_specularMapping->integer)
{
+ image_t *diffuseImg;
if (specular)
{
//ri.Printf(PRINT_ALL, ", specularmap %s", specular->bundle[0].image[0]->imgName);
diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0];
VectorCopy4(specular->specularScale, diffuse->specularScale);
}
+ else if ((lightmap || useLightVector || useLightVertex) && (diffuseImg = diffuse->bundle[TB_DIFFUSEMAP].image[0]))
+ {
+ char specularName[MAX_QPATH];
+ image_t *specularImg;
+ imgFlags_t specularFlags = (diffuseImg->flags & ~(IMGFLAG_GENNORMALMAP | IMGFLAG_SRGB)) | IMGFLAG_NOLIGHTSCALE;
+
+ COM_StripExtension(diffuseImg->imgName, specularName, MAX_QPATH);
+ Q_strcat(specularName, MAX_QPATH, "_s");
+
+ specularImg = R_FindImageFile(specularName, IMGTYPE_COLORALPHA, specularFlags);
+
+ if (specularImg)
+ {
+ diffuse->bundle[TB_SPECULARMAP] = diffuse->bundle[0];
+ diffuse->bundle[TB_SPECULARMAP].numImageAnimations = 0;
+ diffuse->bundle[TB_SPECULARMAP].image[0] = specularImg;
+
+ VectorSet4(diffuse->specularScale, 1.0f, 1.0f, 1.0f, 1.0f);
+ }
+ }
}
if (tcgen || diffuse->bundle[0].numTexMods)
@@ -2783,10 +2877,17 @@ static void InitShader( const char *name, int lightmapIndex ) {
// default normal/specular
VectorSet4(stages[i].normalScale, 0.0f, 0.0f, 0.0f, 0.0f);
- stages[i].specularScale[0] =
- stages[i].specularScale[1] =
- stages[i].specularScale[2] = r_baseSpecular->value;
- stages[i].specularScale[3] = r_baseGloss->value;
+ if (r_pbr->integer)
+ {
+ stages[i].specularScale[0] = r_baseGloss->value;
+ }
+ else
+ {
+ stages[i].specularScale[0] =
+ stages[i].specularScale[1] =
+ stages[i].specularScale[2] = r_baseSpecular->value;
+ stages[i].specularScale[3] = r_baseGloss->value;
+ }
}
}
diff --git a/src/renderergl2/tr_shadows.c b/src/renderergl2/tr_shadows.c
index fdb39091..33bf4bdc 100644
--- a/src/renderergl2/tr_shadows.c
+++ b/src/renderergl2/tr_shadows.c
@@ -207,7 +207,7 @@ void RB_ShadowTessEnd( void ) {
// draw the silhouette edges
- GL_Bind( tr.whiteImage );
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
qglColor3f( 0.2f, 0.2f, 0.2f );
@@ -257,7 +257,7 @@ void RB_ShadowFinish( void ) {
qglDisable (GL_CLIP_PLANE0);
GL_Cull( CT_TWO_SIDED );
- GL_Bind( tr.whiteImage );
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
qglLoadIdentity ();
diff --git a/src/renderergl2/tr_sky.c b/src/renderergl2/tr_sky.c
index ae1dc2ab..3545a973 100644
--- a/src/renderergl2/tr_sky.c
+++ b/src/renderergl2/tr_sky.c
@@ -375,7 +375,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
//tess.numIndexes = 0;
tess.firstIndex = tess.numIndexes;
- GL_Bind( image );
+ GL_BindToTMU( image, TB_COLORMAP );
GL_Cull( CT_TWO_SIDED );
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
diff --git a/src/renderergl2/tr_surface.c b/src/renderergl2/tr_surface.c
index e6146eef..92802f38 100644
--- a/src/renderergl2/tr_surface.c
+++ b/src/renderergl2/tr_surface.c
@@ -576,7 +576,7 @@ static void RB_SurfaceBeam( void )
VectorAdd( start_points[i], direction, end_points[i] );
}
- GL_Bind( tr.whiteImage );
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
@@ -1519,7 +1519,7 @@ Draws x/y/z lines from the origin for orientation debugging
static void RB_SurfaceAxis( void ) {
// FIXME: implement this
#if 0
- GL_Bind( tr.whiteImage );
+ GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
GL_State( GLS_DEFAULT );
qglLineWidth( 3 );
qglBegin( GL_LINES );
diff --git a/src/sdl/sdl_gamma.c b/src/sdl/sdl_gamma.c
index 0029db18..7e030683 100644
--- a/src/sdl/sdl_gamma.c
+++ b/src/sdl/sdl_gamma.c
@@ -89,6 +89,9 @@ void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned
}
}
- SDL_SetWindowGammaRamp(SDL_window, table[0], table[1], table[2]);
+ if (SDL_SetWindowGammaRamp(SDL_window, table[0], table[1], table[2]) < 0)
+ {
+ ri.Printf( PRINT_DEVELOPER, "SDL_SetWindowGammaRamp() failed: %s\n", SDL_GetError() );
+ }
}
diff --git a/src/sdl/sdl_glimp.c b/src/sdl/sdl_glimp.c
index 51b448a2..fed3fc5b 100644
--- a/src/sdl/sdl_glimp.c
+++ b/src/sdl/sdl_glimp.c
@@ -135,19 +135,32 @@ static void GLimp_DetectAvailableModes(void)
{
int i, j;
char buf[ MAX_STRING_CHARS ] = { 0 };
- SDL_Rect modes[ 128 ];
+ int numSDLModes;
+ SDL_Rect *modes;
int numModes = 0;
- int display = SDL_GetWindowDisplayIndex( SDL_window );
SDL_DisplayMode windowMode;
+ int display = SDL_GetWindowDisplayIndex( SDL_window );
+ if( display < 0 )
+ {
+ ri.Printf( PRINT_WARNING, "Couldn't get window display index, no resolutions detected: %s\n", SDL_GetError() );
+ return;
+ }
+ numSDLModes = SDL_GetNumDisplayModes( display );
- if( SDL_GetWindowDisplayMode( SDL_window, &windowMode ) < 0 )
+ if( SDL_GetWindowDisplayMode( SDL_window, &windowMode ) < 0 || numSDLModes <= 0 )
{
- ri.Printf( PRINT_WARNING, "Couldn't get window display mode, no resolutions detected\n" );
+ ri.Printf( PRINT_WARNING, "Couldn't get window display mode, no resolutions detected: %s\n", SDL_GetError() );
return;
}
- for( i = 0; i < SDL_GetNumDisplayModes( display ); i++ )
+ modes = SDL_calloc( (size_t)numSDLModes, sizeof( SDL_Rect ) );
+ if ( !modes )
+ {
+ ri.Error( ERR_FATAL, "Out of memory" );
+ }
+
+ for( i = 0; i < numSDLModes; i++ )
{
SDL_DisplayMode mode;
@@ -157,6 +170,7 @@ static void GLimp_DetectAvailableModes(void)
if( !mode.w || !mode.h )
{
ri.Printf( PRINT_ALL, "Display supports any resolution\n" );
+ SDL_free( modes );
return;
}
@@ -198,6 +212,7 @@ static void GLimp_DetectAvailableModes(void)
ri.Printf( PRINT_ALL, "Available modes: '%s'\n", buf );
ri.Cvar_Set( "r_availableModes", buf );
}
+ SDL_free( modes );
}
#define R_FAILSAFE_WIDTH 640
@@ -243,9 +258,15 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen, qboolean nobor
// If a window exists, note its display index
if( SDL_window != NULL )
+ {
display = SDL_GetWindowDisplayIndex( SDL_window );
+ if( display < 0 )
+ {
+ ri.Printf( PRINT_DEVELOPER, "SDL_GetWindowDisplayIndex() failed: %s\n", SDL_GetError() );
+ }
+ }
- if( SDL_GetDesktopDisplayMode( display, &desktopMode ) == 0 )
+ if( display >= 0 && SDL_GetDesktopDisplayMode( display, &desktopMode ) == 0 )
{
glConfig.displayAspect = (float)desktopMode.w / (float)desktopMode.h;
@@ -445,7 +466,7 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen, qboolean nobor
#endif
if( ( SDL_window = SDL_CreateWindow( CLIENT_WINDOW_TITLE, x, y,
- glConfig.vidWidth, glConfig.vidHeight, flags ) ) == 0 )
+ glConfig.vidWidth, glConfig.vidHeight, flags ) ) == NULL )
{
ri.Printf( PRINT_DEVELOPER, "SDL_CreateWindow failed: %s\n", SDL_GetError( ) );
continue;
@@ -486,7 +507,10 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen, qboolean nobor
qglClear( GL_COLOR_BUFFER_BIT );
SDL_GL_SwapWindow( SDL_window );
- SDL_GL_SetSwapInterval( r_swapInterval->integer );
+ if( SDL_GL_SetSwapInterval( r_swapInterval->integer ) == -1 )
+ {
+ ri.Printf( PRINT_DEVELOPER, "SDL_GL_SetSwapInterval failed: %s\n", SDL_GetError( ) );
+ }
glConfig.colorBits = testColorBits;
glConfig.depthBits = testDepthBits;
@@ -526,7 +550,7 @@ static qboolean GLimp_StartDriverAndSetMode( qboolean failSafe, qboolean fullscr
{
const char *driverName;
- if (SDL_Init(SDL_INIT_VIDEO) == -1)
+ if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
ri.Printf( PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO ) FAILED (%s)\n", SDL_GetError());
return qfalse;
diff --git a/src/sdl/sdl_input.c b/src/sdl/sdl_input.c
index 2b466744..700834c2 100644
--- a/src/sdl/sdl_input.c
+++ b/src/sdl/sdl_input.c
@@ -366,7 +366,7 @@ static void IN_ActivateMouse( void )
if( !mouseActive )
{
SDL_SetRelativeMouseMode( SDL_TRUE );
- SDL_SetWindowGrab( SDL_window, 1 );
+ SDL_SetWindowGrab( SDL_window, SDL_TRUE );
IN_GobbleMotionEvents( );
}
@@ -377,9 +377,9 @@ static void IN_ActivateMouse( void )
if( in_nograb->modified || !mouseActive )
{
if( in_nograb->integer )
- SDL_SetWindowGrab( SDL_window, 0 );
+ SDL_SetWindowGrab( SDL_window, SDL_FALSE );
else
- SDL_SetWindowGrab( SDL_window, 1 );
+ SDL_SetWindowGrab( SDL_window, SDL_TRUE );
in_nograb->modified = qfalse;
}
@@ -416,7 +416,7 @@ static void IN_DeactivateMouse( void )
{
IN_GobbleMotionEvents( );
- SDL_SetWindowGrab( SDL_window, 0 );
+ SDL_SetWindowGrab( SDL_window, SDL_FALSE );
SDL_SetRelativeMouseMode( SDL_FALSE );
// Don't warp the mouse unless the cursor is within the window
@@ -486,7 +486,7 @@ static void IN_InitJoystick( void )
if (!SDL_WasInit(SDL_INIT_JOYSTICK))
{
Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n");
- if (SDL_Init(SDL_INIT_JOYSTICK) == -1)
+ if (SDL_Init(SDL_INIT_JOYSTICK) != 0)
{
Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) failed: %s\n", SDL_GetError());
return;
diff --git a/src/sdl/sdl_snd.c b/src/sdl/sdl_snd.c
index a087c486..9420f0ba 100644
--- a/src/sdl/sdl_snd.c
+++ b/src/sdl/sdl_snd.c
@@ -157,7 +157,7 @@ qboolean SNDDMA_Init(void)
if (!SDL_WasInit(SDL_INIT_AUDIO))
{
- if (SDL_Init(SDL_INIT_AUDIO) == -1)
+ if (SDL_Init(SDL_INIT_AUDIO) != 0)
{
Com_Printf( "FAILED (%s)\n", SDL_GetError( ) );
return qfalse;
diff --git a/src/server/server.h b/src/server/server.h
index 59b3ff8b..57d34b5b 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -45,7 +45,7 @@ typedef struct voipServerPacket_s
int len;
int sender;
int flags;
- byte data[1024];
+ byte data[4000];
} voipServerPacket_t;
#endif
@@ -281,6 +281,7 @@ extern cvar_t *sv_banFile;
#ifdef USE_VOIP
extern cvar_t *sv_voip;
+extern cvar_t *sv_voipProtocol;
#endif
diff --git a/src/server/sv_client.c b/src/server/sv_client.c
index ba4392f7..dcf6311e 100644
--- a/src/server/sv_client.c
+++ b/src/server/sv_client.c
@@ -1200,8 +1200,8 @@ void SV_UserinfoChanged( client_t *cl ) {
}
#ifdef USE_VOIP
- val = Info_ValueForKey(cl->userinfo, "cl_voip");
- cl->hasVoip = atoi(val);
+ val = Info_ValueForKey(cl->userinfo, "cl_voipProtocol");
+ cl->hasVoip = !Q_stricmp( val, "opus" );
#endif
// TTimo
@@ -1536,7 +1536,7 @@ static qboolean SV_ShouldIgnoreVoipSender(const client_t *cl)
}
static
-void SV_UserVoip(client_t *cl, msg_t *msg)
+void SV_UserVoip(client_t *cl, msg_t *msg, qboolean ignoreData)
{
int sender, generation, sequence, frames, packetsize;
uint8_t recips[(MAX_CLIENTS + 7) / 8];
@@ -1571,12 +1571,12 @@ void SV_UserVoip(client_t *cl, msg_t *msg)
MSG_ReadData(msg, encoded, packetsize);
- if (SV_ShouldIgnoreVoipSender(cl))
+ if (ignoreData || SV_ShouldIgnoreVoipSender(cl))
return; // Blacklisted, disabled, etc.
// !!! FIXME: see if we read past end of msg...
- // !!! FIXME: reject if not speex narrowband codec.
+ // !!! FIXME: reject if not opus data.
// !!! FIXME: decide if this is bogus data?
// decide who needs this VoIP packet sent to them...
@@ -1725,10 +1725,18 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
}
} while ( 1 );
+ // skip legacy speex voip data
+ if ( c == clc_voipSpeex ) {
+#ifdef USE_VOIP
+ SV_UserVoip( cl, msg, qtrue );
+ c = MSG_ReadByte( msg );
+#endif
+ }
+
// read optional voip data
- if ( c == clc_voip ) {
+ if ( c == clc_voipOpus ) {
#ifdef USE_VOIP
- SV_UserVoip( cl, msg );
+ SV_UserVoip( cl, msg, qfalse );
c = MSG_ReadByte( msg );
#endif
}
diff --git a/src/server/sv_init.c b/src/server/sv_init.c
index 3fde62ef..8b8db8f7 100644
--- a/src/server/sv_init.c
+++ b/src/server/sv_init.c
@@ -646,8 +646,9 @@ void SV_Init (void)
sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM );
sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO );
#ifdef USE_VOIP
- sv_voip = Cvar_Get("sv_voip", "1", CVAR_SYSTEMINFO | CVAR_LATCH);
+ sv_voip = Cvar_Get("sv_voip", "1", CVAR_LATCH);
Cvar_CheckRange(sv_voip, 0, 1, qtrue);
+ sv_voipProtocol = Cvar_Get("sv_voipProtocol", sv_voip->integer ? "opus" : "", CVAR_SYSTEMINFO | CVAR_ROM );
#endif
Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );
Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );
diff --git a/src/server/sv_main.c b/src/server/sv_main.c
index 77d1a35d..0c4c7f46 100644
--- a/src/server/sv_main.c
+++ b/src/server/sv_main.c
@@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifdef USE_VOIP
cvar_t *sv_voip;
+cvar_t *sv_voipProtocol;
#endif
serverStatic_t svs; // persistant server info
@@ -656,8 +657,8 @@ void SVC_Info( netadr_t from ) {
Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) );
#ifdef USE_VOIP
- if (sv_voip->integer) {
- Info_SetValueForKey( infostring, "voip", va("%i", sv_voip->integer ) );
+ if (sv_voipProtocol->string && *sv_voipProtocol->string) {
+ Info_SetValueForKey( infostring, "voip", sv_voipProtocol->string );
}
#endif
diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c
index 71c4b86c..58136388 100644
--- a/src/server/sv_snapshot.c
+++ b/src/server/sv_snapshot.c
@@ -548,7 +548,7 @@ static void SV_WriteVoipToClient(client_t *cl, msg_t *msg)
if (totalbytes > (msg->maxsize - msg->cursize) / 2)
break;
- MSG_WriteByte(msg, svc_voip);
+ MSG_WriteByte(msg, svc_voipOpus);
MSG_WriteShort(msg, packet->sender);
MSG_WriteByte(msg, (byte) packet->generation);
MSG_WriteLong(msg, packet->sequence);
diff --git a/src/sys/sys_main.c b/src/sys/sys_main.c
index 53084846..34367ce4 100644
--- a/src/sys/sys_main.c
+++ b/src/sys/sys_main.c
@@ -275,10 +275,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;
diff --git a/src/sys/sys_unix.c b/src/sys/sys_unix.c
index 4e6b1ebf..22af0fcf 100644
--- a/src/sys/sys_unix.c
+++ b/src/sys/sys_unix.c
@@ -116,6 +116,8 @@ qboolean Sys_RandomBytes( byte *string, int len )
if( !fp )
return qfalse;
+ setvbuf( fp, NULL, _IONBF, 0 ); // don't buffer reads from /dev/urandom
+
if( fread( string, sizeof( byte ), len, fp ) != len )
{
fclose( fp );
@@ -806,7 +808,7 @@ void Sys_PlatformInit( void )
signal( SIGHUP, Sys_SigHandler );
signal( SIGQUIT, Sys_SigHandler );
signal( SIGTRAP, Sys_SigHandler );
- signal( SIGIOT, Sys_SigHandler );
+ signal( SIGABRT, Sys_SigHandler );
signal( SIGBUS, Sys_SigHandler );
Sys_SetFloatEnv();
diff --git a/src/sys/sys_win32.c b/src/sys/sys_win32.c
index a2554b89..d8e589b0 100644
--- a/src/sys/sys_win32.c
+++ b/src/sys/sys_win32.c
@@ -412,6 +412,7 @@ char **Sys_ListFiles( const char *directory, const char *extension, char *filter
intptr_t findhandle;
int flag;
int i;
+ int extLen;
if (filter) {
@@ -445,6 +446,8 @@ char **Sys_ListFiles( const char *directory, const char *extension, char *filter
flag = _A_SUBDIR;
}
+ extLen = strlen( extension );
+
Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
// search
@@ -458,6 +461,14 @@ char **Sys_ListFiles( const char *directory, const char *extension, char *filter
do {
if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
+ if (*extension) {
+ if ( strlen( findinfo.name ) < extLen ||
+ Q_stricmp(
+ findinfo.name + strlen( findinfo.name ) - extLen,
+ extension ) ) {
+ continue; // didn't match
+ }
+ }
if ( nfiles == MAX_FOUND_FILES - 1 ) {
break;
}
diff --git a/src/tools/lcc/cpp/unix.c b/src/tools/lcc/cpp/unix.c
index 3e70b562..75e5b6d3 100644
--- a/src/tools/lcc/cpp/unix.c
+++ b/src/tools/lcc/cpp/unix.c
@@ -105,7 +105,8 @@ char *basepath( char *fname )
/* memmove is defined here because some vendors don't provide it at
all and others do a terrible job (like calling malloc) */
// -- ouch, that hurts -- ln
-#ifndef MACOS_X /* always use the system memmove() on Mac OS X. --ryan. */
+/* always use the system memmove() on Mac OS X. --ryan. */
+#if !defined(MACOS_X) && !defined(_MSC_VER)
#ifdef memmove
#undef memmove
#endif