/* Copyright (C) 1996-1997 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. */ // draw.c -- this is the only file outside the refresh that touches the // vid buffer #include "quakedef.h" // jkrige - scale2d #ifdef _WIN32 #include "winquake.h" #endif // jkrige - scale2d // jkrige - jpg #include "../jpeg-6/jpeglib.h" byte *jpeg_rgba; // jkrige - jpg //#define GL_COLOR_INDEX8_EXT 0x80E5 extern unsigned char d_15to8table[65536]; cvar_t gl_nobind = {"gl_nobind", "0"}; cvar_t gl_max_size = {"gl_max_size", "1024"}; cvar_t gl_picmip = {"gl_picmip", "0"}; // jkrige - luma textures cvar_t gl_lumatex_render = {"gl_lumatex_render", "1", true}; // jkrige - luma textures byte *draw_chars; // 8*8 graphic characters qpic_t *draw_disc; qpic_t *draw_backtile; int translate_texture; int char_texture; typedef struct { int texnum; float sl, tl, sh, th; } glpic_t; byte conback_buffer[sizeof(qpic_t) + sizeof(glpic_t)]; qpic_t *conback = (qpic_t *)&conback_buffer; // jkrige - .lit colored lights //int gl_lightmap_format = 4; // jkrige - .lit colored lights int gl_solid_format = 3; int gl_alpha_format = 4; // jkrige - change bilinear texture filtering to trilinear texture filtering //int gl_filter_min = GL_LINEAR_MIPMAP_NEAREST; //int gl_filter_max = GL_LINEAR; int gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; int gl_filter_max = GL_LINEAR_MIPMAP_LINEAR; // jkrige - change bilinear texture filtering to trilinear texture filtering float tex_mode = -1.0f; int texels; // jkrige - moved to glquake.h /*typedef struct { int texnum; qboolean tex_luma; // jkrige - luma textures char identifier[64]; int width, height; qboolean mipmap; } gltexture_t; #define MAX_GLTEXTURES 1024*/ // jkrige - moved to glquake.h gltexture_t gltextures[MAX_GLTEXTURES]; int numgltextures; void GL_Bind (int texnum) { if (gl_nobind.value) texnum = char_texture; if (currenttexture == texnum) return; currenttexture = texnum; #ifdef UQ_GLDEBUG // jkrige - opengl's bind function //#ifdef _WIN32 // bindTexFunc (GL_TEXTURE_2D, texnum); //#else glBindTexture(GL_TEXTURE_2D, texnum); //#endif // jkrige - opengl's bind function #endif // UQ_GLDEBUG } /* ============================================================================= scrap allocation Allocate all the little status bar obejcts into a single texture to crutch up stupid hardware / drivers ============================================================================= */ #define MAX_SCRAPS 2 #define BLOCK_WIDTH 256 #define BLOCK_HEIGHT 256 int scrap_allocated[MAX_SCRAPS][BLOCK_WIDTH]; byte scrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4]; qboolean scrap_dirty; int scrap_texnum; // 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 bestx; 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 ; idata; // load little ones into the scrap if (p->width < 64 && p->height < 64) { int x, y; int i, j, k; int texnum; texnum = Scrap_AllocBlock (p->width, p->height, &x, &y); scrap_dirty = true; k = 0; for (i=0 ; iheight ; i++) for (j=0 ; jwidth ; j++, k++) scrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k]; texnum += scrap_texnum; gl->texnum = texnum; gl->sl = (x+0.01)/(float)BLOCK_WIDTH; gl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH; gl->tl = (y+0.01)/(float)BLOCK_WIDTH; gl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH; pic_count++; pic_texels += p->width*p->height; } else { gl->texnum = GL_LoadPicTexture (p); gl->sl = 0; gl->sh = 1; gl->tl = 0; gl->th = 1; } return p; } /* ================ Draw_CachePic ================ */ qpic_t *Draw_CachePic (char *path) { cachepic_t *pic; int i; qpic_t *dat; glpic_t *gl; for (pic=menu_cachepics, i=0 ; iname)) return &pic->pic; if (menu_numcachepics == MAX_CACHED_PICS) Sys_Error ("menu_numcachepics == MAX_CACHED_PICS"); menu_numcachepics++; strcpy (pic->name, path); // // load the pic from disk // dat = (qpic_t *)COM_LoadTempFile (path); if (!dat) Sys_Error ("Draw_CachePic: failed to load %s", path); SwapPic (dat); // HACK HACK HACK --- we need to keep the bytes for // the translatable player picture just for the menu // configuration dialog if (!strcmp (path, "gfx/menuplyr.lmp")) memcpy (menuplyr_pixels, dat->data, dat->width*dat->height); pic->pic.width = dat->width; pic->pic.height = dat->height; gl = (glpic_t *)pic->pic.data; gl->texnum = GL_LoadPicTexture (dat); gl->sl = 0; gl->sh = 1; gl->tl = 0; gl->th = 1; return &pic->pic; } /*void Draw_CharToConback (int num, byte *dest) { int row, col; byte *source; int drawline; int x; row = num>>4; col = num&15; source = draw_chars + (row<<10) + (col<<3); drawline = 8; while (drawline--) { for (x=0 ; x<8 ; x++) if (source[x] != 255) dest[x] = 0x60 + source[x]; source += 128; dest += 320; } }*/ 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} }; /* =============== Draw_TextureMode_f =============== */ /*void Draw_TextureMode_f (void) { int i; gltexture_t *glt; if (Cmd_Argc() == 1) { for (i=0 ; i< 6 ; i++) if (gl_filter_min == modes[i].minimize) { Con_Printf ("%s\n", modes[i].name); return; } Con_Printf ("current filter is unknown???\n"); return; } for (i=0 ; i< 6 ; i++) { if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) ) break; } if (i == 6) { Con_Printf ("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 ; imipmap) { GL_Bind (glt->texnum); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); } } }*/ // jkrige - texture mode extern int solidskytexture; extern int alphaskytexture; void Draw_TextureMode_f (void) { int i, j; gltexture_t *glt; int AnisotropyModes = 0; if(tex_mode < 0.0f) tex_mode = gl_texturemode.value; if(tex_mode == gl_texturemode.value) return; if(floor(gl_texturemode.value) < 0.0f | gl_texturemode.value != floor(gl_texturemode.value)) { Con_Printf ("unknown texture mode\n"); Cvar_Set ("gl_texturemode", "2"); return; } i = 0; if(gl_texturemode.value == 1.0f) i = 3; if(gl_texturemode.value >= 2.0f) i = 5; if(anisotropic_ext == true) AnisotropyModes = (int)floor((log(maximumAnisotrophy)/log(2.0f)) + 0.5f); else AnisotropyModes = 0; if(anisotropic_ext == false) { if (gl_texturemode.value > 2.0f) { Con_Printf ("unknown texture mode\n"); Cvar_Set ("gl_texturemode", "2"); return; } } if(anisotropic_ext == true) { if (gl_texturemode.value > (2.0f + (float)AnisotropyModes)) { Con_Printf ("unknown texture mode\n"); Cvar_SetValue ("gl_texturemode", (2.0f + (float)AnisotropyModes)); return; } } gl_filter_min = modes[i].minimize; gl_filter_max = modes[i].maximize; #ifdef UQ_GLDEBUG // change all the existing mipmap texture objects for (j=0, glt=gltextures ; jmipmap) { GL_Bind (glt->texnum); if(gl_texturemode.value <= 2.0f) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); if(anisotropic_ext == true) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); } // jkrige - anisotropic filtering if(gl_texturemode.value > 2.0f && anisotropic_ext == true) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, pow(2.0f, gl_texturemode.value - 2.0f)); // jkrige - anisotropic filtering // jkrige - luma textures if(glt->tex_luma == true) { GL_Bind (JK_LUMA_TEX + glt->texnum); if(gl_texturemode.value <= 2.0f) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); if(anisotropic_ext == true) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); } // jkrige - anisotropic filtering if(gl_texturemode.value > 2.0f && anisotropic_ext == true) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, pow(2.0f, gl_texturemode.value - 2.0f)); // jkrige - anisotropic filtering } // jkrige - luma textures } } // sky textures if(gl_texturemode.value == 0.0f) { GL_Bind (solidskytexture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_Bind (alphaskytexture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } else { GL_Bind (solidskytexture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL_Bind (alphaskytexture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } // sky textures #endif // UQ_GLDEBUG tex_mode = gl_texturemode.value; } // jkrige - texture mode /* =============== Draw_Init =============== */ void Draw_Init (void) { int i; qpic_t *cb; byte *dest, *src; int x, y; char ver[40]; glpic_t *gl; int start; byte *ncdata; int f, fstep; Cvar_RegisterVariable (&gl_nobind); Cvar_RegisterVariable (&gl_max_size); Cvar_RegisterVariable (&gl_picmip); // jkrige - luma textures Cvar_RegisterVariable (&gl_lumatex_render); // jkrige - luma textures // 3dfx can only handle 256 wide textures if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) || strstr((char *)gl_renderer, "Glide")) Cvar_Set ("gl_max_size", "256"); //Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f); // jkrige - texture mode // load the console background and the charset // by hand, because we need to write the version // string into the background before turning // it into a texture draw_chars = W_GetLumpName ("conchars"); for (i=0 ; i<256*64 ; i++) if (draw_chars[i] == 0) draw_chars[i] = 255; // proper transparent color // now turn them into textures // jkrige - external texture loading //char_texture = GL_LoadTexture ("charset", 128, 128, draw_chars, false, true); char_texture = GL_LoadTexture ("charset", "lump", 128, 128, draw_chars, false, true, 1); // jkrige - external texture loading //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); start = Hunk_LowMark(); cb = (qpic_t *)COM_LoadTempFile ("gfx/conback.lmp"); if (!cb) Sys_Error ("Couldn't load gfx/conback.lmp"); SwapPic (cb); // jkrige - print version info to the console // hack the version number directly into the pic /*#if defined(__linux__) sprintf (ver, "(Linux %2.2f, gl %4.2f) %4.2f", (float)LINUX_VERSION, (float)GLQUAKE_VERSION, (float)VERSION); #else sprintf (ver, "(gl %4.2f) %4.2f", (float)GLQUAKE_VERSION, (float)VERSION); #endif dest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver); y = strlen(ver); for (x=0 ; xwidth = vid.conwidth; conback->height = vid.conheight; // scale console to vid size dest = ncdata = Hunk_AllocName(vid.conwidth * vid.conheight, "conback"); for (y=0 ; ydata + cb->width * (y*cb->height/vid.conheight); if (vid.conwidth == cb->width) memcpy (dest, src, vid.conwidth); else { f = 0; fstep = cb->width*0x10000/vid.conwidth; for (x=0 ; x>16]; f += fstep; dest[x+1] = src[f>>16]; f += fstep; dest[x+2] = src[f>>16]; f += fstep; dest[x+3] = src[f>>16]; f += fstep; } } } #else conback->width = cb->width; conback->height = cb->height; ncdata = cb->data; #endif gl = (glpic_t *)conback->data; // jkrige - external texture loading //gl->texnum = GL_LoadTexture ("conback", conback->width, conback->height, ncdata, false, false); gl->texnum = GL_LoadTexture ("conback", "lump", conback->width, conback->height, ncdata, false, false, 1); // jkrige - external texture loading #ifdef UQ_GLDEBUG glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); #endif // UQ_GLDEBUG gl->sl = 0; gl->sh = 1; gl->tl = 0; gl->th = 1; conback->width = vid.width; conback->height = vid.height; // free loaded console Hunk_FreeToLowMark(start); // save a texture slot for translated picture translate_texture = texture_extension_number++; // save slots for scraps scrap_texnum = texture_extension_number; texture_extension_number += MAX_SCRAPS; // // get the other pics we need // draw_disc = Draw_PicFromWad ("disc"); draw_backtile = Draw_PicFromWad ("backtile"); } /* ================ Draw_Character Draws one 8*8 graphics character with 0 being transparent. It can be clipped to the top of the screen to allow the console to be smoothly scrolled off. ================ */ void Draw_Character (int x, int y, int num) { #ifdef UQ_GLDEBUG byte *dest; byte *source; unsigned short *pusdest; int drawline; int row, col; float frow, fcol, size; if (num == 32) return; // space num &= 255; if (y <= -8) return; // totally off screen row = num>>4; col = num&15; frow = row*0.0625; fcol = col*0.0625; size = 0.0625; GL_Bind (char_texture); glBegin (GL_QUADS); glTexCoord2f (fcol, frow); glVertex2f (x, y); glTexCoord2f (fcol + size, frow); glVertex2f (x+8, y); glTexCoord2f (fcol + size, frow + size); glVertex2f (x+8, y+8); glTexCoord2f (fcol, frow + size); glVertex2f (x, y+8); glEnd (); #endif // UQ_GLDEBUG } /* ================ Draw_String ================ */ void Draw_String (int x, int y, char *str) { while (*str) { Draw_Character (x, y, *str); str++; x += 8; } } /* ================ Draw_DebugChar Draws a single character directly to the upper right corner of the screen. This is for debugging lockups by drawing different chars in different parts of the code. ================ */ void Draw_DebugChar (char num) { } /* ============= Draw_AlphaPic ============= */ void Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha) { #ifdef UQ_GLDEBUG byte *dest, *source; unsigned short *pusdest; int v, u; glpic_t *gl; if (scrap_dirty) Scrap_Upload (); gl = (glpic_t *)pic->data; glDisable(GL_ALPHA_TEST); glEnable (GL_BLEND); // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // glCullFace(GL_FRONT); glColor4f (1,1,1,alpha); GL_Bind (gl->texnum); glBegin (GL_QUADS); glTexCoord2f (gl->sl, gl->tl); glVertex2f (x, y); glTexCoord2f (gl->sh, gl->tl); glVertex2f (x+pic->width, y); glTexCoord2f (gl->sh, gl->th); glVertex2f (x+pic->width, y+pic->height); glTexCoord2f (gl->sl, gl->th); glVertex2f (x, y+pic->height); glEnd (); glColor4f (1,1,1,1); glEnable(GL_ALPHA_TEST); glDisable (GL_BLEND); #endif } /* ============= Draw_Pic ============= */ void Draw_Pic (int x, int y, qpic_t *pic) { #ifdef UQ_GLDEBUG byte *dest, *source; unsigned short *pusdest; int v, u; glpic_t *gl; if (scrap_dirty) Scrap_Upload (); gl = (glpic_t *)pic->data; glColor4f (1,1,1,1); GL_Bind (gl->texnum); glBegin (GL_QUADS); glTexCoord2f (gl->sl, gl->tl); glVertex2f (x, y); glTexCoord2f (gl->sh, gl->tl); glVertex2f (x+pic->width, y); glTexCoord2f (gl->sh, gl->th); glVertex2f (x+pic->width, y+pic->height); glTexCoord2f (gl->sl, gl->th); glVertex2f (x, y+pic->height); glEnd (); #endif } /* ============= Draw_TransPic ============= */ void Draw_TransPic (int x, int y, qpic_t *pic) { byte *dest, *source, tbyte; unsigned short *pusdest; int v, u; if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 || (unsigned)(y + pic->height) > vid.height) { Sys_Error ("Draw_TransPic: bad coordinates"); } Draw_Pic (x, y, pic); } /* ============= Draw_TransPicTranslate Only used for the player color selection menu ============= */ void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation) { #ifdef UQ_GLDEBUG int v, u, c; unsigned trans[64*64], *dest; byte *src; int p; GL_Bind (translate_texture); c = pic->width * pic->height; dest = trans; for (v=0 ; v<64 ; v++, dest += 64) { src = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width]; for (u=0 ; u<64 ; u++) { p = src[(u*pic->width)>>6]; if (p == 255) dest[u] = p; else dest[u] = d_8to24table[translation[p]]; } } glTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans); // jkrige - use "point sampled" texture mode glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // jkrige - use "point sampled" texture mode glColor3f (1,1,1); glBegin (GL_QUADS); glTexCoord2f (0, 0); glVertex2f (x, y); glTexCoord2f (1, 0); glVertex2f (x+pic->width, y); glTexCoord2f (1, 1); glVertex2f (x+pic->width, y+pic->height); glTexCoord2f (0, 1); glVertex2f (x, y+pic->height); glEnd (); #endif // UQ_GLDEBUG } // jkrige - print version info to the console void Console_Print (int cx, int cy, char *str) { while (*str) { Draw_Character (cx, cy, ((unsigned char)(*str))+256); str++; cx += 8; } } // jkrige - print version info to the console /* ================ Draw_ConsoleBackground ================ */ void Draw_ConsoleBackground (int lines) { // jkrige - removed alpha console background //int y = (vid.height * 3) >> 2; // jkrige - removed alpha console background // jkrige - print version info to the console int ver_x, ver_y; char engineversion[32]; sprintf(engineversion, "UQE Quake %.2f", QUAKE_VERSION); ver_x = (int)vid.width - (strlen(engineversion)*8) /*- 8*/; ver_y = (int)vid.height - 8; //- 16; // jkrige - print version info to the console // jkrige - removed alpha console background //if (lines > y) // Draw_Pic(0, lines - vid.height, conback); //else // Draw_AlphaPic (0, lines - vid.height, conback, (float)(1.2 * lines)/y); Draw_Pic(0, lines - vid.height, conback); // jkrige - removed alpha console background // jkrige - print version info to the console Console_Print(ver_x, lines - (int)vid.height + ver_y, engineversion); // jkrige - print version info to the console } /* ============= Draw_TileClear This repeats a 64*64 tile graphic to fill the screen around a sized down refresh window. ============= */ void Draw_TileClear (int x, int y, int w, int h) { #ifdef UQ_GLDEBUG glColor3f (1,1,1); GL_Bind (*(int *)draw_backtile->data); glBegin (GL_QUADS); glTexCoord2f (x/64.0, y/64.0); glVertex2f (x, y); glTexCoord2f ( (x+w)/64.0, y/64.0); glVertex2f (x+w, y); glTexCoord2f ( (x+w)/64.0, (y+h)/64.0); glVertex2f (x+w, y+h); glTexCoord2f ( x/64.0, (y+h)/64.0 ); glVertex2f (x, y+h); glEnd (); #endif // UQ_GLDEBUG } /* ============= Draw_Fill Fills a box of pixels with a single color ============= */ void Draw_Fill (int x, int y, int w, int h, int c) { #ifdef UQ_GLDEBUG glDisable (GL_TEXTURE_2D); glColor3f (host_basepal[c*3]/255.0, host_basepal[c*3+1]/255.0, host_basepal[c*3+2]/255.0); glBegin (GL_QUADS); glVertex2f (x,y); glVertex2f (x+w, y); glVertex2f (x+w, y+h); glVertex2f (x, y+h); glEnd (); glColor3f (1,1,1); glEnable (GL_TEXTURE_2D); #endif } //============================================================================= /* ================ Draw_FadeScreen ================ */ void Draw_FadeScreen (void) { #ifdef UQ_GLDEBUG glEnable (GL_BLEND); glDisable (GL_TEXTURE_2D); glColor4f (0, 0, 0, 0.8); glBegin (GL_QUADS); glVertex2f (0,0); glVertex2f (vid.width, 0); glVertex2f (vid.width, vid.height); glVertex2f (0, vid.height); glEnd (); glColor4f (1,1,1,1); glEnable (GL_TEXTURE_2D); glDisable (GL_BLEND); //Sbar_Changed(); // jkrige - always draw sbar #endif } //============================================================================= /* ================ Draw_BeginDisc Draws the little blue disc in the corner of the screen. Call before beginning any disc IO. ================ */ void Draw_BeginDisc (void) { #ifdef UQ_GLDEBUG if (!draw_disc) return; glDrawBuffer (GL_FRONT); Draw_Pic (vid.width - 24, 0, draw_disc); glDrawBuffer (GL_BACK); #endif } /* ================ Draw_EndDisc Erases the disc icon. Call after completing any disc IO ================ */ void Draw_EndDisc (void) { } /* ================ GL_Set2D Setup as if the screen was 320*200 ================ */ void GL_Set2D (void) { #ifdef UQ_GLDEBUG glViewport (glx, gly, glwidth, glheight); glMatrixMode(GL_PROJECTION); glLoadIdentity (); glOrtho (0, vid.width, vid.height, 0, -99999, 99999); glMatrixMode(GL_MODELVIEW); glLoadIdentity (); glDisable (GL_DEPTH_TEST); glDisable (GL_CULL_FACE); glDisable (GL_BLEND); glEnable (GL_ALPHA_TEST); // glDisable (GL_ALPHA_TEST); glColor4f (1,1,1,1); #endif } //==================================================================== /* ================ GL_FindTexture ================ */ int GL_FindTexture (char *identifier) { int i; gltexture_t *glt; for (i=0, glt=gltextures ; iidentifier)) return gltextures[i].texnum; } return -1; } /* ================ GL_ResampleTexture ================ */ void GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out, int outwidth, int outheight) { int i, j; unsigned *inrow; unsigned frac, fracstep; fracstep = inwidth*0x10000/outwidth; for (i=0 ; i> 1; for (j=0 ; j>16]; frac += fracstep; out[j+1] = inrow[frac>>16]; frac += fracstep; out[j+2] = inrow[frac>>16]; frac += fracstep; out[j+3] = inrow[frac>>16]; frac += fracstep; } } } /* ================ GL_Resample8BitTexture -- JACK ================ */ void GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out, int outwidth, int outheight) { int i, j; unsigned char *inrow; unsigned frac, fracstep; fracstep = inwidth*0x10000/outwidth; for (i=0 ; i> 1; for (j=0 ; j>16]; frac += fracstep; out[j+1] = inrow[frac>>16]; frac += fracstep; out[j+2] = inrow[frac>>16]; frac += fracstep; out[j+3] = inrow[frac>>16]; frac += fracstep; } } } /* ================ GL_MipMap Operates in place, quartering the size of the texture ================ */ void GL_MipMap (byte *in, int width, int height) { int i, j; byte *out; width <<=2; height >>= 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_MipMap8Bit Mipping for 8 bit textures ================ */ void GL_MipMap8Bit (byte *in, int width, int height) { int i, j; unsigned short r,g,b; byte *out, *at1, *at2, *at3, *at4; // width <<=2; height >>= 1; out = in; for (i=0 ; i>=5; g = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5; b = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5; out[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)]; } } } /* =============== GL_Upload32 =============== */ void GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap, qboolean alpha) { #ifdef UQ_GLDEBUG int samples; // jkrige - doubled textures //static unsigned scaled[1024 * 512]; // [512*256]; static unsigned scaled[2048 * 2048]; // jkrige - doubled textures int scaled_width, scaled_height; // jkrige - anisotropic filtering int i = 3; int AnisotropyModes = 0; // jkrige - anisotropic filtering // jkrige - non power of two //for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1); //for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1); if(npow2_ext == true && gl_texture_non_power_of_two.value == 1.0f /*&& !mipmap*/) { scaled_width = width; scaled_height = height; } else { for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1); for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1); } // jkrige - non power of two if ((scaled_width >> (int)gl_picmip.value) && (scaled_height >> (int)gl_picmip.value)) { scaled_width >>= (int)gl_picmip.value; scaled_height >>= (int)gl_picmip.value; } //scaled_width >>= (int)gl_picmip.value; //scaled_height >>= (int)gl_picmip.value; if (scaled_width > gl_max_size.value) scaled_width = gl_max_size.value; if (scaled_height > gl_max_size.value) scaled_height = gl_max_size.value; if (scaled_width * scaled_height > sizeof(scaled)/4) Sys_Error ("GL_LoadTexture: too big"); samples = alpha ? gl_alpha_format : gl_solid_format; #if 0 if (mipmap) gluBuild2DMipmaps (GL_TEXTURE_2D, samples, width, height, GL_RGBA, GL_UNSIGNED_BYTE, trans); else if (scaled_width == width && scaled_height == height) glTexImage2D (GL_TEXTURE_2D, 0, samples, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans); else { gluScaleImage (GL_RGBA, width, height, GL_UNSIGNED_BYTE, trans, scaled_width, scaled_height, GL_UNSIGNED_BYTE, scaled); glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); } #else texels += scaled_width * scaled_height; if (scaled_width == width && scaled_height == height) { if (!mipmap) { glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); goto done; } memcpy (scaled, data, width*height*4); } else GL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height); glTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); if (mipmap) { int miplevel; miplevel = 0; while (scaled_width > 1 || scaled_height > 1) { GL_MipMap ((byte *)scaled, scaled_width, scaled_height); // jkrige - non power of two scaled_width >>= 1; scaled_height >>= 1; /*if(npow2_ext == true && gl_texture_non_power_of_two.value == 1.0f && !mipmap) { scaled_width = (int)floor (width / pow(2, miplevel+1)); scaled_height = (int)floor (height / pow (2, miplevel+1)); } else { scaled_width >>= 1; scaled_height >>= 1; }*/ // jkrige - non power of two if (scaled_width < 1) scaled_width = 1; if (scaled_height < 1) scaled_height = 1; miplevel++; glTexImage2D (GL_TEXTURE_2D, miplevel, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled); } } done: ; #endif // jkrige - anisotropic filtering if (mipmap) { // jkrige - texture modes if(floor(gl_texturemode.value) < 0.0f | gl_texturemode.value != floor(gl_texturemode.value)) { Con_Printf ("unknown texture mode\n"); Cvar_Set ("gl_texturemode", "2"); } if(gl_texturemode.value == 0.0f) i = 0; if(gl_texturemode.value == 1.0f) i = 3; if(gl_texturemode.value >= 2.0f) i = 5; if(anisotropic_ext == true) AnisotropyModes = (int)floor((log(maximumAnisotrophy)/log(2.0f)) + 0.5f); else AnisotropyModes = 0; if(anisotropic_ext == false) { if (gl_texturemode.value > 2.0f) { Con_Printf ("unknown texture mode\n"); Cvar_Set ("gl_texturemode", "2"); return; } } if(anisotropic_ext == true) { if (gl_texturemode.value > (2.0f + (float)AnisotropyModes)) { Con_Printf ("unknown texture mode\n"); Cvar_SetValue ("gl_texturemode", (2.0f + (float)AnisotropyModes)); return; } } gl_filter_min = modes[i].minimize; gl_filter_max = modes[i].maximize; if(gl_texturemode.value <= 2.0f) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); if(anisotropic_ext == true) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); } // jkrige - anisotropic filtering if(gl_texturemode.value > 2.0f && anisotropic_ext == true) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, pow(2.0f, gl_texturemode.value - 2.0f)); // jkrige - anisotropic filtering // jkrige - texture modes /* glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); // jkrige - anisotropic filtering for (i = 0; i < 6; i++) { if (gl_filter_min == modes[i].minimize) break; } if(i == 5 && anisotropic_ext == true) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maximumAnisotrophy); // jkrige - anisotropic filtering */ } else { // jkrige - scale2d glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // jkrige - scale2d //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR /*gl_filter_max*/); // jkrige - change bilinear texture filtering to trilinear texture filtering //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR /*gl_filter_max*/); // jkrige - change bilinear texture filtering to trilinear texture filtering } // jkrige - anisotropic filtering /*if (mipmap) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); } else { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); }*/ #endif // UQ_GLDEBUG } // jkrige - no 8bit palette extensions /*void GL_Upload8_EXT (byte *data, int width, int height, qboolean mipmap, qboolean alpha) { int i, s; qboolean noalpha; int p; static unsigned j; int samples; static unsigned char scaled[1024*512]; // [512*256]; int scaled_width, scaled_height; s = width*height; // if there are no transparent pixels, make it a 3 component // texture even if it was specified as otherwise if (alpha) { noalpha = true; for (i=0 ; i>= (int)gl_picmip.value; scaled_height >>= (int)gl_picmip.value; if (scaled_width > gl_max_size.value) scaled_width = gl_max_size.value; if (scaled_height > gl_max_size.value) scaled_height = gl_max_size.value; if (scaled_width * scaled_height > sizeof(scaled)) Sys_Error ("GL_LoadTexture: too big"); samples = 1; // alpha ? gl_alpha_format : gl_solid_format; texels += scaled_width * scaled_height; if (scaled_width == width && scaled_height == height) { if (!mipmap) { glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX , GL_UNSIGNED_BYTE, data); goto done; } memcpy (scaled, data, width*height); } else GL_Resample8BitTexture (data, width, height, scaled, scaled_width, scaled_height); glTexImage2D (GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled); if (mipmap) { int miplevel; miplevel = 0; while (scaled_width > 1 || scaled_height > 1) { GL_MipMap8Bit ((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++; glTexImage2D (GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, scaled); } } done: ; if (mipmap) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); } else { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); } }*/ // jkrige - no 8bit palette extensions // jkrige - doubled textures //static unsigned trans[640 * 480]; // jkrige - FIXME, temporary static unsigned trans[2048 * 2048]; // jkrige - doubled textures /* =============== GL_Upload8 =============== */ void GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean alpha) { int i, s; qboolean noalpha; int p; //static unsigned trans[640*480]; // FIXME, temporary // jkrige - doubled textures byte *dtdata; int x, y; if (mipmap) { width *= 2; height *= 2; s = width * height; dtdata = malloc(s); for (y = 0; y < height / 2; y++) { for (x = 0; x < width / 2; x++) { dtdata[(y * (width * 2)) + (x * 2) + 0] = data[(y * (width / 2)) + x]; dtdata[(y * (width * 2)) + (x * 2) + 1] = data[(y * (width / 2)) + x]; dtdata[(y * (width * 2)) + (x * 2) + 0 + width] = data[(y * (width / 2)) + x]; dtdata[(y * (width * 2)) + (x * 2) + 1 + width] = data[(y * (width / 2)) + x]; } } } else { s = width * height; dtdata = data; } //s = width * height; // jkrige - doubled textures // if there are no transparent pixels, make it a 3 component // texture even if it was specified as otherwise if (alpha) { noalpha = true; for (i=0 ; iidentifier)) { if (width != glt->width || height != glt->height) Sys_Error ("GL_LoadTexture: cache mismatch"); return gltextures[i].texnum; } } } //else { // jkrige - threewave? glt = &gltextures[numgltextures]; numgltextures++; //} strcpy (glt->identifier, identifier); glt->texnum = texture_extension_number; glt->width = width; glt->height = height; glt->mipmap = mipmap; GL_Bind(texture_extension_number ); GL_Upload8 (data, width, height, mipmap, alpha); texture_extension_number++; return texture_extension_number-1; }*/ int lhcsumtable[256]; int GL_LoadTexture (char *identifier, char *textype, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel) { #ifdef UQ_GLDEBUG //qboolean noalpha; int i, /*p,*/ s, lhcsum; gltexture_t *glt; // jkrige - fullbright pixels byte *data2 = data; // jkrige - fullbright pixels // occurances. well this isn't exactly a checksum, it's better than that but // not following any standards. lhcsum = 0; s = width*height*bytesperpixel; //s = width*height; for (i = 0;i < 256;i++) lhcsumtable[i] = i + 1; for (i = 0;i < s;i++) lhcsum += (lhcsumtable[data[i] & 255]++); // see if the texture is allready present if (identifier[0]) { for (i=0, glt=gltextures ; i < numgltextures ; i++, glt++) { if (!strcmp (identifier, glt->identifier)) { if (lhcsum != glt->lhcsum || width != glt->width || height != glt->height) { Con_DPrintf("GL_LoadTexture: cache mismatch\n"); goto GL_LoadTexture_setup; } return glt->texnum; } } } // whoever at id or threewave must've been half asleep... glt = &gltextures[numgltextures]; numgltextures++; strcpy (glt->identifier, identifier); glt->texnum = texture_extension_number; texture_extension_number++; GL_LoadTexture_setup: glt->lhcsum = lhcsum; glt->width = width; glt->height = height; glt->mipmap = mipmap; // jkrige - luma textures (reset) glt->tex_luma = false; glt->tex_luma8bit = false; // jkrige - luma textures (reset) if (!isDedicated) { GL_Bind(glt->texnum); //if (strcmp (textype, "bloom")) { if (bytesperpixel == 1) { GL_Upload8 (data, width, height, mipmap, alpha); } else if (bytesperpixel == 3 | bytesperpixel == 4) { if(image_alpha == 3) GL_Upload32 ((void *)data, width, height, mipmap, false); else GL_Upload32 ((void *)data, width, height, mipmap, true); } else Sys_Error("GL_LoadTexture: unknown bytes per pixel\n"); } // jkrige - reset external image image_width = 0; image_height = 0; image_bits = 8; image_alpha = 3; // jkrige - reset external image // jkrige - luma textures if (!strcmp (textype, "texture")) { char *ch_dot = strrchr(identifier, '.'); if (ch_dot != NULL) { char *ident; char ch_name[MAX_PATH]; byte *lumadata; i = 0; ident = identifier; while (*identifier && *identifier != '.') ch_name[i++] = *identifier++; ch_name[i++] = 0; strcat(ch_name, "_luma"); strcat(ch_name, ch_dot); identifier = ident; if ((lumadata = LoadImagePixels (ch_name, false))) { GL_Bind(JK_LUMA_TEX + glt->texnum); GL_Upload32((unsigned int *)lumadata, width, height, mipmap, true); free(lumadata); glt->tex_luma = true; } } } // jkrige - luma textures // jkrige - fullbright pixels if ((!strcmp(textype, "texture") || !strcmp(textype, "skin")) && bytesperpixel == 1) { // if fullbright pixels are detected a new texture will // be generated and it will be used asif its a luma texture qboolean fullbright; byte *fbdata; fbdata = malloc(width * height * 4); if (GL_FullbrightTexture(data, fbdata, width, height) == true) { GL_Bind(JK_LUMA_TEX + glt->texnum); GL_Upload32((unsigned int *)fbdata, width, height, mipmap, alpha); glt->tex_luma = true; glt->tex_luma8bit = true; } if (fbdata) free(fbdata); } // jkrige - fullbright pixels glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } return glt->texnum; #endif // UQ_GLDEBUG } // jkrige - memleak & texture mismatch /* ================ GL_LoadPicTexture ================ */ int GL_LoadPicTexture (qpic_t *pic) { int i; // jkrige - external texture loading //i = GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true); i = GL_LoadTexture ("", "", pic->width, pic->height, pic->data, false, true, 1); // jkrige - external texture loading // jkrige - scale2d //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // jkrige - scale2d return i; } // jkrige - external texture loading int image_width; int image_height; int image_bits; int image_alpha; byte Convert24to8(byte *palette, byte Red, byte Green, byte Blue) { int i; for(i=0; i<768; i+=3) { if(palette[i] == Red && palette[i+1] == Green && palette[i+2] == Blue) return 255-(i/3); } return 0; } /* ======== LoadJPG ======== */ byte *LoadJPG ( const char *filename) { /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ /* This struct represents a JPEG error handler. It is declared separately * because applications often want to supply a specialized error handler * (see the second half of this file for an example). But here we just * take the easy way out and use the standard error handler, which will * print a message on stderr and call exit() if compression fails. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct jpeg_error_mgr jerr; /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ unsigned char *out; byte *fbuffer; byte *bbuf; /* In this example we want to open the input file before doing anything else, * so that the setjmp() error recovery below can assume the file is open. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to read binary files. */ // jkrige - pk3 file support int len; FILE *f; byte *pic; // // load the file // len = COM_FOpenFile (( char * )filename, &f); if(len < 1) return NULL; fbuffer = COM_FReadFile(f, len); if (!fbuffer) return NULL; pic = NULL; // jkrige - pk3 file support /* Step 1: allocate and initialize JPEG decompression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src(&cinfo, fbuffer); /* Step 3: read file parameters with jpeg_read_header() */ (void) jpeg_read_header(&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. * In this example, we need to make an output work buffer of the right size. */ /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; out = malloc(cinfo.output_width*cinfo.output_height*cinfo.output_components); // jkrige // *pic = out; // *width = cinfo.output_width; // *height = cinfo.output_height; pic = out; image_width = cinfo.image_width; image_height = cinfo.image_height; // jkrige /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ while (cinfo.output_scanline < cinfo.output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ bbuf = ((out+(row_stride*cinfo.output_scanline))); buffer = &bbuf; (void) jpeg_read_scanlines(&cinfo, buffer, 1); } // clear all the alphas to 255 { int i, j; byte *buf; buf = pic; j = cinfo.output_width * cinfo.output_height * 4; for ( i = 3 ; i < j ; i+=4 ) { buf[i] = 255; } } /* Step 7: Finish decompression */ (void) jpeg_finish_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress(&cinfo); /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ image_bits = 32; image_alpha = 3; free (fbuffer); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ /* And we're done! */ return pic; } /* ============= 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; TargaHeader targa_header; int fgetLittleShort (FILE *f) { byte b1, b2; b1 = fgetc(f); b2 = fgetc(f); return (short)(b1 + b2*256); } int fgetLittleLong (FILE *f) { byte b1, b2, b3, b4; b1 = fgetc(f); b2 = fgetc(f); b3 = fgetc(f); b4 = fgetc(f); return b1 + (b2<<8) + (b3<<16) + (b4<<24); } /* ======== LoadTGA ======== */ byte *LoadTGA ( const char *name) { int columns, rows, numPixels; byte *pixbuf; int row, column; byte *buf_p; byte *buffer; TargaHeader targa_header; byte *targa_rgba; // jkrige - bitsperpixel check int i; // jkrige - bitsperpixel check // jkrige - pk3 file support int len; FILE *f; byte *pic; // jkrige - pk3 file support // *pic = NULL; // jkrige pic = NULL; buffer = NULL; // // load the file // len = COM_FOpenFile (( char * )name, &f); if(len < 1) return NULL; buffer = COM_FReadFile(f, len); if (!buffer) return NULL; buf_p = buffer; targa_header.id_length = *buf_p++; targa_header.colormap_type = *buf_p++; targa_header.image_type = *buf_p++; targa_header.colormap_index = LittleShort ( *(short *)buf_p ); buf_p += 2; targa_header.colormap_length = LittleShort ( *(short *)buf_p ); 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++; if (targa_header.image_type!=2 && targa_header.image_type!=10 && targa_header.image_type != 3 ) { Sys_Error ("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); } if ( targa_header.colormap_type != 0 ) { Sys_Error ("LoadTGA: colormaps not supported\n" ); } if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) { Sys_Error ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); } columns = targa_header.width; rows = targa_header.height; numPixels = columns * rows; // jkrige /*if (width) *width = columns; if (height) *height = rows;*/ image_width = columns; image_height = rows; // jkrige targa_rgba = malloc (numPixels*4); // *pic = targa_rgba; // jkrige 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 || targa_header.image_type == 3 ) { // Uncompressed RGB or gray scale image 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:; } } //#if 0 // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs // bk0101024 - fix from Leonardo // bit 5 set => top-down if (targa_header.attributes & 0x20) { unsigned char *flip = (unsigned char*)malloc (columns*4); unsigned char *src, *dst; for (row = 0; row < rows/2; row++) { src = targa_rgba + row * 4 * columns; dst = targa_rgba + (rows - row - 1) * 4 * columns; memcpy (flip, src, columns*4); memcpy (src, dst, columns*4); memcpy (dst, flip, columns*4); } free (flip); } //#endif // instead we just print a warning //if (targa_header.attributes & 0x20) //{ // Con_Printf("WARNING: '%s' TGA file header declares top-down image, ignoring\n", name); //} // jkrige - bitsperpixel check image_bits = 32; image_alpha = gl_solid_format; for (i = 0;i < image_width*image_height;i++) { if (targa_rgba[i*4+3] < 255) { image_alpha = gl_alpha_format; break; } } // jkrige - bitsperpixel check free (buffer); return pic; } byte* LoadImagePixels (char* filename, qboolean complain) { char basename[128], name[128]; byte *data; COM_StripExtension(filename, basename); // strip the extension to allow more filetypes sprintf (name, "%s.tga", basename); data = LoadTGA(name); if(data) return data; sprintf (name, "%s.jpg", basename); data = LoadJPG(name); if(data) return data; if (complain) Con_Printf ("Couldn't load %s\n", name); return NULL; } int LoadTextureImage (char* filename, char *textype, int matchwidth, int matchheight, qboolean complain, qboolean mipmap) { int texnum; int i; qboolean alpha; byte *data; if (!(data = LoadImagePixels (filename, complain))) return 0; if(image_alpha == 4) alpha = true; else alpha = false; if(image_bits != 32) texnum = GL_LoadTexture (filename, textype, image_width, image_height, data, mipmap, true, 1); else texnum = GL_LoadTexture (filename, textype, image_width, image_height, data, mipmap, alpha, image_alpha); if (data) free(data); return texnum; } // jkrige - external texture loading // jkrige - remove multitexture /*static GLenum oldtarget = TEXTURE0_SGIS; void GL_SelectTexture (GLenum target) { if (!gl_mtexable) return; qglSelectTextureSGIS(target); if (target == oldtarget) return; cnttextures[oldtarget-TEXTURE0_SGIS] = currenttexture; currenttexture = cnttextures[target-TEXTURE0_SGIS]; oldtarget = target; }*/ // jkrige - remove multitexture