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