void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { GL_Bind( tr.scratchImage[client] ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; #ifdef VCMODS_OPENGLES 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 ); } } }
bool Gui_SetScreenTexture(void *data, int w, int h, int bpp) { GLenum texture_format; GLuint color_depth; if(bpp == 32) // Contains an alpha channel { texture_format = GL_RGBA; color_depth = GL_RGBA; } else if(bpp == 24) // No alpha channel { texture_format = GL_RGB; color_depth = GL_RGB; } else { return false; } // Bind the texture object qglBindTexture(GL_TEXTURE_2D, load_screen_tex); // Set the texture's stretching properties qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Edit the texture object's image data using the information SDL_Surface gives us qglTexImage2D(GL_TEXTURE_2D, 0, color_depth, w, h, 0, texture_format, GL_UNSIGNED_BYTE, data); qglBindTexture(GL_TEXTURE_2D, 0); return true; }
/* =============== CreateDSTTex_ARB Create the texture which warps texture shaders =============== */ void CreateDSTTex_ARB (void) { unsigned char dist[DST_SIZE][DST_SIZE][4]; int x,y; srand(GetTickCount()); for (x=0; x<DST_SIZE; x++) for (y=0; y<DST_SIZE; y++) { dist[x][y][0] = rand()%255; dist[x][y][1] = rand()%255; dist[x][y][2] = rand()%48; dist[x][y][3] = rand()%48; } qglGenTextures(1,&dst_texture_ARB); qglBindTexture(GL_TEXTURE_2D, dst_texture_ARB); qglTexImage2D (GL_TEXTURE_2D, 0, 4, DST_SIZE, DST_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, dist); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); qglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); }
GLuint CaptureScreenAsTexID(void) { GLuint id; gld_EnableTexture2D(GL_TEXTURE0_ARB, true); qglGenTextures(1, &id); qglBindTexture(GL_TEXTURE_2D, id); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); #ifdef ANDROID qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, #else qglTexImage2D(GL_TEXTURE_2D, 0, 3, #endif gld_GetTexDimension(SCREENWIDTH), gld_GetTexDimension(SCREENHEIGHT), 0, GL_RGB, GL_UNSIGNED_BYTE, 0); qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, SCREENWIDTH, SCREENHEIGHT); return id; }
//void RE_UploadCinematic( int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty ) { const void *RB_UploadCine( const void *data ) { const uploadCine_t *cmd; cmd = (const uploadCine_t *)data; int client = cmd->client; GL_Bind( tr.scratchImage[client] ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cmd->cols != tr.scratchImage[client]->width || cmd->rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cmd->cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = cmd->rows; qglTexImage2D( GL_TEXTURE_2D, 0, 3, cmd->cols, cmd->rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, cmd->data ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); } else { if ( cmd->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, cmd->cols, cmd->rows, GL_RGBA, GL_UNSIGNED_BYTE, cmd->data ); } } return (const void *)( cmd + 1 ); }
void Draw_StretchRaw (int x, int y, int w, int h, int cols, int rows, byte *data) { unsigned image32[256*256]; unsigned char image8[256*256]; int i, j, trows; byte *source; int frac, fracstep; float hscale; int row; float t; memset(image32, 0, sizeof(image32)); // Nicolas - weird colored line fix GL_Bind (0); if (rows<=256) { hscale = 1; trows = rows; } else { hscale = rows/256.0; trows = 256; } t = rows*hscale / 256; if ( !qglColorTableEXT ) { unsigned *dest; for (i=0 ; i<trows ; i++) { row = (int)(i*hscale); if (row > rows) break; source = data + cols*row; dest = &image32[i*256]; fracstep = cols*0x10000/256; frac = fracstep >> 1; for (j=0 ; j<256 ; j++) { dest[j] = r_rawpalette[source[frac>>16]]; frac += fracstep; } } qglTexImage2D (GL_TEXTURE_2D, 0, gl_tex_solid_format, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, image32); }
static int setupScreenKeyboardButton( int buttonID, Uint8 * charBuf ) { // TODO: softstretch with antialiasing int w, h, format; GLTexture_t * data = NULL; int texture_w, texture_h; if( buttonID < 1 ) data = &arrowImages; else data = &(buttonImages[buttonID-1]); memcpy(&w, charBuf, sizeof(int)); memcpy(&h, charBuf + sizeof(int), sizeof(int)); memcpy(&format, charBuf + 2*sizeof(int), sizeof(int)); w = ntohl(w); h = ntohl(h); format = ntohl(format); texture_w = power_of_2(w); texture_h = power_of_2(h); data->w = texture_w; data->h = texture_h; LOGI("data w:%d, h:%d\n", w, h); qglEnable(GL_TEXTURE_2D); qglGenTextures(1, &data->id); qglBindTexture(GL_TEXTURE_2D, data->id); LOGI("On-screen keyboard generated OpenGL texture ID %x", data->id); qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_w, texture_h, 0, GL_RGBA, format ? GL_UNSIGNED_SHORT_4_4_4_4 : GL_UNSIGNED_SHORT_5_5_5_1, NULL); qglPixelStorei(GL_UNPACK_ALIGNMENT, 1); qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, format ? GL_UNSIGNED_SHORT_4_4_4_4 : GL_UNSIGNED_SHORT_5_5_5_1, charBuf + 3*sizeof(int) ); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); qglDisable(GL_TEXTURE_2D); return 3*sizeof(int) + w * h * 2; }
/* =============== CreateDSTTex_NV Create the texture which warps texture shaders =============== */ void CreateDSTTex_NV (void) { char data[DST_SIZE][DST_SIZE][2]; int x,y; for (x=0; x<DST_SIZE; x++) for (y=0; y<DST_SIZE; y++) { data[x][y][0]=rand()%255-128; data[x][y][1]=rand()%255-128; } qglGenTextures(1,&dst_texture_NV); qglBindTexture(GL_TEXTURE_2D, dst_texture_NV); qglTexImage2D(GL_TEXTURE_2D, 0, GL_DSDT8_NV, DST_SIZE, DST_SIZE, 0, GL_DSDT_NV, GL_BYTE, data); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); }
static void gld_RecolorMipLevels(byte *data) { //e6y: development aid to see texture mip usage if (gl_color_mip_levels) { int miplevel = 0; unsigned char *buf = NULL; for (miplevel = 1; miplevel < 16; miplevel++) { int w, h; buf = gld_GetTextureBuffer(0, miplevel, &w, &h); if (w <= 0 || h <= 0) break; gld_BlendOverTexture((byte *)buf, w * h, mipBlendColors[miplevel]); qglTexImage2D( GL_TEXTURE_2D, miplevel, gl_tex_format, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); } } }
void glf_resize(gl_tex_font_p glf, uint16_t font_size) { if((glf != NULL) && (glf->ft_face != NULL)) { const GLint padding = 2; GLubyte *buffer; GLint chars_in_row, chars_in_column; size_t buffer_size; int x, y, xx, yy; int i, ii, i0 = 0; // clear old atlas, if exists if(glf->gl_tex_indexes != NULL) { if(glf->gl_tex_indexes_count > 0) { qglDeleteTextures(glf->gl_tex_indexes_count, glf->gl_tex_indexes); } free(glf->gl_tex_indexes); } glf->gl_tex_indexes = NULL; glf->gl_real_tex_indexes_count = 0; // resize base font glf->font_size = font_size; FT_Set_Char_Size(glf->ft_face, font_size << 6, font_size << 6, 0, 0); // calculate texture atlas size chars_in_row = 1 + sqrt(glf->glyphs_count); glf->gl_tex_width = (font_size + padding) * chars_in_row; glf->gl_tex_width = NextPowerOf2(glf->gl_tex_width); if(glf->gl_tex_width > glf->gl_max_tex_width) { glf->gl_tex_width = glf->gl_max_tex_width; } // create new atlas chars_in_row = glf->gl_tex_width / (font_size + padding); chars_in_column = glf->glyphs_count / chars_in_row + 1; glf->gl_tex_indexes_count = (chars_in_column * (font_size + padding)) / glf->gl_tex_width + 1; glf->gl_tex_indexes = (GLuint*)malloc(glf->gl_tex_indexes_count * sizeof(GLuint)); qglGenTextures(glf->gl_tex_indexes_count, glf->gl_tex_indexes); buffer_size = glf->gl_tex_width * glf->gl_tex_width * sizeof(GLubyte); buffer = (GLubyte*)malloc(buffer_size); memset(buffer, 0x00, buffer_size); for(i = 0, x = 0, y = 0; i < glf->glyphs_count; i++) { FT_GlyphSlot g; glf->glyphs[i].tex_index = 0; /* load glyph image into the slot (erase previous one) */ if(FT_Load_Glyph(glf->ft_face, i, FT_LOAD_RENDER)) { continue; } /* convert to an anti-aliased bitmap */ if(FT_Render_Glyph(((FT_Face)glf->ft_face)->glyph, FT_RENDER_MODE_NORMAL)) { continue; } g = ((FT_Face)glf->ft_face)->glyph; glf->glyphs[i].width = g->bitmap.width; glf->glyphs[i].height = g->bitmap.rows; glf->glyphs[i].advance_x_pt = g->advance.x; glf->glyphs[i].advance_y_pt = g->advance.y; glf->glyphs[i].left = g->bitmap_left; glf->glyphs[i].top = g->bitmap_top; if((g->bitmap.width == 0) || (g->bitmap.rows == 0)) { continue; } if(x + g->bitmap.width > glf->gl_tex_width) { x = 0; y += glf->font_size + padding; if(y + glf->font_size > glf->gl_tex_width) { int ii; qglBindTexture(GL_TEXTURE_2D, glf->gl_tex_indexes[glf->gl_real_tex_indexes_count]); qglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); qglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, glf->gl_tex_width, glf->gl_tex_width, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); for(ii = i0; ii < i; ii++) { glf->glyphs[ii].tex_x0 /= (GLfloat)glf->gl_tex_width; glf->glyphs[ii].tex_x1 /= (GLfloat)glf->gl_tex_width; glf->glyphs[ii].tex_y0 /= (GLfloat)glf->gl_tex_width; glf->glyphs[ii].tex_y1 /= (GLfloat)glf->gl_tex_width; } memset(buffer, 0x00, buffer_size); y = 0; i0 = i; glf->gl_real_tex_indexes_count++; } } glf->glyphs[i].tex_x0 = (GLfloat)x; glf->glyphs[i].tex_y0 = (GLfloat)y; glf->glyphs[i].tex_x1 = (GLfloat)(x + g->bitmap.width); glf->glyphs[i].tex_y1 = (GLfloat)(y + g->bitmap.rows); glf->glyphs[i].tex_index = glf->gl_tex_indexes[glf->gl_real_tex_indexes_count]; for(xx = 0; xx < g->bitmap.width; xx++) { for(yy = 0; yy < g->bitmap.rows; yy++) { buffer[(y+yy)*glf->gl_tex_width + (x+xx)] = g->bitmap.buffer[yy * g->bitmap.width + xx]; } } x += (g->bitmap.width + padding); } qglBindTexture(GL_TEXTURE_2D, glf->gl_tex_indexes[glf->gl_real_tex_indexes_count]); qglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); chars_in_column = NextPowerOf2(y + font_size + padding); qglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, glf->gl_tex_width, chars_in_column, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); for(ii = i0; ii < glf->glyphs_count; ii++) { glf->glyphs[ii].tex_x0 /= (GLfloat)glf->gl_tex_width; glf->glyphs[ii].tex_x1 /= (GLfloat)glf->gl_tex_width; glf->glyphs[ii].tex_y0 /= (GLfloat)chars_in_column; glf->glyphs[ii].tex_y1 /= (GLfloat)chars_in_column; } free(buffer); glf->gl_real_tex_indexes_count++; } }
/* ============= RE_StretchRaw FIXME: not exactly backend Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. Used for cinematics. ============= */ void RE_StretchRaw( int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty ) { int i, j; int start, end; if ( !tr.registered ) { return; } R_SyncRenderThread(); // we definitely want to sync every frame for the cinematics #if defined( USE_D3D10 ) // TODO #else qglFinish(); #endif start = end = 0; if ( r_speeds->integer ) { #if defined( USE_D3D10 ) // TODO #else qglFinish(); #endif 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 ); } #if defined( USE_D3D10 ) // TODO #else RB_SetGL2D(); qglVertexAttrib4fARB( ATTR_INDEX_NORMAL, 0, 0, 1, 1 ); qglVertexAttrib4fARB( ATTR_INDEX_COLOR, tr.identityLight, tr.identityLight, tr.identityLight, 1 ); GL_BindProgram( &tr.genericSingleShader ); // set uniforms GLSL_SetUniform_TCGen_Environment( &tr.genericSingleShader, qfalse ); GLSL_SetUniform_ColorGen( &tr.genericSingleShader, CGEN_VERTEX ); GLSL_SetUniform_AlphaGen( &tr.genericSingleShader, AGEN_VERTEX ); //GLSL_SetUniform_Color(&tr.genericSingleShader, colorWhite); if ( glConfig.vboVertexSkinningAvailable ) { GLSL_SetUniform_VertexSkinning( &tr.genericSingleShader, qfalse ); } GLSL_SetUniform_DeformGen( &tr.genericSingleShader, DGEN_NONE ); GLSL_SetUniform_AlphaTest( &tr.genericSingleShader, 0 ); GLSL_SetUniform_ModelViewProjectionMatrix( &tr.genericSingleShader, glState.modelViewProjectionMatrix[ glState.stackIndex ] ); // bind u_ColorMap GL_SelectTexture( 0 ); GL_Bind( tr.scratchImage[ client ] ); GLSL_SetUniform_ColorTextureMatrix( &tr.genericSingleShader, matrixIdentity ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cols != tr.scratchImage[ client ]->width || rows != tr.scratchImage[ client ]->height ) { tr.scratchImage[ client ]->width = tr.scratchImage[ client ]->uploadWidth = cols; tr.scratchImage[ client ]->height = tr.scratchImage[ client ]->uploadHeight = rows; qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); } else { if ( dirty ) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing // it and don't try and do a texture compression qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); } } #endif // #if defined(USE_D3D10) if ( r_speeds->integer ) { #if defined( USE_D3D10 ) // TODO #else qglFinish(); #endif end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); } tess.numVertexes = 0; tess.numIndexes = 0; tess.xyz[ tess.numVertexes ][ 0 ] = x; tess.xyz[ tess.numVertexes ][ 1 ] = y; tess.xyz[ tess.numVertexes ][ 2 ] = 0; tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 0.5f / cols; tess.texCoords[ tess.numVertexes ][ 1 ] = 0.5f / rows; tess.texCoords[ tess.numVertexes ][ 2 ] = 0; tess.texCoords[ tess.numVertexes ][ 3 ] = 1; tess.numVertexes++; tess.xyz[ tess.numVertexes ][ 0 ] = x + w; tess.xyz[ tess.numVertexes ][ 1 ] = y; tess.xyz[ tess.numVertexes ][ 2 ] = 0; tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = ( cols - 0.5f ) / cols; tess.texCoords[ tess.numVertexes ][ 1 ] = 0.5f / rows; tess.texCoords[ tess.numVertexes ][ 2 ] = 0; tess.texCoords[ tess.numVertexes ][ 3 ] = 1; tess.numVertexes++; tess.xyz[ tess.numVertexes ][ 0 ] = x + w; tess.xyz[ tess.numVertexes ][ 1 ] = y + h; tess.xyz[ tess.numVertexes ][ 2 ] = 0; tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = ( cols - 0.5f ) / cols; tess.texCoords[ tess.numVertexes ][ 1 ] = ( rows - 0.5f ) / rows; tess.texCoords[ tess.numVertexes ][ 2 ] = 0; tess.texCoords[ tess.numVertexes ][ 3 ] = 1; tess.numVertexes++; tess.xyz[ tess.numVertexes ][ 0 ] = x; tess.xyz[ tess.numVertexes ][ 1 ] = y + h; tess.xyz[ tess.numVertexes ][ 2 ] = 0; tess.xyz[ tess.numVertexes ][ 3 ] = 1; tess.texCoords[ tess.numVertexes ][ 0 ] = 0.5f / cols; tess.texCoords[ tess.numVertexes ][ 1 ] = ( rows - 0.5f ) / rows; tess.texCoords[ tess.numVertexes ][ 2 ] = 0; tess.texCoords[ tess.numVertexes ][ 3 ] = 1; tess.numVertexes++; tess.indexes[ tess.numIndexes++ ] = 0; tess.indexes[ tess.numIndexes++ ] = 1; tess.indexes[ tess.numIndexes++ ] = 2; tess.indexes[ tess.numIndexes++ ] = 0; tess.indexes[ tess.numIndexes++ ] = 2; tess.indexes[ tess.numIndexes++ ] = 3; Tess_UpdateVBOs( ATTR_POSITION | ATTR_TEXCOORD ); Tess_DrawElements(); tess.numVertexes = 0; tess.numIndexes = 0; #if defined( USE_D3D10 ) // TODO #else GL_CheckErrors(); #endif }
/* ======================== 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(); }
/* * 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, qbool dirty) { int i, j; int start, end; shaderProgram_t *sp = &tr.textureColorShader; Vec4 color; if(!tr.registered){ return; } R_SyncRenderThread(); /* 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); } /* FIXME: HUGE hack */ if(glRefConfig.framebufferObject && !glState.currentFBO){ if(backEnd.framePostProcessed){ FBO_Bind(tr.screenScratchFbo); }else{ FBO_Bind(tr.renderFbo); } } RB_SetGL2D(); tess.numIndexes = 0; tess.numVertexes = 0; tess.firstIndex = 0; tess.xyz[tess.numVertexes][0] = x; tess.xyz[tess.numVertexes][1] = y; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = 0.5f / cols; tess.texCoords[tess.numVertexes][0][1] = 0.5f / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = x + w; tess.xyz[tess.numVertexes][1] = y; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = (cols - 0.5f) / cols; tess.texCoords[tess.numVertexes][0][1] = 0.5f / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = x + w; tess.xyz[tess.numVertexes][1] = y + h; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = (cols - 0.5f) / cols; tess.texCoords[tess.numVertexes][0][1] = (rows - 0.5f) / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.xyz[tess.numVertexes][0] = x; tess.xyz[tess.numVertexes][1] = y + h; tess.xyz[tess.numVertexes][2] = 0; tess.xyz[tess.numVertexes][3] = 1; tess.texCoords[tess.numVertexes][0][0] = 0.5f / cols; tess.texCoords[tess.numVertexes][0][1] = (rows - 0.5f) / rows; tess.texCoords[tess.numVertexes][0][2] = 0; tess.texCoords[tess.numVertexes][0][3] = 1; tess.numVertexes++; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 1; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 0; tess.indexes[tess.numIndexes++] = 2; tess.indexes[tess.numIndexes++] = 3; /* FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function */ RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD); sp = &tr.textureColorShader; GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); GLSL_BindProgram(sp); GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); setv34(color, 1, 1, 1, 1); GLSL_SetUniformVec4(sp, TEXTURECOLOR_UNIFORM_COLOR, color); qglDrawElements(GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(0)); /* R_BindNullVBO(); * R_BindNullIBO(); */ tess.numIndexes = 0; tess.numVertexes = 0; tess.firstIndex = 0; }
/********* SP_DrawTexture *********/ void SP_DrawTexture(void* pixels, float width, float height, float vShift) { if (!pixels) { // Ug. We were not even able to load the error message texture. return; } // Create a texture from the buffered file GLuint texid; qglGenTextures(1, &texid); qglBindTexture(GL_TEXTURE_2D, texid); qglTexImage2D(GL_TEXTURE_2D, 0, GL_DDS1_EXT, width, height, 0, GL_DDS1_EXT, GL_UNSIGNED_BYTE, pixels); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); // Reset every GL state we've got. Who knows what state // the renderer could be in when this function gets called. qglColor3f(1.f, 1.f, 1.f); qglViewport(0, 0, 640, 480); GLboolean alpha = qglIsEnabled(GL_ALPHA_TEST); qglDisable(GL_ALPHA_TEST); GLboolean blend = qglIsEnabled(GL_BLEND); qglDisable(GL_BLEND); GLboolean cull = qglIsEnabled(GL_CULL_FACE); qglDisable(GL_CULL_FACE); GLboolean depth = qglIsEnabled(GL_DEPTH_TEST); qglDisable(GL_DEPTH_TEST); GLboolean fog = qglIsEnabled(GL_FOG); qglDisable(GL_FOG); GLboolean lighting = qglIsEnabled(GL_LIGHTING); qglDisable(GL_LIGHTING); GLboolean offset = qglIsEnabled(GL_POLYGON_OFFSET_FILL); qglDisable(GL_POLYGON_OFFSET_FILL); GLboolean scissor = qglIsEnabled(GL_SCISSOR_TEST); qglDisable(GL_SCISSOR_TEST); GLboolean stencil = qglIsEnabled(GL_STENCIL_TEST); qglDisable(GL_STENCIL_TEST); GLboolean texture = qglIsEnabled(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_2D); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglOrtho(0, 640, 0, 480, 0, 1); qglMatrixMode(GL_TEXTURE0); qglLoadIdentity(); qglMatrixMode(GL_TEXTURE1); qglLoadIdentity(); qglActiveTextureARB(GL_TEXTURE0_ARB); qglClientActiveTextureARB(GL_TEXTURE0_ARB); memset(&tess, 0, sizeof(tess)); // Draw the error message qglBeginFrame(); if (!SP_LicenseDone) { // clear the screen if we haven't done the // license yet... qglClearColor(0, 0, 0, 1); qglClear(GL_COLOR_BUFFER_BIT); } float x1 = 320 - width / 2; float x2 = 320 + width / 2; float y1 = 240 - height / 2; float y2 = 240 + height / 2; y1 += vShift; y2 += vShift; qglBeginEXT (GL_TRIANGLE_STRIP, 4, 0, 0, 4, 0); 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(); qglEndFrame(); qglFlush(); // Restore (most) of the render states we reset if (alpha) qglEnable(GL_ALPHA_TEST); else qglDisable(GL_ALPHA_TEST); if (blend) qglEnable(GL_BLEND); else qglDisable(GL_BLEND); if (cull) qglEnable(GL_CULL_FACE); else qglDisable(GL_CULL_FACE); if (depth) qglEnable(GL_DEPTH_TEST); else qglDisable(GL_DEPTH_TEST); if (fog) qglEnable(GL_FOG); else qglDisable(GL_FOG); if (lighting) qglEnable(GL_LIGHTING); else qglDisable(GL_LIGHTING); if (offset) qglEnable(GL_POLYGON_OFFSET_FILL); else qglDisable(GL_POLYGON_OFFSET_FILL); if (scissor) qglEnable(GL_SCISSOR_TEST); else qglDisable(GL_SCISSOR_TEST); if (stencil) qglEnable(GL_STENCIL_TEST); else qglDisable(GL_STENCIL_TEST); if (texture) qglEnable(GL_TEXTURE_2D); else qglDisable(GL_TEXTURE_2D); // Kill the texture qglDeleteTextures(1, &texid); }
int gld_BuildTexture(GLTexture *gltexture, void *data, dboolean readonly, int width, int height) { int result = false; int tex_width, tex_height, tex_buffer_size; unsigned char *tex_buffer = NULL; tex_width = gld_GetTexDimension(width); tex_height = gld_GetTexDimension(height); tex_buffer_size = tex_width * tex_height * 4; //your video is modern if (gl_arb_texture_non_power_of_two) { qglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, ((gltexture->flags & GLTEXTURE_MIPMAP) ? GL_TRUE : GL_FALSE)); qglTexImage2D( GL_TEXTURE_2D, 0, gl_tex_format, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); gld_RecolorMipLevels(data); gld_SetTexFilters(gltexture); result = true; goto l_exit; } #ifdef USE_GLU_MIPMAP if (gltexture->flags & GLTEXTURE_MIPMAP) { gluBuild2DMipmaps(GL_TEXTURE_2D, gl_tex_format, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); gld_RecolorMipLevels(data); gld_SetTexFilters(gltexture); result = true; goto l_exit; } else #endif // USE_GLU_MIPMAP { #ifdef USE_GLU_IMAGESCALE if ((width != tex_width) || (height != tex_height)) { tex_buffer = malloc(tex_buffer_size); if (!tex_buffer) { goto l_exit; } gluScaleImage(GL_RGBA, width, height, GL_UNSIGNED_BYTE, data, tex_width, tex_height, GL_UNSIGNED_BYTE, tex_buffer); qglTexImage2D( GL_TEXTURE_2D, 0, gl_tex_format, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer); } else #endif // USE_GLU_IMAGESCALE { if ((width != tex_width) || (height != tex_height)) { if (width == tex_width) { tex_buffer = malloc(tex_buffer_size); memcpy(tex_buffer, data, width * height * 4); } else { int y; tex_buffer = calloc(1, tex_buffer_size); for (y = 0; y < height; y++) { memcpy(tex_buffer + y * tex_width * 4, ((unsigned char*)data) + y * width * 4, width * 4); } } } else { tex_buffer = data; } if (gl_paletted_texture) { gld_SetTexturePalette(GL_TEXTURE_2D); qglTexImage2D( GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, tex_width, tex_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, tex_buffer); } else { qglTexImage2D( GL_TEXTURE_2D, 0, gl_tex_format, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer); } } gltexture->flags &= ~GLTEXTURE_MIPMAP; gld_SetTexFilters(gltexture); result = true; } l_exit: if (result) { qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } if (tex_buffer && tex_buffer != data) { free(tex_buffer); tex_buffer = NULL; } if (!readonly) { free(data); data = NULL; } return result; }
GLvoid APIENTRY GLDSA_TextureImage2D(GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) { GL_BindMultiTexture(glDsaState.texunit, target, texture); qglTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); }
/* ============= 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(); if ( tess.numIndexes ) { RB_EndSurface(); } // 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; #ifdef USE_OPENGLES qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #else qglTexImage2D( GL_TEXTURE_2D, 0, 3, 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(); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); #ifdef USE_OPENGLES GLfloat tex[] = { 0.5f / cols, 0.5f / rows, ( cols - 0.5f ) / cols , 0.5f / rows, ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows, 0.5f / cols, ( rows - 0.5f ) / rows }; 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 (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglEnableClientState(GL_COLOR_ARRAY); #else 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 }
void bordered_texture_atlas::createTextures(GLuint *textureNames) { GLubyte *data = (GLubyte *) malloc(4 * result_page_width * result_page_width); qglGenTextures((GLsizei) number_result_pages, textureNames); textures_indexes = textureNames; for (unsigned long page = 0; page < number_result_pages; page++) { for (unsigned long texture = 0; texture < number_canonical_object_textures; texture++) { const canonical_object_texture &canonical = canonical_object_textures[texture]; if (canonical.new_page != page) continue; if(canonical.original_page == WHITE_TEXTURE_INDEX) { uint32_t white_pixels[1] = {0xFFFFFFFFU}; // Add top border for (int border = 0; border < border_width; border++) { unsigned x = canonical.new_x_with_border; unsigned y = canonical.new_y_with_border + border; // expand top-left pixel memset_pattern4(&data[(y*result_page_width + x) * 4], white_pixels, 4 * border_width); // copy top line memset_pattern4(&data[(y*result_page_width + x + border_width) * 4], white_pixels, canonical.width * 4); // expand top-right pixel memset_pattern4(&data[(y*result_page_width + x + border_width + canonical.width) * 4], white_pixels, 4 * border_width); } // Copy main content for (int line = 0; line < canonical.height; line++) { unsigned x = canonical.new_x_with_border; unsigned y = canonical.new_y_with_border + border_width + line; // expand left pixel memset_pattern4(&data[(y*result_page_width + x) * 4], white_pixels, 4 * border_width); // copy line memset_pattern4(&data[(y*result_page_width + x + border_width) * 4], white_pixels, canonical.width * 4); // expand right pixel memset_pattern4(&data[(y*result_page_width + x + border_width + canonical.width) * 4], white_pixels, 4 * border_width); } // Add bottom border for (int border = 0; border < border_width; border++) { unsigned x = canonical.new_x_with_border; unsigned y = canonical.new_y_with_border + canonical.height + border_width + border; // expand bottom-left pixel memset_pattern4(&data[(y*result_page_width + x) * 4], white_pixels, 4 * border_width); // copy bottom line memset_pattern4(&data[(y*result_page_width + x + border_width) * 4], white_pixels, canonical.width * 4); // expand bottom-right pixel memset_pattern4(&data[(y*result_page_width + x + border_width + canonical.width) * 4], white_pixels, 4 * border_width); } } else { const char *original = (char *) original_pages[canonical.original_page].pixels; // Add top border for (int border = 0; border < border_width; border++) { unsigned x = canonical.new_x_with_border; unsigned y = canonical.new_y_with_border + border; unsigned old_x = canonical.original_x; unsigned old_y = canonical.original_y; // expand top-left pixel memset_pattern4(&data[(y*result_page_width + x) * 4], &(original[(old_y * 256 + old_x) * 4]), 4 * border_width); // copy top line memcpy(&data[(y*result_page_width + x + border_width) * 4], &original[(old_y * 256 + old_x) * 4], canonical.width * 4); // expand top-right pixel memset_pattern4(&data[(y*result_page_width + x + border_width + canonical.width) * 4], &(original[(old_y * 256 + old_x + canonical.width) * 4]), 4 * border_width); } // Copy main content for (int line = 0; line < canonical.height; line++) { unsigned x = canonical.new_x_with_border; unsigned y = canonical.new_y_with_border + border_width + line; unsigned old_x = canonical.original_x; unsigned old_y = canonical.original_y + line; // expand left pixel memset_pattern4(&data[(y*result_page_width + x) * 4], &(original[(old_y * 256 + old_x) * 4]), 4 * border_width); // copy line memcpy(&data[(y*result_page_width + x + border_width) * 4], &original[(old_y * 256 + old_x) * 4], canonical.width * 4); // expand right pixel memset_pattern4(&data[(y*result_page_width + x + border_width + canonical.width) * 4], &(original[(old_y * 256 + old_x + canonical.width) * 4]), 4 * border_width); } // Add bottom border for (int border = 0; border < border_width; border++) { unsigned x = canonical.new_x_with_border; unsigned y = canonical.new_y_with_border + canonical.height + border_width + border; unsigned old_x = canonical.original_x; unsigned old_y = canonical.original_y + canonical.height; // expand bottom-left pixel memset_pattern4(&data[(y*result_page_width + x) * 4], &(original[(old_y * 256 + old_x) * 4]), 4 * border_width); // copy bottom line memcpy(&data[(y*result_page_width + x + border_width) * 4], &original[(old_y * 256 + old_x) * 4], canonical.width * 4); // expand bottom-right pixel memset_pattern4(&data[(y*result_page_width + x + border_width + canonical.width) * 4], &(original[(old_y * 256 + old_x + canonical.width) * 4]), 4 * border_width); } } } qglBindTexture(GL_TEXTURE_2D, textureNames[page]); qglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)result_page_width, (GLsizei) result_page_height[page], 0, GL_RGBA, GL_UNSIGNED_BYTE, data); if(qglGenerateMipmap != NULL) { qglGenerateMipmap(GL_TEXTURE_2D); } else { int mip_level = 1; int w = result_page_width / 2; int h = result_page_height[page] / 2; GLubyte *mip_data = (GLubyte *) malloc(4 * w * h); assert(w > 0 && h > 0); for(int i = 0; i < h; i++) { for(int j = 0; j < w; j++) { mip_data[i * w * 4 + j * 4 + 0] = 0.25 * ((int)data[i * w * 16 + j * 8 + 0] + (int)data[i * w * 16 + j * 8 + 4 + 0] + (int)data[i * w * 16 + w * 8 + j * 8 + 0] + (int)data[i * w * 16 + w * 8 + j * 8 + 4 + 0]); mip_data[i * w * 4 + j * 4 + 1] = 0.25 * ((int)data[i * w * 16 + j * 8 + 1] + (int)data[i * w * 16 + j * 8 + 4 + 1] + (int)data[i * w * 16 + w * 8 + j * 8 + 1] + (int)data[i * w * 16 + w * 8 + j * 8 + 4 + 1]); mip_data[i * w * 4 + j * 4 + 2] = 0.25 * ((int)data[i * w * 16 + j * 8 + 2] + (int)data[i * w * 16 + j * 8 + 4 + 2] + (int)data[i * w * 16 + w * 8 + j * 8 + 2] + (int)data[i * w * 16 + w * 8 + j * 8 + 4 + 2]); mip_data[i * w * 4 + j * 4 + 3] = 0.25 * ((int)data[i * w * 16 + j * 8 + 3] + (int)data[i * w * 16 + j * 8 + 4 + 3] + (int)data[i * w * 16 + w * 8 + j * 8 + 3] + (int)data[i * w * 16 + w * 8 + j * 8 + 4 + 3]); } } //char tgan[128]; //WriteTGAfile("mip_00.tga", data, result_page_width, result_page_height[page], 0); //sprintf(tgan, "mip_%0.2d.tga", mip_level); //WriteTGAfile(tgan, mip_data, w, h, 0); qglTexImage2D(GL_TEXTURE_2D, mip_level, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip_data); while((w > 1) && (h > 1) /*&& (mip_level < 4)*/) { mip_level++; w /= 2; w = (w==0)?1:w; h /= 2; h = (h==0)?1:h; for(int i = 0; i < h; i++) { for(int j = 0; j < w; j++) { mip_data[i * w * 4 + j * 4 + 0] = 0.25 * ((int)mip_data[i * w * 16 + j * 8 + 0] + (int)mip_data[i * w * 16 + j * 8 + 4 + 0] + (int)mip_data[i * w * 16 + w * 8 + j * 8 + 0] + (int)mip_data[i * w * 16 + w * 8 + j * 8 + 4 + 0]); mip_data[i * w * 4 + j * 4 + 1] = 0.25 * ((int)mip_data[i * w * 16 + j * 8 + 1] + (int)mip_data[i * w * 16 + j * 8 + 4 + 1] + (int)mip_data[i * w * 16 + w * 8 + j * 8 + 1] + (int)mip_data[i * w * 16 + w * 8 + j * 8 + 4 + 1]); mip_data[i * w * 4 + j * 4 + 2] = 0.25 * ((int)mip_data[i * w * 16 + j * 8 + 2] + (int)mip_data[i * w * 16 + j * 8 + 4 + 2] + (int)mip_data[i * w * 16 + w * 8 + j * 8 + 2] + (int)mip_data[i * w * 16 + w * 8 + j * 8 + 4 + 2]); mip_data[i * w * 4 + j * 4 + 3] = 0.25 * ((int)mip_data[i * w * 16 + j * 8 + 3] + (int)mip_data[i * w * 16 + j * 8 + 4 + 3] + (int)mip_data[i * w * 16 + w * 8 + j * 8 + 3] + (int)mip_data[i * w * 16 + w * 8 + j * 8 + 4 + 3]); } } //sprintf(tgan, "mip_%0.2d.tga", mip_level); //WriteTGAfile(tgan, mip_data, w, h, 0); qglTexImage2D(GL_TEXTURE_2D, mip_level, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip_data); } free(mip_data); } qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } free(data); }
void InitGlslShadersAndPrograms( void ) { void *shaderSource; GLenum target; float bloomTextureScale; int ret; if ( !r_enablePostProcess->integer || !glsl ) { return; } GL_SelectTexture(0); qglDisable( GL_TEXTURE_2D ); qglEnable( GL_TEXTURE_RECTANGLE_ARB ); bloomTextureScale = r_BloomTextureScale->value; if ( bloomTextureScale < 0.01 ) { bloomTextureScale = 0.01; } else if ( bloomTextureScale > 1 ) { bloomTextureScale = 1; } target = GL_TEXTURE_RECTANGLE_ARB; tr.bloomWidth = glConfig.vidWidth * bloomTextureScale; tr.bloomHeight = glConfig.vidHeight * bloomTextureScale; qglGenTextures(1, &tr.bloomTexture); qglBindTexture(target, tr.bloomTexture); qglTexImage2D(target, 0, GL_RGBA8, tr.bloomWidth, tr.bloomHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); qglTexParameteri(target, GL_TEXTURE_WRAP_S, r_glClampToEdge->integer ? GL_CLAMP_TO_EDGE : GL_CLAMP); qglTexParameteri(target, GL_TEXTURE_WRAP_T, r_glClampToEdge->integer ? GL_CLAMP_TO_EDGE : GL_CLAMP); qglTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); target = GL_TEXTURE_RECTANGLE_ARB; qglGenTextures(1, &tr.backBufferTexture); qglBindTexture(target, tr.backBufferTexture); qglTexImage2D(target, 0, GL_RGB8, glConfig.vidWidth, glConfig.vidHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); qglTexParameteri(target, GL_TEXTURE_WRAP_S, r_glClampToEdge->integer ? GL_CLAMP_TO_EDGE : GL_CLAMP); qglTexParameteri(target, GL_TEXTURE_WRAP_T, r_glClampToEdge->integer ? GL_CLAMP_TO_EDGE : GL_CLAMP); qglTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); qglTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglDisable(GL_TEXTURE_RECTANGLE_ARB); qglEnable(GL_TEXTURE_2D); GL_SelectTexture(0); Com_VPrintf("^5scripts/posteffect.vs ->\n"); ret = ri.FS_ReadFile("scripts/posteffect.vs", &shaderSource); if (ret > 0) { tr.mainVs = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); qglShaderSourceARB(tr.mainVs, 1, (const char **)&shaderSource, NULL); qglCompileShaderARB(tr.mainVs); printGlslLog(tr.mainVs); ri.FS_FreeFile(shaderSource); } else if ( strlen(fallbackShader_posteffect) ) { Com_VPrintf("^1file not found, using fallback shader\n"); //ri.FS_FreeFile(shaderSource); tr.mainVs = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); qglShaderSourceARB(tr.mainVs, 1, &fallbackShader_posteffect, NULL); qglCompileShaderARB(tr.mainVs); printGlslLog(tr.mainVs); } else { Com_VPrintf("^1file not found\n"); glsl = qfalse; R_DeleteGlslShadersAndPrograms(); } R_InitFragmentShader( "scripts/colorcorrect.fs", &tr.colorCorrectFs, &tr.colorCorrectSp, tr.mainVs, fallbackShader_colorcorrect ); R_InitFragmentShader( "scripts/blurhoriz.fs", &tr.blurHorizFs, &tr.blurHorizSp, tr.mainVs, fallbackShader_blurhoriz ); R_InitFragmentShader( "scripts/blurvertical.fs", &tr.blurVerticalFs, &tr.blurVerticalSp, tr.mainVs, fallbackShader_blurvertical ); R_InitFragmentShader( "scripts/brightpass.fs", &tr.brightPassFs, &tr.brightPassSp, tr.mainVs, fallbackShader_brightpass ); R_InitFragmentShader( "scripts/combine.fs", &tr.combineFs, &tr.combineSp, tr.mainVs, fallbackShader_combine ); R_InitFragmentShader( "scripts/downsample1.fs", &tr.downSample1Fs, &tr.downSample1Sp, tr.mainVs, fallbackShader_downsample1 ); }
/* ============= RE_StretchRaw FIXME: not exactly backend Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. Used for cinematics. ============= */ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { int i, j; int start, end; if ( !tr.registered ) { return; } R_SyncRenderThread(); // we definately want to sync every frame for the cinematics qglFinish(); start = end = 0; if ( r_speeds->integer ) { start = ri.Milliseconds(); } // make sure rows and cols are powers of 2 for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { } for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { } if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); } GL_Bind( tr.scratchImage[client] ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); } else { if (dirty) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing // it and don't try and do a texture compression qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); } } if ( r_speeds->integer ) { end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); } RB_SetGL2D(); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglBegin (GL_QUADS); qglTexCoord2f ( 0.5f / cols, 0.5f / rows ); qglVertex2f (x, y); qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows ); qglVertex2f (x+w, y); qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); qglVertex2f (x+w, y+h); qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows ); qglVertex2f (x, y+h); qglEnd (); }
/* ============= 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 VCMODS_OPENGLES 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 VCMODS_OPENGLES //don't do qglTexImage2D as this may end up doing a compressed image //on which we are not allowed to do further sub images glTexImage2D( 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 VCMODS_OPENGLES qglColor4f( 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 }