/* 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_misc.c #include "r_local.h" #ifdef __unix__ #include #else #include "include/jpeglib.h" //Heffo - JPEG Screenshots #endif /* ================== R_InitParticleTexture ================== */ //Knightmare- new missing texture byte notexture[16][16] = { {025,025,025,025,025,025,025,025,255,255,255,255,255,255,255,255}, {025,025,025,025,025,025,025,025,255,255,255,255,255,255,255,255}, {025,025,025,025,025,025,025,025,255,255,255,255,255,255,255,255}, {025,025,025,025,025,025,025,025,255,255,255,255,255,255,255,255}, {025,025,025,025,025,025,025,025,255,255,255,255,255,255,255,255}, {025,025,025,025,025,025,025,025,255,255,255,255,255,255,255,255}, {025,025,025,025,025,025,025,025,255,255,255,255,255,255,255,255}, {025,025,025,025,025,025,025,025,255,255,255,255,255,255,255,255}, {255,255,255,255,255,255,255,255,025,025,025,025,025,025,025,025}, {255,255,255,255,255,255,255,255,025,025,025,025,025,025,025,025}, {255,255,255,255,255,255,255,255,025,025,025,025,025,025,025,025}, {255,255,255,255,255,255,255,255,025,025,025,025,025,025,025,025}, {255,255,255,255,255,255,255,255,025,025,025,025,025,025,025,025}, {255,255,255,255,255,255,255,255,025,025,025,025,025,025,025,025}, {255,255,255,255,255,255,255,255,025,025,025,025,025,025,025,025}, {255,255,255,255,255,255,255,255,025,025,025,025,025,025,025,025}, }; void R_SetParticlePicture (int num, char *name) { r_particletextures[num] = GL_FindImage(name, it_part); if (!r_particletextures[num]) r_particletextures[num] = r_notexture; } image_t *LoadPartImg (char *name) { image_t *image = GL_FindImage(name, it_part); if (!image) image = r_notexture; return image; } void R_InitParticleTexture (void) { int x,y; byte notex[16][16][4]; #ifdef ROQ_SUPPORT byte data2D[256*256*4]; #endif // ROQ_SUPPORT // use notexture array for bad textures for (x=0; x<16; x++) //was 8 { for (y=0; y<16; y++) //was 8 { notex[y][x][0] = notexture[x][y]; // red checkers! notex[y][x][1] = 0; notex[y][x][2] = 0; notex[y][x][3] = 255; } } r_notexture = GL_LoadPic ("***r_notexture***", (byte *)notex, 16, 16, it_wall, 32); #ifdef ROQ_SUPPORT // Raw texture memset(data2D, 255, 256*256*4); r_rawtexture = GL_LoadPic ("***r_rawtexture***", data2D, 256, 256, it_pic, 32); #endif // ROQ_SUPPORT // Knightmare- Psychospaz's emvmapping r_envmappic = GL_FindImage ("gfx/envmap.tga", it_wall); if (!r_envmappic) r_envmappic = r_notexture; r_spheremappic = GL_FindImage ("gfx/spheremap.tga", it_wall); if (!r_spheremappic) r_spheremappic = r_notexture; r_shelltexture = GL_FindImage ("gfx/shell_generic.tga", it_wall); if (!r_shelltexture) r_shelltexture = r_notexture; r_particlebeam = LoadPartImg ("gfx/particles/beam.tga"); //Knightmare- Psychospaz's enhanced particles for (x=0 ; x> 16; if (xi != oldx) { in += (xi - oldx) * 3; oldx = xi; } if (xi < endx) { l2 = f & 0xFFFF; l1 = 0x10000 - l2; *out++ = (byte) ((in[0] * l1 + in[3] * l2) >> 16); *out++ = (byte) ((in[1] * l1 + in[4] * l2) >> 16); *out++ = (byte) ((in[2] * l1 + in[5] * l2) >> 16); } else // last pixel of the line has no pixel to lerp to { *out++ = in[0]; *out++ = in[1]; *out++ = in[2]; } } } /* ================ R_ResampleShot ================ */ void R_ResampleShot (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*3); row2 = malloc(outwidth*3); inrow = indata; oldy = 0; R_ResampleShotLerpLine (inrow, row1, inwidth, outwidth); R_ResampleShotLerpLine (inrow + inwidth*3, row2, inwidth, outwidth); for (i = 0, f = 0; i < outheight; i++,f += fstep) { yi = f >> 16; if (yi != oldy) { inrow = (byte *)indata + inwidth*3*yi; if (yi == oldy+1) memcpy(row1, row2, outwidth*3); else R_ResampleShotLerpLine (inrow, row1, inwidth, outwidth); if (yi < endy) R_ResampleShotLerpLine (inrow + inwidth*3, row2, inwidth, outwidth); else memcpy(row2, row1, outwidth*3); 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); } row1 -= outwidth*3; row2 -= outwidth*3; } else // last line has no pixels to lerp to { for (j = 0;j < outwidth;j++) { *out++ = *row1++; *out++ = *row1++; *out++ = *row1++; } row1 -= outwidth*3; } } free(row1); free(row2); } /* ================== R_ScaledScreenshot by Knightmare ================== */ #ifdef __linux__ byte *saveshotdata = NULL; #else byte *saveshotdata; #endif int saveshotsize = 256; void R_ScaledScreenshot (char *name) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW s[1]; FILE *file; char shotname[MAX_OSPATH]; int offset; if (!saveshotdata) return; Com_sprintf (shotname, sizeof(shotname), "%s", name); // Open the file for Binary Output file = fopen(shotname, "wb"); if (!file) { VID_Printf (PRINT_ALL, "Menu_ScreenShot: Couldn't create %s\n", name); return; } // Initialise the JPEG compression object cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, file); // Setup JPEG Parameters cinfo.image_width = saveshotsize; //256; cinfo.image_height = saveshotsize; //256; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 85, TRUE); // was 100 // Start Compression jpeg_start_compress(&cinfo, true); // Feed Scanline data offset = (cinfo.image_width * cinfo.image_height * 3) - (cinfo.image_width * 3); while(cinfo.next_scanline < cinfo.image_height) { s[0] = &saveshotdata[offset - (cinfo.next_scanline * (cinfo.image_width * 3))]; jpeg_write_scanlines(&cinfo, s, 1); } // Finish Compression jpeg_finish_compress(&cinfo); // Destroy JPEG object jpeg_destroy_compress(&cinfo); // Close File fclose(file); } /* ================== R_GrabScreen by Knightmare ================== */ void R_GrabScreen (void) { byte *rgbdata; // Free saveshot buffer first #ifdef __linux__ if (saveshotdata) { free(saveshotdata); saveshotdata = NULL; } #else if (saveshotdata) free(saveshotdata); #endif // Optional hi-res saveshots if (r_saveshotsize->value && (vid.width >= 1024) && (vid.height >= 1024)) saveshotsize = 1024; else if (r_saveshotsize->value && (vid.width >= 512) && (vid.height >= 512)) saveshotsize = 512; else saveshotsize = 256; // Allocate room for a copy of the framebuffer rgbdata = malloc(vid.width * vid.height * 3); if (!rgbdata) return; // Allocate room for reduced screenshot saveshotdata = malloc(saveshotsize * saveshotsize * 3); if (!saveshotdata) { free(rgbdata); return; } // Read the framebuffer into our storage qglReadPixels(0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, rgbdata); // Resize to 256x256 R_ResampleShot(rgbdata, vid.width, vid.height, saveshotdata, saveshotsize, saveshotsize); // Free Temp Framebuffer free(rgbdata); } /* ================== GL_ScreenShot_JPG By Robert 'Heffo' Heffernan ================== */ void GL_ScreenShot_JPG (void) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; byte *rgbdata; JSAMPROW s[1]; FILE *file; char picname[80], checkname[MAX_OSPATH]; int i, offset; // Create the scrnshots directory if it doesn't exist Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", FS_Gamedir()); Sys_Mkdir (checkname); // Knightmare- changed screenshot filenames, up to 100 screenies // Find a file name to save it to //strcpy(picname,"quake00.jpg"); for (i=0; i<=999; i++) { //picname[5] = i/10 + '0'; //picname[6] = i%10 + '0'; int one, ten, hundred; hundred = i*0.01; ten = (i - hundred*100)*0.1; one = i - hundred*100 - ten*10; Com_sprintf (picname, sizeof(picname), "kmquake2_%i%i%i.jpg", hundred, ten, one); Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", FS_Gamedir(), picname); file = fopen (checkname, "rb"); if (!file) break; // file doesn't exist fclose (file); } if (i==1000) { VID_Printf (PRINT_ALL, "SCR_JPGScreenShot_f: Couldn't create a file\n"); return; } // Open the file for Binary Output file = fopen(checkname, "wb"); if(!file) { VID_Printf (PRINT_ALL, "SCR_JPGScreenShot_f: Couldn't create a file\n"); return; } // Allocate room for a copy of the framebuffer rgbdata = malloc(vid.width * vid.height * 3); if(!rgbdata) { fclose(file); return; } // Read the framebuffer into our storage qglReadPixels(0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, rgbdata); // Initialise the JPEG compression object cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, file); // Setup JPEG Parameters cinfo.image_width = vid.width; cinfo.image_height = vid.height; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; jpeg_set_defaults(&cinfo); if ((gl_screenshot_jpeg_quality->value >= 101) || (gl_screenshot_jpeg_quality->value <= 0)) Cvar_Set("gl_screenshot_jpeg_quality", "85"); jpeg_set_quality(&cinfo, gl_screenshot_jpeg_quality->value, TRUE); // Start Compression jpeg_start_compress(&cinfo, true); // Feed Scanline data offset = (cinfo.image_width * cinfo.image_height * 3) - (cinfo.image_width * 3); while(cinfo.next_scanline < cinfo.image_height) { s[0] = &rgbdata[offset - (cinfo.next_scanline * (cinfo.image_width * 3))]; jpeg_write_scanlines(&cinfo, s, 1); } // Finish Compression jpeg_finish_compress(&cinfo); // Destroy JPEG object jpeg_destroy_compress(&cinfo); // Close File fclose(file); // Free Temp Framebuffer free(rgbdata); // Done! VID_Printf (PRINT_ALL, "Wrote %s\n", picname); } /* ================== GL_ScreenShot_f ================== */ void GL_ScreenShot_f (void) { byte *buffer; char picname[80]; char checkname[MAX_OSPATH]; int i, c, temp; FILE *f; // Heffo - JPEG Screenshots if(gl_screenshot_jpeg->value) { GL_ScreenShot_JPG(); return; } // create the scrnshots directory if it doesn't exist Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", FS_Gamedir()); Sys_Mkdir (checkname); // // find a file name to save it to // // Knightmare- changed screenshot filenames, up to 100 screenies //strcpy(picname,"quake00.tga"); for (i=0; i<=999; i++) { //picname[5] = i/10 + '0'; //picname[6] = i%10 + '0'; int one, ten, hundred; hundred = i*0.01; ten = (i - hundred*100)*0.1; one = i - hundred*100 - ten*10; Com_sprintf (picname, sizeof(picname), "kmquake2_%i%i%i.tga", hundred, ten, one); Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", FS_Gamedir(), picname); f = fopen (checkname, "rb"); if (!f) break; // file doesn't exist fclose (f); } if (i==1000) { VID_Printf (PRINT_ALL, "SCR_ScreenShot_f: Couldn't create a file\n"); return; } buffer = malloc(vid.width*vid.height*3 + 18); memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = vid.width&255; buffer[13] = vid.width>>8; buffer[14] = vid.height&255; buffer[15] = vid.height>>8; buffer[16] = 24; // pixel size qglReadPixels (0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); // swap rgb to bgr c = 18+vid.width*vid.height*3; for (i=18; istring ); GL_TextureAlphaMode( gl_texturealphamode->string ); GL_TextureSolidMode( gl_texturesolidmode->string ); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv( GL_REPLACE ); /*if ( qglPointParameterfEXT ) { float attenuations[3]; attenuations[0] = gl_particle_att_a->value; attenuations[1] = gl_particle_att_b->value; attenuations[2] = gl_particle_att_c->value; qglEnable( GL_POINT_SMOOTH ); qglPointParameterfEXT( GL_POINT_SIZE_MIN_EXT, gl_particle_min_size->value ); qglPointParameterfEXT( GL_POINT_SIZE_MAX_EXT, gl_particle_max_size->value ); qglPointParameterfvEXT( GL_DISTANCE_ATTENUATION_EXT, attenuations ); }*/ /*if ( qglColorTableEXT && gl_ext_palettedtexture->value ) { qglEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); GL_SetTexturePalette( d_8to24table ); }*/ GL_UpdateSwapInterval(); } void GL_UpdateSwapInterval( void ) { if ( gl_swapinterval->modified ) { gl_swapinterval->modified = false; if ( !gl_state.stereo_enabled ) { #ifdef _WIN32 if ( qwglSwapIntervalEXT ) qwglSwapIntervalEXT( gl_swapinterval->value ); #endif } } }