You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1692 lines
38 KiB
1692 lines
38 KiB
/* |
|
Copyright (C) 1997-2001 Id Software, Inc. |
|
|
|
This program is free software; you can redistribute it and/or |
|
modify it under the terms of the GNU General Public License |
|
as published by the Free Software Foundation; either version 2 |
|
of the License, or (at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
|
|
See the GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program; if not, write to the Free Software |
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
|
|
*/ |
|
// r_main.c |
|
#include "gl_local.h" |
|
|
|
void R_Clear (void); |
|
|
|
viddef_t vid; |
|
|
|
refimport_t ri; |
|
|
|
model_t *r_worldmodel; |
|
|
|
float gldepthmin, gldepthmax; |
|
|
|
glconfig_t gl_config; |
|
glstate_t gl_state; |
|
|
|
image_t *r_notexture; // use for bad textures |
|
image_t *r_particletexture; // little dot for particles |
|
|
|
entity_t *currententity; |
|
model_t *currentmodel; |
|
|
|
cplane_t frustum[4]; |
|
|
|
int r_visframecount; // bumped when going to a new PVS |
|
int r_framecount; // used for dlight push checking |
|
|
|
int c_brush_polys, c_alias_polys; |
|
|
|
float v_blend[4]; // final blending color |
|
|
|
void GL_Strings_f( void ); |
|
|
|
// |
|
// view origin |
|
// |
|
vec3_t vup; |
|
vec3_t vpn; |
|
vec3_t vright; |
|
vec3_t r_origin; |
|
|
|
float r_world_matrix[16]; |
|
float r_base_world_matrix[16]; |
|
|
|
// |
|
// screen size info |
|
// |
|
refdef_t r_newrefdef; |
|
|
|
int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; |
|
|
|
cvar_t *r_norefresh; |
|
cvar_t *r_drawentities; |
|
cvar_t *r_drawworld; |
|
cvar_t *r_speeds; |
|
cvar_t *r_fullbright; |
|
cvar_t *r_novis; |
|
cvar_t *r_nocull; |
|
cvar_t *r_lerpmodels; |
|
cvar_t *r_lefthand; |
|
|
|
cvar_t *r_lightlevel; // FIXME: This is a HACK to get the client's light level |
|
|
|
cvar_t *gl_nosubimage; |
|
cvar_t *gl_allow_software; |
|
|
|
cvar_t *gl_vertex_arrays; |
|
|
|
cvar_t *gl_particle_min_size; |
|
cvar_t *gl_particle_max_size; |
|
cvar_t *gl_particle_size; |
|
cvar_t *gl_particle_att_a; |
|
cvar_t *gl_particle_att_b; |
|
cvar_t *gl_particle_att_c; |
|
|
|
cvar_t *gl_ext_swapinterval; |
|
cvar_t *gl_ext_palettedtexture; |
|
cvar_t *gl_ext_multitexture; |
|
cvar_t *gl_ext_pointparameters; |
|
cvar_t *gl_ext_compiled_vertex_array; |
|
|
|
cvar_t *gl_log; |
|
cvar_t *gl_bitdepth; |
|
cvar_t *gl_drawbuffer; |
|
cvar_t *gl_driver; |
|
cvar_t *gl_lightmap; |
|
cvar_t *gl_shadows; |
|
cvar_t *gl_mode; |
|
cvar_t *gl_dynamic; |
|
cvar_t *gl_monolightmap; |
|
cvar_t *gl_modulate; |
|
cvar_t *gl_nobind; |
|
cvar_t *gl_round_down; |
|
cvar_t *gl_picmip; |
|
cvar_t *gl_skymip; |
|
cvar_t *gl_showtris; |
|
cvar_t *gl_ztrick; |
|
cvar_t *gl_finish; |
|
cvar_t *gl_clear; |
|
cvar_t *gl_cull; |
|
cvar_t *gl_polyblend; |
|
cvar_t *gl_flashblend; |
|
cvar_t *gl_playermip; |
|
cvar_t *gl_saturatelighting; |
|
cvar_t *gl_swapinterval; |
|
cvar_t *gl_texturemode; |
|
cvar_t *gl_texturealphamode; |
|
cvar_t *gl_texturesolidmode; |
|
cvar_t *gl_lockpvs; |
|
|
|
cvar_t *gl_3dlabs_broken; |
|
|
|
cvar_t *vid_fullscreen; |
|
cvar_t *vid_gamma; |
|
cvar_t *vid_ref; |
|
|
|
/* |
|
================= |
|
R_CullBox |
|
|
|
Returns true if the box is completely outside the frustom |
|
================= |
|
*/ |
|
qboolean R_CullBox (vec3_t mins, vec3_t maxs) |
|
{ |
|
int i; |
|
|
|
if (r_nocull->value) |
|
return false; |
|
|
|
for (i=0 ; i<4 ; i++) |
|
if ( BOX_ON_PLANE_SIDE(mins, maxs, &frustum[i]) == 2) |
|
return true; |
|
return false; |
|
} |
|
|
|
|
|
void R_RotateForEntity (entity_t *e) |
|
{ |
|
qglTranslatef (e->origin[0], e->origin[1], e->origin[2]); |
|
|
|
qglRotatef (e->angles[1], 0, 0, 1); |
|
qglRotatef (-e->angles[0], 0, 1, 0); |
|
qglRotatef (-e->angles[2], 1, 0, 0); |
|
} |
|
|
|
/* |
|
============================================================= |
|
|
|
SPRITE MODELS |
|
|
|
============================================================= |
|
*/ |
|
|
|
|
|
/* |
|
================= |
|
R_DrawSpriteModel |
|
|
|
================= |
|
*/ |
|
void R_DrawSpriteModel (entity_t *e) |
|
{ |
|
float alpha = 1.0F; |
|
vec3_t point; |
|
dsprframe_t *frame; |
|
float *up, *right; |
|
dsprite_t *psprite; |
|
|
|
// don't even bother culling, because it's just a single |
|
// polygon without a surface cache |
|
|
|
psprite = (dsprite_t *)currentmodel->extradata; |
|
|
|
#if 0 |
|
if (e->frame < 0 || e->frame >= psprite->numframes) |
|
{ |
|
ri.Con_Printf (PRINT_ALL, "no such sprite frame %i\n", e->frame); |
|
e->frame = 0; |
|
} |
|
#endif |
|
e->frame %= psprite->numframes; |
|
|
|
frame = &psprite->frames[e->frame]; |
|
|
|
#if 0 |
|
if (psprite->type == SPR_ORIENTED) |
|
{ // bullet marks on walls |
|
vec3_t v_forward, v_right, v_up; |
|
|
|
AngleVectors (currententity->angles, v_forward, v_right, v_up); |
|
up = v_up; |
|
right = v_right; |
|
} |
|
else |
|
#endif |
|
{ // normal sprite |
|
up = vup; |
|
right = vright; |
|
} |
|
|
|
if ( e->flags & RF_TRANSLUCENT ) |
|
alpha = e->alpha; |
|
|
|
if ( alpha != 1.0F ) |
|
qglEnable( GL_BLEND ); |
|
|
|
qglColor4f( 1, 1, 1, alpha ); |
|
|
|
GL_Bind(currentmodel->skins[e->frame]->texnum); |
|
|
|
GL_TexEnv( GL_MODULATE ); |
|
|
|
if ( alpha == 1.0 ) |
|
qglEnable (GL_ALPHA_TEST); |
|
else |
|
qglDisable( GL_ALPHA_TEST ); |
|
|
|
qglBegin (GL_QUADS); |
|
|
|
qglTexCoord2f (0, 1); |
|
VectorMA (e->origin, -frame->origin_y, up, point); |
|
VectorMA (point, -frame->origin_x, right, point); |
|
qglVertex3fv (point); |
|
|
|
qglTexCoord2f (0, 0); |
|
VectorMA (e->origin, frame->height - frame->origin_y, up, point); |
|
VectorMA (point, -frame->origin_x, right, point); |
|
qglVertex3fv (point); |
|
|
|
qglTexCoord2f (1, 0); |
|
VectorMA (e->origin, frame->height - frame->origin_y, up, point); |
|
VectorMA (point, frame->width - frame->origin_x, right, point); |
|
qglVertex3fv (point); |
|
|
|
qglTexCoord2f (1, 1); |
|
VectorMA (e->origin, -frame->origin_y, up, point); |
|
VectorMA (point, frame->width - frame->origin_x, right, point); |
|
qglVertex3fv (point); |
|
|
|
qglEnd (); |
|
|
|
qglDisable (GL_ALPHA_TEST); |
|
GL_TexEnv( GL_REPLACE ); |
|
|
|
if ( alpha != 1.0F ) |
|
qglDisable( GL_BLEND ); |
|
|
|
qglColor4f( 1, 1, 1, 1 ); |
|
} |
|
|
|
//================================================================================== |
|
|
|
/* |
|
============= |
|
R_DrawNullModel |
|
============= |
|
*/ |
|
void R_DrawNullModel (void) |
|
{ |
|
vec3_t shadelight; |
|
int i; |
|
|
|
if ( currententity->flags & RF_FULLBRIGHT ) |
|
shadelight[0] = shadelight[1] = shadelight[2] = 1.0F; |
|
else |
|
R_LightPoint (currententity->origin, shadelight); |
|
|
|
qglPushMatrix (); |
|
R_RotateForEntity (currententity); |
|
|
|
qglDisable (GL_TEXTURE_2D); |
|
qglColor3fv (shadelight); |
|
|
|
qglBegin (GL_TRIANGLE_FAN); |
|
qglVertex3f (0, 0, -16); |
|
for (i=0 ; i<=4 ; i++) |
|
qglVertex3f (16*cos(i*M_PI/2), 16*sin(i*M_PI/2), 0); |
|
qglEnd (); |
|
|
|
qglBegin (GL_TRIANGLE_FAN); |
|
qglVertex3f (0, 0, 16); |
|
for (i=4 ; i>=0 ; i--) |
|
qglVertex3f (16*cos(i*M_PI/2), 16*sin(i*M_PI/2), 0); |
|
qglEnd (); |
|
|
|
qglColor3f (1,1,1); |
|
qglPopMatrix (); |
|
qglEnable (GL_TEXTURE_2D); |
|
} |
|
|
|
/* |
|
============= |
|
R_DrawEntitiesOnList |
|
============= |
|
*/ |
|
void R_DrawEntitiesOnList (void) |
|
{ |
|
int i; |
|
|
|
if (!r_drawentities->value) |
|
return; |
|
|
|
// draw non-transparent first |
|
for (i=0 ; i<r_newrefdef.num_entities ; i++) |
|
{ |
|
currententity = &r_newrefdef.entities[i]; |
|
if (currententity->flags & RF_TRANSLUCENT) |
|
continue; // solid |
|
|
|
if ( currententity->flags & RF_BEAM ) |
|
{ |
|
R_DrawBeam( currententity ); |
|
} |
|
else |
|
{ |
|
currentmodel = currententity->model; |
|
if (!currentmodel) |
|
{ |
|
R_DrawNullModel (); |
|
continue; |
|
} |
|
switch (currentmodel->type) |
|
{ |
|
case mod_alias: |
|
R_DrawAliasModel (currententity); |
|
break; |
|
case mod_brush: |
|
R_DrawBrushModel (currententity); |
|
break; |
|
case mod_sprite: |
|
R_DrawSpriteModel (currententity); |
|
break; |
|
default: |
|
ri.Sys_Error (ERR_DROP, "Bad modeltype"); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
// draw transparent entities |
|
// we could sort these if it ever becomes a problem... |
|
qglDepthMask (0); // no z writes |
|
for (i=0 ; i<r_newrefdef.num_entities ; i++) |
|
{ |
|
currententity = &r_newrefdef.entities[i]; |
|
if (!(currententity->flags & RF_TRANSLUCENT)) |
|
continue; // solid |
|
|
|
if ( currententity->flags & RF_BEAM ) |
|
{ |
|
R_DrawBeam( currententity ); |
|
} |
|
else |
|
{ |
|
currentmodel = currententity->model; |
|
|
|
if (!currentmodel) |
|
{ |
|
R_DrawNullModel (); |
|
continue; |
|
} |
|
switch (currentmodel->type) |
|
{ |
|
case mod_alias: |
|
R_DrawAliasModel (currententity); |
|
break; |
|
case mod_brush: |
|
R_DrawBrushModel (currententity); |
|
break; |
|
case mod_sprite: |
|
R_DrawSpriteModel (currententity); |
|
break; |
|
default: |
|
ri.Sys_Error (ERR_DROP, "Bad modeltype"); |
|
break; |
|
} |
|
} |
|
} |
|
qglDepthMask (1); // back to writing |
|
|
|
} |
|
|
|
/* |
|
** GL_DrawParticles |
|
** |
|
*/ |
|
void GL_DrawParticles( int num_particles, const particle_t particles[], const unsigned colortable[768] ) |
|
{ |
|
const particle_t *p; |
|
int i; |
|
vec3_t up, right; |
|
float scale; |
|
byte color[4]; |
|
|
|
GL_Bind(r_particletexture->texnum); |
|
qglDepthMask( GL_FALSE ); // no z buffering |
|
qglEnable( GL_BLEND ); |
|
GL_TexEnv( GL_MODULATE ); |
|
qglBegin( GL_TRIANGLES ); |
|
|
|
VectorScale (vup, 1.5, up); |
|
VectorScale (vright, 1.5, right); |
|
|
|
for ( p = particles, i=0 ; i < num_particles ; i++,p++) |
|
{ |
|
// hack a scale up to keep particles from disapearing |
|
scale = ( p->origin[0] - r_origin[0] ) * vpn[0] + |
|
( p->origin[1] - r_origin[1] ) * vpn[1] + |
|
( p->origin[2] - r_origin[2] ) * vpn[2]; |
|
|
|
if (scale < 20) |
|
scale = 1; |
|
else |
|
scale = 1 + scale * 0.004; |
|
|
|
*(int *)color = colortable[p->color]; |
|
color[3] = p->alpha*255; |
|
|
|
qglColor4ubv( color ); |
|
|
|
qglTexCoord2f( 0.0625, 0.0625 ); |
|
qglVertex3fv( p->origin ); |
|
|
|
qglTexCoord2f( 1.0625, 0.0625 ); |
|
qglVertex3f( p->origin[0] + up[0]*scale, |
|
p->origin[1] + up[1]*scale, |
|
p->origin[2] + up[2]*scale); |
|
|
|
qglTexCoord2f( 0.0625, 1.0625 ); |
|
qglVertex3f( p->origin[0] + right[0]*scale, |
|
p->origin[1] + right[1]*scale, |
|
p->origin[2] + right[2]*scale); |
|
} |
|
|
|
qglEnd (); |
|
qglDisable( GL_BLEND ); |
|
qglColor4f( 1,1,1,1 ); |
|
qglDepthMask( 1 ); // back to normal Z buffering |
|
GL_TexEnv( GL_REPLACE ); |
|
} |
|
|
|
/* |
|
=============== |
|
R_DrawParticles |
|
=============== |
|
*/ |
|
void R_DrawParticles (void) |
|
{ |
|
if ( gl_ext_pointparameters->value && qglPointParameterfEXT ) |
|
{ |
|
int i; |
|
unsigned char color[4]; |
|
const particle_t *p; |
|
|
|
qglDepthMask( GL_FALSE ); |
|
qglEnable( GL_BLEND ); |
|
qglDisable( GL_TEXTURE_2D ); |
|
|
|
qglPointSize( gl_particle_size->value ); |
|
|
|
qglBegin( GL_POINTS ); |
|
for ( i = 0, p = r_newrefdef.particles; i < r_newrefdef.num_particles; i++, p++ ) |
|
{ |
|
*(int *)color = d_8to24table[p->color]; |
|
color[3] = p->alpha*255; |
|
|
|
qglColor4ubv( color ); |
|
|
|
qglVertex3fv( p->origin ); |
|
} |
|
qglEnd(); |
|
|
|
qglDisable( GL_BLEND ); |
|
qglColor4f( 1.0F, 1.0F, 1.0F, 1.0F ); |
|
qglDepthMask( GL_TRUE ); |
|
qglEnable( GL_TEXTURE_2D ); |
|
|
|
} |
|
else |
|
{ |
|
GL_DrawParticles( r_newrefdef.num_particles, r_newrefdef.particles, d_8to24table ); |
|
} |
|
} |
|
|
|
/* |
|
============ |
|
R_PolyBlend |
|
============ |
|
*/ |
|
void R_PolyBlend (void) |
|
{ |
|
if (!gl_polyblend->value) |
|
return; |
|
if (!v_blend[3]) |
|
return; |
|
|
|
qglDisable (GL_ALPHA_TEST); |
|
qglEnable (GL_BLEND); |
|
qglDisable (GL_DEPTH_TEST); |
|
qglDisable (GL_TEXTURE_2D); |
|
|
|
qglLoadIdentity (); |
|
|
|
// FIXME: get rid of these |
|
qglRotatef (-90, 1, 0, 0); // put Z going up |
|
qglRotatef (90, 0, 0, 1); // put Z going up |
|
|
|
qglColor4fv (v_blend); |
|
|
|
qglBegin (GL_QUADS); |
|
|
|
qglVertex3f (10, 100, 100); |
|
qglVertex3f (10, -100, 100); |
|
qglVertex3f (10, -100, -100); |
|
qglVertex3f (10, 100, -100); |
|
qglEnd (); |
|
|
|
qglDisable (GL_BLEND); |
|
qglEnable (GL_TEXTURE_2D); |
|
qglEnable (GL_ALPHA_TEST); |
|
|
|
qglColor4f(1,1,1,1); |
|
} |
|
|
|
//======================================================================= |
|
|
|
int SignbitsForPlane (cplane_t *out) |
|
{ |
|
int bits, j; |
|
|
|
// for fast box on planeside test |
|
|
|
bits = 0; |
|
for (j=0 ; j<3 ; j++) |
|
{ |
|
if (out->normal[j] < 0) |
|
bits |= 1<<j; |
|
} |
|
return bits; |
|
} |
|
|
|
|
|
void R_SetFrustum (void) |
|
{ |
|
int i; |
|
|
|
#if 0 |
|
/* |
|
** this code is wrong, since it presume a 90 degree FOV both in the |
|
** horizontal and vertical plane |
|
*/ |
|
// front side is visible |
|
VectorAdd (vpn, vright, frustum[0].normal); |
|
VectorSubtract (vpn, vright, frustum[1].normal); |
|
VectorAdd (vpn, vup, frustum[2].normal); |
|
VectorSubtract (vpn, vup, frustum[3].normal); |
|
|
|
// we theoretically don't need to normalize these vectors, but I do it |
|
// anyway so that debugging is a little easier |
|
VectorNormalize( frustum[0].normal ); |
|
VectorNormalize( frustum[1].normal ); |
|
VectorNormalize( frustum[2].normal ); |
|
VectorNormalize( frustum[3].normal ); |
|
#else |
|
// rotate VPN right by FOV_X/2 degrees |
|
RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_newrefdef.fov_x / 2 ) ); |
|
// rotate VPN left by FOV_X/2 degrees |
|
RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_newrefdef.fov_x / 2 ); |
|
// rotate VPN up by FOV_X/2 degrees |
|
RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_newrefdef.fov_y / 2 ); |
|
// rotate VPN down by FOV_X/2 degrees |
|
RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_newrefdef.fov_y / 2 ) ); |
|
#endif |
|
|
|
for (i=0 ; i<4 ; i++) |
|
{ |
|
frustum[i].type = PLANE_ANYZ; |
|
frustum[i].dist = DotProduct (r_origin, frustum[i].normal); |
|
frustum[i].signbits = SignbitsForPlane (&frustum[i]); |
|
} |
|
} |
|
|
|
//======================================================================= |
|
|
|
/* |
|
=============== |
|
R_SetupFrame |
|
=============== |
|
*/ |
|
void R_SetupFrame (void) |
|
{ |
|
int i; |
|
mleaf_t *leaf; |
|
|
|
r_framecount++; |
|
|
|
// build the transformation matrix for the given view angles |
|
VectorCopy (r_newrefdef.vieworg, r_origin); |
|
|
|
AngleVectors (r_newrefdef.viewangles, vpn, vright, vup); |
|
|
|
// current viewcluster |
|
if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) |
|
{ |
|
r_oldviewcluster = r_viewcluster; |
|
r_oldviewcluster2 = r_viewcluster2; |
|
leaf = Mod_PointInLeaf (r_origin, r_worldmodel); |
|
r_viewcluster = r_viewcluster2 = leaf->cluster; |
|
|
|
// check above and below so crossing solid water doesn't draw wrong |
|
if (!leaf->contents) |
|
{ // look down a bit |
|
vec3_t temp; |
|
|
|
VectorCopy (r_origin, temp); |
|
temp[2] -= 16; |
|
leaf = Mod_PointInLeaf (temp, r_worldmodel); |
|
if ( !(leaf->contents & CONTENTS_SOLID) && |
|
(leaf->cluster != r_viewcluster2) ) |
|
r_viewcluster2 = leaf->cluster; |
|
} |
|
else |
|
{ // look up a bit |
|
vec3_t temp; |
|
|
|
VectorCopy (r_origin, temp); |
|
temp[2] += 16; |
|
leaf = Mod_PointInLeaf (temp, r_worldmodel); |
|
if ( !(leaf->contents & CONTENTS_SOLID) && |
|
(leaf->cluster != r_viewcluster2) ) |
|
r_viewcluster2 = leaf->cluster; |
|
} |
|
} |
|
|
|
for (i=0 ; i<4 ; i++) |
|
v_blend[i] = r_newrefdef.blend[i]; |
|
|
|
c_brush_polys = 0; |
|
c_alias_polys = 0; |
|
|
|
// clear out the portion of the screen that the NOWORLDMODEL defines |
|
if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) |
|
{ |
|
qglEnable( GL_SCISSOR_TEST ); |
|
qglClearColor( 0.3, 0.3, 0.3, 1 ); |
|
qglScissor( r_newrefdef.x, vid.height - r_newrefdef.height - r_newrefdef.y, r_newrefdef.width, r_newrefdef.height ); |
|
qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); |
|
qglClearColor( 1, 0, 0.5, 0.5 ); |
|
qglDisable( GL_SCISSOR_TEST ); |
|
} |
|
} |
|
|
|
|
|
void MYgluPerspective( GLdouble fovy, GLdouble aspect, |
|
GLdouble zNear, GLdouble zFar ) |
|
{ |
|
GLdouble xmin, xmax, ymin, ymax; |
|
|
|
ymax = zNear * tan( fovy * M_PI / 360.0 ); |
|
ymin = -ymax; |
|
|
|
xmin = ymin * aspect; |
|
xmax = ymax * aspect; |
|
|
|
xmin += -( 2 * gl_state.camera_separation ) / zNear; |
|
xmax += -( 2 * gl_state.camera_separation ) / zNear; |
|
|
|
qglFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); |
|
} |
|
|
|
|
|
/* |
|
============= |
|
R_SetupGL |
|
============= |
|
*/ |
|
void R_SetupGL (void) |
|
{ |
|
float screenaspect; |
|
// float yfov; |
|
int x, x2, y2, y, w, h; |
|
|
|
// |
|
// set up viewport |
|
// |
|
x = floor(r_newrefdef.x * vid.width / vid.width); |
|
x2 = ceil((r_newrefdef.x + r_newrefdef.width) * vid.width / vid.width); |
|
y = floor(vid.height - r_newrefdef.y * vid.height / vid.height); |
|
y2 = ceil(vid.height - (r_newrefdef.y + r_newrefdef.height) * vid.height / vid.height); |
|
|
|
w = x2 - x; |
|
h = y - y2; |
|
|
|
qglViewport (x, y2, w, h); |
|
|
|
// |
|
// set up projection matrix |
|
// |
|
screenaspect = (float)r_newrefdef.width/r_newrefdef.height; |
|
// yfov = 2*atan((float)r_newrefdef.height/r_newrefdef.width)*180/M_PI; |
|
qglMatrixMode(GL_PROJECTION); |
|
qglLoadIdentity (); |
|
MYgluPerspective (r_newrefdef.fov_y, screenaspect, 4, 4096); |
|
|
|
qglCullFace(GL_FRONT); |
|
|
|
qglMatrixMode(GL_MODELVIEW); |
|
qglLoadIdentity (); |
|
|
|
qglRotatef (-90, 1, 0, 0); // put Z going up |
|
qglRotatef (90, 0, 0, 1); // put Z going up |
|
qglRotatef (-r_newrefdef.viewangles[2], 1, 0, 0); |
|
qglRotatef (-r_newrefdef.viewangles[0], 0, 1, 0); |
|
qglRotatef (-r_newrefdef.viewangles[1], 0, 0, 1); |
|
qglTranslatef (-r_newrefdef.vieworg[0], -r_newrefdef.vieworg[1], -r_newrefdef.vieworg[2]); |
|
|
|
// if ( gl_state.camera_separation != 0 && gl_state.stereo_enabled ) |
|
// qglTranslatef ( gl_state.camera_separation, 0, 0 ); |
|
|
|
qglGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix); |
|
|
|
// |
|
// set drawing parms |
|
// |
|
if (gl_cull->value) |
|
qglEnable(GL_CULL_FACE); |
|
else |
|
qglDisable(GL_CULL_FACE); |
|
|
|
qglDisable(GL_BLEND); |
|
qglDisable(GL_ALPHA_TEST); |
|
qglEnable(GL_DEPTH_TEST); |
|
} |
|
|
|
/* |
|
============= |
|
R_Clear |
|
============= |
|
*/ |
|
void R_Clear (void) |
|
{ |
|
if (gl_ztrick->value) |
|
{ |
|
static int trickframe; |
|
|
|
if (gl_clear->value) |
|
qglClear (GL_COLOR_BUFFER_BIT); |
|
|
|
trickframe++; |
|
if (trickframe & 1) |
|
{ |
|
gldepthmin = 0; |
|
gldepthmax = 0.49999; |
|
qglDepthFunc (GL_LEQUAL); |
|
} |
|
else |
|
{ |
|
gldepthmin = 1; |
|
gldepthmax = 0.5; |
|
qglDepthFunc (GL_GEQUAL); |
|
} |
|
} |
|
else |
|
{ |
|
if (gl_clear->value) |
|
qglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
|
else |
|
qglClear (GL_DEPTH_BUFFER_BIT); |
|
gldepthmin = 0; |
|
gldepthmax = 1; |
|
qglDepthFunc (GL_LEQUAL); |
|
} |
|
|
|
qglDepthRange (gldepthmin, gldepthmax); |
|
|
|
} |
|
|
|
void R_Flash( void ) |
|
{ |
|
R_PolyBlend (); |
|
} |
|
|
|
/* |
|
================ |
|
R_RenderView |
|
|
|
r_newrefdef must be set before the first call |
|
================ |
|
*/ |
|
void R_RenderView (refdef_t *fd) |
|
{ |
|
if (r_norefresh->value) |
|
return; |
|
|
|
r_newrefdef = *fd; |
|
|
|
if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) |
|
ri.Sys_Error (ERR_DROP, "R_RenderView: NULL worldmodel"); |
|
|
|
if (r_speeds->value) |
|
{ |
|
c_brush_polys = 0; |
|
c_alias_polys = 0; |
|
} |
|
|
|
R_PushDlights (); |
|
|
|
if (gl_finish->value) |
|
qglFinish (); |
|
|
|
R_SetupFrame (); |
|
|
|
R_SetFrustum (); |
|
|
|
R_SetupGL (); |
|
|
|
R_MarkLeaves (); // done here so we know if we're in water |
|
|
|
R_DrawWorld (); |
|
|
|
R_DrawEntitiesOnList (); |
|
|
|
R_RenderDlights (); |
|
|
|
R_DrawParticles (); |
|
|
|
R_DrawAlphaSurfaces (); |
|
|
|
R_Flash(); |
|
|
|
if (r_speeds->value) |
|
{ |
|
ri.Con_Printf (PRINT_ALL, "%4i wpoly %4i epoly %i tex %i lmaps\n", |
|
c_brush_polys, |
|
c_alias_polys, |
|
c_visible_textures, |
|
c_visible_lightmaps); |
|
} |
|
} |
|
|
|
|
|
void R_SetGL2D (void) |
|
{ |
|
// set 2D virtual screen size |
|
qglViewport (0,0, vid.width, vid.height); |
|
qglMatrixMode(GL_PROJECTION); |
|
qglLoadIdentity (); |
|
qglOrtho (0, vid.width, vid.height, 0, -99999, 99999); |
|
qglMatrixMode(GL_MODELVIEW); |
|
qglLoadIdentity (); |
|
qglDisable (GL_DEPTH_TEST); |
|
qglDisable (GL_CULL_FACE); |
|
qglDisable (GL_BLEND); |
|
qglEnable (GL_ALPHA_TEST); |
|
qglColor4f (1,1,1,1); |
|
} |
|
|
|
static void GL_DrawColoredStereoLinePair( float r, float g, float b, float y ) |
|
{ |
|
qglColor3f( r, g, b ); |
|
qglVertex2f( 0, y ); |
|
qglVertex2f( vid.width, y ); |
|
qglColor3f( 0, 0, 0 ); |
|
qglVertex2f( 0, y + 1 ); |
|
qglVertex2f( vid.width, y + 1 ); |
|
} |
|
|
|
static void GL_DrawStereoPattern( void ) |
|
{ |
|
int i; |
|
|
|
if ( !( gl_config.renderer & GL_RENDERER_INTERGRAPH ) ) |
|
return; |
|
|
|
if ( !gl_state.stereo_enabled ) |
|
return; |
|
|
|
R_SetGL2D(); |
|
|
|
qglDrawBuffer( GL_BACK_LEFT ); |
|
|
|
for ( i = 0; i < 20; i++ ) |
|
{ |
|
qglBegin( GL_LINES ); |
|
GL_DrawColoredStereoLinePair( 1, 0, 0, 0 ); |
|
GL_DrawColoredStereoLinePair( 1, 0, 0, 2 ); |
|
GL_DrawColoredStereoLinePair( 1, 0, 0, 4 ); |
|
GL_DrawColoredStereoLinePair( 1, 0, 0, 6 ); |
|
GL_DrawColoredStereoLinePair( 0, 1, 0, 8 ); |
|
GL_DrawColoredStereoLinePair( 1, 1, 0, 10); |
|
GL_DrawColoredStereoLinePair( 1, 1, 0, 12); |
|
GL_DrawColoredStereoLinePair( 0, 1, 0, 14); |
|
qglEnd(); |
|
|
|
GLimp_EndFrame(); |
|
} |
|
} |
|
|
|
|
|
/* |
|
==================== |
|
R_SetLightLevel |
|
|
|
==================== |
|
*/ |
|
void R_SetLightLevel (void) |
|
{ |
|
vec3_t shadelight; |
|
|
|
if (r_newrefdef.rdflags & RDF_NOWORLDMODEL) |
|
return; |
|
|
|
// save off light value for server to look at (BIG HACK!) |
|
|
|
R_LightPoint (r_newrefdef.vieworg, shadelight); |
|
|
|
// pick the greatest component, which should be the same |
|
// as the mono value returned by software |
|
if (shadelight[0] > shadelight[1]) |
|
{ |
|
if (shadelight[0] > shadelight[2]) |
|
r_lightlevel->value = 150*shadelight[0]; |
|
else |
|
r_lightlevel->value = 150*shadelight[2]; |
|
} |
|
else |
|
{ |
|
if (shadelight[1] > shadelight[2]) |
|
r_lightlevel->value = 150*shadelight[1]; |
|
else |
|
r_lightlevel->value = 150*shadelight[2]; |
|
} |
|
|
|
} |
|
|
|
/* |
|
@@@@@@@@@@@@@@@@@@@@@ |
|
R_RenderFrame |
|
|
|
@@@@@@@@@@@@@@@@@@@@@ |
|
*/ |
|
void R_RenderFrame (refdef_t *fd) |
|
{ |
|
R_RenderView( fd ); |
|
R_SetLightLevel (); |
|
R_SetGL2D (); |
|
} |
|
|
|
|
|
void R_Register( void ) |
|
{ |
|
r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE ); |
|
r_norefresh = ri.Cvar_Get ("r_norefresh", "0", 0); |
|
r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0); |
|
r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0); |
|
r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0); |
|
r_novis = ri.Cvar_Get ("r_novis", "0", 0); |
|
r_nocull = ri.Cvar_Get ("r_nocull", "0", 0); |
|
r_lerpmodels = ri.Cvar_Get ("r_lerpmodels", "1", 0); |
|
r_speeds = ri.Cvar_Get ("r_speeds", "0", 0); |
|
|
|
r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0); |
|
|
|
gl_nosubimage = ri.Cvar_Get( "gl_nosubimage", "0", 0 ); |
|
gl_allow_software = ri.Cvar_Get( "gl_allow_software", "0", 0 ); |
|
|
|
gl_particle_min_size = ri.Cvar_Get( "gl_particle_min_size", "2", CVAR_ARCHIVE ); |
|
gl_particle_max_size = ri.Cvar_Get( "gl_particle_max_size", "40", CVAR_ARCHIVE ); |
|
gl_particle_size = ri.Cvar_Get( "gl_particle_size", "40", CVAR_ARCHIVE ); |
|
gl_particle_att_a = ri.Cvar_Get( "gl_particle_att_a", "0.01", CVAR_ARCHIVE ); |
|
gl_particle_att_b = ri.Cvar_Get( "gl_particle_att_b", "0.0", CVAR_ARCHIVE ); |
|
gl_particle_att_c = ri.Cvar_Get( "gl_particle_att_c", "0.01", CVAR_ARCHIVE ); |
|
|
|
gl_modulate = ri.Cvar_Get ("gl_modulate", "1", CVAR_ARCHIVE ); |
|
gl_log = ri.Cvar_Get( "gl_log", "0", 0 ); |
|
gl_bitdepth = ri.Cvar_Get( "gl_bitdepth", "0", 0 ); |
|
gl_mode = ri.Cvar_Get( "gl_mode", "3", CVAR_ARCHIVE ); |
|
gl_lightmap = ri.Cvar_Get ("gl_lightmap", "0", 0); |
|
gl_shadows = ri.Cvar_Get ("gl_shadows", "0", CVAR_ARCHIVE ); |
|
gl_dynamic = ri.Cvar_Get ("gl_dynamic", "1", 0); |
|
gl_nobind = ri.Cvar_Get ("gl_nobind", "0", 0); |
|
gl_round_down = ri.Cvar_Get ("gl_round_down", "1", 0); |
|
gl_picmip = ri.Cvar_Get ("gl_picmip", "0", 0); |
|
gl_skymip = ri.Cvar_Get ("gl_skymip", "0", 0); |
|
gl_showtris = ri.Cvar_Get ("gl_showtris", "0", 0); |
|
gl_ztrick = ri.Cvar_Get ("gl_ztrick", "0", 0); |
|
gl_finish = ri.Cvar_Get ("gl_finish", "0", CVAR_ARCHIVE); |
|
gl_clear = ri.Cvar_Get ("gl_clear", "0", 0); |
|
gl_cull = ri.Cvar_Get ("gl_cull", "1", 0); |
|
gl_polyblend = ri.Cvar_Get ("gl_polyblend", "1", 0); |
|
gl_flashblend = ri.Cvar_Get ("gl_flashblend", "0", 0); |
|
gl_playermip = ri.Cvar_Get ("gl_playermip", "0", 0); |
|
gl_monolightmap = ri.Cvar_Get( "gl_monolightmap", "0", 0 ); |
|
gl_driver = ri.Cvar_Get( "gl_driver", "opengl32", CVAR_ARCHIVE ); |
|
gl_texturemode = ri.Cvar_Get( "gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); |
|
gl_texturealphamode = ri.Cvar_Get( "gl_texturealphamode", "default", CVAR_ARCHIVE ); |
|
gl_texturesolidmode = ri.Cvar_Get( "gl_texturesolidmode", "default", CVAR_ARCHIVE ); |
|
gl_lockpvs = ri.Cvar_Get( "gl_lockpvs", "0", 0 ); |
|
|
|
gl_vertex_arrays = ri.Cvar_Get( "gl_vertex_arrays", "0", CVAR_ARCHIVE ); |
|
|
|
gl_ext_swapinterval = ri.Cvar_Get( "gl_ext_swapinterval", "1", CVAR_ARCHIVE ); |
|
gl_ext_palettedtexture = ri.Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE ); |
|
gl_ext_multitexture = ri.Cvar_Get( "gl_ext_multitexture", "1", CVAR_ARCHIVE ); |
|
gl_ext_pointparameters = ri.Cvar_Get( "gl_ext_pointparameters", "1", CVAR_ARCHIVE ); |
|
gl_ext_compiled_vertex_array = ri.Cvar_Get( "gl_ext_compiled_vertex_array", "1", CVAR_ARCHIVE ); |
|
|
|
gl_drawbuffer = ri.Cvar_Get( "gl_drawbuffer", "GL_BACK", 0 ); |
|
gl_swapinterval = ri.Cvar_Get( "gl_swapinterval", "1", CVAR_ARCHIVE ); |
|
|
|
gl_saturatelighting = ri.Cvar_Get( "gl_saturatelighting", "0", 0 ); |
|
|
|
gl_3dlabs_broken = ri.Cvar_Get( "gl_3dlabs_broken", "1", CVAR_ARCHIVE ); |
|
|
|
vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE ); |
|
vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE ); |
|
vid_ref = ri.Cvar_Get( "vid_ref", "soft", CVAR_ARCHIVE ); |
|
|
|
ri.Cmd_AddCommand( "imagelist", GL_ImageList_f ); |
|
ri.Cmd_AddCommand( "screenshot", GL_ScreenShot_f ); |
|
ri.Cmd_AddCommand( "modellist", Mod_Modellist_f ); |
|
ri.Cmd_AddCommand( "gl_strings", GL_Strings_f ); |
|
} |
|
|
|
/* |
|
================== |
|
R_SetMode |
|
================== |
|
*/ |
|
qboolean R_SetMode (void) |
|
{ |
|
rserr_t err; |
|
qboolean fullscreen; |
|
|
|
if ( vid_fullscreen->modified && !gl_config.allow_cds ) |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "R_SetMode() - CDS not allowed with this driver\n" ); |
|
ri.Cvar_SetValue( "vid_fullscreen", !vid_fullscreen->value ); |
|
vid_fullscreen->modified = false; |
|
} |
|
|
|
fullscreen = vid_fullscreen->value; |
|
|
|
vid_fullscreen->modified = false; |
|
gl_mode->modified = false; |
|
|
|
if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_mode->value, fullscreen ) ) == rserr_ok ) |
|
{ |
|
gl_state.prev_mode = gl_mode->value; |
|
} |
|
else |
|
{ |
|
if ( err == rserr_invalid_fullscreen ) |
|
{ |
|
ri.Cvar_SetValue( "vid_fullscreen", 0); |
|
vid_fullscreen->modified = false; |
|
ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - fullscreen unavailable in this mode\n" ); |
|
if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_mode->value, false ) ) == rserr_ok ) |
|
return true; |
|
} |
|
else if ( err == rserr_invalid_mode ) |
|
{ |
|
ri.Cvar_SetValue( "gl_mode", gl_state.prev_mode ); |
|
gl_mode->modified = false; |
|
ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - invalid mode\n" ); |
|
} |
|
|
|
// try setting it back to something safe |
|
if ( ( err = GLimp_SetMode( &vid.width, &vid.height, gl_state.prev_mode, false ) ) != rserr_ok ) |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "ref_gl::R_SetMode() - could not revert to safe mode\n" ); |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
/* |
|
=============== |
|
R_Init |
|
=============== |
|
*/ |
|
int R_Init( void *hinstance, void *hWnd ) |
|
{ |
|
char renderer_buffer[1000]; |
|
char vendor_buffer[1000]; |
|
int err; |
|
int j; |
|
extern float r_turbsin[256]; |
|
|
|
for ( j = 0; j < 256; j++ ) |
|
{ |
|
r_turbsin[j] *= 0.5; |
|
} |
|
|
|
ri.Con_Printf (PRINT_ALL, "ref_gl version: "REF_VERSION"\n"); |
|
|
|
Draw_GetPalette (); |
|
|
|
R_Register(); |
|
|
|
// initialize our QGL dynamic bindings |
|
if ( !QGL_Init( gl_driver->string ) ) |
|
{ |
|
QGL_Shutdown(); |
|
ri.Con_Printf (PRINT_ALL, "ref_gl::R_Init() - could not load \"%s\"\n", gl_driver->string ); |
|
return -1; |
|
} |
|
|
|
// initialize OS-specific parts of OpenGL |
|
if ( !GLimp_Init( hinstance, hWnd ) ) |
|
{ |
|
QGL_Shutdown(); |
|
return -1; |
|
} |
|
|
|
// set our "safe" modes |
|
gl_state.prev_mode = 3; |
|
|
|
// create the window and set up the context |
|
if ( !R_SetMode () ) |
|
{ |
|
QGL_Shutdown(); |
|
ri.Con_Printf (PRINT_ALL, "ref_gl::R_Init() - could not R_SetMode()\n" ); |
|
return -1; |
|
} |
|
|
|
ri.Vid_MenuInit(); |
|
|
|
/* |
|
** get our various GL strings |
|
*/ |
|
gl_config.vendor_string = qglGetString (GL_VENDOR); |
|
ri.Con_Printf (PRINT_ALL, "GL_VENDOR: %s\n", gl_config.vendor_string ); |
|
gl_config.renderer_string = qglGetString (GL_RENDERER); |
|
ri.Con_Printf (PRINT_ALL, "GL_RENDERER: %s\n", gl_config.renderer_string ); |
|
gl_config.version_string = qglGetString (GL_VERSION); |
|
ri.Con_Printf (PRINT_ALL, "GL_VERSION: %s\n", gl_config.version_string ); |
|
gl_config.extensions_string = qglGetString (GL_EXTENSIONS); |
|
ri.Con_Printf (PRINT_ALL, "GL_EXTENSIONS: %s\n", gl_config.extensions_string ); |
|
|
|
strcpy( renderer_buffer, gl_config.renderer_string ); |
|
strlwr( renderer_buffer ); |
|
|
|
strcpy( vendor_buffer, gl_config.vendor_string ); |
|
strlwr( vendor_buffer ); |
|
|
|
if ( strstr( renderer_buffer, "voodoo" ) ) |
|
{ |
|
if ( !strstr( renderer_buffer, "rush" ) ) |
|
gl_config.renderer = GL_RENDERER_VOODOO; |
|
else |
|
gl_config.renderer = GL_RENDERER_VOODOO_RUSH; |
|
} |
|
else if ( strstr( vendor_buffer, "sgi" ) ) |
|
gl_config.renderer = GL_RENDERER_SGI; |
|
else if ( strstr( renderer_buffer, "permedia" ) ) |
|
gl_config.renderer = GL_RENDERER_PERMEDIA2; |
|
else if ( strstr( renderer_buffer, "glint" ) ) |
|
gl_config.renderer = GL_RENDERER_GLINT_MX; |
|
else if ( strstr( renderer_buffer, "glzicd" ) ) |
|
gl_config.renderer = GL_RENDERER_REALIZM; |
|
else if ( strstr( renderer_buffer, "gdi" ) ) |
|
gl_config.renderer = GL_RENDERER_MCD; |
|
else if ( strstr( renderer_buffer, "pcx2" ) ) |
|
gl_config.renderer = GL_RENDERER_PCX2; |
|
else if ( strstr( renderer_buffer, "verite" ) ) |
|
gl_config.renderer = GL_RENDERER_RENDITION; |
|
else |
|
gl_config.renderer = GL_RENDERER_OTHER; |
|
|
|
if ( toupper( gl_monolightmap->string[1] ) != 'F' ) |
|
{ |
|
if ( gl_config.renderer == GL_RENDERER_PERMEDIA2 ) |
|
{ |
|
ri.Cvar_Set( "gl_monolightmap", "A" ); |
|
ri.Con_Printf( PRINT_ALL, "...using gl_monolightmap 'a'\n" ); |
|
} |
|
else if ( gl_config.renderer & GL_RENDERER_POWERVR ) |
|
{ |
|
ri.Cvar_Set( "gl_monolightmap", "0" ); |
|
} |
|
else |
|
{ |
|
ri.Cvar_Set( "gl_monolightmap", "0" ); |
|
} |
|
} |
|
|
|
// power vr can't have anything stay in the framebuffer, so |
|
// the screen needs to redraw the tiled background every frame |
|
if ( gl_config.renderer & GL_RENDERER_POWERVR ) |
|
{ |
|
ri.Cvar_Set( "scr_drawall", "1" ); |
|
} |
|
else |
|
{ |
|
ri.Cvar_Set( "scr_drawall", "0" ); |
|
} |
|
|
|
// MCD has buffering issues |
|
if ( gl_config.renderer == GL_RENDERER_MCD ) |
|
{ |
|
ri.Cvar_SetValue( "gl_finish", 1 ); |
|
} |
|
|
|
if ( gl_config.renderer & GL_RENDERER_3DLABS ) |
|
{ |
|
if ( gl_3dlabs_broken->value ) |
|
gl_config.allow_cds = false; |
|
else |
|
gl_config.allow_cds = true; |
|
} |
|
else |
|
{ |
|
gl_config.allow_cds = true; |
|
} |
|
|
|
if ( gl_config.allow_cds ) |
|
ri.Con_Printf( PRINT_ALL, "...allowing CDS\n" ); |
|
else |
|
ri.Con_Printf( PRINT_ALL, "...disabling CDS\n" ); |
|
|
|
/* |
|
** grab extensions |
|
*/ |
|
#ifdef WIN32 |
|
if ( strstr( gl_config.extensions_string, "GL_EXT_compiled_vertex_array" ) || |
|
strstr( gl_config.extensions_string, "GL_SGI_compiled_vertex_array" ) ) |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...enabling GL_EXT_compiled_vertex_array\n" ); |
|
qglLockArraysEXT = ( void * ) qwglGetProcAddress( "glLockArraysEXT" ); |
|
qglUnlockArraysEXT = ( void * ) qwglGetProcAddress( "glUnlockArraysEXT" ); |
|
} |
|
else |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); |
|
} |
|
|
|
if ( strstr( gl_config.extensions_string, "WGL_EXT_swap_control" ) ) |
|
{ |
|
qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( "wglSwapIntervalEXT" ); |
|
ri.Con_Printf( PRINT_ALL, "...enabling WGL_EXT_swap_control\n" ); |
|
} |
|
else |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" ); |
|
} |
|
|
|
if ( strstr( gl_config.extensions_string, "GL_EXT_point_parameters" ) ) |
|
{ |
|
if ( gl_ext_pointparameters->value ) |
|
{ |
|
qglPointParameterfEXT = ( void (APIENTRY *)( GLenum, GLfloat ) ) qwglGetProcAddress( "glPointParameterfEXT" ); |
|
qglPointParameterfvEXT = ( void (APIENTRY *)( GLenum, const GLfloat * ) ) qwglGetProcAddress( "glPointParameterfvEXT" ); |
|
ri.Con_Printf( PRINT_ALL, "...using GL_EXT_point_parameters\n" ); |
|
} |
|
else |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...ignoring GL_EXT_point_parameters\n" ); |
|
} |
|
} |
|
else |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...GL_EXT_point_parameters not found\n" ); |
|
} |
|
|
|
if ( strstr( gl_config.extensions_string, "GL_EXT_paletted_texture" ) && |
|
strstr( gl_config.extensions_string, "GL_EXT_shared_texture_palette" ) ) |
|
{ |
|
if ( gl_ext_palettedtexture->value ) |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...using GL_EXT_shared_texture_palette\n" ); |
|
qglColorTableEXT = ( void ( APIENTRY * ) ( int, int, int, int, int, const void * ) ) qwglGetProcAddress( "glColorTableEXT" ); |
|
} |
|
else |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...ignoring GL_EXT_shared_texture_palette\n" ); |
|
} |
|
} |
|
else |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...GL_EXT_shared_texture_palette not found\n" ); |
|
} |
|
|
|
if ( strstr( gl_config.extensions_string, "GL_SGIS_multitexture" ) ) |
|
{ |
|
if ( gl_ext_multitexture->value ) |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...using GL_SGIS_multitexture\n" ); |
|
qglMTexCoord2fSGIS = ( void * ) qwglGetProcAddress( "glMTexCoord2fSGIS" ); |
|
qglSelectTextureSGIS = ( void * ) qwglGetProcAddress( "glSelectTextureSGIS" ); |
|
} |
|
else |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...ignoring GL_SGIS_multitexture\n" ); |
|
} |
|
} |
|
else |
|
{ |
|
ri.Con_Printf( PRINT_ALL, "...GL_SGIS_multitexture not found\n" ); |
|
} |
|
#endif |
|
|
|
GL_SetDefaultState(); |
|
|
|
/* |
|
** draw our stereo patterns |
|
*/ |
|
#if 0 // commented out until H3D pays us the money they owe us |
|
GL_DrawStereoPattern(); |
|
#endif |
|
|
|
GL_InitImages (); |
|
Mod_Init (); |
|
R_InitParticleTexture (); |
|
Draw_InitLocal (); |
|
|
|
err = qglGetError(); |
|
if ( err != GL_NO_ERROR ) |
|
ri.Con_Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); |
|
} |
|
|
|
/* |
|
=============== |
|
R_Shutdown |
|
=============== |
|
*/ |
|
void R_Shutdown (void) |
|
{ |
|
ri.Cmd_RemoveCommand ("modellist"); |
|
ri.Cmd_RemoveCommand ("screenshot"); |
|
ri.Cmd_RemoveCommand ("imagelist"); |
|
ri.Cmd_RemoveCommand ("gl_strings"); |
|
|
|
Mod_FreeAll (); |
|
|
|
GL_ShutdownImages (); |
|
|
|
/* |
|
** shut down OS specific OpenGL stuff like contexts, etc. |
|
*/ |
|
GLimp_Shutdown(); |
|
|
|
/* |
|
** shutdown our QGL subsystem |
|
*/ |
|
QGL_Shutdown(); |
|
} |
|
|
|
|
|
|
|
/* |
|
@@@@@@@@@@@@@@@@@@@@@ |
|
R_BeginFrame |
|
@@@@@@@@@@@@@@@@@@@@@ |
|
*/ |
|
void R_BeginFrame( float camera_separation ) |
|
{ |
|
|
|
gl_state.camera_separation = camera_separation; |
|
|
|
/* |
|
** change modes if necessary |
|
*/ |
|
if ( gl_mode->modified || vid_fullscreen->modified ) |
|
{ // FIXME: only restart if CDS is required |
|
cvar_t *ref; |
|
|
|
ref = ri.Cvar_Get ("vid_ref", "gl", 0); |
|
ref->modified = true; |
|
} |
|
|
|
if ( gl_log->modified ) |
|
{ |
|
GLimp_EnableLogging( gl_log->value ); |
|
gl_log->modified = false; |
|
} |
|
|
|
if ( gl_log->value ) |
|
{ |
|
GLimp_LogNewFrame(); |
|
} |
|
|
|
/* |
|
** update 3Dfx gamma -- it is expected that a user will do a vid_restart |
|
** after tweaking this value |
|
*/ |
|
if ( vid_gamma->modified ) |
|
{ |
|
vid_gamma->modified = false; |
|
|
|
if ( gl_config.renderer & ( GL_RENDERER_VOODOO ) ) |
|
{ |
|
char envbuffer[1024]; |
|
float g; |
|
|
|
g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F; |
|
Com_sprintf( envbuffer, sizeof(envbuffer), "SSTV2_GAMMA=%f", g ); |
|
putenv( envbuffer ); |
|
Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g ); |
|
putenv( envbuffer ); |
|
} |
|
} |
|
|
|
GLimp_BeginFrame( camera_separation ); |
|
|
|
/* |
|
** go into 2D mode |
|
*/ |
|
qglViewport (0,0, vid.width, vid.height); |
|
qglMatrixMode(GL_PROJECTION); |
|
qglLoadIdentity (); |
|
qglOrtho (0, vid.width, vid.height, 0, -99999, 99999); |
|
qglMatrixMode(GL_MODELVIEW); |
|
qglLoadIdentity (); |
|
qglDisable (GL_DEPTH_TEST); |
|
qglDisable (GL_CULL_FACE); |
|
qglDisable (GL_BLEND); |
|
qglEnable (GL_ALPHA_TEST); |
|
qglColor4f (1,1,1,1); |
|
|
|
/* |
|
** draw buffer stuff |
|
*/ |
|
if ( gl_drawbuffer->modified ) |
|
{ |
|
gl_drawbuffer->modified = false; |
|
|
|
if ( gl_state.camera_separation == 0 || !gl_state.stereo_enabled ) |
|
{ |
|
if ( Q_stricmp( gl_drawbuffer->string, "GL_FRONT" ) == 0 ) |
|
qglDrawBuffer( GL_FRONT ); |
|
else |
|
qglDrawBuffer( GL_BACK ); |
|
} |
|
} |
|
|
|
/* |
|
** texturemode stuff |
|
*/ |
|
if ( gl_texturemode->modified ) |
|
{ |
|
GL_TextureMode( gl_texturemode->string ); |
|
gl_texturemode->modified = false; |
|
} |
|
|
|
if ( gl_texturealphamode->modified ) |
|
{ |
|
GL_TextureAlphaMode( gl_texturealphamode->string ); |
|
gl_texturealphamode->modified = false; |
|
} |
|
|
|
if ( gl_texturesolidmode->modified ) |
|
{ |
|
GL_TextureSolidMode( gl_texturesolidmode->string ); |
|
gl_texturesolidmode->modified = false; |
|
} |
|
|
|
/* |
|
** swapinterval stuff |
|
*/ |
|
GL_UpdateSwapInterval(); |
|
|
|
// |
|
// clear screen if desired |
|
// |
|
R_Clear (); |
|
} |
|
|
|
/* |
|
============= |
|
R_SetPalette |
|
============= |
|
*/ |
|
unsigned r_rawpalette[256]; |
|
|
|
void R_SetPalette ( const unsigned char *palette) |
|
{ |
|
int i; |
|
|
|
byte *rp = ( byte * ) r_rawpalette; |
|
|
|
if ( palette ) |
|
{ |
|
for ( i = 0; i < 256; i++ ) |
|
{ |
|
rp[i*4+0] = palette[i*3+0]; |
|
rp[i*4+1] = palette[i*3+1]; |
|
rp[i*4+2] = palette[i*3+2]; |
|
rp[i*4+3] = 0xff; |
|
} |
|
} |
|
else |
|
{ |
|
for ( i = 0; i < 256; i++ ) |
|
{ |
|
rp[i*4+0] = d_8to24table[i] & 0xff; |
|
rp[i*4+1] = ( d_8to24table[i] >> 8 ) & 0xff; |
|
rp[i*4+2] = ( d_8to24table[i] >> 16 ) & 0xff; |
|
rp[i*4+3] = 0xff; |
|
} |
|
} |
|
GL_SetTexturePalette( r_rawpalette ); |
|
|
|
qglClearColor (0,0,0,0); |
|
qglClear (GL_COLOR_BUFFER_BIT); |
|
qglClearColor (1,0, 0.5 , 0.5); |
|
} |
|
|
|
/* |
|
** R_DrawBeam |
|
*/ |
|
void R_DrawBeam( entity_t *e ) |
|
{ |
|
#define NUM_BEAM_SEGS 6 |
|
|
|
int i; |
|
float r, g, b; |
|
|
|
vec3_t perpvec; |
|
vec3_t direction, normalized_direction; |
|
vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; |
|
vec3_t oldorigin, origin; |
|
|
|
oldorigin[0] = e->oldorigin[0]; |
|
oldorigin[1] = e->oldorigin[1]; |
|
oldorigin[2] = e->oldorigin[2]; |
|
|
|
origin[0] = e->origin[0]; |
|
origin[1] = e->origin[1]; |
|
origin[2] = e->origin[2]; |
|
|
|
normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; |
|
normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; |
|
normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; |
|
|
|
if ( VectorNormalize( normalized_direction ) == 0 ) |
|
return; |
|
|
|
PerpendicularVector( perpvec, normalized_direction ); |
|
VectorScale( perpvec, e->frame / 2, perpvec ); |
|
|
|
for ( i = 0; i < 6; i++ ) |
|
{ |
|
RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); |
|
VectorAdd( start_points[i], origin, start_points[i] ); |
|
VectorAdd( start_points[i], direction, end_points[i] ); |
|
} |
|
|
|
qglDisable( GL_TEXTURE_2D ); |
|
qglEnable( GL_BLEND ); |
|
qglDepthMask( GL_FALSE ); |
|
|
|
r = ( d_8to24table[e->skinnum & 0xFF] ) & 0xFF; |
|
g = ( d_8to24table[e->skinnum & 0xFF] >> 8 ) & 0xFF; |
|
b = ( d_8to24table[e->skinnum & 0xFF] >> 16 ) & 0xFF; |
|
|
|
r *= 1/255.0F; |
|
g *= 1/255.0F; |
|
b *= 1/255.0F; |
|
|
|
qglColor4f( r, g, b, e->alpha ); |
|
|
|
qglBegin( GL_TRIANGLE_STRIP ); |
|
for ( i = 0; i < NUM_BEAM_SEGS; i++ ) |
|
{ |
|
qglVertex3fv( start_points[i] ); |
|
qglVertex3fv( end_points[i] ); |
|
qglVertex3fv( start_points[(i+1)%NUM_BEAM_SEGS] ); |
|
qglVertex3fv( end_points[(i+1)%NUM_BEAM_SEGS] ); |
|
} |
|
qglEnd(); |
|
|
|
qglEnable( GL_TEXTURE_2D ); |
|
qglDisable( GL_BLEND ); |
|
qglDepthMask( GL_TRUE ); |
|
} |
|
|
|
//=================================================================== |
|
|
|
|
|
void R_BeginRegistration (char *map); |
|
struct model_s *R_RegisterModel (char *name); |
|
struct image_s *R_RegisterSkin (char *name); |
|
void R_SetSky (char *name, float rotate, vec3_t axis); |
|
void R_EndRegistration (void); |
|
|
|
void R_RenderFrame (refdef_t *fd); |
|
|
|
struct image_s *Draw_FindPic (char *name); |
|
|
|
void Draw_Pic (int x, int y, char *name); |
|
void Draw_Char (int x, int y, int c); |
|
void Draw_TileClear (int x, int y, int w, int h, char *name); |
|
void Draw_Fill (int x, int y, int w, int h, int c); |
|
void Draw_FadeScreen (void); |
|
|
|
/* |
|
@@@@@@@@@@@@@@@@@@@@@ |
|
GetRefAPI |
|
|
|
@@@@@@@@@@@@@@@@@@@@@ |
|
*/ |
|
refexport_t GetRefAPI (refimport_t rimp ) |
|
{ |
|
refexport_t re; |
|
|
|
ri = rimp; |
|
|
|
re.api_version = API_VERSION; |
|
|
|
re.BeginRegistration = R_BeginRegistration; |
|
re.RegisterModel = R_RegisterModel; |
|
re.RegisterSkin = R_RegisterSkin; |
|
re.RegisterPic = Draw_FindPic; |
|
re.SetSky = R_SetSky; |
|
re.EndRegistration = R_EndRegistration; |
|
|
|
re.RenderFrame = R_RenderFrame; |
|
|
|
re.DrawGetPicSize = Draw_GetPicSize; |
|
re.DrawPic = Draw_Pic; |
|
re.DrawStretchPic = Draw_StretchPic; |
|
re.DrawChar = Draw_Char; |
|
re.DrawTileClear = Draw_TileClear; |
|
re.DrawFill = Draw_Fill; |
|
re.DrawFadeScreen= Draw_FadeScreen; |
|
|
|
re.DrawStretchRaw = Draw_StretchRaw; |
|
|
|
re.Init = R_Init; |
|
re.Shutdown = R_Shutdown; |
|
|
|
re.CinematicSetPalette = R_SetPalette; |
|
re.BeginFrame = R_BeginFrame; |
|
re.EndFrame = GLimp_EndFrame; |
|
|
|
re.AppActivate = GLimp_AppActivate; |
|
|
|
Swap_Init (); |
|
|
|
return re; |
|
} |
|
|
|
|
|
#ifndef REF_HARD_LINKED |
|
// this is only here so the functions in q_shared.c and q_shwin.c can link |
|
void Sys_Error (char *error, ...) |
|
{ |
|
va_list argptr; |
|
char text[1024]; |
|
|
|
va_start (argptr, error); |
|
vsprintf (text, error, argptr); |
|
va_end (argptr); |
|
|
|
ri.Sys_Error (ERR_FATAL, "%s", text); |
|
} |
|
|
|
void Com_Printf (char *fmt, ...) |
|
{ |
|
va_list argptr; |
|
char text[1024]; |
|
|
|
va_start (argptr, fmt); |
|
vsprintf (text, fmt, argptr); |
|
va_end (argptr); |
|
|
|
ri.Con_Printf (PRINT_ALL, "%s", text); |
|
} |
|
|
|
#endif
|
|
|