1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042 |
- /*
- ===========================================================================
- 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 "../idlib/precompiled.h"
- #pragma hdrstop
- #include "tr_local.h"
- idRenderSystemLocal tr;
- idRenderSystem *renderSystem = &tr;
- /*
- =====================
- R_PerformanceCounters
- This prints both front and back end counters, so it should
- only be called when the back end thread is idle.
- =====================
- */
- static void R_PerformanceCounters( void ) {
- if ( r_showPrimitives.GetInteger() != 0 ) {
-
- float megaBytes = globalImages->SumOfUsedImages() / ( 1024*1024.0 );
- if ( r_showPrimitives.GetInteger() > 1 ) {
- common->Printf( "v:%i ds:%i t:%i/%i v:%i/%i st:%i sv:%i image:%5.1f MB\n",
- tr.pc.c_numViews,
- backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements,
- backEnd.pc.c_drawIndexes / 3,
- ( backEnd.pc.c_drawIndexes - backEnd.pc.c_drawRefIndexes ) / 3,
- backEnd.pc.c_drawVertexes,
- ( backEnd.pc.c_drawVertexes - backEnd.pc.c_drawRefVertexes ),
- backEnd.pc.c_shadowIndexes / 3,
- backEnd.pc.c_shadowVertexes,
- megaBytes
- );
- } else {
- common->Printf( "views:%i draws:%i tris:%i (shdw:%i) (vbo:%i) image:%5.1f MB\n",
- tr.pc.c_numViews,
- backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements,
- ( backEnd.pc.c_drawIndexes + backEnd.pc.c_shadowIndexes ) / 3,
- backEnd.pc.c_shadowIndexes / 3,
- backEnd.pc.c_vboIndexes / 3,
- megaBytes
- );
- }
- }
- if ( r_showDynamic.GetBool() ) {
- common->Printf( "callback:%i md5:%i dfrmVerts:%i dfrmTris:%i tangTris:%i guis:%i\n",
- tr.pc.c_entityDefCallbacks,
- tr.pc.c_generateMd5,
- tr.pc.c_deformedVerts,
- tr.pc.c_deformedIndexes/3,
- tr.pc.c_tangentIndexes/3,
- tr.pc.c_guiSurfs
- );
- }
- if ( r_showCull.GetBool() ) {
- common->Printf( "%i sin %i sclip %i sout %i bin %i bout\n",
- tr.pc.c_sphere_cull_in, tr.pc.c_sphere_cull_clip, tr.pc.c_sphere_cull_out,
- tr.pc.c_box_cull_in, tr.pc.c_box_cull_out );
- }
-
- if ( r_showAlloc.GetBool() ) {
- common->Printf( "alloc:%i free:%i\n", tr.pc.c_alloc, tr.pc.c_free );
- }
- if ( r_showInteractions.GetBool() ) {
- common->Printf( "createInteractions:%i createLightTris:%i createShadowVolumes:%i\n",
- tr.pc.c_createInteractions, tr.pc.c_createLightTris, tr.pc.c_createShadowVolumes );
- }
- if ( r_showDefs.GetBool() ) {
- common->Printf( "viewEntities:%i shadowEntities:%i viewLights:%i\n", tr.pc.c_visibleViewEntities,
- tr.pc.c_shadowViewEntities, tr.pc.c_viewLights );
- }
- if ( r_showUpdates.GetBool() ) {
- common->Printf( "entityUpdates:%i entityRefs:%i lightUpdates:%i lightRefs:%i\n",
- tr.pc.c_entityUpdates, tr.pc.c_entityReferences,
- tr.pc.c_lightUpdates, tr.pc.c_lightReferences );
- }
- if ( r_showMemory.GetBool() ) {
- int m1 = frameData ? frameData->memoryHighwater : 0;
- common->Printf( "frameData: %i (%i)\n", R_CountFrameData(), m1 );
- }
- if ( r_showLightScale.GetBool() ) {
- common->Printf( "lightScale: %f\n", backEnd.pc.maxLightValue );
- }
- memset( &tr.pc, 0, sizeof( tr.pc ) );
- memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
- }
- /*
- ====================
- R_IssueRenderCommands
- Called by R_EndFrame each frame
- ====================
- */
- static void R_IssueRenderCommands( void ) {
- if ( frameData->cmdHead->commandId == RC_NOP
- && !frameData->cmdHead->next ) {
- // nothing to issue
- return;
- }
- // r_skipBackEnd allows the entire time of the back end
- // to be removed from performance measurements, although
- // nothing will be drawn to the screen. If the prints
- // are going to a file, or r_skipBackEnd is later disabled,
- // usefull data can be received.
- // r_skipRender is usually more usefull, because it will still
- // draw 2D graphics
- if ( !r_skipBackEnd.GetBool() ) {
- RB_ExecuteBackEndCommands( frameData->cmdHead );
- }
- R_ClearCommandChain();
- }
- /*
- ============
- R_GetCommandBuffer
- Returns memory for a command buffer (stretchPicCommand_t,
- drawSurfsCommand_t, etc) and links it to the end of the
- current command chain.
- ============
- */
- void *R_GetCommandBuffer( int bytes ) {
- emptyCommand_t *cmd;
- cmd = (emptyCommand_t *)R_FrameAlloc( bytes );
- cmd->next = NULL;
- frameData->cmdTail->next = &cmd->commandId;
- frameData->cmdTail = cmd;
- return (void *)cmd;
- }
- /*
- ====================
- R_ClearCommandChain
- Called after every buffer submission
- and by R_ToggleSmpFrame
- ====================
- */
- void R_ClearCommandChain( void ) {
- // clear the command chain
- frameData->cmdHead = frameData->cmdTail = (emptyCommand_t *)R_FrameAlloc( sizeof( *frameData->cmdHead ) );
- frameData->cmdHead->commandId = RC_NOP;
- frameData->cmdHead->next = NULL;
- }
- /*
- =================
- R_ViewStatistics
- =================
- */
- static void R_ViewStatistics( viewDef_t *parms ) {
- // report statistics about this view
- if ( !r_showSurfaces.GetBool() ) {
- return;
- }
- common->Printf( "view:%p surfs:%i\n", parms, parms->numDrawSurfs );
- }
- /*
- =============
- R_AddDrawViewCmd
- This is the main 3D rendering command. A single scene may
- have multiple views if a mirror, portal, or dynamic texture is present.
- =============
- */
- void R_AddDrawViewCmd( viewDef_t *parms ) {
- drawSurfsCommand_t *cmd;
- cmd = (drawSurfsCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
- cmd->commandId = RC_DRAW_VIEW;
- cmd->viewDef = parms;
- if ( parms->viewEntitys ) {
- // save the command for r_lockSurfaces debugging
- tr.lockSurfacesCmd = *cmd;
- }
- tr.pc.c_numViews++;
- R_ViewStatistics( parms );
- }
- //=================================================================================
- /*
- ======================
- R_LockSurfaceScene
- r_lockSurfaces allows a developer to move around
- without changing the composition of the scene, including
- culling. The only thing that is modified is the
- view position and axis, no front end work is done at all
- Add the stored off command again, so the new rendering will use EXACTLY
- the same surfaces, including all the culling, even though the transformation
- matricies have been changed. This allow the culling tightness to be
- evaluated interactively.
- ======================
- */
- void R_LockSurfaceScene( viewDef_t *parms ) {
- drawSurfsCommand_t *cmd;
- viewEntity_t *vModel;
- // set the matrix for world space to eye space
- R_SetViewMatrix( parms );
- tr.lockSurfacesCmd.viewDef->worldSpace = parms->worldSpace;
-
- // update the view origin and axis, and all
- // the entity matricies
- for( vModel = tr.lockSurfacesCmd.viewDef->viewEntitys ; vModel ; vModel = vModel->next ) {
- myGlMultMatrix( vModel->modelMatrix,
- tr.lockSurfacesCmd.viewDef->worldSpace.modelViewMatrix,
- vModel->modelViewMatrix );
- }
- // add the stored off surface commands again
- cmd = (drawSurfsCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
- *cmd = tr.lockSurfacesCmd;
- }
- /*
- =============
- R_CheckCvars
- See if some cvars that we watch have changed
- =============
- */
- static void R_CheckCvars( void ) {
- globalImages->CheckCvars();
- // gamma stuff
- if ( r_gamma.IsModified() || r_brightness.IsModified() ) {
- r_gamma.ClearModified();
- r_brightness.ClearModified();
- R_SetColorMappings();
- }
- // check for changes to logging state
- GLimp_EnableLogging( r_logFile.GetInteger() != 0 );
- }
- /*
- =============
- idRenderSystemLocal::idRenderSystemLocal
- =============
- */
- idRenderSystemLocal::idRenderSystemLocal( void ) {
- Clear();
- }
- /*
- =============
- idRenderSystemLocal::~idRenderSystemLocal
- =============
- */
- idRenderSystemLocal::~idRenderSystemLocal( void ) {
- }
- /*
- =============
- SetColor
- This can be used to pass general information to the current material, not
- just colors
- =============
- */
- void idRenderSystemLocal::SetColor( const idVec4 &rgba ) {
- guiModel->SetColor( rgba[0], rgba[1], rgba[2], rgba[3] );
- }
- /*
- =============
- SetColor4
- =============
- */
- void idRenderSystemLocal::SetColor4( float r, float g, float b, float a ) {
- guiModel->SetColor( r, g, b, a );
- }
- /*
- =============
- DrawStretchPic
- =============
- */
- void idRenderSystemLocal::DrawStretchPic( const idDrawVert *verts, const glIndex_t *indexes, int vertCount, int indexCount, const idMaterial *material,
- bool clip, float min_x, float min_y, float max_x, float max_y ) {
- guiModel->DrawStretchPic( verts, indexes, vertCount, indexCount, material,
- clip, min_x, min_y, max_x, max_y );
- }
- /*
- =============
- DrawStretchPic
- x/y/w/h are in the 0,0 to 640,480 range
- =============
- */
- void idRenderSystemLocal::DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *material ) {
- guiModel->DrawStretchPic( x, y, w, h, s1, t1, s2, t2, material );
- }
- /*
- =============
- DrawStretchTri
- x/y/w/h are in the 0,0 to 640,480 range
- =============
- */
- void idRenderSystemLocal::DrawStretchTri( idVec2 p1, idVec2 p2, idVec2 p3, idVec2 t1, idVec2 t2, idVec2 t3, const idMaterial *material ) {
- tr.guiModel->DrawStretchTri( p1, p2, p3, t1, t2, t3, material );
- }
- /*
- =============
- GlobalToNormalizedDeviceCoordinates
- =============
- */
- void idRenderSystemLocal::GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ) {
- R_GlobalToNormalizedDeviceCoordinates( global, ndc );
- }
- /*
- =============
- GlobalToNormalizedDeviceCoordinates
- =============
- */
- void idRenderSystemLocal::GetGLSettings( int& width, int& height ) {
- width = glConfig.vidWidth;
- height = glConfig.vidHeight;
- }
- /*
- =====================
- idRenderSystemLocal::DrawSmallChar
- small chars are drawn at native screen resolution
- =====================
- */
- void idRenderSystemLocal::DrawSmallChar( int x, int y, int ch, const idMaterial *material ) {
- int row, col;
- float frow, fcol;
- float size;
- ch &= 255;
- if ( ch == ' ' ) {
- return;
- }
- if ( y < -SMALLCHAR_HEIGHT ) {
- return;
- }
- row = ch >> 4;
- col = ch & 15;
- frow = row * 0.0625f;
- fcol = col * 0.0625f;
- size = 0.0625f;
- DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
- fcol, frow,
- fcol + size, frow + size,
- material );
- }
- /*
- ==================
- idRenderSystemLocal::DrawSmallString[Color]
- Draws a multi-colored string with a drop shadow, optionally forcing
- to a fixed color.
- Coordinates are at 640 by 480 virtual resolution
- ==================
- */
- void idRenderSystemLocal::DrawSmallStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ) {
- idVec4 color;
- const unsigned char *s;
- int xx;
- // draw the colored text
- s = (const unsigned char*)string;
- xx = x;
- SetColor( setColor );
- while ( *s ) {
- if ( idStr::IsColor( (const char*)s ) ) {
- if ( !forceColor ) {
- if ( *(s+1) == C_COLOR_DEFAULT ) {
- SetColor( setColor );
- } else {
- color = idStr::ColorForIndex( *(s+1) );
- color[3] = setColor[3];
- SetColor( color );
- }
- }
- s += 2;
- continue;
- }
- DrawSmallChar( xx, y, *s, material );
- xx += SMALLCHAR_WIDTH;
- s++;
- }
- SetColor( colorWhite );
- }
- /*
- =====================
- idRenderSystemLocal::DrawBigChar
- =====================
- */
- void idRenderSystemLocal::DrawBigChar( int x, int y, int ch, const idMaterial *material ) {
- int row, col;
- float frow, fcol;
- float size;
- ch &= 255;
- if ( ch == ' ' ) {
- return;
- }
- if ( y < -BIGCHAR_HEIGHT ) {
- return;
- }
- row = ch >> 4;
- col = ch & 15;
- frow = row * 0.0625f;
- fcol = col * 0.0625f;
- size = 0.0625f;
- DrawStretchPic( x, y, BIGCHAR_WIDTH, BIGCHAR_HEIGHT,
- fcol, frow,
- fcol + size, frow + size,
- material );
- }
- /*
- ==================
- idRenderSystemLocal::DrawBigString[Color]
- Draws a multi-colored string with a drop shadow, optionally forcing
- to a fixed color.
- Coordinates are at 640 by 480 virtual resolution
- ==================
- */
- void idRenderSystemLocal::DrawBigStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ) {
- idVec4 color;
- const char *s;
- int xx;
- // draw the colored text
- s = string;
- xx = x;
- SetColor( setColor );
- while ( *s ) {
- if ( idStr::IsColor( s ) ) {
- if ( !forceColor ) {
- if ( *(s+1) == C_COLOR_DEFAULT ) {
- SetColor( setColor );
- } else {
- color = idStr::ColorForIndex( *(s+1) );
- color[3] = setColor[3];
- SetColor( color );
- }
- }
- s += 2;
- continue;
- }
- DrawBigChar( xx, y, *s, material );
- xx += BIGCHAR_WIDTH;
- s++;
- }
- SetColor( colorWhite );
- }
- //======================================================================================
- /*
- ==================
- SetBackEndRenderer
- Check for changes in the back end renderSystem, possibly invalidating cached data
- ==================
- */
- void idRenderSystemLocal::SetBackEndRenderer() {
- if ( !r_renderer.IsModified() ) {
- return;
- }
- bool oldVPstate = backEndRendererHasVertexPrograms;
- backEndRenderer = BE_BAD;
- if ( idStr::Icmp( r_renderer.GetString(), "arb" ) == 0 ) {
- backEndRenderer = BE_ARB;
- } else if ( idStr::Icmp( r_renderer.GetString(), "arb2" ) == 0 ) {
- if ( glConfig.allowARB2Path ) {
- backEndRenderer = BE_ARB2;
- }
- } else if ( idStr::Icmp( r_renderer.GetString(), "nv10" ) == 0 ) {
- if ( glConfig.allowNV10Path ) {
- backEndRenderer = BE_NV10;
- }
- } else if ( idStr::Icmp( r_renderer.GetString(), "nv20" ) == 0 ) {
- if ( glConfig.allowNV20Path ) {
- backEndRenderer = BE_NV20;
- }
- } else if ( idStr::Icmp( r_renderer.GetString(), "r200" ) == 0 ) {
- if ( glConfig.allowR200Path ) {
- backEndRenderer = BE_R200;
- }
- }
- // fallback
- if ( backEndRenderer == BE_BAD ) {
- // choose the best
- if ( glConfig.allowARB2Path ) {
- backEndRenderer = BE_ARB2;
- } else if ( glConfig.allowR200Path ) {
- backEndRenderer = BE_R200;
- } else if ( glConfig.allowNV20Path ) {
- backEndRenderer = BE_NV20;
- } else if ( glConfig.allowNV10Path ) {
- backEndRenderer = BE_NV10;
- } else {
- // the others are considered experimental
- backEndRenderer = BE_ARB;
- }
- }
- backEndRendererHasVertexPrograms = false;
- backEndRendererMaxLight = 1.0;
- switch( backEndRenderer ) {
- case BE_ARB:
- common->Printf( "using ARB renderSystem\n" );
- break;
- case BE_NV10:
- common->Printf( "using NV10 renderSystem\n" );
- break;
- case BE_NV20:
- common->Printf( "using NV20 renderSystem\n" );
- backEndRendererHasVertexPrograms = true;
- break;
- case BE_R200:
- common->Printf( "using R200 renderSystem\n" );
- backEndRendererHasVertexPrograms = true;
- break;
- case BE_ARB2:
- common->Printf( "using ARB2 renderSystem\n" );
- backEndRendererHasVertexPrograms = true;
- backEndRendererMaxLight = 999;
- break;
- default:
- common->FatalError( "SetbackEndRenderer: bad back end" );
- }
- // clear the vertex cache if we are changing between
- // using vertex programs and not, because specular and
- // shadows will be different data
- if ( oldVPstate != backEndRendererHasVertexPrograms ) {
- vertexCache.PurgeAll();
- if ( primaryWorld ) {
- primaryWorld->FreeInteractions();
- }
- }
- r_renderer.ClearModified();
- }
- /*
- ====================
- BeginFrame
- ====================
- */
- void idRenderSystemLocal::BeginFrame( int windowWidth, int windowHeight ) {
- setBufferCommand_t *cmd;
- if ( !glConfig.isInitialized ) {
- return;
- }
- // determine which back end we will use
- SetBackEndRenderer();
- guiModel->Clear();
- // for the larger-than-window tiled rendering screenshots
- if ( tiledViewport[0] ) {
- windowWidth = tiledViewport[0];
- windowHeight = tiledViewport[1];
- }
- glConfig.vidWidth = windowWidth;
- glConfig.vidHeight = windowHeight;
- renderCrops[0].x = 0;
- renderCrops[0].y = 0;
- renderCrops[0].width = windowWidth;
- renderCrops[0].height = windowHeight;
- currentRenderCrop = 0;
- // screenFraction is just for quickly testing fill rate limitations
- if ( r_screenFraction.GetInteger() != 100 ) {
- int w = SCREEN_WIDTH * r_screenFraction.GetInteger() / 100.0f;
- int h = SCREEN_HEIGHT * r_screenFraction.GetInteger() / 100.0f;
- CropRenderSize( w, h );
- }
- // this is the ONLY place this is modified
- frameCount++;
- // just in case we did a common->Error while this
- // was set
- guiRecursionLevel = 0;
- // the first rendering will be used for commands like
- // screenshot, rather than a possible subsequent remote
- // or mirror render
- // primaryWorld = NULL;
- // set the time for shader effects in 2D rendering
- frameShaderTime = eventLoop->Milliseconds() * 0.001;
- //
- // draw buffer stuff
- //
- cmd = (setBufferCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
- cmd->commandId = RC_SET_BUFFER;
- cmd->frameCount = frameCount;
- if ( r_frontBuffer.GetBool() ) {
- cmd->buffer = (int)GL_FRONT;
- } else {
- cmd->buffer = (int)GL_BACK;
- }
- }
- void idRenderSystemLocal::WriteDemoPics() {
- session->writeDemo->WriteInt( DS_RENDER );
- session->writeDemo->WriteInt( DC_GUI_MODEL );
- guiModel->WriteToDemo( session->writeDemo );
- }
- void idRenderSystemLocal::DrawDemoPics() {
- demoGuiModel->EmitFullScreen();
- }
- /*
- =============
- EndFrame
- Returns the number of msec spent in the back end
- =============
- */
- void idRenderSystemLocal::EndFrame( int *frontEndMsec, int *backEndMsec ) {
- emptyCommand_t *cmd;
- if ( !glConfig.isInitialized ) {
- return;
- }
- // close any gui drawing
- guiModel->EmitFullScreen();
- guiModel->Clear();
- // save out timing information
- if ( frontEndMsec ) {
- *frontEndMsec = pc.frontEndMsec;
- }
- if ( backEndMsec ) {
- *backEndMsec = backEnd.pc.msec;
- }
- // print any other statistics and clear all of them
- R_PerformanceCounters();
- // check for dynamic changes that require some initialization
- R_CheckCvars();
- // check for errors
- GL_CheckErrors();
- // add the swapbuffers command
- cmd = (emptyCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
- cmd->commandId = RC_SWAP_BUFFERS;
- // start the back end up again with the new command list
- R_IssueRenderCommands();
- // use the other buffers next frame, because another CPU
- // may still be rendering into the current buffers
- R_ToggleSmpFrame();
- // we can now release the vertexes used this frame
- vertexCache.EndFrame();
- if ( session->writeDemo ) {
- session->writeDemo->WriteInt( DS_RENDER );
- session->writeDemo->WriteInt( DC_END_FRAME );
- if ( r_showDemo.GetBool() ) {
- common->Printf( "write DC_END_FRAME\n" );
- }
- }
- }
- /*
- =====================
- RenderViewToViewport
- Converts from SCREEN_WIDTH / SCREEN_HEIGHT coordinates to current cropped pixel coordinates
- =====================
- */
- void idRenderSystemLocal::RenderViewToViewport( const renderView_t *renderView, idScreenRect *viewport ) {
- renderCrop_t *rc = &renderCrops[currentRenderCrop];
- float wRatio = (float)rc->width / SCREEN_WIDTH;
- float hRatio = (float)rc->height / SCREEN_HEIGHT;
- viewport->x1 = idMath::Ftoi( rc->x + renderView->x * wRatio );
- viewport->x2 = idMath::Ftoi( rc->x + floor( ( renderView->x + renderView->width ) * wRatio + 0.5f ) - 1 );
- viewport->y1 = idMath::Ftoi( ( rc->y + rc->height ) - floor( ( renderView->y + renderView->height ) * hRatio + 0.5f ) );
- viewport->y2 = idMath::Ftoi( ( rc->y + rc->height ) - floor( renderView->y * hRatio + 0.5f ) - 1 );
- }
- static int RoundDownToPowerOfTwo( int v ) {
- int i;
- for ( i = 0 ; i < 20 ; i++ ) {
- if ( ( 1 << i ) == v ) {
- return v;
- }
- if ( ( 1 << i ) > v ) {
- return 1 << ( i-1 );
- }
- }
- return 1<<i;
- }
- /*
- ================
- CropRenderSize
- This automatically halves sizes until it fits in the current window size,
- so if you specify a power of two size for a texture copy, it may be shrunk
- down, but still valid.
- ================
- */
- void idRenderSystemLocal::CropRenderSize( int width, int height, bool makePowerOfTwo, bool forceDimensions ) {
- if ( !glConfig.isInitialized ) {
- return;
- }
- // close any gui drawing before changing the size
- guiModel->EmitFullScreen();
- guiModel->Clear();
- if ( width < 1 || height < 1 ) {
- common->Error( "CropRenderSize: bad sizes" );
- }
- if ( session->writeDemo ) {
- session->writeDemo->WriteInt( DS_RENDER );
- session->writeDemo->WriteInt( DC_CROP_RENDER );
- session->writeDemo->WriteInt( width );
- session->writeDemo->WriteInt( height );
- session->writeDemo->WriteInt( makePowerOfTwo );
- if ( r_showDemo.GetBool() ) {
- common->Printf( "write DC_CROP_RENDER\n" );
- }
- }
- // convert from virtual SCREEN_WIDTH/SCREEN_HEIGHT coordinates to physical OpenGL pixels
- renderView_t renderView;
- renderView.x = 0;
- renderView.y = 0;
- renderView.width = width;
- renderView.height = height;
- idScreenRect r;
- RenderViewToViewport( &renderView, &r );
- width = r.x2 - r.x1 + 1;
- height = r.y2 - r.y1 + 1;
- if ( forceDimensions ) {
- // just give exactly what we ask for
- width = renderView.width;
- height = renderView.height;
- }
- // if makePowerOfTwo, drop to next lower power of two after scaling to physical pixels
- if ( makePowerOfTwo ) {
- width = RoundDownToPowerOfTwo( width );
- height = RoundDownToPowerOfTwo( height );
- // FIXME: megascreenshots with offset viewports don't work right with this yet
- }
- renderCrop_t *rc = &renderCrops[currentRenderCrop];
- // we might want to clip these to the crop window instead
- while ( width > glConfig.vidWidth ) {
- width >>= 1;
- }
- while ( height > glConfig.vidHeight ) {
- height >>= 1;
- }
- if ( currentRenderCrop == MAX_RENDER_CROPS ) {
- common->Error( "idRenderSystemLocal::CropRenderSize: currentRenderCrop == MAX_RENDER_CROPS" );
- }
- currentRenderCrop++;
- rc = &renderCrops[currentRenderCrop];
- rc->x = 0;
- rc->y = 0;
- rc->width = width;
- rc->height = height;
- }
- /*
- ================
- UnCrop
- ================
- */
- void idRenderSystemLocal::UnCrop() {
- if ( !glConfig.isInitialized ) {
- return;
- }
- if ( currentRenderCrop < 1 ) {
- common->Error( "idRenderSystemLocal::UnCrop: currentRenderCrop < 1" );
- }
- // close any gui drawing
- guiModel->EmitFullScreen();
- guiModel->Clear();
- currentRenderCrop--;
- if ( session->writeDemo ) {
- session->writeDemo->WriteInt( DS_RENDER );
- session->writeDemo->WriteInt( DC_UNCROP_RENDER );
- if ( r_showDemo.GetBool() ) {
- common->Printf( "write DC_UNCROP\n" );
- }
- }
- }
- /*
- ================
- CaptureRenderToImage
- ================
- */
- void idRenderSystemLocal::CaptureRenderToImage( const char *imageName ) {
- if ( !glConfig.isInitialized ) {
- return;
- }
- guiModel->EmitFullScreen();
- guiModel->Clear();
- if ( session->writeDemo ) {
- session->writeDemo->WriteInt( DS_RENDER );
- session->writeDemo->WriteInt( DC_CAPTURE_RENDER );
- session->writeDemo->WriteHashString( imageName );
- if ( r_showDemo.GetBool() ) {
- common->Printf( "write DC_CAPTURE_RENDER: %s\n", imageName );
- }
- }
- // look up the image before we create the render command, because it
- // may need to sync to create the image
- idImage *image = globalImages->ImageFromFile(imageName, TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT);
- renderCrop_t *rc = &renderCrops[currentRenderCrop];
- copyRenderCommand_t *cmd = (copyRenderCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
- cmd->commandId = RC_COPY_RENDER;
- cmd->x = rc->x;
- cmd->y = rc->y;
- cmd->imageWidth = rc->width;
- cmd->imageHeight = rc->height;
- cmd->image = image;
- guiModel->Clear();
- }
- /*
- ==============
- CaptureRenderToFile
- ==============
- */
- void idRenderSystemLocal::CaptureRenderToFile( const char *fileName, bool fixAlpha ) {
- if ( !glConfig.isInitialized ) {
- return;
- }
- renderCrop_t *rc = &renderCrops[currentRenderCrop];
- guiModel->EmitFullScreen();
- guiModel->Clear();
- R_IssueRenderCommands();
- qglReadBuffer( GL_BACK );
- // include extra space for OpenGL padding to word boundaries
- int c = ( rc->width + 3 ) * rc->height;
- byte *data = (byte *)R_StaticAlloc( c * 3 );
-
- qglReadPixels( rc->x, rc->y, rc->width, rc->height, GL_RGB, GL_UNSIGNED_BYTE, data );
- byte *data2 = (byte *)R_StaticAlloc( c * 4 );
- for ( int i = 0 ; i < c ; i++ ) {
- data2[ i * 4 ] = data[ i * 3 ];
- data2[ i * 4 + 1 ] = data[ i * 3 + 1 ];
- data2[ i * 4 + 2 ] = data[ i * 3 + 2 ];
- data2[ i * 4 + 3 ] = 0xff;
- }
- R_WriteTGA( fileName, data2, rc->width, rc->height, true );
- R_StaticFree( data );
- R_StaticFree( data2 );
- }
- /*
- ==============
- AllocRenderWorld
- ==============
- */
- idRenderWorld *idRenderSystemLocal::AllocRenderWorld() {
- idRenderWorldLocal *rw;
- rw = new idRenderWorldLocal;
- worlds.Append( rw );
- return rw;
- }
- /*
- ==============
- FreeRenderWorld
- ==============
- */
- void idRenderSystemLocal::FreeRenderWorld( idRenderWorld *rw ) {
- if ( primaryWorld == rw ) {
- primaryWorld = NULL;
- }
- worlds.Remove( static_cast<idRenderWorldLocal *>(rw) );
- delete rw;
- }
- /*
- ==============
- PrintMemInfo
- ==============
- */
- void idRenderSystemLocal::PrintMemInfo( MemInfo_t *mi ) {
- // sum up image totals
- globalImages->PrintMemInfo( mi );
- // sum up model totals
- renderModelManager->PrintMemInfo( mi );
- // compute render totals
- }
- /*
- ===============
- idRenderSystemLocal::UploadImage
- ===============
- */
- bool idRenderSystemLocal::UploadImage( const char *imageName, const byte *data, int width, int height ) {
- idImage *image = globalImages->GetImage( imageName );
- if ( !image ) {
- return false;
- }
- image->UploadScratch( data, width, height );
- image->SetImageFilterAndRepeat();
- return true;
- }
|