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
2017-08-29 02:29:06 +00:00
static shader_t * forcedsky ;
2010-07-11 02:22:39 +00:00
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
//=========================================================
2017-08-29 02:29:06 +00:00
//called on video shutdown to reset internal state
void R_SkyShutdown ( void )
2009-07-14 23:42:54 +00:00
{
2017-08-29 02:29:06 +00:00
skyboxface = NULL ;
skygridface = NULL ;
forcedsky = NULL ;
}
2017-07-28 01:49:25 +00:00
2017-08-29 02:29:06 +00:00
void R_SetSky ( const char * sky )
{
int i ;
const char * shadername ;
extern cvar_t r_skyboxname ;
Q_strncpyz ( cl . skyname , sky , sizeof ( cl . skyname ) ) ;
if ( * r_skyboxname . string ) //override it with the user's preference
sky = r_skyboxname . string ;
2017-07-28 01:49:25 +00:00
2017-08-29 02:29:06 +00:00
shadername = va ( " skybox_%s " , sky ) ;
if ( ! forcedsky | | strcmp ( shadername , forcedsky - > name ) )
{
forcedsky = NULL ; //fall back to regular skies if forcing fails.
2017-07-28 01:49:25 +00:00
2017-08-29 02:29:06 +00:00
if ( ! * sky )
return ; //no need to do anything
2009-07-14 23:42:54 +00:00
2017-08-29 02:29:06 +00:00
//if we have cubemaps then we can just go and use a cubemap for our skybox
if ( sh_config . havecubemaps )
{
texnums_t tex ;
memset ( & tex , 0 , sizeof ( tex ) ) ;
tex . reflectcube = R_LoadHiResTexture ( sky , " env:gfx/env " , IF_LOADNOW | IF_CUBEMAP | IF_CLAMP ) ;
if ( tex . reflectcube - > width )
{
2019-07-29 05:28:20 +00:00
forcedsky = R_RegisterShader ( va ( " skybox_%s " , sky ) , 0 , " { \n sort sky \n program defaultskybox \n { \n depthwrite \n map \" $cube:$reflectcube \" \n tcgen skybox \n } \n surfaceparm nodlight \n surfaceparm sky \n } " ) ;
2018-09-29 17:31:58 +00:00
R_BuildDefaultTexnums ( & tex , forcedsky , IF_WORLDTEX ) ;
2017-08-29 02:29:06 +00:00
return ;
}
}
2016-07-12 00:40:13 +00:00
2017-08-29 02:29:06 +00:00
//crappy old path that I still need to fix up a bit
//unlike cubemaps, this works on gl1.1/gles1, and also works with the different faces as different sizes.
2018-08-23 06:03:31 +00:00
forcedsky = R_RegisterShader ( shadername , 0 , va ( " { \n sort sky \n skyparms \" %s \" 512 - \n surfaceparm nodlight \n } " , sky ) ) ;
2017-08-29 02:29:06 +00:00
//check that we actually got some textures.
//we accept the skybox if even 1 face is valid.
//we ignore the replacement only request if all are invalid.
for ( i = 0 ; i < 6 ; i + + )
{
extern texid_t missing_texture ;
if ( forcedsky - > skydome & & forcedsky - > skydome - > farbox_textures [ i ] ! = missing_texture )
break ;
}
if ( i = = 6 ) //couldn't find ANY sky textures.
forcedsky = NULL ;
}
2009-07-14 23:42:54 +00:00
}
2004-08-22 22:29:09 +00:00
2017-08-29 02:29:06 +00:00
void R_DrawFastSky ( batch_t * batch )
{
batch_t b = * batch ;
b . shader = R_RegisterShader ( " fastsky " , 0 , " { \n "
" sort sky \n "
" { \n "
" map $whiteimage \n "
" rgbgen const $r_fastskycolour \n "
" } \n "
" surfaceparm nodlight \n "
" } \n " ) ;
b . skin = NULL ;
b . texture = NULL ;
BE_SubmitBatch ( & b ) ;
}
2019-04-01 10:16:36 +00:00
2019-07-29 05:28:20 +00:00
//annoyingly sky does not always write depth values.
//this can allow entities to appear beyond it.
//this can include (massive) entities outside of the skyroom.
//so, we can only draw entities in skyrooms if:
//1) either the ents have robust pvs info and we can draw ONLY the ones actually inside the skyroom
//2) or if r_ignoreentpvs==1 we must mask depth and waste a whole load of batches drawing invisible ents in the sky
extern cvar_t r_ignoreentpvs ;
2019-04-01 10:16:36 +00:00
qboolean R_DrawSkyroom ( shader_t * skyshader )
{
float vmat [ 16 ] ;
refdef_t oldrefdef ;
2019-07-29 05:28:20 +00:00
// extern cvar_t r_ignoreentpvs; //legacy value is 1...
2019-07-19 02:13:19 +00:00
extern cvar_t v_skyroom_orientation ;
2019-04-01 10:16:36 +00:00
if ( r_viewcluster = = - 1 )
return false ; //don't draw the skyroom if the camera is outside.
2019-07-16 02:59:12 +00:00
if ( r_fastsky . value )
return false ; //skyrooms can be expensive.
2019-04-01 10:16:36 +00:00
if ( ! r_refdef . skyroom_enabled | | r_refdef . recurse > = R_MAX_RECURSE - 1 )
return false ;
oldrefdef = r_refdef ;
r_refdef . recurse + = 1 ;
2019-07-29 05:28:20 +00:00
// if (r_ignoreentpvs.ival) //if we're ignoring ent pvs then we're probably drawing lots of ents in the skybox that shouldn't be there
// r_refdef.firstvisedict = cl_numvisedicts;
2019-07-16 02:59:12 +00:00
r_refdef . externalview = true ; //an out-of-body experience...
2019-04-01 10:16:36 +00:00
r_refdef . skyroom_enabled = false ;
2019-07-16 02:59:12 +00:00
r_refdef . forcevis = false ;
2019-07-02 04:12:20 +00:00
r_refdef . flags | = RDF_DISABLEPARTICLES ;
2019-07-16 02:59:12 +00:00
r_refdef . flags & = ~ RDF_SKIPSKY ;
r_refdef . forcedvis = NULL ;
r_refdef . areabitsknown = false ; //recalculate areas clientside.
2019-04-01 10:16:36 +00:00
/*work out where the camera should be (use the same angles)*/
VectorCopy ( r_refdef . skyroom_pos , r_refdef . vieworg ) ;
VectorCopy ( r_refdef . skyroom_pos , r_refdef . pvsorigin ) ;
2019-07-16 02:59:12 +00:00
if ( developer . ival )
if ( r_worldentity . model - > funcs . PointContents ( r_worldentity . model , NULL , r_refdef . skyroom_pos ) & FTECONTENTS_SOLID )
Con_DPrintf ( " Skyroom position %.1f %.1f %.1f in solid \n " , r_refdef . skyroom_pos [ 0 ] , r_refdef . skyroom_pos [ 1 ] , r_refdef . skyroom_pos [ 2 ] ) ;
2019-07-19 02:13:19 +00:00
if ( * v_skyroom_orientation . string )
2019-07-16 02:59:12 +00:00
{
vec3_t axis [ 3 ] ;
2019-07-19 02:13:19 +00:00
float ang = v_skyroom_orientation . vec4 [ 3 ] * cl . time ;
if ( ! v_skyroom_orientation . vec4 [ 0 ] & & ! v_skyroom_orientation . vec4 [ 1 ] & & ! v_skyroom_orientation . vec4 [ 2 ] )
VectorSet ( v_skyroom_orientation . vec4 , 0 , 0 , 1 ) ;
VectorNormalize ( v_skyroom_orientation . vec4 ) ;
RotatePointAroundVector ( axis [ 0 ] , v_skyroom_orientation . vec4 , vpn , ang ) ;
RotatePointAroundVector ( axis [ 1 ] , v_skyroom_orientation . vec4 , vright , ang ) ;
RotatePointAroundVector ( axis [ 2 ] , v_skyroom_orientation . vec4 , vup , ang ) ;
2019-07-16 02:59:12 +00:00
Matrix4x4_CM_ModelViewMatrixFromAxis ( vmat , axis [ 0 ] , axis [ 1 ] , axis [ 2 ] , r_refdef . vieworg ) ;
}
2019-07-19 02:13:19 +00:00
else
2019-07-16 02:59:12 +00:00
Matrix4x4_CM_ModelViewMatrixFromAxis ( vmat , vpn , vright , vup , r_refdef . vieworg ) ;
2019-04-01 10:16:36 +00:00
R_SetFrustum ( r_refdef . m_projection_std , vmat ) ;
//now determine the stuff the backend will use.
memcpy ( r_refdef . m_view , vmat , sizeof ( float ) * 16 ) ;
VectorAngles ( vpn , vup , r_refdef . viewangles , false ) ;
VectorCopy ( r_refdef . vieworg , r_origin ) ;
Surf_SetupFrame ( ) ;
2019-07-29 06:04:43 +00:00
Surf_DrawWorld ( ) ;
2019-04-01 10:16:36 +00:00
r_refdef = oldrefdef ;
/*broken stuff*/
AngleVectors ( r_refdef . viewangles , vpn , vright , vup ) ;
VectorCopy ( r_refdef . vieworg , r_origin ) ;
return true ;
}
2019-07-29 05:28:20 +00:00
//q3 mustn't mask sky (breaks q3map2's invisible skyportals), whereas q1 must (or its a cheat). halflife doesn't normally expect masking.
//we also MUST mask any sky inside skyrooms, or you'll see all the entities outside of the skyroom through the room's own sky (q3map2 skyportals are hopefully irrelevant in this case).
# define SKYMUSTBEMASKED (r_worldentity.model->fromgame != fg_quake3 || ((r_refdef.flags & RDF_DISABLEPARTICLES) && !r_ignoreentpvs.ival))
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
2017-08-29 02:29:06 +00:00
if ( r_fastsky . value )
{
R_DrawFastSky ( batch ) ;
return true ; //depth will always be drawn with this pathway.
}
if ( forcedsky )
{
skyshader = forcedsky ;
2019-07-29 05:28:20 +00:00
if ( r_refdef . flags & RDF_SKIPSKY )
{
if ( r_worldentity . model - > fromgame ! = fg_quake3 )
GL_SkyForceDepth ( batch ) ;
return true ;
}
2017-10-31 22:52:58 +00:00
if ( forcedsky - > numpasses & & ! forcedsky - > skydome )
2017-08-29 02:29:06 +00:00
{ //cubemap skies!
2017-10-31 22:52:58 +00:00
//this is just a simple pass. we use glsl/texgen for any actual work
2017-08-29 02:29:06 +00:00
batch_t b = * batch ;
b . shader = forcedsky ;
b . skin = NULL ;
b . texture = NULL ;
BE_SubmitBatch ( & b ) ;
return true ;
}
}
2009-07-14 23:42:54 +00:00
else
2017-08-29 02:29:06 +00:00
{
2010-07-11 02:22:39 +00:00
skyshader = batch - > shader ;
2017-08-29 02:29:06 +00:00
if ( skyshader - > prog ) //glsl is expected to do the whole skybox/warpsky thing itself, with no assistance from this legacy code.
2019-04-01 10:16:36 +00:00
{
2019-07-19 02:13:19 +00:00
if ( r_refdef . flags & RDF_SKIPSKY )
{
2019-07-29 05:28:20 +00:00
if ( SKYMUSTBEMASKED )
2019-07-19 02:13:19 +00:00
GL_SkyForceDepth ( batch ) ;
return true ;
}
2019-04-01 10:16:36 +00:00
//if the first pass is transparent in some form, then be prepared to give it a skyroom behind.
return false ; //draw as normal...
}
2017-08-29 02:29:06 +00:00
}
2016-01-18 05:22:07 +00:00
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
2019-07-16 02:59:12 +00:00
if ( r_refdef . flags & RDF_SKIPSKY )
2019-07-02 04:12:20 +00:00
{ //don't obscure the skyroom if the sky shader is opaque.
qboolean opaque = false ;
2019-04-01 10:16:36 +00:00
if ( skyshader - > numpasses )
2019-07-02 04:12:20 +00:00
{
shaderpass_t * pass = skyshader - > passes ;
if ( pass - > shaderbits & SBITS_ATEST_BITS ) //alphatests
;
else if ( pass - > shaderbits & SBITS_MASK_BITS ) //colormasks
;
else if ( ( pass - > shaderbits & SBITS_BLEND_BITS ) ! = 0 & & ( pass - > shaderbits & SBITS_BLEND_BITS ) ! = ( SBITS_SRCBLEND_ONE | SBITS_DSTBLEND_ZERO ) ) //blendfunc
;
else
opaque = true ; //that shader looks like its opaque.
}
if ( ! opaque )
2019-04-01 10:16:36 +00:00
GL_DrawSkySphere ( batch , skyshader ) ;
}
else if ( skyboxtex & & TEXVALID ( * skyboxtex ) )
2017-10-31 22:52:58 +00:00
{ //draw a skybox if we were given the textures
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 )
2017-10-31 22:52:58 +00:00
{ //if we have passes, then they're normally projected.
2018-01-22 19:18:04 +00:00
if ( * r_fastsky . string & & skyshader - > numpasses = = 2 & & TEXVALID ( batch - > shader - > defaulttextures - > base ) & & TEXVALID ( batch - > shader - > defaulttextures - > fullbright ) )
2017-10-31 22:52:58 +00:00
{ //we have a small perf trick to accelerate q1 skies, also helps avoids distortions, but doesn't work too well for any other type of sky.
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
}
2017-10-31 22:52:58 +00:00
else if ( batch - > meshes )
{ //skys are weird.
//they're the one type of surface with implicit nodraw when there's no passes.
if ( batch - > shader - > skydome | | batch - > shader - > numpasses )
R_DrawFastSky ( batch ) ;
return true ; //depth will always be drawn with this pathway... or we were not drawing anything anyway...
}
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.
2019-07-29 05:28:20 +00:00
if ( SKYMUSTBEMASKED )
2014-02-13 23:54:57 +00:00
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 ] ;
2017-08-29 02:29:06 +00:00
if ( ! mesh - > xyz_array | | ! mesh - > indexes )
2015-04-14 23:12:17 +00:00
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
2017-08-29 02:29:06 +00:00
if ( ! skygridface )
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 "
) ;
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
2017-08-29 02:29:06 +00:00
if ( ! skyboxface )
skyboxface = R_RegisterShader ( " skyboxface " , 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 "
) ;
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
2018-07-22 11:49:37 +00:00
if ( gl_load24bit . ival )
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 ;
2018-09-29 17:31:58 +00:00
uploadfmt_t format ; //fixme, if this has no alpha, is it worth all this code?
unsigned int * imagedata = ( unsigned int * ) ReadRawImageFile ( filedata , filesize , & imagewidth , & imageheight , & format , true , name ) ;
2016-09-08 19:04:35 +00:00
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