/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // r_image.c #include "r_local.h" //#include "r_cin.h" #ifdef __unix__ #include #include #else #include "include/jpeglib.h" #endif image_t gltextures[MAX_GLTEXTURES]; int numgltextures; int base_textureid; // gltextures[i] = base_textureid+i static byte intensitytable[256]; static unsigned char gammatable[256]; cvar_t *intensity; unsigned d_8to24table[256]; float d_8to24tablef[256][3]; //Knightmare- MrG's Vertex array stuff qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky ); qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap); int gl_solid_format = 3; int gl_alpha_format = 4; int gl_tex_solid_format = 3; int gl_tex_alpha_format = 4; // Knightmare- default to trilinear filtering, thnx to MrG // removed because this causes problems on some vidcards int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; int gl_filter_max = GL_LINEAR; void GL_SetTexturePalette( unsigned palette[256] ) { int i; unsigned char temptable[768]; if ( qglColorTableEXT )//&& gl_ext_palettedtexture->value ) { for ( i = 0; i < 256; i++ ) { temptable[i*3+0] = ( palette[i] >> 0 ) & 0xff; temptable[i*3+1] = ( palette[i] >> 8 ) & 0xff; temptable[i*3+2] = ( palette[i] >> 16 ) & 0xff; } qglColorTableEXT( GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, temptable ); } } // Knightmare- added some of Psychospaz's shortcuts GLenum bFunc1 = -1; GLenum bFunc2 = -1; void GL_BlendFunction (GLenum sfactor, GLenum dfactor) { if (sfactor!=bFunc1 || dfactor!=bFunc2) { bFunc1 = sfactor; bFunc2 = dfactor; qglBlendFunc(bFunc1, bFunc2); } } GLenum shadeModelMode = -1; void GL_ShadeModel (GLenum mode) { if (mode!=shadeModelMode) { shadeModelMode = mode; qglShadeModel(mode); } } // end Knightmare void GL_EnableMultitexture( qboolean enable ) { if ( !qglSelectTextureSGIS && !qglActiveTextureARB ) return; if ( enable ) { GL_SelectTexture( GL_TEXTURE1 ); qglEnable( GL_TEXTURE_2D ); GL_TexEnv( GL_REPLACE ); } else { GL_SelectTexture( GL_TEXTURE1 ); qglDisable( GL_TEXTURE_2D ); GL_TexEnv( GL_REPLACE ); } GL_SelectTexture( GL_TEXTURE0 ); GL_TexEnv( GL_REPLACE ); } void GL_SelectTexture( GLenum texture ) { int tmu; if ( !qglSelectTextureSGIS && !qglActiveTextureARB ) return; if ( texture == GL_TEXTURE0 ) { tmu = 0; } else { tmu = 1; } if ( tmu == gl_state.currenttmu ) { return; } gl_state.currenttmu = tmu; if ( qglSelectTextureSGIS ) { qglSelectTextureSGIS( texture ); } else if ( qglActiveTextureARB ) { qglActiveTextureARB( texture ); qglClientActiveTextureARB( texture ); } } void GL_TexEnv( GLenum mode ) { static int lastmodes[2] = { -1, -1 }; if ( mode != lastmodes[gl_state.currenttmu] ) { qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode ); lastmodes[gl_state.currenttmu] = mode; } } void GL_Bind (int texnum) { extern image_t *draw_chars; if (gl_nobind->value && draw_chars) // performance evaluation option texnum = draw_chars->texnum; if ( gl_state.currenttextures[gl_state.currenttmu] == texnum) return; gl_state.currenttextures[gl_state.currenttmu] = texnum; qglBindTexture (GL_TEXTURE_2D, texnum); } void GL_MBind( GLenum target, int texnum ) { GL_SelectTexture( target ); if ( target == GL_TEXTURE0 ) { if ( gl_state.currenttextures[0] == texnum ) return; } else { if ( gl_state.currenttextures[1] == texnum ) return; } GL_Bind( texnum ); } typedef struct { char *name; int minimize, maximize; } glmode_t; glmode_t modes[] = { {"GL_NEAREST", GL_NEAREST, GL_NEAREST}, {"GL_LINEAR", GL_LINEAR, GL_LINEAR}, {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST}, {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR}, {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST}, {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} }; #define NUM_GL_MODES (sizeof(modes) / sizeof (glmode_t)) typedef struct { char *name; int mode; } gltmode_t; gltmode_t gl_alpha_modes[] = { {"default", 4}, {"GL_RGBA", GL_RGBA}, {"GL_RGBA8", GL_RGBA8}, {"GL_RGB5_A1", GL_RGB5_A1}, {"GL_RGBA4", GL_RGBA4}, {"GL_RGBA2", GL_RGBA2}, }; #define NUM_GL_ALPHA_MODES (sizeof(gl_alpha_modes) / sizeof (gltmode_t)) gltmode_t gl_solid_modes[] = { {"default", 3}, {"GL_RGB", GL_RGB}, {"GL_RGB8", GL_RGB8}, {"GL_RGB5", GL_RGB5}, {"GL_RGB4", GL_RGB4}, {"GL_R3_G3_B2", GL_R3_G3_B2}, #ifdef GL_RGB2_EXT {"GL_RGB2", GL_RGB2_EXT}, #endif }; #define NUM_GL_SOLID_MODES (sizeof(gl_solid_modes) / sizeof (gltmode_t)) /* =============== GL_TextureMode =============== */ void GL_TextureMode( char *string ) { int i; image_t *glt; for (i=0 ; i< NUM_GL_MODES ; i++) { if ( !Q_stricmp( modes[i].name, string ) ) break; } if (i == NUM_GL_MODES) { VID_Printf (PRINT_ALL, "bad filter name\n"); return; } gl_filter_min = modes[i].minimize; gl_filter_max = modes[i].maximize; // clamp selected anisotropy if (gl_config.anisotropic) { if (gl_anisotropic->value > gl_config.max_anisotropy) Cvar_SetValue("gl_anisotropic", gl_config.max_anisotropy); else if (gl_anisotropic->value < 1.0) Cvar_SetValue("gl_anisotropic", 1.0); } // change all the existing mipmap texture objects for (i=0, glt=gltextures ; itype != it_pic && glt->type != it_sky ) { GL_Bind (glt->texnum); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); // Set anisotropic filter if supported and enabled if (gl_config.anisotropic && gl_anisotropic->value) { qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_anisotropic->value); //GLfloat largest_supported_anisotropy; //qglGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy); //qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy); } } } } /* =============== GL_TextureAlphaMode =============== */ void GL_TextureAlphaMode( char *string ) { int i; for (i=0 ; i< NUM_GL_ALPHA_MODES ; i++) { if ( !Q_stricmp( gl_alpha_modes[i].name, string ) ) break; } if (i == NUM_GL_ALPHA_MODES) { VID_Printf (PRINT_ALL, "bad alpha texture mode name\n"); return; } gl_tex_alpha_format = gl_alpha_modes[i].mode; } /* =============== GL_TextureSolidMode =============== */ void GL_TextureSolidMode( char *string ) { int i; for (i=0 ; i< NUM_GL_SOLID_MODES ; i++) { if ( !Q_stricmp( gl_solid_modes[i].name, string ) ) break; } if (i == NUM_GL_SOLID_MODES) { VID_Printf (PRINT_ALL, "bad solid texture mode name\n"); return; } gl_tex_solid_format = gl_solid_modes[i].mode; } /* =============== GL_ImageList_f =============== */ void GL_ImageList_f (void) { int i; image_t *image; int texels; const char *palstrings[2] = { "RGB", "PAL" }; VID_Printf (PRINT_ALL, "------------------\n"); texels = 0; for (i=0, image=gltextures; itexnum <= 0) continue; texels += image->upload_width*image->upload_height; switch (image->type) { case it_skin: VID_Printf (PRINT_ALL, "M"); break; case it_sprite: VID_Printf (PRINT_ALL, "S"); break; case it_wall: VID_Printf (PRINT_ALL, "W"); break; case it_pic: VID_Printf (PRINT_ALL, "P"); break; default: VID_Printf (PRINT_ALL, " "); break; } VID_Printf (PRINT_ALL, " %3i %3i %s: %s\n", image->upload_width, image->upload_height, palstrings[image->paletted], image->name); } VID_Printf (PRINT_ALL, "Total texel count (not counting mipmaps): %i\n", texels); } /* ============================================================================= scrap allocation Allocate all the little status bar obejcts into a single texture to crutch up inefficient hardware / drivers ============================================================================= */ #define MAX_SCRAPS 1 #define BLOCK_WIDTH 256 #define BLOCK_HEIGHT 256 int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT]; qboolean scrap_dirty; // returns a texture number and the position inside it int Scrap_AllocBlock (int w, int h, int *x, int *y) { int i, j; int best, best2; int texnum; for (texnum=0 ; texnum= best) break; if (scrap_allocated[texnum][i+j] > best2) best2 = scrap_allocated[texnum][i+j]; } if (j == w) { // this is a valid spot *x = i; *y = best = best2; } } if (best + h > BLOCK_HEIGHT) continue; for (i=0 ; ixmin = LittleShort(pcx->xmin); pcx->ymin = LittleShort(pcx->ymin); pcx->xmax = LittleShort(pcx->xmax); pcx->ymax = LittleShort(pcx->ymax); pcx->hres = LittleShort(pcx->hres); pcx->vres = LittleShort(pcx->vres); pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); pcx->palette_type = LittleShort(pcx->palette_type); raw = &pcx->data; if (pcx->manufacturer != 0x0a || pcx->version != 5 || pcx->encoding != 1 || pcx->bits_per_pixel != 8 || pcx->xmax >= 640 || pcx->ymax >= 480) { VID_Printf (PRINT_ALL, "Bad pcx file %s\n", filename); return; } out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); *pic = out; pix = out; if (palette) { *palette = malloc(768); memcpy (*palette, (byte *)pcx + len - 768, 768); } if (width) *width = pcx->xmax+1; if (height) *height = pcx->ymax+1; for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) { for (x=0 ; x<=pcx->xmax ; ) { dataByte = *raw++; if((dataByte & 0xC0) == 0xC0) { runLength = dataByte & 0x3F; dataByte = *raw++; } else runLength = 1; while(runLength-- > 0) pix[x++] = dataByte; } } if ( raw - (byte *)pcx > len) { VID_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename); free (*pic); *pic = NULL; } FS_FreeFile (pcx); } /* ========================================================= TARGA LOADING ========================================================= */ typedef struct _TargaHeader { unsigned char id_length, colormap_type, image_type; unsigned short colormap_index, colormap_length; unsigned char colormap_size; unsigned short x_origin, y_origin, width, height; unsigned char pixel_size, attributes; } TargaHeader; /* ============= LoadTGA ============= */ void LoadTGA (char *name, byte **pic, int *width, int *height) { int columns, rows, numPixels; byte *pixbuf; int row, column; byte *buf_p; byte *buffer; int length; TargaHeader targa_header; byte *targa_rgba; byte tmp[2]; *pic = NULL; // // load the file // length = FS_LoadFile (name, (void **)&buffer); if (!buffer) { // Knightmare- removed this because it spams the console //VID_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name); return; } buf_p = buffer; targa_header.id_length = *buf_p++; targa_header.colormap_type = *buf_p++; targa_header.image_type = *buf_p++; tmp[0] = buf_p[0]; tmp[1] = buf_p[1]; targa_header.colormap_index = LittleShort ( *((short *)tmp) ); buf_p+=2; tmp[0] = buf_p[0]; tmp[1] = buf_p[1]; targa_header.colormap_length = LittleShort ( *((short *)tmp) ); buf_p+=2; targa_header.colormap_size = *buf_p++; targa_header.x_origin = LittleShort ( *((short *)buf_p) ); buf_p+=2; targa_header.y_origin = LittleShort ( *((short *)buf_p) ); buf_p+=2; targa_header.width = LittleShort ( *((short *)buf_p) ); buf_p+=2; targa_header.height = LittleShort ( *((short *)buf_p) ); buf_p+=2; targa_header.pixel_size = *buf_p++; targa_header.attributes = *buf_p++; // Knightmare- check for bad data if (!targa_header.width || !targa_header.height) { VID_Printf (PRINT_ALL, "Bad tga file %s\n", name); FS_FreeFile (buffer); return; } if (targa_header.image_type != 2 && targa_header.image_type != 10) { // VID_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); VID_Printf (PRINT_ALL, "LoadTGA: %s has wrong image format; only type 2 and 10 targa RGB images supported.\n", name); FS_FreeFile (buffer); return; } if (targa_header.colormap_type !=0 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) { // VID_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); VID_Printf (PRINT_ALL, "LoadTGA: %s has wrong image format; only 32 or 24 bit images supported (no colormaps).\n", name); FS_FreeFile (buffer); return; } columns = targa_header.width; rows = targa_header.height; numPixels = columns * rows; if (width) *width = columns; if (height) *height = rows; targa_rgba = malloc (numPixels*4); *pic = targa_rgba; if (targa_header.id_length != 0) buf_p += targa_header.id_length; // skip TARGA image comment if (targa_header.image_type==2) { // Uncompressed, RGB images for(row=rows-1; row>=0; row--) { pixbuf = targa_rgba + row*columns*4; for(column=0; column=0; row--) { pixbuf = targa_rgba + row*columns*4; for(column=0; column0) row--; else goto breakOut; pixbuf = targa_rgba + row*columns*4; } } } else { // non run-length packet for(j=0;j0) row--; else goto breakOut; pixbuf = targa_rgba + row*columns*4; } } } } breakOut:; } } FS_FreeFile (buffer); } /* ================================================================= JPEG LOADING By Robert 'Heffo' Heffernan ================================================================= */ void jpg_null(j_decompress_ptr cinfo) { } #ifdef __unix__ boolean jpg_fill_input_buffer(j_decompress_ptr cinfo) { VID_Printf(PRINT_ALL, "Premature end of JPEG data\n"); return 1; } #else unsigned char jpg_fill_input_buffer(j_decompress_ptr cinfo) { VID_Printf(PRINT_ALL, "Premature end of JPEG data\n"); return 1; } #endif void jpg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { cinfo->src->next_input_byte += (size_t) num_bytes; cinfo->src->bytes_in_buffer -= (size_t) num_bytes; if (cinfo->src->bytes_in_buffer < 0) VID_Printf(PRINT_ALL, "Premature end of JPEG data\n"); } void jpeg_mem_src(j_decompress_ptr cinfo, byte *mem, int len) { cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr)); cinfo->src->init_source = jpg_null; cinfo->src->fill_input_buffer = jpg_fill_input_buffer; cinfo->src->skip_input_data = jpg_skip_input_data; cinfo->src->resync_to_restart = jpeg_resync_to_restart; cinfo->src->term_source = jpg_null; cinfo->src->bytes_in_buffer = len; cinfo->src->next_input_byte = mem; } #define DSTATE_START 200 /* after create_decompress */ #define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ /* ============== LoadJPG ============== */ void LoadJPG (char *filename, byte **pic, int *width, int *height) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; byte *rawdata, *rgbadata, *scanline, *p, *q; int rawsize, i; // Load JPEG file into memory rawsize = FS_LoadFile(filename, (void **)&rawdata); if (!rawdata) { //VID_Printf (PRINT_DEVELOPER, "Bad jpg file %s\n", filename); return; } // Knightmare- check for bad data if ( rawdata[6] != 'J' || rawdata[7] != 'F' || rawdata[8] != 'I' || rawdata[9] != 'F') { // VID_Printf (PRINT_ALL, "Bad jpg file %s\n", filename); FS_FreeFile(rawdata); return; } // Initialise libJpeg Object cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); // Feed JPEG memory into the libJpeg Object jpeg_mem_src(&cinfo, rawdata, rawsize); // Process JPEG header jpeg_read_header(&cinfo, true); // bombs out here // Start Decompression jpeg_start_decompress(&cinfo); // Check Color Components if(cinfo.output_components != 3) { VID_Printf(PRINT_ALL, "Invalid JPEG color components\n"); jpeg_destroy_decompress(&cinfo); FS_FreeFile(rawdata); return; } // Allocate Memory for decompressed image rgbadata = malloc(cinfo.output_width * cinfo.output_height * 4); if(!rgbadata) { VID_Printf(PRINT_ALL, "Insufficient RAM for JPEG buffer\n"); jpeg_destroy_decompress(&cinfo); FS_FreeFile(rawdata); return; } // Pass sizes to output *width = cinfo.output_width; *height = cinfo.output_height; // Allocate Scanline buffer scanline = malloc(cinfo.output_width * 3); if(!scanline) { VID_Printf(PRINT_ALL, "Insufficient RAM for JPEG scanline buffer\n"); free(rgbadata); jpeg_destroy_decompress(&cinfo); FS_FreeFile(rawdata); return; } // Read Scanlines, and expand from RGB to RGBA q = rgbadata; while(cinfo.output_scanline < cinfo.output_height) { p = scanline; jpeg_read_scanlines(&cinfo, &scanline, 1); for(i=0; iData) { free(my_png->Data); my_png->Data = 0; } if (my_png->FRowPtrs) { free(my_png->FRowPtrs); my_png->FRowPtrs = 0; } my_png->Data = malloc(my_png->Height * my_png->FRowBytes); /* DL Added 30/5/2000 */ my_png->FRowPtrs = malloc(sizeof(void *) * my_png->Height); if ((my_png->Data) && (my_png->FRowPtrs)) { cvaluep = (long *)my_png->FRowPtrs; for (y = 0; y < my_png->Height; y++) { cvaluep[y] = (long)my_png->Data + (y * (long)my_png->FRowBytes); /* DL Added 08/07/2000 */ } } } void mypng_struct_create() { if (my_png) return; my_png = malloc(sizeof(png_t)); my_png->Data = 0; my_png->FRowPtrs = 0; my_png->Height = 0; my_png->Width = 0; my_png->ColorType = PNG_COLOR_TYPE_RGB; my_png->Interlace = PNG_INTERLACE_NONE; my_png->Compression = PNG_COMPRESSION_TYPE_DEFAULT; my_png->Filter = PNG_FILTER_TYPE_DEFAULT; } void mypng_struct_destroy(qboolean keepData) { if (!my_png) return; if (my_png->Data && !keepData) free(my_png->Data); if (my_png->FRowPtrs) free(my_png->FRowPtrs); free(my_png); my_png = 0; } /* * ============================================================= * * fReadData * * ============================================================= */ void PNGAPI fReadData(png_structp png, png_bytep data, png_size_t length) { /* called by pnglib */ int i; for (i = 0; i < length; i++) data[i] = my_png->tmpBuf[my_png->tmpi++]; /* give pnglib a some more bytes */ } /* ============================================================= LoadPNG ============================================================= */ void LoadPNG(char *filename, byte ** pic, int *width, int *height) { png_structp png; png_infop pnginfo; byte ioBuffer [8192]; int len; byte *raw; *pic = 0; len = FS_LoadFile(filename, (void **)&raw); if (!raw) { //VID_Printf(PRINT_DEVELOPER, "Bad png file %s\n", filename); return; } if (png_sig_cmp(raw, 0, 4)) return; png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!png) return; pnginfo = png_create_info_struct(png); if (!pnginfo) { png_destroy_read_struct(&png, &pnginfo, 0); return; } png_set_sig_bytes(png, 0 /* sizeof( sig ) */ ); mypng_struct_create(); /* creates the my_png struct */ my_png->tmpBuf = (char *)raw; /* buf = whole file content */ my_png->tmpi = 0; png_set_read_fn(png, ioBuffer, fReadData); png_read_info(png, pnginfo); png_get_IHDR(png, pnginfo, &my_png->Width, &my_png->Height, &my_png->BitDepth, &my_png->ColorType, &my_png->Interlace, &my_png->Compression, &my_png->Filter); /* ...removed bgColor code here... */ if (my_png->ColorType == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (my_png->ColorType == PNG_COLOR_TYPE_GRAY && my_png->BitDepth < 8) png_set_gray_1_2_4_to_8(png); /* Add alpha channel if present */ if (png_get_valid(png, pnginfo, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); /* hax: expand 24bit to 32bit */ if (my_png->BitDepth == 8 && my_png->ColorType == PNG_COLOR_TYPE_RGB) png_set_filler(png, 255, PNG_FILLER_AFTER); if ((my_png->ColorType == PNG_COLOR_TYPE_GRAY) || (my_png->ColorType == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_to_rgb(png); if (my_png->BitDepth < 8) png_set_expand(png); /* update the info structure */ png_read_update_info(png, pnginfo); my_png->FRowBytes = png_get_rowbytes(png, pnginfo); my_png->BytesPerPixel = png_get_channels(png, pnginfo); /* DL Added 30/08/2000 */ InitializeDemData(); if ((my_png->Data) && (my_png->FRowPtrs)) png_read_image(png, (png_bytepp) my_png->FRowPtrs); png_read_end(png, pnginfo); /* read last information chunks */ png_destroy_read_struct(&png, &pnginfo, 0); /* only load 32 bit by now... */ if (my_png->BitDepth == 8) { *pic = (byte *)my_png->Data; *width = my_png->Width; *height = my_png->Height; } else { //VID_Printf(PRINT_DEVELOPER, "Bad png color depth: %s\n", filename); *pic = NULL; free(my_png->Data); } mypng_struct_destroy(true); FS_FreeFile((void *)raw); } #endif /* ==================================================================== IMAGE FLOOD FILLING ==================================================================== */ /* ================= Mod_FloodFillSkin Fill background pixels so mipmapping doesn't have haloes ================= */ typedef struct { short x, y; } floodfill_t; // must be a power of 2 #define FLOODFILL_FIFO_SIZE 0x1000 #define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1) #define FLOODFILL_STEP( off, dx, dy ) \ { \ if (pos[off] == fillcolor) \ { \ pos[off] = 255; \ fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \ inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \ } \ else if (pos[off] != 255) fdc = pos[off]; \ } void R_FloodFillSkin( byte *skin, int skinwidth, int skinheight ) { byte fillcolor = *skin; // assume this is the pixel to fill floodfill_t fifo[FLOODFILL_FIFO_SIZE]; int inpt = 0, outpt = 0; int filledcolor = -1; int i; if (filledcolor == -1) { filledcolor = 0; // attempt to find opaque black for (i = 0; i < 256; ++i) if (d_8to24table[i] == (255 << 0)) // alpha 1.0 { filledcolor = i; break; } } // can't fill to filled color or to transparent color (used as visited marker) if ((fillcolor == filledcolor) || (fillcolor == 255)) { //printf( "not filling skin from %d to %d\n", fillcolor, filledcolor ); return; } fifo[inpt].x = 0, fifo[inpt].y = 0; inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; while (outpt != inpt) { int x = fifo[outpt].x, y = fifo[outpt].y; int fdc = filledcolor; byte *pos = &skin[x + skinwidth * y]; outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; if (x > 0) FLOODFILL_STEP( -1, -1, 0 ); if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 ); if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 ); if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 ); skin[x + skinwidth * y] = fdc; } } //======================================================= /* ================ GL_ResampleTextureLerpLine from DarkPlaces ================ */ void GL_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth) { int j, xi, oldx = 0, f, fstep, l1, l2, endx; fstep = (int) (inwidth*65536.0f/outwidth); endx = (inwidth-1); for (j = 0,f = 0;j < outwidth;j++, f += fstep) { xi = (int) f >> 16; if (xi != oldx) { in += (xi - oldx) * 4; oldx = xi; } if (xi < endx) { l2 = f & 0xFFFF; l1 = 0x10000 - l2; *out++ = (byte) ((in[0] * l1 + in[4] * l2) >> 16); *out++ = (byte) ((in[1] * l1 + in[5] * l2) >> 16); *out++ = (byte) ((in[2] * l1 + in[6] * l2) >> 16); *out++ = (byte) ((in[3] * l1 + in[7] * l2) >> 16); } else // last pixel of the line has no pixel to lerp to { *out++ = in[0]; *out++ = in[1]; *out++ = in[2]; *out++ = in[3]; } } } /* ================ GL_ResampleTexture ================ */ void GL_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight) { int i, j, yi, oldy, f, fstep, l1, l2, endy = (inheight-1); byte *inrow, *out, *row1, *row2; out = outdata; fstep = (int) (inheight*65536.0f/outheight); row1 = malloc(outwidth*4); row2 = malloc(outwidth*4); inrow = indata; oldy = 0; GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth); GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth); for (i = 0, f = 0;i < outheight;i++,f += fstep) { yi = f >> 16; if (yi != oldy) { inrow = (byte *)indata + inwidth*4*yi; if (yi == oldy+1) memcpy(row1, row2, outwidth*4); else GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth); if (yi < endy) GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth); else memcpy(row2, row1, outwidth*4); oldy = yi; } if (yi < endy) { l2 = f & 0xFFFF; l1 = 0x10000 - l2; for (j = 0;j < outwidth;j++) { *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16); *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16); *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16); *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16); } row1 -= outwidth*4; row2 -= outwidth*4; } else // last line has no pixels to lerp to { for (j = 0;j < outwidth;j++) { *out++ = *row1++; *out++ = *row1++; *out++ = *row1++; *out++ = *row1++; } row1 -= outwidth*4; } } free(row1); free(row2); } /* void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight) { int i, j; unsigned *inrow, *inrow2; unsigned frac, fracstep; unsigned p1[1024], p2[1024]; byte *pix1, *pix2, *pix3, *pix4; fracstep = inwidth*0x10000/outwidth; frac = fracstep>>2; for (i=0 ; i>16); frac += fracstep; } frac = 3*(fracstep>>2); for (i=0 ; i>16); frac += fracstep; } for (i=0 ; i> 1; for (j=0 ; j>2; ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; } } }*/ /* ================ GL_LightScaleTexture Scale up the pixel values in a texture to increase the lighting range ================ */ void GL_LightScaleTexture (unsigned *in, int inwidth, int inheight, qboolean only_gamma ) { if ( only_gamma ) { int i, c; byte *p; p = (byte *)in; c = inwidth*inheight; for (i=0 ; i>= 1; out = in; for (i=0 ; i>2; out[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2; out[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2; out[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2; } } } /* =============== GL_Upload32 Returns has_alpha =============== */ void GL_BuildPalettedTexture( unsigned char *paletted_texture, unsigned char *scaled, int scaled_width, int scaled_height ) { int i; for ( i = 0; i < scaled_width * scaled_height; i++ ) { unsigned int r, g, b, c; r = ( scaled[0] >> 3 ) & 31; g = ( scaled[1] >> 2 ) & 63; b = ( scaled[2] >> 3 ) & 31; c = r | ( g << 5 ) | ( b << 11 ); paletted_texture[i] = gl_state.d_16to8table[c]; scaled += 4; } } /* =============== here starts modified code by Heffo/changes by Nexus =============== */ static int upload_width, upload_height; //** DMP made local to module static qboolean uploaded_paletted; //** DMP ditto int nearest_power_of_2 (int size) { int i = 2; // NeVo - infinite loop bug-fix if (size == 1) return size; while (1) { i <<= 1; if (size == i) return i; if (size > i && size < (i <<1)) { if (size >= ((i+(i<<1))/2)) return i<<1; else return i; } }; } qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap) { int samples; unsigned *scaled; int scaled_width, scaled_height; int i, c; byte *scan; int comp; uploaded_paletted = false; // scan the texture for any non-255 alpha c = width*height; scan = ((byte *)data) + 3; samples = gl_solid_format; for (i=0 ; i gl_config.max_texsize) scaled_width = gl_config.max_texsize; if (scaled_height > gl_config.max_texsize) scaled_height = gl_config.max_texsize; } // let people sample down the world textures for speed if (mipmap && (int)gl_picmip->value > 0) { int maxsize; if ((int)gl_picmip->value == 1) // clamp to 512x512 maxsize = 512; else if ((int)gl_picmip->value == 2) // clamp to 256x256 maxsize = 256; else // clamp to 128x128 maxsize = 128; while (1) { if (scaled_width <= maxsize && scaled_height <= maxsize) break; scaled_width >>= 1; scaled_height >>= 1; } //scaled_width >>= (int)gl_picmip->value; //scaled_height >>= (int)gl_picmip->value; } //if (scaled_width * scaled_height > sizeof(scaled)/4) // Sys_Error ("GL_LoadTexture: too big"); //upload_width = scaled_width; //upload_height = scaled_height; // scan the texture for any non-255 alpha /*c = width*height; scan = ((byte *)data) + 3; samples = gl_solid_format; for (i=0 ; i 1 || scaled_height > 1) { GL_MipMap ((byte *)scaled, scaled_width, scaled_height); scaled_width >>= 1; scaled_height >>= 1; if (scaled_width < 1) scaled_width = 1; if (scaled_height < 1) scaled_height = 1; miplevel++; qglTexImage2D (GL_TEXTURE_2D, miplevel, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); } } done: */ if (scaled_width != width || scaled_height != height) { scaled=malloc((scaled_width * scaled_height) * 4); GL_ResampleTexture(data,width,height,scaled,scaled_width,scaled_height); } else { scaled_width=width; scaled_height=height; scaled=data; } if (!gl_state.gammaramp) GL_LightScaleTexture (scaled, scaled_width, scaled_height, !mipmap ); if (mipmap) { if (gl_state.sgis_mipmap) { qglTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, true); qglTexImage2D (GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); } else gluBuild2DMipmaps (GL_TEXTURE_2D, comp, scaled_width, scaled_height, GL_RGBA, GL_UNSIGNED_BYTE, scaled); } else qglTexImage2D (GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); if (scaled_width != width || scaled_height != height) free(scaled); upload_width=scaled_width; upload_height = scaled_height; qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (mipmap) ? gl_filter_min : gl_filter_max); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); if (mipmap) { // Set anisotropic filter if supported and enabled if (gl_config.anisotropic && gl_anisotropic->value) qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_anisotropic->value); } return (samples == gl_alpha_format || samples == GL_COMPRESSED_RGBA_ARB); } /* =============== GL_Upload8 Returns has_alpha =============== */ /* static qboolean IsPowerOf2( int value ) { int i = 1; while ( 1 ) { if ( value == i ) return true; if ( i > value ) return false; i <<= 1; } } */ qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky ) { unsigned trans[512*256]; int i, s; int p; s = width*height; if (s > sizeof(trans)/4) VID_Error (ERR_DROP, "GL_Upload8: too large"); /*if ( qglColorTableEXT && gl_ext_palettedtexture->value && is_sky ) { qglTexImage2D( GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, width, height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, data ); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); } else*/ { for (i=0 ; i width && data[i-width] != 255) p = data[i-width]; else if (i < s-width && data[i+width] != 255) p = data[i+width]; else if (i > 0 && data[i-1] != 255) p = data[i-1]; else if (i < s-1 && data[i+1] != 255) p = data[i+1]; else p = 0; // copy rgb components ((byte *)&trans[i])[0] = ((byte *)&d_8to24table[p])[0]; ((byte *)&trans[i])[1] = ((byte *)&d_8to24table[p])[1]; ((byte *)&trans[i])[2] = ((byte *)&d_8to24table[p])[2]; } } return GL_Upload32 (trans, width, height, mipmap); } } /* ================ GL_LoadPic This is also used as an entry point for the generated r_notexture Nexus - changes for hires-textures ================ */ image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type, int bits) { image_t *image; int i; //Nexus'added vars int len; char s[128]; // find a free image_t for (i=0, image=gltextures ; itexnum) break; } if (i == numgltextures) { if (numgltextures == MAX_GLTEXTURES) VID_Error (ERR_DROP, "MAX_GLTEXTURES"); numgltextures++; } image = &gltextures[i]; if (strlen(name) >= sizeof(image->name)) VID_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name); strcpy (image->name, name); image->registration_sequence = registration_sequence; image->width = width; image->height = height; image->type = type; image->replace_scale_w = image->replace_scale_h = 1.0f; // Knightmare added if (type == it_skin && bits == 8) R_FloodFillSkin(pic, width, height); // Knightmare- replacement scaling hack for TGA/JPEG HUD images and skins // NOTE: replace this with shaders as soon as they are supported len = strlen(name); strcpy(s,name); // check if we have a .tga/jpg pic #if defined (__unix__) if ((type == it_pic /*| type == it_skin*/) && (!strcmp(s+len-4, ".png") || !strcmp(s+len-4, ".tga") || !strcmp(s+len-4, ".jpg")) ) #else if ((type == it_pic /*| type == it_skin*/)&& (!strcmp(s+len-4, ".tga") || !strcmp(s+len-4, ".jpg")) ) #endif { byte *pic, *palette; int pcxwidth, pcxheight; s[len-3]='p'; s[len-2]='c'; s[len-1]='x'; // replace extension LoadPCX (s, &pic, &palette, &pcxwidth, &pcxheight); // load .pcx file if (pcxwidth > 0 && pcxheight > 0) { //if (type == it_pic) { image->replace_scale_w = (float)pcxwidth/image->width; image->replace_scale_h = (float)pcxheight/image->height; //image->replace_scale = ((float)pcxwidth/image->width + (float)pcxheight/image->height)*0.5; //if (image->replace_scale == 0.0f) image->replace_scale = 1.0f; //image->replace_scale = max(image->replace_scale, 0.0f); //image->replace_scale = min(image->replace_scale, 1.0f); /*} else if (type == it_skin) { image->replace_scale_w = (float)image->width/(float)pcxwidth; image->replace_scale_h = (float)image->height/(float)pcxheight; VID_Printf(PRINT_ALL, "Skin: %s replace scale: %f x %f y\n", image->name, image->replace_scale_w ,image->replace_scale_h); }*/ } if (pic) free(pic); if (palette) free(palette); } // end Knightmare // load little pics into the scrap if (image->type == it_pic && bits == 8 && image->width < 64 && image->height < 64) { int x, y; int i, j, k; int texnum; texnum = Scrap_AllocBlock (image->width, image->height, &x, &y); if (texnum == -1) goto nonscrap; scrap_dirty = true; // copy the texels into the scrap block k = 0; for (i=0 ; iheight ; i++) for (j=0 ; jwidth ; j++, k++) scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = pic[k]; image->texnum = TEXNUM_SCRAPS + texnum; image->scrap = true; image->has_alpha = true; image->sl = (x+0.01)/(float)BLOCK_WIDTH; image->sh = (x+image->width-0.01)/(float)BLOCK_WIDTH; image->tl = (y+0.01)/(float)BLOCK_WIDTH; image->th = (y+image->height-0.01)/(float)BLOCK_WIDTH; } else { nonscrap: image->scrap = false; image->texnum = TEXNUM_IMAGES + (image - gltextures); GL_Bind(image->texnum); if (bits == 8) image->has_alpha = GL_Upload8 (pic, width, height, (image->type != it_pic && image->type != it_sky), image->type == it_sky ); else image->has_alpha = GL_Upload32 ((unsigned *)pic, width, height, (image->type != it_pic && image->type != it_sky) ); image->upload_width = upload_width; // after power of 2 and scales image->upload_height = upload_height; image->paletted = uploaded_paletted; image->sl = 0; image->sh = 1; image->tl = 0; image->th = 1; } return image; } /* ================ GL_LoadWal ================ */ image_t *GL_LoadWal (char *name) { miptex_t *mt; int width, height, ofs; image_t *image; FS_LoadFile (name, (void **)&mt); if (!mt) { VID_Printf (PRINT_ALL, "GL_FindImage: can't load %s\n", name); return r_notexture; } width = LittleLong (mt->width); height = LittleLong (mt->height); ofs = LittleLong (mt->offsets[0]); image = GL_LoadPic (name, (byte *)mt + ofs, width, height, it_wall, 8); FS_FreeFile ((void *)mt); return image; } /* =============== GL_FindImage Finds or loads the given image =============== */ image_t *GL_FindImage (char *name, imagetype_t type) { image_t *image; int i, len; byte *pic, *palette; int width, height; if (!name) return NULL; len = strlen(name); if (len<5) return NULL; // look for it for (i=0, image=gltextures ; iname)) { image->registration_sequence = registration_sequence; return image; } } // // load the pic from disk // pic = NULL; palette = NULL; //Knightmare- MrG's automatic JPG & TGA loading // search for TGAs or JPGs to replace .pcx and .wal images if (!strcmp(name+len-4, ".pcx") || !strcmp(name+len-4, ".wal")) { char s[128]; strcpy(s,name); #if defined (__unix__) s[len-3]='p'; s[len-2]='n'; s[len-1]='g'; image = GL_FindImage(s,type); if (image) return image; #endif s[len-3]='t'; s[len-2]='g'; s[len-1]='a'; image = GL_FindImage(s,type); if (image) return image; //Knightmare- if no TGA, check for JPG s[len-3]='j'; s[len-2]='p'; s[len-1]='g'; image = GL_FindImage(s,type); if (image) return image; } //end Knightmare if (!strcmp(name+len-4, ".pcx")) { LoadPCX (name, &pic, &palette, &width, &height); if (!pic) return NULL; image = GL_LoadPic (name, pic, width, height, type, 8); } else if (!strcmp(name+len-4, ".wal")) { image = GL_LoadWal (name); } #if defined (__unix__) else if (!strcmp(name+len-4, ".png")) { LoadPNG(name, &pic, &width, &height); if(!pic) return NULL; image = GL_LoadPic(name, pic, width, height, type, 32); } #endif else if (!strcmp(name+len-4, ".tga")) { LoadTGA (name, &pic, &width, &height); if (!pic) { //hack for md3s- they usually have tga skin references, check for jpg char s[128]; strcpy(s,name); s[len-3]='j'; s[len-2]='p'; s[len-1]='g'; image = GL_FindImage(s,type); if (image) return image; else return NULL; } image = GL_LoadPic (name, pic, width, height, type, 32); } else if (!strcmp(name+len-4, ".jpg")) // Heffo - JPEG support { LoadJPG(name, &pic, &width, &height); if(!pic) return NULL; image = GL_LoadPic(name, pic, width, height, type, 32); } /*else if (!strcmp(name+len-4, ".cin")) // Heffo { // WHY .cin files? because we can! cinematics_t *newcin; newcin = CIN_OpenCin(name); if(!newcin) return NULL; pic = malloc(256*256*4); memset(pic, 192, (256*256*4)); image = GL_LoadPic (name, pic, 256, 256, type, 32); newcin->texnum = image->texnum; image->is_cin = true; }*/ else return NULL; if (pic) free(pic); if (palette) free(palette); return image; } /* =============== R_RegisterSkin =============== */ struct image_s *R_RegisterSkin (char *name) { return GL_FindImage (name, it_skin); } /* ================ GL_FreeUnusedImages Any image that was not touched on this registration sequence will be freed. ================ */ void GL_FreeUnusedImages (void) { int i; image_t *image; // never free r_notexture or particle texture r_notexture->registration_sequence = registration_sequence; #ifdef ROQ_SUPPORT r_rawtexture->registration_sequence = registration_sequence; #endif // ROQ_SUPPORT r_envmappic->registration_sequence = registration_sequence; r_spheremappic->registration_sequence = registration_sequence; r_shelltexture->registration_sequence = registration_sequence; r_particlebeam->registration_sequence = registration_sequence; for (i=0; iregistration_sequence = registration_sequence; for (i=0, image=gltextures ; iregistration_sequence == registration_sequence) continue; // used this sequence if (!image->registration_sequence) continue; // free image_t slot if (image->type == it_pic) continue; // don't free pics //Heffo - Free Cinematic //if(image->is_cin) // CIN_FreeCin(image->texnum); // free it qglDeleteTextures (1, (GLuint *)&image->texnum); memset (image, 0, sizeof(*image)); } } /* =============== Draw_GetPalette =============== */ int Draw_GetPalette (void) { int i; int r, g, b; unsigned v; byte *pic, *pal; int width, height; //int avg, dr, dg, db, d1, d2, d3; //** DMP //float sat; //** DMP // get the palette LoadPCX ("pics/colormap.pcx", &pic, &pal, &width, &height); if (!pal) VID_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx"); for (i=0 ; i<256 ; i++) { r = pal[i*3+0]; g = pal[i*3+1]; b = pal[i*3+2]; //** DMP adjust saturation /*avg = (r + g + b + 2) / 3; // first calc grey value we'll desaturate to dr = avg - r; // calc distance from grey value to each gun dg = avg - g; db = avg - b; d1 = abs(r - g); // find greatest distance between all the guns d2 = abs(g - b); d3 = abs(b - r); if (d1 > d2) // we will use this for our existing saturation if (d1 > d3) sat = d1; else if (d2 > d3) sat = d2; else sat = d3; else if (d2 > d3) sat = d2; else sat = d3; sat /= 255.0; // convert existing saturationn to ratio sat = 1.0 - sat; // invert so the most saturation causes the desaturation to lessen sat *= (1.0 - gl_saturation->value); // scale the desaturation value so our desaturation is non-linear (keeps lava looking good) dr *= sat; // scale the differences by the amount we want to desaturate dg *= sat; db *= sat; r += dr; // now move the gun values towards total grey by the amount we desaturated g += dg; b += db;*/ //** DMP end saturation mod v = (255<<24) + (r<<0) + (g<<8) + (b<<16); d_8to24table[i] = LittleLong(v); } d_8to24table[255] &= LittleLong(0xffffff); // 255 is transparent free (pic); free (pal); return 0; } /* =============== GL_InitImages =============== */ void GL_InitImages (void) { int i, j; float g = vid_gamma->value; registration_sequence = 1; // init intensity conversions //intensity = Cvar_Get ("intensity", "2", CVAR_ARCHIVE); // Knightmare- added Vic's overbright rendering if (gl_config.mtexcombine) intensity = Cvar_Get ("intensity", "1", 0); else intensity = Cvar_Get ("intensity", "2", 0); // end Knightmare if ( intensity->value <= 1 ) Cvar_Set( "intensity", "1" ); gl_state.inverse_intensity = 1 / intensity->value; Draw_GetPalette (); if ( qglColorTableEXT ) { FS_LoadFile( "pics/16to8.dat", (void *)&gl_state.d_16to8table ); if ( !gl_state.d_16to8table ) VID_Error( ERR_FATAL, "Couldn't load pics/16to8.pcx"); } if ( gl_config.renderer & ( GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2 ) ) { g = 1.0F; } for ( i = 0; i < 256; i++ ) { if ( g == 1 ) { gammatable[i] = i; } else { float inf; inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5; if (inf < 0) inf = 0; if (inf > 255) inf = 255; gammatable[i] = inf; } } for (i=0 ; i<256 ; i++) { j = i*intensity->value; if (j > 255) j = 255; intensitytable[i] = j; } #ifdef LIGHT_BLOOMS R_InitBloomTextures(); // BLOOMS #endif } /* =============== R_FreePic by Knightmare Frees a single pic =============== */ void R_FreePic (char *name) { int i; image_t *image; for (i=0, image=gltextures; iregistration_sequence) continue; // free image_t slot if (image->type != it_pic) continue; // only free pics if (!strcmp(name, image->name)) { //Heffo - Free Cinematic //if (image->is_cin) // CIN_FreeCin(image->texnum); // free it qglDeleteTextures (1, (GLuint *)&image->texnum); memset (image, 0, sizeof(*image)); return; //we're done here } } } /* =============== GL_ShutdownImages =============== */ void GL_ShutdownImages (void) { int i; image_t *image; for (i=0, image=gltextures; iregistration_sequence) continue; // free image_t slot //Heffo - Free Cinematic //if (image->is_cin) // CIN_FreeCin(image->texnum); // free it qglDeleteTextures (1, (GLuint *)&image->texnum); memset (image, 0, sizeof(*image)); } }