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;
109 rtexture_t *r_texture_blanknormalmap;
110 rtexture_t *r_texture_white;
111 rtexture_t *r_texture_black;
112 rtexture_t *r_texture_notexture;
114 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
117 for (i = 0;i < verts;i++)
128 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
131 for (i = 0;i < verts;i++)
143 float fog_density, fog_red, fog_green, fog_blue;
145 qboolean oldgl_fogenable;
146 void R_UpdateFog(void)
148 if (gamemode == GAME_NEHAHRA)
150 if (gl_fogenable.integer)
152 oldgl_fogenable = true;
153 fog_density = gl_fogdensity.value;
154 fog_red = gl_fogred.value;
155 fog_green = gl_foggreen.value;
156 fog_blue = gl_fogblue.value;
158 else if (oldgl_fogenable)
160 oldgl_fogenable = false;
169 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
170 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
171 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
176 fogdensity = -4000.0f / (fog_density * fog_density);
177 // fog color was already set
183 // FIXME: move this to client?
186 if (gamemode == GAME_NEHAHRA)
188 Cvar_Set("gl_fogenable", "0");
189 Cvar_Set("gl_fogdensity", "0.2");
190 Cvar_Set("gl_fogred", "0.3");
191 Cvar_Set("gl_foggreen", "0.3");
192 Cvar_Set("gl_fogblue", "0.3");
194 fog_density = fog_red = fog_green = fog_blue = 0.0f;
197 // FIXME: move this to client?
198 void FOG_registercvars(void)
200 if (gamemode == GAME_NEHAHRA)
202 Cvar_RegisterVariable (&gl_fogenable);
203 Cvar_RegisterVariable (&gl_fogdensity);
204 Cvar_RegisterVariable (&gl_fogred);
205 Cvar_RegisterVariable (&gl_foggreen);
206 Cvar_RegisterVariable (&gl_fogblue);
207 Cvar_RegisterVariable (&gl_fogstart);
208 Cvar_RegisterVariable (&gl_fogend);
212 void gl_main_start(void)
215 qbyte pix[16][16][4];
217 r_main_texturepool = R_AllocTexturePool();
218 r_bloom_texture_screen = NULL;
219 r_bloom_texture_bloom = NULL;
220 data[0] = 128; // normal X
221 data[1] = 128; // normal Y
222 data[2] = 255; // normal Z
223 data[3] = 128; // height
224 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
229 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
234 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
235 // this makes a light grey/dark grey checkerboard texture
236 for (y = 0;y < 16;y++)
238 for (x = 0;x < 16;x++)
240 if ((y < 8) ^ (x < 8))
256 r_texture_notexture = R_LoadTexture2D(mod_shared_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
259 void gl_main_shutdown(void)
261 R_FreeTexturePool(&r_main_texturepool);
262 r_bloom_texture_screen = NULL;
263 r_bloom_texture_bloom = NULL;
264 r_texture_blanknormalmap = NULL;
265 r_texture_white = NULL;
266 r_texture_black = NULL;
269 extern void CL_ParseEntityLump(char *entitystring);
270 void gl_main_newmap(void)
272 // FIXME: move this code to client
274 char *entities, entname[MAX_QPATH];
278 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
279 l = strlen(entname) - 4;
280 if (l >= 0 && !strcmp(entname + l, ".bsp"))
282 strcpy(entname + l, ".ent");
283 if ((entities = FS_LoadFile(entname, tempmempool, true)))
285 CL_ParseEntityLump(entities);
290 if (cl.worldmodel->brush.entities)
291 CL_ParseEntityLump(cl.worldmodel->brush.entities);
295 void GL_Main_Init(void)
297 Matrix4x4_CreateIdentity(&r_identitymatrix);
298 // FIXME: move this to client?
300 Cvar_RegisterVariable(&r_showtris);
301 Cvar_RegisterVariable(&r_drawentities);
302 Cvar_RegisterVariable(&r_drawviewmodel);
303 Cvar_RegisterVariable(&r_speeds);
304 Cvar_RegisterVariable(&r_fullbrights);
305 Cvar_RegisterVariable(&r_wateralpha);
306 Cvar_RegisterVariable(&r_dynamic);
307 Cvar_RegisterVariable(&r_fullbright);
308 Cvar_RegisterVariable(&r_textureunits);
309 Cvar_RegisterVariable(&r_lerpsprites);
310 Cvar_RegisterVariable(&r_lerpmodels);
311 Cvar_RegisterVariable(&r_waterscroll);
312 Cvar_RegisterVariable(&r_watershader);
313 Cvar_RegisterVariable(&r_drawcollisionbrushes);
314 Cvar_RegisterVariable(&r_bloom);
315 Cvar_RegisterVariable(&r_bloom_intensity);
316 Cvar_RegisterVariable(&r_bloom_blur);
317 Cvar_RegisterVariable(&r_bloom_resolution);
318 Cvar_RegisterVariable(&r_bloom_power);
319 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
320 Cvar_SetValue("r_fullbrights", 0);
321 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
324 static vec3_t r_farclip_origin;
325 static vec3_t r_farclip_direction;
326 static vec_t r_farclip_directiondist;
327 static vec_t r_farclip_meshfarclip;
328 static int r_farclip_directionbit0;
329 static int r_farclip_directionbit1;
330 static int r_farclip_directionbit2;
332 // enlarge farclip to accomodate box
333 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
336 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
337 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
338 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
339 if (r_farclip_meshfarclip < d)
340 r_farclip_meshfarclip = d;
343 // return farclip value
344 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
348 VectorCopy(origin, r_farclip_origin);
349 VectorCopy(direction, r_farclip_direction);
350 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
351 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
352 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
353 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
354 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
356 if (r_refdef.worldmodel)
357 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
358 for (i = 0;i < r_refdef.numentities;i++)
359 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
361 return r_farclip_meshfarclip - r_farclip_directiondist;
364 extern void R_Textures_Init(void);
365 extern void Mod_RenderInit(void);
366 extern void GL_Draw_Init(void);
367 extern void GL_Main_Init(void);
368 extern void R_Shadow_Init(void);
369 extern void GL_Models_Init(void);
370 extern void R_Sky_Init(void);
371 extern void GL_Surf_Init(void);
372 extern void R_Crosshairs_Init(void);
373 extern void R_Light_Init(void);
374 extern void R_Particles_Init(void);
375 extern void R_Explosion_Init(void);
376 extern void ui_init(void);
377 extern void gl_backend_init(void);
378 extern void Sbar_Init(void);
379 extern void R_LightningBeams_Init(void);
381 void Render_Init(void)
400 R_LightningBeams_Init();
408 extern char *ENGINE_EXTENSIONS;
411 VID_CheckExtensions();
413 // LordHavoc: report supported extensions
414 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
416 // clear to black (loading plaque will be seen over this)
417 qglClearColor(0,0,0,1);
418 qglClear(GL_COLOR_BUFFER_BIT);
421 int R_CullBox(const vec3_t mins, const vec3_t maxs)
425 for (i = 0;i < 4;i++)
432 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
436 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
440 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
444 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
448 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
452 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
456 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
460 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
468 //==================================================================================
470 static void R_MarkEntities (void)
473 entity_render_t *ent;
475 if (!r_drawentities.integer)
478 renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
479 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
481 // worldmodel can check visibility
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) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_worldleafvisible, ent->mins, ent->maxs)))
492 R_UpdateEntLights(ent);
493 ent->visframe = r_framecount;
499 // no worldmodel or it can't check visibility
500 for (i = 0;i < r_refdef.numentities;i++)
502 ent = r_refdef.entities[i];
503 Mod_CheckLoaded(ent->model);
504 // some of the renderer still relies on origin...
505 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
506 // some of the renderer still relies on scale...
507 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
508 if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
510 R_UpdateEntLights(ent);
511 ent->visframe = r_framecount;
517 // only used if skyrendermasked, and normally returns false
518 int R_DrawBrushModelsSky (void)
521 entity_render_t *ent;
523 if (!r_drawentities.integer)
527 for (i = 0;i < r_refdef.numentities;i++)
529 ent = r_refdef.entities[i];
530 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
532 ent->model->DrawSky(ent);
539 void R_DrawNoModel(entity_render_t *ent);
540 void R_DrawModels(void)
543 entity_render_t *ent;
545 if (!r_drawentities.integer)
548 for (i = 0;i < r_refdef.numentities;i++)
550 ent = r_refdef.entities[i];
551 if (ent->visframe == r_framecount)
553 if (ent->model && ent->model->Draw != NULL)
554 ent->model->Draw(ent);
561 static void R_SetFrustum(void)
563 // break apart the view matrix into vectors for various purposes
564 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
565 VectorNegate(r_viewleft, r_viewright);
567 // LordHavoc: note to all quake engine coders, the special case for 90
568 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
571 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
572 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
573 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
574 PlaneClassify(&frustum[0]);
576 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
577 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
578 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
579 PlaneClassify(&frustum[1]);
581 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
582 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
583 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
584 PlaneClassify(&frustum[2]);
586 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
587 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
588 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
589 PlaneClassify(&frustum[3]);
592 static void R_BlendView(void)
596 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
599 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
602 R_Mesh_Matrix(&r_identitymatrix);
603 // vertex coordinates for a quad that covers the screen exactly
604 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
605 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
606 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
607 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
608 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)
610 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
611 float xoffset, yoffset, r;
613 // set the (poorly named) screenwidth and screenheight variables to
614 // a power of 2 at least as large as the screen, these will define the
615 // size of the texture to allocate
616 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
617 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
618 // allocate textures as needed
619 if (!r_bloom_texture_screen)
620 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
621 if (!r_bloom_texture_bloom)
622 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
623 // set bloomwidth and bloomheight to the bloom resolution that will be
624 // used (often less than the screen resolution for faster rendering)
625 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
626 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
627 // set up a texcoord array for the full resolution screen image
628 // (we have to keep this around to copy back during final render)
629 varray_texcoord2f[0][0] = 0;
630 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
631 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
632 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
633 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
634 varray_texcoord2f[0][5] = 0;
635 varray_texcoord2f[0][6] = 0;
636 varray_texcoord2f[0][7] = 0;
637 // set up a texcoord array for the reduced resolution bloom image
638 // (which will be additive blended over the screen image)
639 varray_texcoord2f[1][0] = 0;
640 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
641 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
642 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
643 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
644 varray_texcoord2f[1][5] = 0;
645 varray_texcoord2f[1][6] = 0;
646 varray_texcoord2f[1][7] = 0;
647 memset(&m, 0, sizeof(m));
648 m.pointer_vertex = varray_vertex3f;
649 m.pointer_texcoord[0] = varray_texcoord2f[0];
650 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
652 // copy view into the full resolution screen image texture
654 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
656 c_bloomcopypixels += r_view_width * r_view_height;
657 // now scale it down to the bloom size and raise to a power of itself
658 // to darken it (this leaves the really bright stuff bright, and
659 // everything else becomes very dark)
660 // TODO: optimize with multitexture or GLSL
661 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
662 GL_BlendFunc(GL_ONE, GL_ZERO);
663 GL_Color(1, 1, 1, 1);
664 R_Mesh_Draw(0, 4, 2, polygonelements);
666 c_bloomdrawpixels += bloomwidth * bloomheight;
667 // render multiple times with a multiply blendfunc to raise to a power
668 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
669 for (x = 1;x < r_bloom_power.integer;x++)
671 R_Mesh_Draw(0, 4, 2, polygonelements);
673 c_bloomdrawpixels += bloomwidth * bloomheight;
675 // we now have a darkened bloom image in the framebuffer, copy it into
676 // the bloom image texture for more processing
677 memset(&m, 0, sizeof(m));
678 m.pointer_vertex = varray_vertex3f;
679 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
680 m.pointer_texcoord[0] = varray_texcoord2f[2];
683 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
685 c_bloomcopypixels += bloomwidth * bloomheight;
686 // blend on at multiple vertical offsets to achieve a vertical blur
687 // TODO: do offset blends using GLSL
688 range = r_bloom_blur.integer * bloomwidth / 320;
689 GL_BlendFunc(GL_ONE, GL_ZERO);
690 for (x = -range;x <= range;x++)
692 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
693 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
694 // compute a texcoord array with the specified x and y offset
695 varray_texcoord2f[2][0] = xoffset+0;
696 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
697 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
698 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
699 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
700 varray_texcoord2f[2][5] = yoffset+0;
701 varray_texcoord2f[2][6] = xoffset+0;
702 varray_texcoord2f[2][7] = yoffset+0;
703 // this r value looks like a 'dot' particle, fading sharply to
704 // black at the edges
705 // (probably not realistic but looks good enough)
706 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
709 GL_Color(r, r, r, 1);
710 R_Mesh_Draw(0, 4, 2, polygonelements);
712 c_bloomdrawpixels += bloomwidth * bloomheight;
713 GL_BlendFunc(GL_ONE, GL_ONE);
715 // copy the vertically blurred bloom view to a texture
717 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
719 c_bloomcopypixels += bloomwidth * bloomheight;
720 // blend the vertically blurred image at multiple offsets horizontally
721 // to finish the blur effect
722 // TODO: do offset blends using GLSL
723 range = r_bloom_blur.integer * bloomwidth / 320;
724 GL_BlendFunc(GL_ONE, GL_ZERO);
725 for (x = -range;x <= range;x++)
727 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
728 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
729 // compute a texcoord array with the specified x and y offset
730 varray_texcoord2f[2][0] = xoffset+0;
731 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
732 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
733 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
734 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
735 varray_texcoord2f[2][5] = yoffset+0;
736 varray_texcoord2f[2][6] = xoffset+0;
737 varray_texcoord2f[2][7] = yoffset+0;
738 // this r value looks like a 'dot' particle, fading sharply to
739 // black at the edges
740 // (probably not realistic but looks good enough)
741 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
744 GL_Color(r, r, r, 1);
745 R_Mesh_Draw(0, 4, 2, polygonelements);
747 c_bloomdrawpixels += bloomwidth * bloomheight;
748 GL_BlendFunc(GL_ONE, GL_ONE);
750 // copy the blurred bloom view to a texture
752 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
754 c_bloomcopypixels += bloomwidth * bloomheight;
755 // go back to full view area
756 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
757 // put the original screen image back in place and blend the bloom
759 memset(&m, 0, sizeof(m));
760 m.pointer_vertex = varray_vertex3f;
761 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
762 m.pointer_texcoord[0] = varray_texcoord2f[0];
764 dobloomblend = false;
766 // do both in one pass if possible
767 if (r_textureunits.integer >= 2 && gl_combine.integer)
769 dobloomblend = false;
770 m.texcombinergb[1] = GL_ADD;
771 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
772 m.pointer_texcoord[1] = varray_texcoord2f[1];
778 GL_BlendFunc(GL_ONE, GL_ZERO);
780 R_Mesh_Draw(0, 4, 2, polygonelements);
782 c_bloomdrawpixels += r_view_width * r_view_height;
783 // now blend on the bloom texture if multipass
786 memset(&m, 0, sizeof(m));
787 m.pointer_vertex = varray_vertex3f;
788 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
789 m.pointer_texcoord[0] = varray_texcoord2f[1];
791 GL_BlendFunc(GL_ONE, GL_ONE);
793 R_Mesh_Draw(0, 4, 2, polygonelements);
795 c_bloomdrawpixels += r_view_width * r_view_height;
798 if (r_refdef.viewblend[3] >= 0.01f)
800 // apply a color tint to the whole view
801 memset(&m, 0, sizeof(m));
802 m.pointer_vertex = varray_vertex3f;
804 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
805 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
806 R_Mesh_Draw(0, 4, 2, polygonelements);
810 void R_RenderScene(void);
817 void R_RenderView(void)
819 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
820 return; //Host_Error ("R_RenderView: NULL worldmodel");
822 r_view_width = bound(0, r_refdef.width, vid.realwidth);
823 r_view_height = bound(0, r_refdef.height, vid.realheight);
825 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
826 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
828 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
829 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
830 r_view_matrix = r_refdef.viewentitymatrix;
831 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
832 r_rtworld = r_shadow_realtime_world.integer;
833 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
834 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
835 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
836 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
838 // GL is weird because it's bottom to top, r_view_y is top to bottom
839 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
840 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
841 GL_ScissorTest(true);
847 R_TimeReport("setup");
849 qglDepthFunc(GL_LEQUAL);
850 qglPolygonOffset(0, 0);
851 qglEnable(GL_POLYGON_OFFSET_FILL);
855 qglPolygonOffset(0, 0);
856 qglDisable(GL_POLYGON_OFFSET_FILL);
859 R_TimeReport("blendview");
861 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
862 GL_ScissorTest(false);
865 extern void R_DrawLightningBeams (void);
866 void R_RenderScene(void)
868 // don't let sound skip if going slow
869 if (r_refdef.extraupdate)
874 R_MeshQueue_BeginScene();
876 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
880 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
881 if (r_rtworldshadows || r_rtdlightshadows)
882 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
884 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
886 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
891 R_TimeReport("worldvis");
894 R_TimeReport("markentity");
896 R_Shadow_UpdateWorldLightSelection();
898 // don't let sound skip if going slow
899 if (r_refdef.extraupdate)
902 GL_ShowTrisColor(0.025, 0.025, 0, 1);
903 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
905 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
906 R_TimeReport("worldsky");
909 if (R_DrawBrushModelsSky())
910 R_TimeReport("bmodelsky");
912 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
913 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
915 r_refdef.worldmodel->Draw(r_refdef.worldentity);
916 R_TimeReport("world");
919 // don't let sound skip if going slow
920 if (r_refdef.extraupdate)
923 GL_ShowTrisColor(0, 0.015, 0, 1);
926 R_TimeReport("models");
928 // don't let sound skip if going slow
929 if (r_refdef.extraupdate)
932 GL_ShowTrisColor(0, 0, 0.033, 1);
933 R_ShadowVolumeLighting(false);
934 R_TimeReport("rtlights");
936 // don't let sound skip if going slow
937 if (r_refdef.extraupdate)
940 GL_ShowTrisColor(0.1, 0, 0, 1);
942 R_DrawLightningBeams();
943 R_TimeReport("lightning");
946 R_TimeReport("particles");
949 R_TimeReport("explosions");
951 R_MeshQueue_RenderTransparent();
952 R_TimeReport("drawtrans");
955 R_TimeReport("coronas");
957 R_DrawWorldCrosshair();
958 R_TimeReport("crosshair");
960 R_MeshQueue_Render();
961 R_MeshQueue_EndScene();
963 if (r_shadow_visiblevolumes.integer && !r_showtrispass)
965 R_ShadowVolumeLighting(true);
966 R_TimeReport("shadowvolume");
969 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
971 // don't let sound skip if going slow
972 if (r_refdef.extraupdate)
977 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
980 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
982 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
985 R_Mesh_Matrix(&r_identitymatrix);
987 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
988 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
989 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
990 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
991 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
992 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
993 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
994 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
995 R_FillColors(color, 8, cr, cg, cb, ca);
998 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1000 VectorSubtract(v, r_vieworigin, diff);
1001 f2 = exp(fogdensity/DotProduct(diff, diff));
1003 c[0] = c[0] * f1 + fogcolor[0] * f2;
1004 c[1] = c[1] * f1 + fogcolor[1] * f2;
1005 c[2] = c[2] * f1 + fogcolor[2] * f2;
1008 memset(&m, 0, sizeof(m));
1009 m.pointer_vertex = vertex3f;
1010 m.pointer_color = color;
1016 int nomodelelements[24] =
1028 float nomodelvertex3f[6*3] =
1038 float nomodelcolor4f[6*4] =
1040 0.0f, 0.0f, 0.5f, 1.0f,
1041 0.0f, 0.0f, 0.5f, 1.0f,
1042 0.0f, 0.5f, 0.0f, 1.0f,
1043 0.0f, 0.5f, 0.0f, 1.0f,
1044 0.5f, 0.0f, 0.0f, 1.0f,
1045 0.5f, 0.0f, 0.0f, 1.0f
1048 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1050 const entity_render_t *ent = calldata1;
1052 float f1, f2, *c, diff[3];
1055 R_Mesh_Matrix(&ent->matrix);
1057 memset(&m, 0, sizeof(m));
1058 m.pointer_vertex = nomodelvertex3f;
1060 if (ent->flags & EF_ADDITIVE)
1062 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1063 GL_DepthMask(false);
1065 else if (ent->alpha < 1)
1067 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1068 GL_DepthMask(false);
1072 GL_BlendFunc(GL_ONE, GL_ZERO);
1075 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1078 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1079 m.pointer_color = color4f;
1080 VectorSubtract(ent->origin, r_vieworigin, diff);
1081 f2 = exp(fogdensity/DotProduct(diff, diff));
1083 for (i = 0, c = color4f;i < 6;i++, c += 4)
1085 c[0] = (c[0] * f1 + fogcolor[0] * f2);
1086 c[1] = (c[1] * f1 + fogcolor[1] * f2);
1087 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1091 else if (ent->alpha != 1)
1093 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1094 m.pointer_color = color4f;
1095 for (i = 0, c = color4f;i < 6;i++, c += 4)
1099 m.pointer_color = nomodelcolor4f;
1101 R_Mesh_Draw(0, 6, 8, nomodelelements);
1104 void R_DrawNoModel(entity_render_t *ent)
1106 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1107 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1109 // R_DrawNoModelCallback(ent, 0);
1112 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1114 vec3_t right1, right2, diff, normal;
1116 VectorSubtract (org2, org1, normal);
1118 // calculate 'right' vector for start
1119 VectorSubtract (r_vieworigin, org1, diff);
1120 CrossProduct (normal, diff, right1);
1121 VectorNormalize (right1);
1123 // calculate 'right' vector for end
1124 VectorSubtract (r_vieworigin, org2, diff);
1125 CrossProduct (normal, diff, right2);
1126 VectorNormalize (right2);
1128 vert[ 0] = org1[0] + width * right1[0];
1129 vert[ 1] = org1[1] + width * right1[1];
1130 vert[ 2] = org1[2] + width * right1[2];
1131 vert[ 3] = org1[0] - width * right1[0];
1132 vert[ 4] = org1[1] - width * right1[1];
1133 vert[ 5] = org1[2] - width * right1[2];
1134 vert[ 6] = org2[0] - width * right2[0];
1135 vert[ 7] = org2[1] - width * right2[1];
1136 vert[ 8] = org2[2] - width * right2[2];
1137 vert[ 9] = org2[0] + width * right2[0];
1138 vert[10] = org2[1] + width * right2[1];
1139 vert[11] = org2[2] + width * right2[2];
1142 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1144 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)
1151 VectorSubtract(origin, r_vieworigin, diff);
1152 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1155 R_Mesh_Matrix(&r_identitymatrix);
1156 GL_BlendFunc(blendfunc1, blendfunc2);
1157 GL_DepthMask(false);
1158 GL_DepthTest(!depthdisable);
1160 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1161 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1162 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1163 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1164 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1165 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1166 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1167 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1168 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1169 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1170 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1171 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1173 memset(&m, 0, sizeof(m));
1174 m.tex[0] = R_GetTexture(texture);
1175 m.pointer_texcoord[0] = spritetexcoord2f;
1176 m.pointer_vertex = varray_vertex3f;
1178 GL_Color(cr, cg, cb, ca);
1179 R_Mesh_Draw(0, 4, 2, polygonelements);