/* 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. */ #include "gl_local.h" #include #include "gl_cin.h" 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]; 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; int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; int gl_filter_max = GL_LINEAR; qboolean picMipmap (image_t *image) { if (image->type == it_part && image->script) { rscript_t *rs = image->script; return !rs->dontflush; } if (image->type != it_pic && image->type != it_sky ) return true; return false; } void GL_SetTexturePalette( unsigned palette[256] ) { int i; unsigned char temptable[768]; if ( qglColorTableEXT ) { 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 ); } } 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); } } 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; GLfloat largest_supported_anisotropy; for (i=0 ; i< NUM_GL_MODES ; i++) { if ( !Q_stricmp( modes[i].name, string ) ) break; } if (i == NUM_GL_MODES) { ri.Con_Printf (PRINT_ALL, "bad filter name\n"); return; } gl_filter_min = modes[i].minimize; gl_filter_max = modes[i].maximize; // change all the existing mipmap texture objects for (i=0, glt=gltextures ; itexnum); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); if (gl_anisotropic->value) { qglGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy); } } else { GL_Bind (glt->texnum); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); } } } /* =============== 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) { ri.Con_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) { ri.Con_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" }; ri.Con_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: ri.Con_Printf (PRINT_ALL, "M"); break; case it_sprite: ri.Con_Printf (PRINT_ALL, "S"); break; case it_wall: ri.Con_Printf (PRINT_ALL, "W"); break; case it_pic: ri.Con_Printf (PRINT_ALL, "P"); break; default: ri.Con_Printf (PRINT_ALL, " "); break; } ri.Con_Printf (PRINT_ALL, " %3i %3i %s: %s\n", image->upload_width, image->upload_height, palstrings[image->paletted], image->name); } ri.Con_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) { ri.Con_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) { ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename); free (*pic); *pic = NULL; } ri.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 = ri.FS_LoadFile (name, (void **)&buffer); if (!buffer) { ri.Con_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) { ri.Con_Printf (PRINT_ALL, "LoadTGA: Bad tga file %s\n", name); ri.FS_FreeFile (buffer); return; } if (targa_header.image_type != 2 && targa_header.image_type != 10) { ri.Con_Printf (PRINT_ALL, "LoadTGA: %s has wrong image format; only type 2 and 10 targa RGB images supported.\n", name); ri.FS_FreeFile (buffer); return; } if (targa_header.colormap_type !=0 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) { ri.Con_Printf (PRINT_ALL, "LoadTGA: %s has wrong image format; only 32 or 24 bit images supported (no colormaps).\n", name); ri.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:; } } ri.FS_FreeFile (buffer); } /* ================================================================= JPEG LOADING By Robert 'Heffo' Heffernan ================================================================= */ void jpg_null(j_decompress_ptr cinfo) { } boolean jpg_fill_input_buffer(j_decompress_ptr cinfo) { ri.Con_Printf(PRINT_ALL, "Premature end of JPEG data\n"); return 1; } 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) ri.Con_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; } /* ============== 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; *pic = NULL; // Load JPEG file into memory rawsize = ri.FS_LoadFile(filename, (void **)&rawdata); if(!rawdata) return; // Knightmare- check for bad data if ( rawdata[6] != 'J' || rawdata[7] != 'F' || rawdata[8] != 'I' || rawdata[9] != 'F') { ri.Con_Printf (PRINT_ALL, "Bad jpg file %s\n", filename); ri.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); // Start Decompression jpeg_start_decompress(&cinfo); // Check Colour Components if(cinfo.output_components != 3 && cinfo.output_components != 4) { ri.Con_Printf(PRINT_ALL, "Invalid JPEG colour components\n"); jpeg_destroy_decompress(&cinfo); ri.FS_FreeFile(rawdata); return; } // Allocate Memory for decompressed image rgbadata = malloc(cinfo.output_width * cinfo.output_height * 4); if(!rgbadata) { ri.Con_Printf(PRINT_ALL, "Insufficient RAM for JPEG buffer\n"); jpeg_destroy_decompress(&cinfo); ri.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) { ri.Con_Printf(PRINT_ALL, "Insufficient RAM for JPEG scanline buffer\n"); free(rgbadata); jpeg_destroy_decompress(&cinfo); ri.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; i 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_ResampleTexture ================ */ 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[4096], p2[4096]; byte *pix1, *pix2, *pix3, *pix4; //divby0 error! - psychospaz if (outheight==0) { out = NULL; return; } if (outwidth==0) { out = NULL; return; } 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 ) { double 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 ) { double i; for ( i = 0; i < (double)(scaled_width) * (double)(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[(int)(i)] = gl_state.d_16to8table[c]; scaled += 4; } } int upload_width, upload_height; qboolean uploaded_paletted; int nearest_power_of_2(int size) { int i = 2; 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, picmip; 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 ; ivalue - 1; if (picmip == -1) picmip = 0; else max_size = 256; if (scaled_width > max_size) scaled_width = max_size; if (scaled_height > max_size) scaled_height = max_size; } if (mipmap && picmip) { scaled_width >>= picmip; scaled_height >>= picmip; } 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 (mipmap) { #ifdef _WIN32 if (!gl_state.gammaramp) #else if (!gl_state.hwgamma) #endif GL_LightScaleTexture (scaled, scaled_width, scaled_height, !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 { if (!gl_state.gammaramp) GL_LightScaleTexture (scaled, scaled_width, scaled_height, !mipmap ); 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); return (samples == gl_alpha_format || samples == GL_COMPRESSED_RGBA_ARB); } /* =============== end of modifications =============== */ /* =============== GL_Upload8 Returns has_alpha =============== */ 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) ri.Sys_Error (ERR_DROP, "GL_Upload8: ()too large"); 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 ================ */ image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type, int bits) { image_t *image; int i; // find a free image_t for (i=0, image=gltextures ; itexnum) break; } if (i == numgltextures) { if (numgltextures == MAX_GLTEXTURES) ri.Sys_Error (ERR_DROP, "MAX_GLTEXTURES"); numgltextures++; } image = &gltextures[i]; if (strlen(name) >= sizeof(image->name)) ri.Sys_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; if (type == it_skin && bits == 8) R_FloodFillSkin(pic, width, height); image->scrap = false; image->texnum = TEXNUM_IMAGES + (image - gltextures); GL_Bind(image->texnum); if (bits == 8) image->has_alpha = GL_Upload8 (pic, width, height, picMipmap(image), image->type == it_sky ); else image->has_alpha = GL_Upload32 ((unsigned *)pic, width, height, picMipmap(image) ); 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; ri.FS_LoadFile (name, (void **)&mt); if (!mt) { ri.Con_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); ri.FS_FreeFile ((void *)mt); return image; } /* =============== GL_FindImage Finds or loads the given image =============== */ #define IMAGETYPES 3 char *image_types[IMAGETYPES]= { ".png", ".tga", ".jpg" }; image_t * checkOtherFormats (char *basename, imagetype_t type) { int i,j; image_t *image = NULL; for (i=0;iname)) { image->registration_sequence = registration_sequence; return image; } } //get rid of suffix... Com_sprintf(base_name, sizeof(base_name), "%s", name); dot = strstr (base_name, "."); if (dot) { spot = strlen(base_name)-strlen(dot); base_name[spot] = 0; } // // load the pic from disk // pic = NULL; palette = NULL; image = NULL; if (!strcmp(name+len-4, ".pcx")) { //only try to overwrite pcxs, others are specified in model files etc image = checkOtherFormats (&base_name[0], type); if (!image) { LoadPCX (name, &pic, &palette, &width, &height); if (!pic) return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name); image = GL_LoadPic (name, pic, width, height, type, 8); } } else if (!strcmp(name+len-4, ".wal")) { //overwrite wal textures image = checkOtherFormats (&base_name[0], type); if (!image) { image = GL_LoadWal (name); } } 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, 50, (256*256*4)); image = GL_LoadPic (name, pic, 256, 256, type, 32); newcin->texnum = image->texnum; image->is_cin = true; } else { if (!strcmp(name+len-4, ".jpg")) //heffo hax0r { LoadJPG (name, &pic, &width, &height); if (!pic) return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name); image = GL_LoadPic (name, pic, width, height, type, 32); } else if (!strcmp(name+len-4, ".tga")) { LoadTGA (name, &pic, &width, &height); if (!pic) return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name); image = GL_LoadPic (name, pic, width, height, type, 32); } else if (!strcmp(name+len-4, ".png")) { LoadPNG (name, &pic, &width, &height); if (!pic) return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: can't load %s", name); image = GL_LoadPic (name, pic, width, height, type, 32); } else return NULL; // ri.Sys_Error (ERR_DROP, "GL_FindImage: bad extension on: %s", name); } if (pic) free(pic); if (palette) free(palette); if (strlen(base_name)>5 && (base_name[0]=='P' || base_name[0]=='p') && (base_name[1]=='I' || base_name[1]=='i') && (base_name[2]=='C' || base_name[2]=='c') && (base_name[3]=='S' || base_name[3]=='s') && base_name[4]=='/') Com_sprintf(image->bare_name, sizeof(image->bare_name), "%s", &base_name[5]); else Com_sprintf(image->bare_name, sizeof(image->bare_name), "%s", &base_name[0]); if (dot) base_name[spot] = (char)135; image->script = RS_FindScript(image->bare_name); 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[s] r_notexture->registration_sequence = registration_sequence; r_celtexture->registration_sequence = registration_sequence; r_particlebeam->registration_sequence = registration_sequence; r_dynamicimage->registration_sequence = registration_sequence; r_lblendimage->registration_sequence = registration_sequence; r_motionblurimage->registration_sequence = registration_sequence; r_motionblurscreenimage->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, &image->texnum); memset (image, 0, sizeof(*image)); } } /* =============== Draw_GetPalette =============== */ byte default_pal[768] = { 0,0,0,15,15,15,31,31,31,47,47,47,63,63,63,75,75,75,91,91,91,107,107,107,123,123,123,139,139,139,155,155,155,171,171,171,187,187,187,203,203,203,219,219,219,235,235,235,99,75,35,91,67,31,83,63,31,79,59,27,71,55,27,63,47, 23,59,43,23,51,39,19,47,35,19,43,31,19,39,27,15,35,23,15,27,19,11,23,15,11,19,15,7,15,11,7,95,95,111,91,91,103,91,83,95,87,79,91,83,75,83,79,71,75,71,63,67,63,59,59,59,55,55,51,47,47,47,43,43,39, 39,39,35,35,35,27,27,27,23,23,23,19,19,19,143,119,83,123,99,67,115,91,59,103,79,47,207,151,75,167,123,59,139,103,47,111,83,39,235,159,39,203,139,35,175,119,31,147,99,27,119,79,23,91,59,15,63,39,11,35,23,7,167,59,43, 159,47,35,151,43,27,139,39,19,127,31,15,115,23,11,103,23,7,87,19,0,75,15,0,67,15,0,59,15,0,51,11,0,43,11,0,35,11,0,27,7,0,19,7,0,123,95,75,115,87,67,107,83,63,103,79,59,95,71,55,87,67,51,83,63, 47,75,55,43,67,51,39,63,47,35,55,39,27,47,35,23,39,27,19,31,23,15,23,15,11,15,11,7,111,59,23,95,55,23,83,47,23,67,43,23,55,35,19,39,27,15,27,19,11,15,11,7,179,91,79,191,123,111,203,155,147,215,187,183,203, 215,223,179,199,211,159,183,195,135,167,183,115,151,167,91,135,155,71,119,139,47,103,127,23,83,111,19,75,103,15,67,91,11,63,83,7,55,75,7,47,63,7,39,51,0,31,43,0,23,31,0,15,19,0,7,11,0,0,0,139,87,87,131,79,79, 123,71,71,115,67,67,107,59,59,99,51,51,91,47,47,87,43,43,75,35,35,63,31,31,51,27,27,43,19,19,31,15,15,19,11,11,11,7,7,0,0,0,151,159,123,143,151,115,135,139,107,127,131,99,119,123,95,115,115,87,107,107,79,99,99, 71,91,91,67,79,79,59,67,67,51,55,55,43,47,47,35,35,35,27,23,23,19,15,15,11,159,75,63,147,67,55,139,59,47,127,55,39,119,47,35,107,43,27,99,35,23,87,31,19,79,27,15,67,23,11,55,19,11,43,15,7,31,11,7,23, 7,0,11,0,0,0,0,0,119,123,207,111,115,195,103,107,183,99,99,167,91,91,155,83,87,143,75,79,127,71,71,115,63,63,103,55,55,87,47,47,75,39,39,63,35,31,47,27,23,35,19,15,23,11,7,7,155,171,123,143,159,111,135,151,99, 123,139,87,115,131,75,103,119,67,95,111,59,87,103,51,75,91,39,63,79,27,55,67,19,47,59,11,35,47,7,27,35,0,19,23,0,11,15,0,0,255,0,35,231,15,63,211,27,83,187,39,95,167,47,95,143,51,95,123,51,255,255,255,255,255, 211,255,255,167,255,255,127,255,255,83,255,255,39,255,235,31,255,215,23,255,191,15,255,171,7,255,147,0,239,127,0,227,107,0,211,87,0,199,71,0,183,59,0,171,43,0,155,31,0,143,23,0,127,15,0,115,7,0,95,0,0,71,0,0,47, 0,0,27,0,0,239,0,0,55,55,255,255,0,0,0,0,255,43,43,35,27,27,23,19,19,15,235,151,127,195,115,83,159,87,51,123,63,27,235,211,199,199,171,155,167,139,119,135,107,87,159,91,83 }; int Draw_GetPalette (void) { int i; int r, g, b; unsigned v; byte *pic, *pal; int width, height; // get the palette LoadPCX ("pics/colormap.pcx", &pic, &pal, &width, &height); if (!pal) { //this will set up colormap default (same as q2 pal w/o pcx file) #if 0 for (i=0 ; i<256 ; i++) { r = default_pal[i*3+0]; g = default_pal[i*3+1]; b = default_pal[i*3+2]; v = (255<<24) + (r<<0) + (g<<8) + (b<<16); d_8to24table[i] = LittleLong(v); } #else ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx"); #endif } else for (i=0 ; i<256 ; i++) { r = pal[i*3+0]; g = pal[i*3+1]; b = pal[i*3+2]; 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 // Vic - begin if ( gl_config.mtexcombine ) intensity = ri.Cvar_Get ("intensity", "1", 0); else intensity = ri.Cvar_Get ("intensity", "2", 0); // Vic - end if ( intensity->value <= 1 ) ri.Cvar_Set( "intensity", "1" ); gl_state.inverse_intensity = 1 / intensity->value; Draw_GetPalette (); if ( qglColorTableEXT ) { ri.FS_LoadFile( "pics/16to8.dat", (void *)&gl_state.d_16to8table ); if ( !gl_state.d_16to8table ) ri.Sys_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)*DIV255 , 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; } } /* =============== GL_ShutdownImages =============== */ void GL_ShutdownImages (void) { int i; image_t *image, *c; 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, &image->texnum); memset (image, 0, sizeof(*image)); } }