2011-11-22 21:28:15 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 GPL Source Code
2011-12-06 18:20:15 +00:00
Copyright ( C ) 1999 - 2011 id Software LLC , a ZeniMax Media company .
2011-11-22 21:28:15 +00:00
2011-12-06 16:14:59 +00:00
This file is part of the Doom 3 GPL Source Code ( " Doom 3 Source Code " ) .
2011-11-22 21:28:15 +00:00
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 .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2011-12-16 22:28:29 +00:00
# include "sys/platform.h"
2011-11-22 21:28:15 +00:00
2011-12-16 22:28:29 +00:00
# include "renderer/tr_local.h"
2011-11-22 21:28:15 +00:00
2022-02-05 05:08:46 +00:00
static idCVar r_fillWindowAlphaChan ( " r_fillWindowAlphaChan " , " -1 " , CVAR_SYSTEM | CVAR_NOCHEAT | CVAR_ARCHIVE , " Make sure alpha channel of windows default framebuffer is completely opaque at the end of each frame. Needed at least when using Wayland. \n 1: do this, 0: don't do it, -1: let dhewm3 decide (default) " ) ;
2011-11-22 21:28:15 +00:00
frameData_t * frameData ;
backEndState_t backEnd ;
/*
= = = = = = = = = = = = = = = = = = = = = =
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 ;
qglClearDepth ( 1.0f ) ;
qglColor4f ( 1 , 1 , 1 , 1 ) ;
// the vertex array is always enabled
qglEnableClientState ( GL_VERTEX_ARRAY ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglDisableClientState ( GL_COLOR_ARRAY ) ;
//
// make sure our GL state vector is set correctly
//
memset ( & backEnd . glState , 0 , sizeof ( backEnd . glState ) ) ;
backEnd . glState . forceGlState = true ;
qglColorMask ( 1 , 1 , 1 , 1 ) ;
qglEnable ( GL_DEPTH_TEST ) ;
qglEnable ( GL_BLEND ) ;
qglEnable ( GL_SCISSOR_TEST ) ;
qglEnable ( GL_CULL_FACE ) ;
qglDisable ( GL_LIGHTING ) ;
qglDisable ( GL_LINE_STIPPLE ) ;
qglDisable ( GL_STENCIL_TEST ) ;
qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
qglDepthMask ( GL_TRUE ) ;
qglDepthFunc ( GL_ALWAYS ) ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
qglCullFace ( GL_FRONT_AND_BACK ) ;
qglShadeModel ( GL_SMOOTH ) ;
if ( r_useScissor . GetBool ( ) ) {
qglScissor ( 0 , 0 , glConfig . vidWidth , glConfig . vidHeight ) ;
}
for ( i = glConfig . maxTextureUnits - 1 ; i > = 0 ; i - - ) {
GL_SelectTexture ( i ) ;
// object linear texgen is our default
qglTexGenf ( GL_S , GL_TEXTURE_GEN_MODE , GL_OBJECT_LINEAR ) ;
qglTexGenf ( GL_T , GL_TEXTURE_GEN_MODE , GL_OBJECT_LINEAR ) ;
qglTexGenf ( GL_R , GL_TEXTURE_GEN_MODE , GL_OBJECT_LINEAR ) ;
qglTexGenf ( GL_Q , GL_TEXTURE_GEN_MODE , GL_OBJECT_LINEAR ) ;
GL_TexEnv ( GL_MODULATE ) ;
qglDisable ( GL_TEXTURE_2D ) ;
if ( glConfig . texture3DAvailable ) {
qglDisable ( GL_TEXTURE_3D ) ;
}
if ( glConfig . cubeMapAvailable ) {
qglDisable ( GL_TEXTURE_CUBE_MAP_EXT ) ;
}
}
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = = = = =
GL_SelectTexture
= = = = = = = = = = = = = = = = = = = =
*/
void GL_SelectTexture ( int unit ) {
if ( backEnd . glState . currenttmu = = unit ) {
return ;
}
2011-12-08 00:19:54 +00:00
if ( unit < 0 | | ( unit > = glConfig . maxTextureUnits & & unit > = glConfig . maxTextureImageUnits ) ) {
2011-11-22 21:28:15 +00:00
common - > Warning ( " GL_SelectTexture: unit = %i " , unit ) ;
return ;
}
qglActiveTextureARB ( GL_TEXTURE0_ARB + unit ) ;
qglClientActiveTextureARB ( GL_TEXTURE0_ARB + unit ) ;
backEnd . glState . currenttmu = 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_TexEnv
= = = = = = = = = = = = = = = = = = = =
*/
void GL_TexEnv ( int env ) {
tmu_t * tmu ;
tmu = & backEnd . glState . tmu [ backEnd . glState . currenttmu ] ;
if ( env = = tmu - > texEnv ) {
return ;
}
tmu - > texEnv = env ;
switch ( env ) {
case GL_COMBINE_EXT :
case GL_MODULATE :
case GL_REPLACE :
case GL_DECAL :
case GL_ADD :
qglTexEnvi ( GL_TEXTURE_ENV , GL_TEXTURE_ENV_MODE , env ) ;
break ;
default :
common - > Error ( " GL_TexEnv: invalid env '%d' passed \n " , env ) ;
break ;
}
}
/*
= = = = = = = = = = = = = = = = =
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 ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
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 ) ;
}
//
// fill/line mode
//
if ( diff & GLS_POLYMODE_LINE ) {
if ( stateBits & GLS_POLYMODE_LINE ) {
qglPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
} else {
qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
}
}
//
// alpha test
//
if ( diff & GLS_ATEST_BITS ) {
switch ( stateBits & GLS_ATEST_BITS ) {
case 0 :
qglDisable ( GL_ALPHA_TEST ) ;
break ;
case GLS_ATEST_EQ_255 :
qglEnable ( GL_ALPHA_TEST ) ;
qglAlphaFunc ( GL_EQUAL , 1 ) ;
break ;
case GLS_ATEST_LT_128 :
qglEnable ( GL_ALPHA_TEST ) ;
qglAlphaFunc ( GL_LESS , 0.5 ) ;
break ;
case GLS_ATEST_GE_128 :
qglEnable ( GL_ALPHA_TEST ) ;
qglAlphaFunc ( GL_GEQUAL , 0.5 ) ;
break ;
default :
assert ( 0 ) ;
break ;
}
}
backEnd . glState . glStateBits = stateBits ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
RENDER BACK END THREAD FUNCTIONS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = =
RB_SetGL2D
This is not used by the normal game paths , just by some tools
= = = = = = = = = = = = =
*/
void RB_SetGL2D ( void ) {
// set 2D virtual screen size
qglViewport ( 0 , 0 , glConfig . vidWidth , glConfig . vidHeight ) ;
if ( r_useScissor . GetBool ( ) ) {
qglScissor ( 0 , 0 , glConfig . vidWidth , glConfig . vidHeight ) ;
}
qglMatrixMode ( GL_PROJECTION ) ;
2011-12-06 18:20:15 +00:00
qglLoadIdentity ( ) ;
2011-11-22 21:28:15 +00:00
qglOrtho ( 0 , 640 , 480 , 0 , 0 , 1 ) ; // always assume 640x480 virtual coordinates
qglMatrixMode ( GL_MODELVIEW ) ;
2011-12-06 18:20:15 +00:00
qglLoadIdentity ( ) ;
2011-11-22 21:28:15 +00:00
GL_State ( GLS_DEPTHFUNC_ALWAYS |
GLS_SRCBLEND_SRC_ALPHA |
GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ;
GL_Cull ( CT_TWO_SIDED ) ;
qglDisable ( GL_DEPTH_TEST ) ;
qglDisable ( GL_STENCIL_TEST ) ;
}
/*
= = = = = = = = = = = = =
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 ;
qglDrawBuffer ( 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 ( ) | | r_showOverDraw . 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 if ( r_showOverDraw . GetBool ( ) ) {
qglClearColor ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
} else {
qglClearColor ( 0.4f , 0.0f , 0.25f , 1.0f ) ;
}
qglClear ( GL_COLOR_BUFFER_BIT ) ;
}
}
/*
= = = = = = = = = = = = = = =
RB_ShowImages
Draw all the images to the screen , on top of whatever
was there . This is used to test for texture thrashing .
= = = = = = = = = = = = = = =
*/
void RB_ShowImages ( void ) {
int i ;
idImage * image ;
float x , y , w , h ;
int start , end ;
RB_SetGL2D ( ) ;
//qglClearColor( 0.2, 0.2, 0.2, 1 );
//qglClear( GL_COLOR_BUFFER_BIT );
qglFinish ( ) ;
start = Sys_Milliseconds ( ) ;
for ( i = 0 ; i < globalImages - > images . Num ( ) ; i + + ) {
image = globalImages - > images [ i ] ;
if ( image - > texnum = = idImage : : TEXTURE_NOT_LOADED & & image - > partialImage = = NULL ) {
continue ;
}
w = glConfig . vidWidth / 20 ;
h = glConfig . vidHeight / 15 ;
x = i % 20 * w ;
y = i / 20 * h ;
// show in proportional size in mode 2
if ( r_showImages . GetInteger ( ) = = 2 ) {
w * = image - > uploadWidth / 512.0f ;
h * = image - > uploadHeight / 512.0f ;
}
image - > Bind ( ) ;
qglBegin ( GL_QUADS ) ;
qglTexCoord2f ( 0 , 0 ) ;
qglVertex2f ( x , y ) ;
qglTexCoord2f ( 1 , 0 ) ;
qglVertex2f ( x + w , y ) ;
qglTexCoord2f ( 1 , 1 ) ;
qglVertex2f ( x + w , y + h ) ;
qglTexCoord2f ( 0 , 1 ) ;
qglVertex2f ( x , y + h ) ;
qglEnd ( ) ;
}
qglFinish ( ) ;
end = Sys_Milliseconds ( ) ;
common - > Printf ( " %i msec to draw all images \n " , end - start ) ;
}
/*
= = = = = = = = = = = = =
RB_SwapBuffers
= = = = = = = = = = = = =
*/
const void RB_SwapBuffers ( const void * data ) {
// texture swapping test
if ( r_showImages . GetInteger ( ) ! = 0 ) {
RB_ShowImages ( ) ;
}
2022-02-05 05:08:46 +00:00
int fillAlpha = r_fillWindowAlphaChan . GetInteger ( ) ;
if ( fillAlpha = = 1 | | ( fillAlpha = = - 1 & & glConfig . shouldFillWindowAlpha ) )
{
// make sure the whole alpha chan of the (default) framebuffer is opaque.
// at least Wayland needs this, see also the big comment in GLimp_Init()
2022-01-22 23:29:04 +00:00
2022-02-05 05:08:46 +00:00
bool blendEnabled = qglIsEnabled ( GL_BLEND ) ;
if ( ! blendEnabled )
qglEnable ( GL_BLEND ) ;
2022-01-22 23:29:04 +00:00
2022-02-05 05:08:46 +00:00
// TODO: GL_DEPTH_TEST ? (should be disabled, if it needs changing at all)
2022-01-22 23:29:04 +00:00
2022-02-05 05:08:46 +00:00
bool scissorEnabled = qglIsEnabled ( GL_SCISSOR_TEST ) ;
if ( scissorEnabled )
qglDisable ( GL_SCISSOR_TEST ) ;
2022-01-22 23:29:04 +00:00
2022-02-05 05:08:46 +00:00
bool tex2Denabled = qglIsEnabled ( GL_TEXTURE_2D ) ;
if ( tex2Denabled )
qglDisable ( GL_TEXTURE_2D ) ;
2022-01-22 23:29:04 +00:00
2022-02-05 05:08:46 +00:00
qglDisable ( GL_VERTEX_PROGRAM_ARB ) ;
qglDisable ( GL_FRAGMENT_PROGRAM_ARB ) ;
2022-01-22 23:29:04 +00:00
2022-02-05 05:08:46 +00:00
qglBlendEquation ( GL_FUNC_ADD ) ;
2022-01-22 15:07:51 +00:00
2022-02-05 05:08:46 +00:00
qglBlendFunc ( GL_ONE , GL_ONE ) ;
2022-01-22 23:29:04 +00:00
2022-02-05 05:08:46 +00:00
// setup transform matrices so we can easily/reliably draw a fullscreen quad
qglMatrixMode ( GL_MODELVIEW ) ;
qglPushMatrix ( ) ;
qglLoadIdentity ( ) ;
qglMatrixMode ( GL_PROJECTION ) ;
qglPushMatrix ( ) ;
qglLoadIdentity ( ) ;
qglOrtho ( 0 , 1 , 0 , 1 , - 1 , 1 ) ;
// draw screen-sized quad with color (0.0, 0.0, 0.0, 1.0)
const float x = 0 , y = 0 , w = 1 , h = 1 ;
qglColor4f ( 0.0f , 0.0f , 0.0f , 1.0f ) ;
// debug values:
//const float x = 0.1, y = 0.1, w = 0.8, h = 0.8;
//qglColor4f( 0.0f, 0.0f, 0.5f, 1.0f );
qglBegin ( GL_QUADS ) ;
qglVertex2f ( x , y ) ; // ( 0,0 );
qglVertex2f ( x , y + h ) ; // ( 0,1 );
qglVertex2f ( x + w , y + h ) ; // ( 1,1 );
qglVertex2f ( x + w , y ) ; // ( 1,0 );
qglEnd ( ) ;
// restore previous transform matrix states
qglPopMatrix ( ) ; // for projection
qglMatrixMode ( GL_MODELVIEW ) ;
qglPopMatrix ( ) ; // for modelview
// restore default or previous states
qglBlendEquation ( GL_FUNC_ADD ) ;
if ( ! blendEnabled )
qglDisable ( GL_BLEND ) ;
if ( tex2Denabled )
qglEnable ( GL_TEXTURE_2D ) ;
if ( scissorEnabled )
qglEnable ( GL_SCISSOR_TEST ) ;
}
2022-01-22 15:07:51 +00:00
2011-11-22 21:28:15 +00:00
// force a gl sync if requested
if ( r_finish . GetBool ( ) ) {
qglFinish ( ) ;
}
// don't flip if drawing to front buffer
if ( ! r_frontBuffer . GetBool ( ) ) {
2011-12-06 18:20:15 +00:00
GLimp_SwapBuffers ( ) ;
2011-11-22 21:28:15 +00:00
}
}
/*
= = = = = = = = = = = = =
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 ;
}
backEndStartTime = Sys_Milliseconds ( ) ;
// needed for editor rendering
RB_SetDefaultGLState ( ) ;
// upload any image loads that have completed
globalImages - > CompleteBackgroundImageLoads ( ) ;
for ( ; cmds ; cmds = ( const emptyCommand_t * ) cmds - > next ) {
switch ( cmds - > commandId ) {
case RC_NOP :
break ;
case RC_DRAW_VIEW :
RB_DrawView ( cmds ) ;
if ( ( ( const drawSurfsCommand_t * ) cmds ) - > viewDef - > viewEntitys ) {
c_draw3d + + ;
}
else {
c_draw2d + + ;
}
break ;
case RC_SET_BUFFER :
RB_SetBuffer ( cmds ) ;
c_setBuffers + + ;
break ;
case RC_SWAP_BUFFERS :
RB_SwapBuffers ( cmds ) ;
c_swapBuffers + + ;
break ;
case RC_COPY_RENDER :
RB_CopyRender ( cmds ) ;
c_copyRenders + + ;
break ;
default :
common - > Error ( " RB_ExecuteBackEndCommands: bad commandId " ) ;
break ;
}
}
// go back to the default texture so the editor doesn't mess up a bound image
qglBindTexture ( GL_TEXTURE_2D , 0 ) ;
backEnd . glState . tmu [ 0 ] . current2DMap = - 1 ;
// 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 ;
}
}