2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 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.
24 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.
26 ===========================================================================
28 #include "../idlib/precompiled.h"
33 idRenderSystemLocal tr;
34 idRenderSystem *renderSystem = &tr;
41 This prints both front and back end counters, so it should
42 only be called when the back end thread is idle.
45 static void R_PerformanceCounters( void ) {
46 if ( r_showPrimitives.GetInteger() != 0 ) {
48 float megaBytes = globalImages->SumOfUsedImages() / ( 1024*1024.0 );
50 if ( r_showPrimitives.GetInteger() > 1 ) {
51 common->Printf( "v:%i ds:%i t:%i/%i v:%i/%i st:%i sv:%i image:%5.1f MB\n",
53 backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements,
54 backEnd.pc.c_drawIndexes / 3,
55 ( backEnd.pc.c_drawIndexes - backEnd.pc.c_drawRefIndexes ) / 3,
56 backEnd.pc.c_drawVertexes,
57 ( backEnd.pc.c_drawVertexes - backEnd.pc.c_drawRefVertexes ),
58 backEnd.pc.c_shadowIndexes / 3,
59 backEnd.pc.c_shadowVertexes,
63 common->Printf( "views:%i draws:%i tris:%i (shdw:%i) (vbo:%i) image:%5.1f MB\n",
65 backEnd.pc.c_drawElements + backEnd.pc.c_shadowElements,
66 ( backEnd.pc.c_drawIndexes + backEnd.pc.c_shadowIndexes ) / 3,
67 backEnd.pc.c_shadowIndexes / 3,
68 backEnd.pc.c_vboIndexes / 3,
74 if ( r_showDynamic.GetBool() ) {
75 common->Printf( "callback:%i md5:%i dfrmVerts:%i dfrmTris:%i tangTris:%i guis:%i\n",
76 tr.pc.c_entityDefCallbacks,
78 tr.pc.c_deformedVerts,
79 tr.pc.c_deformedIndexes/3,
80 tr.pc.c_tangentIndexes/3,
85 if ( r_showCull.GetBool() ) {
86 common->Printf( "%i sin %i sclip %i sout %i bin %i bout\n",
87 tr.pc.c_sphere_cull_in, tr.pc.c_sphere_cull_clip, tr.pc.c_sphere_cull_out,
88 tr.pc.c_box_cull_in, tr.pc.c_box_cull_out );
91 if ( r_showAlloc.GetBool() ) {
92 common->Printf( "alloc:%i free:%i\n", tr.pc.c_alloc, tr.pc.c_free );
95 if ( r_showInteractions.GetBool() ) {
96 common->Printf( "createInteractions:%i createLightTris:%i createShadowVolumes:%i\n",
97 tr.pc.c_createInteractions, tr.pc.c_createLightTris, tr.pc.c_createShadowVolumes );
99 if ( r_showDefs.GetBool() ) {
100 common->Printf( "viewEntities:%i shadowEntities:%i viewLights:%i\n", tr.pc.c_visibleViewEntities,
101 tr.pc.c_shadowViewEntities, tr.pc.c_viewLights );
103 if ( r_showUpdates.GetBool() ) {
104 common->Printf( "entityUpdates:%i entityRefs:%i lightUpdates:%i lightRefs:%i\n",
105 tr.pc.c_entityUpdates, tr.pc.c_entityReferences,
106 tr.pc.c_lightUpdates, tr.pc.c_lightReferences );
108 if ( r_showMemory.GetBool() ) {
109 int m1 = frameData ? frameData->memoryHighwater : 0;
110 common->Printf( "frameData: %i (%i)\n", R_CountFrameData(), m1 );
112 if ( r_showLightScale.GetBool() ) {
113 common->Printf( "lightScale: %f\n", backEnd.pc.maxLightValue );
116 memset( &tr.pc, 0, sizeof( tr.pc ) );
117 memset( &backEnd.pc, 0, sizeof( backEnd.pc ) );
124 R_IssueRenderCommands
126 Called by R_EndFrame each frame
129 static void R_IssueRenderCommands( void ) {
130 if ( frameData->cmdHead->commandId == RC_NOP
131 && !frameData->cmdHead->next ) {
136 // r_skipBackEnd allows the entire time of the back end
137 // to be removed from performance measurements, although
138 // nothing will be drawn to the screen. If the prints
139 // are going to a file, or r_skipBackEnd is later disabled,
140 // usefull data can be received.
142 // r_skipRender is usually more usefull, because it will still
144 if ( !r_skipBackEnd.GetBool() ) {
145 RB_ExecuteBackEndCommands( frameData->cmdHead );
148 R_ClearCommandChain();
155 Returns memory for a command buffer (stretchPicCommand_t,
156 drawSurfsCommand_t, etc) and links it to the end of the
157 current command chain.
160 void *R_GetCommandBuffer( int bytes ) {
163 cmd = (emptyCommand_t *)R_FrameAlloc( bytes );
165 frameData->cmdTail->next = &cmd->commandId;
166 frameData->cmdTail = cmd;
176 Called after every buffer submission
177 and by R_ToggleSmpFrame
180 void R_ClearCommandChain( void ) {
181 // clear the command chain
182 frameData->cmdHead = frameData->cmdTail = (emptyCommand_t *)R_FrameAlloc( sizeof( *frameData->cmdHead ) );
183 frameData->cmdHead->commandId = RC_NOP;
184 frameData->cmdHead->next = NULL;
192 static void R_ViewStatistics( viewDef_t *parms ) {
193 // report statistics about this view
194 if ( !r_showSurfaces.GetBool() ) {
197 common->Printf( "view:%p surfs:%i\n", parms, parms->numDrawSurfs );
204 This is the main 3D rendering command. A single scene may
205 have multiple views if a mirror, portal, or dynamic texture is present.
208 void R_AddDrawViewCmd( viewDef_t *parms ) {
209 drawSurfsCommand_t *cmd;
211 cmd = (drawSurfsCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
212 cmd->commandId = RC_DRAW_VIEW;
214 cmd->viewDef = parms;
216 if ( parms->viewEntitys ) {
217 // save the command for r_lockSurfaces debugging
218 tr.lockSurfacesCmd = *cmd;
223 R_ViewStatistics( parms );
227 //=================================================================================
231 ======================
234 r_lockSurfaces allows a developer to move around
235 without changing the composition of the scene, including
236 culling. The only thing that is modified is the
237 view position and axis, no front end work is done at all
240 Add the stored off command again, so the new rendering will use EXACTLY
241 the same surfaces, including all the culling, even though the transformation
242 matricies have been changed. This allow the culling tightness to be
243 evaluated interactively.
244 ======================
246 void R_LockSurfaceScene( viewDef_t *parms ) {
247 drawSurfsCommand_t *cmd;
248 viewEntity_t *vModel;
250 // set the matrix for world space to eye space
251 R_SetViewMatrix( parms );
252 tr.lockSurfacesCmd.viewDef->worldSpace = parms->worldSpace;
254 // update the view origin and axis, and all
255 // the entity matricies
256 for( vModel = tr.lockSurfacesCmd.viewDef->viewEntitys ; vModel ; vModel = vModel->next ) {
257 myGlMultMatrix( vModel->modelMatrix,
258 tr.lockSurfacesCmd.viewDef->worldSpace.modelViewMatrix,
259 vModel->modelViewMatrix );
262 // add the stored off surface commands again
263 cmd = (drawSurfsCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
264 *cmd = tr.lockSurfacesCmd;
271 See if some cvars that we watch have changed
274 static void R_CheckCvars( void ) {
275 globalImages->CheckCvars();
278 if ( r_gamma.IsModified() || r_brightness.IsModified() ) {
279 r_gamma.ClearModified();
280 r_brightness.ClearModified();
281 R_SetColorMappings();
284 // check for changes to logging state
285 GLimp_EnableLogging( r_logFile.GetInteger() != 0 );
290 idRenderSystemLocal::idRenderSystemLocal
293 idRenderSystemLocal::idRenderSystemLocal( void ) {
299 idRenderSystemLocal::~idRenderSystemLocal
302 idRenderSystemLocal::~idRenderSystemLocal( void ) {
309 This can be used to pass general information to the current material, not
313 void idRenderSystemLocal::SetColor( const idVec4 &rgba ) {
314 guiModel->SetColor( rgba[0], rgba[1], rgba[2], rgba[3] );
323 void idRenderSystemLocal::SetColor4( float r, float g, float b, float a ) {
324 guiModel->SetColor( r, g, b, a );
332 void idRenderSystemLocal::DrawStretchPic( const idDrawVert *verts, const glIndex_t *indexes, int vertCount, int indexCount, const idMaterial *material,
333 bool clip, float min_x, float min_y, float max_x, float max_y ) {
334 guiModel->DrawStretchPic( verts, indexes, vertCount, indexCount, material,
335 clip, min_x, min_y, max_x, max_y );
342 x/y/w/h are in the 0,0 to 640,480 range
345 void idRenderSystemLocal::DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *material ) {
346 guiModel->DrawStretchPic( x, y, w, h, s1, t1, s2, t2, material );
353 x/y/w/h are in the 0,0 to 640,480 range
356 void idRenderSystemLocal::DrawStretchTri( idVec2 p1, idVec2 p2, idVec2 p3, idVec2 t1, idVec2 t2, idVec2 t3, const idMaterial *material ) {
357 tr.guiModel->DrawStretchTri( p1, p2, p3, t1, t2, t3, material );
362 GlobalToNormalizedDeviceCoordinates
365 void idRenderSystemLocal::GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ) {
366 R_GlobalToNormalizedDeviceCoordinates( global, ndc );
371 GlobalToNormalizedDeviceCoordinates
374 void idRenderSystemLocal::GetGLSettings( int& width, int& height ) {
375 width = glConfig.vidWidth;
376 height = glConfig.vidHeight;
380 =====================
381 idRenderSystemLocal::DrawSmallChar
383 small chars are drawn at native screen resolution
384 =====================
386 void idRenderSystemLocal::DrawSmallChar( int x, int y, int ch, const idMaterial *material ) {
397 if ( y < -SMALLCHAR_HEIGHT ) {
404 frow = row * 0.0625f;
405 fcol = col * 0.0625f;
408 DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT,
410 fcol + size, frow + size,
416 idRenderSystemLocal::DrawSmallString[Color]
418 Draws a multi-colored string with a drop shadow, optionally forcing
421 Coordinates are at 640 by 480 virtual resolution
424 void idRenderSystemLocal::DrawSmallStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ) {
426 const unsigned char *s;
429 // draw the colored text
430 s = (const unsigned char*)string;
432 SetColor( setColor );
434 if ( idStr::IsColor( (const char*)s ) ) {
436 if ( *(s+1) == C_COLOR_DEFAULT ) {
437 SetColor( setColor );
439 color = idStr::ColorForIndex( *(s+1) );
440 color[3] = setColor[3];
447 DrawSmallChar( xx, y, *s, material );
448 xx += SMALLCHAR_WIDTH;
451 SetColor( colorWhite );
455 =====================
456 idRenderSystemLocal::DrawBigChar
457 =====================
459 void idRenderSystemLocal::DrawBigChar( int x, int y, int ch, const idMaterial *material ) {
470 if ( y < -BIGCHAR_HEIGHT ) {
477 frow = row * 0.0625f;
478 fcol = col * 0.0625f;
481 DrawStretchPic( x, y, BIGCHAR_WIDTH, BIGCHAR_HEIGHT,
483 fcol + size, frow + size,
489 idRenderSystemLocal::DrawBigString[Color]
491 Draws a multi-colored string with a drop shadow, optionally forcing
494 Coordinates are at 640 by 480 virtual resolution
497 void idRenderSystemLocal::DrawBigStringExt( int x, int y, const char *string, const idVec4 &setColor, bool forceColor, const idMaterial *material ) {
502 // draw the colored text
505 SetColor( setColor );
507 if ( idStr::IsColor( s ) ) {
509 if ( *(s+1) == C_COLOR_DEFAULT ) {
510 SetColor( setColor );
512 color = idStr::ColorForIndex( *(s+1) );
513 color[3] = setColor[3];
520 DrawBigChar( xx, y, *s, material );
524 SetColor( colorWhite );
527 //======================================================================================
533 Check for changes in the back end renderSystem, possibly invalidating cached data
536 void idRenderSystemLocal::SetBackEndRenderer() {
537 if ( !r_renderer.IsModified() ) {
541 bool oldVPstate = backEndRendererHasVertexPrograms;
543 backEndRenderer = BE_BAD;
545 if ( idStr::Icmp( r_renderer.GetString(), "arb" ) == 0 ) {
546 backEndRenderer = BE_ARB;
547 } else if ( idStr::Icmp( r_renderer.GetString(), "arb2" ) == 0 ) {
548 if ( glConfig.allowARB2Path ) {
549 backEndRenderer = BE_ARB2;
551 } else if ( idStr::Icmp( r_renderer.GetString(), "nv10" ) == 0 ) {
552 if ( glConfig.allowNV10Path ) {
553 backEndRenderer = BE_NV10;
555 } else if ( idStr::Icmp( r_renderer.GetString(), "nv20" ) == 0 ) {
556 if ( glConfig.allowNV20Path ) {
557 backEndRenderer = BE_NV20;
559 } else if ( idStr::Icmp( r_renderer.GetString(), "r200" ) == 0 ) {
560 if ( glConfig.allowR200Path ) {
561 backEndRenderer = BE_R200;
566 if ( backEndRenderer == BE_BAD ) {
568 if ( glConfig.allowARB2Path ) {
569 backEndRenderer = BE_ARB2;
570 } else if ( glConfig.allowR200Path ) {
571 backEndRenderer = BE_R200;
572 } else if ( glConfig.allowNV20Path ) {
573 backEndRenderer = BE_NV20;
574 } else if ( glConfig.allowNV10Path ) {
575 backEndRenderer = BE_NV10;
577 // the others are considered experimental
578 backEndRenderer = BE_ARB;
582 backEndRendererHasVertexPrograms = false;
583 backEndRendererMaxLight = 1.0;
585 switch( backEndRenderer ) {
587 common->Printf( "using ARB renderSystem\n" );
590 common->Printf( "using NV10 renderSystem\n" );
593 common->Printf( "using NV20 renderSystem\n" );
594 backEndRendererHasVertexPrograms = true;
597 common->Printf( "using R200 renderSystem\n" );
598 backEndRendererHasVertexPrograms = true;
601 common->Printf( "using ARB2 renderSystem\n" );
602 backEndRendererHasVertexPrograms = true;
603 backEndRendererMaxLight = 999;
606 common->FatalError( "SetbackEndRenderer: bad back end" );
609 // clear the vertex cache if we are changing between
610 // using vertex programs and not, because specular and
611 // shadows will be different data
612 if ( oldVPstate != backEndRendererHasVertexPrograms ) {
613 vertexCache.PurgeAll();
614 if ( primaryWorld ) {
615 primaryWorld->FreeInteractions();
619 r_renderer.ClearModified();
627 void idRenderSystemLocal::BeginFrame( int windowWidth, int windowHeight ) {
628 setBufferCommand_t *cmd;
630 if ( !glConfig.isInitialized ) {
634 // determine which back end we will use
635 SetBackEndRenderer();
639 // for the larger-than-window tiled rendering screenshots
640 if ( tiledViewport[0] ) {
641 windowWidth = tiledViewport[0];
642 windowHeight = tiledViewport[1];
645 glConfig.vidWidth = windowWidth;
646 glConfig.vidHeight = windowHeight;
648 renderCrops[0].x = 0;
649 renderCrops[0].y = 0;
650 renderCrops[0].width = windowWidth;
651 renderCrops[0].height = windowHeight;
652 currentRenderCrop = 0;
654 // screenFraction is just for quickly testing fill rate limitations
655 if ( r_screenFraction.GetInteger() != 100 ) {
656 int w = SCREEN_WIDTH * r_screenFraction.GetInteger() / 100.0f;
657 int h = SCREEN_HEIGHT * r_screenFraction.GetInteger() / 100.0f;
658 CropRenderSize( w, h );
662 // this is the ONLY place this is modified
665 // just in case we did a common->Error while this
667 guiRecursionLevel = 0;
669 // the first rendering will be used for commands like
670 // screenshot, rather than a possible subsequent remote
672 // primaryWorld = NULL;
674 // set the time for shader effects in 2D rendering
675 frameShaderTime = eventLoop->Milliseconds() * 0.001;
680 cmd = (setBufferCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
681 cmd->commandId = RC_SET_BUFFER;
682 cmd->frameCount = frameCount;
684 if ( r_frontBuffer.GetBool() ) {
685 cmd->buffer = (int)GL_FRONT;
687 cmd->buffer = (int)GL_BACK;
691 void idRenderSystemLocal::WriteDemoPics() {
692 session->writeDemo->WriteInt( DS_RENDER );
693 session->writeDemo->WriteInt( DC_GUI_MODEL );
694 guiModel->WriteToDemo( session->writeDemo );
697 void idRenderSystemLocal::DrawDemoPics() {
698 demoGuiModel->EmitFullScreen();
705 Returns the number of msec spent in the back end
708 void idRenderSystemLocal::EndFrame( int *frontEndMsec, int *backEndMsec ) {
711 if ( !glConfig.isInitialized ) {
715 // close any gui drawing
716 guiModel->EmitFullScreen();
719 // save out timing information
720 if ( frontEndMsec ) {
721 *frontEndMsec = pc.frontEndMsec;
724 *backEndMsec = backEnd.pc.msec;
727 // print any other statistics and clear all of them
728 R_PerformanceCounters();
730 // check for dynamic changes that require some initialization
736 // add the swapbuffers command
737 cmd = (emptyCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
738 cmd->commandId = RC_SWAP_BUFFERS;
740 // start the back end up again with the new command list
741 R_IssueRenderCommands();
743 // use the other buffers next frame, because another CPU
744 // may still be rendering into the current buffers
747 // we can now release the vertexes used this frame
748 vertexCache.EndFrame();
750 if ( session->writeDemo ) {
751 session->writeDemo->WriteInt( DS_RENDER );
752 session->writeDemo->WriteInt( DC_END_FRAME );
753 if ( r_showDemo.GetBool() ) {
754 common->Printf( "write DC_END_FRAME\n" );
761 =====================
764 Converts from SCREEN_WIDTH / SCREEN_HEIGHT coordinates to current cropped pixel coordinates
765 =====================
767 void idRenderSystemLocal::RenderViewToViewport( const renderView_t *renderView, idScreenRect *viewport ) {
768 renderCrop_t *rc = &renderCrops[currentRenderCrop];
770 float wRatio = (float)rc->width / SCREEN_WIDTH;
771 float hRatio = (float)rc->height / SCREEN_HEIGHT;
773 viewport->x1 = idMath::Ftoi( rc->x + renderView->x * wRatio );
774 viewport->x2 = idMath::Ftoi( rc->x + floor( ( renderView->x + renderView->width ) * wRatio + 0.5f ) - 1 );
775 viewport->y1 = idMath::Ftoi( ( rc->y + rc->height ) - floor( ( renderView->y + renderView->height ) * hRatio + 0.5f ) );
776 viewport->y2 = idMath::Ftoi( ( rc->y + rc->height ) - floor( renderView->y * hRatio + 0.5f ) - 1 );
779 static int RoundDownToPowerOfTwo( int v ) {
782 for ( i = 0 ; i < 20 ; i++ ) {
783 if ( ( 1 << i ) == v ) {
786 if ( ( 1 << i ) > v ) {
797 This automatically halves sizes until it fits in the current window size,
798 so if you specify a power of two size for a texture copy, it may be shrunk
799 down, but still valid.
802 void idRenderSystemLocal::CropRenderSize( int width, int height, bool makePowerOfTwo, bool forceDimensions ) {
803 if ( !glConfig.isInitialized ) {
807 // close any gui drawing before changing the size
808 guiModel->EmitFullScreen();
811 if ( width < 1 || height < 1 ) {
812 common->Error( "CropRenderSize: bad sizes" );
815 if ( session->writeDemo ) {
816 session->writeDemo->WriteInt( DS_RENDER );
817 session->writeDemo->WriteInt( DC_CROP_RENDER );
818 session->writeDemo->WriteInt( width );
819 session->writeDemo->WriteInt( height );
820 session->writeDemo->WriteInt( makePowerOfTwo );
822 if ( r_showDemo.GetBool() ) {
823 common->Printf( "write DC_CROP_RENDER\n" );
827 // convert from virtual SCREEN_WIDTH/SCREEN_HEIGHT coordinates to physical OpenGL pixels
828 renderView_t renderView;
831 renderView.width = width;
832 renderView.height = height;
835 RenderViewToViewport( &renderView, &r );
837 width = r.x2 - r.x1 + 1;
838 height = r.y2 - r.y1 + 1;
840 if ( forceDimensions ) {
841 // just give exactly what we ask for
842 width = renderView.width;
843 height = renderView.height;
846 // if makePowerOfTwo, drop to next lower power of two after scaling to physical pixels
847 if ( makePowerOfTwo ) {
848 width = RoundDownToPowerOfTwo( width );
849 height = RoundDownToPowerOfTwo( height );
850 // FIXME: megascreenshots with offset viewports don't work right with this yet
853 renderCrop_t *rc = &renderCrops[currentRenderCrop];
855 // we might want to clip these to the crop window instead
856 while ( width > glConfig.vidWidth ) {
859 while ( height > glConfig.vidHeight ) {
863 if ( currentRenderCrop == MAX_RENDER_CROPS ) {
864 common->Error( "idRenderSystemLocal::CropRenderSize: currentRenderCrop == MAX_RENDER_CROPS" );
869 rc = &renderCrops[currentRenderCrop];
882 void idRenderSystemLocal::UnCrop() {
883 if ( !glConfig.isInitialized ) {
887 if ( currentRenderCrop < 1 ) {
888 common->Error( "idRenderSystemLocal::UnCrop: currentRenderCrop < 1" );
891 // close any gui drawing
892 guiModel->EmitFullScreen();
897 if ( session->writeDemo ) {
898 session->writeDemo->WriteInt( DS_RENDER );
899 session->writeDemo->WriteInt( DC_UNCROP_RENDER );
901 if ( r_showDemo.GetBool() ) {
902 common->Printf( "write DC_UNCROP\n" );
912 void idRenderSystemLocal::CaptureRenderToImage( const char *imageName ) {
913 if ( !glConfig.isInitialized ) {
916 guiModel->EmitFullScreen();
919 if ( session->writeDemo ) {
920 session->writeDemo->WriteInt( DS_RENDER );
921 session->writeDemo->WriteInt( DC_CAPTURE_RENDER );
922 session->writeDemo->WriteHashString( imageName );
924 if ( r_showDemo.GetBool() ) {
925 common->Printf( "write DC_CAPTURE_RENDER: %s\n", imageName );
929 // look up the image before we create the render command, because it
930 // may need to sync to create the image
931 idImage *image = globalImages->ImageFromFile(imageName, TF_DEFAULT, true, TR_REPEAT, TD_DEFAULT);
933 renderCrop_t *rc = &renderCrops[currentRenderCrop];
935 copyRenderCommand_t *cmd = (copyRenderCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) );
936 cmd->commandId = RC_COPY_RENDER;
939 cmd->imageWidth = rc->width;
940 cmd->imageHeight = rc->height;
952 void idRenderSystemLocal::CaptureRenderToFile( const char *fileName, bool fixAlpha ) {
953 if ( !glConfig.isInitialized ) {
957 renderCrop_t *rc = &renderCrops[currentRenderCrop];
959 guiModel->EmitFullScreen();
961 R_IssueRenderCommands();
963 qglReadBuffer( GL_BACK );
965 // include extra space for OpenGL padding to word boundaries
966 int c = ( rc->width + 3 ) * rc->height;
967 byte *data = (byte *)R_StaticAlloc( c * 3 );
969 qglReadPixels( rc->x, rc->y, rc->width, rc->height, GL_RGB, GL_UNSIGNED_BYTE, data );
971 byte *data2 = (byte *)R_StaticAlloc( c * 4 );
973 for ( int i = 0 ; i < c ; i++ ) {
974 data2[ i * 4 ] = data[ i * 3 ];
975 data2[ i * 4 + 1 ] = data[ i * 3 + 1 ];
976 data2[ i * 4 + 2 ] = data[ i * 3 + 2 ];
977 data2[ i * 4 + 3 ] = 0xff;
980 R_WriteTGA( fileName, data2, rc->width, rc->height, true );
982 R_StaticFree( data );
983 R_StaticFree( data2 );
992 idRenderWorld *idRenderSystemLocal::AllocRenderWorld() {
993 idRenderWorldLocal *rw;
994 rw = new idRenderWorldLocal;
1004 void idRenderSystemLocal::FreeRenderWorld( idRenderWorld *rw ) {
1005 if ( primaryWorld == rw ) {
1006 primaryWorld = NULL;
1008 worlds.Remove( static_cast<idRenderWorldLocal *>(rw) );
1017 void idRenderSystemLocal::PrintMemInfo( MemInfo_t *mi ) {
1018 // sum up image totals
1019 globalImages->PrintMemInfo( mi );
1021 // sum up model totals
1022 renderModelManager->PrintMemInfo( mi );
1024 // compute render totals
1030 idRenderSystemLocal::UploadImage
1033 bool idRenderSystemLocal::UploadImage( const char *imageName, const byte *data, int width, int height ) {
1034 idImage *image = globalImages->GetImage( imageName );
1038 image->UploadScratch( data, width, height );
1039 image->SetImageFilterAndRepeat();