mirror of
https://github.com/DrBeef/Doom3Quest.git
synced 2025-02-16 00:51:12 +00:00
start of weapons working (6DoF) looks like glitchiness is fixed stereo working correctly most buttons working nicely positional tracking (sort of)
436 lines
11 KiB
C++
436 lines
11 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
|
|
|
Doom 3 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
#include "sys/platform.h"
|
|
|
|
#include "renderer/tr_local.h"
|
|
|
|
frameData_t *frameData;
|
|
backEndState_t backEnd;
|
|
|
|
const unsigned int NUM_FRAME_DATA = 2;
|
|
frameData_t *smpFrameData[NUM_FRAME_DATA];
|
|
volatile unsigned int smpFrame;
|
|
|
|
/*
|
|
======================
|
|
RB_SetDefaultGLState
|
|
|
|
This should initialize all GL state that any part of the entire program
|
|
may touch, including the editor.
|
|
======================
|
|
*/
|
|
void RB_SetDefaultGLState( void ) {
|
|
int i;
|
|
|
|
// Clear value for the Depth buffer
|
|
qglClearDepthf(1.0f);
|
|
|
|
// make sure our GL state vector is set correctly
|
|
memset( &backEnd.glState, 0, sizeof( backEnd.glState ) );
|
|
backEnd.glState.forceGlState = true;
|
|
|
|
// All color channels are used
|
|
qglColorMask( 1, 1, 1, 1 );
|
|
|
|
qglEnable( GL_DEPTH_TEST );
|
|
qglEnable( GL_BLEND );
|
|
qglEnable( GL_SCISSOR_TEST );
|
|
qglEnable( GL_CULL_FACE );
|
|
qglDisable( GL_STENCIL_TEST );
|
|
|
|
qglDepthMask( GL_TRUE );
|
|
qglDepthFunc( GL_ALWAYS );
|
|
|
|
qglCullFace( GL_FRONT_AND_BACK );
|
|
|
|
if ( r_useScissor.GetBool() ) {
|
|
qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
|
|
}
|
|
|
|
backEnd.glState.currentTexture = -1; // Force texture unit to be reset
|
|
for ( i = glConfig.maxTextureUnits - 1 ; i >= 0 ; i-- ) {
|
|
GL_SelectTexture( i );
|
|
globalImages->BindNull();
|
|
}
|
|
// Last active texture is Tex0
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GL_SelectTexture
|
|
====================
|
|
*/
|
|
void GL_SelectTexture( int unit ) {
|
|
if ( backEnd.glState.currentTexture != unit ) {
|
|
qglActiveTexture(GL_TEXTURE0 + unit);
|
|
backEnd.glState.currentTexture = unit;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GL_Cull
|
|
|
|
This handles the flipping needed when the view being
|
|
rendered is a mirored view.
|
|
====================
|
|
*/
|
|
void GL_Cull( int cullType ) {
|
|
if ( backEnd.glState.faceCulling == cullType ) {
|
|
return;
|
|
}
|
|
|
|
if ( cullType == CT_TWO_SIDED ) {
|
|
qglDisable( GL_CULL_FACE );
|
|
} else {
|
|
if ( backEnd.glState.faceCulling == CT_TWO_SIDED ) {
|
|
qglEnable( GL_CULL_FACE );
|
|
}
|
|
|
|
if ( cullType == CT_BACK_SIDED ) {
|
|
if ( backEnd.viewDef->isMirror ) {
|
|
qglCullFace( GL_FRONT );
|
|
} else {
|
|
qglCullFace( GL_BACK );
|
|
}
|
|
} else {
|
|
if ( backEnd.viewDef->isMirror ) {
|
|
qglCullFace( GL_BACK );
|
|
} else {
|
|
qglCullFace( GL_FRONT );
|
|
}
|
|
}
|
|
}
|
|
|
|
backEnd.glState.faceCulling = cullType;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
GL_ClearStateDelta
|
|
|
|
Clears the state delta bits, so the next GL_State
|
|
will set every item
|
|
=================
|
|
*/
|
|
void GL_ClearStateDelta( void ) {
|
|
backEnd.glState.forceGlState = true;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
GL_State
|
|
|
|
This routine is responsible for setting the most commonly changed state
|
|
====================
|
|
*/
|
|
void GL_State( int stateBits ) {
|
|
int diff;
|
|
|
|
if ( !r_useStateCaching.GetBool() || backEnd.glState.forceGlState ) {
|
|
// make sure everything is set all the time, so we
|
|
// can see if our delta checking is screwing up
|
|
diff = -1;
|
|
backEnd.glState.forceGlState = false;
|
|
} else {
|
|
diff = stateBits ^ backEnd.glState.glStateBits;
|
|
if ( !diff ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// check depthFunc bits
|
|
//
|
|
if ( diff & ( GLS_DEPTHFUNC_EQUAL | GLS_DEPTHFUNC_LESS | GLS_DEPTHFUNC_ALWAYS ) ) {
|
|
if ( stateBits & GLS_DEPTHFUNC_EQUAL ) {
|
|
qglDepthFunc( GL_EQUAL );
|
|
} else if ( stateBits & GLS_DEPTHFUNC_ALWAYS ) {
|
|
qglDepthFunc( GL_ALWAYS );
|
|
} else {
|
|
qglDepthFunc( GL_LEQUAL );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// check blend bits
|
|
//
|
|
if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) {
|
|
GLenum srcFactor, dstFactor;
|
|
|
|
switch ( stateBits & GLS_SRCBLEND_BITS ) {
|
|
case GLS_SRCBLEND_ZERO:
|
|
srcFactor = GL_ZERO;
|
|
break;
|
|
case GLS_SRCBLEND_ONE:
|
|
srcFactor = GL_ONE;
|
|
break;
|
|
case GLS_SRCBLEND_DST_COLOR:
|
|
srcFactor = GL_DST_COLOR;
|
|
break;
|
|
case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
|
|
srcFactor = GL_ONE_MINUS_DST_COLOR;
|
|
break;
|
|
case GLS_SRCBLEND_SRC_ALPHA:
|
|
srcFactor = GL_SRC_ALPHA;
|
|
break;
|
|
case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
|
|
srcFactor = GL_ONE_MINUS_SRC_ALPHA;
|
|
break;
|
|
case GLS_SRCBLEND_DST_ALPHA:
|
|
srcFactor = GL_DST_ALPHA;
|
|
break;
|
|
case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
|
|
srcFactor = GL_ONE_MINUS_DST_ALPHA;
|
|
break;
|
|
case GLS_SRCBLEND_ALPHA_SATURATE:
|
|
srcFactor = GL_SRC_ALPHA_SATURATE;
|
|
break;
|
|
default:
|
|
srcFactor = GL_ONE; // to get warning to shut up
|
|
common->Error( "GL_State: invalid src blend state bits\n" );
|
|
break;
|
|
}
|
|
|
|
switch ( stateBits & GLS_DSTBLEND_BITS ) {
|
|
case GLS_DSTBLEND_ZERO:
|
|
dstFactor = GL_ZERO;
|
|
break;
|
|
case GLS_DSTBLEND_ONE:
|
|
dstFactor = GL_ONE;
|
|
break;
|
|
case GLS_DSTBLEND_SRC_COLOR:
|
|
dstFactor = GL_SRC_COLOR;
|
|
break;
|
|
case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
|
|
dstFactor = GL_ONE_MINUS_SRC_COLOR;
|
|
break;
|
|
case GLS_DSTBLEND_SRC_ALPHA:
|
|
dstFactor = GL_SRC_ALPHA;
|
|
break;
|
|
case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
|
|
dstFactor = GL_ONE_MINUS_SRC_ALPHA;
|
|
break;
|
|
case GLS_DSTBLEND_DST_ALPHA:
|
|
dstFactor = GL_DST_ALPHA;
|
|
break;
|
|
case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
|
|
dstFactor = GL_ONE_MINUS_DST_ALPHA;
|
|
break;
|
|
default:
|
|
dstFactor = GL_ONE; // to get warning to shut up
|
|
common->Error( "GL_State: invalid dst blend state bits\n" );
|
|
break;
|
|
}
|
|
|
|
qglBlendFunc( srcFactor, dstFactor );
|
|
}
|
|
|
|
//
|
|
// check depthmask
|
|
//
|
|
if ( diff & GLS_DEPTHMASK ) {
|
|
if ( stateBits & GLS_DEPTHMASK ) {
|
|
qglDepthMask( GL_FALSE );
|
|
} else {
|
|
qglDepthMask( GL_TRUE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// check colormask
|
|
//
|
|
if ( diff & (GLS_REDMASK|GLS_GREENMASK|GLS_BLUEMASK|GLS_ALPHAMASK) ) {
|
|
GLboolean r, g, b, a;
|
|
r = ( stateBits & GLS_REDMASK ) ? 0 : 1;
|
|
g = ( stateBits & GLS_GREENMASK ) ? 0 : 1;
|
|
b = ( stateBits & GLS_BLUEMASK ) ? 0 : 1;
|
|
a = ( stateBits & GLS_ALPHAMASK ) ? 0 : 1;
|
|
qglColorMask( r, g, b, a );
|
|
}
|
|
|
|
backEnd.glState.glStateBits = stateBits;
|
|
}
|
|
|
|
/*
|
|
============================================================================
|
|
|
|
RENDER BACK END THREAD FUNCTIONS
|
|
|
|
============================================================================
|
|
*/
|
|
|
|
/*
|
|
=============
|
|
RB_SetBuffer
|
|
|
|
=============
|
|
*/
|
|
static void RB_SetBuffer( const void *data ) {
|
|
const setBufferCommand_t *cmd;
|
|
|
|
// see which draw buffer we want to render the frame to
|
|
|
|
cmd = (const setBufferCommand_t *)data;
|
|
|
|
backEnd.frameCount = cmd->frameCount;
|
|
|
|
// Disabled for OES2
|
|
//qglDrawBuffer( cmd->buffer );
|
|
|
|
GLimp_SetupFrame((int)cmd->buffer);
|
|
|
|
|
|
// clear screen for debugging
|
|
// automatically enable this with several other debug tools
|
|
// that might leave unrendered portions of the screen
|
|
if ( r_clear.GetFloat() || idStr::Length( r_clear.GetString() ) != 1 || r_lockSurfaces.GetBool() || r_singleArea.GetBool() ) {
|
|
float c[3];
|
|
if ( sscanf( r_clear.GetString(), "%f %f %f", &c[0], &c[1], &c[2] ) == 3 ) {
|
|
qglClearColor( c[0], c[1], c[2], 1 );
|
|
} else if ( r_clear.GetInteger() == 2 ) {
|
|
qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
|
|
} else {
|
|
qglClearColor( 0.4f, 0.0f, 0.25f, 1.0f );
|
|
}
|
|
qglClear( GL_COLOR_BUFFER_BIT );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
RB_SwapBuffers
|
|
|
|
=============
|
|
*/
|
|
const void RB_SwapBuffers( const void *data ) {
|
|
|
|
#ifdef WEBGL
|
|
// GAB Note Dec 2018: Clear the Alpha channel, so that final render will not blend with the HTML5 background (canvas with premultiplied alpha)
|
|
qglColorMask(0, 0, 0, 1);
|
|
qglClear(GL_COLOR_BUFFER_BIT);
|
|
#endif
|
|
|
|
|
|
// force a gl sync if requested
|
|
if ( r_finish.GetBool() ) {
|
|
qglFinish();
|
|
}
|
|
|
|
// don't flip if drawing to front buffer
|
|
GLimp_SwapBuffers();
|
|
|
|
}
|
|
|
|
/*
|
|
=============
|
|
RB_CopyRender
|
|
|
|
Copy part of the current framebuffer to an image
|
|
=============
|
|
*/
|
|
const void RB_CopyRender( const void *data ) {
|
|
const copyRenderCommand_t *cmd;
|
|
|
|
cmd = (const copyRenderCommand_t *)data;
|
|
|
|
if ( r_skipCopyTexture.GetBool() ) {
|
|
return;
|
|
}
|
|
|
|
if (cmd->image) {
|
|
cmd->image->CopyFramebuffer( cmd->x, cmd->y, cmd->imageWidth, cmd->imageHeight, false );
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
RB_ExecuteBackEndCommands
|
|
|
|
This function will be called syncronously if running without
|
|
smp extensions, or asyncronously by another thread.
|
|
====================
|
|
*/
|
|
int backEndStartTime, backEndFinishTime;
|
|
void RB_ExecuteBackEndCommands( const emptyCommand_t *cmds ) {
|
|
// r_debugRenderToTexture
|
|
int c_draw3d = 0, c_draw2d = 0, c_setBuffers = 0, c_swapBuffers = 0, c_copyRenders = 0;
|
|
|
|
if ( cmds->commandId == RC_NOP && !cmds->next ) {
|
|
return;
|
|
}
|
|
|
|
{
|
|
const emptyCommand_t *cmd = cmds;
|
|
|
|
backEndStartTime = Sys_Milliseconds();
|
|
|
|
// needed for editor rendering
|
|
RB_SetDefaultGLState();
|
|
|
|
for (; cmd; cmd = (const emptyCommand_t *) cmd->next) {
|
|
switch (cmd->commandId) {
|
|
case RC_NOP:
|
|
break;
|
|
case RC_DRAW_VIEW:
|
|
RB_DrawView(cmd);
|
|
if (((const drawSurfsCommand_t *) cmd)->viewDef->viewEntitys) {
|
|
c_draw3d++;
|
|
} else {
|
|
c_draw2d++;
|
|
}
|
|
break;
|
|
case RC_SET_BUFFER:
|
|
RB_SetBuffer(cmd);
|
|
c_setBuffers++;
|
|
break;
|
|
case RC_SWAP_BUFFERS:
|
|
RB_SwapBuffers(cmd);
|
|
c_swapBuffers++;
|
|
break;
|
|
case RC_COPY_RENDER:
|
|
RB_CopyRender(cmd);
|
|
c_copyRenders++;
|
|
break;
|
|
default:
|
|
common->Error("RB_ExecuteBackEndCommands: bad commandId");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// stop rendering on this thread
|
|
backEndFinishTime = Sys_Milliseconds();
|
|
backEnd.pc.msec = backEndFinishTime - backEndStartTime;
|
|
|
|
if ( r_debugRenderToTexture.GetInteger() == 1 ) {
|
|
common->Printf( "3d: %i, 2d: %i, SetBuf: %i, SwpBuf: %i, CpyRenders: %i, CpyFrameBuf: %i\n", c_draw3d, c_draw2d, c_setBuffers, c_swapBuffers, c_copyRenders, backEnd.c_copyFrameBuffer );
|
|
backEnd.c_copyFrameBuffer = 0;
|
|
}
|
|
}
|