Updating ioq3 dates March 03 2016

This commit is contained in:
Richard Allen 2016-03-03 21:18:53 +00:00
parent c3cc9fb7f7
commit 854aa04376
54 changed files with 3249 additions and 1798 deletions

View file

@ -202,10 +202,6 @@ ifndef USE_INTERNAL_LIBS
USE_INTERNAL_LIBS=1 USE_INTERNAL_LIBS=1
endif endif
ifndef USE_INTERNAL_SPEEX
USE_INTERNAL_SPEEX=$(USE_INTERNAL_LIBS)
endif
ifndef USE_INTERNAL_OGG ifndef USE_INTERNAL_OGG
USE_INTERNAL_OGG=$(USE_INTERNAL_LIBS) USE_INTERNAL_OGG=$(USE_INTERNAL_LIBS)
endif endif
@ -258,7 +254,6 @@ NDIR=$(MOUNT_DIR)/null
UIDIR=$(MOUNT_DIR)/ui UIDIR=$(MOUNT_DIR)/ui
Q3UIDIR=$(MOUNT_DIR)/ui Q3UIDIR=$(MOUNT_DIR)/ui
JPDIR=$(MOUNT_DIR)/jpeg-8c JPDIR=$(MOUNT_DIR)/jpeg-8c
SPEEXDIR=$(MOUNT_DIR)/libspeex
OGGDIR=$(MOUNT_DIR)/libogg-1.3.1 OGGDIR=$(MOUNT_DIR)/libogg-1.3.1
VORBISDIR=$(MOUNT_DIR)/libvorbis-1.3.4 VORBISDIR=$(MOUNT_DIR)/libvorbis-1.3.4
OPUSDIR=$(MOUNT_DIR)/opus-1.1 OPUSDIR=$(MOUNT_DIR)/opus-1.1
@ -571,7 +566,7 @@ ifdef MINGW
SHLIBEXT=dll SHLIBEXT=dll
SHLIBCFLAGS= SHLIBCFLAGS=
SHLIBLDFLAGS=-shared -static-libgcc $(LDFLAGS) SHLIBLDFLAGS=-shared $(LDFLAGS)
BINEXT=.exe BINEXT=.exe
@ -991,8 +986,18 @@ ifeq ($(USE_CURL),1)
endif endif
endif endif
ifeq ($(USE_VOIP),1)
CLIENT_CFLAGS += -DUSE_VOIP
SERVER_CFLAGS += -DUSE_VOIP
NEED_OPUS=1
endif
ifeq ($(USE_CODEC_OPUS),1) ifeq ($(USE_CODEC_OPUS),1)
CLIENT_CFLAGS += -DUSE_CODEC_OPUS CLIENT_CFLAGS += -DUSE_CODEC_OPUS
NEED_OPUS=1
endif
ifeq ($(NEED_OPUS),1)
ifeq ($(USE_INTERNAL_OPUS),1) ifeq ($(USE_INTERNAL_OPUS),1)
OPUS_CFLAGS = -DOPUS_BUILD -DHAVE_LRINTF -DFLOATING_POINT -DUSE_ALLOCA \ OPUS_CFLAGS = -DOPUS_BUILD -DHAVE_LRINTF -DFLOATING_POINT -DUSE_ALLOCA \
-I$(OPUSDIR)/include -I$(OPUSDIR)/celt -I$(OPUSDIR)/silk \ -I$(OPUSDIR)/include -I$(OPUSDIR)/celt -I$(OPUSDIR)/silk \
@ -1038,19 +1043,6 @@ ifeq ($(USE_MUMBLE),1)
CLIENT_CFLAGS += -DUSE_MUMBLE CLIENT_CFLAGS += -DUSE_MUMBLE
endif 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) ifeq ($(USE_INTERNAL_ZLIB),1)
ZLIB_CFLAGS = -DNO_GZIP -I$(ZDIR) ZLIB_CFLAGS = -DNO_GZIP -I$(ZDIR)
else else
@ -1261,7 +1253,7 @@ endif
NAKED_TARGETS=$(shell echo $(TARGETS) | sed -e "s!$(B)/!!g") NAKED_TARGETS=$(shell echo $(TARGETS) | sed -e "s!$(B)/!!g")
print_list=@for i in $(1); \ print_list=-@for i in $(1); \
do \ do \
echo " $$i"; \ echo " $$i"; \
done done
@ -1652,6 +1644,7 @@ Q3R2OBJ = \
$(B)/renderergl2/tr_bsp.o \ $(B)/renderergl2/tr_bsp.o \
$(B)/renderergl2/tr_cmds.o \ $(B)/renderergl2/tr_cmds.o \
$(B)/renderergl2/tr_curve.o \ $(B)/renderergl2/tr_curve.o \
$(B)/renderergl2/tr_dsa.o \
$(B)/renderergl2/tr_extramath.o \ $(B)/renderergl2/tr_extramath.o \
$(B)/renderergl2/tr_extensions.o \ $(B)/renderergl2/tr_extensions.o \
$(B)/renderergl2/tr_fbo.o \ $(B)/renderergl2/tr_fbo.o \
@ -1664,6 +1657,7 @@ Q3R2OBJ = \
$(B)/renderergl2/tr_image_pcx.o \ $(B)/renderergl2/tr_image_pcx.o \
$(B)/renderergl2/tr_image_png.o \ $(B)/renderergl2/tr_image_png.o \
$(B)/renderergl2/tr_image_tga.o \ $(B)/renderergl2/tr_image_tga.o \
$(B)/renderergl2/tr_image_dds.o \
$(B)/renderergl2/tr_init.o \ $(B)/renderergl2/tr_init.o \
$(B)/renderergl2/tr_light.o \ $(B)/renderergl2/tr_light.o \
$(B)/renderergl2/tr_main.o \ $(B)/renderergl2/tr_main.o \
@ -1827,53 +1821,7 @@ ifeq ($(ARCH),x86_64)
$(B)/client/ftola.o $(B)/client/ftola.o
endif endif
ifeq ($(USE_VOIP),1) ifeq ($(NEED_OPUS),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 ($(USE_INTERNAL_OPUS),1) ifeq ($(USE_INTERNAL_OPUS),1)
Q3OBJ += \ Q3OBJ += \
$(B)/client/opus/analysis.o \ $(B)/client/opus/analysis.o \
@ -2556,9 +2504,6 @@ $(B)/client/%.o: $(CMDIR)/%.c
$(B)/client/%.o: $(BLIBDIR)/%.c $(B)/client/%.o: $(BLIBDIR)/%.c
$(DO_BOT_CC) $(DO_BOT_CC)
$(B)/client/%.o: $(SPEEXDIR)/%.c
$(DO_CC)
$(B)/client/%.o: $(OGGDIR)/src/%.c $(B)/client/%.o: $(OGGDIR)/src/%.c
$(DO_CC) $(DO_CC)
@ -2849,7 +2794,6 @@ ifdef MINGW
USE_OPENAL_DLOPEN=$(USE_OPENAL_DLOPEN) \ USE_OPENAL_DLOPEN=$(USE_OPENAL_DLOPEN) \
USE_CURL_DLOPEN=$(USE_CURL_DLOPEN) \ USE_CURL_DLOPEN=$(USE_CURL_DLOPEN) \
USE_INTERNAL_OPUS=$(USE_INTERNAL_OPUS) \ USE_INTERNAL_OPUS=$(USE_INTERNAL_OPUS) \
USE_INTERNAL_SPEEX=$(USE_INTERNAL_SPEEX) \
USE_INTERNAL_ZLIB=$(USE_INTERNAL_ZLIB) \ USE_INTERNAL_ZLIB=$(USE_INTERNAL_ZLIB) \
USE_INTERNAL_JPEG=$(USE_INTERNAL_JPEG) USE_INTERNAL_JPEG=$(USE_INTERNAL_JPEG)
else else

View file

@ -919,37 +919,27 @@ void CL_FirstSnapshot( void ) {
#endif #endif
#ifdef USE_VOIP #ifdef USE_VOIP
if (!clc.speexInitialized) { if (!clc.voipCodecInitialized) {
int i; int i;
speex_bits_init(&clc.speexEncoderBits); int error;
speex_bits_reset(&clc.speexEncoderBits);
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, if ( error ) {
&clc.speexFrameSize); Com_DPrintf("VoIP: Error opus_encoder_create %d\n", error);
speex_encoder_ctl(clc.speexEncoder, SPEEX_GET_SAMPLING_RATE, return;
&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);
for (i = 0; i < MAX_CLIENTS; i++) { for (i = 0; i < MAX_CLIENTS; i++) {
speex_bits_init(&clc.speexDecoderBits[i]); clc.opusDecoder[i] = opus_decoder_create(48000, 1, &error);
speex_bits_reset(&clc.speexDecoderBits[i]); if ( error ) {
clc.speexDecoder[i] = speex_decoder_init(&speex_nb_mode); Com_DPrintf("VoIP: Error opus_decoder_create(%d) %d\n", i, error);
return;
}
clc.voipIgnore[i] = qfalse; clc.voipIgnore[i] = qfalse;
clc.voipGain[i] = 1.0f; clc.voipGain[i] = 1.0f;
} }
clc.speexInitialized = qtrue; clc.voipCodecInitialized = qtrue;
clc.voipMuteAll = qfalse; clc.voipMuteAll = qfalse;
Cmd_AddCommand ("voip", CL_Voip_f); Cmd_AddCommand ("voip", CL_Voip_f);
Cvar_Set("cl_voipSendTarget", "spatial"); Cvar_Set("cl_voipSendTarget", "spatial");

View file

@ -632,6 +632,12 @@ void CL_CreateNewCommands( void ) {
frame_msec = com_frameTime - old_com_frameTime; 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 // if running less than 5fps, truncate the extra time to prevent
// unexpected moves after a hitch // unexpected moves after a hitch
if ( frame_msec > 200 ) { if ( frame_msec > 200 ) {
@ -788,7 +794,7 @@ void CL_WritePacket( void ) {
{ {
if((clc.voipFlags & VOIP_SPATIAL) || Com_IsVoipTarget(clc.voipTargets, sizeof(clc.voipTargets), -1)) 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_WriteByte (&buf, clc.voipOutgoingGeneration);
MSG_WriteLong (&buf, clc.voipOutgoingSequence); MSG_WriteLong (&buf, clc.voipOutgoingSequence);
MSG_WriteByte (&buf, clc.voipOutgoingDataFrames); MSG_WriteByte (&buf, clc.voipOutgoingDataFrames);
@ -809,7 +815,7 @@ void CL_WritePacket( void ) {
MSG_Init (&fakemsg, fakedata, sizeof (fakedata)); MSG_Init (&fakemsg, fakedata, sizeof (fakedata));
MSG_Bitstream (&fakemsg); MSG_Bitstream (&fakemsg);
MSG_WriteLong (&fakemsg, clc.reliableAcknowledge); MSG_WriteLong (&fakemsg, clc.reliableAcknowledge);
MSG_WriteByte (&fakemsg, svc_voip); MSG_WriteByte (&fakemsg, svc_voipOpus);
MSG_WriteShort (&fakemsg, clc.clientNum); MSG_WriteShort (&fakemsg, clc.clientNum);
MSG_WriteByte (&fakemsg, clc.voipOutgoingGeneration); MSG_WriteByte (&fakemsg, clc.voipOutgoingGeneration);
MSG_WriteLong (&fakemsg, clc.voipOutgoingSequence); MSG_WriteLong (&fakemsg, clc.voipOutgoingSequence);

View file

@ -44,6 +44,7 @@ cvar_t *cl_voipSendTarget;
cvar_t *cl_voipGainDuringCapture; cvar_t *cl_voipGainDuringCapture;
cvar_t *cl_voipCaptureMult; cvar_t *cl_voipCaptureMult;
cvar_t *cl_voipShowMeter; cvar_t *cl_voipShowMeter;
cvar_t *cl_voipProtocol;
cvar_t *cl_voip; cvar_t *cl_voip;
#endif #endif
@ -250,8 +251,8 @@ void CL_Voip_f( void )
if (clc.state != CA_ACTIVE) if (clc.state != CA_ACTIVE)
reason = "Not connected to a server"; reason = "Not connected to a server";
else if (!clc.speexInitialized) else if (!clc.voipCodecInitialized)
reason = "Speex not initialized"; reason = "Voip codec not initialized";
else if (!clc.voipEnabled) else if (!clc.voipEnabled)
reason = "Server doesn't support VoIP"; reason = "Server doesn't support VoIP";
else if (!clc.demoplaying && (Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive"))) else if (!clc.demoplaying && (Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")))
@ -306,6 +307,8 @@ void CL_VoipNewGeneration(void)
clc.voipOutgoingGeneration = 1; clc.voipOutgoingGeneration = 1;
clc.voipPower = 0.0f; clc.voipPower = 0.0f;
clc.voipOutgoingSequence = 0; clc.voipOutgoingSequence = 0;
opus_encoder_ctl(clc.opusEncoder, OPUS_RESET_STATE);
} }
/* /*
@ -394,7 +397,7 @@ void CL_VoipParseTargets(void)
=============== ===============
CL_CaptureVoip 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. data for later transmission.
=============== ===============
*/ */
@ -424,11 +427,12 @@ void CL_CaptureVoip(void)
Com_Printf("Until then, VoIP is disabled.\n"); Com_Printf("Until then, VoIP is disabled.\n");
Cvar_Set("cl_voip", "0"); Cvar_Set("cl_voip", "0");
} }
Cvar_Set("cl_voipProtocol", cl_voip->integer ? "opus" : "");
cl_voip->modified = qfalse; cl_voip->modified = qfalse;
cl_rate->modified = qfalse; cl_rate->modified = qfalse;
} }
if (!clc.speexInitialized) if (!clc.voipCodecInitialized)
return; // just in case this gets called at a bad time. return; // just in case this gets called at a bad time.
if (clc.voipOutgoingDataSize > 0) if (clc.voipOutgoingDataSize > 0)
@ -481,80 +485,67 @@ void CL_CaptureVoip(void)
if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio? if ((cl_voipSend->integer) || (finalFrame)) { // user wants to capture audio?
int samples = S_AvailableCaptureSamples(); 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? // enough data buffered in audio hardware to process yet?
if (samples >= (clc.speexFrameSize * mult)) { if (samples >= packetSamples) {
// audio capture is always MONO16 (and that's what speex wants!). // audio capture is always MONO16.
// 2048 will cover 12 uncompressed frames in narrowband mode. static int16_t sampbuffer[VOIP_MAX_PACKET_SAMPLES];
static int16_t sampbuffer[2048];
float voipPower = 0.0f; float voipPower = 0.0f;
int speexFrames = 0; int voipFrames;
int wpos = 0; int i, bytes;
int pos = 0;
if (samples > (clc.speexFrameSize * 4)) if (samples > VOIP_MAX_PACKET_SAMPLES)
samples = (clc.speexFrameSize * 4); samples = VOIP_MAX_PACKET_SAMPLES;
// !!! FIXME: maybe separate recording from encoding, so voipPower // !!! FIXME: maybe separate recording from encoding, so voipPower
// !!! FIXME: updates faster than 4Hz? // !!! FIXME: updates faster than 4Hz?
samples -= samples % clc.speexFrameSize; 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;
S_Capture(samples, (byte *) sampbuffer); // grab from audio card. S_Capture(samples, (byte *) sampbuffer); // grab from audio card.
// this will probably generate multiple speex packets each time. // check the "power" of this packet...
while (samples > 0) { for (i = 0; i < samples; i++) {
int16_t *sampptr = &sampbuffer[pos]; const float flsamp = (float) sampbuffer[i];
int i, bytes; const float s = fabs(flsamp);
voipPower += s * s;
sampbuffer[i] = (int16_t) ((flsamp) * audioMult);
}
// preprocess samples to remove noise... // encode raw audio samples into Opus data...
speex_preprocess_run(clc.speexPreprocessor, sampptr); bytes = opus_encode(clc.opusEncoder, sampbuffer, samples,
(unsigned char *) clc.voipOutgoingData,
// check the "power" of this packet... sizeof (clc.voipOutgoingData));
for (i = 0; i < clc.speexFrameSize; i++) { if ( bytes <= 0 ) {
const float flsamp = (float) sampptr[i]; Com_DPrintf("VoIP: Error encoding %d samples\n", samples);
const float s = fabs(flsamp); bytes = 0;
voipPower += s * s;
sampptr[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++;
} }
clc.voipPower = (voipPower / (32768.0f * 32768.0f * clc.voipPower = (voipPower / (32768.0f * 32768.0f *
((float) (clc.speexFrameSize * speexFrames)))) * ((float) samples))) * 100.0f;
100.0f;
if ((useVad) && (clc.voipPower < cl_voipVADThreshold->value)) { if ((useVad) && (clc.voipPower < cl_voipVADThreshold->value)) {
CL_VoipNewGeneration(); // no "talk" for at least 1/4 second. CL_VoipNewGeneration(); // no "talk" for at least 1/4 second.
} else { } else {
clc.voipOutgoingDataSize = wpos; clc.voipOutgoingDataSize = bytes;
clc.voipOutgoingDataFrames = speexFrames; clc.voipOutgoingDataFrames = voipFrames;
Com_DPrintf("VoIP: Send %d frames, %d bytes, %f power\n", Com_DPrintf("VoIP: Send %d frames, %d bytes, %f power\n",
speexFrames, wpos, clc.voipPower); voipFrames, bytes, clc.voipPower);
#if 0 #if 0
static FILE *encio = NULL; static FILE *encio = NULL;
if (encio == NULL) encio = fopen("voip-outgoing-encoded.bin", "wb"); 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; static FILE *decio = NULL;
if (decio == NULL) decio = fopen("voip-outgoing-decoded.bin", "wb"); 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 #endif
} }
} }
@ -1420,14 +1411,11 @@ void CL_Disconnect( qboolean showMainMenu ) {
cl_voipUseVAD->integer = tmp; cl_voipUseVAD->integer = tmp;
} }
if (clc.speexInitialized) { if (clc.voipCodecInitialized) {
int i; int i;
speex_bits_destroy(&clc.speexEncoderBits); opus_encoder_destroy(clc.opusEncoder);
speex_encoder_destroy(clc.speexEncoder);
speex_preprocess_state_destroy(clc.speexPreprocessor);
for (i = 0; i < MAX_CLIENTS; i++) { for (i = 0; i < MAX_CLIENTS; i++) {
speex_bits_destroy(&clc.speexDecoderBits[i]); opus_decoder_destroy(clc.opusDecoder[i]);
speex_decoder_destroy(clc.speexDecoder[i]);
} }
} }
Cmd_RemoveCommand ("voip"); Cmd_RemoveCommand ("voip");
@ -1808,6 +1796,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 CL_Rcon_f
@ -1820,7 +1852,7 @@ void CL_Rcon_f( void ) {
char message[MAX_RCON_MESSAGE]; char message[MAX_RCON_MESSAGE];
netadr_t to; netadr_t to;
if ( !rcon_client_password->string ) { if ( !rcon_client_password->string[0] ) {
Com_Printf ("You must set 'rconpassword' before\n" Com_Printf ("You must set 'rconpassword' before\n"
"issuing an rcon command.\n"); "issuing an rcon command.\n");
return; return;
@ -3396,6 +3428,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 CL_Init
@ -3559,9 +3641,9 @@ void CL_Init( void ) {
cl_voipVADThreshold = Cvar_Get ("cl_voipVADThreshold", "0.25", CVAR_ARCHIVE); cl_voipVADThreshold = Cvar_Get ("cl_voipVADThreshold", "0.25", CVAR_ARCHIVE);
cl_voipShowMeter = Cvar_Get ("cl_voipShowMeter", "1", 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_ARCHIVE);
cl_voip = Cvar_Get ("cl_voip", "1", CVAR_USERINFO | CVAR_ARCHIVE);
Cvar_CheckRange( cl_voip, 0, 1, qtrue ); Cvar_CheckRange( cl_voip, 0, 1, qtrue );
cl_voipProtocol = Cvar_Get ("cl_voipProtocol", cl_voip->integer ? "opus" : "", CVAR_USERINFO | CVAR_ROM);
#endif #endif
@ -3598,6 +3680,10 @@ void CL_Init( void ) {
Cmd_AddCommand ("model", CL_SetModel_f ); Cmd_AddCommand ("model", CL_SetModel_f );
Cmd_AddCommand ("video", CL_Video_f ); Cmd_AddCommand ("video", CL_Video_f );
Cmd_AddCommand ("stopvideo", CL_StopVideo_f ); Cmd_AddCommand ("stopvideo", CL_StopVideo_f );
if( !com_dedicated->integer ) {
Cmd_AddCommand ("sayto", CL_Sayto_f );
Cmd_SetCommandCompletionFunc( "sayto", CL_CompletePlayerName );
}
CL_InitRef(); CL_InitRef();
SCR_Init (); SCR_Init ();

View file

@ -34,7 +34,8 @@ char *svc_strings[256] = {
"svc_download", "svc_download",
"svc_snapshot", "svc_snapshot",
"svc_EOF", "svc_EOF",
"svc_voip", "svc_voipSpeex",
"svc_voipOpus",
}; };
void SHOWNET( msg_t *msg, char *s) { void SHOWNET( msg_t *msg, char *s) {
@ -359,8 +360,8 @@ void CL_SystemInfoChanged( void ) {
else else
#endif #endif
{ {
s = Info_ValueForKey( systemInfo, "sv_voip" ); s = Info_ValueForKey( systemInfo, "sv_voipProtocol" );
clc.voipEnabled = atoi(s); clc.voipEnabled = !Q_stricmp(s, "opus");
} }
#endif #endif
@ -680,13 +681,13 @@ static void CL_PlayVoip(int sender, int samplecnt, const byte *data, int flags)
{ {
if(flags & VOIP_DIRECT) 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); data, clc.voipGain[sender], -1);
} }
if(flags & VOIP_SPATIAL) 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); data, 1.0f, sender);
} }
} }
@ -699,8 +700,8 @@ A VoIP message has been received from the server
===================== =====================
*/ */
static static
void CL_ParseVoip ( msg_t *msg ) { void CL_ParseVoip ( msg_t *msg, qboolean ignoreData ) {
static short decoded[4096]; // !!! FIXME: don't hardcode. static short decoded[VOIP_MAX_PACKET_SAMPLES*4]; // !!! FIXME: don't hard code
const int sender = MSG_ReadShort(msg); const int sender = MSG_ReadShort(msg);
const int generation = MSG_ReadByte(msg); const int generation = MSG_ReadByte(msg);
@ -708,7 +709,8 @@ void CL_ParseVoip ( msg_t *msg ) {
const int frames = MSG_ReadByte(msg); const int frames = MSG_ReadByte(msg);
const int packetsize = MSG_ReadShort(msg); const int packetsize = MSG_ReadShort(msg);
const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT); const int flags = MSG_ReadBits(msg, VOIP_FLAGCNT);
char encoded[1024]; unsigned char encoded[4000];
int numSamples;
int seqdiff; int seqdiff;
int written = 0; int written = 0;
int i; int i;
@ -738,14 +740,15 @@ void CL_ParseVoip ( msg_t *msg ) {
return; // overlarge packet, bail. return; // overlarge packet, bail.
} }
if (!clc.speexInitialized) { MSG_ReadData(msg, encoded, packetsize);
MSG_ReadData(msg, encoded, packetsize); // skip payload.
return; // can't handle VoIP without libspeex! 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) { } else if (sender >= MAX_CLIENTS) {
MSG_ReadData(msg, encoded, packetsize); // skip payload.
return; // bogus sender. return; // bogus sender.
} else if (CL_ShouldIgnoreVoipSender(sender)) { } else if (CL_ShouldIgnoreVoipSender(sender)) {
MSG_ReadData(msg, encoded, packetsize); // skip payload.
return; // Channel is muted, bail. return; // Channel is muted, bail.
} }
@ -758,70 +761,59 @@ void CL_ParseVoip ( msg_t *msg ) {
// This is a new "generation" ... a new recording started, reset the bits. // This is a new "generation" ... a new recording started, reset the bits.
if (generation != clc.voipIncomingGeneration[sender]) { if (generation != clc.voipIncomingGeneration[sender]) {
Com_DPrintf("VoIP: new generation %d!\n", generation); 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; clc.voipIncomingGeneration[sender] = generation;
seqdiff = 0; seqdiff = 0;
} else if (seqdiff < 0) { // we're ahead of the sequence?! } else if (seqdiff < 0) { // we're ahead of the sequence?!
// This shouldn't happen unless the packet is corrupted or something. // This shouldn't happen unless the packet is corrupted or something.
Com_DPrintf("VoIP: misordered sequence! %d < %d!\n", Com_DPrintf("VoIP: misordered sequence! %d < %d!\n",
sequence, clc.voipIncomingSequence[sender]); sequence, clc.voipIncomingSequence[sender]);
// reset the bits just in case. // reset the decoder just in case.
speex_bits_reset(&clc.speexDecoderBits[sender]); opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
seqdiff = 0; 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. // just start over.
Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n", Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n",
seqdiff, sender); seqdiff, sender);
speex_bits_reset(&clc.speexDecoderBits[sender]); opus_decoder_ctl(clc.opusDecoder[sender], OPUS_RESET_STATE);
seqdiff = 0; seqdiff = 0;
} }
if (seqdiff != 0) { if (seqdiff != 0) {
Com_DPrintf("VoIP: Dropped %d frames from client #%d\n", Com_DPrintf("VoIP: Dropped %d frames from client #%d\n",
seqdiff, sender); seqdiff, sender);
// tell speex that we're missing frames... // tell opus that we're missing frames...
for (i = 0; i < seqdiff; i++) { for (i = 0; i < seqdiff; i++) {
assert((written + clc.speexFrameSize) * 2 < sizeof (decoded)); assert((written + VOIP_MAX_PACKET_SAMPLES) * 2 < sizeof (decoded));
speex_decode_int(clc.speexDecoder[sender], NULL, decoded + written); numSamples = opus_decode(clc.opusDecoder[sender], NULL, 0, decoded + written, VOIP_MAX_PACKET_SAMPLES, 0);
written += clc.speexFrameSize; 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++) { numSamples = opus_decode(clc.opusDecoder[sender], encoded, packetsize, decoded + written, ARRAY_LEN(decoded) - written, 0);
const int len = MSG_ReadByte(msg);
if (len < 0) {
Com_DPrintf("VoIP: Short packet!\n");
break;
}
MSG_ReadData(msg, encoded, len);
// shouldn't happen, but just in case... if ( numSamples <= 0 ) {
if ((written + clc.speexFrameSize) * 2 > sizeof (decoded)) { Com_DPrintf("VoIP: Error decoding voip data from client #%d\n", sender);
Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n", numSamples = 0;
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 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;
} }
#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 += numSamples;
Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n", Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
written * 2, written, i); written * 2, written, frames);
if(written > 0) if(written > 0)
CL_PlayVoip(sender, written, (const byte *) decoded, flags); CL_PlayVoip(sender, written, (const byte *) decoded, flags);
@ -924,9 +916,14 @@ void CL_ParseServerMessage( msg_t *msg ) {
case svc_download: case svc_download:
CL_ParseDownload( msg ); CL_ParseDownload( msg );
break; break;
case svc_voip: case svc_voipSpeex:
#ifdef USE_VOIP #ifdef USE_VOIP
CL_ParseVoip( msg ); CL_ParseVoip( msg, qtrue );
#endif
break;
case svc_voipOpus:
#ifdef USE_VOIP
CL_ParseVoip( msg, !clc.voipEnabled );
#endif #endif
break; break;
} }

View file

@ -35,8 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif /* USE_CURL */ #endif /* USE_CURL */
#ifdef USE_VOIP #ifdef USE_VOIP
#include "speex/speex.h" #include <opus.h>
#include "speex/speex_preprocess.h"
#endif #endif
// file full of random crap that gets used to create cl_guid // file full of random crap that gets used to create cl_guid
@ -238,14 +237,11 @@ typedef struct {
#ifdef USE_VOIP #ifdef USE_VOIP
qboolean voipEnabled; qboolean voipEnabled;
qboolean speexInitialized; qboolean voipCodecInitialized;
int speexFrameSize;
int speexSampleRate;
// incoming data... // incoming data...
// !!! FIXME: convert from parallel arrays to array of a struct. // !!! FIXME: convert from parallel arrays to array of a struct.
SpeexBits speexDecoderBits[MAX_CLIENTS]; OpusDecoder *opusDecoder[MAX_CLIENTS];
void *speexDecoder[MAX_CLIENTS];
byte voipIncomingGeneration[MAX_CLIENTS]; byte voipIncomingGeneration[MAX_CLIENTS];
int voipIncomingSequence[MAX_CLIENTS]; int voipIncomingSequence[MAX_CLIENTS];
float voipGain[MAX_CLIENTS]; float voipGain[MAX_CLIENTS];
@ -257,9 +253,7 @@ typedef struct {
// then we are sending to clientnum i. // then we are sending to clientnum i.
uint8_t voipTargets[(MAX_CLIENTS + 7) / 8]; uint8_t voipTargets[(MAX_CLIENTS + 7) / 8];
uint8_t voipFlags; uint8_t voipFlags;
SpeexPreprocessState *speexPreprocessor; OpusEncoder *opusEncoder;
SpeexBits speexEncoderBits;
void *speexEncoder;
int voipOutgoingDataSize; int voipOutgoingDataSize;
int voipOutgoingDataFrames; int voipOutgoingDataFrames;
int voipOutgoingSequence; int voipOutgoingSequence;
@ -447,6 +441,13 @@ extern cvar_t *cl_voipGainDuringCapture;
extern cvar_t *cl_voipCaptureMult; extern cvar_t *cl_voipCaptureMult;
extern cvar_t *cl_voipShowMeter; extern cvar_t *cl_voipShowMeter;
extern cvar_t *cl_voip; 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 #endif
//================================================= //=================================================

View file

@ -3443,16 +3443,12 @@ qboolean S_AL_Init( soundInterface_t *si )
s_alAvailableInputDevices = Cvar_Get("s_alAvailableInputDevices", inputdevicenames, CVAR_ROM | CVAR_NORESTART); 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"); 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 ) if( !alCaptureDevice && inputdevice )
{ {
Com_Printf( "Failed to open OpenAL Input device '%s', trying default.\n", 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", Com_Printf( "OpenAL capture device %s.\n",
(alCaptureDevice == NULL) ? "failed to open" : "opened"); (alCaptureDevice == NULL) ? "failed to open" : "opened");

View file

@ -1752,7 +1752,7 @@ static void Cmd_Tell_f(gentity_t * ent)
} }
//Slicer : no TELL FOR TP //Slicer : no TELL FOR TP
if (!g_gametype.integer < GT_TEAM) if (g_gametype.integer >= GT_TEAM)
return; return;
trap_Argv(1, arg, sizeof(arg)); trap_Argv(1, arg, sizeof(arg));

View file

@ -3585,3 +3585,177 @@ qboolean Com_IsVoipTarget(uint8_t *voipTargets, int voipTargetsSize, int clientN
return qfalse; 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 );
}

353
code/qcommon/json.h Normal file
View file

@ -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

View file

@ -27,26 +27,26 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// A user mod should never modify this file // A user mod should never modify this file
#ifdef STANDALONE #ifdef STANDALONE
#define PRODUCT_NAME "Reaction" #define PRODUCT_NAME "Reaction"
#define BASEGAME "Boomstick" #define BASEGAME "Boomstick"
#define CLIENT_WINDOW_TITLE "Reaction" #define CLIENT_WINDOW_TITLE "Reaction"
#define CLIENT_WINDOW_MIN_TITLE "Reaction" #define CLIENT_WINDOW_MIN_TITLE "Reaction"
#define HOMEPATH_NAME_UNIX ".Reaction" #define HOMEPATH_NAME_UNIX ".Reaction"
#define HOMEPATH_NAME_WIN "Reaction" #define HOMEPATH_NAME_WIN "Reaction"
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN #define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
// #define STEAMPATH_NAME "Foo Bar" // #define STEAMPATH_NAME "Foo Bar"
// #define STEAMPATH_APPID "" // #define STEAMPATH_APPID ""
#define GAMENAME_FOR_MASTER "Reaction" #define GAMENAME_FOR_MASTER "Reaction"
// #define LEGACY_PROTOCOL // You probably don't need this for your standalone game // #define LEGACY_PROTOCOL // You probably don't need this for your standalone game
#else #else
#define PRODUCT_NAME "Reaction" #define PRODUCT_NAME "Reaction"
#define BASEGAME "Boomstick" #define BASEGAME "Boomstick"
#define CLIENT_WINDOW_TITLE "Reaction" #define CLIENT_WINDOW_TITLE "Reaction"
#define CLIENT_WINDOW_MIN_TITLE "Reaction" #define CLIENT_WINDOW_MIN_TITLE "Reaction"
#define HOMEPATH_NAME_UNIX ".Reaction" #define HOMEPATH_NAME_UNIX ".Reaction"
#define HOMEPATH_NAME_WIN "Reaction" #define HOMEPATH_NAME_WIN "Reaction"
#define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN #define HOMEPATH_NAME_MACOSX HOMEPATH_NAME_WIN
// #define STEAMPATH_NAME "Foo Bar" // #define STEAMPATH_NAME "Foo Bar"
// #define STEAMPATH_APPID "" // #define STEAMPATH_APPID ""
#define GAMENAME_FOR_MASTER "Reaction" #define GAMENAME_FOR_MASTER "Reaction"
// #define LEGACY_PROTOCOL // #define LEGACY_PROTOCOL

View file

@ -300,7 +300,8 @@ enum svc_ops_e {
svc_EOF, svc_EOF,
// new commands, supported only by ioquake3 protocol but not legacy // 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, //
}; };
@ -316,7 +317,8 @@ enum clc_ops_e {
clc_EOF, clc_EOF,
// new commands, supported only by ioquake3 protocol but not legacy // 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, //
}; };
/* /*
@ -760,6 +762,7 @@ void Field_CompleteFilename( const char *dir,
const char *ext, qboolean stripExt, qboolean allowNonPureFilesOnDisk ); const char *ext, qboolean stripExt, qboolean allowNonPureFilesOnDisk );
void Field_CompleteCommand( char *cmd, void Field_CompleteCommand( char *cmd,
qboolean doCommands, qboolean doCvars ); qboolean doCommands, qboolean doCvars );
void Field_CompletePlayerName( char **names, int count );
/* /*
============================================================== ==============================================================
@ -839,6 +842,10 @@ void Com_StartupVariable( const char *match );
// if match is NULL, all set commands will be executed, otherwise // if match is NULL, all set commands will be executed, otherwise
// only a set with the exact name. Only used during startup. // 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_developer;
extern cvar_t *com_dedicated; extern cvar_t *com_dedicated;

View file

@ -677,12 +677,12 @@ extern void (APIENTRY * qglRenderbufferStorageMultisampleEXT)(GLenum target, GLs
#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 #define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9
#endif #endif
#ifndef GL_EXT_texture_compression_latc #ifndef GL_ARB_texture_compression_rgtc
#define GL_EXT_texture_compression_latc #define GL_ARB_texture_compression_rgtc
#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70 #define GL_COMPRESSED_RED_RGTC1 0x8DBB
#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71 #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72 #define GL_COMPRESSED_RG_RGTC2 0x8DBD
#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73 #define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
#endif #endif
#ifndef GL_ARB_texture_compression_bptc #ifndef GL_ARB_texture_compression_bptc
@ -736,6 +736,51 @@ extern GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array);
#define GL_VERTEX_ARRAY_BINDING_ARB 0x85B5 #define GL_VERTEX_ARRAY_BINDING_ARB 0x85B5
#endif #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) #if defined(WIN32)
// WGL_ARB_create_context // WGL_ARB_create_context

View file

@ -20,6 +20,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=========================================================================== ===========================================================================
*/ */
#include <setjmp.h>
#include "tr_common.h" #include "tr_common.h"
/* /*
@ -42,16 +44,27 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# endif # endif
#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]; 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); (*cinfo->err->format_message) (cinfo, buffer);
/* Let the memory manager delete any temp files before we die */ ri.Printf(PRINT_ALL, "Error: %s", buffer);
jpeg_destroy(cinfo);
/* Return control to the setjmp point */
ri.Error(ERR_FATAL, "%s", buffer); longjmp(jerr->setjmp_buffer, 1);
} }
static void R_JPGOutputMessage(j_common_ptr cinfo) static void R_JPGOutputMessage(j_common_ptr cinfo)
@ -83,7 +96,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 * Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems. * struct, to avoid dangling-pointer problems.
*/ */
struct jpeg_error_mgr jerr; q_jpeg_error_mgr_t jerr;
/* More stuff */ /* More stuff */
JSAMPARRAY buffer; /* Output row buffer */ JSAMPARRAY buffer; /* Output row buffer */
unsigned int row_stride; /* physical row width in output buffer */ unsigned int row_stride; /* physical row width in output buffer */
@ -115,10 +128,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 * This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo. * 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->error_exit = R_JPGErrorExit;
cinfo.err->output_message = R_JPGOutputMessage; 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. */ /* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo); jpeg_create_decompress(&cinfo);
@ -361,17 +388,29 @@ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality,
int image_width, int image_height, byte *image_buffer, int padding) int image_width, int image_height, byte *image_buffer, int padding)
{ {
struct jpeg_compress_struct cinfo; 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] */ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
my_dest_ptr dest; my_dest_ptr dest;
int row_stride; /* physical row width in image buffer */ int row_stride; /* physical row width in image buffer */
size_t outcount; size_t outcount;
/* Step 1: allocate and initialize JPEG compression object */ /* 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->error_exit = R_JPGErrorExit;
cinfo.err->output_message = R_JPGOutputMessage; 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. */ /* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo); jpeg_create_compress(&cinfo);

View file

@ -495,8 +495,6 @@ void RB_BeginDrawingView (void) {
} }
#define MAC_EVENT_PUMP_MSEC 5
/* /*
================== ==================
RB_RenderDrawSurfList RB_RenderDrawSurfList

View file

@ -114,20 +114,20 @@ void R_IssuePendingRenderCommands( void ) {
/* /*
============ ============
R_GetCommandBuffer R_GetCommandBufferReserved
make sure there is enough command space make sure there is enough command space
============ ============
*/ */
void *R_GetCommandBuffer( int bytes ) { void *R_GetCommandBufferReserved( int bytes, int reservedBytes ) {
renderCommandList_t *cmdList; renderCommandList_t *cmdList;
cmdList = &backEndData->commands; cmdList = &backEndData->commands;
bytes = PAD(bytes, sizeof(void *)); bytes = PAD(bytes, sizeof(void *));
// always leave room for the end of list command // always leave room for the end of list command
if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) { if ( cmdList->used + bytes + sizeof( int ) + reservedBytes > MAX_RENDER_COMMANDS ) {
if ( bytes > MAX_RENDER_COMMANDS - 4 ) { if ( bytes > MAX_RENDER_COMMANDS - sizeof( int ) ) {
ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes ); ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
} }
// if we run out of room, just start dropping commands // if we run out of room, just start dropping commands
@ -139,6 +139,17 @@ void *R_GetCommandBuffer( int bytes ) {
return cmdList->cmds + cmdList->used - 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 *) ) );
}
/* /*
============= =============
@ -454,7 +465,7 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
if ( !tr.registered ) { if ( !tr.registered ) {
return; return;
} }
cmd = R_GetCommandBuffer( sizeof( *cmd ) ); cmd = R_GetCommandBufferReserved( sizeof( *cmd ), 0 );
if ( !cmd ) { if ( !cmd ) {
return; return;
} }

View file

@ -557,6 +557,7 @@ static void Upload32( unsigned *data,
qboolean mipmap, qboolean mipmap,
qboolean picmip, qboolean picmip,
qboolean lightMap, qboolean lightMap,
qboolean allowCompression,
int *format, int *format,
int *pUploadWidth, int *pUploadHeight ) int *pUploadWidth, int *pUploadHeight )
{ {
@ -692,11 +693,11 @@ static void Upload32( unsigned *data,
} }
else else
{ {
if ( glConfig.textureCompression == TC_S3TC_ARB ) if ( allowCompression && glConfig.textureCompression == TC_S3TC_ARB )
{ {
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
} }
else if ( glConfig.textureCompression == TC_S3TC ) else if ( allowCompression && glConfig.textureCompression == TC_S3TC )
{ {
internalFormat = GL_RGB4_S3TC; internalFormat = GL_RGB4_S3TC;
} }
@ -892,6 +893,7 @@ image_t *R_CreateImage( const char *name, byte *pic, int width, int height,
image->flags & IMGFLAG_MIPMAP, image->flags & IMGFLAG_MIPMAP,
image->flags & IMGFLAG_PICMIP, image->flags & IMGFLAG_PICMIP,
isLightmap, isLightmap,
!(image->flags & IMGFLAG_NO_COMPRESSION),
&image->internalFormat, &image->internalFormat,
&image->uploadWidth, &image->uploadWidth,
&image->uploadHeight ); &image->uploadHeight );

View file

@ -1146,13 +1146,6 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
return; 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 // sort the drawsurfs by sort type, then orientation, then shader
R_RadixSort( drawSurfs, numDrawSurfs ); R_RadixSort( drawSurfs, numDrawSurfs );
@ -1361,6 +1354,7 @@ or a mirror / remote location
*/ */
void R_RenderView (viewParms_t *parms) { void R_RenderView (viewParms_t *parms) {
int firstDrawSurf; int firstDrawSurf;
int numDrawSurfs;
if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
return; return;
@ -1383,7 +1377,15 @@ void R_RenderView (viewParms_t *parms) {
R_GenerateDrawSurfs(); 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) // draw main system development information (surface outlines, etc)
R_DebugGraphics(); R_DebugGraphics();

View file

@ -14,8 +14,8 @@ vec3 GetValues(vec2 offset, vec3 current)
#ifdef FIRST_PASS #ifdef FIRST_PASS
#if defined(r_framebufferGamma) #if defined(USE_PBR)
minAvgMax = pow(minAvgMax, vec3(r_framebufferGamma)); minAvgMax *= minAvgMax;
#endif #endif
float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001); float lumi = max(dot(LUMINANCE_VECTOR, minAvgMax), 0.000001);

View file

@ -29,11 +29,6 @@ uniform samplerCube u_CubeMap;
uniform vec4 u_EnableTextures; uniform vec4 u_EnableTextures;
#endif #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) #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
uniform vec3 u_PrimaryLightColor; uniform vec3 u_PrimaryLightColor;
uniform vec3 u_PrimaryLightAmbient; uniform vec3 u_PrimaryLightAmbient;
@ -53,6 +48,9 @@ uniform vec4 u_CubeMapInfo;
varying vec4 var_TexCoords; varying vec4 var_TexCoords;
varying vec4 var_Color; 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_LIGHT) && !defined(USE_FAST_LIGHT))
#if defined(USE_VERT_TANGENT_SPACE) #if defined(USE_VERT_TANGENT_SPACE)
@ -150,156 +148,35 @@ float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap)
} }
#endif #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) #if defined(USE_BURLEY)
float gamma = dot(E, L) - NE * NL; // modified from https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf
float B = 2.22222 + 0.1 * shininess; float fd90 = -0.5 + EH * EH * roughness;
float burley = 1.0 + fd90 * 0.04 / NH;
#if defined(USE_OREN_NAYAR) burley *= burley;
float A = 1.0 - 1.0 / (2.0 + 0.33 * shininess); return diffuseAlbedo * burley;
gamma = clamp(gamma, 0.0, 1.0); #else
#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; 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);
#else
return norm * pow(NH, shininess);
#endif #endif
} }
float CalcGGX(float NH, float gloss) vec3 EnvironmentBRDF(float roughness, float NE, vec3 specular)
{ {
// from http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf // from http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
float a_sq = exp2(gloss * -13.0 + 1.0); float v = 1.0 - max(roughness, NE);
float d = ((NH * NH) * (a_sq - 1.0) + 1.0); v *= v * v;
return a_sq / (d * d); return vec3(v) + specular;
} }
float CalcFresnel(float EH) vec3 CalcSpecular(vec3 specular, float NH, float EH, float roughness)
{ {
#if 1 // from http://community.arm.com/servlet/JiveServlet/download/96891546-19496/siggraph2015-mmg-renaldas-slides.pdf
// From http://blog.selfshadow.com/publications/s2013-shading-course/lazarov/s2013_pbs_black_ops_2_notes.pdf float rr = roughness*roughness;
// not accurate, but fast float rrrr = rr*rr;
return exp2(-10.0 * EH); float d = (NH * NH) * (rrrr - 1.0) + 1.0;
#elif 0 float v = (EH * EH) * (roughness + 0.5);
// From http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximation-for-blinn-phong-phong-and-fresnel/ return specular * (rrrr / (4.0 * d * d * v));
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);
#endif
}
float CalcVisibility(float NH, float NL, float NE, float EH, float gloss)
{
#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
}
vec3 CalcSpecular(vec3 specular, float NH, float NL, float NE, float EH, float gloss, float shininess)
{
#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);
} }
@ -341,7 +218,7 @@ mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv )
void main() void main()
{ {
vec3 viewDir, lightColor, ambientColor; vec3 viewDir, lightColor, ambientColor, reflectance;
vec3 L, N, E, H; vec3 L, N, E, H;
float NL, NH, NE, EH, attenuation; float NL, NH, NE, EH, attenuation;
@ -353,21 +230,20 @@ void main()
mat3 tangentToWorld = cotangent_frame(var_Normal, -var_ViewDir, var_TexCoords.xy); mat3 tangentToWorld = cotangent_frame(var_Normal, -var_ViewDir, var_TexCoords.xy);
viewDir = var_ViewDir; viewDir = var_ViewDir;
#endif #endif
E = normalize(viewDir); 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 #endif
lightColor = var_Color.rgb;
#if defined(USE_LIGHTMAP) #if defined(USE_LIGHTMAP)
vec4 lightmapColor = texture2D(u_LightMap, var_TexCoords.zw); vec4 lightmapColor = texture2D(u_LightMap, var_TexCoords.zw);
#if defined(RGBM_LIGHTMAP) #if defined(RGBM_LIGHTMAP)
lightmapColor.rgb *= lightmapColor.a; lightmapColor.rgb *= lightmapColor.a;
#endif #endif
#if defined(USE_PBR) && !defined(USE_FAST_LIGHT)
lightmapColor.rgb *= lightmapColor.rgb;
#endif
lightColor *= lightmapColor.rgb;
#endif #endif
vec2 texCoords = var_TexCoords.xy; vec2 texCoords = var_TexCoords.xy;
@ -383,17 +259,16 @@ void main()
vec4 diffuse = texture2D(u_DiffuseMap, texCoords); vec4 diffuse = texture2D(u_DiffuseMap, texCoords);
#if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) #if defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)
#if defined(USE_LIGHTMAP) L = var_LightDir.xyz;
lightColor = lightmapColor.rgb * var_Color.rgb; #if defined(USE_DELUXEMAP)
ambientColor = vec3(0.0); L += (texture2D(u_DeluxeMap, var_TexCoords.zw).xyz - vec3(0.5)) * u_EnableTextures.y;
attenuation = 1.0; #endif
#elif defined(USE_LIGHT_VECTOR) float sqrLightDist = dot(L, L);
lightColor = u_DirectedLight * var_Color.rgb; L /= sqrt(sqrLightDist);
ambientColor = u_AmbientLight * var_Color.rgb;
#if defined(USE_LIGHT_VECTOR)
attenuation = CalcLightAttenuation(float(var_LightDir.w > 0.0), var_LightDir.w / sqrLightDist); attenuation = CalcLightAttenuation(float(var_LightDir.w > 0.0), var_LightDir.w / sqrLightDist);
#elif defined(USE_LIGHT_VERTEX) #else
lightColor = var_Color.rgb;
ambientColor = vec3(0.0);
attenuation = 1.0; attenuation = 1.0;
#endif #endif
@ -411,33 +286,20 @@ void main()
#endif #endif
N = normalize(N); N = normalize(N);
L /= sqrt(sqrLightDist);
#if defined(USE_SHADOWMAP) #if defined(USE_SHADOWMAP)
vec2 shadowTex = gl_FragCoord.xy * r_FBufScale; vec2 shadowTex = gl_FragCoord.xy * r_FBufScale;
float shadowValue = texture2D(u_ShadowMap, shadowTex).r; float shadowValue = texture2D(u_ShadowMap, shadowTex).r;
// surfaces not facing the light are always shadowed // surfaces not facing the light are always shadowed
shadowValue *= float(dot(var_Normal.xyz, var_PrimaryLightDir.xyz) > 0.0); shadowValue *= clamp(dot(var_Normal.xyz, var_PrimaryLightDir.xyz), 0.0, 1.0);
#if defined(SHADOWMAP_MODULATE) #if defined(SHADOWMAP_MODULATE)
//vec3 shadowColor = min(u_PrimaryLightAmbient, lightColor); lightColor *= shadowValue * (1.0 - u_PrimaryLightAmbient.r) + u_PrimaryLightAmbient.r;
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);
#endif #endif
#endif #endif
#if defined(r_lightGamma) #if !defined(USE_LIGHT_VECTOR)
lightColor = pow(lightColor, vec3(r_lightGamma));
ambientColor = pow(ambientColor, vec3(r_lightGamma));
#endif
#if defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX)
ambientColor = lightColor; ambientColor = lightColor;
float surfNL = clamp(dot(var_Normal.xyz, L), 0.0, 1.0); 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 // Recover any unused light as ambient, in case attenuation is over 4x or
// light is below the surface // 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 #endif
vec3 reflectance;
NL = clamp(dot(N, L), 0.0, 1.0); NL = clamp(dot(N, L), 0.0, 1.0);
NE = clamp(dot(N, E), 0.0, 1.0); NE = clamp(dot(N, E), 0.0, 1.0);
@ -460,70 +322,36 @@ void main()
#else #else
vec4 specular = vec4(1.0); vec4 specular = vec4(1.0);
#endif #endif
specular *= u_SpecularScale; specular *= u_SpecularScale;
#if defined(r_materialGamma) #if defined(USE_PBR)
diffuse.rgb = pow(diffuse.rgb, vec3(r_materialGamma)); diffuse.rgb *= diffuse.rgb;
specular.rgb = pow(specular.rgb, vec3(r_materialGamma));
#endif #endif
float gloss = specular.a; #if defined(USE_PBR)
float shininess = exp2(gloss * 13.0); // diffuse rgb is base color
// specular red is smoothness
#if defined(SPECULAR_IS_METALLIC) // specular green is metallicness
// diffuse is actually base color, and red of specular is metallicness float roughness = 1.0 - specular.r;
float metallic = specular.r; specular.rgb = specular.g * diffuse.rgb + vec3(0.04 - 0.04 * specular.g);
diffuse.rgb *= 1.0 - specular.g;
specular.rgb = (0.96 * metallic) * diffuse.rgb + vec3(0.04);
diffuse.rgb *= 1.0 - metallic;
#else #else
// diffuse rgb is diffuse
// specular rgb is specular reflectance at normal incidence
// specular alpha is gloss
float roughness = exp2(-3.0 * specular.a);
// adjust diffuse by specular reflectance, to maintain energy conservation // adjust diffuse by specular reflectance, to maintain energy conservation
diffuse.rgb *= vec3(1.0) - specular.rgb; diffuse.rgb *= vec3(1.0) - specular.rgb;
#endif #endif
reflectance = CalcDiffuse(diffuse.rgb, N, L, E, NE, NL, shininess); reflectance = CalcDiffuse(diffuse.rgb, NH, EH, roughness);
#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
#endif
gl_FragColor.rgb = lightColor * reflectance * (attenuation * NL); gl_FragColor.rgb = lightColor * reflectance * (attenuation * NL);
gl_FragColor.rgb += ambientColor * diffuse.rgb;
#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;
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
#if defined(USE_CUBEMAP) #if defined(USE_CUBEMAP)
reflectance = EnvironmentBRDF(gloss, NE, specular.rgb); reflectance = EnvironmentBRDF(roughness, NE, specular.rgb);
vec3 R = reflect(E, N); vec3 R = reflect(E, N);
@ -531,15 +359,15 @@ void main()
// from http://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ // 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 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) // normalize cubemap based on lowest mip (~diffuse)
// multiplying cubemap values by lighting below depends on either this or the cubemap being normalized at generation // multiplying cubemap values by lighting below depends on either this or the cubemap being normalized at generation
//vec3 cubeLightDiffuse = max(textureCubeLod(u_CubeMap, N, 6.0).rgb, 0.5 / 255.0); //vec3 cubeLightDiffuse = max(textureCubeLod(u_CubeMap, N, 6.0).rgb, 0.5 / 255.0);
//cubeLightColor /= dot(cubeLightDiffuse, vec3(0.2125, 0.7154, 0.0721)); //cubeLightColor /= dot(cubeLightDiffuse, vec3(0.2125, 0.7154, 0.0721));
#if defined(r_framebufferGamma) #if defined(USE_PBR)
cubeLightColor = pow(cubeLightColor, vec3(r_framebufferGamma)); cubeLightColor *= cubeLightColor;
#endif #endif
// multiply cubemap values by lighting // multiply cubemap values by lighting
@ -549,7 +377,7 @@ void main()
gl_FragColor.rgb += cubeLightColor * reflectance; gl_FragColor.rgb += cubeLightColor * reflectance;
#endif #endif
#if defined(USE_PRIMARY_LIGHT) #if defined(USE_PRIMARY_LIGHT) || defined(SHADOWMAP_MODULATE)
vec3 L2, H2; vec3 L2, H2;
float NL2, EH2, NH2; float NL2, EH2, NH2;
@ -560,20 +388,19 @@ void main()
//L2 /= sqrt(sqrLightDist); //L2 /= sqrt(sqrLightDist);
NL2 = clamp(dot(N, L2), 0.0, 1.0); NL2 = clamp(dot(N, L2), 0.0, 1.0);
H2 = normalize(L2 + E); H2 = normalize(L2 + E);
EH2 = clamp(dot(E, H2), 0.0, 1.0); EH2 = clamp(dot(E, H2), 0.0, 1.0);
NH2 = clamp(dot(N, 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, EH2, roughness);
reflectance += CalcSpecular(specular.rgb, NH2, NL2, NE, EH2, gloss, shininess);
lightColor = u_PrimaryLightColor * var_Color.rgb; // bit of a hack, with modulated shadowmaps, ignore diffuse
#if !defined(SHADOWMAP_MODULATE)
#if defined(r_lightGamma) reflectance += CalcDiffuse(diffuse.rgb, NH2, EH2, roughness);
lightColor = pow(lightColor, vec3(r_lightGamma));
#endif #endif
lightColor = u_PrimaryLightColor;
#if defined(USE_SHADOWMAP) #if defined(USE_SHADOWMAP)
lightColor *= shadowValue; lightColor *= shadowValue;
#endif #endif
@ -583,28 +410,16 @@ void main()
gl_FragColor.rgb += lightColor * reflectance * NL2; gl_FragColor.rgb += lightColor * reflectance * NL2;
#endif #endif
#if defined(USE_PBR)
gl_FragColor.rgb = sqrt(gl_FragColor.rgb);
#endif
#else #else
lightColor = var_Color.rgb;
#if defined(USE_LIGHTMAP)
lightColor *= lightmapColor.rgb;
#endif
#if defined(r_lightGamma)
lightColor = pow(lightColor, vec3(r_lightGamma));
#endif
#if defined(r_materialGamma)
diffuse.rgb = pow(diffuse.rgb, vec3(r_materialGamma));
#endif
gl_FragColor.rgb = diffuse.rgb * lightColor; gl_FragColor.rgb = diffuse.rgb * lightColor;
#endif #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; gl_FragColor.a = diffuse.a * var_Color.a;
} }

View file

@ -57,10 +57,8 @@ uniform float u_VertexLerp;
#if defined(USE_LIGHT_VECTOR) #if defined(USE_LIGHT_VECTOR)
uniform vec4 u_LightOrigin; uniform vec4 u_LightOrigin;
uniform float u_LightRadius; uniform float u_LightRadius;
#if defined(USE_FAST_LIGHT)
uniform vec3 u_DirectedLight; uniform vec3 u_DirectedLight;
uniform vec3 u_AmbientLight; uniform vec3 u_AmbientLight;
#endif
#endif #endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)
@ -71,6 +69,9 @@ uniform float u_PrimaryLightRadius;
varying vec4 var_TexCoords; varying vec4 var_TexCoords;
varying vec4 var_Color; 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_LIGHT) && !defined(USE_FAST_LIGHT)
#if defined(USE_VERT_TANGENT_SPACE) #if defined(USE_VERT_TANGENT_SPACE)
@ -208,12 +209,24 @@ void main()
var_Color = u_VertColor * attr_Color + u_BaseColor; 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 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 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; 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 #endif
#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) #if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP)

View file

@ -28,8 +28,8 @@ void main()
{ {
vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color; vec4 color = texture2D(u_TextureMap, var_TexCoords) * u_Color;
#if defined(r_framebufferGamma) #if defined(USE_PBR)
color.rgb = pow(color.rgb, vec3(r_framebufferGamma)); color.rgb *= color.rgb;
#endif #endif
vec3 minAvgMax = texture2D(u_LevelsMap, var_TexCoords).rgb; 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); color.rgb = clamp(color.rgb * var_InvWhite, 0.0, 1.0);
#if defined(r_tonemapGamma) #if defined(USE_PBR)
color.rgb = pow(color.rgb, vec3(1.0 / r_tonemapGamma)); color.rgb = sqrt(color.rgb);
#endif #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; gl_FragColor = color;
} }

View file

@ -20,6 +20,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
=========================================================================== ===========================================================================
*/ */
#include "tr_local.h" #include "tr_local.h"
#include "tr_fbo.h"
#include "tr_dsa.h"
backEndData_t *backEndData; backEndData_t *backEndData;
backEndState_t backEnd; backEndState_t backEnd;
@ -35,81 +37,28 @@ 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 ** GL_BindToTMU
*/ */
void GL_BindToTMU( image_t *image, int tmu ) void GL_BindToTMU( image_t *image, int tmu )
{ {
int texnum; GLuint texture = (tmu == TB_COLORMAP) ? tr.defaultImage->texnum : 0;
int oldtmu = glState.currenttmu; GLenum target = GL_TEXTURE_2D;
if (!image) if (image)
texnum = 0; {
else if (image->flags & IMGFLAG_CUBEMAP)
texnum = image->texnum; target = GL_TEXTURE_CUBE_MAP;
if ( glState.currenttextures[tmu] != texnum ) { image->frameUsed = tr.frameCount;
GL_SelectTexture( tmu ); texture = image->texnum;
if (image)
image->frameUsed = tr.frameCount;
glState.currenttextures[tmu] = texnum;
if (image && (image->flags & IMGFLAG_CUBEMAP))
qglBindTexture( GL_TEXTURE_CUBE_MAP, texnum );
else
qglBindTexture( GL_TEXTURE_2D, texnum );
GL_SelectTexture( oldtmu );
} }
else
{
ri.Printf(PRINT_WARNING, "GL_BindToTMU: NULL image\n");
}
GL_BindMultiTexture(GL_TEXTURE0_ARB + tmu, target, texture);
} }
@ -141,39 +90,6 @@ void GL_Cull( int cullType ) {
glState.faceCulling = cullType; glState.faceCulling = 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 ** GL_State
** **
@ -462,30 +378,20 @@ void RB_BeginDrawingView (void) {
if (glRefConfig.framebufferObject) 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 // 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 // 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.renderFbo || (backEnd.framePostProcessed && (backEnd.refdef.rdflags & RDF_NOWORLDMODEL)))
{
FBO_Bind(NULL);
}
else
{
FBO_Bind(tr.renderFbo);
}
}
else
{
FBO_Bind(backEnd.viewParms.targetFbo);
// FIXME: hack for cubemap testing if (tr.renderCubeFbo && fbo == tr.renderCubeFbo)
if (tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) {
{ cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
//qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + backEnd.viewParms.targetFboLayer, backEnd.viewParms.targetFbo->colorImage[0]->texnum, 0); FBO_AttachImage(fbo, cubemap->image, GL_COLOR_ATTACHMENT0_EXT, backEnd.viewParms.targetFboLayer);
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);
} }
// //
@ -549,8 +455,6 @@ void RB_BeginDrawingView (void) {
} }
#define MAC_EVENT_PUMP_MSEC 5
/* /*
================== ==================
RB_RenderDrawSurfList RB_RenderDrawSurfList
@ -856,6 +760,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); RE_UploadCinematic (w, h, cols, rows, data, client, dirty);
GL_BindToTMU(tr.scratchImage[client], TB_COLORMAP);
if ( r_speeds->integer ) { if ( r_speeds->integer ) {
end = ri.Milliseconds(); end = ri.Milliseconds();
@ -865,14 +770,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *
// FIXME: HUGE hack // FIXME: HUGE hack
if (glRefConfig.framebufferObject) if (glRefConfig.framebufferObject)
{ {
if (!tr.renderFbo || backEnd.framePostProcessed) FBO_Bind(backEnd.framePostProcessed ? NULL : tr.renderFbo);
{
FBO_Bind(NULL);
}
else
{
FBO_Bind(tr.renderFbo);
}
} }
RB_SetGL2D(); RB_SetGL2D();
@ -896,23 +794,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) { void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
GLuint texture;
GL_Bind( tr.scratchImage[client] ); if (!tr.scratchImage[client])
{
ri.Printf(PRINT_WARNING, "RE_UploadCinematic: scratch images not initialized\n");
return;
}
texture = tr.scratchImage[client]->texnum;
// if the scratchImage isn't in the format we want, specify it as a new texture // 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 ) { if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; 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 ); qglTextureImage2D(texture, 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 ); qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); qglTextureParameterf(texture, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else { } else {
if (dirty) { if (dirty) {
// otherwise, just subimage upload it so that drivers can tell we are going to be changing // 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 // 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);
} }
} }
} }
@ -951,16 +856,7 @@ const void *RB_StretchPic ( const void *data ) {
// FIXME: HUGE hack // FIXME: HUGE hack
if (glRefConfig.framebufferObject) if (glRefConfig.framebufferObject)
{ FBO_Bind(backEnd.framePostProcessed ? NULL : tr.renderFbo);
if (!tr.renderFbo || backEnd.framePostProcessed)
{
FBO_Bind(NULL);
}
else
{
FBO_Bind(tr.renderFbo);
}
}
RB_SetGL2D(); RB_SetGL2D();
@ -1072,11 +968,10 @@ const void *RB_DrawSurfs( const void *data ) {
// If we're using multisampling, resolve the depth first // If we're using multisampling, resolve the depth first
FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_DEPTH_BUFFER_BIT, GL_NEAREST); 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 // If we're rendering directly to the screen, copy the depth to a texture
GL_BindToTMU(tr.renderDepthImage, 0); qglCopyTextureImage2D(tr.renderDepthImage->texnum, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0);
qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, glConfig.vidWidth, glConfig.vidHeight, 0);
} }
if (r_ssao->integer) if (r_ssao->integer)
@ -1313,11 +1208,11 @@ const void *RB_DrawSurfs( const void *data ) {
if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo) if (glRefConfig.framebufferObject && tr.renderCubeFbo && backEnd.viewParms.targetFbo == tr.renderCubeFbo)
{ {
cubemap_t *cubemap = &tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex];
FBO_Bind(NULL); FBO_Bind(NULL);
GL_SelectTexture(TB_CUBEMAP); if (cubemap && cubemap->image)
GL_BindToTMU(tr.cubemaps[backEnd.viewParms.targetFboCubemapIndex], TB_CUBEMAP); qglGenerateTextureMipmap(cubemap->image->texnum, GL_TEXTURE_CUBE_MAP);
qglGenerateMipmapEXT(GL_TEXTURE_CUBE_MAP);
GL_SelectTexture(0);
} }
return (const void *)(cmd + 1); return (const void *)(cmd + 1);
@ -1394,7 +1289,7 @@ void RB_ShowImages( void ) {
{ {
vec4_t quadVerts[4]; vec4_t quadVerts[4];
GL_Bind(image); GL_BindToTMU(image, TB_COLORMAP);
VectorSet4(quadVerts[0], x, y, 0, 1); VectorSet4(quadVerts[0], x, y, 0, 1);
VectorSet4(quadVerts[1], x + w, y, 0, 1); VectorSet4(quadVerts[1], x + w, y, 0, 1);
@ -1570,21 +1465,18 @@ const void *RB_CapShadowMap(const void *data)
if (cmd->map != -1) if (cmd->map != -1)
{ {
GL_SelectTexture(0);
if (cmd->cubeSide != -1) if (cmd->cubeSide != -1)
{ {
if (tr.shadowCubemaps[cmd->map]) if (tr.shadowCubemaps[cmd->map])
{ {
GL_Bind(tr.shadowCubemaps[cmd->map]); qglCopyTextureImage2D(tr.shadowCubemaps[cmd->map]->texnum, GL_TEXTURE_CUBE_MAP_POSITIVE_X + cmd->cubeSide, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - ( backEnd.refdef.y + PSHADOW_MAP_SIZE ), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0);
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);
} }
} }
else else
{ {
if (tr.pshadowMaps[cmd->map]) if (tr.pshadowMaps[cmd->map])
{ {
GL_Bind(tr.pshadowMaps[cmd->map]); qglCopyTextureImage2D(tr.pshadowMaps[cmd->map]->texnum, GL_TEXTURE_2D, 0, GL_RGBA8, backEnd.refdef.x, glConfig.vidHeight - (backEnd.refdef.y + PSHADOW_MAP_SIZE), PSHADOW_MAP_SIZE, PSHADOW_MAP_SIZE, 0);
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);
} }
} }
} }
@ -1657,7 +1549,7 @@ const void *RB_PostProcess(const void *data)
if (srcFbo) 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; autoExposure = r_autoExposure->integer || r_forceAutoExposure->integer;
RB_ToneMap(srcFbo, srcBox, NULL, dstBox, autoExposure); RB_ToneMap(srcFbo, srcBox, NULL, dstBox, autoExposure);
@ -1726,7 +1618,7 @@ const void *RB_PostProcess(const void *data)
{ {
VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256); VectorSet4(dstBox, 0, glConfig.vidHeight - 256, 256, 256);
//FBO_BlitFromTexture(tr.renderCubeImage, NULL, NULL, NULL, dstBox, &tr.testcubeShader, NULL, 0); //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 #endif
@ -1736,6 +1628,74 @@ const void *RB_PostProcess(const void *data)
return (const void *)(cmd + 1); 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);
}
/* /*
==================== ====================
@ -1784,6 +1744,9 @@ void RB_ExecuteRenderCommands( const void *data ) {
case RC_POSTPROCESS: case RC_POSTPROCESS:
data = RB_PostProcess(data); data = RB_PostProcess(data);
break; break;
case RC_EXPORT_CUBEMAPS:
data = RB_ExportCubemaps(data);
break;
case RC_END_OF_LIST: case RC_END_OF_LIST:
default: default:
// finish any 2D drawing if needed // finish any 2D drawing if needed

View file

@ -23,6 +23,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h" #include "tr_local.h"
#define JSON_IMPLEMENTATION
#include "../qcommon/json.h"
#undef JSON_IMPLEMENTATION
/* /*
Loads and prepares a map file for scene rendering. Loads and prepares a map file for scene rendering.
@ -101,7 +105,11 @@ static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) {
int shift, r, g, b; int shift, r, g, b;
// shift the color data based on overbright range // shift the color data based on overbright range
#if defined(USE_OVERBRIGHT)
shift = r_mapOverBrightBits->integer - tr.overbrightBits; shift = r_mapOverBrightBits->integer - tr.overbrightBits;
#else
shift = 0;
#endif
// shift the data based on overbright range // shift the data based on overbright range
r = in[0] << shift; r = in[0] << shift;
@ -136,7 +144,9 @@ static void R_ColorShiftLightingFloats(float in[4], float out[4], float scale )
{ {
float r, g, b; 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; r = in[0] * scale;
g = in[1] * scale; g = in[1] * scale;
@ -2755,7 +2765,11 @@ void R_LoadLightGrid( lump_t *l ) {
if (hdrLightGrid) 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"); //ri.Printf(PRINT_ALL, "found!\n");
@ -2962,6 +2976,78 @@ qboolean R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int *numSp
return qtrue; 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) void R_LoadCubemapEntities(char *cubemapEntityName)
{ {
char spawnVarChars[2048]; char spawnVarChars[2048];
@ -2986,33 +3072,45 @@ void R_LoadCubemapEntities(char *cubemapEntityName)
return; return;
tr.numCubemaps = numCubemaps; 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; numCubemaps = 0;
while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars)) while(R_ParseSpawnVars(spawnVarChars, sizeof(spawnVarChars), &numSpawnVars, spawnVars))
{ {
int i; int i;
char name[MAX_QPATH];
qboolean isCubemap = qfalse; qboolean isCubemap = qfalse;
qboolean positionSet = qfalse; qboolean originSet = qfalse;
vec3_t origin; vec3_t origin;
float parallaxRadius = 1000.0f;
name[0] = '\0';
for (i = 0; i < numSpawnVars; i++) for (i = 0; i < numSpawnVars; i++)
{ {
if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName)) if (!Q_stricmp(spawnVars[i][0], "classname") && !Q_stricmp(spawnVars[i][1], cubemapEntityName))
isCubemap = qtrue; isCubemap = qtrue;
if (!Q_stricmp(spawnVars[i][0], "name"))
Q_strncpyz(name, spawnVars[i][1], MAX_QPATH);
if (!Q_stricmp(spawnVars[i][0], "origin")) if (!Q_stricmp(spawnVars[i][0], "origin"))
{ {
sscanf(spawnVars[i][1], "%f %f %f", &origin[0], &origin[1], &origin[2]); 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]); cubemap_t *cubemap = &tr.cubemaps[numCubemaps];
VectorCopy(origin, tr.cubemapOrigins[numCubemaps]); Q_strncpyz(cubemap->name, name, MAX_QPATH);
VectorCopy(origin, cubemap->origin);
cubemap->parallaxRadius = parallaxRadius;
numCubemaps++; numCubemaps++;
} }
} }
@ -3052,23 +3150,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++) 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 (i = 0; i < tr.numCubemaps; i++)
{ {
for (j = 0; j < 6; j++) if (!tr.cubemaps[i].image)
{ {
RE_ClearScene(); tr.cubemaps[i].image = R_CreateImage(va("*cubeMap%d", i), NULL, r_cubemapSize->integer, r_cubemapSize->integer, IMGTYPE_COLORALPHA, flags, GL_RGBA8);
R_RenderCubemapSide(i, j, qfalse);
R_IssuePendingRenderCommands(); for (j = 0; j < 6; j++)
R_InitNextFrame(); {
RE_ClearScene();
R_RenderCubemapSide(i, j, qfalse);
R_IssuePendingRenderCommands();
R_InitNextFrame();
}
} }
} }
} }
@ -3385,7 +3501,14 @@ void RE_LoadWorldMap( const char *name ) {
// load cubemaps // load cubemaps
if (r_cubeMapping->integer) 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) if (!tr.numCubemaps)
{ {
// use deathmatch spawn points as cubemaps // use deathmatch spawn points as cubemaps
@ -3409,10 +3532,11 @@ void RE_LoadWorldMap( const char *name ) {
// make sure the VAO glState entry is safe // make sure the VAO glState entry is safe
R_BindNullVao(); R_BindNullVao();
// Render all cubemaps // Render or load all cubemaps
if (r_cubeMapping->integer && tr.numCubemaps) if (r_cubeMapping->integer && tr.numCubemaps)
{ {
R_RenderAllCubemaps(); R_LoadCubemaps();
R_RenderMissingCubemaps();
} }
ri.FS_FreeFile( buffer.v ); ri.FS_FreeFile( buffer.v );

View file

@ -121,20 +121,20 @@ void R_IssuePendingRenderCommands( void ) {
/* /*
============ ============
R_GetCommandBuffer R_GetCommandBufferReserved
make sure there is enough command space make sure there is enough command space
============ ============
*/ */
void *R_GetCommandBuffer( int bytes ) { void *R_GetCommandBufferReserved( int bytes, int reservedBytes ) {
renderCommandList_t *cmdList; renderCommandList_t *cmdList;
cmdList = &backEndData->commands; cmdList = &backEndData->commands;
bytes = PAD(bytes, sizeof(void *)); bytes = PAD(bytes, sizeof(void *));
// always leave room for the end of list command // always leave room for the end of list command
if ( cmdList->used + bytes + 4 > MAX_RENDER_COMMANDS ) { if ( cmdList->used + bytes + sizeof( int ) + reservedBytes > MAX_RENDER_COMMANDS ) {
if ( bytes > MAX_RENDER_COMMANDS - 4 ) { if ( bytes > MAX_RENDER_COMMANDS - sizeof( int ) ) {
ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes ); ri.Error( ERR_FATAL, "R_GetCommandBuffer: bad size %i", bytes );
} }
// if we run out of room, just start dropping commands // if we run out of room, just start dropping commands
@ -146,6 +146,17 @@ void *R_GetCommandBuffer( int bytes ) {
return cmdList->cmds + cmdList->used - 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 *) ) );
}
/* /*
============= =============
@ -525,7 +536,7 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) {
if ( !tr.registered ) { if ( !tr.registered ) {
return; return;
} }
cmd = R_GetCommandBuffer( sizeof( *cmd ) ); cmd = R_GetCommandBufferReserved( sizeof( *cmd ), 0 );
if ( !cmd ) { if ( !cmd ) {
return; return;
} }

287
code/renderergl2/tr_dsa.c Normal file
View file

@ -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);
}

80
code/renderergl2/tr_dsa.h Normal file
View file

@ -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

View file

@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif #endif
#include "tr_local.h" #include "tr_local.h"
#include "tr_dsa.h"
// GL_EXT_draw_range_elements // GL_EXT_draw_range_elements
void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); 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); void (APIENTRY * qglGenVertexArraysARB)(GLsizei n, GLuint *arrays);
GLboolean (APIENTRY * qglIsVertexArrayARB)(GLuint array); 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) static qboolean GLimp_HaveExtension(const char *ext)
{ {
const char *ptr = Q_stristr( glConfig.extensions_string, ext ); const char *ptr = Q_stristr( glConfig.extensions_string, ext );
@ -585,6 +630,22 @@ void GLimp_InitExtraExtensions()
ri.Printf(PRINT_ALL, result[2], extension); 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 // GL_EXT_framebuffer_multisample
extension = "GL_EXT_framebuffer_multisample"; extension = "GL_EXT_framebuffer_multisample";
glRefConfig.framebufferMultisample = qfalse; glRefConfig.framebufferMultisample = qfalse;
@ -601,12 +662,12 @@ void GLimp_InitExtraExtensions()
glRefConfig.textureCompression = TCR_NONE; glRefConfig.textureCompression = TCR_NONE;
// GL_EXT_texture_compression_latc // GL_ARB_texture_compression_rgtc
extension = "GL_EXT_texture_compression_latc"; extension = "GL_ARB_texture_compression_rgtc";
if (GLimp_HaveExtension(extension)) if (GLimp_HaveExtension(extension))
{ {
if (r_ext_compressed_textures->integer) if (r_ext_compressed_textures->integer && glRefConfig.arbTextureCompression)
glRefConfig.textureCompression |= TCR_LATC; glRefConfig.textureCompression |= TCR_RGTC;
ri.Printf(PRINT_ALL, result[r_ext_compressed_textures->integer ? 1 : 0], extension); 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); ri.Printf(PRINT_ALL, result[2], extension);
} }
glRefConfig.swizzleNormalmap = r_ext_compressed_textures->integer && !(glRefConfig.textureCompression & TCR_RGTC);
// GL_ARB_texture_compression_bptc // GL_ARB_texture_compression_bptc
extension = "GL_ARB_texture_compression_bptc"; extension = "GL_ARB_texture_compression_bptc";
if (GLimp_HaveExtension(extension)) if (GLimp_HaveExtension(extension))
@ -732,4 +795,68 @@ void GLimp_InitExtraExtensions()
ri.Printf(PRINT_ALL, result[2], extension); 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);
}
} }

View file

@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_fbo.c // tr_fbo.c
#include "tr_local.h" #include "tr_local.h"
#include "tr_dsa.h"
/* /*
============= =============
R_CheckFBO R_CheckFBO
@ -30,19 +32,10 @@ R_CheckFBO
*/ */
qboolean R_CheckFBO(const FBO_t * fbo) qboolean R_CheckFBO(const FBO_t * fbo)
{ {
int code; GLenum code = qglCheckNamedFramebufferStatus(fbo->frameBuffer, GL_FRAMEBUFFER_EXT);
int id;
qglGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &id);
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->frameBuffer);
code = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(code == GL_FRAMEBUFFER_COMPLETE_EXT) if(code == GL_FRAMEBUFFER_COMPLETE_EXT)
{
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
return qtrue; return qtrue;
}
// an error occured // an error occured
switch (code) switch (code)
@ -83,13 +76,9 @@ qboolean R_CheckFBO(const FBO_t * fbo)
default: default:
ri.Printf(PRINT_WARNING, "R_CheckFBO: (%s) unknown error 0x%X\n", fbo->name, code); 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; break;
} }
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
return qfalse; return qfalse;
} }
@ -133,6 +122,11 @@ FBO_t *FBO_Create(const char *name, int width, int height)
return fbo; return fbo;
} }
/*
=================
FBO_CreateBuffer
=================
*/
void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample) void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
{ {
uint32_t *pRenderBuffer; uint32_t *pRenderBuffer;
@ -189,115 +183,45 @@ void FBO_CreateBuffer(FBO_t *fbo, int format, int index, int multisample)
if (absent) if (absent)
qglGenRenderbuffersEXT(1, pRenderBuffer); qglGenRenderbuffersEXT(1, pRenderBuffer);
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, *pRenderBuffer);
if (multisample && glRefConfig.framebufferMultisample) if (multisample && glRefConfig.framebufferMultisample)
{ qglNamedRenderbufferStorageMultisample(*pRenderBuffer, multisample, format, fbo->width, fbo->height);
qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, multisample, format, fbo->width, fbo->height);
}
else else
{ qglNamedRenderbufferStorage(*pRenderBuffer, format, fbo->width, fbo->height);
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fbo->width, fbo->height);
}
if(absent) if(absent)
{ {
if (attachment == 0) if (attachment == 0)
{ {
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); qglNamedFramebufferRenderbuffer(fbo->frameBuffer, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer); qglNamedFramebufferRenderbuffer(fbo->frameBuffer, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, *pRenderBuffer);
} }
else else
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer); {
qglNamedFramebufferRenderbuffer(fbo->frameBuffer, attachment, GL_RENDERBUFFER_EXT, *pRenderBuffer);
}
} }
} }
/* /*
================= =================
R_AttachFBOTexture1D FBO_AttachImage
================= =================
*/ */
void R_AttachFBOTexture1D(int texId, int index) void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside)
{ {
if(index < 0 || index >= glRefConfig.maxColorAttachments) GLenum target = GL_TEXTURE_2D;
{ int index;
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); if (image->flags & IMGFLAG_CUBEMAP)
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + cubemapside;
qglNamedFramebufferTexture2D(fbo->frameBuffer, attachment, target, image->texnum, 0);
index = attachment - GL_COLOR_ATTACHMENT0_EXT;
if (index >= 0 && index <= 15)
fbo->colorImage[index] = image;
} }
/*
=================
R_AttachFBOTexture2D
=================
*/
void R_AttachFBOTexture2D(int target, int texId, int index)
{
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;
}
if(index < 0 || index >= glRefConfig.maxColorAttachments)
{
ri.Printf(PRINT_WARNING, "R_AttachFBOTexture2D: invalid attachment index %i\n", index);
return;
}
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + index, target, texId, 0);
}
/*
=================
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;
}
/* /*
============ ============
@ -312,38 +236,10 @@ void FBO_Bind(FBO_t * fbo)
if (r_logFile->integer) if (r_logFile->integer)
{ {
// don't just call LogComment, or we will get a call to va() every frame! // 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 ? fbo->name : "NULL"));
GLimp_LogComment(va("--- FBO_Bind( %s ) ---\n", fbo->name));
else
GLimp_LogComment("--- FBO_Bind ( NULL ) ---\n");
} }
if (!fbo) GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, fbo ? fbo->frameBuffer : 0);
{
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
//qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glState.currentFBO = NULL;
return;
}
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);
}
*/
glState.currentFBO = fbo; glState.currentFBO = fbo;
} }
@ -355,8 +251,7 @@ FBO_Init
void FBO_Init(void) void FBO_Init(void)
{ {
int i; int i;
// int width, height, hdrFormat, multisample; int hdrFormat, multisample = 0;
int hdrFormat, multisample;
ri.Printf(PRINT_ALL, "------- FBO_Init -------\n"); ri.Printf(PRINT_ALL, "------- FBO_Init -------\n");
@ -369,73 +264,41 @@ void FBO_Init(void)
R_IssuePendingRenderCommands(); R_IssuePendingRenderCommands();
/* if(glRefConfig.textureNonPowerOfTwo)
{
width = glConfig.vidWidth;
height = glConfig.vidHeight;
}
else
{
width = NextPowerOfTwo(glConfig.vidWidth);
height = NextPowerOfTwo(glConfig.vidHeight);
} */
hdrFormat = GL_RGBA8; hdrFormat = GL_RGBA8;
if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat) if (r_hdr->integer && glRefConfig.framebufferObject && glRefConfig.textureFloat)
{
hdrFormat = GL_RGBA16F_ARB; 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) if (r_ext_framebuffer_multisample->integer < multisample)
{
multisample = r_ext_framebuffer_multisample->integer; multisample = r_ext_framebuffer_multisample->integer;
}
if (multisample < 2 || !glRefConfig.framebufferBlit) if (multisample < 2 || !glRefConfig.framebufferBlit)
multisample = 0; multisample = 0;
if (multisample != r_ext_framebuffer_multisample->integer) if (multisample != r_ext_framebuffer_multisample->integer)
{
ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample); ri.Cvar_SetValue("r_ext_framebuffer_multisample", (float)multisample);
}
// only create a render FBO if we need to resolve MSAA or do HDR // only create a render FBO if we need to resolve MSAA or do HDR
// otherwise just render straight to the screen (tr.renderFbo = NULL) // otherwise just render straight to the screen (tr.renderFbo = NULL)
if (multisample && glRefConfig.framebufferMultisample) if (multisample && glRefConfig.framebufferMultisample)
{ {
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); 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, hdrFormat, 0, multisample);
FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample); FBO_CreateBuffer(tr.renderFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample);
R_CheckFBO(tr.renderFbo); R_CheckFBO(tr.renderFbo);
tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height); tr.msaaResolveFbo = FBO_Create("_msaaResolve", tr.renderDepthImage->width, tr.renderDepthImage->height);
FBO_Bind(tr.msaaResolveFbo); FBO_AttachImage(tr.msaaResolveFbo, tr.renderImage, GL_COLOR_ATTACHMENT0_EXT, 0);
FBO_AttachImage(tr.msaaResolveFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
//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);
R_CheckFBO(tr.msaaResolveFbo); R_CheckFBO(tr.msaaResolveFbo);
} }
else if (r_hdr->integer) else if (r_hdr->integer)
{ {
tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height); tr.renderFbo = FBO_Create("_render", tr.renderDepthImage->width, tr.renderDepthImage->height);
FBO_Bind(tr.renderFbo); FBO_AttachImage(tr.renderFbo, tr.renderImage, GL_COLOR_ATTACHMENT0_EXT, 0);
FBO_AttachImage(tr.renderFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
//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);
R_CheckFBO(tr.renderFbo); R_CheckFBO(tr.renderFbo);
} }
@ -443,20 +306,15 @@ void FBO_Init(void)
// this fixes the corrupt screen bug with r_hdr 1 on older hardware // this fixes the corrupt screen bug with r_hdr 1 on older hardware
if (tr.renderFbo) if (tr.renderFbo)
{ {
FBO_Bind(tr.renderFbo); GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, tr.renderFbo->frameBuffer);
qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
FBO_Bind(NULL);
} }
if (r_drawSunRays->integer) if (r_drawSunRays->integer)
{ {
tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height); tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height);
FBO_Bind(tr.sunRaysFbo); FBO_AttachImage(tr.sunRaysFbo, tr.sunRaysImage, GL_COLOR_ATTACHMENT0_EXT, 0);
FBO_AttachImage(tr.sunRaysFbo, tr.renderDepthImage, GL_DEPTH_ATTACHMENT_EXT, 0);
FBO_AttachTextureImage(tr.sunRaysImage, 0);
R_AttachFBOTextureDepth(tr.renderDepthImage->texnum);
R_CheckFBO(tr.sunRaysFbo); R_CheckFBO(tr.sunRaysFbo);
} }
@ -466,14 +324,8 @@ void FBO_Init(void)
for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) 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); tr.pshadowFbos[i] = FBO_Create(va("_shadowmap%d", i), tr.pshadowMaps[i]->width, tr.pshadowMaps[i]->height);
FBO_Bind(tr.pshadowFbos[i]); FBO_AttachImage(tr.pshadowFbos[i], tr.pshadowMaps[i], GL_COLOR_ATTACHMENT0_EXT, 0);
//FBO_CreateBuffer(tr.pshadowFbos[i], GL_RGBA8, 0, 0);
FBO_AttachTextureImage(tr.pshadowMaps[i], 0);
FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0); FBO_CreateBuffer(tr.pshadowFbos[i], GL_DEPTH_COMPONENT24_ARB, 0, 0);
//R_AttachFBOTextureDepth(tr.textureDepthImage->texnum);
R_CheckFBO(tr.pshadowFbos[i]); R_CheckFBO(tr.pshadowFbos[i]);
} }
} }
@ -483,104 +335,67 @@ void FBO_Init(void)
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); tr.sunShadowFbo[i] = FBO_Create("_sunshadowmap", tr.sunShadowDepthImage[i]->width, tr.sunShadowDepthImage[i]->height);
FBO_Bind(tr.sunShadowFbo[i]); // 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_CreateBuffer(tr.sunShadowFbo[i], GL_RGBA8, 0, 0);
//FBO_AttachTextureImage(tr.sunShadowImage, 0); FBO_AttachImage(tr.sunShadowFbo[i], tr.sunShadowDepthImage[i], GL_DEPTH_ATTACHMENT_EXT, 0);
qglDrawBuffer(GL_NONE);
qglReadBuffer(GL_NONE);
//FBO_CreateBuffer(tr.sunShadowFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
R_AttachFBOTextureDepth(tr.sunShadowDepthImage[i]->texnum);
R_CheckFBO(tr.sunShadowFbo[i]); R_CheckFBO(tr.sunShadowFbo[i]);
} }
tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height); tr.screenShadowFbo = FBO_Create("_screenshadow", tr.screenShadowImage->width, tr.screenShadowImage->height);
FBO_Bind(tr.screenShadowFbo); FBO_AttachImage(tr.screenShadowFbo, tr.screenShadowImage, GL_COLOR_ATTACHMENT0_EXT, 0);
FBO_AttachTextureImage(tr.screenShadowImage, 0);
R_CheckFBO(tr.screenShadowFbo); R_CheckFBO(tr.screenShadowFbo);
} }
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height); tr.textureScratchFbo[i] = FBO_Create(va("_texturescratch%d", i), tr.textureScratchImage[i]->width, tr.textureScratchImage[i]->height);
FBO_Bind(tr.textureScratchFbo[i]); FBO_AttachImage(tr.textureScratchFbo[i], tr.textureScratchImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
//FBO_CreateBuffer(tr.textureScratchFbo[i], GL_RGBA8, 0, 0);
FBO_AttachTextureImage(tr.textureScratchImage[i], 0);
R_CheckFBO(tr.textureScratchFbo[i]); R_CheckFBO(tr.textureScratchFbo[i]);
} }
{ {
tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height); tr.calcLevelsFbo = FBO_Create("_calclevels", tr.calcLevelsImage->width, tr.calcLevelsImage->height);
FBO_Bind(tr.calcLevelsFbo); FBO_AttachImage(tr.calcLevelsFbo, tr.calcLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0);
//FBO_CreateBuffer(tr.calcLevelsFbo, hdrFormat, 0, 0);
FBO_AttachTextureImage(tr.calcLevelsImage, 0);
R_CheckFBO(tr.calcLevelsFbo); R_CheckFBO(tr.calcLevelsFbo);
} }
{ {
tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height); tr.targetLevelsFbo = FBO_Create("_targetlevels", tr.targetLevelsImage->width, tr.targetLevelsImage->height);
FBO_Bind(tr.targetLevelsFbo); FBO_AttachImage(tr.targetLevelsFbo, tr.targetLevelsImage, GL_COLOR_ATTACHMENT0_EXT, 0);
//FBO_CreateBuffer(tr.targetLevelsFbo, hdrFormat, 0, 0);
FBO_AttachTextureImage(tr.targetLevelsImage, 0);
R_CheckFBO(tr.targetLevelsFbo); R_CheckFBO(tr.targetLevelsFbo);
} }
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height); tr.quarterFbo[i] = FBO_Create(va("_quarter%d", i), tr.quarterImage[i]->width, tr.quarterImage[i]->height);
FBO_Bind(tr.quarterFbo[i]); FBO_AttachImage(tr.quarterFbo[i], tr.quarterImage[i], GL_COLOR_ATTACHMENT0_EXT, 0);
//FBO_CreateBuffer(tr.quarterFbo[i], hdrFormat, 0, 0);
FBO_AttachTextureImage(tr.quarterImage[i], 0);
R_CheckFBO(tr.quarterFbo[i]); R_CheckFBO(tr.quarterFbo[i]);
} }
if (r_ssao->integer) if (r_ssao->integer)
{ {
tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height); tr.hdrDepthFbo = FBO_Create("_hdrDepth", tr.hdrDepthImage->width, tr.hdrDepthImage->height);
FBO_Bind(tr.hdrDepthFbo); FBO_AttachImage(tr.hdrDepthFbo, tr.hdrDepthImage, GL_COLOR_ATTACHMENT0_EXT, 0);
FBO_AttachTextureImage(tr.hdrDepthImage, 0);
R_CheckFBO(tr.hdrDepthFbo); R_CheckFBO(tr.hdrDepthFbo);
tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height); tr.screenSsaoFbo = FBO_Create("_screenssao", tr.screenSsaoImage->width, tr.screenSsaoImage->height);
FBO_Bind(tr.screenSsaoFbo); FBO_AttachImage(tr.screenSsaoFbo, tr.screenSsaoImage, GL_COLOR_ATTACHMENT0_EXT, 0);
FBO_AttachTextureImage(tr.screenSsaoImage, 0);
R_CheckFBO(tr.screenSsaoFbo); R_CheckFBO(tr.screenSsaoFbo);
} }
if (tr.renderCubeImage) if (tr.renderCubeImage)
{ {
tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height); tr.renderCubeFbo = FBO_Create("_renderCubeFbo", tr.renderCubeImage->width, tr.renderCubeImage->height);
FBO_Bind(tr.renderCubeFbo); FBO_AttachImage(tr.renderCubeFbo, tr.renderCubeImage, GL_COLOR_ATTACHMENT0_EXT, 0);
//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_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0); FBO_CreateBuffer(tr.renderCubeFbo, GL_DEPTH_COMPONENT24_ARB, 0, 0);
R_CheckFBO(tr.renderCubeFbo); R_CheckFBO(tr.renderCubeFbo);
} }
GL_CheckErrors(); GL_CheckErrors();
FBO_Bind(NULL); GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glState.currentFBO = NULL;
} }
/* /*
@ -663,7 +478,10 @@ void FBO_BlitFromTexture(struct image_s *src, ivec4_t inSrcBox, vec2_t inSrcTexS
int width, height; int width, height;
if (!src) if (!src)
{
ri.Printf(PRINT_WARNING, "Tried to blit from a NULL texture!\n");
return; return;
}
if (inSrcBox) if (inSrcBox)
{ {
@ -849,12 +667,12 @@ void FBO_FastBlit(FBO_t *src, ivec4_t srcBox, FBO_t *dst, ivec4_t dstBox, int bu
VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]); VectorSet4(dstBoxFinal, dstBox[0], dstBox[1], dstBox[0] + dstBox[2], dstBox[1] + dstBox[3]);
} }
qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, srcFb); GL_BindFramebuffer(GL_READ_FRAMEBUFFER_EXT, srcFb);
qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dstFb); GL_BindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, dstFb);
qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3], qglBlitFramebufferEXT(srcBoxFinal[0], srcBoxFinal[1], srcBoxFinal[2], srcBoxFinal[3],
dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3], dstBoxFinal[0], dstBoxFinal[1], dstBoxFinal[2], dstBoxFinal[3],
buffers, filter); buffers, filter);
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); GL_BindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
glState.currentFBO = NULL; glState.currentFBO = NULL;
} }

View file

@ -52,6 +52,7 @@ typedef struct FBO_s
int height; int height;
} FBO_t; } FBO_t;
void FBO_AttachImage(FBO_t *fbo, image_t *image, GLenum attachment, GLuint cubemapside);
void FBO_Bind(FBO_t *fbo); void FBO_Bind(FBO_t *fbo);
void FBO_Init(void); void FBO_Init(void);
void FBO_Shutdown(void); void FBO_Shutdown(void);

View file

@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
// tr_glsl.c // tr_glsl.c
#include "tr_local.h" #include "tr_local.h"
void GLSL_BindNullProgram(void); #include "tr_dsa.h"
extern const char *fallbackShader_bokeh_vp; extern const char *fallbackShader_bokeh_vp;
extern const char *fallbackShader_bokeh_fp; extern const char *fallbackShader_bokeh_fp;
@ -322,17 +322,8 @@ static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, cha
Q_strcat(dest, size, Q_strcat(dest, size,
va("#ifndef r_FBufScale\n#define r_FBufScale vec2(%f, %f)\n#endif\n", fbufWidthScale, fbufHeightScale)); va("#ifndef r_FBufScale\n#define r_FBufScale vec2(%f, %f)\n#endif\n", fbufWidthScale, fbufHeightScale));
if (r_materialGamma->value != 1.0f) if (r_pbr->integer)
Q_strcat(dest, size, va("#ifndef r_materialGamma\n#define r_materialGamma %f\n#endif\n", r_materialGamma->value)); Q_strcat(dest, size, "#define USE_PBR\n");
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 (extra) if (extra)
{ {
@ -482,11 +473,6 @@ static void GLSL_ShowProgramUniforms(GLhandleARB program)
GLenum type; GLenum type;
char uniformName[1000]; 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 // query the number of active uniforms
qglGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count); 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); 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) 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; *compare = value;
qglUniform1iARB(uniforms[uniformNum], value); qglProgramUniform1i(program->program, uniforms[uniformNum], value);
} }
void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat 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; *compare = value;
qglUniform1fARB(uniforms[uniformNum], value); qglProgramUniform1f(program->program, uniforms[uniformNum], value);
} }
void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v) 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[0] = v[0];
compare[1] = v[1]; 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) 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); 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) 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); 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) 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); 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) 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); 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) void GLSL_DeleteGPUShader(shaderProgram_t *program)
@ -925,10 +909,8 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.genericShader[i]); 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_DIFFUSEMAP, TB_DIFFUSEMAP);
GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP); GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.genericShader[i]); GLSL_FinishGPUShader(&tr.genericShader[i]);
@ -945,9 +927,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.textureColorShader); GLSL_InitUniforms(&tr.textureColorShader);
qglUseProgramObjectARB(tr.textureColorShader.program);
GLSL_SetUniformInt(&tr.textureColorShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); GLSL_SetUniformInt(&tr.textureColorShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.textureColorShader); GLSL_FinishGPUShader(&tr.textureColorShader);
@ -993,9 +973,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.dlightShader[i]); GLSL_InitUniforms(&tr.dlightShader[i]);
qglUseProgramObjectARB(tr.dlightShader[i].program);
GLSL_SetUniformInt(&tr.dlightShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); GLSL_SetUniformInt(&tr.dlightShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.dlightShader[i]); GLSL_FinishGPUShader(&tr.dlightShader[i]);
@ -1022,16 +1000,10 @@ void GLSL_InitGPUShaders(void)
extradefines[0] = '\0'; 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) if (r_dlightMode->integer >= 2)
Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n");
if (1) if (glRefConfig.swizzleNormalmap)
Q_strcat(extradefines, 1024, "#define SWIZZLE_NORMALMAP\n"); Q_strcat(extradefines, 1024, "#define SWIZZLE_NORMALMAP\n");
if (r_hdr->integer && !glRefConfig.floatLightmap) if (r_hdr->integer && !glRefConfig.floatLightmap)
@ -1067,12 +1039,6 @@ void GLSL_InitGPUShaders(void)
{ {
Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n"); 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 #ifdef USE_VERT_TANGENT_SPACE
Q_strcat(extradefines, 1024, "#define USE_VERT_TANGENT_SPACE\n"); Q_strcat(extradefines, 1024, "#define USE_VERT_TANGENT_SPACE\n");
attribs |= ATTR_TANGENT; attribs |= ATTR_TANGENT;
@ -1087,34 +1053,8 @@ void GLSL_InitGPUShaders(void)
} }
if (r_specularMapping->integer) if (r_specularMapping->integer)
{
Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n"); 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) if (r_cubeMapping->integer)
Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n"); Q_strcat(extradefines, 1024, "#define USE_CUBEMAP\n");
} }
@ -1155,7 +1095,6 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.lightallShader[i]); 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_DIFFUSEMAP, TB_DIFFUSEMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP); GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_NORMALMAP, TB_NORMALMAP); GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_NORMALMAP, TB_NORMALMAP);
@ -1163,7 +1102,6 @@ void GLSL_InitGPUShaders(void)
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP); GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP, TB_SHADOWMAP); GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP, TB_SHADOWMAP);
GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP, TB_CUBEMAP); GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_CUBEMAP, TB_CUBEMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.lightallShader[i]); GLSL_FinishGPUShader(&tr.lightallShader[i]);
@ -1196,9 +1134,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.pshadowShader); GLSL_InitUniforms(&tr.pshadowShader);
qglUseProgramObjectARB(tr.pshadowShader.program);
GLSL_SetUniformInt(&tr.pshadowShader, UNIFORM_SHADOWMAP, TB_DIFFUSEMAP); GLSL_SetUniformInt(&tr.pshadowShader, UNIFORM_SHADOWMAP, TB_DIFFUSEMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.pshadowShader); GLSL_FinishGPUShader(&tr.pshadowShader);
@ -1215,9 +1151,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.down4xShader); GLSL_InitUniforms(&tr.down4xShader);
qglUseProgramObjectARB(tr.down4xShader.program);
GLSL_SetUniformInt(&tr.down4xShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); GLSL_SetUniformInt(&tr.down4xShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.down4xShader); GLSL_FinishGPUShader(&tr.down4xShader);
@ -1234,9 +1168,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.bokehShader); GLSL_InitUniforms(&tr.bokehShader);
qglUseProgramObjectARB(tr.bokehShader.program);
GLSL_SetUniformInt(&tr.bokehShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); GLSL_SetUniformInt(&tr.bokehShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.bokehShader); GLSL_FinishGPUShader(&tr.bokehShader);
@ -1253,10 +1185,8 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.tonemapShader); GLSL_InitUniforms(&tr.tonemapShader);
qglUseProgramObjectARB(tr.tonemapShader.program);
GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_TEXTUREMAP, TB_COLORMAP); GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_LEVELSMAP, TB_LEVELSMAP); GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_LEVELSMAP, TB_LEVELSMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.tonemapShader); GLSL_FinishGPUShader(&tr.tonemapShader);
@ -1278,9 +1208,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.calclevels4xShader[i]); GLSL_InitUniforms(&tr.calclevels4xShader[i]);
qglUseProgramObjectARB(tr.calclevels4xShader[i].program);
GLSL_SetUniformInt(&tr.calclevels4xShader[i], UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); GLSL_SetUniformInt(&tr.calclevels4xShader[i], UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.calclevels4xShader[i]); GLSL_FinishGPUShader(&tr.calclevels4xShader[i]);
@ -1311,13 +1239,11 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.shadowmaskShader); GLSL_InitUniforms(&tr.shadowmaskShader);
qglUseProgramObjectARB(tr.shadowmaskShader.program);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP, TB_SHADOWMAP); GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP, TB_SHADOWMAP);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP2, TB_SHADOWMAP2); GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP2, TB_SHADOWMAP2);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP3, TB_SHADOWMAP3); GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP3, TB_SHADOWMAP3);
GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP4, TB_SHADOWMAP4); GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP4, TB_SHADOWMAP4);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.shadowmaskShader); GLSL_FinishGPUShader(&tr.shadowmaskShader);
@ -1334,9 +1260,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.ssaoShader); GLSL_InitUniforms(&tr.ssaoShader);
qglUseProgramObjectARB(tr.ssaoShader.program);
GLSL_SetUniformInt(&tr.ssaoShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); GLSL_SetUniformInt(&tr.ssaoShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.ssaoShader); GLSL_FinishGPUShader(&tr.ssaoShader);
@ -1361,10 +1285,8 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.depthBlurShader[i]); 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_SCREENIMAGEMAP, TB_COLORMAP);
GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP); GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.depthBlurShader[i]); GLSL_FinishGPUShader(&tr.depthBlurShader[i]);
@ -1382,9 +1304,7 @@ void GLSL_InitGPUShaders(void)
GLSL_InitUniforms(&tr.testcubeShader); GLSL_InitUniforms(&tr.testcubeShader);
qglUseProgramObjectARB(tr.testcubeShader.program);
GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP); GLSL_SetUniformInt(&tr.testcubeShader, UNIFORM_TEXTUREMAP, TB_COLORMAP);
qglUseProgramObjectARB(0);
GLSL_FinishGPUShader(&tr.testcubeShader); GLSL_FinishGPUShader(&tr.testcubeShader);
@ -1408,7 +1328,7 @@ void GLSL_ShutdownGPUShaders(void)
for (i = 0; i < ATTR_INDEX_COUNT; i++) for (i = 0; i < ATTR_INDEX_COUNT; i++)
qglDisableVertexAttribArrayARB(i); qglDisableVertexAttribArrayARB(i);
GLSL_BindNullProgram(); GL_BindNullProgram();
for ( i = 0; i < GENERICDEF_COUNT; i++) for ( i = 0; i < GENERICDEF_COUNT; i++)
GLSL_DeleteGPUShader(&tr.genericShader[i]); GLSL_DeleteGPUShader(&tr.genericShader[i]);
@ -1438,47 +1358,22 @@ void GLSL_ShutdownGPUShaders(void)
for ( i = 0; i < 2; i++) for ( i = 0; i < 2; i++)
GLSL_DeleteGPUShader(&tr.depthBlurShader[i]); GLSL_DeleteGPUShader(&tr.depthBlurShader[i]);
glState.currentProgram = 0;
qglUseProgramObjectARB(0);
} }
void GLSL_BindProgram(shaderProgram_t * program) void GLSL_BindProgram(shaderProgram_t * program)
{ {
if(!program) GLuint programObject = program ? program->program : 0;
{ char *name = program ? program->name : "NULL";
GLSL_BindNullProgram();
return;
}
if(r_logFile->integer) if(r_logFile->integer)
{ {
// don't just call LogComment, or we will get a call to va() every frame! // 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) if (GL_UseProgramObject(programObject))
{
qglUseProgramObjectARB(program->program);
glState.currentProgram = program;
backEnd.pc.c_glslShaderBinds++; 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;
}
} }

File diff suppressed because it is too large Load diff

View file

@ -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);
}

View file

@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "tr_local.h" #include "tr_local.h"
#include "tr_dsa.h"
glconfig_t glConfig; glconfig_t glConfig;
glRefConfig_t glRefConfig; glRefConfig_t glRefConfig;
qboolean textureFilterAnisotropic = qfalse; qboolean textureFilterAnisotropic = qfalse;
@ -106,6 +108,7 @@ cvar_t *r_ext_framebuffer_multisample;
cvar_t *r_arb_seamless_cube_map; cvar_t *r_arb_seamless_cube_map;
cvar_t *r_arb_vertex_type_2_10_10_10_rev; cvar_t *r_arb_vertex_type_2_10_10_10_rev;
cvar_t *r_arb_vertex_array_object; cvar_t *r_arb_vertex_array_object;
cvar_t *r_ext_direct_state_access;
cvar_t *r_mergeMultidraws; cvar_t *r_mergeMultidraws;
cvar_t *r_mergeLeafSurfaces; cvar_t *r_mergeLeafSurfaces;
@ -129,11 +132,6 @@ cvar_t *r_forceAutoExposure;
cvar_t *r_forceAutoExposureMin; cvar_t *r_forceAutoExposureMin;
cvar_t *r_forceAutoExposureMax; 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_depthPrepass;
cvar_t *r_ssao; cvar_t *r_ssao;
@ -142,8 +140,8 @@ cvar_t *r_specularMapping;
cvar_t *r_deluxeMapping; cvar_t *r_deluxeMapping;
cvar_t *r_parallaxMapping; cvar_t *r_parallaxMapping;
cvar_t *r_cubeMapping; cvar_t *r_cubeMapping;
cvar_t *r_deluxeSpecular; cvar_t *r_cubemapSize;
cvar_t *r_specularIsMetallic; cvar_t *r_pbr;
cvar_t *r_baseNormalX; cvar_t *r_baseNormalX;
cvar_t *r_baseNormalY; cvar_t *r_baseNormalY;
cvar_t *r_baseParallax; cvar_t *r_baseParallax;
@ -455,6 +453,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); buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1);
bufstart = PADP((intptr_t) buffer + *offset, packAlign); bufstart = PADP((intptr_t) buffer + *offset, packAlign);
qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart); qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart);
*offset = bufstart - buffer; *offset = bufstart - buffer;
@ -830,6 +829,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 RB_TakeVideoFrameCmd
@ -924,19 +952,11 @@ void GL_SetDefaultState( void )
qglColor4f (1,1,1,1); qglColor4f (1,1,1,1);
// initialize downstream texture unit if we're running GL_BindNullTextures();
// in a multitexture environment GL_BindNullFramebuffers();
if ( qglActiveTextureARB ) {
GL_SelectTexture( 1 );
GL_TextureMode( r_textureMode->string );
GL_TexEnv( GL_MODULATE );
qglDisable( GL_TEXTURE_2D );
GL_SelectTexture( 0 );
}
qglEnable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_2D);
GL_TextureMode( r_textureMode->string ); GL_TextureMode( r_textureMode->string );
GL_TexEnv( GL_MODULATE );
//qglShadeModel( GL_SMOOTH ); //qglShadeModel( GL_SMOOTH );
qglDepthFunc( GL_LEQUAL ); qglDepthFunc( GL_LEQUAL );
@ -949,8 +969,7 @@ void GL_SetDefaultState( void )
glState.faceCulling = CT_TWO_SIDED; glState.faceCulling = CT_TWO_SIDED;
glState.faceCullFront = qtrue; glState.faceCullFront = qtrue;
glState.currentProgram = 0; GL_BindNullProgram();
qglUseProgramObjectARB(0);
if (glRefConfig.vertexArrayObject) if (glRefConfig.vertexArrayObject)
qglBindVertexArrayARB(0); qglBindVertexArrayARB(0);
@ -1149,6 +1168,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_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_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_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", r_ext_texture_filter_anisotropic = ri.Cvar_Get( "r_ext_texture_filter_anisotropic",
"0", CVAR_ARCHIVE | CVAR_LATCH ); "0", CVAR_ARCHIVE | CVAR_LATCH );
@ -1187,7 +1207,7 @@ void R_Register( void )
r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_floatLightmap = ri.Cvar_Get( "r_floatLightmap", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_postProcess = ri.Cvar_Get( "r_postProcess", "1", CVAR_ARCHIVE ); 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_forceToneMap = ri.Cvar_Get( "r_forceToneMap", "0", CVAR_CHEAT );
r_forceToneMapMin = ri.Cvar_Get( "r_forceToneMapMin", "-8.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 ); r_forceToneMapAvg = ri.Cvar_Get( "r_forceToneMapAvg", "-2.0", CVAR_CHEAT );
@ -1200,11 +1220,6 @@ void R_Register( void )
r_cameraExposure = ri.Cvar_Get( "r_cameraExposure", "0", CVAR_CHEAT ); 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_depthPrepass = ri.Cvar_Get( "r_depthPrepass", "1", CVAR_ARCHIVE );
r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE ); r_ssao = ri.Cvar_Get( "r_ssao", "0", CVAR_LATCH | CVAR_ARCHIVE );
@ -1213,8 +1228,8 @@ void R_Register( void )
r_deluxeMapping = ri.Cvar_Get( "r_deluxeMapping", "1", CVAR_ARCHIVE | CVAR_LATCH ); 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_parallaxMapping = ri.Cvar_Get( "r_parallaxMapping", "0", CVAR_ARCHIVE | CVAR_LATCH );
r_cubeMapping = ri.Cvar_Get( "r_cubeMapping", "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_cubemapSize = ri.Cvar_Get( "r_cubemapSize", "128", CVAR_ARCHIVE | CVAR_LATCH );
r_specularIsMetallic = ri.Cvar_Get( "r_specularIsMetallic", "0", 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_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_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_baseParallax = ri.Cvar_Get( "r_baseParallax", "0.05", CVAR_ARCHIVE | CVAR_LATCH );
@ -1352,6 +1367,7 @@ void R_Register( void )
ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f ); ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f );
ri.Cmd_AddCommand( "minimize", GLimp_Minimize ); ri.Cmd_AddCommand( "minimize", GLimp_Minimize );
ri.Cmd_AddCommand( "gfxmeminfo", GfxMemInfo_f ); ri.Cmd_AddCommand( "gfxmeminfo", GfxMemInfo_f );
ri.Cmd_AddCommand( "exportCubemaps", R_ExportCubemaps_f );
} }
void R_InitQueries(void) void R_InitQueries(void)
@ -1497,6 +1513,7 @@ void RE_Shutdown( qboolean destroyWindow ) {
ri.Cmd_RemoveCommand( "modelist" ); ri.Cmd_RemoveCommand( "modelist" );
ri.Cmd_RemoveCommand( "shaderstate" ); ri.Cmd_RemoveCommand( "shaderstate" );
ri.Cmd_RemoveCommand( "gfxmeminfo" ); ri.Cmd_RemoveCommand( "gfxmeminfo" );
ri.Cmd_RemoveCommand( "exportCubemaps" );
if ( tr.registered ) { if ( tr.registered ) {

View file

@ -471,7 +471,7 @@ int R_CubemapForPoint( vec3_t point )
vec3_t diff; vec3_t diff;
vec_t length; vec_t length;
VectorSubtract(point, tr.cubemapOrigins[i], diff); VectorSubtract(point, tr.cubemaps[i].origin, diff);
length = DotProduct(diff, diff); length = DotProduct(diff, diff);
if (shortest > length) if (shortest > length)

View file

@ -54,10 +54,16 @@ typedef unsigned int glIndex_t;
#define MAX_CALC_PSHADOWS 64 #define MAX_CALC_PSHADOWS 64
#define MAX_DRAWN_PSHADOWS 16 // do not increase past 32, because bit flags are used on surfaces #define MAX_DRAWN_PSHADOWS 16 // do not increase past 32, because bit flags are used on surfaces
#define PSHADOW_MAP_SIZE 512 #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_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 { typedef struct dlight_s {
vec3_t origin; vec3_t origin;
@ -1346,8 +1352,6 @@ typedef struct {
// the renderer front end should never modify glstate_t // the renderer front end should never modify glstate_t
typedef struct { typedef struct {
int currenttextures[NUM_TEXTURE_BUNDLES];
int currenttmu;
qboolean finishCalled; qboolean finishCalled;
int texEnv[2]; int texEnv[2];
int faceCulling; int faceCulling;
@ -1357,7 +1361,6 @@ typedef struct {
float vertexAttribsInterpolation; float vertexAttribsInterpolation;
qboolean vertexAnimation; qboolean vertexAnimation;
uint32_t vertexAttribsEnabled; // global if no VAOs, tess only otherwise uint32_t vertexAttribsEnabled; // global if no VAOs, tess only otherwise
shaderProgram_t *currentProgram;
FBO_t *currentFBO; FBO_t *currentFBO;
vao_t *currentVao; vao_t *currentVao;
mat4_t modelview; mat4_t modelview;
@ -1373,7 +1376,7 @@ typedef enum {
typedef enum { typedef enum {
TCR_NONE = 0x0000, TCR_NONE = 0x0000,
TCR_LATC = 0x0001, TCR_RGTC = 0x0001,
TCR_BPTC = 0x0002, TCR_BPTC = 0x0002,
} textureCompressionRef_t; } textureCompressionRef_t;
@ -1397,7 +1400,9 @@ typedef struct {
qboolean textureFloat; qboolean textureFloat;
qboolean halfFloatPixel; qboolean halfFloatPixel;
qboolean packedDepthStencil; qboolean packedDepthStencil;
qboolean arbTextureCompression;
textureCompressionRef_t textureCompression; textureCompressionRef_t textureCompression;
qboolean swizzleNormalmap;
qboolean framebufferMultisample; qboolean framebufferMultisample;
qboolean framebufferBlit; qboolean framebufferBlit;
@ -1413,6 +1418,7 @@ typedef struct {
qboolean floatLightmap; qboolean floatLightmap;
qboolean vertexArrayObject; qboolean vertexArrayObject;
qboolean directStateAccess;
} glRefConfig_t; } glRefConfig_t;
@ -1559,8 +1565,7 @@ typedef struct {
int fatLightmapStep; int fatLightmapStep;
int numCubemaps; int numCubemaps;
vec3_t *cubemapOrigins; cubemap_t *cubemaps;
image_t **cubemaps;
trRefEntity_t *currentEntity; trRefEntity_t *currentEntity;
trRefEntity_t worldEntity; // point currentEntity at this when rendering world trRefEntity_t worldEntity; // point currentEntity at this when rendering world
@ -1712,6 +1717,7 @@ extern cvar_t *r_ext_framebuffer_multisample;
extern cvar_t *r_arb_seamless_cube_map; 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_type_2_10_10_10_rev;
extern cvar_t *r_arb_vertex_array_object; 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_nobind; // turns off binding to appropriate textures
extern cvar_t *r_singleShader; // make most world faces use default shader extern cvar_t *r_singleShader; // make most world faces use default shader
@ -1771,11 +1777,6 @@ extern cvar_t *r_forceAutoExposureMax;
extern cvar_t *r_cameraExposure; 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_depthPrepass;
extern cvar_t *r_ssao; extern cvar_t *r_ssao;
@ -1784,8 +1785,8 @@ extern cvar_t *r_specularMapping;
extern cvar_t *r_deluxeMapping; extern cvar_t *r_deluxeMapping;
extern cvar_t *r_parallaxMapping; extern cvar_t *r_parallaxMapping;
extern cvar_t *r_cubeMapping; extern cvar_t *r_cubeMapping;
extern cvar_t *r_deluxeSpecular; extern cvar_t *r_cubemapSize;
extern cvar_t *r_specularIsMetallic; extern cvar_t *r_pbr;
extern cvar_t *r_baseNormalX; extern cvar_t *r_baseNormalX;
extern cvar_t *r_baseNormalY; extern cvar_t *r_baseNormalY;
extern cvar_t *r_baseParallax; extern cvar_t *r_baseParallax;
@ -1875,17 +1876,14 @@ void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
/* /*
** GL wrapper/helper functions ** GL wrapper/helper functions
*/ */
void GL_Bind( image_t *image );
void GL_BindToTMU( image_t *image, int tmu ); void GL_BindToTMU( image_t *image, int tmu );
void GL_SetDefaultState (void); void GL_SetDefaultState (void);
void GL_SelectTexture( int unit );
void GL_TextureMode( const char *string ); void GL_TextureMode( const char *string );
void GL_CheckErrs( char *file, int line ); void GL_CheckErrs( char *file, int line );
#define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__) #define GL_CheckErrors(...) GL_CheckErrs(__FILE__, __LINE__)
void GL_State( unsigned long stateVector ); void GL_State( unsigned long stateVector );
void GL_SetProjectionMatrix(mat4_t matrix); void GL_SetProjectionMatrix(mat4_t matrix);
void GL_SetModelviewMatrix(mat4_t matrix); void GL_SetModelviewMatrix(mat4_t matrix);
void GL_TexEnv( int env );
void GL_Cull( int cullType ); void GL_Cull( int cullType );
#define GLS_SRCBLEND_ZERO 0x00000001 #define GLS_SRCBLEND_ZERO 0x00000001
@ -2209,7 +2207,6 @@ void GLSL_InitGPUShaders(void);
void GLSL_ShutdownGPUShaders(void); void GLSL_ShutdownGPUShaders(void);
void GLSL_VertexAttribPointers(uint32_t attribBits); void GLSL_VertexAttribPointers(uint32_t attribBits);
void GLSL_BindProgram(shaderProgram_t * program); void GLSL_BindProgram(shaderProgram_t * program);
void GLSL_BindNullProgram(void);
void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value); void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value);
void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value); void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value);
@ -2411,6 +2408,10 @@ typedef struct {
viewParms_t viewParms; viewParms_t viewParms;
} postProcessCommand_t; } postProcessCommand_t;
typedef struct {
int commandId;
} exportCubemapsCommand_t;
typedef enum { typedef enum {
RC_END_OF_LIST, RC_END_OF_LIST,
RC_SET_COLOR, RC_SET_COLOR,
@ -2423,7 +2424,8 @@ typedef enum {
RC_COLORMASK, RC_COLORMASK,
RC_CLEARDEPTH, RC_CLEARDEPTH,
RC_CAPSHADOWMAP, RC_CAPSHADOWMAP,
RC_POSTPROCESS RC_POSTPROCESS,
RC_EXPORT_CUBEMAPS
} renderCommand_t; } renderCommand_t;

View file

@ -1820,13 +1820,6 @@ void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
return; 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 // sort the drawsurfs by sort type, then orientation, then shader
R_RadixSort( drawSurfs, numDrawSurfs ); R_RadixSort( drawSurfs, numDrawSurfs );
@ -2037,7 +2030,7 @@ void R_DebugGraphics( void ) {
R_IssuePendingRenderCommands(); R_IssuePendingRenderCommands();
GL_Bind( tr.whiteImage); GL_BindToTMU(tr.whiteImage, TB_COLORMAP);
GL_Cull( CT_FRONT_SIDED ); GL_Cull( CT_FRONT_SIDED );
ri.CM_DrawDebugSurface( R_DebugPolygon ); ri.CM_DrawDebugSurface( R_DebugPolygon );
} }
@ -2053,6 +2046,7 @@ or a mirror / remote location
*/ */
void R_RenderView (viewParms_t *parms) { void R_RenderView (viewParms_t *parms) {
int firstDrawSurf; int firstDrawSurf;
int numDrawSurfs;
if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
return; return;
@ -2075,7 +2069,15 @@ void R_RenderView (viewParms_t *parms) {
R_GenerateDrawSurfs(); 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) // draw main system development information (surface outlines, etc)
R_DebugGraphics(); R_DebugGraphics();
@ -2860,7 +2862,7 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
memset( &refdef, 0, sizeof( refdef ) ); memset( &refdef, 0, sizeof( refdef ) );
refdef.rdflags = 0; refdef.rdflags = 0;
VectorCopy(tr.cubemapOrigins[cubemapIndex], refdef.vieworg); VectorCopy(tr.cubemaps[cubemapIndex].origin, refdef.vieworg);
switch(cubemapSide) switch(cubemapSide)
{ {
@ -2934,7 +2936,7 @@ void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
// only print message for first side // only print message for first side
if (directed[0] + directed[1] + directed[2] == 0 && cubemapSide == 0) if (directed[0] + directed[1] + directed[2] == 0 && 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!\n", cubemapIndex, tr.cubemaps[cubemapIndex].name, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]);
} }
} }

View file

@ -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[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 // higher quality blur, but slower
else if (blur > 1.0f) 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[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 #endif
} }
@ -232,49 +232,44 @@ static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretc
const float mul = powf(stretch, inc); const float mul = powf(stretch, inc);
float scale; float scale;
{ alpha *= inc;
vec2_t texScale; VectorSet4(color, alpha, alpha, alpha, 1.0f);
texScale[0] =
texScale[1] = 1.0f;
alpha *= inc;
VectorSet4(color, alpha, alpha, alpha, 1.0f);
if (srcFbo)
VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height); VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
VectorSet4(dstBox, x, y, w, h); else
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, 0); VectorSet4(srcBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
--passes; VectorSet4(dstBox, x, y, w, h);
scale = mul; FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, 0);
while (passes > 0)
--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);
if (srcFbo)
{ {
float iscale = 1.f / scale; srcBox[0] = s0 * srcFbo->width;
float s0 = xcenter * (1.f - iscale); srcBox[1] = t0 * srcFbo->height;
float t0 = (1.0f - ycenter) * (1.f - iscale); srcBox[2] = iscale * srcFbo->width;
float s1 = iscale + s0; srcBox[3] = iscale * srcFbo->height;
float t1 = iscale + t0;
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;
}
FBO_Blit(srcFbo, srcBox, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
scale *= mul;
--passes;
} }
else
{
srcBox[0] = s0 * glConfig.vidWidth;
srcBox[1] = t0 * glConfig.vidHeight;
srcBox[2] = iscale * glConfig.vidWidth;
srcBox[3] = iscale * glConfig.vidHeight;
}
FBO_Blit(srcFbo, srcBox, NULL, dstFbo, dstBox, NULL, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
scale *= mul;
--passes;
} }
} }
@ -329,7 +324,7 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
// From RB_DrawSun() // From RB_DrawSun()
{ {
float dist; float dist;
mat4_t trans, model, mvp; mat4_t trans, model;
Mat4Translation( backEnd.viewParms.or.origin, trans ); Mat4Translation( backEnd.viewParms.or.origin, trans );
Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model ); Mat4Multiply( backEnd.viewParms.world.modelMatrix, trans, model );
@ -353,12 +348,8 @@ void RB_SunRays(FBO_t *srcFbo, ivec4_t srcBox, FBO_t *dstFbo, ivec4_t dstBox)
// initialize quarter buffers // initialize quarter buffers
{ {
float mul = 1.f; float mul = 1.f;
vec2_t texScale;
ivec4_t rayBox, quarterBox; ivec4_t rayBox, quarterBox;
texScale[0] =
texScale[1] = 1.0f;
VectorSet4(color, mul, mul, mul, 1); VectorSet4(color, mul, mul, mul, 1);
if (srcFbo) if (srcFbo)
@ -408,14 +399,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 // add result back on top of the main buffer
{ {
float mul = 1.f; float mul = 1.f;
vec2_t texScale;
texScale[0] =
texScale[1] = 1.0f;
VectorSet4(color, mul, mul, mul, 1); 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 +430,27 @@ static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean h
{ {
ivec4_t srcBox, dstBox; ivec4_t srcBox, dstBox;
vec4_t color; vec4_t color;
vec2_t texScale;
texScale[0] =
texScale[1] = 1.0f;
VectorSet4(color, weights[0], weights[0], weights[0], 1.0f); VectorSet4(color, weights[0], weights[0], weights[0], 1.0f);
VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height); VectorSet4(srcBox, 0, 0, srcFbo->width, srcFbo->height);
VectorSet4(dstBox, 0, 0, dstFbo->width, dstFbo->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); VectorSet4(color, weights[1], weights[1], weights[1], 1.0f);
dx = offsets[1] * xmul; dx = offsets[1] * xmul;
dy = offsets[1] * ymul; dy = offsets[1] * ymul;
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height); 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); 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); VectorSet4(color, weights[2], weights[2], weights[2], 1.0f);
dx = offsets[2] * xmul; dx = offsets[2] * xmul;
dy = offsets[2] * ymul; dy = offsets[2] * ymul;
VectorSet4(srcBox, dx, dy, srcFbo->width, srcFbo->height); 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); 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 +475,6 @@ void RB_GaussianBlur(float blur)
{ {
ivec4_t srcBox, dstBox; ivec4_t srcBox, dstBox;
vec4_t color; vec4_t color;
vec2_t texScale;
texScale[0] =
texScale[1] = 1.0f;
VectorSet4(color, 1, 1, 1, 1); VectorSet4(color, 1, 1, 1, 1);
@ -507,7 +486,7 @@ void RB_GaussianBlur(float blur)
VectorSet4(srcBox, 0, 0, tr.whiteImage->width, tr.whiteImage->height); VectorSet4(srcBox, 0, 0, tr.whiteImage->width, tr.whiteImage->height);
VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height); VectorSet4(dstBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
qglColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); 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, srcBox, NULL, tr.textureScratchFbo[0], dstBox, NULL, color, GLS_DEPTHTEST_DISABLE);
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// blur the tiny buffer horizontally and vertically // blur the tiny buffer horizontally and vertically
@ -518,6 +497,6 @@ void RB_GaussianBlur(float blur)
VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height); VectorSet4(srcBox, 0, 0, tr.textureScratchFbo[0]->width, tr.textureScratchFbo[0]->height);
VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight); VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
color[3] = factor; 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);
} }
} }

View file

@ -335,31 +335,30 @@ void RE_BeginScene(const refdef_t *fd)
} }
else 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; 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) 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[0] =
tr.refdef.sunAmbCol[1] = tr.refdef.sunAmbCol[1] =
tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale; tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale;
} }
else else
{ {
float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8);
if (r_forceSun->integer) if (r_forceSun->integer)
{
VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol);
VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol); VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol);
}
else else
{
VectorScale(tr.sunLight, scale, tr.refdef.sunCol);
VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol); VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol);
}
} }
} }

View file

@ -101,11 +101,9 @@ static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
int index; int index;
if ( bundle->isVideoMap ) { if ( bundle->isVideoMap ) {
int oldtmu = glState.currenttmu;
GL_SelectTexture(tmu);
ri.CIN_RunCinematic(bundle->videoMapHandle); ri.CIN_RunCinematic(bundle->videoMapHandle);
ri.CIN_UploadCinematic(bundle->videoMapHandle); ri.CIN_UploadCinematic(bundle->videoMapHandle);
GL_SelectTexture(oldtmu); GL_BindToTMU(tr.scratchImage[bundle->videoMapHandle], tmu);
return; return;
} }
@ -136,7 +134,7 @@ Draws triangle outlines for debugging
================ ================
*/ */
static void DrawTris (shaderCommands_t *input) { static void DrawTris (shaderCommands_t *input) {
GL_Bind( tr.whiteImage ); GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ); GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
qglDepthRange( 0, 0 ); qglDepthRange( 0, 0 );
@ -414,7 +412,7 @@ static void ProjectDlightTexture( void ) {
vector[3] = scale; vector[3] = scale;
GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector); 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 // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
// where they aren't rendered // where they aren't rendered
@ -444,9 +442,21 @@ static void ProjectDlightTexture( void ) {
static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor, int blend ) 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);
#if defined(USE_OVERBRIGHT)
float exactLight = 1.0f;
#else
qboolean isWorldDraw = !(backEnd.refdef.rdflags & RDF_NOWORLDMODEL);
float exactLight = (isBlend || !isWorldDraw) ? 1.0f : (float)(1 << r_mapOverBrightBits->integer);
#endif
baseColor[0] = baseColor[0] =
baseColor[1] = baseColor[1] =
baseColor[2] = baseColor[2] = exactLight;
baseColor[3] = 1.0f; baseColor[3] = 1.0f;
vertColor[0] = vertColor[0] =
@ -473,7 +483,7 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t
vertColor[0] = vertColor[0] =
vertColor[1] = vertColor[1] =
vertColor[2] = vertColor[2] = exactLight;
vertColor[3] = 1.0f; vertColor[3] = 1.0f;
break; break;
case CGEN_CONST: case CGEN_CONST:
@ -601,11 +611,7 @@ static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t
} }
// multiply color by overbrightbits if this isn't a blend // multiply color by overbrightbits if this isn't a blend
if (tr.overbrightBits if (tr.overbrightBits && !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))
{ {
float scale = 1 << tr.overbrightBits; float scale = 1 << tr.overbrightBits;
@ -854,11 +860,7 @@ static void ForwardDlight( void ) {
} }
if (r_dlightMode->integer >= 2) if (r_dlightMode->integer >= 2)
{ GL_BindToTMU(tr.shadowCubemaps[l], TB_SHADOWMAP);
GL_SelectTexture(TB_SHADOWMAP);
GL_Bind(tr.shadowCubemaps[l]);
GL_SelectTexture(0);
}
ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb );
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
@ -1258,7 +1260,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
if ( backEnd.depthFill ) if ( backEnd.depthFill )
{ {
if (!(pStage->stateBits & GLS_ATEST_BITS)) 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 ) else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 )
R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP ); R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP );
} }
@ -1271,7 +1273,19 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
{ {
GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP); GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP);
GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol); 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); GLSL_SetUniformVec4(sp, UNIFORM_PRIMARYLIGHTORIGIN, backEnd.refdef.sunDir);
} }
@ -1367,15 +1381,14 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input )
if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex && r_cubeMapping->integer) if (!(tr.viewParms.flags & VPF_NOCUBEMAPS) && input->cubemapIndex && r_cubeMapping->integer)
{ {
vec4_t vec; 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]; VectorSubtract(cubemap->origin, backEnd.viewParms.or.origin, vec);
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];
vec[3] = 1.0f; vec[3] = 1.0f;
VectorScale4(vec, 1.0f / 1000.0f, vec); VectorScale4(vec, 1.0f / cubemap->parallaxRadius, vec);
GLSL_SetUniformVec4(sp, UNIFORM_CUBEMAPINFO, vec); GLSL_SetUniformVec4(sp, UNIFORM_CUBEMAPINFO, vec);
} }

View file

@ -934,9 +934,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 ); ri.Printf( PRINT_WARNING, "WARNING: missing parameter for specular reflectance in shader '%s'\n", shader.name );
continue; continue;
} }
stage->specularScale[0] =
stage->specularScale[1] = if (r_pbr->integer)
stage->specularScale[2] = atof( token ); {
// 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> // specularExponent <value>
@ -954,17 +963,23 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
exponent = atof( token ); exponent = atof( token );
// Change shininess to gloss if (r_pbr->integer)
// FIXME: assumes max exponent of 8192 and min of 1, must change here if altered in lightall_fp.glsl stage->specularScale[0] = 1.0f - powf(2.0f / (exponent + 2.0), 0.25);
exponent = CLAMP(exponent, 1.0, 8192.0); else
{
stage->specularScale[3] = log(exponent) / log(8192.0); // 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> // gloss <value>
// //
else if (!Q_stricmp(token, "gloss")) else if (!Q_stricmp(token, "gloss"))
{ {
float gloss;
token = COM_ParseExt(text, qfalse); token = COM_ParseExt(text, qfalse);
if ( token[0] == 0 ) if ( token[0] == 0 )
{ {
@ -972,7 +987,38 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
continue; 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> // parallaxDepth <value>
@ -1025,6 +1071,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
} }
// //
// specularScale <rgb> <gloss> // specularScale <rgb> <gloss>
// or specularScale <metallic> <smoothness> with r_pbr 1
// or specularScale <r> <g> <b> // or specularScale <r> <g> <b>
// or specularScale <r> <g> <b> <gloss> // or specularScale <r> <g> <b> <gloss>
// //
@ -1051,10 +1098,19 @@ static qboolean ParseStage( shaderStage_t *stage, char **text )
token = COM_ParseExt(text, qfalse); token = COM_ParseExt(text, qfalse);
if ( token[0] == 0 ) if ( token[0] == 0 )
{ {
// two values, rgb then gloss if (r_pbr->integer)
stage->specularScale[3] = stage->specularScale[1]; {
stage->specularScale[1] = // two values, metallic then smoothness
stage->specularScale[2] = stage->specularScale[0]; 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; continue;
} }
@ -2212,12 +2268,33 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse,
if (r_specularMapping->integer) if (r_specularMapping->integer)
{ {
image_t *diffuseImg;
if (specular) if (specular)
{ {
//ri.Printf(PRINT_ALL, ", specularmap %s", specular->bundle[0].image[0]->imgName); //ri.Printf(PRINT_ALL, ", specularmap %s", specular->bundle[0].image[0]->imgName);
diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0]; diffuse->bundle[TB_SPECULARMAP] = specular->bundle[0];
VectorCopy4(specular->specularScale, diffuse->specularScale); 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) if (tcgen || diffuse->bundle[0].numTexMods)
@ -2799,10 +2876,17 @@ static void InitShader( const char *name, int lightmapIndex ) {
// default normal/specular // default normal/specular
VectorSet4(stages[i].normalScale, 0.0f, 0.0f, 0.0f, 0.0f); VectorSet4(stages[i].normalScale, 0.0f, 0.0f, 0.0f, 0.0f);
stages[i].specularScale[0] = if (r_pbr->integer)
stages[i].specularScale[1] = {
stages[i].specularScale[2] = r_baseSpecular->value; stages[i].specularScale[0] = r_baseGloss->value;
stages[i].specularScale[3] = 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;
}
} }
} }

View file

@ -206,7 +206,7 @@ void RB_ShadowTessEnd( void ) {
// draw the silhouette edges // draw the silhouette edges
GL_Bind( tr.whiteImage ); GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
qglColor3f( 0.2f, 0.2f, 0.2f ); qglColor3f( 0.2f, 0.2f, 0.2f );
@ -256,7 +256,7 @@ void RB_ShadowFinish( void ) {
qglDisable (GL_CLIP_PLANE0); qglDisable (GL_CLIP_PLANE0);
GL_Cull( CT_TWO_SIDED ); GL_Cull( CT_TWO_SIDED );
GL_Bind( tr.whiteImage ); GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
qglLoadIdentity (); qglLoadIdentity ();

View file

@ -374,7 +374,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max
//tess.numIndexes = 0; //tess.numIndexes = 0;
tess.firstIndex = tess.numIndexes; tess.firstIndex = tess.numIndexes;
GL_Bind( image ); GL_BindToTMU( image, TB_COLORMAP );
GL_Cull( CT_TWO_SIDED ); GL_Cull( CT_TWO_SIDED );
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )

View file

@ -575,7 +575,7 @@ static void RB_SurfaceBeam( void )
VectorAdd( start_points[i], direction, end_points[i] ); 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 ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
@ -1518,7 +1518,7 @@ Draws x/y/z lines from the origin for orientation debugging
static void RB_SurfaceAxis( void ) { static void RB_SurfaceAxis( void ) {
// FIXME: implement this // FIXME: implement this
#if 0 #if 0
GL_Bind( tr.whiteImage ); GL_BindToTMU( tr.whiteImage, TB_COLORMAP );
GL_State( GLS_DEFAULT ); GL_State( GLS_DEFAULT );
qglLineWidth( 3 ); qglLineWidth( 3 );
qglBegin( GL_LINES ); qglBegin( GL_LINES );

View file

@ -44,7 +44,7 @@ typedef struct voipServerPacket_s
int len; int len;
int sender; int sender;
int flags; int flags;
byte data[1024]; byte data[4000];
} voipServerPacket_t; } voipServerPacket_t;
#endif #endif
@ -299,6 +299,7 @@ extern int serverBansCount;
#ifdef USE_VOIP #ifdef USE_VOIP
extern cvar_t *sv_voip; extern cvar_t *sv_voip;
extern cvar_t *sv_voipProtocol;
#endif #endif

View file

@ -1303,6 +1303,71 @@ static void SV_ConTell_f(void) {
} }
/*
==================
SV_ConSayto_f
==================
*/
static void SV_ConSayto_f(void) {
char *p;
char text[1024];
client_t *cl;
char *rawname;
char name[MAX_NAME_LENGTH];
char cleanName[MAX_NAME_LENGTH];
client_t *saytocl;
int i;
// make sure server is running
if ( !com_sv_running->integer ) {
Com_Printf( "Server is not running.\n" );
return;
}
if ( Cmd_Argc() < 3 ) {
Com_Printf ("Usage: sayto <player name> <text>\n");
return;
}
rawname = Cmd_Argv(1);
//allowing special characters in the console
//with hex strings for player names
Com_FieldStringToPlayerName( name, MAX_NAME_LENGTH, rawname );
saytocl = NULL;
for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) {
if ( !cl->state ) {
continue;
}
Q_strncpyz( cleanName, cl->name, sizeof(cleanName) );
Q_CleanStr( cleanName );
if ( !Q_stricmp( cleanName, name ) ) {
saytocl = cl;
break;
}
}
if( !saytocl )
{
Com_Printf ("No such player name: %s.\n", name);
return;
}
strcpy (text, "console_sayto: ");
p = Cmd_ArgsFrom(2);
if ( *p == '"' ) {
p++;
p[strlen(p)-1] = 0;
}
strcat(text, p);
SV_SendServerCommand(saytocl, "chat \"%s\"", text);
}
/* /*
================== ==================
SV_Heartbeat_f SV_Heartbeat_f
@ -1407,6 +1472,43 @@ static void SV_CompleteMapName( char *args, int argNum ) {
} }
} }
/*
==================
SV_CompletePlayerName
==================
*/
static void SV_CompletePlayerName( char *args, int argNum ) {
if( argNum == 2 ) {
char names[MAX_CLIENTS][MAX_NAME_LENGTH];
char *namesPtr[MAX_CLIENTS];
client_t *cl;
int i;
int nameCount;
int clientCount;
nameCount = 0;
clientCount = sv_maxclients->integer;
for ( i=0, cl=svs.clients ; i < clientCount; i++,cl++ ) {
if ( !cl->state ) {
continue;
}
if( i >= MAX_CLIENTS ) {
break;
}
Q_strncpyz( names[nameCount], cl->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 );
}
}
/* /*
================== ==================
SV_AddOperatorCommands SV_AddOperatorCommands
@ -1453,6 +1555,8 @@ void SV_AddOperatorCommands( void ) {
if( com_dedicated->integer ) { if( com_dedicated->integer ) {
Cmd_AddCommand ("say", SV_ConSay_f); Cmd_AddCommand ("say", SV_ConSay_f);
Cmd_AddCommand ("tell", SV_ConTell_f); Cmd_AddCommand ("tell", SV_ConTell_f);
Cmd_AddCommand ("sayto", SV_ConSayto_f);
Cmd_SetCommandCompletionFunc( "sayto", SV_CompletePlayerName );
} }
Cmd_AddCommand("rehashbans", SV_RehashBans_f); Cmd_AddCommand("rehashbans", SV_RehashBans_f);

View file

@ -1459,8 +1459,8 @@ void SV_UserinfoChanged( client_t *cl ) {
else else
#endif #endif
{ {
val = Info_ValueForKey(cl->userinfo, "cl_voip"); val = Info_ValueForKey(cl->userinfo, "cl_voipProtocol");
cl->hasVoip = atoi(val); cl->hasVoip = !Q_stricmp( val, "opus" );
} }
#endif #endif
@ -1794,7 +1794,7 @@ static qboolean SV_ShouldIgnoreVoipSender(const client_t *cl)
} }
static 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; int sender, generation, sequence, frames, packetsize;
uint8_t recips[(MAX_CLIENTS + 7) / 8]; uint8_t recips[(MAX_CLIENTS + 7) / 8];
@ -1829,12 +1829,12 @@ void SV_UserVoip(client_t *cl, msg_t *msg)
MSG_ReadData(msg, encoded, packetsize); MSG_ReadData(msg, encoded, packetsize);
if (SV_ShouldIgnoreVoipSender(cl)) if (ignoreData || SV_ShouldIgnoreVoipSender(cl))
return; // Blacklisted, disabled, etc. return; // Blacklisted, disabled, etc.
// !!! FIXME: see if we read past end of msg... // !!! 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? // !!! FIXME: decide if this is bogus data?
// decide who needs this VoIP packet sent to them... // decide who needs this VoIP packet sent to them...
@ -1983,10 +1983,18 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
} }
} while ( 1 ); } while ( 1 );
// read optional voip data // skip legacy speex voip data
if ( c == clc_voip ) { if ( c == clc_voipSpeex ) {
#ifdef USE_VOIP #ifdef USE_VOIP
SV_UserVoip( cl, msg ); SV_UserVoip( cl, msg, qtrue );
c = MSG_ReadByte( msg );
#endif
}
// read optional voip data
if ( c == clc_voipOpus ) {
#ifdef USE_VOIP
SV_UserVoip( cl, msg, qfalse );
c = MSG_ReadByte( msg ); c = MSG_ReadByte( msg );
#endif #endif
} }

View file

@ -656,8 +656,9 @@ void SV_Init (void)
sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM ); sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM );
sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO ); sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO );
#ifdef USE_VOIP #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); Cvar_CheckRange(sv_voip, 0, 1, qtrue);
sv_voipProtocol = Cvar_Get("sv_voipProtocol", sv_voip->integer ? "opus" : "", CVAR_SYSTEMINFO | CVAR_ROM );
#endif #endif
Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM ); Cvar_Get ("sv_paks", "", CVAR_SYSTEMINFO | CVAR_ROM );
Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM ); Cvar_Get ("sv_pakNames", "", CVAR_SYSTEMINFO | CVAR_ROM );

View file

@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#ifdef USE_VOIP #ifdef USE_VOIP
cvar_t *sv_voip; cvar_t *sv_voip;
cvar_t *sv_voipProtocol;
#endif #endif
serverStatic_t svs; // persistant server info serverStatic_t svs; // persistant server info
@ -665,8 +666,8 @@ void SVC_Info( netadr_t from ) {
Info_SetValueForKey(infostring, "g_needpass", va("%d", Cvar_VariableIntegerValue("g_needpass"))); Info_SetValueForKey(infostring, "g_needpass", va("%d", Cvar_VariableIntegerValue("g_needpass")));
#ifdef USE_VOIP #ifdef USE_VOIP
if (sv_voip->integer) { if (sv_voipProtocol->string && *sv_voipProtocol->string) {
Info_SetValueForKey( infostring, "voip", va("%i", sv_voip->integer ) ); Info_SetValueForKey( infostring, "voip", sv_voipProtocol->string );
} }
#endif #endif

View file

@ -547,7 +547,7 @@ static void SV_WriteVoipToClient(client_t *cl, msg_t *msg)
if (totalbytes > (msg->maxsize - msg->cursize) / 2) if (totalbytes > (msg->maxsize - msg->cursize) / 2)
break; break;
MSG_WriteByte(msg, svc_voip); MSG_WriteByte(msg, svc_voipOpus);
MSG_WriteShort(msg, packet->sender); MSG_WriteShort(msg, packet->sender);
MSG_WriteByte(msg, (byte) packet->generation); MSG_WriteByte(msg, (byte) packet->generation);
MSG_WriteLong(msg, packet->sequence); MSG_WriteLong(msg, packet->sequence);

View file

@ -644,12 +644,6 @@ int main( int argc, char **argv )
// Set the initial time base // Set the initial time base
Sys_Milliseconds( ); Sys_Milliseconds( );
#ifdef MACOS_X
// This is passed if we are launched by double-clicking
if ( argc >= 2 && Q_strncmp ( argv[1], "-psn", 4 ) == 0 )
argc = 1;
#endif
#ifdef MACOS_X #ifdef MACOS_X
// This is passed if we are launched by double-clicking // This is passed if we are launched by double-clicking
if ( argc >= 2 && Q_strncmp ( argv[1], "-psn", 4 ) == 0 ) if ( argc >= 2 && Q_strncmp ( argv[1], "-psn", 4 ) == 0 )

View file

@ -142,14 +142,8 @@ char *Sys_SteamPath( void )
qboolean finishPath = qfalse; qboolean finishPath = qfalse;
#ifdef STEAMPATH_APPID #ifdef STEAMPATH_APPID
if (!steamPath[0] && !RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App " STEAMPATH_APPID, 0, KEY_QUERY_VALUE, &steamRegKey)) // Assuming Steam is a 32-bit app
{ if (!steamPath[0] && !RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App " STEAMPATH_APPID, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &steamRegKey))
pathLen = MAX_OSPATH;
if (RegQueryValueEx(steamRegKey, "InstallLocation", NULL, NULL, (LPBYTE)steamPath, &pathLen))
steamPath[0] = '\0';
}
if (!steamPath[0] && !RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App " STEAMPATH_APPID, 0, KEY_QUERY_VALUE, &steamRegKey))
{ {
pathLen = MAX_OSPATH; pathLen = MAX_OSPATH;
if (RegQueryValueEx(steamRegKey, "InstallLocation", NULL, NULL, (LPBYTE)steamPath, &pathLen)) if (RegQueryValueEx(steamRegKey, "InstallLocation", NULL, NULL, (LPBYTE)steamPath, &pathLen))

View file

@ -18,7 +18,7 @@ compatibility with existing Quake 3 mods.
- Texture upsampling. - Texture upsampling.
- Advanced materials support. - Advanced materials support.
- Advanced shading and specular methods. - Advanced shading and specular methods.
- LATC and BPTC texture compression support. - RGTC and BPTC texture compression support.
- Screen-space ambient occlusion. - Screen-space ambient occlusion.
@ -67,7 +67,7 @@ Cvars for simple rendering features:
* `r_ext_compressed_textures` - Automatically compress textures. * `r_ext_compressed_textures` - Automatically compress textures.
0 - No texture compression. (default) 0 - No texture compression. (default)
1 - DXT/LATC texture compression if 1 - DXT/RGTC texture compression if
supported. supported.
2 - BPTC texture compression if supported. 2 - BPTC texture compression if supported.
@ -160,24 +160,15 @@ Cvars for HDR and tonemapping:
Cvars for advanced material usage: Cvars for advanced material usage:
* `r_normalMapping` - Enable normal mapping for materials that * `r_normalMapping` - Enable normal maps for materials that
support it, and also specify advanced support it.
shading techniques.
0 - No. 0 - No.
1 - Yes. (default) 1 - Yes. (default)
2 - Yes, and use Oren-Nayar reflectance
model.
3 - Yes, and use tri-Ace's Oren-Nayar
reflectance model.
* `r_specularMapping` - Enable specular mapping for materials that * `r_specularMapping` - Enable specular maps for materials that
support it, and also specify advanced support it.
specular techniques.
0 - No. 0 - No.
1 - Yes, and use tri-Ace. (default) 1 - Yes. (default)
2 - Yes, and use Blinn-Phong.
3 - Yes, and use Cook-Torrance.
4 - Yes, and use Torrance-Sparrow.
* `r_deluxeMapping` - Enable deluxe mapping. (Map is compiled * `r_deluxeMapping` - Enable deluxe mapping. (Map is compiled
with light directions.) Even if the map with light directions.) Even if the map
@ -231,6 +222,12 @@ Cvars for advanced material usage:
0.05 - Standard depth. (default) 0.05 - Standard depth. (default)
0.1 - Looks broken. 0.1 - Looks broken.
* `r_pbr` - Enable physically based rendering.
Experimental, will not look correct without
assets meant for it.
0 - No. (default)
1 - Yes.
Cvars for image interpolation and generation: Cvars for image interpolation and generation:
* `r_imageUpsample` - Use interpolation to artifically increase * `r_imageUpsample` - Use interpolation to artifically increase
@ -333,13 +330,6 @@ Cvars that you probably don't care about or shouldn't mess with:
0 - No. 0 - No.
1 - Yes. (default) 1 - Yes. (default)
* `r_normalAmbient` - Split map light into ambient and directed
portions when doing deluxe mapping. Not
very useful.
0 - Don't. (default).
0.3 - 30% ambient, 70% directed.
1.0 - 100% ambient.
* `r_mergeLightmaps` - Merge the small (128x128) lightmaps into * `r_mergeLightmaps` - Merge the small (128x128) lightmaps into
2 or fewer giant (4096x4096) lightmaps. 2 or fewer giant (4096x4096) lightmaps.
Easy speedup. Easy speedup.
@ -355,20 +345,6 @@ Cvars that you probably don't care about or shouldn't mess with:
* `r_shadowCascadeZBias` - Z-bias for shadow cascade frustums. * `r_shadowCascadeZBias` - Z-bias for shadow cascade frustums.
-256 - Default. -256 - Default.
* `r_materialGamma` - Gamma level for material textures.
(diffuse, specular)
1.0 - Quake 3, fastest. (default)
* `r_lightGamma` - Gamma level for light.
(lightmap, lightgrid, vertex lights)
1.0 - Quake 3, fastest. (default)
* `r_framebufferGamma` - Gamma level for framebuffers.
1.0 - Quake 3, fastest. (default)
* `r_tonemapGamma` - Gamma applied after tonemapping.
1.0 - Quake 3, fastest. (default)
Cvars that have broken bits: Cvars that have broken bits:
* `r_dlightMode` - Change how dynamic lights look. * `r_dlightMode` - Change how dynamic lights look.

View file

@ -6,9 +6,10 @@ failed=0;
(make clean release) || failed=1; (make clean release) || failed=1;
if [ $failed -eq 1 ]; then if [ $failed -eq 1 ]; then
echo "Build failure."; echo "Build failure.";
else else
echo "Build successful."; echo "Build successful.";
fi fi
exit $failed; exit $failed;