2004-08-22 22:29:09 +00:00
/*
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
2011-05-15 13:23:13 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-08-22 22:29:09 +00:00
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_warp.c -- sky and water polygons
# include "quakedef.h"
2016-07-12 00:40:13 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
# include "glquake.h"
2005-04-16 16:21:27 +00:00
# include "shader.h"
2004-12-09 23:40:30 +00:00
# include <ctype.h>
2004-08-22 22:29:09 +00:00
2010-07-11 02:22:39 +00:00
static void R_CalcSkyChainBounds ( batch_t * s ) ;
static void GL_DrawSkySphere ( batch_t * fa , shader_t * shader ) ;
static void GL_SkyForceDepth ( batch_t * fa ) ;
static void GL_DrawSkyBox ( texid_t * texnums , batch_t * s ) ;
2004-08-22 22:29:09 +00:00
2016-07-12 00:40:13 +00:00
static void GL_DrawSkyGrid ( texnums_t * tex ) ;
2004-08-22 22:29:09 +00:00
2004-10-10 06:32:29 +00:00
extern cvar_t gl_skyboxdist ;
extern cvar_t r_fastsky ;
extern cvar_t r_fastskycolour ;
2009-07-14 23:42:54 +00:00
2010-07-11 02:22:39 +00:00
static shader_t * forcedskyshader ;
static shader_t * skyboxface ;
2016-07-12 00:40:13 +00:00
static shader_t * skygridface ;
2009-07-14 23:42:54 +00:00
2004-08-22 22:29:09 +00:00
//=========================================================
2010-07-11 02:22:39 +00:00
void R_SetSky ( char * skyname )
2009-07-14 23:42:54 +00:00
{
2017-07-28 01:49:25 +00:00
extern cvar_t r_skyboxname ;
forcedskyshader = NULL ;
if ( ! qrenderer )
return ;
if ( * r_skyboxname . string ) //user's setting overrides.
skyname = r_skyboxname . string ;
Shader_NeedReload ( false ) ;
2010-07-11 02:22:39 +00:00
if ( * skyname )
2013-08-21 07:14:39 +00:00
forcedskyshader = R_RegisterCustom ( va ( " skybox_%s " , skyname ) , SUF_NONE , Shader_DefaultSkybox , NULL ) ;
2009-07-14 23:42:54 +00:00
2013-08-21 07:14:39 +00:00
skyboxface = R_RegisterShader ( " skyboxface " , SUF_NONE ,
2010-07-11 02:22:39 +00:00
" { \n "
2013-05-11 14:02:55 +00:00
" program default2d \n "
2010-07-11 02:22:39 +00:00
" { \n "
" map $diffuse \n "
2014-03-30 08:55:06 +00:00
" nodepth \n " //don't write depth. this stuff is meant to be an infiniteish distance away.
2010-07-11 02:22:39 +00:00
" } \n "
" } \n "
) ;
2016-07-12 00:40:13 +00:00
skygridface = R_RegisterShader ( " skygridface " , SUF_NONE ,
" { \n "
" program default2d \n "
" { \n "
" map $diffuse \n "
" nodepth \n " //don't write depth. this stuff is meant to be an infiniteish distance away.
" } \n "
" { \n "
" map $fullbright \n "
" blendfunc blend \n "
" nodepth \n " //don't write depth. this stuff is meant to be an infiniteish distance away.
" } \n "
" } \n "
) ;
2009-07-14 23:42:54 +00:00
}
2004-08-22 22:29:09 +00:00
/*
= = = = = = = = = = = = = = = = =
2007-05-25 22:16:29 +00:00
GL_DrawSkyChain
2004-08-22 22:29:09 +00:00
= = = = = = = = = = = = = = = = =
*/
2016-01-18 05:22:07 +00:00
qboolean R_DrawSkyChain ( batch_t * batch )
2004-08-22 22:29:09 +00:00
{
2010-07-11 02:22:39 +00:00
shader_t * skyshader ;
2009-11-04 21:16:50 +00:00
texid_t * skyboxtex ;
2004-08-22 22:29:09 +00:00
2010-07-11 02:22:39 +00:00
if ( forcedskyshader )
skyshader = forcedskyshader ;
2009-07-14 23:42:54 +00:00
else
2010-07-11 02:22:39 +00:00
skyshader = batch - > shader ;
2005-05-15 18:49:04 +00:00
2016-01-18 05:22:07 +00:00
if ( skyshader - > prog )
return false ;
2010-07-11 02:22:39 +00:00
if ( skyshader - > skydome )
skyboxtex = skyshader - > skydome - > farbox_textures ;
else
skyboxtex = NULL ;
2009-08-12 08:12:36 +00:00
2010-11-13 17:22:46 +00:00
if ( skyboxtex & & TEXVALID ( * skyboxtex ) )
2004-10-10 06:32:29 +00:00
{
2010-07-11 02:22:39 +00:00
R_CalcSkyChainBounds ( batch ) ;
GL_DrawSkyBox ( skyboxtex , batch ) ;
2016-07-12 00:40:13 +00:00
if ( skyshader - > numpasses )
GL_DrawSkySphere ( batch , skyshader ) ;
2004-10-10 06:32:29 +00:00
}
2016-07-12 00:40:13 +00:00
else if ( skyshader - > numpasses )
2009-07-14 23:42:54 +00:00
{
2016-07-12 00:40:13 +00:00
if ( * r_fastsky . string & & TEXVALID ( batch - > shader - > defaulttextures - > base ) & & TEXVALID ( batch - > shader - > defaulttextures - > fullbright ) )
2014-02-13 23:54:57 +00:00
{
R_CalcSkyChainBounds ( batch ) ;
2015-09-14 10:36:42 +00:00
GL_DrawSkyGrid ( skyshader - > defaulttextures ) ;
2014-02-13 23:54:57 +00:00
}
else
GL_DrawSkySphere ( batch , skyshader ) ;
2009-07-14 23:42:54 +00:00
}
2014-02-13 23:54:57 +00:00
2016-07-12 00:40:13 +00:00
//neither skydomes nor skyboxes nor skygrids will have been drawn with the correct depth values for the sky.
2014-02-13 23:54:57 +00:00
//this can result in rooms behind the sky surfaces being visible.
//so make sure they're correct where they're expected to be.
//don't do it on q3 bsp, because q3map2 can't do skyrooms without being weird about it. or something. anyway, we get different (buggy) behaviour from q3 if we don't skip this.
//See: The Edge Of Forever (motef, by sock) for an example of where this needs to be skipped.
//See dm3 for an example of where the depth needs to be correct (OMG THERE'S PLAYERS IN MY SKYBOX! WALLHAXX!).
//you can't please them all.
if ( r_worldentity . model - > fromgame ! = fg_quake3 )
GL_SkyForceDepth ( batch ) ;
2016-01-18 05:22:07 +00:00
return true ;
2004-08-22 22:29:09 +00:00
}
2007-05-25 22:16:29 +00:00
2004-08-22 22:29:09 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Quake 2 environment sky
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2009-06-21 17:45:33 +00:00
static vec3_t skyclip [ 6 ] = {
2004-08-22 22:29:09 +00:00
{ 1 , 1 , 0 } ,
{ 1 , - 1 , 0 } ,
{ 0 , - 1 , 1 } ,
{ 0 , 1 , 1 } ,
{ 1 , 0 , 1 } ,
2011-05-15 13:23:13 +00:00
{ - 1 , 0 , 1 }
2004-08-22 22:29:09 +00:00
} ;
// 1 = s, 2 = t, 3 = 2048
2009-06-21 17:45:33 +00:00
static int st_to_vec [ 6 ] [ 3 ] =
2004-08-22 22:29:09 +00:00
{
{ 3 , - 1 , 2 } ,
{ - 3 , 1 , 2 } ,
{ 1 , 3 , 2 } ,
{ - 1 , - 3 , 2 } ,
{ - 2 , - 1 , 3 } , // 0 degrees yaw, look straight up
{ 2 , - 1 , - 3 } // look straight down
// {-1,2,3},
// {1,2,-3}
} ;
// s = [0]/[2], t = [1]/[2]
2009-06-21 17:45:33 +00:00
static int vec_to_st [ 6 ] [ 3 ] =
2004-08-22 22:29:09 +00:00
{
{ - 2 , 3 , 1 } ,
{ 2 , 3 , - 1 } ,
{ 1 , 3 , 2 } ,
{ - 1 , 3 , - 2 } ,
{ - 2 , - 1 , 3 } ,
{ - 2 , 1 , - 3 }
// {-1,2,3},
// {1,2,-3}
} ;
2009-06-21 17:45:33 +00:00
static float skymins [ 2 ] [ 6 ] , skymaxs [ 2 ] [ 6 ] ;
2004-08-22 22:29:09 +00:00
2009-06-21 17:45:33 +00:00
static void DrawSkyPolygon ( int nump , vec3_t vecs )
2004-08-22 22:29:09 +00:00
{
int i , j ;
vec3_t v , av ;
float s , t , dv ;
int axis ;
float * vp ;
// decide which face it maps to
2006-05-29 04:50:24 +00:00
VectorClear ( v ) ;
2004-08-22 22:29:09 +00:00
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 ] ;
if ( dv < 0.001 )
continue ; // don't divide by zero
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 ;
2016-07-12 00:40:13 +00:00
if ( skymins [ 0 ] [ axis ] > s )
2004-08-22 22:29:09 +00:00
skymins [ 0 ] [ axis ] = s ;
2016-07-12 00:40:13 +00:00
if ( skymins [ 1 ] [ axis ] > t )
2004-08-22 22:29:09 +00:00
skymins [ 1 ] [ axis ] = t ;
2016-07-12 00:40:13 +00:00
if ( skymaxs [ 0 ] [ axis ] < s )
2004-08-22 22:29:09 +00:00
skymaxs [ 0 ] [ axis ] = s ;
2016-07-12 00:40:13 +00:00
if ( skymaxs [ 1 ] [ axis ] < t )
2004-08-22 22:29:09 +00:00
skymaxs [ 1 ] [ axis ] = t ;
}
}
# define MAX_CLIP_VERTS 64
2009-06-21 17:45:33 +00:00
static void ClipSkyPolygon ( int nump , vec3_t vecs , int stage )
2004-08-22 22:29:09 +00:00
{
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 ( " ClipSkyPolygon: MAX_CLIP_VERTS " ) ;
if ( stage = = 6 )
{ // fully clipped, so draw it
DrawSkyPolygon ( 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
ClipSkyPolygon ( 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
ClipSkyPolygon ( newc [ 0 ] , newv [ 0 ] [ 0 ] , stage + 1 ) ;
ClipSkyPolygon ( newc [ 1 ] , newv [ 1 ] [ 0 ] , stage + 1 ) ;
}
/*
= = = = = = = = = = = = = = = = =
2007-05-25 22:16:29 +00:00
R_DrawSkyBoxChain
2004-08-22 22:29:09 +00:00
= = = = = = = = = = = = = = = = =
*/
2010-07-11 02:22:39 +00:00
static void R_CalcSkyChainBounds ( batch_t * batch )
2004-08-22 22:29:09 +00:00
{
2010-07-11 02:22:39 +00:00
mesh_t * mesh ;
2004-08-22 22:29:09 +00:00
2010-07-11 02:22:39 +00:00
int i , m ;
2004-08-22 22:29:09 +00:00
vec3_t verts [ MAX_CLIP_VERTS ] ;
2016-07-12 00:40:13 +00:00
if ( batch - > meshes = = 1 & & ! batch - > mesh [ batch - > firstmesh ] - > numindexes )
{ //deal with geometryless skies, like terrain/raw maps
for ( i = 0 ; i < 6 ; i + + )
{
skymins [ 0 ] [ i ] = skymins [ 1 ] [ i ] = - 1 ;
skymaxs [ 0 ] [ i ] = skymaxs [ 1 ] [ i ] = 1 ;
}
return ;
}
2009-11-04 21:16:50 +00:00
for ( i = 0 ; i < 6 ; i + + )
{
2016-07-12 00:40:13 +00:00
skymins [ 0 ] [ i ] = skymins [ 1 ] [ i ] = 1 ; //9999;
skymaxs [ 0 ] [ i ] = skymaxs [ 1 ] [ i ] = - 1 ; //-9999;
2009-11-04 21:16:50 +00:00
}
2004-08-22 22:29:09 +00:00
// calculate vertex values for sky box
2010-07-11 02:22:39 +00:00
for ( m = batch - > firstmesh ; m < batch - > meshes ; m + + )
2004-08-22 22:29:09 +00:00
{
2010-07-11 02:22:39 +00:00
mesh = batch - > mesh [ m ] ;
2015-04-14 23:12:17 +00:00
if ( ! mesh - > xyz_array )
continue ;
2005-04-16 16:21:27 +00:00
//triangulate
2016-07-12 00:40:13 +00:00
for ( i = 0 ; i < mesh - > numindexes ; i + = 3 )
2004-08-22 22:29:09 +00:00
{
2016-07-12 00:40:13 +00:00
VectorSubtract ( mesh - > xyz_array [ mesh - > indexes [ i + 0 ] ] , r_origin , verts [ 0 ] ) ;
VectorSubtract ( mesh - > xyz_array [ mesh - > indexes [ i + 1 ] ] , r_origin , verts [ 1 ] ) ;
VectorSubtract ( mesh - > xyz_array [ mesh - > indexes [ i + 2 ] ] , r_origin , verts [ 2 ] ) ;
2005-04-16 16:21:27 +00:00
ClipSkyPolygon ( 3 , verts [ 0 ] , 0 ) ;
2004-08-22 22:29:09 +00:00
}
}
2005-04-16 16:21:27 +00:00
}
2004-08-22 22:29:09 +00:00
2005-06-04 04:20:20 +00:00
# define skygridx 16
2005-04-16 16:21:27 +00:00
# define skygridx1 (skygridx + 1)
# define skygridxrecip (1.0f / (skygridx))
2005-06-04 04:20:20 +00:00
# define skygridy 16
2005-04-16 16:21:27 +00:00
# define skygridy1 (skygridy + 1)
# define skygridyrecip (1.0f / (skygridy))
# define skysphere_numverts (skygridx1 * skygridy1)
# define skysphere_numtriangles (skygridx * skygridy * 2)
2007-05-25 22:16:29 +00:00
2009-06-21 17:45:33 +00:00
static int skymade ;
2007-05-25 22:16:29 +00:00
static index_t skysphere_element3i [ skysphere_numtriangles * 3 ] ;
2005-04-16 16:21:27 +00:00
static float skysphere_texcoord2f [ skysphere_numverts * 2 ] ;
2007-05-25 22:16:29 +00:00
2009-11-04 21:16:50 +00:00
static vecV_t skysphere_vertex3f [ skysphere_numverts ] ;
2009-06-21 17:45:33 +00:00
static mesh_t skymesh ;
2005-04-16 16:21:27 +00:00
2007-05-25 22:16:29 +00:00
static void gl_skyspherecalc ( int skytype )
2005-04-16 16:21:27 +00:00
{ //yes, this is basically stolen from DarkPlaces
2007-05-25 22:16:29 +00:00
int i , j ;
index_t * e ;
2009-11-04 21:16:50 +00:00
float a , b , x , ax , ay , v [ 3 ] , length , * texcoord2f ;
vecV_t * vertex ;
2005-04-16 16:21:27 +00:00
float dx , dy , dz ;
float texscale ;
if ( skymade = = skytype )
return ;
skymade = skytype ;
if ( skymade = = 2 )
texscale = 1 / 16.0f ;
else
texscale = 1 / 1.5f ;
texscale * = 3 ;
skymesh . indexes = skysphere_element3i ;
skymesh . st_array = ( void * ) skysphere_texcoord2f ;
2012-07-05 19:42:36 +00:00
skymesh . lmst_array [ 0 ] = ( void * ) skysphere_texcoord2f ;
2005-05-13 10:42:48 +00:00
skymesh . xyz_array = ( void * ) skysphere_vertex3f ;
2005-04-16 16:21:27 +00:00
skymesh . numindexes = skysphere_numtriangles * 3 ;
skymesh . numvertexes = skysphere_numverts ;
2012-07-05 19:42:36 +00:00
dx = 1 ;
dy = 1 ;
dz = 1 / 3.0 ;
2009-11-04 21:16:50 +00:00
vertex = skysphere_vertex3f ;
2005-04-16 16:21:27 +00:00
texcoord2f = skysphere_texcoord2f ;
for ( j = 0 ; j < = skygridy ; j + + )
2004-08-22 22:29:09 +00:00
{
2005-04-16 16:21:27 +00:00
a = j * skygridyrecip ;
ax = cos ( a * M_PI * 2 ) ;
ay = - sin ( a * M_PI * 2 ) ;
for ( i = 0 ; i < = skygridx ; i + + )
2004-08-22 22:29:09 +00:00
{
2005-04-16 16:21:27 +00:00
b = i * skygridxrecip ;
x = cos ( ( b + 0.5 ) * M_PI ) ;
v [ 0 ] = ax * x * dx ;
v [ 1 ] = ay * x * dy ;
v [ 2 ] = - sin ( ( b + 0.5 ) * M_PI ) * dz ;
length = texscale / sqrt ( v [ 0 ] * v [ 0 ] + v [ 1 ] * v [ 1 ] + ( v [ 2 ] * v [ 2 ] * 9 ) ) ;
* texcoord2f + + = v [ 0 ] * length ;
* texcoord2f + + = v [ 1 ] * length ;
2009-11-04 21:16:50 +00:00
( * vertex ) [ 0 ] = v [ 0 ] ;
( * vertex ) [ 1 ] = v [ 1 ] ;
( * vertex ) [ 2 ] = v [ 2 ] ;
vertex + + ;
2004-08-22 22:29:09 +00:00
}
}
2005-04-16 16:21:27 +00:00
e = skysphere_element3i ;
for ( j = 0 ; j < skygridy ; j + + )
{
for ( i = 0 ; i < skygridx ; i + + )
{
* e + + = j * skygridx1 + i ;
* e + + = j * skygridx1 + i + 1 ;
* e + + = ( j + 1 ) * skygridx1 + i ;
2004-08-22 22:29:09 +00:00
2005-04-16 16:21:27 +00:00
* e + + = j * skygridx1 + i + 1 ;
* e + + = ( j + 1 ) * skygridx1 + i + 1 ;
* e + + = ( j + 1 ) * skygridx1 + i ;
}
}
}
2007-05-25 22:16:29 +00:00
2010-07-11 02:22:39 +00:00
static void GL_SkyForceDepth ( batch_t * batch )
2009-07-14 23:42:54 +00:00
{
2011-05-20 04:10:46 +00:00
if ( ! cls . allow_skyboxes & & batch - > texture ) //allow a little extra fps.
2009-07-14 23:42:54 +00:00
{
2011-04-20 23:34:13 +00:00
BE_SelectMode ( BEM_DEPTHONLY ) ;
2015-05-03 19:57:46 +00:00
BE_DrawMesh_List ( batch - > shader , batch - > meshes - batch - > firstmesh , batch - > mesh + batch - > firstmesh , batch - > vbo , NULL , batch - > flags ) ;
2011-04-20 23:34:13 +00:00
BE_SelectMode ( BEM_STANDARD ) ; /*skys only render in standard mode anyway, so this is safe*/
2009-07-14 23:42:54 +00:00
}
}
2010-11-13 17:22:46 +00:00
static void R_DrawSkyMesh ( batch_t * batch , mesh_t * m , shader_t * shader )
2004-08-22 22:29:09 +00:00
{
2010-11-11 18:22:49 +00:00
static entity_t skyent ;
batch_t b ;
2005-04-16 16:21:27 +00:00
2010-12-18 17:02:47 +00:00
float skydist = gl_skyboxdist . value ;
2005-04-16 16:21:27 +00:00
if ( skydist < 1 )
2016-10-22 07:06:51 +00:00
skydist = r_refdef . maxdist * 0.577 ;
2010-12-18 17:02:47 +00:00
if ( skydist < 1 )
skydist = 10000000 ;
2005-04-16 16:21:27 +00:00
2010-11-11 18:22:49 +00:00
VectorCopy ( r_refdef . vieworg , skyent . origin ) ;
skyent . axis [ 0 ] [ 0 ] = skydist ;
skyent . axis [ 0 ] [ 1 ] = 0 ;
2011-05-19 13:34:07 +00:00
skyent . axis [ 0 ] [ 2 ] = 0 ;
2010-11-11 18:22:49 +00:00
skyent . axis [ 1 ] [ 0 ] = 0 ;
skyent . axis [ 1 ] [ 1 ] = skydist ;
skyent . axis [ 1 ] [ 2 ] = 0 ;
skyent . axis [ 2 ] [ 0 ] = 0 ;
skyent . axis [ 2 ] [ 1 ] = 0 ;
skyent . axis [ 2 ] [ 2 ] = skydist ;
skyent . scale = 1 ;
2005-04-16 16:21:27 +00:00
//FIXME: We should use the skybox clipping code and split the sphere into 6 sides.
2010-11-11 18:22:49 +00:00
b = * batch ;
b . meshes = 1 ;
b . firstmesh = 0 ;
b . mesh = & m ;
b . ent = & skyent ;
b . shader = shader ;
2015-05-03 19:57:46 +00:00
b . skin = NULL ;
2010-12-18 17:02:47 +00:00
b . texture = NULL ;
2012-07-05 19:42:36 +00:00
b . vbo = NULL ;
2016-10-22 07:06:51 +00:00
Vector4Set ( skyent . shaderRGBAf , 1 , 1 , 1 , 1 ) ;
2010-11-11 18:22:49 +00:00
BE_SubmitBatch ( & b ) ;
2004-08-22 22:29:09 +00:00
}
2007-05-25 22:16:29 +00:00
2010-11-13 17:22:46 +00:00
static void GL_DrawSkySphere ( batch_t * batch , shader_t * shader )
{
//FIXME: We should use the skybox clipping code and split the sphere into 6 sides.
gl_skyspherecalc ( 2 ) ;
R_DrawSkyMesh ( batch , & skymesh , shader ) ;
}
2007-05-25 22:16:29 +00:00
2010-07-11 02:22:39 +00:00
static void GL_MakeSkyVec ( float s , float t , int axis , float * vc , float * tc )
2004-08-22 22:29:09 +00:00
{
2010-07-11 02:22:39 +00:00
vec3_t b ;
2004-08-22 22:29:09 +00:00
int j , k ;
2004-10-10 06:32:29 +00:00
2010-11-13 17:22:46 +00:00
b [ 0 ] = s ;
b [ 1 ] = t ;
b [ 2 ] = 1 ;
2004-08-22 22:29:09 +00:00
for ( j = 0 ; j < 3 ; j + + )
{
k = st_to_vec [ axis ] [ j ] ;
if ( k < 0 )
2010-07-11 02:22:39 +00:00
vc [ j ] = - b [ - k - 1 ] ;
2004-08-22 22:29:09 +00:00
else
2010-07-11 02:22:39 +00:00
vc [ j ] = b [ k - 1 ] ;
2004-08-22 22:29:09 +00:00
}
// avoid bilerp seam
s = ( s + 1 ) * 0.5 ;
t = ( t + 1 ) * 0.5 ;
if ( s < 1.0 / 512 )
s = 1.0 / 512 ;
else if ( s > 511.0 / 512 )
s = 511.0 / 512 ;
if ( t < 1.0 / 512 )
t = 1.0 / 512 ;
else if ( t > 511.0 / 512 )
t = 511.0 / 512 ;
2010-07-11 02:22:39 +00:00
tc [ 0 ] = s ;
tc [ 1 ] = 1.0 - t ;
2004-08-22 22:29:09 +00:00
}
2009-07-14 23:42:54 +00:00
2016-07-12 00:40:13 +00:00
static float speedscale1 ; // for top sky
static float speedscale2 ; // for bottom sky
static void EmitSkyGridVert ( vec3_t v , vec2_t tc1 , vec2_t tc2 )
2009-07-14 23:42:54 +00:00
{
vec3_t dir ;
float length ;
VectorSubtract ( v , r_origin , dir ) ;
dir [ 2 ] * = 3 ; // flatten the sphere
length = VectorLength ( dir ) ;
length = 6 * 63 / length ;
dir [ 0 ] * = length ;
dir [ 1 ] * = length ;
2016-07-12 00:40:13 +00:00
tc1 [ 0 ] = ( speedscale1 + dir [ 0 ] ) * ( 1.0 / 128 ) ;
tc1 [ 1 ] = ( speedscale1 + dir [ 1 ] ) * ( 1.0 / 128 ) ;
2009-07-14 23:42:54 +00:00
2016-07-12 00:40:13 +00:00
tc2 [ 0 ] = ( speedscale2 + dir [ 0 ] ) * ( 1.0 / 128 ) ;
tc2 [ 1 ] = ( speedscale2 + dir [ 1 ] ) * ( 1.0 / 128 ) ;
2009-07-14 23:42:54 +00:00
}
// s and t range from -1 to 1
2016-07-12 00:40:13 +00:00
static void MakeSkyGridVec2 ( float s , float t , int axis , vec3_t v , vec2_t tc1 , vec2_t tc2 )
2009-07-14 23:42:54 +00:00
{
vec3_t b ;
int j , k ;
2011-04-30 17:58:24 +00:00
float skydist = gl_skyboxdist . value ;
if ( skydist < 1 )
2016-10-22 07:06:51 +00:00
skydist = r_refdef . maxdist * 0.577 ;
2011-04-30 17:58:24 +00:00
if ( skydist < 1 )
skydist = 10000000 ;
2009-07-14 23:42:54 +00:00
b [ 0 ] = s * skydist ;
b [ 1 ] = t * skydist ;
b [ 2 ] = skydist ;
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 ] ;
}
2016-07-12 00:40:13 +00:00
EmitSkyGridVert ( v , tc1 , tc2 ) ;
2009-07-14 23:42:54 +00:00
}
# define SUBDIVISIONS 10
2016-07-12 00:40:13 +00:00
static void GL_DrawSkyGridFace ( int axis , mesh_t * fte_restrict mesh )
2009-07-14 23:42:54 +00:00
{
int i , j ;
float s , t ;
float fstep = 2.0 / SUBDIVISIONS ;
for ( i = 0 ; i < SUBDIVISIONS ; i + + )
{
s = ( float ) ( i * 2 - SUBDIVISIONS ) / SUBDIVISIONS ;
if ( s + fstep < skymins [ 0 ] [ axis ] | | s > skymaxs [ 0 ] [ axis ] )
continue ;
for ( j = 0 ; j < SUBDIVISIONS ; j + + )
{
t = ( float ) ( j * 2 - SUBDIVISIONS ) / SUBDIVISIONS ;
if ( t + fstep < skymins [ 1 ] [ axis ] | | t > skymaxs [ 1 ] [ axis ] )
continue ;
2016-07-12 00:40:13 +00:00
mesh - > indexes [ mesh - > numindexes + + ] = mesh - > numvertexes + 0 ;
mesh - > indexes [ mesh - > numindexes + + ] = mesh - > numvertexes + 1 ;
mesh - > indexes [ mesh - > numindexes + + ] = mesh - > numvertexes + 2 ;
mesh - > indexes [ mesh - > numindexes + + ] = mesh - > numvertexes + 0 ;
mesh - > indexes [ mesh - > numindexes + + ] = mesh - > numvertexes + 2 ;
mesh - > indexes [ mesh - > numindexes + + ] = mesh - > numvertexes + 3 ;
MakeSkyGridVec2 ( s , t , axis , mesh - > xyz_array [ mesh - > numvertexes ] , mesh - > st_array [ mesh - > numvertexes ] , mesh - > lmst_array [ 0 ] [ mesh - > numvertexes ] ) ; mesh - > numvertexes + + ;
MakeSkyGridVec2 ( s , t + fstep , axis , mesh - > xyz_array [ mesh - > numvertexes ] , mesh - > st_array [ mesh - > numvertexes ] , mesh - > lmst_array [ 0 ] [ mesh - > numvertexes ] ) ; mesh - > numvertexes + + ;
MakeSkyGridVec2 ( s + fstep , t + fstep , axis , mesh - > xyz_array [ mesh - > numvertexes ] , mesh - > st_array [ mesh - > numvertexes ] , mesh - > lmst_array [ 0 ] [ mesh - > numvertexes ] ) ; mesh - > numvertexes + + ;
MakeSkyGridVec2 ( s + fstep , t , axis , mesh - > xyz_array [ mesh - > numvertexes ] , mesh - > st_array [ mesh - > numvertexes ] , mesh - > lmst_array [ 0 ] [ mesh - > numvertexes ] ) ; mesh - > numvertexes + + ;
2009-07-14 23:42:54 +00:00
}
}
}
2015-09-14 10:36:42 +00:00
static void GL_DrawSkyGrid ( texnums_t * tex )
2009-07-14 23:42:54 +00:00
{
2016-07-12 00:40:13 +00:00
static entity_t skyent ;
static batch_t b ;
static mesh_t skymesh , * meshptr = & skymesh ;
vecV_t coords [ SUBDIVISIONS * SUBDIVISIONS * 4 * 6 ] ;
vec2_t texcoords1 [ SUBDIVISIONS * SUBDIVISIONS * 4 * 6 ] ;
vec2_t texcoords2 [ SUBDIVISIONS * SUBDIVISIONS * 4 * 6 ] ;
index_t indexes [ SUBDIVISIONS * SUBDIVISIONS * 6 * 6 ] ;
2009-07-14 23:42:54 +00:00
int i ;
float time = cl . gametime + realtime - cl . gametimemark ;
2016-07-12 00:40:13 +00:00
speedscale1 = time * 8 ;
speedscale1 - = ( int ) speedscale1 & ~ 127 ;
speedscale2 = time * 16 ;
speedscale2 - = ( int ) speedscale2 & ~ 127 ;
2009-07-14 23:42:54 +00:00
2016-07-12 00:40:13 +00:00
skymesh . indexes = indexes ;
skymesh . st_array = texcoords1 ;
skymesh . lmst_array [ 0 ] = texcoords2 ;
skymesh . xyz_array = coords ;
skymesh . numindexes = 0 ;
skymesh . numvertexes = 0 ;
2009-07-14 23:42:54 +00:00
for ( i = 0 ; i < 6 ; i + + )
{
if ( ( skymins [ 0 ] [ i ] > = skymaxs [ 0 ] [ i ] | | skymins [ 1 ] [ i ] > = skymaxs [ 1 ] [ i ] ) )
continue ;
2016-07-12 00:40:13 +00:00
GL_DrawSkyGridFace ( i , & skymesh ) ;
2009-07-14 23:42:54 +00:00
}
2016-07-12 00:40:13 +00:00
VectorCopy ( r_refdef . vieworg , skyent . origin ) ;
skyent . axis [ 0 ] [ 0 ] = 1 ;
skyent . axis [ 0 ] [ 1 ] = 0 ;
skyent . axis [ 0 ] [ 2 ] = 0 ;
skyent . axis [ 1 ] [ 0 ] = 0 ;
skyent . axis [ 1 ] [ 1 ] = 1 ;
skyent . axis [ 1 ] [ 2 ] = 0 ;
skyent . axis [ 2 ] [ 0 ] = 0 ;
skyent . axis [ 2 ] [ 1 ] = 0 ;
skyent . axis [ 2 ] [ 2 ] = 1 ;
skyent . scale = 1 ;
2009-07-14 23:42:54 +00:00
2016-07-12 00:40:13 +00:00
//FIXME: We should use the skybox clipping code and split the sphere into 6 sides.
b . meshes = 1 ;
b . firstmesh = 0 ;
b . mesh = & meshptr ;
b . ent = & skyent ;
b . shader = skygridface ;
b . skin = tex ;
b . texture = NULL ;
b . vbo = NULL ;
BE_SubmitBatch ( & b ) ;
2009-07-14 23:42:54 +00:00
}
2004-08-22 22:29:09 +00:00
/*
= = = = = = = = = = = = = =
R_DrawSkyBox
= = = = = = = = = = = = = =
*/
2009-11-04 21:16:50 +00:00
static int skytexorder [ 6 ] = { 0 , 2 , 1 , 3 , 4 , 5 } ;
2010-07-11 02:22:39 +00:00
static void GL_DrawSkyBox ( texid_t * texnums , batch_t * s )
2004-08-22 22:29:09 +00:00
{
int i ;
2010-07-11 02:22:39 +00:00
vecV_t skyface_vertex [ 4 ] ;
vec2_t skyface_texcoord [ 4 ] ;
index_t skyface_index [ 6 ] = { 0 , 1 , 2 , 0 , 2 , 3 } ;
2013-05-20 16:01:40 +00:00
vec4_t skyface_colours [ 4 ] = { { 1 , 1 , 1 , 1 } , { 1 , 1 , 1 , 1 } , { 1 , 1 , 1 , 1 } , { 1 , 1 , 1 , 1 } } ;
2010-07-11 02:22:39 +00:00
mesh_t skyfacemesh = { 0 } ;
2004-08-22 22:29:09 +00:00
2009-11-04 21:16:50 +00:00
if ( cl . skyrotate )
2005-10-15 20:08:50 +00:00
{
for ( i = 0 ; i < 6 ; i + + )
{
if ( skymins [ 0 ] [ i ] < skymaxs [ 0 ] [ i ]
& & skymins [ 1 ] [ i ] < skymaxs [ 1 ] [ i ] )
break ;
skymins [ 0 ] [ i ] = - 1 ; //fully visible
skymins [ 1 ] [ i ] = - 1 ;
skymaxs [ 0 ] [ i ] = 1 ;
skymaxs [ 1 ] [ i ] = 1 ;
}
if ( i = = 6 )
return ; //can't see anything
for ( ; i < 6 ; i + + )
{
skymins [ 0 ] [ i ] = - 1 ;
skymins [ 1 ] [ i ] = - 1 ;
skymaxs [ 0 ] [ i ] = 1 ;
skymaxs [ 1 ] [ i ] = 1 ;
}
}
2010-07-11 02:22:39 +00:00
skyfacemesh . indexes = skyface_index ;
skyfacemesh . st_array = skyface_texcoord ;
skyfacemesh . xyz_array = skyface_vertex ;
2013-08-27 13:18:09 +00:00
skyfacemesh . colors4f_array [ 0 ] = skyface_colours ;
2010-07-11 02:22:39 +00:00
skyfacemesh . numindexes = 6 ;
skyfacemesh . numvertexes = 4 ;
2005-10-15 20:08:50 +00:00
2004-08-22 22:29:09 +00:00
for ( i = 0 ; i < 6 ; i + + )
{
if ( skymins [ 0 ] [ i ] > = skymaxs [ 0 ] [ i ]
| | skymins [ 1 ] [ i ] > = skymaxs [ 1 ] [ i ] )
continue ;
2010-07-11 02:22:39 +00:00
GL_MakeSkyVec ( skymins [ 0 ] [ i ] , skymins [ 1 ] [ i ] , i , skyface_vertex [ 0 ] , skyface_texcoord [ 0 ] ) ;
GL_MakeSkyVec ( skymins [ 0 ] [ i ] , skymaxs [ 1 ] [ i ] , i , skyface_vertex [ 1 ] , skyface_texcoord [ 1 ] ) ;
GL_MakeSkyVec ( skymaxs [ 0 ] [ i ] , skymaxs [ 1 ] [ i ] , i , skyface_vertex [ 2 ] , skyface_texcoord [ 2 ] ) ;
GL_MakeSkyVec ( skymaxs [ 0 ] [ i ] , skymins [ 1 ] [ i ] , i , skyface_vertex [ 3 ] , skyface_texcoord [ 3 ] ) ;
2005-04-16 16:21:27 +00:00
2015-05-03 19:57:46 +00:00
skyboxface - > defaulttextures - > base = texnums [ skytexorder [ i ] ] ;
2010-11-13 17:22:46 +00:00
R_DrawSkyMesh ( s , & skyfacemesh , skyboxface ) ;
2004-08-22 22:29:09 +00:00
}
}
//===============================================================
/*
= = = = = = = = = = = = =
R_InitSky
2016-09-08 19:04:35 +00:00
A sky image is 256 * 128 and comprises two logical textures .
the left is the transparent / blended part . the right is the opaque / background part .
2004-08-22 22:29:09 +00:00
= = = = = = = = = = = = = =
*/
2015-05-03 19:57:46 +00:00
void R_InitSky ( shader_t * shader , const char * skyname , qbyte * src , unsigned int width , unsigned int height )
2004-08-22 22:29:09 +00:00
{
int i , j , p ;
2016-09-08 19:04:35 +00:00
unsigned * temp ;
2007-05-25 22:16:29 +00:00
unsigned transpix , alphamask ;
2004-08-22 22:29:09 +00:00
int r , g , b ;
unsigned * rgba ;
2016-09-08 19:04:35 +00:00
char name [ MAX_QPATH * 2 ] ;
2004-08-22 22:29:09 +00:00
2015-04-14 23:12:17 +00:00
unsigned int stride = width ;
width / = 2 ;
2015-10-11 11:34:58 +00:00
if ( width < 1 | | height < 1 | | stride ! = width * 2 | | ! src )
2015-04-14 23:12:17 +00:00
return ;
2016-09-08 19:04:35 +00:00
//try to load dual-layer-single-image skies.
//this is always going to be lame special case crap
2015-07-14 15:50:18 +00:00
{
2016-09-08 19:04:35 +00:00
size_t filesize = 0 ;
qbyte * filedata = NULL ;
if ( ! filedata )
{
Q_snprintfz ( name , sizeof ( name ) , " textures/%s.tga " , skyname ) ;
filedata = FS_LoadMallocFile ( name , & filesize ) ;
}
if ( ! filedata )
{
Q_snprintfz ( name , sizeof ( name ) , " textures/%s.png " , skyname ) ;
filedata = FS_LoadMallocFile ( name , & filesize ) ;
}
if ( filedata )
{
int imagewidth , imageheight ;
qboolean hasalpha ; //fixme, if this is false, is it worth all this code?
unsigned int * imagedata = ( unsigned int * ) Read32BitImageFile ( filedata , filesize , & imagewidth , & imageheight , & hasalpha , name ) ;
Z_Free ( filedata ) ;
if ( imagedata & & ! ( imagewidth & 1 ) )
{
imagewidth > > = 1 ;
temp = BZF_Malloc ( imagewidth * imageheight * sizeof ( * temp ) ) ;
if ( temp )
{
2016-10-22 07:06:51 +00:00
for ( i = 0 ; i < imageheight ; i + + )
for ( j = 0 ; j < imagewidth ; j + + )
2016-09-08 19:04:35 +00:00
{
2016-10-22 07:06:51 +00:00
temp [ i * imagewidth + j ] = imagedata [ i * ( imagewidth < < 1 ) + j + imagewidth ] ;
2016-09-08 19:04:35 +00:00
}
Q_snprintfz ( name , sizeof ( name ) , " %s_solid " , skyname ) ;
Q_strlwr ( name ) ;
shader - > defaulttextures - > base = R_LoadReplacementTexture ( name , NULL , IF_NOALPHA , temp , imagewidth , imageheight , TF_RGBX32 ) ;
2016-10-22 07:06:51 +00:00
for ( i = 0 ; i < imageheight ; i + + )
for ( j = 0 ; j < imagewidth ; j + + )
2016-09-08 19:04:35 +00:00
{
2016-10-22 07:06:51 +00:00
temp [ i * imagewidth + j ] = imagedata [ i * ( imagewidth < < 1 ) + j ] ;
2016-09-08 19:04:35 +00:00
}
BZ_Free ( imagedata ) ;
Q_snprintfz ( name , sizeof ( name ) , " %s_alpha:%s_trans " , skyname , skyname ) ;
Q_strlwr ( name ) ;
shader - > defaulttextures - > fullbright = R_LoadReplacementTexture ( name , NULL , 0 , temp , imagewidth , imageheight , TF_RGBA32 ) ;
BZ_Free ( temp ) ;
return ;
}
}
BZ_Free ( imagedata ) ;
}
2015-07-14 15:50:18 +00:00
}
2016-09-08 19:04:35 +00:00
temp = BZ_Malloc ( width * height * sizeof ( * temp ) ) ;
2004-08-22 22:29:09 +00:00
// make an average value for the back to avoid
// a fringe on the top level
r = g = b = 0 ;
2015-04-14 23:12:17 +00:00
for ( i = 0 ; i < height ; i + + )
for ( j = 0 ; j < width ; j + + )
2004-08-22 22:29:09 +00:00
{
2015-04-14 23:12:17 +00:00
p = src [ i * stride + j + width ] ;
2004-08-22 22:29:09 +00:00
rgba = & d_8to24rgbtable [ p ] ;
2016-09-08 19:04:35 +00:00
temp [ ( i * width ) + j ] = * rgba ;
2004-08-22 22:29:09 +00:00
r + = ( ( qbyte * ) rgba ) [ 0 ] ;
g + = ( ( qbyte * ) rgba ) [ 1 ] ;
b + = ( ( qbyte * ) rgba ) [ 2 ] ;
}
2015-05-03 19:57:46 +00:00
if ( ! shader - > defaulttextures - > base )
{
Q_snprintfz ( name , sizeof ( name ) , " %s_solid " , skyname ) ;
Q_strlwr ( name ) ;
2016-09-08 19:04:35 +00:00
shader - > defaulttextures - > base = R_LoadReplacementTexture ( name , NULL , IF_NOALPHA , temp , width , height , TF_RGBX32 ) ;
2015-05-03 19:57:46 +00:00
}
2004-08-22 22:29:09 +00:00
2015-05-03 19:57:46 +00:00
if ( ! shader - > defaulttextures - > fullbright )
{
2016-09-08 19:04:35 +00:00
//fixme: use premultiplied alpha here.
2015-05-03 19:57:46 +00:00
( ( qbyte * ) & transpix ) [ 0 ] = r / ( width * height ) ;
( ( qbyte * ) & transpix ) [ 1 ] = g / ( width * height ) ;
( ( qbyte * ) & transpix ) [ 2 ] = b / ( width * height ) ;
( ( qbyte * ) & transpix ) [ 3 ] = 0 ;
alphamask = LittleLong ( 0x7fffffff ) ;
for ( i = 0 ; i < height ; i + + )
for ( j = 0 ; j < width ; j + + )
{
p = src [ i * stride + j ] ;
if ( p = = 0 )
2016-09-08 19:04:35 +00:00
temp [ ( i * width ) + j ] = transpix ;
2015-05-03 19:57:46 +00:00
else
2016-09-08 19:04:35 +00:00
temp [ ( i * width ) + j ] = d_8to24rgbtable [ p ] & alphamask ;
2015-05-03 19:57:46 +00:00
}
//FIXME: support _trans
2016-09-08 19:04:35 +00:00
Q_snprintfz ( name , sizeof ( name ) , " %s_alpha:%s_trans " , skyname , skyname ) ;
2015-05-03 19:57:46 +00:00
Q_strlwr ( name ) ;
2016-09-08 19:04:35 +00:00
shader - > defaulttextures - > fullbright = R_LoadReplacementTexture ( name , NULL , 0 , temp , width , height , TF_RGBA32 ) ;
2015-05-03 19:57:46 +00:00
}
2016-09-08 19:04:35 +00:00
BZ_Free ( temp ) ;
2004-08-22 22:29:09 +00:00
}
2004-12-15 19:53:30 +00:00
# endif