2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 1996-2001 Id Software, Inc.
|
|
|
|
Copyright (C) 2002-2009 John Fitzgibbons and others
|
|
|
|
Copyright (C) 2007-2008 Kristian Duske
|
2014-09-22 08:55:46 +00:00
|
|
|
Copyright (C) 2010-2014 QuakeSpasm developers
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
//gl_sky.c
|
|
|
|
|
|
|
|
#include "quakedef.h"
|
|
|
|
|
|
|
|
#define MAX_CLIP_VERTS 64
|
|
|
|
|
|
|
|
float Fog_GetDensity(void);
|
|
|
|
float *Fog_GetColor(void);
|
|
|
|
|
2012-05-30 08:56:06 +00:00
|
|
|
extern qmodel_t *loadmodel;
|
2010-02-15 23:26:55 +00:00
|
|
|
extern int rs_skypolys; //for r_speeds readout
|
|
|
|
extern int rs_skypasses; //for r_speeds readout
|
|
|
|
float skyflatcolor[3];
|
|
|
|
float skymins[2][6], skymaxs[2][6];
|
|
|
|
|
2019-09-10 17:58:03 +00:00
|
|
|
qboolean skyroom_drawn;
|
|
|
|
qboolean skyroom_enabled;
|
2019-11-02 20:22:54 +00:00
|
|
|
vec4_t skyroom_origin;
|
|
|
|
vec4_t skyroom_orientation;
|
2019-09-10 17:58:03 +00:00
|
|
|
|
2020-03-28 05:09:06 +00:00
|
|
|
char skybox_name[1024]; //name of current skybox, or "" if no skybox
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
gltexture_t *skybox_textures[6];
|
|
|
|
gltexture_t *solidskytexture, *alphaskytexture;
|
|
|
|
|
|
|
|
extern cvar_t gl_farclip;
|
2011-12-28 22:01:33 +00:00
|
|
|
cvar_t r_fastsky = {"r_fastsky", "0", CVAR_NONE};
|
|
|
|
cvar_t r_sky_quality = {"r_sky_quality", "12", CVAR_NONE};
|
|
|
|
cvar_t r_skyalpha = {"r_skyalpha", "1", CVAR_NONE};
|
|
|
|
cvar_t r_skyfog = {"r_skyfog","0.5",CVAR_NONE};
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
int skytexorder[6] = {0,2,1,3,4,5}; //for skybox
|
|
|
|
|
|
|
|
vec3_t skyclip[6] = {
|
|
|
|
{1,1,0},
|
|
|
|
{1,-1,0},
|
|
|
|
{0,-1,1},
|
|
|
|
{0,1,1},
|
|
|
|
{1,0,1},
|
|
|
|
{-1,0,1}
|
|
|
|
};
|
|
|
|
|
|
|
|
int st_to_vec[6][3] =
|
|
|
|
{
|
|
|
|
{3,-1,2},
|
|
|
|
{-3,1,2},
|
|
|
|
{1,3,2},
|
|
|
|
{-1,-3,2},
|
|
|
|
{-2,-1,3}, // straight up
|
|
|
|
{2,-1,-3} // straight down
|
|
|
|
};
|
|
|
|
|
|
|
|
int vec_to_st[6][3] =
|
|
|
|
{
|
|
|
|
{-2,3,1},
|
|
|
|
{2,3,-1},
|
|
|
|
{1,3,2},
|
|
|
|
{-1,3,-2},
|
|
|
|
{-2,-1,3},
|
|
|
|
{-2,1,-3}
|
|
|
|
};
|
|
|
|
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
float skyfog; // ericw
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
//==============================================================================
|
|
|
|
//
|
|
|
|
// INIT
|
|
|
|
//
|
|
|
|
//==============================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
Sky_LoadTexture
|
|
|
|
|
|
|
|
A sky texture is 256*128, with the left side being a masked overlay
|
|
|
|
==============
|
|
|
|
*/
|
2020-03-07 09:03:46 +00:00
|
|
|
void Sky_LoadTexture (texture_t *mt, enum srcformat fmt, unsigned int srcwidth, unsigned int height)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
char texturename[64];
|
2020-03-07 09:03:46 +00:00
|
|
|
int i, p, r, g, b, count;
|
2010-02-15 23:26:55 +00:00
|
|
|
byte *src;
|
2020-03-07 09:03:46 +00:00
|
|
|
byte *front_data;
|
|
|
|
byte *back_data;
|
2010-02-15 23:26:55 +00:00
|
|
|
unsigned *rgba;
|
2020-03-07 09:03:46 +00:00
|
|
|
int rows, columns;
|
|
|
|
int bb,bw,bh;
|
|
|
|
int width = srcwidth/2;
|
|
|
|
|
|
|
|
TexMgr_BlockSize(fmt, &bb, &bw, &bh);
|
|
|
|
columns = (width+bw-1) / bw;
|
|
|
|
rows = (height+bh-1) / bh;
|
|
|
|
|
|
|
|
front_data = Hunk_AllocName (bb*columns*rows*2, "skytex");
|
|
|
|
back_data = front_data+bb*columns*rows;
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2017-09-17 02:12:53 +00:00
|
|
|
src = (byte *)(mt+1);
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
// extract back layer and upload
|
2020-03-07 09:03:46 +00:00
|
|
|
for (i=0 ; i<rows ; i++)
|
|
|
|
memcpy(back_data+bb*i*columns, src+bb*(i*columns*2 + columns), columns*bb);
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2011-12-27 10:50:42 +00:00
|
|
|
q_snprintf(texturename, sizeof(texturename), "%s:%s_back", loadmodel->name, mt->name);
|
2020-03-07 09:03:46 +00:00
|
|
|
solidskytexture = TexMgr_LoadImage (loadmodel, texturename, width, height, fmt, back_data, "", (src_offset_t)back_data, TEXPREF_NONE);
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
// extract front layer and upload
|
2020-03-07 09:03:46 +00:00
|
|
|
for (i=0 ; i<rows ; i++)
|
|
|
|
memcpy(front_data+bb*i*columns, src+bb*(i*columns*2), columns*bb);
|
|
|
|
if (fmt == SRC_INDEXED)
|
|
|
|
{ //the lame texmgr only knows one transparent index...
|
|
|
|
for (i=0 ; i<width*height ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2020-03-07 09:03:46 +00:00
|
|
|
if (front_data[i] == 0)
|
|
|
|
front_data[i] = 255;
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
2020-03-07 09:03:46 +00:00
|
|
|
}
|
2011-12-27 10:50:42 +00:00
|
|
|
q_snprintf(texturename, sizeof(texturename), "%s:%s_front", loadmodel->name, mt->name);
|
2020-03-07 09:03:46 +00:00
|
|
|
alphaskytexture = TexMgr_LoadImage (loadmodel, texturename, width, height, fmt, front_data, "", (src_offset_t)front_data, TEXPREF_ALPHA);
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2020-03-07 09:03:46 +00:00
|
|
|
// calculate r_fastsky color based on average of all opaque foreground colors, if we can.
|
2010-02-15 23:26:55 +00:00
|
|
|
r = g = b = count = 0;
|
2020-03-07 09:03:46 +00:00
|
|
|
if (fmt == SRC_INDEXED)
|
|
|
|
{
|
|
|
|
for (i=0 ; i<width*height ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2020-03-07 09:03:46 +00:00
|
|
|
p = src[i];
|
2010-02-15 23:26:55 +00:00
|
|
|
if (p != 0)
|
|
|
|
{
|
|
|
|
rgba = &d_8to24table[p];
|
|
|
|
r += ((byte *)rgba)[0];
|
|
|
|
g += ((byte *)rgba)[1];
|
|
|
|
b += ((byte *)rgba)[2];
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
2020-03-07 09:03:46 +00:00
|
|
|
}
|
2010-02-15 23:26:55 +00:00
|
|
|
skyflatcolor[0] = (float)r/(count*255);
|
|
|
|
skyflatcolor[1] = (float)g/(count*255);
|
|
|
|
skyflatcolor[2] = (float)b/(count*255);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
Sky_LoadSkyBox
|
|
|
|
==================
|
|
|
|
*/
|
2010-08-29 02:22:55 +00:00
|
|
|
const char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
|
|
|
|
void Sky_LoadSkyBox (const char *name)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
int i, mark, width, height;
|
|
|
|
char filename[MAX_OSPATH];
|
|
|
|
byte *data;
|
|
|
|
qboolean nonefound = true;
|
2017-09-17 02:12:53 +00:00
|
|
|
qboolean malloced;
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
if (strcmp(skybox_name, name) == 0)
|
|
|
|
return; //no change
|
|
|
|
|
|
|
|
//purge old textures
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
{
|
|
|
|
if (skybox_textures[i] && skybox_textures[i] != notexture)
|
|
|
|
TexMgr_FreeTexture (skybox_textures[i]);
|
|
|
|
skybox_textures[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//turn off skybox if sky is set to ""
|
|
|
|
if (name[0] == 0)
|
|
|
|
{
|
|
|
|
skybox_name[0] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//load textures
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
{
|
2020-04-11 02:06:00 +00:00
|
|
|
enum srcformat fmt;
|
2010-02-15 23:26:55 +00:00
|
|
|
mark = Hunk_LowMark ();
|
2011-12-27 10:50:42 +00:00
|
|
|
q_snprintf (filename, sizeof(filename), "gfx/env/%s%s", name, suf[i]);
|
2020-04-11 02:06:00 +00:00
|
|
|
data = Image_LoadImage (filename, &width, &height, &fmt, &malloced);
|
2010-02-15 23:26:55 +00:00
|
|
|
if (data)
|
|
|
|
{
|
2020-04-11 02:06:00 +00:00
|
|
|
skybox_textures[i] = TexMgr_LoadImage (cl.worldmodel, filename, width, height, fmt, data, filename, 0, TEXPREF_NONE);
|
2010-02-15 23:26:55 +00:00
|
|
|
nonefound = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Con_Printf ("Couldn't load %s\n", filename);
|
|
|
|
skybox_textures[i] = notexture;
|
|
|
|
}
|
2017-09-17 02:12:53 +00:00
|
|
|
if (malloced)
|
|
|
|
free(data);
|
2010-02-15 23:26:55 +00:00
|
|
|
Hunk_FreeToLowMark (mark);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nonefound) // go back to scrolling sky if skybox is totally missing
|
|
|
|
{
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
{
|
|
|
|
if (skybox_textures[i] && skybox_textures[i] != notexture)
|
|
|
|
TexMgr_FreeTexture (skybox_textures[i]);
|
|
|
|
skybox_textures[i] = NULL;
|
|
|
|
}
|
|
|
|
skybox_name[0] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-28 05:09:06 +00:00
|
|
|
q_strlcpy(skybox_name, name, sizeof(skybox_name));
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
Sky_NewMap
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void Sky_NewMap (void)
|
|
|
|
{
|
|
|
|
char key[128], value[4096];
|
2010-08-29 02:22:55 +00:00
|
|
|
const char *data;
|
2010-02-15 23:26:55 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
//
|
|
|
|
// initially no sky
|
|
|
|
//
|
2019-09-10 17:58:03 +00:00
|
|
|
skyroom_enabled = false;
|
2010-02-15 23:26:55 +00:00
|
|
|
skybox_name[0] = 0;
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
skybox_textures[i] = NULL;
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
skyfog = r_skyfog.value;
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// read worldspawn (this is so ugly, and shouldn't it be done on the server?)
|
|
|
|
//
|
|
|
|
data = cl.worldmodel->entities;
|
|
|
|
if (!data)
|
|
|
|
return; //FIXME: how could this possibly ever happen? -- if there's no
|
|
|
|
// worldspawn then the sever wouldn't send the loadmap message to the client
|
|
|
|
|
|
|
|
data = COM_Parse(data);
|
|
|
|
if (!data) //should never happen
|
|
|
|
return; // error
|
|
|
|
if (com_token[0] != '{') //should never happen
|
|
|
|
return; // error
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
data = COM_Parse(data);
|
|
|
|
if (!data)
|
|
|
|
return; // error
|
|
|
|
if (com_token[0] == '}')
|
|
|
|
break; // end of worldspawn
|
|
|
|
if (com_token[0] == '_')
|
2019-09-12 04:06:54 +00:00
|
|
|
q_strlcpy(key, com_token + 1, sizeof(key));
|
2010-02-15 23:26:55 +00:00
|
|
|
else
|
2019-09-12 04:06:54 +00:00
|
|
|
q_strlcpy(key, com_token, sizeof(key));
|
2019-09-12 12:33:02 +00:00
|
|
|
while (key[0] && key[strlen(key)-1] == ' ') // remove trailing spaces
|
2010-02-15 23:26:55 +00:00
|
|
|
key[strlen(key)-1] = 0;
|
|
|
|
data = COM_Parse(data);
|
|
|
|
if (!data)
|
|
|
|
return; // error
|
2019-09-12 04:06:54 +00:00
|
|
|
q_strlcpy(value, com_token, sizeof(value));
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
if (!strcmp("sky", key))
|
|
|
|
Sky_LoadSkyBox(value);
|
2019-09-10 17:58:03 +00:00
|
|
|
else if (!strcmp("skyroom", key))
|
|
|
|
{ //"_skyroom" "X Y Z". ideally the gamecode would do this with an entity, but people want to use the vanilla gamecode from 1996 for some reason.
|
|
|
|
const char *t = COM_Parse(value);
|
|
|
|
skyroom_origin[0] = atof(com_token);
|
|
|
|
t = COM_Parse(t);
|
|
|
|
skyroom_origin[1] = atof(com_token);
|
|
|
|
t = COM_Parse(t);
|
|
|
|
skyroom_origin[2] = atof(com_token);
|
2019-11-02 20:22:54 +00:00
|
|
|
t = COM_Parse(t);
|
|
|
|
skyroom_origin[3] = atof(com_token);
|
2019-09-10 17:58:03 +00:00
|
|
|
skyroom_enabled = true;
|
2019-11-02 20:22:54 +00:00
|
|
|
|
|
|
|
t = COM_Parse(t);
|
|
|
|
skyroom_orientation[3] = atof(com_token);
|
|
|
|
t = COM_Parse(t);
|
|
|
|
skyroom_orientation[0] = atof(com_token);
|
|
|
|
t = COM_Parse(t);
|
|
|
|
skyroom_orientation[1] = atof(com_token);
|
|
|
|
t = COM_Parse(t);
|
|
|
|
skyroom_orientation[2] = atof(com_token);
|
2019-09-10 17:58:03 +00:00
|
|
|
}
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2019-09-10 17:58:03 +00:00
|
|
|
else if (!strcmp("skyfog", key))
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
skyfog = atof(value);
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
#if 1 //also accept non-standard keys
|
|
|
|
else if (!strcmp("skyname", key)) //half-life
|
|
|
|
Sky_LoadSkyBox(value);
|
|
|
|
else if (!strcmp("qlsky", key)) //quake lives
|
|
|
|
Sky_LoadSkyBox(value);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
Sky_SkyCommand_f
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void Sky_SkyCommand_f (void)
|
|
|
|
{
|
|
|
|
switch (Cmd_Argc())
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
Con_Printf("\"sky\" is \"%s\"\n", skybox_name);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
Sky_LoadSkyBox(Cmd_Argv(1));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Con_Printf("usage: sky <skyname>\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-02 20:22:54 +00:00
|
|
|
static void Sky_SkyRoomCommand_f (void)
|
|
|
|
{
|
|
|
|
switch (Cmd_Argc())
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
if (skyroom_enabled)
|
|
|
|
Con_Printf("\"skyroom\" is \"%f %f %f %f %f %f %f %f\"\n", skyroom_origin[0],skyroom_origin[1],skyroom_origin[2],skyroom_origin[3], skyroom_orientation[3],skyroom_orientation[0],skyroom_orientation[1],skyroom_orientation[2]);
|
|
|
|
else
|
|
|
|
Con_Printf("\"skyroom\" is \"\"\n");
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
Sky_LoadSkyBox(Cmd_Argv(1));
|
|
|
|
skyroom_enabled = true;
|
|
|
|
skyroom_origin[0] = atof(Cmd_Argv(1));
|
|
|
|
skyroom_origin[1] = atof(Cmd_Argv(2));
|
|
|
|
skyroom_origin[2] = atof(Cmd_Argv(3));
|
|
|
|
skyroom_origin[3] = atof(Cmd_Argv(4)); //paralax
|
|
|
|
|
|
|
|
skyroom_orientation[3] = atof(Cmd_Argv(5)); //speed
|
|
|
|
skyroom_orientation[0] = atof(Cmd_Argv(6));
|
|
|
|
skyroom_orientation[1] = atof(Cmd_Argv(7));
|
|
|
|
skyroom_orientation[2] = atof(Cmd_Argv(8));
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
default:
|
|
|
|
Con_Printf("usage: skyroom origin_x origin_y origin_z paralax_scale speed axis_x axis_y axis_z\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
/*
|
|
|
|
====================
|
|
|
|
R_SetSkyfog_f -- ericw
|
|
|
|
====================
|
|
|
|
*/
|
|
|
|
static void R_SetSkyfog_f (cvar_t *var)
|
|
|
|
{
|
|
|
|
// clear any skyfog setting from worldspawn
|
|
|
|
skyfog = var->value;
|
|
|
|
}
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
=============
|
|
|
|
Sky_Init
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void Sky_Init (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2011-12-28 22:01:33 +00:00
|
|
|
Cvar_RegisterVariable (&r_fastsky);
|
|
|
|
Cvar_RegisterVariable (&r_sky_quality);
|
|
|
|
Cvar_RegisterVariable (&r_skyalpha);
|
|
|
|
Cvar_RegisterVariable (&r_skyfog);
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
Cvar_SetCallback (&r_skyfog, R_SetSkyfog_f);
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
Cmd_AddCommand ("sky",Sky_SkyCommand_f);
|
2019-11-02 20:22:54 +00:00
|
|
|
Cmd_AddCommand ("skyroom",Sky_SkyRoomCommand_f);
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2020-03-28 05:09:06 +00:00
|
|
|
skybox_name[0] = 0;
|
2010-02-15 23:26:55 +00:00
|
|
|
for (i=0; i<6; i++)
|
|
|
|
skybox_textures[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
//
|
|
|
|
// PROCESS SKY SURFS
|
|
|
|
//
|
|
|
|
//==============================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
Sky_ProjectPoly
|
|
|
|
|
|
|
|
update sky bounds
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void Sky_ProjectPoly (int nump, vec3_t vecs)
|
|
|
|
{
|
|
|
|
int i,j;
|
|
|
|
vec3_t v, av;
|
|
|
|
float s, t, dv;
|
|
|
|
int axis;
|
|
|
|
float *vp;
|
|
|
|
|
|
|
|
// decide which face it maps to
|
|
|
|
VectorCopy (vec3_origin, v);
|
|
|
|
for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
|
|
|
|
{
|
|
|
|
VectorAdd (vp, v, v);
|
|
|
|
}
|
|
|
|
av[0] = fabs(v[0]);
|
|
|
|
av[1] = fabs(v[1]);
|
|
|
|
av[2] = fabs(v[2]);
|
|
|
|
if (av[0] > av[1] && av[0] > av[2])
|
|
|
|
{
|
|
|
|
if (v[0] < 0)
|
|
|
|
axis = 1;
|
|
|
|
else
|
|
|
|
axis = 0;
|
|
|
|
}
|
|
|
|
else if (av[1] > av[2] && av[1] > av[0])
|
|
|
|
{
|
|
|
|
if (v[1] < 0)
|
|
|
|
axis = 3;
|
|
|
|
else
|
|
|
|
axis = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (v[2] < 0)
|
|
|
|
axis = 5;
|
|
|
|
else
|
|
|
|
axis = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// project new texture coords
|
|
|
|
for (i=0 ; i<nump ; i++, vecs+=3)
|
|
|
|
{
|
|
|
|
j = vec_to_st[axis][2];
|
|
|
|
if (j > 0)
|
|
|
|
dv = vecs[j - 1];
|
|
|
|
else
|
|
|
|
dv = -vecs[-j - 1];
|
|
|
|
|
|
|
|
j = vec_to_st[axis][0];
|
|
|
|
if (j < 0)
|
|
|
|
s = -vecs[-j -1] / dv;
|
|
|
|
else
|
|
|
|
s = vecs[j-1] / dv;
|
|
|
|
j = vec_to_st[axis][1];
|
|
|
|
if (j < 0)
|
|
|
|
t = -vecs[-j -1] / dv;
|
|
|
|
else
|
|
|
|
t = vecs[j-1] / dv;
|
|
|
|
|
|
|
|
if (s < skymins[0][axis])
|
|
|
|
skymins[0][axis] = s;
|
|
|
|
if (t < skymins[1][axis])
|
|
|
|
skymins[1][axis] = t;
|
|
|
|
if (s > skymaxs[0][axis])
|
|
|
|
skymaxs[0][axis] = s;
|
|
|
|
if (t > skymaxs[1][axis])
|
|
|
|
skymaxs[1][axis] = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
Sky_ClipPoly
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void Sky_ClipPoly (int nump, vec3_t vecs, int stage)
|
|
|
|
{
|
|
|
|
float *norm;
|
|
|
|
float *v;
|
|
|
|
qboolean front, back;
|
|
|
|
float d, e;
|
|
|
|
float dists[MAX_CLIP_VERTS];
|
|
|
|
int sides[MAX_CLIP_VERTS];
|
|
|
|
vec3_t newv[2][MAX_CLIP_VERTS];
|
|
|
|
int newc[2];
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
if (nump > MAX_CLIP_VERTS-2)
|
|
|
|
Sys_Error ("Sky_ClipPoly: MAX_CLIP_VERTS");
|
|
|
|
if (stage == 6) // fully clipped
|
|
|
|
{
|
|
|
|
Sky_ProjectPoly (nump, vecs);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
front = back = false;
|
|
|
|
norm = skyclip[stage];
|
|
|
|
for (i=0, v = vecs ; i<nump ; i++, v+=3)
|
|
|
|
{
|
|
|
|
d = DotProduct (v, norm);
|
|
|
|
if (d > ON_EPSILON)
|
|
|
|
{
|
|
|
|
front = true;
|
|
|
|
sides[i] = SIDE_FRONT;
|
|
|
|
}
|
|
|
|
else if (d < ON_EPSILON)
|
|
|
|
{
|
|
|
|
back = true;
|
|
|
|
sides[i] = SIDE_BACK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sides[i] = SIDE_ON;
|
|
|
|
dists[i] = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!front || !back)
|
|
|
|
{ // not clipped
|
|
|
|
Sky_ClipPoly (nump, vecs, stage+1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clip it
|
|
|
|
sides[i] = sides[0];
|
|
|
|
dists[i] = dists[0];
|
|
|
|
VectorCopy (vecs, (vecs+(i*3)) );
|
|
|
|
newc[0] = newc[1] = 0;
|
|
|
|
|
|
|
|
for (i=0, v = vecs ; i<nump ; i++, v+=3)
|
|
|
|
{
|
|
|
|
switch (sides[i])
|
|
|
|
{
|
|
|
|
case SIDE_FRONT:
|
|
|
|
VectorCopy (v, newv[0][newc[0]]);
|
|
|
|
newc[0]++;
|
|
|
|
break;
|
|
|
|
case SIDE_BACK:
|
|
|
|
VectorCopy (v, newv[1][newc[1]]);
|
|
|
|
newc[1]++;
|
|
|
|
break;
|
|
|
|
case SIDE_ON:
|
|
|
|
VectorCopy (v, newv[0][newc[0]]);
|
|
|
|
newc[0]++;
|
|
|
|
VectorCopy (v, newv[1][newc[1]]);
|
|
|
|
newc[1]++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
d = dists[i] / (dists[i] - dists[i+1]);
|
|
|
|
for (j=0 ; j<3 ; j++)
|
|
|
|
{
|
|
|
|
e = v[j] + d*(v[j+3] - v[j]);
|
|
|
|
newv[0][newc[0]][j] = e;
|
|
|
|
newv[1][newc[1]][j] = e;
|
|
|
|
}
|
|
|
|
newc[0]++;
|
|
|
|
newc[1]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// continue
|
|
|
|
Sky_ClipPoly (newc[0], newv[0][0], stage+1);
|
|
|
|
Sky_ClipPoly (newc[1], newv[1][0], stage+1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
Sky_ProcessPoly
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void Sky_ProcessPoly (glpoly_t *p)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
vec3_t verts[MAX_CLIP_VERTS];
|
|
|
|
|
|
|
|
//draw it
|
|
|
|
DrawGLPoly(p);
|
|
|
|
rs_brushpasses++;
|
|
|
|
|
|
|
|
//update sky bounds
|
|
|
|
if (!r_fastsky.value)
|
|
|
|
{
|
|
|
|
for (i=0 ; i<p->numverts ; i++)
|
|
|
|
VectorSubtract (p->verts[i], r_origin, verts[i]);
|
|
|
|
Sky_ClipPoly (p->numverts, verts[0], 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
Sky_ProcessTextureChains -- handles sky polys in world model
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void Sky_ProcessTextureChains (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
|
|
|
|
|
|
|
if (!r_drawworld_cheatsafe)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
|
|
|
|
{
|
|
|
|
t = cl.worldmodel->textures[i];
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (!t || !t->texturechains[chain_world] || !(t->texturechains[chain_world]->flags & SURF_DRAWSKY))
|
2010-02-15 23:26:55 +00:00
|
|
|
continue;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain_world]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
Sky_ProcessPoly (s->polys);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
Sky_ProcessEntities -- handles sky polys on brush models
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void Sky_ProcessEntities (void)
|
|
|
|
{
|
|
|
|
entity_t *e;
|
|
|
|
msurface_t *s;
|
|
|
|
glpoly_t *p;
|
|
|
|
int i,j,k,mark;
|
|
|
|
float dot;
|
|
|
|
qboolean rotated;
|
|
|
|
vec3_t temp, forward, right, up;
|
|
|
|
|
|
|
|
if (!r_drawentities.value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i=0 ; i<cl_numvisedicts ; i++)
|
|
|
|
{
|
|
|
|
e = cl_visedicts[i];
|
|
|
|
|
|
|
|
if (e->model->type != mod_brush)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (R_CullModelForEntity(e))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (e->alpha == ENTALPHA_ZERO)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
|
|
|
|
if (e->angles[0] || e->angles[1] || e->angles[2])
|
|
|
|
{
|
|
|
|
rotated = true;
|
|
|
|
AngleVectors (e->angles, forward, right, up);
|
|
|
|
VectorCopy (modelorg, temp);
|
|
|
|
modelorg[0] = DotProduct (temp, forward);
|
|
|
|
modelorg[1] = -DotProduct (temp, right);
|
|
|
|
modelorg[2] = DotProduct (temp, up);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rotated = false;
|
|
|
|
|
|
|
|
s = &e->model->surfaces[e->model->firstmodelsurface];
|
|
|
|
|
|
|
|
for (j=0 ; j<e->model->nummodelsurfaces ; j++, s++)
|
|
|
|
{
|
|
|
|
if (s->flags & SURF_DRAWSKY)
|
|
|
|
{
|
|
|
|
dot = DotProduct (modelorg, s->plane->normal) - s->plane->dist;
|
|
|
|
if (((s->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
|
|
|
|
(!(s->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
|
|
|
|
{
|
|
|
|
//copy the polygon and translate manually, since Sky_ProcessPoly needs it to be in world space
|
|
|
|
mark = Hunk_LowMark();
|
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
|
|
|
p = (glpoly_t *) Hunk_Alloc (sizeof(*s->polys)); //FIXME: don't allocate for each poly
|
2010-02-15 23:26:55 +00:00
|
|
|
p->numverts = s->polys->numverts;
|
|
|
|
for (k=0; k<p->numverts; k++)
|
|
|
|
{
|
|
|
|
if (rotated)
|
|
|
|
{
|
|
|
|
p->verts[k][0] = e->origin[0] + s->polys->verts[k][0] * forward[0]
|
|
|
|
- s->polys->verts[k][1] * right[0]
|
|
|
|
+ s->polys->verts[k][2] * up[0];
|
|
|
|
p->verts[k][1] = e->origin[1] + s->polys->verts[k][0] * forward[1]
|
|
|
|
- s->polys->verts[k][1] * right[1]
|
|
|
|
+ s->polys->verts[k][2] * up[1];
|
|
|
|
p->verts[k][2] = e->origin[2] + s->polys->verts[k][0] * forward[2]
|
|
|
|
- s->polys->verts[k][1] * right[2]
|
|
|
|
+ s->polys->verts[k][2] * up[2];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
VectorAdd(s->polys->verts[k], e->origin, p->verts[k]);
|
|
|
|
}
|
|
|
|
Sky_ProcessPoly (p);
|
|
|
|
Hunk_FreeToLowMark (mark);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
//
|
|
|
|
// RENDER SKYBOX
|
|
|
|
//
|
|
|
|
//==============================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
Sky_EmitSkyBoxVertex
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void Sky_EmitSkyBoxVertex (float s, float t, int axis)
|
|
|
|
{
|
|
|
|
vec3_t v, b;
|
|
|
|
int j, k;
|
|
|
|
float w, h;
|
|
|
|
|
|
|
|
b[0] = s * gl_farclip.value / sqrt(3.0);
|
|
|
|
b[1] = t * gl_farclip.value / sqrt(3.0);
|
|
|
|
b[2] = gl_farclip.value / sqrt(3.0);
|
|
|
|
|
|
|
|
for (j=0 ; j<3 ; j++)
|
|
|
|
{
|
|
|
|
k = st_to_vec[axis][j];
|
|
|
|
if (k < 0)
|
|
|
|
v[j] = -b[-k - 1];
|
|
|
|
else
|
|
|
|
v[j] = b[k - 1];
|
|
|
|
v[j] += r_origin[j];
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert from range [-1,1] to [0,1]
|
|
|
|
s = (s+1)*0.5;
|
|
|
|
t = (t+1)*0.5;
|
|
|
|
|
|
|
|
// avoid bilerp seam
|
|
|
|
w = skybox_textures[skytexorder[axis]]->width;
|
|
|
|
h = skybox_textures[skytexorder[axis]]->height;
|
|
|
|
s = s * (w-1)/w + 0.5/w;
|
|
|
|
t = t * (h-1)/h + 0.5/h;
|
|
|
|
|
|
|
|
t = 1.0 - t;
|
|
|
|
glTexCoord2f (s, t);
|
|
|
|
glVertex3fv (v);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
Sky_DrawSkyBox
|
|
|
|
|
|
|
|
FIXME: eliminate cracks by adding an extra vert on tjuncs
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void Sky_DrawSkyBox (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0 ; i<6 ; i++)
|
|
|
|
{
|
|
|
|
if (skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
GL_Bind (skybox_textures[skytexorder[i]]);
|
|
|
|
|
|
|
|
#if 1 //FIXME: this is to avoid tjunctions until i can do it the right way
|
|
|
|
skymins[0][i] = -1;
|
|
|
|
skymins[1][i] = -1;
|
|
|
|
skymaxs[0][i] = 1;
|
|
|
|
skymaxs[1][i] = 1;
|
|
|
|
#endif
|
|
|
|
glBegin (GL_QUADS);
|
|
|
|
Sky_EmitSkyBoxVertex (skymins[0][i], skymins[1][i], i);
|
|
|
|
Sky_EmitSkyBoxVertex (skymins[0][i], skymaxs[1][i], i);
|
|
|
|
Sky_EmitSkyBoxVertex (skymaxs[0][i], skymaxs[1][i], i);
|
|
|
|
Sky_EmitSkyBoxVertex (skymaxs[0][i], skymins[1][i], i);
|
|
|
|
glEnd ();
|
|
|
|
|
|
|
|
rs_skypolys++;
|
|
|
|
rs_skypasses++;
|
|
|
|
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
if (Fog_GetDensity() > 0 && skyfog > 0)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
float *c;
|
|
|
|
|
|
|
|
c = Fog_GetColor();
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
glColor4f (c[0],c[1],c[2], CLAMP(0.0,skyfog,1.0));
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
glBegin (GL_QUADS);
|
|
|
|
Sky_EmitSkyBoxVertex (skymins[0][i], skymins[1][i], i);
|
|
|
|
Sky_EmitSkyBoxVertex (skymins[0][i], skymaxs[1][i], i);
|
|
|
|
Sky_EmitSkyBoxVertex (skymaxs[0][i], skymaxs[1][i], i);
|
|
|
|
Sky_EmitSkyBoxVertex (skymaxs[0][i], skymins[1][i], i);
|
|
|
|
glEnd ();
|
|
|
|
|
|
|
|
glColor3f (1, 1, 1);
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
|
|
|
|
rs_skypasses++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
//
|
|
|
|
// RENDER CLOUDS
|
|
|
|
//
|
|
|
|
//==============================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
Sky_SetBoxVert
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void Sky_SetBoxVert (float s, float t, int axis, vec3_t v)
|
|
|
|
{
|
|
|
|
vec3_t b;
|
|
|
|
int j, k;
|
|
|
|
|
|
|
|
b[0] = s * gl_farclip.value / sqrt(3.0);
|
|
|
|
b[1] = t * gl_farclip.value / sqrt(3.0);
|
|
|
|
b[2] = gl_farclip.value / sqrt(3.0);
|
|
|
|
|
|
|
|
for (j=0 ; j<3 ; j++)
|
|
|
|
{
|
|
|
|
k = st_to_vec[axis][j];
|
|
|
|
if (k < 0)
|
|
|
|
v[j] = -b[-k - 1];
|
|
|
|
else
|
|
|
|
v[j] = b[k - 1];
|
|
|
|
v[j] += r_origin[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
Sky_GetTexCoord
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void Sky_GetTexCoord (vec3_t v, float speed, float *s, float *t)
|
|
|
|
{
|
|
|
|
vec3_t dir;
|
|
|
|
float length, scroll;
|
|
|
|
|
|
|
|
VectorSubtract (v, r_origin, dir);
|
|
|
|
dir[2] *= 3; // flatten the sphere
|
|
|
|
|
|
|
|
length = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];
|
|
|
|
length = sqrt (length);
|
|
|
|
length = 6*63/length;
|
|
|
|
|
|
|
|
scroll = cl.time*speed;
|
|
|
|
scroll -= (int)scroll & ~127;
|
|
|
|
|
|
|
|
*s = (scroll + dir[0] * length) * (1.0/128);
|
|
|
|
*t = (scroll + dir[1] * length) * (1.0/128);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Sky_DrawFaceQuad
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Sky_DrawFaceQuad (glpoly_t *p)
|
|
|
|
{
|
|
|
|
float s, t;
|
|
|
|
float *v;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (gl_mtexable && r_skyalpha.value >= 1.0)
|
|
|
|
{
|
|
|
|
GL_Bind (solidskytexture);
|
|
|
|
GL_EnableMultitexture();
|
|
|
|
GL_Bind (alphaskytexture);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
|
|
|
|
|
|
|
glBegin (GL_QUADS);
|
|
|
|
for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE)
|
|
|
|
{
|
|
|
|
Sky_GetTexCoord (v, 8, &s, &t);
|
2014-08-30 08:00:34 +00:00
|
|
|
GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, s, t);
|
2010-02-15 23:26:55 +00:00
|
|
|
Sky_GetTexCoord (v, 16, &s, &t);
|
2014-08-30 08:00:34 +00:00
|
|
|
GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, s, t);
|
2010-02-15 23:26:55 +00:00
|
|
|
glVertex3fv (v);
|
|
|
|
}
|
|
|
|
glEnd ();
|
|
|
|
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
|
|
|
|
rs_skypolys++;
|
|
|
|
rs_skypasses++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GL_Bind (solidskytexture);
|
|
|
|
|
|
|
|
if (r_skyalpha.value < 1.0)
|
|
|
|
glColor3f (1, 1, 1);
|
|
|
|
|
|
|
|
glBegin (GL_QUADS);
|
|
|
|
for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE)
|
|
|
|
{
|
|
|
|
Sky_GetTexCoord (v, 8, &s, &t);
|
|
|
|
glTexCoord2f (s, t);
|
|
|
|
glVertex3fv (v);
|
|
|
|
}
|
|
|
|
glEnd ();
|
|
|
|
|
|
|
|
GL_Bind (alphaskytexture);
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
|
|
|
|
if (r_skyalpha.value < 1.0)
|
|
|
|
glColor4f (1, 1, 1, r_skyalpha.value);
|
|
|
|
|
|
|
|
glBegin (GL_QUADS);
|
|
|
|
for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE)
|
|
|
|
{
|
|
|
|
Sky_GetTexCoord (v, 16, &s, &t);
|
|
|
|
glTexCoord2f (s, t);
|
|
|
|
glVertex3fv (v);
|
|
|
|
}
|
|
|
|
glEnd ();
|
|
|
|
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
|
|
|
|
rs_skypolys++;
|
|
|
|
rs_skypasses += 2;
|
|
|
|
}
|
|
|
|
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
if (Fog_GetDensity() > 0 && skyfog > 0)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
float *c;
|
|
|
|
|
|
|
|
c = Fog_GetColor();
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
glColor4f (c[0],c[1],c[2], CLAMP(0.0,skyfog,1.0));
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
glBegin (GL_QUADS);
|
|
|
|
for (i=0, v=p->verts[0] ; i<4 ; i++, v+=VERTEXSIZE)
|
|
|
|
glVertex3fv (v);
|
|
|
|
glEnd ();
|
|
|
|
|
|
|
|
glColor3f (1, 1, 1);
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
|
|
|
|
rs_skypasses++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
Sky_DrawFace
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void Sky_DrawFace (int axis)
|
|
|
|
{
|
|
|
|
glpoly_t *p;
|
|
|
|
vec3_t verts[4];
|
|
|
|
int i, j, start;
|
|
|
|
float di,qi,dj,qj;
|
|
|
|
vec3_t vup, vright, temp, temp2;
|
|
|
|
|
|
|
|
Sky_SetBoxVert(-1.0, -1.0, axis, verts[0]);
|
|
|
|
Sky_SetBoxVert(-1.0, 1.0, axis, verts[1]);
|
|
|
|
Sky_SetBoxVert(1.0, 1.0, axis, verts[2]);
|
|
|
|
Sky_SetBoxVert(1.0, -1.0, axis, verts[3]);
|
|
|
|
|
|
|
|
start = Hunk_LowMark ();
|
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
|
|
|
p = (glpoly_t *) Hunk_Alloc(sizeof(glpoly_t));
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
VectorSubtract(verts[2],verts[3],vup);
|
|
|
|
VectorSubtract(verts[2],verts[1],vright);
|
|
|
|
|
2011-01-10 10:35:40 +00:00
|
|
|
di = q_max((int)r_sky_quality.value, 1);
|
2010-02-15 23:26:55 +00:00
|
|
|
qi = 1.0 / di;
|
|
|
|
dj = (axis < 4) ? di*2 : di; //subdivide vertically more than horizontally on skybox sides
|
|
|
|
qj = 1.0 / dj;
|
|
|
|
|
|
|
|
for (i=0; i<di; i++)
|
|
|
|
{
|
|
|
|
for (j=0; j<dj; j++)
|
|
|
|
{
|
|
|
|
if (i*qi < skymins[0][axis]/2+0.5 - qi || i*qi > skymaxs[0][axis]/2+0.5 ||
|
|
|
|
j*qj < skymins[1][axis]/2+0.5 - qj || j*qj > skymaxs[1][axis]/2+0.5)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
//if (i&1 ^ j&1) continue; //checkerboard test
|
|
|
|
VectorScale (vright, qi*i, temp);
|
|
|
|
VectorScale (vup, qj*j, temp2);
|
|
|
|
VectorAdd(temp,temp2,temp);
|
|
|
|
VectorAdd(verts[0],temp,p->verts[0]);
|
|
|
|
|
|
|
|
VectorScale (vup, qj, temp);
|
|
|
|
VectorAdd (p->verts[0],temp,p->verts[1]);
|
|
|
|
|
|
|
|
VectorScale (vright, qi, temp);
|
|
|
|
VectorAdd (p->verts[1],temp,p->verts[2]);
|
|
|
|
|
|
|
|
VectorAdd (p->verts[0],temp,p->verts[3]);
|
|
|
|
|
|
|
|
Sky_DrawFaceQuad (p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Hunk_FreeToLowMark (start);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
Sky_DrawSkyLayers
|
|
|
|
|
|
|
|
draws the old-style scrolling cloud layers
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void Sky_DrawSkyLayers (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (r_skyalpha.value < 1.0)
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
|
|
|
|
for (i=0 ; i<6 ; i++)
|
|
|
|
if (skymins[0][i] < skymaxs[0][i] && skymins[1][i] < skymaxs[1][i])
|
|
|
|
Sky_DrawFace (i);
|
|
|
|
|
|
|
|
if (r_skyalpha.value < 1.0)
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
Sky_DrawSky
|
|
|
|
|
|
|
|
called once per frame before drawing anything else
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
void Sky_DrawSky (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
//in these special render modes, the sky faces are handled in the normal world/brush renderer
|
2019-09-10 17:58:03 +00:00
|
|
|
if (r_drawflat_cheatsafe || r_lightmap_cheatsafe || skyroom_drawn)
|
2010-02-15 23:26:55 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
//
|
|
|
|
// reset sky bounds
|
|
|
|
//
|
|
|
|
for (i=0 ; i<6 ; i++)
|
|
|
|
{
|
2020-03-28 05:09:09 +00:00
|
|
|
skymins[0][i] = skymins[1][i] = FLT_MAX;
|
|
|
|
skymaxs[0][i] = skymaxs[1][i] = -FLT_MAX;
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// process world and bmodels: draw flat-shaded sky surfs, and update skybounds
|
|
|
|
//
|
|
|
|
Fog_DisableGFog ();
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
|
|
|
if (Fog_GetDensity() > 0)
|
|
|
|
glColor3fv (Fog_GetColor());
|
|
|
|
else
|
|
|
|
glColor3fv (skyflatcolor);
|
|
|
|
Sky_ProcessTextureChains ();
|
|
|
|
Sky_ProcessEntities ();
|
|
|
|
glColor3f (1, 1, 1);
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
//
|
|
|
|
// render slow sky: cloud layers or skybox
|
|
|
|
//
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
if (!r_fastsky.value && !(Fog_GetDensity() > 0 && skyfog >= 1))
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
glDepthFunc(GL_GEQUAL);
|
|
|
|
glDepthMask(0);
|
|
|
|
|
|
|
|
if (skybox_name[0])
|
|
|
|
Sky_DrawSkyBox ();
|
|
|
|
else
|
|
|
|
Sky_DrawSkyLayers();
|
|
|
|
|
|
|
|
glDepthMask(1);
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
Fog_EnableGFog ();
|
2010-02-16 12:24:38 +00:00
|
|
|
}
|