/* ============= 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; vec4_t quadVerts[4]; vec2_t texCoords[4]; if ( !tr.registered ) { return; } R_IssuePendingRenderCommands(); // we definately want to sync every frame for the cinematics qglFinish(); start = 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); } RE_UploadCinematic (w, h, cols, rows, data, client, dirty); if ( r_speeds->integer ) { end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); } // FIXME: HUGE hack if (glRefConfig.framebufferObject) { if (!tr.renderFbo || backEnd.framePostProcessed) { FBO_Bind(NULL); } else { FBO_Bind(tr.renderFbo); } } RB_SetGL2D(); VectorSet4(quadVerts[0], x, y, 0.0f, 1.0f); VectorSet4(quadVerts[1], x + w, y, 0.0f, 1.0f); VectorSet4(quadVerts[2], x + w, y + h, 0.0f, 1.0f); VectorSet4(quadVerts[3], x, y + h, 0.0f, 1.0f); VectorSet2(texCoords[0], 0.5f / cols, 0.5f / rows); VectorSet2(texCoords[1], (cols - 0.5f) / cols, 0.5f / rows); VectorSet2(texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows); VectorSet2(texCoords[3], 0.5f / cols, (rows - 0.5f) / rows); GLSL_BindProgram(&tr.textureColorShader); GLSL_SetUniformMatrix16(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); RB_InstantQuad2(quadVerts, texCoords); }
/* ============= RB_StretchPic ============= */ const void *RB_StretchPic ( const void *data ) { const stretchPicCommand_t *cmd; shader_t *shader; int numVerts, numIndexes; cmd = (const stretchPicCommand_t *)data; // FIXME: HUGE hack if (glRefConfig.framebufferObject) { if (!tr.renderFbo || backEnd.framePostProcessed) { FBO_Bind(NULL); } else { FBO_Bind(tr.renderFbo); } } RB_SetGL2D(); shader = cmd->shader; if ( shader != tess.shader ) { if ( tess.numIndexes ) { RB_EndSurface(); } backEnd.currentEntity = &backEnd.entity2D; RB_BeginSurface( shader, 0, 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; { vec4_t color; VectorScale4(backEnd.color2D, 1.0f / 255.0f, color); VectorCopy4(color, tess.vertexColors[ numVerts ]); VectorCopy4(color, tess.vertexColors[ numVerts + 1]); VectorCopy4(color, tess.vertexColors[ numVerts + 2]); VectorCopy4(color, tess.vertexColors[ numVerts + 3 ]); } 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); }
void RB_ColorCorrect( void ) { GLint loc; GLenum target; int width, height; int shift; float mul; if ( !r_enablePostProcess->integer || !r_enableColorCorrect->integer || !glsl ) { return; } GL_SelectTexture(0); qglDisable(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_RECTANGLE_ARB); target = GL_TEXTURE_RECTANGLE_ARB; width = glConfig.vidWidth; height = glConfig.vidHeight; qglBindTexture(target, tr.backBufferTexture); qglCopyTexSubImage2D(target, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); RB_SetGL2D(); GL_State( GLS_DEPTHTEST_DISABLE ); qglUseProgramObjectARB(tr.colorCorrectSp); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_gammaRecip"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_gammaRecip", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)(1.0 / r_gamma->value)); //mul = r_overBrightBitsValue->value; mul = r_overBrightBits->value; if (mul < 0.0) { mul = 0.0; } shift = tr.overbrightBits; loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_overbright"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_overbright", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)((float)(1 << shift) * mul)); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "p_contrast"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get p_contrast", __FUNCTION__); } qglUniform1fARB(loc, (GLfloat)r_contrast->value); loc = qglGetUniformLocationARB(tr.colorCorrectSp, "backBufferTex"); if (loc < 0) { Com_Error(ERR_DROP, "%s() couldn't get backBufferTex", __FUNCTION__); } qglUniform1iARB(loc, 0); qglBegin(GL_QUADS); qglTexCoord2i(0, 0); qglVertex2i(0, height); qglTexCoord2i(width, 0); qglVertex2i(width, height); qglTexCoord2i(width, height); qglVertex2i(width, 0); qglTexCoord2i(0, height); qglVertex2i(0, 0); qglEnd(); qglUseProgramObjectARB(0); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); }
/* ============= RB_StretchPic ============= */ const void *RB_StretchPic ( const void *data ) { const stretchPicCommand_t *cmd; shader_t *shader; int numVerts, numIndexes; cmd = (const stretchPicCommand_t *)data; shader = cmd->shader; if ( shader != tess.shader ) { if ( tess.numIndexes ) { RB_EndSurface(); //this might change culling and other states } backEnd.currentEntity = &backEnd.entity2D; RB_BeginSurface( shader, 0 ); } if ( !backEnd.projection2D ) { RB_SetGL2D(); //set culling and other states } 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); }
/* ============== RenderBumpTriangles ============== */ static void RenderBumpTriangles( srfTriangles_t *lowMesh, renderBump_t *rb ) { int i, j; RB_SetGL2D(); qglDisable( GL_CULL_FACE ); qglColor3f( 1, 1, 1 ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, 1, 1, 0, -1, 1 ); qglDisable( GL_BLEND ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); qglDisable( GL_DEPTH_TEST ); qglClearColor(1,0,0,1); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglColor3f( 1, 1, 1 ); // create smoothed normals for the surface, which might be // different than the normals at the vertexes if the // surface uses unsmoothedNormals, which only takes the // normal from a single triangle. We need properly smoothed // normals to make sure that the traces always go off normal // to the true surface. idVec3 *lowMeshNormals = (idVec3 *)Mem_ClearedAlloc( lowMesh->numVerts * sizeof( *lowMeshNormals ) ); R_DeriveFacePlanes( lowMesh ); R_CreateSilIndexes( lowMesh ); // recreate, merging the mirrored verts back together const idPlane *planes = lowMesh->facePlanes; for ( i = 0 ; i < lowMesh->numIndexes ; i += 3, planes++ ) { for ( j = 0 ; j < 3 ; j++ ) { int index; index = lowMesh->silIndexes[i+j]; lowMeshNormals[index] += (*planes).Normal(); } } // normalize and replicate from silIndexes to all indexes for ( i = 0 ; i < lowMesh->numIndexes ; i++ ) { lowMeshNormals[lowMesh->indexes[i]] = lowMeshNormals[lowMesh->silIndexes[i]]; lowMeshNormals[lowMesh->indexes[i]].Normalize(); } // rasterize each low poly face for ( j = 0 ; j < lowMesh->numIndexes ; j+=3 ) { // pump the event loop so the window can be dragged around Sys_GenerateEvents(); RasterizeTriangle( lowMesh, lowMeshNormals, j/3, rb ); qglClearColor(1,0,0,1); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglRasterPos2f( 0, 1 ); qglPixelZoom( glConfig.vidWidth / (float)rb->width, glConfig.vidHeight / (float)rb->height ); qglDrawPixels( rb->width, rb->height, GL_RGBA, GL_UNSIGNED_BYTE, rb->localPic ); qglPixelZoom( 1, 1 ); qglFlush(); GLimp_SwapBuffers(); } Mem_Free( lowMeshNormals ); }
/* ============= 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_IssuePendingRenderCommands(); // we definately want to sync every frame for the cinematics qglFinish(); start = 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_TO_EDGE ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); } 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 (); }
/* =============== 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; #ifdef PANDORA vec2_t texcoords[4] = { {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} }; vec2_t verts[4]; glIndex_t indicies[6] = { 0, 1, 2, 0, 3, 2 }; #endif if ( !backEnd.projection2D ) { RB_SetGL2D(); } qglClear( GL_COLOR_BUFFER_BIT ); qglFinish(); start = ri.Milliseconds(); #ifdef PANDORA qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); #endif 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; } #ifdef PANDORA verts[0][0] = x; verts[0][1] = y; verts[1][0] = x+w; verts[1][1] = y; verts[2][0] = x+w; verts[2][1] = y+h; verts[3][0] = x; verts[3][1] = y+h; qglTexCoordPointer( 2, GL_FLOAT, 0, texcoords ); qglVertexPointer ( 2, GL_FLOAT, 0, verts ); qglDrawElements( GL_TRIANGLE_STRIP, 6, GL_INDEX_TYPE, indicies ); #else 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(); #endif } #ifdef PANDORA qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); #endif qglFinish(); end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); }
void RB_DrawPolys( const void *data ) { const drawPolysCmd_t *cmd = (drawPolysCmd_t*)data; uint i; uint numVerts, numIndices; float *xy, *st; uint *colors; glIndex_t *indices; uint baseVtx; if( !backEnd.projection2D ) RB_SetGL2D(); numVerts = cmd->numVertsPerPoly * cmd->numPolys; numIndices = cmd->numPolys * (cmd->numVertsPerPoly - 2) * 3; RB_CheckSurface( cmd->shader, 0, GL_TRIANGLES ); RB_CHECKOVERFLOW( numVerts, numIndices ); baseVtx = tess.numVertexes; xy = tess.xyz[baseVtx]; st = tess.texCoords[baseVtx][0]; colors = (uint*)tess.vertexColors + baseVtx; tess.numVertexes = baseVtx + numVerts; for( i = 0; i < numVerts; i++ ) { xy[0] = cmd->verts[i].xy[0]; xy[1] = cmd->verts[i].xy[1]; xy[2] = 0; st[0] = cmd->verts[i].st[0]; st[1] = cmd->verts[i].st[1]; *colors = *(uint*)cmd->verts[i].modulate; xy++; st++; colors++; } indices = tess.indexes + tess.numIndexes; for( i = 0; i < cmd->numPolys; i++ ) { uint j; //emit fan-order indices for( j = 2; j < cmd->numVertsPerPoly; j++ ) { indices[0] = baseVtx; indices[1] = baseVtx + j - 1; indices[2] = baseVtx + j; indices += 3; } baseVtx += cmd->numVertsPerPoly; } tess.numIndexes += numIndices; }
void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) { swapBuffersCommand_t *cmd; float x; float y; float w; float h; GLuint texID; static int b = 0; if ( !tr.registered ) { return; } cmd = R_GetCommandBuffer( sizeof( *cmd ) ); if ( !cmd ) { return; } cmd->commandId = RC_SWAP_BUFFERS; R_IssueRenderCommands( qtrue ); //*** Rift post processing if (vr_warpingShader->integer) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); if (!backEnd.projection2D) { RB_SetGL2D(); } glViewport(0, 0, glConfig.vidWidth, glConfig.vidHeight); // Render on the whole framebuffer, complete from the lower left corner to the upper right // Use our shader glUseProgram(glConfig.oculusProgId); glEnable(GL_TEXTURE_2D); { float VPX = 0.0f; float VPY = 0.0f; float VPW = glConfig.vidWidth; // ViewPort Width float VPH = glConfig.vidHeight; SetupShaderDistortion(0, VPX, VPY, VPW, VPH); // Left Eye } // Set our "renderedTexture" sampler to user Texture Unit 0 texID = glGetUniformLocation(glConfig.oculusProgId, "texid"); glUniform1i(texID, 0); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); // if (stereoFrame == STEREO_LEFT) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, glConfig.oculusRenderTargetLeft); x = 0.0f; y = 0.0f; w = glConfig.vidWidth; h = glConfig.vidHeight; qglBegin (GL_QUADS); qglTexCoord2f( 0, 1 ); qglVertex2f( x, y ); qglTexCoord2f( 1, 1 ); qglVertex2f( x + w/2, y ); qglTexCoord2f( 1, 0 ); qglVertex2f( x + w/2, y + h ); qglTexCoord2f( 0, 0 ); qglVertex2f( x, y + h ); qglEnd(); } //else { { float VPX = 0; float VPY = 0.0f; float VPW = glConfig.vidWidth; // ViewPort Width float VPH = glConfig.vidHeight; SetupShaderDistortion(1, VPX, VPY, VPW, VPH); // Right Eye } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, glConfig.oculusRenderTargetRight); x = glConfig.vidWidth*0.5f; y = 0.0f; w = glConfig.vidWidth; h = glConfig.vidHeight; qglBegin (GL_QUADS); qglTexCoord2f( 0, 1 ); qglVertex2f( x, y ); qglTexCoord2f( 1, 1 ); qglVertex2f( x + w/2, y ); qglTexCoord2f( 1, 0 ); qglVertex2f( x + w/2, y + h ); qglTexCoord2f( 0, 0 ); qglVertex2f( x, y + h ); qglEnd(); } // unbind the GLSL program // this means that from here the OpenGL fixed functionality is used glUseProgram(0); } // use the other buffers next frame, because another CPU // may still be rendering into the current ones R_ToggleSmpFrame(); if ( frontEndMsec ) { *frontEndMsec = tr.frontEndMsec; } tr.frontEndMsec = 0; if ( backEndMsec ) { *backEndMsec = backEnd.pc.msec; } backEnd.pc.msec = 0; }
/* =============== 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 / 40; h = glConfig.vidHeight / 30; x = i % 40 * w; y = i / 30 * h; // show in proportional size in mode 2 if ( r_showImages->integer == 2 ) { w *= image->uploadWidth / 512.0f; h *= image->uploadHeight / 512.0f; } #ifdef USE_OPENGLES GLfloat tex[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; GLfloat vtx[] = { x, y, x + w, y, x + w, y + h, x, y + h }; GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (glcol) qglDisableClientState(GL_COLOR_ARRAY); if (!text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, tex ); qglVertexPointer ( 2, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); if (glcol) qglEnableClientState(GL_COLOR_ARRAY); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); #else 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(); #endif } qglFinish(); end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); }
void RB_GammaScreen(void) { // We force the 2D drawing RB_SetGL2D(); R_ScreenGamma(); }
void R_Splash() { #ifndef _XBOX image_t *pImage; /* const char* s = Cvar_VariableString("se_language"); if (stricmp(s,"english")) { pImage = R_FindImageFile( "menu/splash_eur", qfalse, qfalse, qfalse, GL_CLAMP); } else { pImage = R_FindImageFile( "menu/splash", qfalse, qfalse, qfalse, GL_CLAMP); } */ pImage = R_FindImageFile( "menu/splash", qfalse, qfalse, qfalse, GL_CLAMP); extern void RB_SetGL2D (void); RB_SetGL2D(); if (pImage ) { //invalid paths? GL_Bind( pImage ); } GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO); #ifdef _XBOX int width; if(glw_state->isWidescreen) width = 720; else width = 640; #else const int width = 640; #endif const int height = 480; #ifdef _XBOX float x1, x2; if(glw_state->isWidescreen) { x1 = 360 - width / 2; x2 = 360 + width / 2; } else { x1 = 320 - width / 2; x2 = 320 + width / 2; } #else const float x1 = 320 - width / 2; const float x2 = 320 + width / 2; #endif const float y1 = 240 - height / 2; const float y2 = 240 + height / 2; qglBegin (GL_TRIANGLE_STRIP); qglTexCoord2f( 0, 0 ); qglVertex2f(x1, y1); qglTexCoord2f( 1 , 0 ); qglVertex2f(x2, y1); qglTexCoord2f( 0, 1 ); qglVertex2f(x1, y2); qglTexCoord2f( 1, 1 ); qglVertex2f(x2, y2); qglEnd(); GLimp_EndFrame(); #endif }
/* ============= RB_DrawRotatePic2 ============= */ const void *RB_RotatePic2 ( const void *data ) { const rotatePicCommand_t *cmd; image_t *image; shader_t *shader; cmd = (const rotatePicCommand_t *)data; shader = cmd->shader; if ( shader->numUnfoggedPasses ) { image = &shader->stages[0].bundle[0].image[0]; if ( image ) { if ( !backEnd.projection2D ) { RB_SetGL2D(); } // Get our current blend mode, etc. GL_State( shader->stages[0].stateBits ); qglColor4ubv( backEnd.color2D ); qglPushMatrix(); // rotation point is going to be around the center of the passed in coordinates qglTranslatef( cmd->x, cmd->y, 0 ); qglRotatef( cmd->a, 0.0, 0.0, 1.0 ); GL_Bind( image ); #ifdef _XBOX qglBeginEXT( GL_QUADS, 4, 0, 0, 4, 0); #else qglBegin( GL_QUADS ); #endif qglTexCoord2f( cmd->s1, cmd->t1); qglVertex2f( -cmd->w * 0.5f, -cmd->h * 0.5f ); qglTexCoord2f( cmd->s2, cmd->t1 ); qglVertex2f( cmd->w * 0.5f, -cmd->h * 0.5f ); qglTexCoord2f( cmd->s2, cmd->t2 ); qglVertex2f( cmd->w * 0.5f, cmd->h * 0.5f ); qglTexCoord2f( cmd->s1, cmd->t2 ); qglVertex2f( -cmd->w * 0.5f, cmd->h * 0.5f ); qglEnd(); qglPopMatrix(); // Hmmm, this is not too cool GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); } } return (const void *)(cmd + 1); }
/* ============= RB_RotatedPic ============= */ const void *RB_RotatedPic(const void *data) { const stretchPicCommand_t *cmd = ( const stretchPicCommand_t * ) data; shader_t *shader; int numVerts, numIndexes; float angle; float pi2 = M_PI * 2; 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].v = *( int * ) tess.vertexColors[numVerts + 1].v = *( int * ) tess.vertexColors[numVerts + 2].v = *( int * ) tess.vertexColors[numVerts + 3].v = *( int * ) backEnd.color2D; angle = cmd->angle * pi2; tess.xyz[numVerts].v[0] = cmd->x + (cos(angle) * cmd->w); tess.xyz[numVerts].v[1] = cmd->y + (sin(angle) * cmd->h); tess.xyz[numVerts].v[2] = 0; tess.texCoords0[numVerts].v[0] = cmd->s1; tess.texCoords0[numVerts].v[1] = cmd->t1; angle = cmd->angle * pi2 + 0.25 * pi2; tess.xyz[numVerts + 1].v[0] = cmd->x + (cos(angle) * cmd->w); tess.xyz[numVerts + 1].v[1] = cmd->y + (sin(angle) * cmd->h); tess.xyz[numVerts + 1].v[2] = 0; tess.texCoords0[numVerts + 1].v[0] = cmd->s2; tess.texCoords0[numVerts + 1].v[1] = cmd->t1; angle = cmd->angle * pi2 + 0.50 * pi2; tess.xyz[numVerts + 2].v[0] = cmd->x + (cos(angle) * cmd->w); tess.xyz[numVerts + 2].v[1] = cmd->y + (sin(angle) * cmd->h); tess.xyz[numVerts + 2].v[2] = 0; tess.texCoords0[numVerts + 2].v[0] = cmd->s2; tess.texCoords0[numVerts + 2].v[1] = cmd->t2; angle = cmd->angle * pi2 + 0.75 * pi2; tess.xyz[numVerts + 3].v[0] = cmd->x + (cos(angle) * cmd->w); tess.xyz[numVerts + 3].v[1] = cmd->y + (sin(angle) * cmd->h); tess.xyz[numVerts + 3].v[2] = 0; tess.texCoords0[numVerts + 3].v[0] = cmd->s1; tess.texCoords0[numVerts + 3].v[1] = cmd->t2; return ( const void * ) (cmd + 1); }
/* ============= 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; #ifdef PANDORA vec2_t texcoords[4]; vec2_t verts[4]; glIndex_t indicies[6] = { 0, 1, 2, 0, 3, 2 }; #endif 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; #ifdef PANDORA qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #else qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #endif 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_TO_EDGE ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); } 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(); #ifdef PANDORA glColor4f( tr.identityLight, tr.identityLight, tr.identityLight, 1.0f ); verts[0][0] = x; verts[0][1] = y; verts[1][0] = x+w; verts[1][1] = y; verts[2][0] = x+w; verts[2][1] = y+h; verts[3][0] = x; verts[3][1] = y+h; texcoords[0][0] = 0.5f/cols; texcoords[0][1] = 0.5f/rows; texcoords[1][0] = (cols-0.5f)/cols; texcoords[1][1] = 0.5f/rows; texcoords[2][0] = (cols-0.5f)/cols; texcoords[2][1] = (rows-0.5f)/rows; texcoords[3][0] = 0.5f/cols; texcoords[3][1] = (rows-0.5f)/rows; qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, texcoords ); qglVertexPointer ( 2, GL_FLOAT, 0, verts ); qglDrawElements( GL_TRIANGLE_STRIP, 6, GL_INDEX_TYPE, indicies ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); #else 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 (); #endif }
/* ============== RB_StretchPicGradient ============== */ const void *RB_StretchPicGradient(const void *data) { const stretchPicCommand_t *cmd = ( const stretchPicCommand_t * ) data; shader_t *shader; int numVerts, numIndexes; 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].v = *( int * ) tess.vertexColors[numVerts + 1].v = *( int * ) backEnd.color2D; *( int * ) tess.vertexColors[numVerts + 2].v = *( int * ) tess.vertexColors[numVerts + 3].v = *( int * ) cmd->gradientColor; tess.xyz[numVerts].v[0] = cmd->x; tess.xyz[numVerts].v[1] = cmd->y; tess.xyz[numVerts].v[2] = 0; tess.texCoords0[numVerts].v[0] = cmd->s1; tess.texCoords0[numVerts].v[1] = cmd->t1; tess.xyz[numVerts + 1].v[0] = cmd->x + cmd->w; tess.xyz[numVerts + 1].v[1] = cmd->y; tess.xyz[numVerts + 1].v[2] = 0; tess.texCoords0[numVerts + 1].v[0] = cmd->s2; tess.texCoords0[numVerts + 1].v[1] = cmd->t1; tess.xyz[numVerts + 2].v[0] = cmd->x + cmd->w; tess.xyz[numVerts + 2].v[1] = cmd->y + cmd->h; tess.xyz[numVerts + 2].v[2] = 0; tess.texCoords0[numVerts + 2].v[0] = cmd->s2; tess.texCoords0[numVerts + 2].v[1] = cmd->t2; tess.xyz[numVerts + 3].v[0] = cmd->x; tess.xyz[numVerts + 3].v[1] = cmd->y + cmd->h; tess.xyz[numVerts + 3].v[2] = 0; tess.texCoords0[numVerts + 3].v[0] = cmd->s1; tess.texCoords0[numVerts + 3].v[1] = cmd->t2; return ( const void * ) (cmd + 1); }
static void RB_StretchPic ( const void *data ) { const stretchPicCommand_t *cmd = (const stretchPicCommand_t *)data; int i; shader_t *shader; int numVerts, numIndexes; if( !backEnd.projection2D ) RB_SetGL2D(); shader = cmd->shader; RB_CheckSurface( shader, 0, GL_TRIANGLES ); 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; for( i = 0; i < 4; i++ ) { vec2_t v; Vec2_Cpy( v, tess.xyz[numVerts + i] ); tess.xyz[numVerts + i][0] = v[0] * cmd->mat[0][0] + v[1] * cmd->mat[0][1] + cmd->mat[0][2]; tess.xyz[numVerts + i][1] = v[0] * cmd->mat[1][0] + v[1] * cmd->mat[1][1] + cmd->mat[1][2]; } }