2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 // used for dlight push checking and other things
30 matrix4x4_t r_identitymatrix;
32 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights, c_meshs, c_meshelements, c_rt_lights, c_rt_clears, c_rt_scissored, c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris, c_rtcached_shadowmeshes, c_rtcached_shadowtris, c_bloom, c_bloomcopies, c_bloomcopypixels, c_bloomdraws, c_bloomdrawpixels;
34 // true during envmap command capture
37 // maximum visible distance (recalculated from world box each frame)
39 // brightness of world lightmaps and related lighting
40 // (often reduced when world rtlights are enabled)
41 float r_lightmapintensity;
42 // whether to draw world lights realtime, dlights realtime, and their shadows
44 qboolean r_rtworldshadows;
46 qboolean r_rtdlightshadows;
49 // forces all rendering to draw triangle outlines
66 matrix4x4_t r_view_matrix;
73 // 8.8 fraction of base light value
74 unsigned short d_lightstylevalue[256];
76 cvar_t r_showtris = {0, "r_showtris", "0"};
77 cvar_t r_drawentities = {0, "r_drawentities","1"};
78 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
79 cvar_t r_speeds = {0, "r_speeds","0"};
80 cvar_t r_fullbright = {0, "r_fullbright","0"};
81 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
82 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
83 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
84 cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
86 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
87 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
88 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
89 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
90 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
91 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
92 cvar_t gl_fogend = {0, "gl_fogend","0"};
94 cvar_t r_textureunits = {0, "r_textureunits", "32"};
96 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
97 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
98 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
99 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
101 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"};
102 cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"};
103 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
104 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
105 cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
106 rtexturepool_t *r_main_texturepool;
107 rtexture_t *r_bloom_texture_screen;
108 rtexture_t *r_bloom_texture_bloom;
110 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
113 for (i = 0;i < verts;i++)
124 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
127 for (i = 0;i < verts;i++)
139 float fog_density, fog_red, fog_green, fog_blue;
141 qboolean oldgl_fogenable;
142 void R_UpdateFog(void)
144 if (gamemode == GAME_NEHAHRA)
146 if (gl_fogenable.integer)
148 oldgl_fogenable = true;
149 fog_density = gl_fogdensity.value;
150 fog_red = gl_fogred.value;
151 fog_green = gl_foggreen.value;
152 fog_blue = gl_fogblue.value;
154 else if (oldgl_fogenable)
156 oldgl_fogenable = false;
165 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
166 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
167 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
172 fogdensity = -4000.0f / (fog_density * fog_density);
173 // fog color was already set
179 // FIXME: move this to client?
182 if (gamemode == GAME_NEHAHRA)
184 Cvar_Set("gl_fogenable", "0");
185 Cvar_Set("gl_fogdensity", "0.2");
186 Cvar_Set("gl_fogred", "0.3");
187 Cvar_Set("gl_foggreen", "0.3");
188 Cvar_Set("gl_fogblue", "0.3");
190 fog_density = fog_red = fog_green = fog_blue = 0.0f;
193 // FIXME: move this to client?
194 void FOG_registercvars(void)
196 if (gamemode == GAME_NEHAHRA)
198 Cvar_RegisterVariable (&gl_fogenable);
199 Cvar_RegisterVariable (&gl_fogdensity);
200 Cvar_RegisterVariable (&gl_fogred);
201 Cvar_RegisterVariable (&gl_foggreen);
202 Cvar_RegisterVariable (&gl_fogblue);
203 Cvar_RegisterVariable (&gl_fogstart);
204 Cvar_RegisterVariable (&gl_fogend);
208 void gl_main_start(void)
210 r_main_texturepool = R_AllocTexturePool();
211 r_bloom_texture_screen = NULL;
212 r_bloom_texture_bloom = NULL;
215 void gl_main_shutdown(void)
217 R_FreeTexturePool(&r_main_texturepool);
218 r_bloom_texture_screen = NULL;
219 r_bloom_texture_bloom = NULL;
222 extern void CL_ParseEntityLump(char *entitystring);
223 void gl_main_newmap(void)
225 // FIXME: move this code to client
227 char *entities, entname[MAX_QPATH];
231 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
232 l = strlen(entname) - 4;
233 if (l >= 0 && !strcmp(entname + l, ".bsp"))
235 strcpy(entname + l, ".ent");
236 if ((entities = FS_LoadFile(entname, tempmempool, true)))
238 CL_ParseEntityLump(entities);
243 if (cl.worldmodel->brush.entities)
244 CL_ParseEntityLump(cl.worldmodel->brush.entities);
248 void GL_Main_Init(void)
250 Matrix4x4_CreateIdentity(&r_identitymatrix);
251 // FIXME: move this to client?
253 Cvar_RegisterVariable(&r_showtris);
254 Cvar_RegisterVariable(&r_drawentities);
255 Cvar_RegisterVariable(&r_drawviewmodel);
256 Cvar_RegisterVariable(&r_speeds);
257 Cvar_RegisterVariable(&r_fullbrights);
258 Cvar_RegisterVariable(&r_wateralpha);
259 Cvar_RegisterVariable(&r_dynamic);
260 Cvar_RegisterVariable(&r_fullbright);
261 Cvar_RegisterVariable(&r_textureunits);
262 Cvar_RegisterVariable(&r_lerpsprites);
263 Cvar_RegisterVariable(&r_lerpmodels);
264 Cvar_RegisterVariable(&r_waterscroll);
265 Cvar_RegisterVariable(&r_watershader);
266 Cvar_RegisterVariable(&r_drawcollisionbrushes);
267 Cvar_RegisterVariable(&r_bloom);
268 Cvar_RegisterVariable(&r_bloom_intensity);
269 Cvar_RegisterVariable(&r_bloom_blur);
270 Cvar_RegisterVariable(&r_bloom_resolution);
271 Cvar_RegisterVariable(&r_bloom_power);
272 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
273 Cvar_SetValue("r_fullbrights", 0);
274 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
277 static vec3_t r_farclip_origin;
278 static vec3_t r_farclip_direction;
279 static vec_t r_farclip_directiondist;
280 static vec_t r_farclip_meshfarclip;
281 static int r_farclip_directionbit0;
282 static int r_farclip_directionbit1;
283 static int r_farclip_directionbit2;
285 // enlarge farclip to accomodate box
286 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
289 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
290 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
291 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
292 if (r_farclip_meshfarclip < d)
293 r_farclip_meshfarclip = d;
296 // return farclip value
297 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
301 VectorCopy(origin, r_farclip_origin);
302 VectorCopy(direction, r_farclip_direction);
303 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
304 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
305 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
306 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
307 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
309 if (r_refdef.worldmodel)
310 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
311 for (i = 0;i < r_refdef.numentities;i++)
312 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
314 return r_farclip_meshfarclip - r_farclip_directiondist;
317 extern void R_Textures_Init(void);
318 extern void Mod_RenderInit(void);
319 extern void GL_Draw_Init(void);
320 extern void GL_Main_Init(void);
321 extern void R_Shadow_Init(void);
322 extern void GL_Models_Init(void);
323 extern void R_Sky_Init(void);
324 extern void GL_Surf_Init(void);
325 extern void R_Crosshairs_Init(void);
326 extern void R_Light_Init(void);
327 extern void R_Particles_Init(void);
328 extern void R_Explosion_Init(void);
329 extern void ui_init(void);
330 extern void gl_backend_init(void);
331 extern void Sbar_Init(void);
332 extern void R_LightningBeams_Init(void);
334 void Render_Init(void)
353 R_LightningBeams_Init();
361 extern char *ENGINE_EXTENSIONS;
364 VID_CheckExtensions();
366 // LordHavoc: report supported extensions
367 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
369 // clear to black (loading plaque will be seen over this)
370 qglClearColor(0,0,0,1);
371 qglClear(GL_COLOR_BUFFER_BIT);
374 int R_CullBox(const vec3_t mins, const vec3_t maxs)
378 for (i = 0;i < 4;i++)
385 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
389 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
393 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
397 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
401 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
405 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
409 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
413 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
421 int R_BoxVisible(const vec3_t mins, const vec3_t maxs)
423 int side, nodestackindex = 0;
424 mnode_t *node, *nodestack[1024];
425 if (R_CullBox(mins, maxs))
427 if (!r_refdef.worldmodel || !r_refdef.worldmodel->brush.data_nodes)
429 node = r_refdef.worldmodel->brush.data_nodes;
434 // node - recurse down the BSP tree
435 side = BoxOnPlaneSide(mins, maxs, node->plane) - 1;
438 // box is on one side of plane, take that path
439 node = node->children[side];
443 // box crosses plane, take one path and remember the other
444 if (nodestackindex < 1024)
445 nodestack[nodestackindex++] = node->children[0];
446 node = node->children[1];
451 // leaf - check leaf visibility
452 if (r_worldleafvisible[(mleaf_t *)node - r_refdef.worldmodel->brush.data_leafs])
454 // it is visible, return immediately with the news
459 // nothing to see here, try another path we didn't take earlier
460 if (nodestackindex == 0)
462 node = nodestack[--nodestackindex];
471 //==================================================================================
473 static void R_MarkEntities (void)
476 entity_render_t *ent;
478 if (!r_drawentities.integer)
481 renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
482 for (i = 0;i < r_refdef.numentities;i++)
484 ent = r_refdef.entities[i];
485 Mod_CheckLoaded(ent->model);
486 // some of the renderer still relies on origin...
487 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
488 // some of the renderer still relies on scale...
489 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
490 if (!(ent->flags & renderimask) && ((ent->effects & EF_NODEPTHTEST) ? R_CullBox(ent->mins, ent->maxs) : R_BoxVisible(ent->mins, ent->maxs)))
492 R_UpdateEntLights(ent);
493 ent->visframe = r_framecount;
498 // only used if skyrendermasked, and normally returns false
499 int R_DrawBrushModelsSky (void)
502 entity_render_t *ent;
504 if (!r_drawentities.integer)
508 for (i = 0;i < r_refdef.numentities;i++)
510 ent = r_refdef.entities[i];
511 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
513 ent->model->DrawSky(ent);
520 void R_DrawNoModel(entity_render_t *ent);
521 void R_DrawModels(void)
524 entity_render_t *ent;
526 if (!r_drawentities.integer)
529 for (i = 0;i < r_refdef.numentities;i++)
531 ent = r_refdef.entities[i];
532 if (ent->visframe == r_framecount)
534 if (ent->model && ent->model->Draw != NULL)
535 ent->model->Draw(ent);
542 static void R_SetFrustum(void)
544 // break apart the view matrix into vectors for various purposes
545 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
546 VectorNegate(r_viewleft, r_viewright);
548 // LordHavoc: note to all quake engine coders, the special case for 90
549 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
552 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
553 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
554 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
555 PlaneClassify(&frustum[0]);
557 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
558 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
559 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
560 PlaneClassify(&frustum[1]);
562 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
563 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
564 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
565 PlaneClassify(&frustum[2]);
567 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
568 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
569 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
570 PlaneClassify(&frustum[3]);
573 static void R_BlendView(void)
577 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
580 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
583 R_Mesh_Matrix(&r_identitymatrix);
584 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
585 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
586 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
587 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
588 if (r_bloom.integer && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512)
590 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
591 float xoffset, yoffset, r;
593 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
594 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
595 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
596 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
597 varray_texcoord2f[0][0] = 0;
598 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
599 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
600 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
601 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
602 varray_texcoord2f[0][5] = 0;
603 varray_texcoord2f[0][6] = 0;
604 varray_texcoord2f[0][7] = 0;
605 varray_texcoord2f[1][0] = 0;
606 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
607 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
608 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
609 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
610 varray_texcoord2f[1][5] = 0;
611 varray_texcoord2f[1][6] = 0;
612 varray_texcoord2f[1][7] = 0;
613 if (!r_bloom_texture_screen)
614 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
615 if (!r_bloom_texture_bloom)
616 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
617 memset(&m, 0, sizeof(m));
618 m.pointer_vertex = varray_vertex3f;
619 m.pointer_texcoord[0] = varray_texcoord2f[0];
620 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
622 // copy view to a texture
624 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
626 c_bloomcopypixels += r_view_width * r_view_height;
627 // now scale it down to the bloom size and raise to a power of itself
628 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
629 // TODO: optimize with multitexture or GLSL
630 GL_BlendFunc(GL_ONE, GL_ZERO);
631 GL_Color(1, 1, 1, 1);
632 R_Mesh_Draw(4, 2, polygonelements);
634 c_bloomdrawpixels += bloomwidth * bloomheight;
635 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
636 for (x = 1;x < r_bloom_power.integer;x++)
638 R_Mesh_Draw(4, 2, polygonelements);
640 c_bloomdrawpixels += bloomwidth * bloomheight;
642 // copy the bloom view to a texture
643 memset(&m, 0, sizeof(m));
644 m.pointer_vertex = varray_vertex3f;
645 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
646 m.pointer_texcoord[0] = varray_texcoord2f[2];
649 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
651 c_bloomcopypixels += bloomwidth * bloomheight;
652 // blend on at multiple offsets vertically
653 // TODO: do offset blends using GLSL
654 range = r_bloom_blur.integer * bloomwidth / 320;
655 GL_BlendFunc(GL_ONE, GL_ZERO);
656 for (x = -range;x <= range;x++)
658 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
659 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
660 varray_texcoord2f[2][0] = xoffset+0;
661 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
662 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
663 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
664 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
665 varray_texcoord2f[2][5] = yoffset+0;
666 varray_texcoord2f[2][6] = xoffset+0;
667 varray_texcoord2f[2][7] = yoffset+0;
668 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
671 GL_Color(r, r, r, 1);
672 R_Mesh_Draw(4, 2, polygonelements);
674 c_bloomdrawpixels += bloomwidth * bloomheight;
675 GL_BlendFunc(GL_ONE, GL_ONE);
677 // copy the blurred bloom view to a texture
679 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
681 c_bloomcopypixels += bloomwidth * bloomheight;
682 // blend on at multiple offsets horizontally
683 // TODO: do offset blends using GLSL
684 range = r_bloom_blur.integer * bloomwidth / 320;
685 GL_BlendFunc(GL_ONE, GL_ZERO);
686 for (x = -range;x <= range;x++)
688 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
689 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
690 varray_texcoord2f[2][0] = xoffset+0;
691 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
692 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
693 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
694 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
695 varray_texcoord2f[2][5] = yoffset+0;
696 varray_texcoord2f[2][6] = xoffset+0;
697 varray_texcoord2f[2][7] = yoffset+0;
698 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
701 GL_Color(r, r, r, 1);
702 R_Mesh_Draw(4, 2, polygonelements);
704 c_bloomdrawpixels += bloomwidth * bloomheight;
705 GL_BlendFunc(GL_ONE, GL_ONE);
707 // copy the blurred bloom view to a texture
709 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
711 c_bloomcopypixels += bloomwidth * bloomheight;
712 // go back to full view area
713 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
714 // put the original view back in place
715 memset(&m, 0, sizeof(m));
716 m.pointer_vertex = varray_vertex3f;
717 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
718 m.pointer_texcoord[0] = varray_texcoord2f[0];
720 dobloomblend = false;
722 // do both in one pass if possible
723 if (r_textureunits.integer >= 2 && gl_combine.integer)
725 dobloomblend = false;
726 m.texcombinergb[1] = GL_ADD;
727 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
728 m.pointer_texcoord[1] = varray_texcoord2f[1];
734 GL_BlendFunc(GL_ONE, GL_ZERO);
736 R_Mesh_Draw(4, 2, polygonelements);
738 c_bloomdrawpixels += r_view_width * r_view_height;
739 // now blend on the bloom texture if multipass
742 memset(&m, 0, sizeof(m));
743 m.pointer_vertex = varray_vertex3f;
744 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
745 m.pointer_texcoord[0] = varray_texcoord2f[1];
747 GL_BlendFunc(GL_ONE, GL_ONE);
749 R_Mesh_Draw(4, 2, polygonelements);
751 c_bloomdrawpixels += r_view_width * r_view_height;
754 if (r_refdef.viewblend[3] >= 0.01f)
756 // apply a color tint to the whole view
757 memset(&m, 0, sizeof(m));
758 m.pointer_vertex = varray_vertex3f;
760 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
761 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
762 R_Mesh_Draw(4, 2, polygonelements);
766 void R_RenderScene(void);
773 void R_RenderView(void)
775 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
776 return; //Host_Error ("R_RenderView: NULL worldmodel");
778 r_view_width = bound(0, r_refdef.width, vid.realwidth);
779 r_view_height = bound(0, r_refdef.height, vid.realheight);
781 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
782 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
784 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
785 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
786 r_view_matrix = r_refdef.viewentitymatrix;
787 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
788 r_rtworld = r_shadow_realtime_world.integer;
789 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
790 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
791 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
792 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
794 // GL is weird because it's bottom to top, r_view_y is top to bottom
795 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
796 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
797 GL_ScissorTest(true);
803 R_TimeReport("setup");
805 qglDepthFunc(GL_LEQUAL);
806 qglPolygonOffset(0, 0);
807 qglEnable(GL_POLYGON_OFFSET_FILL);
811 qglPolygonOffset(0, 0);
812 qglDisable(GL_POLYGON_OFFSET_FILL);
815 R_TimeReport("blendview");
817 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
818 GL_ScissorTest(false);
821 extern void R_DrawLightningBeams (void);
822 void R_RenderScene(void)
824 // don't let sound skip if going slow
825 if (r_refdef.extraupdate)
830 R_MeshQueue_BeginScene();
832 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
836 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
837 if (r_rtworldshadows || r_rtdlightshadows)
838 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
840 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
842 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
847 R_TimeReport("worldvis");
850 R_TimeReport("markentity");
852 R_Shadow_UpdateWorldLightSelection();
854 // don't let sound skip if going slow
855 if (r_refdef.extraupdate)
858 GL_ShowTrisColor(0.025, 0.025, 0, 1);
859 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
861 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
862 R_TimeReport("worldsky");
865 if (R_DrawBrushModelsSky())
866 R_TimeReport("bmodelsky");
868 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
869 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
871 r_refdef.worldmodel->Draw(r_refdef.worldentity);
872 R_TimeReport("world");
875 // don't let sound skip if going slow
876 if (r_refdef.extraupdate)
879 GL_ShowTrisColor(0, 0.015, 0, 1);
882 R_TimeReport("models");
884 // don't let sound skip if going slow
885 if (r_refdef.extraupdate)
888 GL_ShowTrisColor(0, 0, 0.033, 1);
889 R_ShadowVolumeLighting(false);
890 R_TimeReport("rtlights");
892 // don't let sound skip if going slow
893 if (r_refdef.extraupdate)
896 GL_ShowTrisColor(0.1, 0, 0, 1);
898 R_DrawLightningBeams();
899 R_TimeReport("lightning");
902 R_TimeReport("particles");
905 R_TimeReport("explosions");
907 R_MeshQueue_RenderTransparent();
908 R_TimeReport("drawtrans");
911 R_TimeReport("coronas");
913 R_DrawWorldCrosshair();
914 R_TimeReport("crosshair");
916 R_MeshQueue_Render();
917 R_MeshQueue_EndScene();
919 if (r_shadow_visiblevolumes.integer && !r_showtrispass)
921 R_ShadowVolumeLighting(true);
922 R_TimeReport("shadowvolume");
925 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
927 // don't let sound skip if going slow
928 if (r_refdef.extraupdate)
933 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
936 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
938 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
941 R_Mesh_Matrix(&r_identitymatrix);
943 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
944 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
945 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
946 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
947 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
948 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
949 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
950 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
951 R_FillColors(color, 8, cr, cg, cb, ca);
954 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
956 VectorSubtract(v, r_vieworigin, diff);
957 f2 = exp(fogdensity/DotProduct(diff, diff));
959 c[0] = c[0] * f1 + fogcolor[0] * f2;
960 c[1] = c[1] * f1 + fogcolor[1] * f2;
961 c[2] = c[2] * f1 + fogcolor[2] * f2;
964 memset(&m, 0, sizeof(m));
965 m.pointer_vertex = vertex3f;
966 m.pointer_color = color;
972 int nomodelelements[24] =
984 float nomodelvertex3f[6*3] =
994 float nomodelcolor4f[6*4] =
996 0.0f, 0.0f, 0.5f, 1.0f,
997 0.0f, 0.0f, 0.5f, 1.0f,
998 0.0f, 0.5f, 0.0f, 1.0f,
999 0.0f, 0.5f, 0.0f, 1.0f,
1000 0.5f, 0.0f, 0.0f, 1.0f,
1001 0.5f, 0.0f, 0.0f, 1.0f
1004 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1006 const entity_render_t *ent = calldata1;
1008 float f1, f2, *c, diff[3];
1011 R_Mesh_Matrix(&ent->matrix);
1013 memset(&m, 0, sizeof(m));
1014 m.pointer_vertex = nomodelvertex3f;
1016 if (ent->flags & EF_ADDITIVE)
1018 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1019 GL_DepthMask(false);
1021 else if (ent->alpha < 1)
1023 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1024 GL_DepthMask(false);
1028 GL_BlendFunc(GL_ONE, GL_ZERO);
1031 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1034 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1035 m.pointer_color = color4f;
1036 VectorSubtract(ent->origin, r_vieworigin, diff);
1037 f2 = exp(fogdensity/DotProduct(diff, diff));
1039 for (i = 0, c = color4f;i < 6;i++, c += 4)
1041 c[0] = (c[0] * f1 + fogcolor[0] * f2);
1042 c[1] = (c[1] * f1 + fogcolor[1] * f2);
1043 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1047 else if (ent->alpha != 1)
1049 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1050 m.pointer_color = color4f;
1051 for (i = 0, c = color4f;i < 6;i++, c += 4)
1055 m.pointer_color = nomodelcolor4f;
1057 R_Mesh_Draw(6, 8, nomodelelements);
1060 void R_DrawNoModel(entity_render_t *ent)
1062 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1063 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1065 // R_DrawNoModelCallback(ent, 0);
1068 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1070 vec3_t right1, right2, diff, normal;
1072 VectorSubtract (org2, org1, normal);
1074 // calculate 'right' vector for start
1075 VectorSubtract (r_vieworigin, org1, diff);
1076 CrossProduct (normal, diff, right1);
1077 VectorNormalize (right1);
1079 // calculate 'right' vector for end
1080 VectorSubtract (r_vieworigin, org2, diff);
1081 CrossProduct (normal, diff, right2);
1082 VectorNormalize (right2);
1084 vert[ 0] = org1[0] + width * right1[0];
1085 vert[ 1] = org1[1] + width * right1[1];
1086 vert[ 2] = org1[2] + width * right1[2];
1087 vert[ 3] = org1[0] - width * right1[0];
1088 vert[ 4] = org1[1] - width * right1[1];
1089 vert[ 5] = org1[2] - width * right1[2];
1090 vert[ 6] = org2[0] - width * right2[0];
1091 vert[ 7] = org2[1] - width * right2[1];
1092 vert[ 8] = org2[2] - width * right2[2];
1093 vert[ 9] = org2[0] + width * right2[0];
1094 vert[10] = org2[1] + width * right2[1];
1095 vert[11] = org2[2] + width * right2[2];
1098 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1100 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depthdisable, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
1107 VectorSubtract(origin, r_vieworigin, diff);
1108 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1111 R_Mesh_Matrix(&r_identitymatrix);
1112 GL_BlendFunc(blendfunc1, blendfunc2);
1113 GL_DepthMask(false);
1114 GL_DepthTest(!depthdisable);
1116 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1117 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1118 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1119 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1120 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1121 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1122 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1123 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1124 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1125 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1126 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1127 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1129 memset(&m, 0, sizeof(m));
1130 m.tex[0] = R_GetTexture(texture);
1131 m.pointer_texcoord[0] = spritetexcoord2f;
1132 m.pointer_vertex = varray_vertex3f;
1134 GL_Color(cr, cg, cb, ca);
1135 R_Mesh_Draw(4, 2, polygonelements);