mirror of
https://github.com/libretro/libretro-tyrquake.git
synced 2024-11-25 09:00:21 +00:00
e24ff3553f
This patch sets things up to make use of the XFree86 gamma manipulation functions. One issue is that the OpenGL blending substitute we set up is not really the same as gamma correction because it only brightens pixels according to their current values. This means black areas are not brightened using this method (which I think is a good thing), but gamma correction adds "white" to every area of the screen. At the moment I've set up the "manual" OpenGL version as a fallback in case the system gamma functions are not working or not available. I've also set things up such that the system gamma is not used unless we are in fullscreen mode since it affects the whole display. The cvar _gl_allowgammafallback controls whether the fallback is used or not, but I don't currently have a way to force it to use the "fallback" even if the other gamma settings work. Most likely I'll separate out the two functions into gamma and "intensity" similar to Quake 2 and later games. Signed-off-by: Tyrann <tyrann@disenchant.net>
473 lines
12 KiB
C
473 lines
12 KiB
C
/*
|
|
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.
|
|
|
|
*/
|
|
// r_misc.c
|
|
|
|
#include "cmd.h"
|
|
#include "console.h"
|
|
#include "glquake.h"
|
|
#include "protocol.h"
|
|
#include "quakedef.h"
|
|
#include "sys.h"
|
|
|
|
// FIXME - should only be needed in r_part.c or here, not both.
|
|
int particletexture;
|
|
|
|
/*
|
|
==================
|
|
R_InitTextures
|
|
==================
|
|
*/
|
|
void
|
|
R_InitTextures(void)
|
|
{
|
|
int x, y, m;
|
|
byte *dest;
|
|
|
|
// create a simple checkerboard texture for the default
|
|
r_notexture_mip =
|
|
Hunk_AllocName(sizeof(texture_t) + 16 * 16 + 8 * 8 + 4 * 4 + 2 * 2,
|
|
"notexture");
|
|
|
|
r_notexture_mip->width = r_notexture_mip->height = 16;
|
|
r_notexture_mip->offsets[0] = sizeof(texture_t);
|
|
r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16 * 16;
|
|
r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8 * 8;
|
|
r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4 * 4;
|
|
|
|
for (m = 0; m < 4; m++) {
|
|
dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
|
|
for (y = 0; y < (16 >> m); y++) {
|
|
for (x = 0; x < (16 >> m); x++) {
|
|
if ((y < (8 >> m)) ^ (x < (8 >> m)))
|
|
*dest++ = 0;
|
|
else
|
|
*dest++ = 0xff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static byte dottexture[8][8] = {
|
|
{0, 1, 1, 0, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 0, 0, 0, 0},
|
|
{1, 1, 1, 1, 0, 0, 0, 0},
|
|
{0, 1, 1, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
{0, 0, 0, 0, 0, 0, 0, 0},
|
|
};
|
|
|
|
static void
|
|
R_InitParticleTexture(void)
|
|
{
|
|
int x, y;
|
|
byte data[8][8][4];
|
|
|
|
//
|
|
// particle texture
|
|
//
|
|
particletexture = texture_extension_number++;
|
|
GL_Bind(particletexture);
|
|
|
|
for (x = 0; x < 8; x++) {
|
|
for (y = 0; y < 8; y++) {
|
|
data[y][x][0] = 255;
|
|
data[y][x][1] = 255;
|
|
data[y][x][2] = 255;
|
|
data[y][x][3] = dottexture[x][y] * 255;
|
|
}
|
|
}
|
|
glTexImage2D(GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA,
|
|
GL_UNSIGNED_BYTE, data);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
R_Envmap_f
|
|
|
|
Grab six views for environment mapping tests
|
|
===============
|
|
*/
|
|
static void
|
|
R_Envmap_f(void)
|
|
{
|
|
byte buffer[256 * 256 * 4];
|
|
|
|
glDrawBuffer(GL_FRONT);
|
|
glReadBuffer(GL_FRONT);
|
|
envmap = true;
|
|
|
|
r_refdef.vrect.x = 0;
|
|
r_refdef.vrect.y = 0;
|
|
r_refdef.vrect.width = 256;
|
|
r_refdef.vrect.height = 256;
|
|
|
|
r_refdef.viewangles[0] = 0;
|
|
r_refdef.viewangles[1] = 0;
|
|
r_refdef.viewangles[2] = 0;
|
|
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
|
R_RenderView();
|
|
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
COM_WriteFile("env0.rgb", buffer, sizeof(buffer));
|
|
|
|
r_refdef.viewangles[1] = 90;
|
|
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
|
R_RenderView();
|
|
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
COM_WriteFile("env1.rgb", buffer, sizeof(buffer));
|
|
|
|
r_refdef.viewangles[1] = 180;
|
|
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
|
R_RenderView();
|
|
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
COM_WriteFile("env2.rgb", buffer, sizeof(buffer));
|
|
|
|
r_refdef.viewangles[1] = 270;
|
|
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
|
R_RenderView();
|
|
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
COM_WriteFile("env3.rgb", buffer, sizeof(buffer));
|
|
|
|
r_refdef.viewangles[0] = -90;
|
|
r_refdef.viewangles[1] = 0;
|
|
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
|
R_RenderView();
|
|
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
COM_WriteFile("env4.rgb", buffer, sizeof(buffer));
|
|
|
|
r_refdef.viewangles[0] = 90;
|
|
r_refdef.viewangles[1] = 0;
|
|
GL_BeginRendering(&glx, &gly, &glwidth, &glheight);
|
|
R_RenderView();
|
|
glReadPixels(0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
|
COM_WriteFile("env5.rgb", buffer, sizeof(buffer));
|
|
|
|
envmap = false;
|
|
glDrawBuffer(GL_BACK);
|
|
glReadBuffer(GL_BACK);
|
|
GL_EndRendering();
|
|
}
|
|
|
|
// FIXME - locate somewhere else?
|
|
cvar_t r_lockpvs = { "r_lockpvs", "0" };
|
|
cvar_t r_lockfrustum = { "r_lockfrustum", "0" };
|
|
cvar_t r_drawflat = { "r_drawflat", "0" };
|
|
|
|
/*
|
|
===============
|
|
R_Init
|
|
===============
|
|
*/
|
|
void
|
|
R_Init(void)
|
|
{
|
|
Cmd_AddCommand("envmap", R_Envmap_f);
|
|
Cmd_AddCommand("pointfile", R_ReadPointFile_f);
|
|
Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
|
|
|
|
Cvar_RegisterVariable(&r_speeds);
|
|
Cvar_RegisterVariable(&r_fullbright);
|
|
Cvar_RegisterVariable(&r_drawentities);
|
|
Cvar_RegisterVariable(&r_drawviewmodel);
|
|
Cvar_RegisterVariable(&r_drawflat);
|
|
|
|
Cvar_RegisterVariable(&r_lockpvs);
|
|
Cvar_RegisterVariable(&r_lockfrustum);
|
|
|
|
Cvar_RegisterVariable(&r_norefresh);
|
|
Cvar_RegisterVariable(&r_lightmap);
|
|
Cvar_RegisterVariable(&r_shadows);
|
|
Cvar_RegisterVariable(&r_mirroralpha);
|
|
Cvar_RegisterVariable(&r_wateralpha);
|
|
Cvar_RegisterVariable(&r_dynamic);
|
|
Cvar_RegisterVariable(&r_novis);
|
|
Cvar_RegisterVariable(&r_waterwarp);
|
|
|
|
Cvar_RegisterVariable(&gl_finish);
|
|
Cvar_RegisterVariable(&gl_clear);
|
|
Cvar_RegisterVariable(&gl_texsort);
|
|
|
|
Cvar_RegisterVariable(&_gl_lightmap_sort);
|
|
Cvar_RegisterVariable(&_gl_sky_mtex);
|
|
Cvar_RegisterVariable(&_gl_allowgammafallback);
|
|
Cvar_RegisterVariable(&_gl_drawhull);
|
|
|
|
Cvar_RegisterVariable(&gl_cull);
|
|
Cvar_RegisterVariable(&gl_smoothmodels);
|
|
Cvar_RegisterVariable(&gl_affinemodels);
|
|
Cvar_RegisterVariable(&gl_polyblend);
|
|
Cvar_RegisterVariable(&gl_flashblend);
|
|
Cvar_RegisterVariable(&gl_playermip);
|
|
Cvar_RegisterVariable(&gl_nocolors);
|
|
|
|
Cvar_RegisterVariable(&gl_keeptjunctions);
|
|
Cvar_RegisterVariable(&gl_reporttjunctions);
|
|
|
|
Cvar_RegisterVariable(&gl_doubleeyes);
|
|
|
|
if (gl_mtexable)
|
|
Cvar_SetValue("gl_texsort", 0.0);
|
|
|
|
R_InitBubble();
|
|
|
|
R_InitParticles();
|
|
R_InitParticleTexture();
|
|
|
|
playertextures = texture_extension_number;
|
|
texture_extension_number += MAX_CLIENTS;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
R_TranslatePlayerSkin
|
|
|
|
Translates a skin texture by the per-player color lookup
|
|
===============
|
|
*/
|
|
void
|
|
R_TranslatePlayerSkin(int playernum)
|
|
{
|
|
int top, bottom;
|
|
byte translate[256];
|
|
unsigned translate32[256];
|
|
int i, j, s;
|
|
model_t *model;
|
|
aliashdr_t *paliashdr;
|
|
byte *original;
|
|
unsigned pixels[512 * 256], *out;
|
|
unsigned scaled_width, scaled_height;
|
|
int inwidth, inheight;
|
|
byte *inrow;
|
|
unsigned frac, fracstep;
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
top = cl.scores[playernum].colors & 0xf0;
|
|
bottom = (cl.scores[playernum].colors & 15) << 4;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
translate[i] = i;
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
if (top < 128) // the artists made some backwards ranges. sigh.
|
|
translate[TOP_RANGE + i] = top + i;
|
|
else
|
|
translate[TOP_RANGE + i] = top + 15 - i;
|
|
|
|
if (bottom < 128)
|
|
translate[BOTTOM_RANGE + i] = bottom + i;
|
|
else
|
|
translate[BOTTOM_RANGE + i] = bottom + 15 - i;
|
|
}
|
|
|
|
//
|
|
// locate the original skin pixels
|
|
//
|
|
currententity = &cl_entities[1 + playernum];
|
|
model = currententity->model;
|
|
if (!model)
|
|
return; // player doesn't have a model yet
|
|
if (model->type != mod_alias)
|
|
return; // only translate skins on alias models
|
|
|
|
paliashdr = (aliashdr_t *)Mod_Extradata(model);
|
|
s = paliashdr->skinwidth * paliashdr->skinheight;
|
|
if (currententity->skinnum < 0
|
|
|| currententity->skinnum >= paliashdr->numskins) {
|
|
Con_Printf("(%d): Invalid player skin #%d\n", playernum,
|
|
currententity->skinnum);
|
|
original = (byte *)paliashdr + paliashdr->texels[0];
|
|
} else
|
|
original =
|
|
(byte *)paliashdr + paliashdr->texels[currententity->skinnum];
|
|
if (s & 3)
|
|
Sys_Error("%s: s&3", __func__);
|
|
|
|
inwidth = paliashdr->skinwidth;
|
|
inheight = paliashdr->skinheight;
|
|
|
|
// because this happens during gameplay, do it fast
|
|
// instead of sending it through gl_upload 8
|
|
GL_Bind(playertextures + playernum);
|
|
|
|
#if 0
|
|
byte translated[320 * 200];
|
|
|
|
for (i = 0; i < s; i += 4) {
|
|
translated[i] = translate[original[i]];
|
|
translated[i + 1] = translate[original[i + 1]];
|
|
translated[i + 2] = translate[original[i + 2]];
|
|
translated[i + 3] = translate[original[i + 3]];
|
|
}
|
|
|
|
|
|
// don't mipmap these, because it takes too long
|
|
GL_Upload8(translated, paliashdr->skinwidth, paliashdr->skinheight,
|
|
false, false, true);
|
|
#else
|
|
// allow users to crunch sizes down
|
|
scaled_width = 512 >> (int)gl_playermip.value;
|
|
scaled_height = 256 >> (int)gl_playermip.value;
|
|
|
|
// make sure not still too big
|
|
scaled_width = gl_max_size.value < scaled_width
|
|
? gl_max_size.value : scaled_width;
|
|
scaled_height = gl_max_size.value < scaled_height
|
|
? gl_max_size.value : scaled_height;
|
|
|
|
if (VID_Is8bit()) { // 8bit texture upload
|
|
byte *out2;
|
|
|
|
out2 = (byte *)pixels;
|
|
memset(pixels, 0, sizeof(pixels));
|
|
fracstep = inwidth * 0x10000 / scaled_width;
|
|
for (i = 0; i < scaled_height; i++, out2 += scaled_width) {
|
|
inrow = original + inwidth * (i * inheight / scaled_height);
|
|
frac = fracstep >> 1;
|
|
for (j = 0; j < scaled_width; j += 4) {
|
|
out2[j] = translate[inrow[frac >> 16]];
|
|
frac += fracstep;
|
|
out2[j + 1] = translate[inrow[frac >> 16]];
|
|
frac += fracstep;
|
|
out2[j + 2] = translate[inrow[frac >> 16]];
|
|
frac += fracstep;
|
|
out2[j + 3] = translate[inrow[frac >> 16]];
|
|
frac += fracstep;
|
|
}
|
|
}
|
|
|
|
GL_Upload8_EXT((byte *)pixels, scaled_width, scaled_height, false,
|
|
false);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < 256; i++)
|
|
translate32[i] = d_8to24table[translate[i]];
|
|
|
|
out = pixels;
|
|
fracstep = inwidth * 0x10000 / scaled_width;
|
|
for (i = 0; i < scaled_height; i++, out += scaled_width) {
|
|
inrow = original + inwidth * (i * inheight / scaled_height);
|
|
frac = fracstep >> 1;
|
|
for (j = 0; j < scaled_width; j += 4) {
|
|
out[j] = translate32[inrow[frac >> 16]];
|
|
frac += fracstep;
|
|
out[j + 1] = translate32[inrow[frac >> 16]];
|
|
frac += fracstep;
|
|
out[j + 2] = translate32[inrow[frac >> 16]];
|
|
frac += fracstep;
|
|
out[j + 3] = translate32[inrow[frac >> 16]];
|
|
frac += fracstep;
|
|
}
|
|
}
|
|
glTexImage2D(GL_TEXTURE_2D, 0, gl_solid_format, scaled_width,
|
|
scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
R_NewMap
|
|
===============
|
|
*/
|
|
void
|
|
R_NewMap(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
d_lightstylevalue[i] = 264; // normal light value
|
|
|
|
memset(&r_worldentity, 0, sizeof(r_worldentity));
|
|
r_worldentity.model = cl.worldmodel;
|
|
|
|
// clear out efrags in case the level hasn't been reloaded
|
|
// FIXME: is this one short?
|
|
for (i = 0; i < cl.worldmodel->numleafs; i++)
|
|
cl.worldmodel->leafs[i].efrags = NULL;
|
|
|
|
r_viewleaf = NULL;
|
|
R_ClearParticles();
|
|
|
|
GL_BuildLightmaps();
|
|
|
|
// identify sky texture
|
|
skytexturenum = -1;
|
|
mirrortexturenum = -1;
|
|
for (i = 0; i < cl.worldmodel->numtextures; i++) {
|
|
if (!cl.worldmodel->textures[i])
|
|
continue;
|
|
if (!strncmp(cl.worldmodel->textures[i]->name, "sky", 3))
|
|
skytexturenum = i;
|
|
if (!strncmp(cl.worldmodel->textures[i]->name, "window02_1", 10))
|
|
mirrortexturenum = i;
|
|
cl.worldmodel->textures[i]->texturechain = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
R_TimeRefresh_f
|
|
|
|
For program optimization
|
|
====================
|
|
*/
|
|
void
|
|
R_TimeRefresh_f(void)
|
|
{
|
|
int i;
|
|
float start, stop, time;
|
|
|
|
glDrawBuffer(GL_FRONT);
|
|
glFinish();
|
|
|
|
start = Sys_DoubleTime();
|
|
for (i = 0; i < 128; i++) {
|
|
r_refdef.viewangles[1] = i / 128.0 * 360.0;
|
|
R_RenderView();
|
|
}
|
|
|
|
glFinish();
|
|
stop = Sys_DoubleTime();
|
|
time = stop - start;
|
|
Con_Printf("%f seconds (%f fps)\n", time, 128 / time);
|
|
|
|
glDrawBuffer(GL_BACK);
|
|
GL_EndRendering();
|
|
}
|
|
|
|
void
|
|
D_FlushCaches(void)
|
|
{
|
|
}
|