/* 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" #include "vlights.h" void R_Clear (void); #define random() ((rand () & 0x7fff) / ((float)0x7fff)) #define crandom() (2.0 * (random() - 0.5)) viddef_t vid; refimport_t ri; int GL_TEXTURE0, GL_TEXTURE1; model_t *r_worldmodel; float gldepthmin, gldepthmax; glconfig_t gl_config; glstate_t gl_state; image_t *r_particletextures[PARTICLE_TYPES]; //list for particles image_t *r_particlebeam;//used for beam ents image_t *r_celtexture;//used for cel shading image_t *r_notexture; // use for bad textures image_t *r_dynamicimage; image_t *r_lblendimage; image_t *r_motionblurimage; image_t *r_motionblurscreenimage; particle_t *currentparticle; entity_t *currententity; rscript_t *currententityscript; model_t *currentmodel; cplane_t frustum[4]; int r_viewport[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 *skydistance; // DMP - skybox size change cvar_t *gl_transrendersort; cvar_t *gl_particle_lighting; cvar_t *gl_particle_min; cvar_t *gl_particle_max; 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_dlights_normal; cvar_t *r_shaders; cvar_t *rs_glares; cvar_t *rs_glares_sky; cvar_t *rs_glares_size; cvar_t *rs_glares_shell; cvar_t *rs_glares_particles; cvar_t *rs_dynamic_time; cvar_t *rs_dynamic_size; cvar_t *rs_dynamic_particles; cvar_t *rs_dynamic_entities; cvar_t *gl_motionblur; cvar_t *gl_motionblur_size; cvar_t *rs_detail; cvar_t *r_model_lightlerp; cvar_t *r_model_dlights; 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_ext_texture_compression; // Heffo - ARB Texture Compression // Vic - begin cvar_t *gl_ext_mtexcombine; cvar_t *r_overbrightbits; // Vic - end cvar_t *r_celshading; cvar_t *r_celshading_width; cvar_t *con_font; cvar_t *con_font_size; cvar_t *cl_3dcam; cvar_t *cl_3dcam_angle; cvar_t *cl_3dcam_chase; cvar_t *cl_3dcam_dist; cvar_t *cl_3dcam_alpha; cvar_t *cl_3dcam_adjust; cvar_t *gl_ext_swapinterval; cvar_t *gl_ext_multitexture; cvar_t *gl_ext_pointparameters; cvar_t *gl_ext_compiled_vertex_array; cvar_t *gl_stencil; cvar_t *gl_screenshot_quality; cvar_t *gl_surftrans_light; 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_anisotropic; 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; /* ================= GL_Stencil setting stencil buffer ================= */ extern qboolean have_stencil; void GL_Stencil (qboolean enable) { if (!have_stencil || !gl_stencil->value) return; if (enable) { qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_EQUAL, 1, 2); qglStencilOp(GL_KEEP,GL_KEEP,GL_INCR); } else { qglDisable(GL_STENCIL_TEST); } } qboolean GL_HasStencil (void) { return (have_stencil && gl_stencil->value); } /* ================= GL_Spheremap setting up spheremap ================= */ void GL_Spheremap (qboolean enable) { if (enable) { qglTexGenf(GL_S, GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP); qglTexGenf(GL_T, GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP); GLSTATE_ENABLE_TEXGEN } else { GLSTATE_DISABLE_TEXGEN } } /* ================= 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; } qboolean R_CullSphere (const vec3_t origin, float radius) { int i; cplane_t *p; if (r_nocull->value) return false; for (i = 0, p = frustum; i < 4; i++, p++) if (DotProduct(origin, p->normal) - p->dist <= -radius) return true; return false; } void R_RotateForEntity (entity_t *e, qboolean full) { qglTranslatef (e->origin[0], e->origin[1], e->origin[2]); qglRotatef (e->angles[1], 0, 0, 1); if (full==true) { 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, up, right; dsprframe_t *frame; dsprite_t *psprite; // don't even bother culling, because it's just a single // polygon without a surface cache psprite = (dsprite_t *)currentmodel->extradata; e->frame %= psprite->numframes; frame = &psprite->frames[e->frame]; if (!frame) return; // normal sprite VectorCopy(vup, up); VectorCopy(vright, right); if ( e->flags & RF_TRANSLUCENT ) alpha = e->alpha; if (!currentmodel->skins[e->frame]) return; GL_Bind(currentmodel->skins[e->frame]->texnum); if ((currententity->flags&RF_TRANS_ADDITIVE) && (alpha != 1.0F)) { GLSTATE_ENABLE_BLEND GL_TexEnv( GL_MODULATE ); GLSTATE_DISABLE_ALPHATEST GL_BlendFunction (GL_SRC_ALPHA, GL_ONE); qglColor4ub(255, 255, 255, alpha*254); } else { if ( alpha != 1.0F ) GLSTATE_ENABLE_BLEND GL_TexEnv( GL_MODULATE ); if ( alpha == 1.0 ) GLSTATE_ENABLE_ALPHATEST else GLSTATE_DISABLE_ALPHATEST qglColor4f( 1, 1, 1, alpha ); } 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 (); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GLSTATE_DISABLE_ALPHATEST GL_TexEnv( GL_REPLACE ); if ( alpha != 1.0F ) GLSTATE_DISABLE_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, true); 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 ============= */ // STRUCTURE STUFF typedef struct sortedelement_s { void *data; vec_t len; vec3_t org; void *left, *right, *next; } sortedelement_t; int entstosort; sortedelement_t theents[MAX_ENTITIES]; sortedelement_t *ents_viewweaps; sortedelement_t *ents_viewweaps_trans; sortedelement_t *ents_prerender; sortedelement_t *ents_last; void resetSortList (void) { entstosort = 0; ents_last = NULL; ents_prerender = NULL; ents_viewweaps = NULL; ents_viewweaps_trans = NULL; } sortedelement_t *NewSortEnt (entity_t *ent) { qboolean entinwater, is_weapmodel = false; vec3_t distance; sortedelement_t *element; mleaf_t *point_in; element = &theents[entstosort]; VectorSubtract(ent->origin, r_origin, distance); VectorCopy(ent->origin, element->org); element->data = (entity_t *)ent; element->len = (vec_t)VectorLength(distance); element->left = NULL; element->right = NULL; element->next = NULL; return element; } // TREE BUILDING AND USAGE void ElementAddNode ( sortedelement_t *base, sortedelement_t *thisElement ) { if (thisElement->len > base->len) { if (base->left) ElementAddNode(base->left, thisElement); else base->left = thisElement; } else { if (base->right) ElementAddNode(base->right, thisElement); else base->right = thisElement; } } void AddEntViewWeapTree( entity_t *ent, qboolean trans) { int closer = 0; sortedelement_t *thisEnt; thisEnt = NewSortEnt(ent); if (!thisEnt) return; if (!trans) { if (ents_viewweaps) ElementAddNode(ents_viewweaps, thisEnt); else ents_viewweaps = thisEnt; } else { if (ents_viewweaps_trans) ElementAddNode(ents_viewweaps_trans, thisEnt); else ents_viewweaps_trans = thisEnt; } entstosort++; } void AddEntTransTree( entity_t *ent ) { int closer = 0; sortedelement_t *thisEnt; thisEnt = NewSortEnt(ent); if (!thisEnt) return; if (ents_prerender) ElementAddNode(ents_prerender, thisEnt); else ents_prerender = thisEnt; ents_last = thisEnt; entstosort++; } void ParseRenderEntity (entity_t *ent) { currententity = ent; if ( currententity->flags & RF_BEAM ) { R_DrawBeam( currententity ); } else { currentmodel = currententity->model; if (!currentmodel) { R_DrawNullModel (); return; } if (currententity->model && r_shaders->value) { currententityscript=(rscript_t *)currententity->model->script[currententity->skinnum]; if (currententity->skin) currententityscript = currententity->skin->script; } 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; } } } qboolean transBrushModel (entity_t *ent) { int i; msurface_t *surf; if (ent && ent->model && ent->model->type==mod_brush) { surf = &ent->model->surfaces[ent->model->firstmodelsurface]; for (i=0 ; imodel->nummodelsurfaces ; i++, surf++) if (surf && surf->texinfo->flags & (SURF_TRANS33|SURF_TRANS66)) return true; } return false; } void RenderEntTree (sortedelement_t *element) { if (!element) return; RenderEntTree(element->left); if (element->data) ParseRenderEntity(element->data); RenderEntTree(element->right); } // ACTUAL RENDERING FUNCTIONS void R_DrawAliasShadow (entity_t *ent); void R_DrawAllEntityShadows (void) { qboolean alpha; rscript_t *rs = NULL; int i; if(!gl_shadows->value) return; for (i=0;iflags & RF_BEAM ) continue; currentmodel = currententity->model; if (!currentmodel) continue; if (currentmodel->type!=mod_alias) continue; if ( currententity->flags & ( RF_TRANSLUCENT | RF_WEAPONMODEL | RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) ) continue; if (currententity->renderfx & RF2_NOSHADOW) continue; if (currententity->flags&RF_TRANSLUCENT) continue; // if (transBrushModel(currententity)) //crashy // continue; alpha = false; if (currententity->model && r_shaders->value) { rs=(rscript_t *)currententity->model->script[currententity->skinnum]; if (!rs && currententity->skin) rs = currententity->skin->script; if (rs) { RS_ReadyScript(rs); currententityscript = rs; if (rs->stage && rs->stage->has_alpha) continue; } else currententityscript = NULL; } R_DrawAliasShadow (currententity); } } void R_DrawAllEntities (qboolean addViewWeaps) { qboolean alpha; rscript_t *rs = NULL; int i; if (!r_drawentities->value) return; resetSortList(); for (i=0;iflags&RF_TRANSLUCENT) alpha = true; if (currententity->model && r_shaders->value) { rs=(rscript_t *)currententity->model->script[currententity->skinnum]; if (currententity->skin) rs = currententity->skin->script; if (rs) { RS_ReadyScript(rs); currententityscript = rs; if (rs->stage && rs->stage->has_alpha) alpha = true; } else currententityscript = NULL; } if (alpha) continue; if (currententity->flags & RF_WEAPONMODEL) if (!addViewWeaps) continue; ParseRenderEntity(currententity); } qglDepthMask (0); for (i=0;iflags&RF_TRANSLUCENT) alpha = true; if (currententity->model && r_shaders->value) { rs=(rscript_t *)currententity->model->script[currententity->skinnum]; if (currententity->skin) rs = currententity->skin->script; if (rs) { RS_ReadyScript(rs); currententityscript = rs; if (rs->stage && rs->stage->has_alpha) alpha = true; } else currententityscript = NULL; } if (currententity->flags & RF_WEAPONMODEL) if (!addViewWeaps) continue; if (!alpha) continue; ParseRenderEntity(currententity); } qglDepthMask (1); } void setRenderMotionBlur (void); void R_DrawMotionBlurEntities (void) { qboolean alpha; int i; rscript_t *rs = NULL; if (!r_drawentities->value) return; for (i=0;iflags & RF_TRANSLUCENT) continue; if (currententity->renderfx & RF2_MOTIONBLUR) ParseRenderEntity(currententity); } } void R_DrawSolidEntities (void) { qboolean alpha; int i; rscript_t *rs = NULL; if (!r_drawentities->value) return; resetSortList(); for (i=0;imodel && r_shaders->value) { rs=(rscript_t *)currententity->model->script[currententity->skinnum]; if (currententity->skin) rs = currententity->skin->script; if (rs) { RS_ReadyScript(rs); currententityscript = rs; //only add to list if base layer is alpha if (rs->stage && rs->stage->has_alpha) alpha = true; } else currententityscript = NULL; } if (currententity->flags&RF_TRANSLUCENT) alpha = true; // if (transBrushModel(currententity)) // alpha = true; if (currententity->flags & RF_WEAPONMODEL) { AddEntViewWeapTree(currententity, alpha); continue; } if (alpha) { AddEntTransTree(currententity); continue; } ParseRenderEntity(currententity); } } void R_DrawEntitiesOnList (void *list) { if (!r_drawentities->value) return; RenderEntTree(list); } /* ** GL_DrawParticles ** */ int partstosort; sortedelement_t theparts[MAX_PARTICLES]; sortedelement_t *parts_prerender; sortedelement_t *parts_decals; sortedelement_t *parts_last; void renderParticle (particle_t *p); void renderDecal (particle_t *p); sortedelement_t *NewSortPart ( particle_t *p) { qboolean partinwater; vec3_t distance; sortedelement_t *element; element = &theparts[partstosort]; VectorSubtract(p->origin, r_origin, distance); VectorCopy(p->origin, element->org); element->data = p; element->len = VectorLength(distance); element->left = NULL; element->right = NULL; return element; } void resetPartSortList (void) { partstosort = 0; parts_prerender = NULL; parts_decals = NULL; parts_last = NULL; } qboolean particleClip( float len ) { if (gl_particle_min->value>0) { if (len < gl_particle_min->value) return true; } if (gl_particle_max->value>0) { if (len > gl_particle_max->value) return true; } return false; } void DecalElementAddNode ( sortedelement_t *base, sortedelement_t *thisElement ) { particle_t *pBase = thisElement->data, *pThis = base->data; if (pBase->flags & PART_DECAL_SUB) { if (pThis->flags & PART_DECAL_SUB) { if (base->right) ElementAddNode(base->right, thisElement); else base->right = thisElement; } else { if (base->left) ElementAddNode(base->left, thisElement); else base->left = thisElement; } return; } else if (pThis->flags & PART_DECAL_ADD) { if (pThis->flags & PART_DECAL_SUB) { if (base->left) ElementAddNode(base->left, thisElement); else base->left = thisElement; } else { if (base->right) ElementAddNode(base->right, thisElement); else base->right = thisElement; } return; } if (thisElement->len > base->len) { if (base->left) ElementAddNode(base->left, thisElement); else base->left = thisElement; } else { if (base->right) ElementAddNode(base->right, thisElement); else base->right = thisElement; } } void AddPartTransTree( particle_t *p ) { sortedelement_t *thisPart; thisPart = NewSortPart(p); //decals are sorted by render type, then depth if (p->flags&PART_DECAL) { if (parts_decals) DecalElementAddNode(parts_decals, thisPart); else parts_decals = thisPart; } else { if (particleClip(thisPart->len)) return; if (parts_prerender) ElementAddNode(parts_prerender, thisPart); else parts_prerender = thisPart; parts_last = thisPart; } partstosort++; } void GL_BuildParticleList() { int i; resetPartSortList(); for ( i=0 ; i < r_newrefdef.num_particles ; i++) { currentparticle = &r_newrefdef.particles[i]; AddPartTransTree(currentparticle); } } void RenderParticleTree (sortedelement_t *element) { if (!element) return; RenderParticleTree(element->left); if (element->data) renderParticle((particle_t *)element->data); RenderParticleTree(element->right); } void RenderDecalTree (sortedelement_t *element) { if (!element) return; RenderDecalTree(element->left); if (element->data) renderDecal((particle_t *)element->data); RenderDecalTree(element->right); } /* =============== R_DrawParticles =============== */ vec3_t particle_coord[4]; void R_DrawDecals (void) { vec3_t up = {vup[0] * 0.75f, vup[1] * 0.75f, vup[2] * 0.75f}; vec3_t right = {vright[0] * 0.75f, vright[1] * 0.75f, vright[2] * 0.75f}; VectorAdd (up, right, particle_coord[0]); VectorSubtract (right, up, particle_coord[1]); VectorNegate (particle_coord[0], particle_coord[2]); VectorNegate (particle_coord[1], particle_coord[3]); qglEnable (GL_TEXTURE_2D); GL_TexEnv( GL_MODULATE ); qglDepthMask (false); GLSTATE_ENABLE_BLEND GL_ShadeModel (GL_SMOOTH); GLSTATE_DISABLE_ALPHATEST RenderDecalTree(parts_decals); qglDepthRange (gldepthmin, gldepthmax); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv( GL_MODULATE ); qglDepthMask (true); GLSTATE_DISABLE_BLEND qglColor4f (1,1,1,1); } void R_DrawAllAddGlareParticles (void) { vec3_t up = {vup[0] * 0.75f, vup[1] * 0.75f, vup[2] * 0.75f}; vec3_t right = {vright[0] * 0.75f, vright[1] * 0.75f, vright[2] * 0.75f}; int i; VectorAdd (up, right, particle_coord[0]); VectorSubtract (right, up, particle_coord[1]); VectorNegate (particle_coord[0], particle_coord[2]); VectorNegate (particle_coord[1], particle_coord[3]); qglEnable (GL_TEXTURE_2D); GL_TexEnv( GL_MODULATE ); qglDepthMask (false); GLSTATE_ENABLE_BLEND GL_ShadeModel (GL_SMOOTH); GLSTATE_DISABLE_ALPHATEST for ( i=0 ; i < r_newrefdef.num_particles ; i++) if (r_newrefdef.particles[i].flags&PART_GLARE) { if (r_newrefdef.particles[i].flags&PART_DECAL) renderDecal(&r_newrefdef.particles[i]); else renderParticle(&r_newrefdef.particles[i]); } qglDepthRange (gldepthmin, gldepthmax); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv( GL_MODULATE ); qglDepthMask (true); GLSTATE_DISABLE_BLEND qglColor4f (1,1,1,1); } void R_DrawAllSubDecals (void) { vec3_t up = {vup[0] * 0.75f, vup[1] * 0.75f, vup[2] * 0.75f}; vec3_t right = {vright[0] * 0.75f, vright[1] * 0.75f, vright[2] * 0.75f}; int i; VectorAdd (up, right, particle_coord[0]); VectorSubtract (right, up, particle_coord[1]); VectorNegate (particle_coord[0], particle_coord[2]); VectorNegate (particle_coord[1], particle_coord[3]); qglEnable (GL_TEXTURE_2D); GL_TexEnv( GL_MODULATE ); qglDepthMask (false); GLSTATE_ENABLE_BLEND GL_ShadeModel (GL_SMOOTH); GLSTATE_DISABLE_ALPHATEST for ( i=0 ; i < r_newrefdef.num_particles ; i++) if (r_newrefdef.particles[i].flags&PART_DECAL && r_newrefdef.particles[i].flags&PART_DECAL_SUB) renderDecal(&r_newrefdef.particles[i]); qglDepthRange (gldepthmin, gldepthmax); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv( GL_MODULATE ); qglDepthMask (true); GLSTATE_DISABLE_BLEND qglColor4f (1,1,1,1); } void R_DrawAllDecals (void) { vec3_t up = {vup[0] * 0.75f, vup[1] * 0.75f, vup[2] * 0.75f}; vec3_t right = {vright[0] * 0.75f, vright[1] * 0.75f, vright[2] * 0.75f}; int i; VectorAdd (up, right, particle_coord[0]); VectorSubtract (right, up, particle_coord[1]); VectorNegate (particle_coord[0], particle_coord[2]); VectorNegate (particle_coord[1], particle_coord[3]); qglEnable (GL_TEXTURE_2D); GL_TexEnv( GL_MODULATE ); qglDepthMask (false); GLSTATE_ENABLE_BLEND GL_ShadeModel (GL_SMOOTH); GLSTATE_DISABLE_ALPHATEST for ( i=0 ; i < r_newrefdef.num_particles ; i++) if (r_newrefdef.particles[i].flags&PART_DECAL) renderDecal(&r_newrefdef.particles[i]); qglDepthRange (gldepthmin, gldepthmax); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv( GL_MODULATE ); qglDepthMask (true); GLSTATE_DISABLE_BLEND qglColor4f (1,1,1,1); } void SetVertexOverbrights(qboolean); qboolean ParticleOverbright; void SetParticleOverbright(qboolean toggle) { if ( (toggle && !ParticleOverbright) || (!toggle && ParticleOverbright) ) { SetVertexOverbrights(toggle); ParticleOverbright = toggle; } } void R_DrawParticles (void *list) { vec3_t up = {vup[0] * 0.75f, vup[1] * 0.75f, vup[2] * 0.75f}; vec3_t right = {vright[0] * 0.75f, vright[1] * 0.75f, vright[2] * 0.75f}; VectorAdd (up, right, particle_coord[0]); VectorSubtract (right, up, particle_coord[1]); VectorNegate (particle_coord[0], particle_coord[2]); VectorNegate (particle_coord[1], particle_coord[3]); qglEnable (GL_TEXTURE_2D); GL_TexEnv( GL_MODULATE ); qglDepthMask (false); GLSTATE_ENABLE_BLEND GL_ShadeModel (GL_SMOOTH); GLSTATE_DISABLE_ALPHATEST ParticleOverbright = false; RenderParticleTree(list); qglDepthRange (gldepthmin, gldepthmax); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv( GL_MODULATE ); qglDepthMask (true); GLSTATE_DISABLE_BLEND qglColor4f (1,1,1,1); } void R_DrawAllParticles (void) { vec3_t up = {vup[0] * 0.75f, vup[1] * 0.75f, vup[2] * 0.75f}; vec3_t right = {vright[0] * 0.75f, vright[1] * 0.75f, vright[2] * 0.75f}; int i; VectorAdd (up, right, particle_coord[0]); VectorSubtract (right, up, particle_coord[1]); VectorNegate (particle_coord[0], particle_coord[2]); VectorNegate (particle_coord[1], particle_coord[3]); qglEnable (GL_TEXTURE_2D); GL_TexEnv( GL_MODULATE ); qglDepthMask (false); GLSTATE_ENABLE_BLEND GL_ShadeModel (GL_SMOOTH); GLSTATE_DISABLE_ALPHATEST ParticleOverbright = false; for ( i=0 ; i < r_newrefdef.num_particles ; i++) if (!(r_newrefdef.particles[i].flags&PART_DECAL)) renderParticle(&r_newrefdef.particles[i]); qglDepthRange (gldepthmin, gldepthmax); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv( GL_MODULATE ); qglDepthMask (true); GLSTATE_DISABLE_BLEND qglColor4f (1,1,1,1); } /********************************************************** renderParticle **********************************************************/ int texParticle (int type) { image_t *part_img; part_img = r_particletextures [type]; return part_img->texnum; } void vectoanglerolled (vec3_t value1, float angleyaw, vec3_t angles) { float forward, yaw, pitch; yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI); forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]); pitch = (int) (atan2(value1[2], forward) * 180 / M_PI); if (pitch < 0) pitch += 360; angles[PITCH] = -pitch; angles[YAW] = yaw; angles[ROLL] = - angleyaw; } float AngleFind(float input) { return 180.0/input; } void setBeamAngles (vec3_t start, vec3_t end, vec3_t up, vec3_t right) { vec3_t move, delta; VectorSubtract(end, start, move); VectorNormalize(move); VectorCopy(move, up); VectorSubtract(r_newrefdef.vieworg, start, delta); CrossProduct(up, delta, right); // if(!VectorCompare(right, vec3_origin)) VectorNormalize(right); } void getParticleLight (particle_t *p, vec3_t pos, float lighting, vec3_t shadelight) { int j; float lightest = 0; if (!lighting) { VectorSet(shadelight, p->red, p->green, p->blue); return; } R_LightPoint (pos, shadelight); shadelight[0]= (lighting*shadelight[0]+(1-lighting)) * p->red; shadelight[1]= (lighting*shadelight[1]+(1-lighting)) * p->green; shadelight[2]= (lighting*shadelight[2]+(1-lighting)) * p->blue; //this cleans up the lighting { for (j=0;j<3;j++) if (shadelight[j]>lightest) lightest= shadelight[j]; if (lightest>255) for (j=0;j<3;j++) { shadelight[j]*= 255/lightest; if (shadelight[j]>255) shadelight[j] = 255; } for (j=0;j<3;j++) { if (shadelight[j]<0) shadelight[j] = 0; } } } //id move this somewhere less dirty, but im too damn lazy - psychospaz #define DEPTHHACK_RANGE_SHORT 0.999f #define DEPTHHACK_RANGE_MID 0.99f #define DEPTHHACK_RANGE_LONG 0.975f vec3_t ParticleVec[4]; vec3_t shadelight; rscript_t *shaderParticle (int type) { image_t *part_img; part_img = r_particletextures[type]; return part_img->script; } void renderParticleShader (particle_t *p, vec3_t origin, float size, qboolean translate) { rscript_t *rs = NULL; float txm,tym, alpha,s,t; rs_stage_t *stage; char scriptname [MAX_QPATH]; vec3_t color; if (r_shaders->value) rs=shaderParticle(p->image); if (rs) { RS_ReadyScript(rs); stage=rs->stage; while (stage) { if (stage->colormap.enabled) qglDisable (GL_TEXTURE_2D); else if (stage->anim_count) GL_Bind(RS_Animate(stage)); else GL_Bind (stage->texture->texnum); if (stage->blendfunc.blend) GL_BlendFunction(stage->blendfunc.source,stage->blendfunc.dest); else GL_BlendFunction (p->blendfunc_src, p->blendfunc_dst); alpha=1.0f; if (stage->alphashift.min || stage->alphashift.speed) { if (!stage->alphashift.speed && stage->alphashift.min > 0) { alpha=stage->alphashift.min; } else if (stage->alphashift.speed) { alpha=sin(rs_realtime * stage->alphashift.speed); alpha=(alpha+1)*0.5f; if (alpha > stage->alphashift.max) alpha=stage->alphashift.max; if (alpha < stage->alphashift.min) alpha=stage->alphashift.min; } } alpha *= p->alpha; if (stage->alphamask) { GLSTATE_ENABLE_ALPHATEST } else { GLSTATE_DISABLE_ALPHATEST } if (stage->colormap.enabled) { float red = 1, green = 1, blue = 1; red = stage->colormap.red/255.0; green = stage->colormap.green/255.0; blue = stage->colormap.blue/255.0; VectorSet(color, red,green,blue); } else if (stage->lightmap && p->flags&PART_SHADED) VectorSet(color, shadelight[0]/255.0, shadelight[1]/255.0, shadelight[2]/255.0); else VectorSet(color, p->red/255.0, p->green/255.0, p->blue/255.0); if (p->flags&PART_ALPHACOLOR) qglColor4f(color[0]*alpha,color[1]*alpha,color[2]*alpha, alpha); else qglColor4f(color[0],color[1],color[2], alpha); qglPushMatrix(); { if (translate) { qglTranslatef( origin[0], origin[1], origin[2] ); qglScalef(size, size, size ); } if (p->decal) { qglEnable(GL_POLYGON_OFFSET_FILL); qglPolygonOffset(-2, -1); qglBegin (GL_TRIANGLE_FAN); { int i; float s, t; vec3_t point; decalpolys_t *decal = p->decal; for (i = 0; i < p->decal->numpolys; i++) { s = p->decal->coords[i][0]; t = p->decal->coords[i][1]; VectorCopy(decal->polys[i], point); RS_SetTexcoords2D (stage, &s, &t); qglTexCoord2f (s, t); qglVertex3fv (point); } } qglEnd (); qglDisable(GL_POLYGON_OFFSET_FILL); } else { qglBegin (GL_QUADS); { float s, t; s = 0; t = 1; RS_SetTexcoords2D (stage, &s, &t); qglTexCoord2f (s, t); qglVertex3fv (ParticleVec[0]); s = 0; t = 0; RS_SetTexcoords2D (stage, &s, &t); qglTexCoord2f (s, t); qglVertex3fv (ParticleVec[1]); s = 1; t = 0; RS_SetTexcoords2D (stage, &s, &t); qglTexCoord2f (s, t); qglVertex3fv (ParticleVec[2]); s = 1; t = 1; RS_SetTexcoords2D (stage, &s, &t); qglTexCoord2f (s, t); qglVertex3fv (ParticleVec[3]); } qglEnd (); } } qglPopMatrix (); if (stage->colormap.enabled) qglEnable (GL_TEXTURE_2D); stage=stage->next; } } else { qglPushMatrix(); { if (translate) { qglTranslatef( origin[0], origin[1], origin[2] ); qglScalef(size, size, size ); } if (p->decal) { qglEnable(GL_POLYGON_OFFSET_FILL); qglPolygonOffset(-2, -1); qglBegin (GL_TRIANGLE_FAN); { int i; for (i = 0; i < p->decal->numpolys; i++) { qglTexCoord2f (p->decal->coords[i][0], p->decal->coords[i][1]); qglVertex3fv (p->decal->polys[i]); } } qglEnd (); qglDisable(GL_POLYGON_OFFSET_FILL); } else { qglBegin (GL_QUADS); { qglTexCoord2f (0, 1); qglVertex3fv (ParticleVec[0]); qglTexCoord2f (0, 0); qglVertex3fv (ParticleVec[1]); qglTexCoord2f (1, 0); qglVertex3fv (ParticleVec[2]); qglTexCoord2f (1, 1); qglVertex3fv (ParticleVec[3]); } qglEnd (); } } qglPopMatrix (); } } void renderDecal (particle_t *p) { float size, alpha; vec3_t angl_coord[4]; vec3_t ang_up, ang_right, ang_forward, color; rscript_t *rs = NULL; size = (p->size>0.1) ? p->size : 0.1; alpha = p->alpha; if (p->flags&PART_SHADED) { getParticleLight (p, p->origin, gl_particle_lighting->value, shadelight); VectorSet(color, shadelight[0]/255.0, shadelight[1]/255.0, shadelight[2]/255.0); } else { VectorSet(shadelight, p->red, p->green, p->blue); VectorSet(color, p->red/255.0, p->green/255.0, p->blue/255.0); } if (!r_shaders->value || !shaderParticle(p->image)) { GL_BlendFunction (p->blendfunc_src, p->blendfunc_dst); GL_Bind(texParticle(p->image)); if (p->flags&PART_ALPHACOLOR) qglColor4f(color[0]*alpha,color[1]*alpha,color[2]*alpha, alpha); else qglColor4f(color[0],color[1],color[2], alpha); } if (!p->decal) { AngleVectors(p->angle, ang_forward, ang_right, ang_up); VectorScale (ang_right, 0.75f, ang_right); VectorScale (ang_up, 0.75f, ang_up); VectorAdd (ang_up, ang_right, angl_coord[0]); VectorSubtract (ang_right, ang_up, angl_coord[1]); VectorNegate (angl_coord[0], angl_coord[2]); VectorNegate (angl_coord[1], angl_coord[3]); VectorMA(p->origin, size, angl_coord[0], ParticleVec[0]); VectorMA(p->origin, size, angl_coord[1], ParticleVec[1]); VectorMA(p->origin, size, angl_coord[2], ParticleVec[2]); VectorMA(p->origin, size, angl_coord[3], ParticleVec[3]); } renderParticleShader(p, NULL, 0, false); } void renderParticle (particle_t *p) { float size, lighting = gl_particle_lighting->value; vec3_t up = {vup[0] * 0.75f, vup[1] * 0.75f, vup[2] * 0.75f}; vec3_t right = {vright[0] * 0.75f, vright[1] * 0.75f, vright[2] * 0.75f}; vec3_t shadelight; float alpha; vec3_t coord[4], color; rscript_t *rs = NULL; VectorCopy(particle_coord[0], coord[0]); VectorCopy(particle_coord[1], coord[1]); VectorCopy(particle_coord[2], coord[2]); VectorCopy(particle_coord[3], coord[3]); size = (p->size>0.1) ? p->size : 0.1; alpha = p->alpha; if (p->flags&PART_DEPTHHACK_SHORT) //nice little poly-peeking - psychospaz qglDepthRange (gldepthmin, gldepthmin + DEPTHHACK_RANGE_SHORT*(gldepthmax-gldepthmin)); if (p->flags&PART_DEPTHHACK_MID) qglDepthRange (gldepthmin, gldepthmin + DEPTHHACK_RANGE_MID*(gldepthmax-gldepthmin)); if (p->flags&PART_DEPTHHACK_LONG) qglDepthRange (gldepthmin, gldepthmin + DEPTHHACK_RANGE_LONG*(gldepthmax-gldepthmin)); if (p->flags&PART_OVERBRIGHT) SetParticleOverbright(true); if (p->flags&PART_SHADED) { getParticleLight (p, p->origin, lighting, shadelight); VectorSet(color, shadelight[0]/255.0, shadelight[1]/255.0, shadelight[2]/255.0); } else { VectorSet(shadelight, p->red, p->green, p->blue); VectorSet(color, p->red/255.0, p->green/255.0, p->blue/255.0); } if (!r_shaders->value || !shaderParticle(p->image)) { GL_BlendFunction (p->blendfunc_src, p->blendfunc_dst); GL_Bind(texParticle(p->image)); if (p->flags&PART_ALPHACOLOR) qglColor4f(color[0]*alpha,color[1]*alpha,color[2]*alpha, alpha); else qglColor4f(color[0],color[1],color[2], alpha); } if (p->flags&PART_BEAM) //given start and end positions, will have fun here :) { //p->angle = start //p->origin= end vec3_t angl_coord[4]; vec3_t ang_up, ang_right; setBeamAngles(p->angle, p->origin, ang_up, ang_right); VectorScale(ang_right, size, ang_right); VectorAdd(p->origin, ang_right, ParticleVec[0]); VectorAdd(p->angle, ang_right, ParticleVec[1]); VectorSubtract(p->angle, ang_right, ParticleVec[2]); VectorSubtract(p->origin, ang_right, ParticleVec[3]); renderParticleShader(p, NULL, 0, false); } else if (p->flags&PART_LIGHTNING) //given start and end positions, will have fun here :) { //p->angle = start //p->origin= end int k = 0; float len, dec, angdot; vec3_t move, lastvec, thisvec, tempvec; vec3_t angl_coord[4], old_coord[2]; vec3_t ang_up, ang_right, last_right, abs_up, abs_right; float width, scale_up, scale_right; scale_up = scale_right = 0; dec = size*5.0; width = size; VectorSubtract(p->origin, p->angle, move); len = VectorNormalize(move); setBeamAngles(p->angle, p->origin, abs_up, abs_right); VectorScale(move, dec, move); VectorCopy(p->angle, thisvec); VectorSubtract(thisvec, move, lastvec); VectorCopy(thisvec, tempvec); len+=dec; setBeamAngles(lastvec, thisvec, ang_up, ang_right); VectorScale (ang_right, width, ang_right); while (len>dec) { VectorCopy(ang_right, last_right); setBeamAngles(lastvec, thisvec, ang_up, ang_right); VectorScale (ang_right, width, ang_right); angdot = DotProduct(ang_right, last_right); { VectorAdd(lastvec, ang_right, ParticleVec[1]); VectorSubtract(lastvec, ang_right, ParticleVec[2]); VectorAdd(thisvec, ang_right, ParticleVec[0]); VectorSubtract(thisvec, ang_right, ParticleVec[3]); VectorCopy(ParticleVec[0], old_coord[0]); VectorCopy(ParticleVec[3], old_coord[1]); } if (k>0) renderParticleShader(p, NULL, 0, false); k++; len-=dec; VectorCopy(thisvec, lastvec); //now modify stuff { float diff = lastvec[0] + lastvec[1] + lastvec[2]; //scale_up += crandom() * size; //scale_right -= crandom() * size; scale_up = size*( cos(diff*0.1+rs_realtime*15.0) ); scale_right = size*( sin( diff*0.1+rs_realtime*15.0) ); } if (scale_right > size) scale_right = size; if (scale_right < -size) scale_right = -size; if (scale_up > size) scale_up = size; if (scale_up < -size) scale_up = -size; VectorAdd(tempvec, move, tempvec); thisvec[0] = tempvec[0] + abs_up[0]*scale_up + abs_right[0]*scale_right; thisvec[1] = tempvec[1] + abs_up[1]*scale_up + abs_right[1]*scale_right; thisvec[2] = tempvec[2] + abs_up[2]*scale_up + abs_right[2]*scale_right; } //one more time if (len>0) { VectorCopy(p->origin, thisvec); VectorCopy(ang_right, last_right); setBeamAngles(lastvec, thisvec, ang_up, ang_right); VectorScale (ang_right, width, ang_right); angdot = DotProduct(ang_right, last_right); { VectorAdd(lastvec, ang_right, ParticleVec[1]); VectorSubtract(lastvec, ang_right, ParticleVec[2]); VectorAdd(thisvec, ang_right, ParticleVec[0]); VectorSubtract(thisvec, ang_right, ParticleVec[3]); VectorCopy(ParticleVec[0], old_coord[0]); VectorCopy(ParticleVec[3], old_coord[1]); } renderParticleShader(p, NULL, 0, false); } } else if (p->flags&PART_DIRECTION) //streched out in direction...tracers etc... //never dissapears because of angle like other engines :D { vec3_t angl_coord[4]; vec3_t ang_up, ang_right, vdelta; VectorAdd(p->angle, p->origin, vdelta); setBeamAngles(vdelta, p->origin, ang_up, ang_right); VectorScale (ang_right, 0.75f, ang_right); VectorScale (ang_up, 0.75f * VectorLength(p->angle), ang_up); VectorAdd (ang_up, ang_right, ParticleVec[0]); VectorSubtract (ang_right, ang_up, ParticleVec[1]); VectorNegate (ParticleVec[0], ParticleVec[2]); VectorNegate (ParticleVec[1], ParticleVec[3]); renderParticleShader(p, p->origin, size, true); } else if (p->flags&PART_ANGLED) //facing direction... (decal wannabes) { vec3_t angl_coord[4]; vec3_t ang_up, ang_right, ang_forward; AngleVectors(p->angle, ang_forward, ang_right, ang_up); VectorScale (ang_right, 0.75f, ang_right); VectorScale (ang_up, 0.75f, ang_up); VectorAdd (ang_up, ang_right, ParticleVec[0]); VectorSubtract (ang_right, ang_up, ParticleVec[1]); VectorNegate (ParticleVec[0], ParticleVec[2]); VectorNegate (ParticleVec[1], ParticleVec[3]); qglDisable (GL_CULL_FACE); renderParticleShader(p, p->origin, size, true); qglEnable (GL_CULL_FACE); } else //normal sprites { if (p->angle[2]) //if we have roll, we do calcs { vec3_t angl_coord[4]; vec3_t ang_up, ang_right, ang_forward; VectorSubtract(p->origin, r_newrefdef.vieworg, angl_coord[0]); vectoanglerolled(angl_coord[0], p->angle[2], angl_coord[1]); AngleVectors(angl_coord[1], ang_forward, ang_right, ang_up); VectorScale (ang_forward, 0.75f, ang_forward); VectorScale (ang_right, 0.75f, ang_right); VectorScale (ang_up, 0.75f, ang_up); VectorAdd (ang_up, ang_right, ParticleVec[0]); VectorSubtract (ang_right, ang_up, ParticleVec[1]); VectorNegate (ParticleVec[0], ParticleVec[2]); VectorNegate (ParticleVec[1], ParticleVec[3]); } else { VectorCopy(coord[0], ParticleVec[0]); VectorCopy(coord[1], ParticleVec[1]); VectorCopy(coord[2], ParticleVec[2]); VectorCopy(coord[3], ParticleVec[3]); } renderParticleShader(p, p->origin, size, true); } if (p->flags&PART_OVERBRIGHT) SetParticleOverbright(false); if (p->flags&PART_DEPTHHACK) qglDepthRange (gldepthmin, gldepthmax); } /* ============ R_PolyBlend ============ */ void R_MotionBlurBlend (void) { if (!gl_motionblur->value) return; GLSTATE_DISABLE_ALPHATEST GLSTATE_ENABLE_BLEND qglDisable (GL_DEPTH_TEST); qglEnable (GL_TEXTURE_2D); GL_TexEnv( GL_MODULATE ); qglLoadIdentity (); // FIXME: get rid of these qglRotatef (-90, 1, 0, 0); // put Z going up qglRotatef (90, 0, 0, 1); // put Z going up GL_Bind(r_motionblurimage->texnum); GL_BlendFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR); qglColor4ub(255, 255, 255, 250); qglBegin (GL_QUADS); qglTexCoord2f (0, 0); qglVertex3f (100, 100, 100); qglTexCoord2f (1, 0); qglVertex3f (100, -100, 100); qglTexCoord2f (1, -1); qglVertex3f (100, -100, -100); qglTexCoord2f (0, -1); qglVertex3f (100, 100, -100); qglEnd (); GLSTATE_DISABLE_BLEND GLSTATE_ENABLE_ALPHATEST GL_TexEnv( GL_REPLACE ); qglColor4f(1,1,1,1); } void R_PolyBlend (void) { if (!gl_polyblend->value) return; if (!v_blend[3]) return; GLSTATE_DISABLE_ALPHATEST GLSTATE_ENABLE_BLEND qglDisable (GL_DEPTH_TEST); qglDisable (GL_TEXTURE_2D); GL_BlendFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 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 (); GLSTATE_DISABLE_BLEND qglEnable (GL_TEXTURE_2D); GLSTATE_ENABLE_ALPHATEST qglColor4f(1,1,1,1); } void R_StencilBlend (void) { GLSTATE_DISABLE_ALPHATEST GLSTATE_ENABLE_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 qglColor4f(0,0,0,0.3); qglStencilFunc( GL_NOTEQUAL, 0, 0xFFFFFFFFL ); qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); qglEnable(GL_STENCIL_TEST); qglBegin (GL_QUADS); qglVertex3f (10, 100, 100); qglVertex3f (10, -100, 100); qglVertex3f (10, -100, -100); qglVertex3f (10, 100, -100); qglEnd (); qglDisable(GL_STENCIL_TEST); GLSTATE_DISABLE_BLEND qglEnable (GL_TEXTURE_2D); GLSTATE_ENABLE_ALPHATEST 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<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) { static GLdouble farz; // DMP skybox size change GLdouble boxsize; // DMP skybox size change 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); if (skydistance->modified) { skydistance->modified = false; boxsize = skydistance->value; boxsize -= 252 * ceil(boxsize / 2300); farz = 1.0; while (farz < boxsize) // DMP: make this value a power-of-2 { farz *= 2.0; if (farz >= 65536.0) // DMP: don't make it larger than this break; } farz *= 2.0; // DMP: double since boxsize is distance from camera to // edge of skybox - not total size of skybox ri.Con_Printf(PRINT_DEVELOPER, "farz now set to %g\n", farz); } // // 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); MYgluPerspective (r_newrefdef.fov_y, screenaspect, 4, farz); // DMP skybox 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); qglGetIntegerv (GL_VIEWPORT, r_viewport); // // set drawing parms // if (gl_cull->value) qglEnable(GL_CULL_FACE); else qglDisable(GL_CULL_FACE); GLSTATE_DISABLE_BLEND GLSTATE_DISABLE_ALPHATEST 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); } if (have_stencil) { qglClearStencil(0); qglClear(GL_STENCIL_BUFFER_BIT); } //this is for spheremapping... qglTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); qglTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); qglDepthRange (gldepthmin, gldepthmax); } void R_ShadowBlend() { if (!gl_shadows->value) return; qglLoadIdentity (); // FIXME: get rid of these qglRotatef (-90, 1, 0, 0); // put Z going up qglRotatef (90, 0, 0, 1); // put Z going up qglColor4f (0,0,0,0.4f); GLSTATE_DISABLE_ALPHATEST GLSTATE_ENABLE_BLEND qglDisable (GL_DEPTH_TEST); qglDisable (GL_TEXTURE_2D); qglEnable(GL_STENCIL_TEST); qglStencilFunc( GL_NOTEQUAL, 0, 0xFF); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); qglBegin (GL_QUADS); qglVertex3f (10, 100, 100); qglVertex3f (10, -100, 100); qglVertex3f (10, -100, -100); qglVertex3f (10, 100, -100); qglEnd (); GLSTATE_DISABLE_BLEND qglEnable (GL_TEXTURE_2D); GLSTATE_ENABLE_ALPHATEST qglDisable(GL_STENCIL_TEST); qglColor4f(1,1,1,1); } void R_Flash( void ) { R_PolyBlend (); R_ShadowBlend (); } /* ================ R_RenderView r_newrefdef must be set before the first call ================ */ void R_DrawSkyBox_Models (void); void R_DrawSpecialSurfaces(void); void R_RenderMotionBlurView (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 (); GLSTATE_DISABLE_ALPHATEST R_DrawMotionBlurEntities(); R_MotionBlurBlend(); } void R_RenderDynamicView (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 (); GLSTATE_DISABLE_ALPHATEST R_RenderDlights (); //never sort - could get too messy! R_DrawSpecialSurfaces(); if (rs_dynamic_particles->value) { R_DrawAllDecals(); R_DrawAllParticles(); } if (rs_dynamic_entities->value) R_DrawAllEntities(false); R_DrawAlphaSurfaces (false); } void R_RenderGlareView (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 (); GLSTATE_DISABLE_ALPHATEST R_DrawAllSubDecals(); R_DrawAllEntities(true); if (rs_glares_particles->value) R_DrawAllAddGlareParticles(); } qboolean checkSurfaceTrace (msurface_t *surf, vec3_t end, vec3_t start) { float front, back, side, dist; vec3_t normal; cplane_t *plane; plane = surf->plane; if (!plane) return false; dist = plane->dist; VectorCopy(plane->normal, normal); front = DotProduct (start, normal) - dist; back = DotProduct (end, normal) - dist; side = front < 0; if ( (back < 0) == side) return false; return true; } qboolean TracePoints (vec3_t start, vec3_t end, void *surface) { int i; msurface_t *surf = r_worldmodel->surfaces; for (i=0; inumsurfaces; i++, surf++) { if (surf == surface) continue; if (surf->texinfo->flags & (SURF_TRANS33 | SURF_TRANS66)) continue; if (checkSurfaceTrace(surf, start, end)) return true; } return false; } qboolean checkElementSurfaceScan (msurface_t *surf, vec3_t start) { float front, back, side, dist; vec3_t end, normal; cplane_t *plane; plane = surf->plane; if (!plane) return false; dist = plane->dist; VectorCopy(plane->normal, normal); VectorCopy(r_newrefdef.vieworg, end); front = DotProduct (start, normal) - dist; back = DotProduct (end, normal) - dist; side = front < 0; if ( (back < 0) == side) return false; return true; } sortedelement_t *listswap[2]; void ElementChecker (sortedelement_t *element, msurface_t *surf) { if (!element) return; ElementChecker(element->right, surf); ElementChecker(element->left, surf); element->left = element->right = NULL; if (checkElementSurfaceScan(surf, element->org)) { if (!listswap[0]) listswap[0] = element; else ElementAddNode(listswap[0], element); } else { if (!listswap[1]) listswap[1] = element; else ElementAddNode(listswap[1], element); } } void surf_ElementList(msurface_t *surf, qboolean ents) { sortedelement_t *temp, *element, *last = NULL, *found = NULL; listswap[0] = listswap[1] = NULL; if (ents) ElementChecker(ents_prerender, surf); else ElementChecker(parts_prerender, surf); if (ents) { ents_prerender = listswap[1]; RenderEntTree(listswap[0]); } else { parts_prerender = listswap[1]; R_DrawParticles(listswap[0]); } } void R_DrawLastElements (void) { if (parts_prerender) R_DrawParticles(parts_prerender); if (ents_prerender) RenderEntTree(ents_prerender); } void R_RenderView (refdef_t *fd) { qboolean mBlur = fd->rdflags & RDF_MOTIONBLUR; if (mBlur) fd->rdflags &= ~RDF_MOTIONBLUR; 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 (); if (r_newrefdef.rdflags & RDF_NOWORLDMODEL) //options menu { R_DrawAllDecals(); R_DrawAllEntities(false); R_DrawAllParticles(); } else { R_DrawSpecialSurfaces(); GLSTATE_DISABLE_ALPHATEST R_RenderDlights (); //spaz -> my nice trees if (gl_transrendersort->value) { GL_BuildParticleList(); R_DrawSolidEntities(); // R_DrawAllEntityShadows(); R_DrawDecals (); if (gl_transrendersort->value==1) { R_DrawLastElements(); R_DrawAlphaSurfaces (false); } else { R_DrawAlphaSurfaces (true); R_DrawLastElements(); } } //nonsorted routines else { R_DrawAllDecals(); R_DrawAllEntities(true); // R_DrawAllEntityShadows(); R_DrawAllParticles(); R_DrawAlphaSurfaces (false); } //always draw vwep last... R_DrawEntitiesOnList(ents_viewweaps); R_DrawEntitiesOnList(ents_viewweaps_trans); R_DrawAllEntityShadows(); 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); } } if (mBlur) { R_MotionBlurBlend(); fd->rdflags |= RDF_MOTIONBLUR; } } byte mulc(int i1, const float mult) { //amplify colors a bit int r = i1 * mult; if (r > 255) return 255; else return r; } void ProcessGlare(byte glarepixels[][4], int width, int height, const float mult) { int i; for (i=0; i0) { tot.r+=dst[-1].r; tot.g+=dst[-1].g; tot.b+=dst[-1].b; } if (y>0) { tot.r+=dst[-src_w].r; tot.g+=dst[-src_w].g; tot.b+=dst[-src_w].b; } if (x>0 && y>0) { tot.r-=dst[-src_w-1].r; tot.g-=dst[-src_w-1].g; tot.b-=dst[-src_w-1].b; } dst->r=tot.r; dst->g=tot.g; dst->b=tot.b; dst->a=255; dst++; src++; } } } // this is a utility function used by DoBoxBlur below longcolor_t *ReadP(longcolor_t *p, int w, int h, int x, int y) { if (x<0) x=0; else if (x>=w) x=w-1; if (y<0) y=0; else if (y>=h) y=h-1; return &p[x+y*w]; } // the main meat of the algorithm lies here void DoBoxBlur(bytecolor_t *src, int src_w, int src_h, bytecolor_t *dst, longcolor_t *p, int boxw, int boxh) { longcolor_t *to1, *to2, *to3, *to4; int y,x; float mul; if (boxw<0 || boxh<0) { memcpy(dst,src,src_w*src_h*4); // deal with degenerate kernel sizes return; } mul=1.f/((boxw*2+1)*(boxh*2+1)); for (y=0;yr= (to1->r + to2->r - to3->r - to4->r)*mul; dst->g= (to1->g + to2->g - to3->g - to4->g)*mul; dst->b= (to1->b + to2->b - to3->b - to4->b)*mul; dst->a= 255; dst++; src++; } } } qboolean screenMotionBlurRender = false; void ProcessBlur (bytecolor_t *src, int src_w, int src_h) { int x, y, alpha, r ,g ,b, noalpha= true; for (y=0;yr; g = src->g; b = src->b; alpha = (r + g + b); src->r = r*r * DIV255; src->g = g*g * DIV255; src->b = b*b * DIV255; if (alpha > 254) alpha = 254; if (alpha > 0) noalpha = false; src->a = alpha; } if (noalpha) screenMotionBlurRender = false; } byte imagepixels[256*256][4]; byte glareblurpixels[256*256][4]; long glaresum[256*256][4]; const int powerof2s[] = { 8, 16, 32, 64 , 128, 256 }; int checkResolution (int check) { int i; for (i=5; i>0; i--) if (check>=powerof2s[i]) return powerof2s[i]; return powerof2s[0]; } float CalcFov (float fov_x, float width, float height); int lastcapture = 0; qboolean renderDynamic = false; qboolean renderMotionBlur = false; void setRenderDynamic (void) { renderDynamic = true; } void setRenderMotionBlur (void) { renderMotionBlur = true; } void R_PreRenderDynamic (refdef_t *fd) { int i; msurface_t *surf; refdef_t refdef; qboolean motionBlurScreen = fd->rdflags & RDF_MOTIONBLUR; if (fd->rdflags & RDF_NOWORLDMODEL) return; if (r_shaders->value && lastcapture++ > rs_dynamic_time->value && renderDynamic) { int width = checkResolution(rs_dynamic_size->value); int height = checkResolution(rs_dynamic_size->value); //lower res wont get messed up if (vid.width < width || vid.height < height) width = height = 128; renderDynamic = false; lastcapture = 0; memcpy (&refdef, fd, sizeof( refdef )); refdef.x = 0; refdef.y = vid.height - height; refdef.width = width; refdef.height = height; refdef.fov_x = 150; refdef.fov_y = CalcFov (refdef.fov_x, refdef.width, refdef.height); refdef.viewangles[1] += (refdef.viewangles[1]>180)? -180: 180; if (motionBlurScreen) refdef.rdflags &= ~RDF_MOTIONBLUR; R_Clear(); R_RenderDynamicView ( &refdef ); GL_Bind(r_dynamicimage->texnum); qglReadPixels (0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imagepixels); qglTexImage2D (GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imagepixels); r_dynamicimage->upload_width = width; r_dynamicimage->upload_height = height; } if (rs_glares->value) { int width = checkResolution(rs_glares_size->value); int height = checkResolution(rs_glares_size->value); //lower res wont get messed up if (vid.width < width || vid.height < height) width = height = 128; memcpy (&refdef, fd, sizeof( refdef )); refdef.x = 0; refdef.y = vid.height - height; refdef.width = width; refdef.height = height; refdef.fov_y = CalcFov (refdef.fov_x, refdef.width, refdef.height); refdef.rdflags |= RDF_LIGHTBLEND; if (motionBlurScreen) refdef.rdflags &= ~RDF_MOTIONBLUR; R_Clear(); R_RenderGlareView ( &refdef ); GL_Bind(r_lblendimage->texnum); qglReadPixels (0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imagepixels); ProcessGlare(imagepixels, width, height, 1 + rs_glares->value*.5); DoPreComputation((bytecolor_t *)imagepixels, width, height, (longcolor_t *)glaresum); DoBoxBlur((bytecolor_t *)imagepixels, width, height, (bytecolor_t *)glareblurpixels, (longcolor_t *)glaresum, rs_glares->value*3, rs_glares->value*3); if (rs_glares->value != 1) ProcessGlare(glareblurpixels, width, height, 1 + rs_glares->value/3); qglTexImage2D (GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, glareblurpixels); r_lblendimage->upload_width = width; r_lblendimage->upload_height = height; } if (gl_motionblur->value && (motionBlurScreen || renderMotionBlur || screenMotionBlurRender)) { int width = checkResolution(gl_motionblur_size->value); int height = checkResolution(gl_motionblur_size->value); //lower res wont get messed up if (vid.width < width || vid.height < height) width = height = 128; renderMotionBlur = false; screenMotionBlurRender = true; memcpy (&refdef, fd, sizeof( refdef )); refdef.x = 0; refdef.y = vid.height - height; refdef.width = width; refdef.height = height; refdef.fov_y = CalcFov (refdef.fov_x, refdef.width, refdef.height); R_Clear(); if (motionBlurScreen) { R_RenderView( &refdef ); } else { refdef.rdflags |= RDF_MOTIONBLUR; R_RenderMotionBlurView ( &refdef ); } qglReadPixels (0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imagepixels); GL_Bind(r_motionblurimage->texnum); qglTexImage2D (GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imagepixels); GL_Bind(r_motionblurscreenimage->texnum); ProcessBlur((void *)imagepixels, width, height); qglTexImage2D (GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imagepixels); r_motionblurscreenimage->upload_width = width; r_motionblurscreenimage->upload_height = height; r_motionblurimage->upload_width = width; r_motionblurimage->upload_height = height; } R_Clear(); } void R_RenderPic(int x, int y, int w, int h) { qglTexCoord2f (0, 0); qglVertex2f (x, y); qglTexCoord2f (1, 0); qglVertex2f (x+w, y); qglTexCoord2f (1, -1); qglVertex2f (x+w, y+h); qglTexCoord2f (0, -1); qglVertex2f (x, y+h); } void R_RenderMotionBlur (refdef_t *fd) { int x, y, w, h; if (fd->rdflags & RDF_NOWORLDMODEL) return; if (!gl_motionblur->value) return; if (!screenMotionBlurRender) return; w = fd->width; h = fd->width; x = 0; y = (fd->width-fd->height)*-0.5; GL_Bind (r_motionblurscreenimage->texnum); GL_BlendFunction(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); GLSTATE_DISABLE_ALPHATEST GLSTATE_ENABLE_BLEND GL_TexEnv( GL_MODULATE ); qglColor4ub(255, 255, 255, 255); qglBegin (GL_QUADS); R_RenderPic(x, y, w, h); qglEnd (); GLSTATE_ENABLE_ALPHATEST GLSTATE_DISABLE_BLEND GL_TexEnv( GL_REPLACE ); GL_BlendFunction(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); } void R_RenderGlares (refdef_t *fd) { int x, y, w, h; if (fd->rdflags & RDF_NOWORLDMODEL) return; if (!rs_glares->value) return; w = fd->width; h = fd->width; x = 0; y = (fd->width-fd->height)*-0.5; GL_Bind (r_lblendimage->texnum); GL_BlendFunction(GL_ONE,GL_ONE); GLSTATE_DISABLE_ALPHATEST GLSTATE_ENABLE_BLEND GL_TexEnv( GL_MODULATE ); qglColor4f(1,1,1,1); qglBegin (GL_QUADS); R_RenderPic(x, y, w, h); qglEnd (); GLSTATE_ENABLE_ALPHATEST GLSTATE_DISABLE_BLEND GL_TexEnv( GL_REPLACE ); GL_BlendFunction(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); } 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); GLSTATE_DISABLE_BLEND GLSTATE_ENABLE_ALPHATEST GLSTATE_DISABLE_TEXGEN qglColor4f (1,1,1,1); GL_BlendFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } 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_PreRenderDynamic( fd ); R_RenderView( fd ); R_SetLightLevel (); R_SetGL2D (); R_RenderGlares(fd); R_RenderMotionBlur(fd); } void R_Register( void ) { con_font = ri.Cvar_Get ("con_font", "default", CVAR_ARCHIVE); con_font_size = ri.Cvar_Get ("con_font_size", "8", CVAR_ARCHIVE); r_dlights_normal = ri.Cvar_Get("r_dlights_normal", "1", CVAR_ARCHIVE); skydistance = ri.Cvar_Get("r_skydistance", "10000", CVAR_ARCHIVE); // DMP - skybox size change gl_transrendersort = ri.Cvar_Get ("gl_transrendersort", "1", CVAR_ARCHIVE ); gl_particle_lighting = ri.Cvar_Get ("gl_particle_lighting", "0.75", CVAR_ARCHIVE ); gl_particle_min = ri.Cvar_Get ("gl_particle_min", "0", CVAR_ARCHIVE ); gl_particle_max = ri.Cvar_Get ("gl_particle_max", "0", CVAR_ARCHIVE ); gl_surftrans_light = ri.Cvar_Get ("gl_surftrans_light", "1", CVAR_ARCHIVE ); gl_stencil = ri.Cvar_Get ("gl_stencil", "1", CVAR_ARCHIVE ); gl_screenshot_quality = ri.Cvar_Get ("gl_screenshot_quality", "85", CVAR_ARCHIVE ); 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); r_shaders = ri.Cvar_Get ("r_shaders", "1", CVAR_ARCHIVE); rs_dynamic_time = ri.Cvar_Get("rs_dynamic_time", "2", CVAR_ARCHIVE); rs_dynamic_size = ri.Cvar_Get("rs_dynamic_size", "64", CVAR_ARCHIVE); rs_dynamic_particles = ri.Cvar_Get("rs_dynamic_particles", "1", CVAR_ARCHIVE); rs_dynamic_entities = ri.Cvar_Get("rs_dynamic_entities", "1", CVAR_ARCHIVE); gl_motionblur = ri.Cvar_Get("gl_motionblur", "1", CVAR_ARCHIVE); gl_motionblur_size = ri.Cvar_Get("gl_motionblur_size", "128", CVAR_ARCHIVE); rs_detail = ri.Cvar_Get("rs_detail", "1", CVAR_ARCHIVE); rs_glares = ri.Cvar_Get("rs_glares", "0", CVAR_ARCHIVE); rs_glares_sky = ri.Cvar_Get("rs_glares_sky", "0", CVAR_ARCHIVE); rs_glares_size = ri.Cvar_Get("rs_glares_size", "128", CVAR_ARCHIVE); rs_glares_shell = ri.Cvar_Get("rs_glares_shell", "1", CVAR_ARCHIVE); rs_glares_particles = ri.Cvar_Get("rs_glares_particles", "1", CVAR_ARCHIVE); r_model_lightlerp = ri.Cvar_Get( "r_model_lightlerp", "1", CVAR_ARCHIVE ); r_model_dlights = ri.Cvar_Get( "r_model_dlights", "3", CVAR_ARCHIVE ); gl_nosubimage = ri.Cvar_Get( "gl_nosubimage", "0", 0 ); gl_allow_software = ri.Cvar_Get( "gl_allow_software", "0", 0 ); // Vic - begin r_overbrightbits = ri.Cvar_Get( "r_overbrightbits", "2", CVAR_ARCHIVE ); gl_ext_mtexcombine = ri.Cvar_Get( "gl_ext_mtexcombine", "1", CVAR_ARCHIVE ); // Vic - end gl_ext_texture_compression = ri.Cvar_Get( "gl_ext_texture_compression", "0", CVAR_ARCHIVE ); // Heffo - ARB Texture Compression 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", "libGL.so", CVAR_ARCHIVE ); gl_texturemode = ri.Cvar_Get( "gl_texturemode", "GL_LINEAR_MIPMAP_NEAREST", CVAR_ARCHIVE ); gl_anisotropic = ri.Cvar_Get( "gl_anisotropic", "0", 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 ); r_celshading = ri.Cvar_Get( "r_celshading", "0", CVAR_ARCHIVE ); r_celshading_width = ri.Cvar_Get( "r_celshading_width", "4", CVAR_ARCHIVE ); cl_3dcam = ri.Cvar_Get ("cl_3dcam", "0", CVAR_ARCHIVE); cl_3dcam_angle = ri.Cvar_Get ("cl_3dcam_angle", "0", CVAR_ARCHIVE); cl_3dcam_dist = ri.Cvar_Get ("cl_3dcam_dist", "50", CVAR_ARCHIVE); cl_3dcam_alpha = ri.Cvar_Get ("cl_3dcam_alpha", "1", CVAR_ARCHIVE); cl_3dcam_chase = ri.Cvar_Get ("cl_3dcam_chase", "1", CVAR_ARCHIVE); cl_3dcam_adjust = ri.Cvar_Get ("cl_3dcam_adjust", "1", CVAR_ARCHIVE); gl_ext_swapinterval = ri.Cvar_Get( "gl_ext_swapinterval", "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", "0", 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", "glx", 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; skydistance->modified = true; // DMP skybox size change 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, "rfx_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, "rfx_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, "rfx_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, "rfx_gl version: "REF_VERSION"\n"); Draw_GetPalette (); R_Register(); VLight_Init(); // initialize our QGL dynamic bindings if ( !QGL_Init( gl_driver->string ) ) { QGL_Shutdown(); ri.Con_Printf (PRINT_ALL, "rfx_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, "rfx_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" ); } #ifdef __unix__ ri.Cvar_SetValue( "gl_finish", 1 ); #endif // 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 */ 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" ); } #ifdef _WIN32 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" ); } #endif 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_ARB_multitexture" ) ) { if ( gl_ext_multitexture->value ) { ri.Con_Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); qglMTexCoord2fSGIS = ( void * ) qwglGetProcAddress( "glMultiTexCoord2fARB" ); qglActiveTextureARB = ( void * ) qwglGetProcAddress( "glActiveTextureARB" ); qglClientActiveTextureARB = ( void * ) qwglGetProcAddress( "glClientActiveTextureARB" ); GL_TEXTURE0 = GL_TEXTURE0_ARB; GL_TEXTURE1 = GL_TEXTURE1_ARB; } else { ri.Con_Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); } } else { ri.Con_Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); } if ( strstr( gl_config.extensions_string, "GL_SGIS_multitexture" ) ) { if ( qglActiveTextureARB ) { ri.Con_Printf( PRINT_ALL, "...GL_SGIS_multitexture deprecated in favor of ARB_multitexture\n" ); } else if ( gl_ext_multitexture->value ) { ri.Con_Printf( PRINT_ALL, "...using GL_SGIS_multitexture\n" ); qglMTexCoord2fSGIS = ( void * ) qwglGetProcAddress( "glMTexCoord2fSGIS" ); qglSelectTextureSGIS = ( void * ) qwglGetProcAddress( "glSelectTextureSGIS" ); GL_TEXTURE0 = GL_TEXTURE0_SGIS; GL_TEXTURE1 = GL_TEXTURE1_SGIS; } else { ri.Con_Printf( PRINT_ALL, "...ignoring GL_SGIS_multitexture\n" ); } } else { ri.Con_Printf( PRINT_ALL, "...GL_SGIS_multitexture not found\n" ); } // Vic - begin gl_config.mtexcombine = false; if ( strstr( gl_config.extensions_string, "GL_ARB_texture_env_combine" ) ) { if ( gl_ext_mtexcombine->value ) { Com_Printf( "...using GL_ARB_texture_env_combine\n" ); gl_config.mtexcombine = true; } else { Com_Printf( "...ignoring GL_ARB_texture_env_combine\n" ); } } else { Com_Printf( "...GL_ARB_texture_env_combine not found\n" ); } if ( !gl_config.mtexcombine ) { if ( strstr( gl_config.extensions_string, "GL_EXT_texture_env_combine" ) ) { if ( gl_ext_mtexcombine->value ) { Com_Printf( "...using GL_EXT_texture_env_combine\n" ); gl_config.mtexcombine = true; } else { Com_Printf( "...ignoring GL_EXT_texture_env_combine\n" ); } } else { Com_Printf( "...GL_EXT_texture_env_combine not found\n" ); } } // Vic - end // Texture Shader support - MrG if ( strstr( gl_config.extensions_string, "GL_NV_texture_shader" ) ) { ri.Con_Printf(PRINT_ALL, "...using GL_NV_texture_shader\n"); gl_state.texshaders=true; } else { ri.Con_Printf(PRINT_ALL, "...GL_NV_texture_shader not found\n"); gl_state.texshaders=false; } if ( strstr( gl_config.extensions_string, "GL_SGIS_generate_mipmap" ) ) { ri.Con_Printf(PRINT_ALL, "...using GL_SGIS_generate_mipmap\n"); gl_state.sgis_mipmap=true; } else { ri.Con_Printf(PRINT_ALL, "...GL_SGIS_generate_mipmap not found\n"); gl_state.sgis_mipmap=false; } // Heffo - ARB Texture Compression if ( strstr( gl_config.extensions_string, "GL_ARB_texture_compression" ) ) { if(!gl_ext_texture_compression->value) { ri.Con_Printf(PRINT_ALL, "...ignoring GL_ARB_texture_compression\n"); gl_state.texture_compression = false; } else { ri.Con_Printf(PRINT_ALL, "...using GL_ARB_texture_compression\n"); gl_state.texture_compression = true; } } else { ri.Con_Printf(PRINT_ALL, "...GL_ARB_texture_compression not found\n"); gl_state.texture_compression = false; ri.Cvar_Set("gl_ext_texture_compression", "0"); } GL_SetDefaultState(); /* ** draw our stereo patterns */ #if 0 // commented out until H3D pays us the money they owe us GL_DrawStereoPattern(); #endif gl_swapinterval->modified = true; GL_InitImages (); Mod_Init (); R_InitParticleTexture (); Draw_InitLocal (); if(gl_texturemode) GL_TextureMode( gl_texturemode->string ); 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 @@@@@@@@@@@@@@@@@@@@@ */ #ifdef _WIN32 void UpdateGammaRamp(); #endif void RefreshFont (void); void R_BeginFrame( float camera_separation ) { gl_state.camera_separation = camera_separation; if (con_font->modified) RefreshFont (); if (con_font_size->modified) { if (con_font_size->value<4) ri.Cvar_Set( "con_font_size", "4" ); else if (con_font_size->value>32) ri.Cvar_Set( "con_font_size", "32" ); con_font_size->modified = false; } if (r_overbrightbits->modified) { if (r_overbrightbits->value<1) ri.Cvar_Set( "r_overbrightbits", "1" ); else if (r_overbrightbits->value>2 && r_overbrightbits->value!=4) ri.Cvar_Set( "r_overbrightbits", "4" ); r_overbrightbits->modified = false; } if (gl_modulate->modified) { if (gl_modulate->value<0.5) ri.Cvar_Set( "gl_modulate", "0.5"); else if (gl_modulate->value>3) ri.Cvar_Set( "gl_modulate", "3" ); gl_modulate->modified = false; } /* ** 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", "glx", 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; #ifdef _WIN32 if (gl_state.gammaramp) UpdateGammaRamp(); #else if ( gl_state.hwgamma ) UpdateHardwareGamma(); #endif else 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 ); } } if (gl_particle_lighting->modified) { gl_particle_lighting->modified = false; if (gl_particle_lighting->value<0) gl_particle_lighting->value=0; if (gl_particle_lighting->value>1) gl_particle_lighting->value=1; } 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); GLSTATE_DISABLE_BLEND GLSTATE_ENABLE_ALPHATEST 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_RenderBeam( vec3_t start, vec3_t end, float size, float red, float green, float blue, float alpha ); void R_DrawBeam( entity_t *e ) { R_RenderBeam( e->origin, e->oldorigin, e->frame, ( d_8to24table[e->skinnum & 0xFF] ) & 0xFF, ( d_8to24table[e->skinnum & 0xFF] >> 8 ) & 0xFF, ( d_8to24table[e->skinnum & 0xFF] >> 16 ) & 0xFF, e->alpha*254 ); //OLD BEAM RENDERING CODE ... /* #define NUM_BEAM_SEGS 12 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 < NUM_BEAM_SEGS; 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 ); GLSTATE_ENABLE_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 *= DIV255; g *= DIV255; b *= DIV255; 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 ); GLSTATE_DISABLE_BLEND qglDepthMask( GL_TRUE ); */ } void R_RenderBeam( vec3_t start, vec3_t end, float size, float red, float green, float blue, float alpha ) { particle_t beam; vec3_t up = {vup[0] * 0.75f, vup[1] * 0.75f, vup[2] * 0.75f}; vec3_t right = {vright[0] * 0.75f, vright[1] * 0.75f, vright[2] * 0.75f}; VectorAdd (up, right, particle_coord[0]); VectorSubtract (right, up, particle_coord[1]); VectorNegate (particle_coord[0], particle_coord[2]); VectorNegate (particle_coord[1], particle_coord[3]); qglEnable (GL_TEXTURE_2D); GL_TexEnv( GL_MODULATE ); qglDepthMask (false); GLSTATE_ENABLE_BLEND GL_ShadeModel (GL_SMOOTH); GLSTATE_DISABLE_ALPHATEST ParticleOverbright = false; beam.alpha = alpha*DIV255*2.5; beam.blendfunc_src = GL_SRC_ALPHA; beam.blendfunc_dst = GL_ONE; beam.blue = blue*255; beam.red = red*255; beam.green = green*255; beam.decal = NULL; beam.flags = PART_BEAM; beam.image = 0; VectorCopy(start, beam.angle); VectorCopy(end, beam.origin); beam.size = size*2; renderParticle (&beam); qglDepthRange (gldepthmin, gldepthmax); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv( GL_MODULATE ); qglDepthMask (true); GLSTATE_DISABLE_BLEND qglColor4f (1,1,1,1); } /* void R_RenderBeam( vec3_t start, vec3_t end, float size, float red, float green, float blue, float alpha ) { float len; vec3_t coord[4], ang_up, ang_right, vdelta; particle_t beam; GL_TexEnv( GL_MODULATE ); qglDepthMask (false); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE); GLSTATE_ENABLE_BLEND GL_ShadeModel (GL_SMOOTH); GL_Bind(r_particlebeam->texnum); qglColor4ub(red, green, blue, alpha); VectorSubtract(start, end, ang_up); len = VectorNormalize(ang_up); VectorSubtract(r_newrefdef.vieworg, start, vdelta); CrossProduct(ang_up, vdelta, ang_right); if(!VectorCompare(ang_right, vec3_origin)) VectorNormalize(ang_right); VectorScale (ang_right, size*3.0, ang_right); VectorAdd(start, ang_right, coord[0]); VectorAdd(end, ang_right, coord[1]); VectorSubtract(end, ang_right, coord[2]); VectorSubtract(start, ang_right, coord[3]); qglPushMatrix(); { qglBegin (GL_QUADS); { qglTexCoord2f (0, 1); qglVertex3fv (coord[0]); qglTexCoord2f (0, 0); qglVertex3fv (coord[1]); qglTexCoord2f (1, 0); qglVertex3fv (coord[2]); qglTexCoord2f (1, 1); qglVertex3fv (coord[3]); } qglEnd (); } qglPopMatrix (); GL_BlendFunction (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_TexEnv( GL_MODULATE ); qglDepthMask (true); GLSTATE_DISABLE_BLEND qglColor4f (1,1,1,1); } */ //=================================================================== 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_ScaledPic (int x, int y, float scale, char *pic); void Draw_Pic (int x, int y, char *name); void Draw_Char (float x, float y, int num, int alpha); void Draw_ScaledChar (float x, float y, int num, float scale, int red, int green, int blue, int alpha, qboolean italic); 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_FadeBox (int x, int y, int w, int h, float r, float g, float b, float alpha); float CharMapScale (void); void SetParticlePicture (int num, char *name); int Mod_MarkFragments (const vec3_t origin, vec3_t axis[3], float radius, int maxPoints, vec3_t *points, vec2_t *tcoords, int maxFragments, markFragment_t *fragments); /* @@@@@@@@@@@@@@@@@@@@@ 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.SetParticlePicture = SetParticlePicture; re.DrawGetPicSize = Draw_GetPicSize; re.DrawScaledPic = Draw_ScaledPic; re.DrawPic = Draw_Pic; re.DrawStretchPic = Draw_StretchPic; re.DrawScaledChar = Draw_ScaledChar; re.DrawChar = Draw_Char; re.DrawTileClear = Draw_TileClear; re.DrawFill = Draw_Fill; re.DrawFadeBox= Draw_FadeBox; re.CharMap_Scale = CharMapScale; re.DrawStretchRaw = Draw_StretchRaw; re.MarkFragments = Mod_MarkFragments; 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