thirtyflightsofloving/renderer/r_misc.c
2020-06-12 12:21:21 -07:00

565 lines
13 KiB
C

/*
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 - particle image loading, and screenshots
#include "r_local.h"
#include "include/jpeglib.h" // Heffo - JPEG Screenshots
/*
==================
R_CreateNullTexture
==================
*/
#define NULLTEX_SIZE 16
void R_CreateNullTexture (void)
{
byte nulltex[NULLTEX_SIZE][NULLTEX_SIZE][4];
int x;
memset (nulltex, 32, sizeof(nulltex));
for (x=0; x<NULLTEX_SIZE; x++)
{
nulltex[0][x][0]=
nulltex[0][x][1]=
nulltex[0][x][2]=
nulltex[0][x][3]= 255;
nulltex[x][0][0]=
nulltex[x][0][1]=
nulltex[x][0][2]=
nulltex[x][0][3]= 255;
nulltex[NULLTEX_SIZE-1][x][0]=
nulltex[NULLTEX_SIZE-1][x][1]=
nulltex[NULLTEX_SIZE-1][x][2]=
nulltex[NULLTEX_SIZE-1][x][3]= 255;
nulltex[x][NULLTEX_SIZE-1][0]=
nulltex[x][NULLTEX_SIZE-1][1]=
nulltex[x][NULLTEX_SIZE-1][2]=
nulltex[x][NULLTEX_SIZE-1][3]= 255;
}
r_notexture = R_LoadPic ("***r_notexture***", (byte *)nulltex, NULLTEX_SIZE, NULLTEX_SIZE, it_wall, 32);
}
/*
==================
LoadPartImg
==================
*/
image_t *LoadPartImg (char *name, imagetype_t type)
{
image_t *image = R_FindImage(name, type);
if (!image) image = r_notexture;
return image;
}
/*
==================
R_SetParticlePicture
==================
*/
void R_SetParticlePicture (int num, char *name)
{
r_particletextures[num] = LoadPartImg (name, it_part);
}
/*
==================
R_InitParticleTextures
==================
*/
void R_InitParticleTextures (void)
{
int x;
#ifdef ROQ_SUPPORT
byte data2D[256*256*4]; // Raw texture
#endif // ROQ_SUPPORT
R_CreateNullTexture(); // Generate null texture
#ifdef ROQ_SUPPORT
memset(data2D, 255, 256*256*4);
r_rawtexture = R_LoadPic ("***r_rawtexture***", data2D, 256, 256, it_pic, 32);
#endif // ROQ_SUPPORT
r_envmappic = LoadPartImg ("gfx/envmap.tga", it_wall);
r_spheremappic = LoadPartImg ("gfx/spheremap.tga", it_skin);
r_causticpic = LoadPartImg ("gfx/water/caustic.tga", it_wall);
r_shelltexture = LoadPartImg ("gfx/shell_generic.tga", it_skin);
r_particlebeam = LoadPartImg ("gfx/particles/beam.tga", it_part);
//Knightmare- Psychospaz's enhanced particles
for (x=0 ; x<PARTICLE_TYPES ; x++)
r_particletextures[x] = NULL;
SetParticleImages();
}
/*
==============================================================================
SCREEN SHOTS
==============================================================================
*/
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;
/*
================
R_ResampleShotLerpLine
from DarkPlaces
================
*/
void R_ResampleShotLerpLine (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) * 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
==================
*/
byte *saveshotdata;
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, 100, 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
if (saveshotdata)
free(saveshotdata);
// 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);
}
/*
==================
R_ScreenShot_JPG
By Robert 'Heffo' Heffernan
==================
*/
void R_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 ((r_screenshot_jpeg_quality->value >= 101) || (r_screenshot_jpeg_quality->value <= 0))
Cvar_Set("r_screenshot_jpeg_quality", "100");
jpeg_set_quality(&cinfo, r_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);
}
/*
==================
R_ScreenShot_f
==================
*/
void R_ScreenShot_f (void)
{
byte *buffer;
char picname[80];
char checkname[MAX_OSPATH];
int i, c, temp;
FILE *f;
// Heffo - JPEG Screenshots
if(r_screenshot_jpeg->value)
{
R_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; i<c; i+=3)
{
temp = buffer[i];
buffer[i] = buffer[i+2];
buffer[i+2] = temp;
}
f = fopen (checkname, "wb");
fwrite (buffer, 1, c, f);
fclose (f);
free (buffer);
VID_Printf (PRINT_ALL, "Wrote %s\n", picname);
}
//==============================================================================
/*
=================
GL_UpdateSwapInterval
=================
*/
void GL_UpdateSwapInterval (void)
{
if ( r_swapinterval->modified )
{
r_swapinterval->modified = false;
if ( !gl_state.stereo_enabled )
{
#ifdef _WIN32
if ( qwglSwapIntervalEXT )
qwglSwapIntervalEXT( r_swapinterval->value );
#endif
}
}
}