📄 tr_backend.c
字号:
#ifdef __MACOS__ // crutch up the mac's limited buffer queue size
int t;
t = ri.Milliseconds();
if ( t > macEventTime ) {
macEventTime = t + MAC_EVENT_PUMP_MSEC;
Sys_PumpEvents();
}
#endif
RB_EndSurface();
}
RB_BeginSurface( shader, fogNum );
oldShader = shader;
oldFogNum = fogNum;
oldDlighted = dlighted;
}
//
// change the modelview matrix if needed
//
if ( entityNum != oldEntityNum ) {
depthRange = qfalse;
if ( entityNum != ENTITYNUM_WORLD ) {
backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
// we have to reset the shaderTime as well otherwise image animations start
// from the wrong frame
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
// set up the transformation matrix
R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or );
// set up the dynamic lighting if needed
if ( backEnd.currentEntity->needDlights ) {
R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
}
if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) {
// hack the depth range to prevent view model from poking into walls
depthRange = qtrue;
}
} else {
backEnd.currentEntity = &tr.worldEntity;
backEnd.refdef.floatTime = originalTime;
backEnd.or = backEnd.viewParms.world;
// we have to reset the shaderTime as well otherwise image animations on
// the world (like water) continue with the wrong frame
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
}
qglLoadMatrixf( backEnd.or.modelMatrix );
//
// change depthrange if needed
//
if ( oldDepthRange != depthRange ) {
if ( depthRange ) {
qglDepthRange (0, 0.3);
} else {
qglDepthRange (0, 1);
}
oldDepthRange = depthRange;
}
oldEntityNum = entityNum;
}
// add the triangles for this surface
rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
}
backEnd.refdef.floatTime = originalTime;
// draw the contents of the last shader batch
if (oldShader != NULL) {
RB_EndSurface();
}
// go back to the world modelview matrix
qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
if ( depthRange ) {
qglDepthRange (0, 1);
}
#if 0
RB_DrawSun();
#endif
// darken down any stencil shadows
RB_ShadowFinish();
// add light flares on lights that aren't obscured
RB_RenderFlares();
#ifdef __MACOS__
Sys_PumpEvents(); // crutch up the mac's limited buffer queue size
#endif
}
/*
============================================================================
RENDER BACK END THREAD FUNCTIONS
============================================================================
*/
/*
================
RB_SetGL2D
================
*/
void RB_SetGL2D (void) {
backEnd.projection2D = qtrue;
// set 2D virtual screen size
qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity ();
qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1);
qglMatrixMode(GL_MODELVIEW);
qglLoadIdentity ();
GL_State( GLS_DEPTHTEST_DISABLE |
GLS_SRCBLEND_SRC_ALPHA |
GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
qglDisable( GL_CULL_FACE );
qglDisable( GL_CLIP_PLANE0 );
// set time for 2D shaders
backEnd.refdef.time = ri.Milliseconds();
backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
}
/*
=============
RE_StretchRaw
FIXME: not exactly backend
Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
Used for cinematics.
=============
*/
void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
int i, j;
int start, end;
if ( !tr.registered ) {
return;
}
R_SyncRenderThread();
// we definately want to sync every frame for the cinematics
qglFinish();
start = end = 0;
if ( r_speeds->integer ) {
start = ri.Milliseconds();
}
// make sure rows and cols are powers of 2
for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
}
for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
}
if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
}
GL_Bind( tr.scratchImage[client] );
// 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 );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
} 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 );
}
}
if ( r_speeds->integer ) {
end = ri.Milliseconds();
ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
}
RB_SetGL2D();
qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
qglBegin (GL_QUADS);
qglTexCoord2f ( 0.5f / cols, 0.5f / rows );
qglVertex2f (x, y);
qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows );
qglVertex2f (x+w, y);
qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows );
qglVertex2f (x+w, y+h);
qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows );
qglVertex2f (x, y+h);
qglEnd ();
}
void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
GL_Bind( tr.scratchImage[client] );
// 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 );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
} 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 );
}
}
}
/*
=============
RB_SetColor
=============
*/
const void *RB_SetColor( const void *data ) {
const setColorCommand_t *cmd;
cmd = (const setColorCommand_t *)data;
backEnd.color2D[0] = cmd->color[0] * 255;
backEnd.color2D[1] = cmd->color[1] * 255;
backEnd.color2D[2] = cmd->color[2] * 255;
backEnd.color2D[3] = cmd->color[3] * 255;
return (const void *)(cmd + 1);
}
/*
=============
RB_StretchPic
=============
*/
const void *RB_StretchPic ( const void *data ) {
const stretchPicCommand_t *cmd;
shader_t *shader;
int numVerts, numIndexes;
cmd = (const stretchPicCommand_t *)data;
if ( !backEnd.projection2D ) {
RB_SetGL2D();
}
shader = cmd->shader;
if ( shader != tess.shader ) {
if ( tess.numIndexes ) {
RB_EndSurface();
}
backEnd.currentEntity = &backEnd.entity2D;
RB_BeginSurface( shader, 0 );
}
RB_CHECKOVERFLOW( 4, 6 );
numVerts = tess.numVertexes;
numIndexes = tess.numIndexes;
tess.numVertexes += 4;
tess.numIndexes += 6;
tess.indexes[ numIndexes ] = numVerts + 3;
tess.indexes[ numIndexes + 1 ] = numVerts + 0;
tess.indexes[ numIndexes + 2 ] = numVerts + 2;
tess.indexes[ numIndexes + 3 ] = numVerts + 2;
tess.indexes[ numIndexes + 4 ] = numVerts + 0;
tess.indexes[ numIndexes + 5 ] = numVerts + 1;
*(int *)tess.vertexColors[ numVerts ] =
*(int *)tess.vertexColors[ numVerts + 1 ] =
*(int *)tess.vertexColors[ numVerts + 2 ] =
*(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D;
tess.xyz[ numVerts ][0] = cmd->x;
tess.xyz[ numVerts ][1] = cmd->y;
tess.xyz[ numVerts ][2] = 0;
tess.texCoords[ numVerts ][0][0] = cmd->s1;
tess.texCoords[ numVerts ][0][1] = cmd->t1;
tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w;
tess.xyz[ numVerts + 1 ][1] = cmd->y;
tess.xyz[ numVerts + 1 ][2] = 0;
tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2;
tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1;
tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w;
tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h;
tess.xyz[ numVerts + 2 ][2] = 0;
tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2;
tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2;
tess.xyz[ numVerts + 3 ][0] = cmd->x;
tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h;
tess.xyz[ numVerts + 3 ][2] = 0;
tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1;
tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2;
return (const void *)(cmd + 1);
}
/*
=============
RB_DrawSurfs
=============
*/
const void *RB_DrawSurfs( const void *data ) {
const drawSurfsCommand_t *cmd;
// finish any 2D drawing if needed
if ( tess.numIndexes ) {
RB_EndSurface();
}
cmd = (const drawSurfsCommand_t *)data;
backEnd.refdef = cmd->refdef;
backEnd.viewParms = cmd->viewParms;
RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );
return (const void *)(cmd + 1);
}
/*
=============
RB_DrawBuffer
=============
*/
const void *RB_DrawBuffer( const void *data ) {
const drawBufferCommand_t *cmd;
cmd = (const drawBufferCommand_t *)data;
qglDrawBuffer( cmd->buffer );
// clear screen for debugging
if ( r_clear->integer ) {
qglClearColor( 1, 0, 0.5, 1 );
qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
}
return (const void *)(cmd + 1);
}
/*
===============
RB_ShowImages
Draw all the images to the screen, on top of whatever
was there. This is used to test for texture thrashing.
Also called by RE_EndRegistration
===============
*/
void RB_ShowImages( void ) {
int i;
image_t *image;
float x, y, w, h;
int start, end;
if ( !backEnd.projection2D ) {
RB_SetGL2D();
}
qglClear( GL_COLOR_BUFFER_BIT );
qglFinish();
start = ri.Milliseconds();
for ( i=0 ; i<tr.numImages ; i++ ) {
image = tr.images[i];
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->integer == 2 ) {
w *= image->uploadWidth / 512.0f;
h *= image->uploadHeight / 512.0f;
}
GL_Bind( image );
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 = ri.Milliseconds();
ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start );
}
/*
=============
RB_SwapBuffers
=============
*/
const void *RB_SwapBuffers( const void *data ) {
const swapBuffersCommand_t *cmd;
// finish any 2D drawing if needed
if ( tess.numIndexes ) {
RB_EndSurface();
}
// texture swapping test
if ( r_showImages->integer ) {
RB_ShowImages();
}
cmd = (const swapBuffersCommand_t *)data;
// we measure overdraw by reading back the stencil buffer and
// counting up the number of increments that have happened
if ( r_measureOverdraw->integer ) {
int i;
long sum = 0;
unsigned char *stencilReadback;
stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight );
qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback );
for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) {
sum += stencilReadback[i];
}
backEnd.pc.c_overDraw += sum;
ri.Hunk_FreeTempMemory( stencilReadback );
}
if ( !glState.finishCalled ) {
qglFinish();
}
GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );
GLimp_EndFrame();
backEnd.projection2D = qfalse;
return (const void *)(cmd + 1);
}
/*
====================
RB_ExecuteRenderCommands
This function will be called synchronously if running without
smp extensions, or asynchronously by another thread.
====================
*/
void RB_ExecuteRenderCommands( const void *data ) {
int t1, t2;
t1 = ri.Milliseconds ();
if ( !r_smp->integer || data == backEndData[0]->commands.cmds ) {
backEnd.smpFrame = 0;
} else {
backEnd.smpFrame = 1;
}
while ( 1 ) {
switch ( *(const int *)data ) {
case RC_SET_COLOR:
data = RB_SetColor( data );
break;
case RC_STRETCH_PIC:
data = RB_StretchPic( data );
break;
case RC_DRAW_SURFS:
data = RB_DrawSurfs( data );
break;
case RC_DRAW_BUFFER:
data = RB_DrawBuffer( data );
break;
case RC_SWAP_BUFFERS:
data = RB_SwapBuffers( data );
break;
case RC_SCREENSHOT:
data = RB_TakeScreenshotCmd( data );
break;
case RC_END_OF_LIST:
default:
// stop rendering on this thread
t2 = ri.Milliseconds ();
backEnd.pc.msec = t2 - t1;
return;
}
}
}
/*
================
RB_RenderThread
================
*/
void RB_RenderThread( void ) {
const void *data;
// wait for either a rendering command or a quit command
while ( 1 ) {
// sleep until we have work to do
data = GLimp_RendererSleep();
if ( !data ) {
return; // all done, renderer is shutting down
}
renderThreadActive = qtrue;
RB_ExecuteRenderCommands( data );
renderThreadActive = qfalse;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -