/* ================ idRenderSystemLocal::CaptureRenderToImage ================ */ void idRenderSystemLocal::CaptureRenderToImage( const char *imageName, bool clearColorAfterCopy ) { if ( !R_IsInitialized() ) { return; } guiModel->EmitFullScreen(); guiModel->Clear(); if ( common->WriteDemo() ) { common->WriteDemo()->WriteInt( DS_RENDER ); common->WriteDemo()->WriteInt( DC_CAPTURE_RENDER ); common->WriteDemo()->WriteHashString( imageName ); if ( r_showDemo.GetBool() ) { common->Printf( "write DC_CAPTURE_RENDER: %s\n", imageName ); } } idImage * image = globalImages->GetImage( imageName ); if ( image == NULL ) { image = globalImages->AllocImage( imageName ); } idScreenRect & rc = renderCrops[currentRenderCrop]; copyRenderCommand_t *cmd = (copyRenderCommand_t *)R_GetCommandBuffer( sizeof( *cmd ) ); cmd->commandId = RC_COPY_RENDER; cmd->x = rc.x1; cmd->y = rc.y1; cmd->imageWidth = rc.GetWidth(); cmd->imageHeight = rc.GetHeight(); cmd->image = image; cmd->clearColorAfterCopy = clearColorAfterCopy; guiModel->Clear(); }
/* ================ idRenderSystemLocal::UnCrop ================ */ void idRenderSystemLocal::UnCrop() { if( !R_IsInitialized() ) { return; } if( currentRenderCrop < 1 ) { common->Error( "idRenderSystemLocal::UnCrop: currentRenderCrop < 1" ); } // close any gui drawing guiModel->EmitFullScreen(); guiModel->Clear(); currentRenderCrop--; if( common->WriteDemo() ) { common->WriteDemo()->WriteInt( DS_RENDER ); common->WriteDemo()->WriteInt( DC_UNCROP_RENDER ); if( r_showDemo.GetBool() ) { common->Printf( "write DC_UNCROP\n" ); } } }
/* ===================== idRenderSystemLocal::SwapCommandBuffers_FinishRendering ===================== */ void idRenderSystemLocal::SwapCommandBuffers_FinishRendering( uint64 * frontEndMicroSec, uint64 * backEndMicroSec, uint64 * shadowMicroSec, uint64 * gpuMicroSec ) { SCOPED_PROFILE_EVENT( "SwapCommandBuffers" ); if ( gpuMicroSec != NULL ) { *gpuMicroSec = 0; // until shown otherwise } if ( !R_IsInitialized() ) { return; } // After coming back from an autoswap, we won't have anything to render if ( frameData->cmdHead->next != NULL ) { // wait for our fence to hit, which means the swap has actually happened // We must do this before clearing any resources the GPU may be using void GL_BlockingSwapBuffers(); GL_BlockingSwapBuffers(); } // read back the start and end timer queries from the previous frame if ( glConfig.timerQueryAvailable ) { uint64 drawingTimeNanoseconds = 0; if ( tr.timerQueryId != 0 ) { qglGetQueryObjectui64vEXT( tr.timerQueryId, GL_QUERY_RESULT, &drawingTimeNanoseconds ); } if ( gpuMicroSec != NULL ) { *gpuMicroSec = drawingTimeNanoseconds / 1000; } } //------------------------------ // save out timing information if ( frontEndMicroSec != NULL ) { *frontEndMicroSec = pc.frontEndMicroSec; } if ( backEndMicroSec != NULL ) { *backEndMicroSec = backEnd.pc.totalMicroSec; } if ( shadowMicroSec != NULL ) { *shadowMicroSec = backEnd.pc.shadowMicroSec; } // 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(); }
void idRenderSystemLocal::DrawStretchPic( const idVec4& topLeft, const idVec4& topRight, const idVec4& bottomRight, const idVec4& bottomLeft, const idMaterial* material ) { if( !R_IsInitialized() ) { return; } if( material == NULL ) { return; } idDrawVert* verts = guiModel->AllocTris( 4, quadPicIndexes, 6, material, currentGLState, STEREO_DEPTH_TYPE_NONE ); if( verts == NULL ) { return; } ALIGNTYPE16 idDrawVert localVerts[4]; localVerts[0].Clear(); localVerts[0].xyz[0] = topLeft.x; localVerts[0].xyz[1] = topLeft.y; localVerts[0].SetTexCoord( topLeft.z, topLeft.w ); localVerts[0].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[0].ClearColor2(); localVerts[1].Clear(); localVerts[1].xyz[0] = topRight.x; localVerts[1].xyz[1] = topRight.y; localVerts[1].SetTexCoord( topRight.z, topRight.w ); localVerts[1].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[1].ClearColor2(); localVerts[2].Clear(); localVerts[2].xyz[0] = bottomRight.x; localVerts[2].xyz[1] = bottomRight.y; localVerts[2].SetTexCoord( bottomRight.z, bottomRight.w ); localVerts[2].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[2].ClearColor2(); localVerts[3].Clear(); localVerts[3].xyz[0] = bottomLeft.x; localVerts[3].xyz[1] = bottomLeft.y; localVerts[3].SetTexCoord( bottomLeft.z, bottomLeft.w ); localVerts[3].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[3].ClearColor2(); WriteDrawVerts16( verts, localVerts, 4 ); }
/* ============= idRenderSystemLocal::DrawStretchTri ============= */ void idRenderSystemLocal::DrawStretchTri( const idVec2& p1, const idVec2& p2, const idVec2& p3, const idVec2& t1, const idVec2& t2, const idVec2& t3, const idMaterial* material ) { if( !R_IsInitialized() ) { return; } if( material == NULL ) { return; } triIndex_t tempIndexes[3] = { 1, 0, 2 }; idDrawVert* verts = guiModel->AllocTris( 3, tempIndexes, 3, material, currentGLState, STEREO_DEPTH_TYPE_NONE ); if( verts == NULL ) { return; } ALIGNTYPE16 idDrawVert localVerts[3]; localVerts[0].Clear(); localVerts[0].xyz[0] = p1.x; localVerts[0].xyz[1] = p1.y; localVerts[0].SetTexCoord( t1 ); localVerts[0].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[0].ClearColor2(); localVerts[1].Clear(); localVerts[1].xyz[0] = p2.x; localVerts[1].xyz[1] = p2.y; localVerts[1].SetTexCoord( t2 ); localVerts[1].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[1].ClearColor2(); localVerts[2].Clear(); localVerts[2].xyz[0] = p3.x; localVerts[2].xyz[1] = p3.y; localVerts[2].SetTexCoord( t3 ); localVerts[2].SetNativeOrderColor( currentColorNativeBytesOrder ); localVerts[2].ClearColor2(); WriteDrawVerts16( verts, localVerts, 3 ); }
/* ============= SetColor ============= */ void idGuiModel::SetColor( float r, float g, float b, float a ) { if ( !R_IsInitialized() ) { return; } if ( r == surf->color[0] && g == surf->color[1] && b == surf->color[2] && a == surf->color[3] ) { return; // no change } if ( surf->numVerts ) { AdvanceSurf(); } // change the parms surf->color[0] = r; surf->color[1] = g; surf->color[2] = b; surf->color[3] = a; }
/* ================ idRenderSystemLocal::CropRenderSize ================ */ void idRenderSystemLocal::CropRenderSize( int width, int height ) { if( !R_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( common->WriteDemo() ) { common->WriteDemo()->WriteInt( DS_RENDER ); common->WriteDemo()->WriteInt( DC_CROP_RENDER ); common->WriteDemo()->WriteInt( width ); common->WriteDemo()->WriteInt( height ); if( r_showDemo.GetBool() ) { common->Printf( "write DC_CROP_RENDER\n" ); } } idScreenRect& previous = renderCrops[currentRenderCrop]; currentRenderCrop++; idScreenRect& current = renderCrops[currentRenderCrop]; current.x1 = previous.x1; current.x2 = previous.x1 + width - 1; current.y1 = previous.y2 - height + 1; current.y2 = previous.y2; }
/* ============== idRenderSystemLocal::CaptureRenderToFile ============== */ void idRenderSystemLocal::CaptureRenderToFile( const char *fileName, bool fixAlpha ) { if ( !R_IsInitialized() ) { return; } idScreenRect & rc = renderCrops[currentRenderCrop]; guiModel->EmitFullScreen(); guiModel->Clear(); RenderCommandBuffers( frameData->cmdHead ); if ( !vr->useFBO ) // koz { glReadBuffer( GL_BACK ); } // include extra space for OpenGL padding to word boundaries int c = ( rc.GetWidth() + 3 ) * rc.GetHeight(); byte *data = (byte *)R_StaticAlloc( c * 3 ); qglReadPixels( rc.x1, rc.y1, rc.GetWidth(), rc.GetHeight(), 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.GetWidth(), rc.GetHeight(), true ); R_StaticFree( data ); R_StaticFree( data2 ); }
/* ======================== idImage::AllocImage Every image will pass through this function. Allocates all the necessary MipMap levels for the Image, but doesn't put anything in them. This should not be done during normal game-play, if you can avoid it. ======================== */ void idImage::AllocImage() { GL_CheckErrors(); PurgeImage(); switch ( opts.format ) { case FMT_RGBA8: internalFormat = GL_RGBA8; dataFormat = GL_RGBA; dataType = GL_UNSIGNED_BYTE; break; case FMT_XRGB8: internalFormat = GL_RGB; dataFormat = GL_RGBA; dataType = GL_UNSIGNED_BYTE; break; case FMT_RGB565: internalFormat = GL_RGB; dataFormat = GL_RGB; dataType = GL_UNSIGNED_SHORT_5_6_5; break; case FMT_ALPHA: #if defined( USE_CORE_PROFILE ) internalFormat = GL_R8; dataFormat = GL_RED; #else internalFormat = GL_ALPHA8; dataFormat = GL_ALPHA; #endif dataType = GL_UNSIGNED_BYTE; break; case FMT_L8A8: #if defined( USE_CORE_PROFILE ) internalFormat = GL_RG8; dataFormat = GL_RG; #else internalFormat = GL_LUMINANCE8_ALPHA8; dataFormat = GL_LUMINANCE_ALPHA; #endif dataType = GL_UNSIGNED_BYTE; break; case FMT_LUM8: #if defined( USE_CORE_PROFILE ) internalFormat = GL_R8; dataFormat = GL_RED; #else internalFormat = GL_LUMINANCE8; dataFormat = GL_LUMINANCE; #endif dataType = GL_UNSIGNED_BYTE; break; case FMT_INT8: #if defined( USE_CORE_PROFILE ) internalFormat = GL_R8; dataFormat = GL_RED; #else internalFormat = GL_INTENSITY8; dataFormat = GL_LUMINANCE; #endif dataType = GL_UNSIGNED_BYTE; break; case FMT_DXT1: internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; dataFormat = GL_RGBA; dataType = GL_UNSIGNED_BYTE; break; case FMT_DXT5: internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; dataFormat = GL_RGBA; dataType = GL_UNSIGNED_BYTE; break; case FMT_DEPTH: internalFormat = GL_DEPTH_COMPONENT; dataFormat = GL_DEPTH_COMPONENT; dataType = GL_UNSIGNED_BYTE; break; case FMT_X16: internalFormat = GL_INTENSITY16; dataFormat = GL_LUMINANCE; dataType = GL_UNSIGNED_SHORT; break; case FMT_Y16_X16: internalFormat = GL_LUMINANCE16_ALPHA16; dataFormat = GL_LUMINANCE_ALPHA; dataType = GL_UNSIGNED_SHORT; break; default: idLib::Error( "Unhandled image format %d in %s\n", opts.format, GetName() ); } // if we don't have a rendering context, just return after we // have filled in the parms. We must have the values set, or // an image match from a shader before OpenGL starts would miss // the generated texture if ( !R_IsInitialized() ) { return; } // generate the texture number qglGenTextures( 1, (GLuint *)&texnum ); assert( texnum != TEXTURE_NOT_LOADED ); //---------------------------------------------------- // allocate all the mip levels with NULL data //---------------------------------------------------- int numSides; int target; int uploadTarget; if ( opts.textureType == TT_2D ) { target = uploadTarget = GL_TEXTURE_2D; numSides = 1; } else if ( opts.textureType == TT_CUBIC ) { target = GL_TEXTURE_CUBE_MAP_EXT; uploadTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT; numSides = 6; } else { assert( !"opts.textureType" ); target = uploadTarget = GL_TEXTURE_2D; numSides = 1; } qglBindTexture( target, texnum ); for ( int side = 0; side < numSides; side++ ) { int w = opts.width; int h = opts.height; if ( opts.textureType == TT_CUBIC ) { h = w; } for ( int level = 0; level < opts.numLevels; level++ ) { // clear out any previous error GL_CheckErrors(); if ( IsCompressed() ) { int compressedSize = ( ((w+3)/4) * ((h+3)/4) * int64( 16 ) * BitsForFormat( opts.format ) ) / 8; // Even though the OpenGL specification allows the 'data' pointer to be NULL, for some // drivers we actually need to upload data to get it to allocate the texture. // However, on 32-bit systems we may fail to allocate a large block of memory for large // textures. We handle this case by using HeapAlloc directly and allowing the allocation // to fail in which case we simply pass down NULL to glCompressedTexImage2D and hope for the best. // As of 2011-10-6 using NVIDIA hardware and drivers we have to allocate the memory with HeapAlloc // with the exact size otherwise large image allocation (for instance for physical page textures) // may fail on Vista 32-bit. void * data = HeapAlloc( GetProcessHeap(), 0, compressedSize ); qglCompressedTexImage2DARB( uploadTarget+side, level, internalFormat, w, h, 0, compressedSize, data ); if ( data != NULL ) { HeapFree( GetProcessHeap(), 0, data ); } } else { qglTexImage2D( uploadTarget + side, level, internalFormat, w, h, 0, dataFormat, dataType, NULL ); } GL_CheckErrors(); w = Max( 1, w >> 1 ); h = Max( 1, h >> 1 ); } } qglTexParameteri( target, GL_TEXTURE_MAX_LEVEL, opts.numLevels - 1 ); // see if we messed anything up GL_CheckErrors(); SetTexParameters(); GL_CheckErrors(); }
/* ===================== idRenderSystemLocal::SwapCommandBuffers_FinishCommandBuffers ===================== */ const emptyCommand_t* idRenderSystemLocal::SwapCommandBuffers_FinishCommandBuffers() { if( !R_IsInitialized() ) { return NULL; } // close any gui drawing guiModel->EmitFullScreen(); guiModel->Clear(); // unmap the buffer objects so they can be used by the GPU vertexCache.BeginBackEnd(); // save off this command buffer const emptyCommand_t* commandBufferHead = frameData->cmdHead; // copy the code-used drawsurfs that were // allocated at the start of the buffer memory to the backEnd referenced locations backEnd.unitSquareSurface = tr.unitSquareSurface_; backEnd.zeroOneCubeSurface = tr.zeroOneCubeSurface_; backEnd.testImageSurface = tr.testImageSurface_; // use the other buffers next frame, because another CPU // may still be rendering into the current buffers R_ToggleSmpFrame(); // possibly change the stereo3D mode // PC if( glConfig.nativeScreenWidth == 1280 && glConfig.nativeScreenHeight == 1470 ) { glConfig.stereo3Dmode = STEREO3D_HDMI_720; } else { glConfig.stereo3Dmode = GetStereoScopicRenderingMode(); } // prepare the new command buffer guiModel->BeginFrame(); //------------------------------ // Make sure that geometry used by code is present in the buffer cache. // These use frame buffer cache (not static) because they may be used during // map loads. // // It is important to do this first, so if the buffers overflow during // scene generation, the basic surfaces needed for drawing the buffers will // always be present. //------------------------------ R_InitDrawSurfFromTri( tr.unitSquareSurface_, *tr.unitSquareTriangles ); R_InitDrawSurfFromTri( tr.zeroOneCubeSurface_, *tr.zeroOneCubeTriangles ); R_InitDrawSurfFromTri( tr.testImageSurface_, *tr.testImageTriangles ); // Reset render crop to be the full screen renderCrops[0].x1 = 0; renderCrops[0].y1 = 0; renderCrops[0].x2 = GetWidth() - 1; renderCrops[0].y2 = GetHeight() - 1; currentRenderCrop = 0; // 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 = Sys_Milliseconds() * 0.001; setBufferCommand_t* cmd2 = ( setBufferCommand_t* )R_GetCommandBuffer( sizeof( *cmd2 ) ); cmd2->commandId = RC_SET_BUFFER; cmd2->buffer = ( int )GL_BACK; // the old command buffer can now be rendered, while the new one can // be built in parallel return commandBufferHead; }
/* ============= DrawStretchTri x/y/w/h are in the 0,0 to 640,480 range ============= */ void idGuiModel::DrawStretchTri( idVec2 p1, idVec2 p2, idVec2 p3, idVec2 t1, idVec2 t2, idVec2 t3, const idMaterial *material ) { idDrawVert tempVerts[3]; glIndex_t tempIndexes[3]; int vertCount = 3; int indexCount = 3; if ( !R_IsInitialized() ) { return; } if ( !material ) { return; } tempIndexes[0] = 1; tempIndexes[1] = 0; tempIndexes[2] = 2; tempVerts[0].xyz[0] = p1.x; tempVerts[0].xyz[1] = p1.y; tempVerts[0].xyz[2] = 0; tempVerts[0].st[0] = t1.x; tempVerts[0].st[1] = t1.y; tempVerts[0].normal[0] = 0; tempVerts[0].normal[1] = 0; tempVerts[0].normal[2] = 1; tempVerts[0].tangents[0][0] = 1; tempVerts[0].tangents[0][1] = 0; tempVerts[0].tangents[0][2] = 0; tempVerts[0].tangents[1][0] = 0; tempVerts[0].tangents[1][1] = 1; tempVerts[0].tangents[1][2] = 0; tempVerts[1].xyz[0] = p2.x; tempVerts[1].xyz[1] = p2.y; tempVerts[1].xyz[2] = 0; tempVerts[1].st[0] = t2.x; tempVerts[1].st[1] = t2.y; tempVerts[1].normal[0] = 0; tempVerts[1].normal[1] = 0; tempVerts[1].normal[2] = 1; tempVerts[1].tangents[0][0] = 1; tempVerts[1].tangents[0][1] = 0; tempVerts[1].tangents[0][2] = 0; tempVerts[1].tangents[1][0] = 0; tempVerts[1].tangents[1][1] = 1; tempVerts[1].tangents[1][2] = 0; tempVerts[2].xyz[0] = p3.x; tempVerts[2].xyz[1] = p3.y; tempVerts[2].xyz[2] = 0; tempVerts[2].st[0] = t3.x; tempVerts[2].st[1] = t3.y; tempVerts[2].normal[0] = 0; tempVerts[2].normal[1] = 0; tempVerts[2].normal[2] = 1; tempVerts[2].tangents[0][0] = 1; tempVerts[2].tangents[0][1] = 0; tempVerts[2].tangents[0][2] = 0; tempVerts[2].tangents[1][0] = 0; tempVerts[2].tangents[1][1] = 1; tempVerts[2].tangents[1][2] = 0; // break the current surface if we are changing to a new material if ( material != surf->material ) { if ( surf->numVerts ) { AdvanceSurf(); } const_cast<idMaterial *>(material)->EnsureNotPurged(); // in case it was a gui item started before a level change surf->material = material; } int numVerts = verts.Num(); int numIndexes = indexes.Num(); verts.AssureSize( numVerts + vertCount ); indexes.AssureSize( numIndexes + indexCount ); surf->numVerts += vertCount; surf->numIndexes += indexCount; for ( int i = 0; i < indexCount; i++ ) { indexes[numIndexes + i] = numVerts + tempIndexes[i] - surf->firstVert; } memcpy( &verts[numVerts], tempVerts, vertCount * sizeof( verts[0] ) ); }
/* ============= DrawStretchPic x/y/w/h are in the 0,0 to 640,480 range ============= */ void idGuiModel::DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, const idMaterial *hShader ) { idDrawVert verts[4]; glIndex_t indexes[6]; if ( !R_IsInitialized() ) { return; } if ( !hShader ) { return; } // clip to edges, because the pic may be going into a guiShader // instead of full screen if ( x < 0 ) { s1 += ( s2 - s1 ) * -x / w; w += x; x = 0; } if ( y < 0 ) { t1 += ( t2 - t1 ) * -y / h; h += y; y = 0; } if ( x + w > 640 ) { s2 -= ( s2 - s1 ) * ( x + w - 640 ) / w; w = 640 - x; } if ( y + h > 480 ) { t2 -= ( t2 - t1 ) * ( y + h - 480 ) / h; h = 480 - y; } if ( w <= 0 || h <= 0 ) { return; // completely clipped away } indexes[0] = 3; indexes[1] = 0; indexes[2] = 2; indexes[3] = 2; indexes[4] = 0; indexes[5] = 1; verts[0].xyz[0] = x; verts[0].xyz[1] = y; verts[0].xyz[2] = 0; verts[0].st[0] = s1; verts[0].st[1] = t1; verts[0].normal[0] = 0; verts[0].normal[1] = 0; verts[0].normal[2] = 1; verts[0].tangents[0][0] = 1; verts[0].tangents[0][1] = 0; verts[0].tangents[0][2] = 0; verts[0].tangents[1][0] = 0; verts[0].tangents[1][1] = 1; verts[0].tangents[1][2] = 0; verts[1].xyz[0] = x + w; verts[1].xyz[1] = y; verts[1].xyz[2] = 0; verts[1].st[0] = s2; verts[1].st[1] = t1; verts[1].normal[0] = 0; verts[1].normal[1] = 0; verts[1].normal[2] = 1; verts[1].tangents[0][0] = 1; verts[1].tangents[0][1] = 0; verts[1].tangents[0][2] = 0; verts[1].tangents[1][0] = 0; verts[1].tangents[1][1] = 1; verts[1].tangents[1][2] = 0; verts[2].xyz[0] = x + w; verts[2].xyz[1] = y + h; verts[2].xyz[2] = 0; verts[2].st[0] = s2; verts[2].st[1] = t2; verts[2].normal[0] = 0; verts[2].normal[1] = 0; verts[2].normal[2] = 1; verts[2].tangents[0][0] = 1; verts[2].tangents[0][1] = 0; verts[2].tangents[0][2] = 0; verts[2].tangents[1][0] = 0; verts[2].tangents[1][1] = 1; verts[2].tangents[1][2] = 0; verts[3].xyz[0] = x; verts[3].xyz[1] = y + h; verts[3].xyz[2] = 0; verts[3].st[0] = s1; verts[3].st[1] = t2; verts[3].normal[0] = 0; verts[3].normal[1] = 0; verts[3].normal[2] = 1; verts[3].tangents[0][0] = 1; verts[3].tangents[0][1] = 0; verts[3].tangents[0][2] = 0; verts[3].tangents[1][0] = 0; verts[3].tangents[1][1] = 1; verts[3].tangents[1][2] = 0; DrawStretchPic( &verts[0], &indexes[0], 4, 6, hShader, false, 0.0f, 0.0f, 640.0f, 480.0f ); }
/* ============= DrawStretchPic ============= */ void idGuiModel::DrawStretchPic( const idDrawVert *dverts, const glIndex_t *dindexes, int vertCount, int indexCount, const idMaterial *hShader, bool clip, float min_x, float min_y, float max_x, float max_y ) { if ( !R_IsInitialized() ) { return; } if ( !( dverts && dindexes && vertCount && indexCount && hShader ) ) { return; } // break the current surface if we are changing to a new material if ( hShader != surf->material ) { if ( surf->numVerts ) { AdvanceSurf(); } const_cast<idMaterial *>(hShader)->EnsureNotPurged(); // in case it was a gui item started before a level change surf->material = hShader; } // add the verts and indexes to the current surface if ( clip ) { int i, j; // FIXME: this is grim stuff, and should be rewritten if we have any significant // number of guis asking for clipping idFixedWinding w; for ( i = 0; i < indexCount; i += 3 ) { w.Clear(); w.AddPoint(idVec5(dverts[dindexes[i]].xyz.x, dverts[dindexes[i]].xyz.y, dverts[dindexes[i]].xyz.z, dverts[dindexes[i]].st.x, dverts[dindexes[i]].st.y)); w.AddPoint(idVec5(dverts[dindexes[i+1]].xyz.x, dverts[dindexes[i+1]].xyz.y, dverts[dindexes[i+1]].xyz.z, dverts[dindexes[i+1]].st.x, dverts[dindexes[i+1]].st.y)); w.AddPoint(idVec5(dverts[dindexes[i+2]].xyz.x, dverts[dindexes[i+2]].xyz.y, dverts[dindexes[i+2]].xyz.z, dverts[dindexes[i+2]].st.x, dverts[dindexes[i+2]].st.y)); for ( j = 0; j < 3; j++ ) { if ( w[j].x < min_x || w[j].x > max_x || w[j].y < min_y || w[j].y > max_y ) { break; } } if ( j < 3 ) { idPlane p; p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = 1.0f; p.SetDist( min_x ); w.ClipInPlace( p ); p.Normal().y = p.Normal().z = 0.0f; p.Normal().x = -1.0f; p.SetDist( -max_x ); w.ClipInPlace( p ); p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = 1.0f; p.SetDist( min_y ); w.ClipInPlace( p ); p.Normal().x = p.Normal().z = 0.0f; p.Normal().y = -1.0f; p.SetDist( -max_y ); w.ClipInPlace( p ); } int numVerts = verts.Num(); verts.SetNum( numVerts + w.GetNumPoints(), false ); for ( j = 0 ; j < w.GetNumPoints() ; j++ ) { idDrawVert *dv = &verts[numVerts+j]; dv->xyz.x = w[j].x; dv->xyz.y = w[j].y; dv->xyz.z = w[j].z; dv->st.x = w[j].s; dv->st.y = w[j].t; dv->normal.Set(0, 0, 1); dv->tangents[0].Set(1, 0, 0); dv->tangents[1].Set(0, 1, 0); } surf->numVerts += w.GetNumPoints(); for ( j = 2; j < w.GetNumPoints(); j++ ) { indexes.Append( numVerts - surf->firstVert ); indexes.Append( numVerts + j - 1 - surf->firstVert ); indexes.Append( numVerts + j - surf->firstVert ); surf->numIndexes += 3; } } } else { int numVerts = verts.Num(); int numIndexes = indexes.Num(); verts.AssureSize( numVerts + vertCount ); indexes.AssureSize( numIndexes + indexCount ); surf->numVerts += vertCount; surf->numIndexes += indexCount; for ( int i = 0; i < indexCount; i++ ) { indexes[numIndexes + i] = numVerts + dindexes[i] - surf->firstVert; } memcpy( &verts[numVerts], dverts, vertCount * sizeof( verts[0] ) ); } }
/* ================= R_LoadARBProgram ================= */ void R_LoadARBProgram( int progIndex ) { int ofs; int err; idStr fullPath = "glprogs/"; fullPath += progs[progIndex].name; char *fileBuffer; char *buffer; char *start = NULL, *end; common->Printf( "%s", fullPath.c_str() ); // load the program even if we don't support it, so // fs_copyfiles can generate cross-platform data dumps fileSystem->ReadFile( fullPath.c_str(), (void **)&fileBuffer, NULL ); if ( !fileBuffer ) { common->Printf( ": File not found\n" ); return; } // copy to stack memory and free buffer = (char *)_alloca( strlen( fileBuffer ) + 1 ); strcpy( buffer, fileBuffer ); fileSystem->FreeFile( fileBuffer ); if ( !R_IsInitialized() ) { return; } // // submit the program string at start to GL // if ( progs[progIndex].ident == 0 ) { // allocate a new identifier for this program progs[progIndex].ident = PROG_USER + progIndex; } // vertex and fragment programs can both be present in a single file, so // scan for the proper header to be the start point, and stamp a 0 in after the end if ( progs[progIndex].target == GL_VERTEX_PROGRAM_ARB ) { if ( !glConfig.ARBVertexProgramAvailable ) { common->Printf( ": GL_VERTEX_PROGRAM_ARB not available\n" ); return; } start = strstr( (char *)buffer, "!!ARBvp" ); } if ( progs[progIndex].target == GL_FRAGMENT_PROGRAM_ARB ) { if ( !glConfig.ARBFragmentProgramAvailable ) { common->Printf( ": GL_FRAGMENT_PROGRAM_ARB not available\n" ); return; } start = strstr( (char *)buffer, "!!ARBfp" ); } if ( !start ) { common->Printf( ": !!ARB not found\n" ); return; } end = strstr( start, "END" ); if ( !end ) { common->Printf( ": END not found\n" ); return; } end[3] = 0; qglBindProgramARB( progs[progIndex].target, progs[progIndex].ident ); qglGetError(); qglProgramStringARB( progs[progIndex].target, GL_PROGRAM_FORMAT_ASCII_ARB, strlen( start ), (unsigned char *)start ); err = qglGetError(); qglGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, (GLint *)&ofs ); if ( err == GL_INVALID_OPERATION ) { const GLubyte *str = qglGetString( GL_PROGRAM_ERROR_STRING_ARB ); common->Printf( "\nGL_PROGRAM_ERROR_STRING_ARB: %s\n", str ); if ( ofs < 0 ) { common->Printf( "GL_PROGRAM_ERROR_POSITION_ARB < 0 with error\n" ); } else if ( ofs >= (int)strlen( (char *)start ) ) { common->Printf( "error at end of program\n" ); } else { common->Printf( "error at %i:\n%s", ofs, start + ofs ); } return; } if ( ofs != -1 ) { common->Printf( "\nGL_PROGRAM_ERROR_POSITION_ARB != -1 without error\n" ); return; } common->Printf( "\n" ); }