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 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
604 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
605 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
606 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
607 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)
609 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
610 float xoffset, yoffset, r;
612 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
613 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
614 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
615 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
616 varray_texcoord2f[0][0] = 0;
617 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
618 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
619 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
620 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
621 varray_texcoord2f[0][5] = 0;
622 varray_texcoord2f[0][6] = 0;
623 varray_texcoord2f[0][7] = 0;
624 varray_texcoord2f[1][0] = 0;
625 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
626 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
627 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
628 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
629 varray_texcoord2f[1][5] = 0;
630 varray_texcoord2f[1][6] = 0;
631 varray_texcoord2f[1][7] = 0;
632 if (!r_bloom_texture_screen)
633 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
634 if (!r_bloom_texture_bloom)
635 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
636 memset(&m, 0, sizeof(m));
637 m.pointer_vertex = varray_vertex3f;
638 m.pointer_texcoord[0] = varray_texcoord2f[0];
639 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
641 // copy view to a texture
643 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
645 c_bloomcopypixels += r_view_width * r_view_height;
646 // now scale it down to the bloom size and raise to a power of itself
647 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
648 // TODO: optimize with multitexture or GLSL
649 GL_BlendFunc(GL_ONE, GL_ZERO);
650 GL_Color(1, 1, 1, 1);
651 R_Mesh_Draw(4, 2, polygonelements);
653 c_bloomdrawpixels += bloomwidth * bloomheight;
654 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
655 for (x = 1;x < r_bloom_power.integer;x++)
657 R_Mesh_Draw(4, 2, polygonelements);
659 c_bloomdrawpixels += bloomwidth * bloomheight;
661 // copy the bloom view to a texture
662 memset(&m, 0, sizeof(m));
663 m.pointer_vertex = varray_vertex3f;
664 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
665 m.pointer_texcoord[0] = varray_texcoord2f[2];
668 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
670 c_bloomcopypixels += bloomwidth * bloomheight;
671 // blend on at multiple offsets vertically
672 // TODO: do offset blends using GLSL
673 range = r_bloom_blur.integer * bloomwidth / 320;
674 GL_BlendFunc(GL_ONE, GL_ZERO);
675 for (x = -range;x <= range;x++)
677 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
678 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
679 varray_texcoord2f[2][0] = xoffset+0;
680 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
681 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
682 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
683 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
684 varray_texcoord2f[2][5] = yoffset+0;
685 varray_texcoord2f[2][6] = xoffset+0;
686 varray_texcoord2f[2][7] = yoffset+0;
687 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
690 GL_Color(r, r, r, 1);
691 R_Mesh_Draw(4, 2, polygonelements);
693 c_bloomdrawpixels += bloomwidth * bloomheight;
694 GL_BlendFunc(GL_ONE, GL_ONE);
696 // copy the blurred bloom view to a texture
698 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
700 c_bloomcopypixels += bloomwidth * bloomheight;
701 // blend on at multiple offsets horizontally
702 // TODO: do offset blends using GLSL
703 range = r_bloom_blur.integer * bloomwidth / 320;
704 GL_BlendFunc(GL_ONE, GL_ZERO);
705 for (x = -range;x <= range;x++)
707 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
708 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
709 varray_texcoord2f[2][0] = xoffset+0;
710 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
711 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
712 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
713 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
714 varray_texcoord2f[2][5] = yoffset+0;
715 varray_texcoord2f[2][6] = xoffset+0;
716 varray_texcoord2f[2][7] = yoffset+0;
717 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
720 GL_Color(r, r, r, 1);
721 R_Mesh_Draw(4, 2, polygonelements);
723 c_bloomdrawpixels += bloomwidth * bloomheight;
724 GL_BlendFunc(GL_ONE, GL_ONE);
726 // copy the blurred bloom view to a texture
728 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
730 c_bloomcopypixels += bloomwidth * bloomheight;
731 // go back to full view area
732 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
733 // put the original view back in place
734 memset(&m, 0, sizeof(m));
735 m.pointer_vertex = varray_vertex3f;
736 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
737 m.pointer_texcoord[0] = varray_texcoord2f[0];
739 dobloomblend = false;
741 // do both in one pass if possible
742 if (r_textureunits.integer >= 2 && gl_combine.integer)
744 dobloomblend = false;
745 m.texcombinergb[1] = GL_ADD;
746 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
747 m.pointer_texcoord[1] = varray_texcoord2f[1];
753 GL_BlendFunc(GL_ONE, GL_ZERO);
755 R_Mesh_Draw(4, 2, polygonelements);
757 c_bloomdrawpixels += r_view_width * r_view_height;
758 // now blend on the bloom texture if multipass
761 memset(&m, 0, sizeof(m));
762 m.pointer_vertex = varray_vertex3f;
763 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
764 m.pointer_texcoord[0] = varray_texcoord2f[1];
766 GL_BlendFunc(GL_ONE, GL_ONE);
768 R_Mesh_Draw(4, 2, polygonelements);
770 c_bloomdrawpixels += r_view_width * r_view_height;
773 if (r_refdef.viewblend[3] >= 0.01f)
775 // apply a color tint to the whole view
776 memset(&m, 0, sizeof(m));
777 m.pointer_vertex = varray_vertex3f;
779 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
780 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
781 R_Mesh_Draw(4, 2, polygonelements);
785 void R_RenderScene(void);
792 void R_RenderView(void)
794 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
795 return; //Host_Error ("R_RenderView: NULL worldmodel");
797 r_view_width = bound(0, r_refdef.width, vid.realwidth);
798 r_view_height = bound(0, r_refdef.height, vid.realheight);
800 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
801 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
803 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
804 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
805 r_view_matrix = r_refdef.viewentitymatrix;
806 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
807 r_rtworld = r_shadow_realtime_world.integer;
808 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
809 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
810 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
811 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
813 // GL is weird because it's bottom to top, r_view_y is top to bottom
814 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
815 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
816 GL_ScissorTest(true);
822 R_TimeReport("setup");
824 qglDepthFunc(GL_LEQUAL);
825 qglPolygonOffset(0, 0);
826 qglEnable(GL_POLYGON_OFFSET_FILL);
830 qglPolygonOffset(0, 0);
831 qglDisable(GL_POLYGON_OFFSET_FILL);
834 R_TimeReport("blendview");
836 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
837 GL_ScissorTest(false);
840 extern void R_DrawLightningBeams (void);
841 void R_RenderScene(void)
843 // don't let sound skip if going slow
844 if (r_refdef.extraupdate)
849 R_MeshQueue_BeginScene();
851 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
855 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
856 if (r_rtworldshadows || r_rtdlightshadows)
857 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
859 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
861 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
866 R_TimeReport("worldvis");
869 R_TimeReport("markentity");
871 R_Shadow_UpdateWorldLightSelection();
873 // don't let sound skip if going slow
874 if (r_refdef.extraupdate)
877 GL_ShowTrisColor(0.025, 0.025, 0, 1);
878 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
880 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
881 R_TimeReport("worldsky");
884 if (R_DrawBrushModelsSky())
885 R_TimeReport("bmodelsky");
887 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
888 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
890 r_refdef.worldmodel->Draw(r_refdef.worldentity);
891 R_TimeReport("world");
894 // don't let sound skip if going slow
895 if (r_refdef.extraupdate)
898 GL_ShowTrisColor(0, 0.015, 0, 1);
901 R_TimeReport("models");
903 // don't let sound skip if going slow
904 if (r_refdef.extraupdate)
907 GL_ShowTrisColor(0, 0, 0.033, 1);
908 R_ShadowVolumeLighting(false);
909 R_TimeReport("rtlights");
911 // don't let sound skip if going slow
912 if (r_refdef.extraupdate)
915 GL_ShowTrisColor(0.1, 0, 0, 1);
917 R_DrawLightningBeams();
918 R_TimeReport("lightning");
921 R_TimeReport("particles");
924 R_TimeReport("explosions");
926 R_MeshQueue_RenderTransparent();
927 R_TimeReport("drawtrans");
930 R_TimeReport("coronas");
932 R_DrawWorldCrosshair();
933 R_TimeReport("crosshair");
935 R_MeshQueue_Render();
936 R_MeshQueue_EndScene();
938 if (r_shadow_visiblevolumes.integer && !r_showtrispass)
940 R_ShadowVolumeLighting(true);
941 R_TimeReport("shadowvolume");
944 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
946 // don't let sound skip if going slow
947 if (r_refdef.extraupdate)
952 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
955 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
957 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
960 R_Mesh_Matrix(&r_identitymatrix);
962 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
963 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
964 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
965 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
966 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
967 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
968 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
969 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
970 R_FillColors(color, 8, cr, cg, cb, ca);
973 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
975 VectorSubtract(v, r_vieworigin, diff);
976 f2 = exp(fogdensity/DotProduct(diff, diff));
978 c[0] = c[0] * f1 + fogcolor[0] * f2;
979 c[1] = c[1] * f1 + fogcolor[1] * f2;
980 c[2] = c[2] * f1 + fogcolor[2] * f2;
983 memset(&m, 0, sizeof(m));
984 m.pointer_vertex = vertex3f;
985 m.pointer_color = color;
991 int nomodelelements[24] =
1003 float nomodelvertex3f[6*3] =
1013 float nomodelcolor4f[6*4] =
1015 0.0f, 0.0f, 0.5f, 1.0f,
1016 0.0f, 0.0f, 0.5f, 1.0f,
1017 0.0f, 0.5f, 0.0f, 1.0f,
1018 0.0f, 0.5f, 0.0f, 1.0f,
1019 0.5f, 0.0f, 0.0f, 1.0f,
1020 0.5f, 0.0f, 0.0f, 1.0f
1023 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1025 const entity_render_t *ent = calldata1;
1027 float f1, f2, *c, diff[3];
1030 R_Mesh_Matrix(&ent->matrix);
1032 memset(&m, 0, sizeof(m));
1033 m.pointer_vertex = nomodelvertex3f;
1035 if (ent->flags & EF_ADDITIVE)
1037 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1038 GL_DepthMask(false);
1040 else if (ent->alpha < 1)
1042 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1043 GL_DepthMask(false);
1047 GL_BlendFunc(GL_ONE, GL_ZERO);
1050 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1053 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1054 m.pointer_color = color4f;
1055 VectorSubtract(ent->origin, r_vieworigin, diff);
1056 f2 = exp(fogdensity/DotProduct(diff, diff));
1058 for (i = 0, c = color4f;i < 6;i++, c += 4)
1060 c[0] = (c[0] * f1 + fogcolor[0] * f2);
1061 c[1] = (c[1] * f1 + fogcolor[1] * f2);
1062 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1066 else if (ent->alpha != 1)
1068 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1069 m.pointer_color = color4f;
1070 for (i = 0, c = color4f;i < 6;i++, c += 4)
1074 m.pointer_color = nomodelcolor4f;
1076 R_Mesh_Draw(6, 8, nomodelelements);
1079 void R_DrawNoModel(entity_render_t *ent)
1081 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1082 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1084 // R_DrawNoModelCallback(ent, 0);
1087 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1089 vec3_t right1, right2, diff, normal;
1091 VectorSubtract (org2, org1, normal);
1093 // calculate 'right' vector for start
1094 VectorSubtract (r_vieworigin, org1, diff);
1095 CrossProduct (normal, diff, right1);
1096 VectorNormalize (right1);
1098 // calculate 'right' vector for end
1099 VectorSubtract (r_vieworigin, org2, diff);
1100 CrossProduct (normal, diff, right2);
1101 VectorNormalize (right2);
1103 vert[ 0] = org1[0] + width * right1[0];
1104 vert[ 1] = org1[1] + width * right1[1];
1105 vert[ 2] = org1[2] + width * right1[2];
1106 vert[ 3] = org1[0] - width * right1[0];
1107 vert[ 4] = org1[1] - width * right1[1];
1108 vert[ 5] = org1[2] - width * right1[2];
1109 vert[ 6] = org2[0] - width * right2[0];
1110 vert[ 7] = org2[1] - width * right2[1];
1111 vert[ 8] = org2[2] - width * right2[2];
1112 vert[ 9] = org2[0] + width * right2[0];
1113 vert[10] = org2[1] + width * right2[1];
1114 vert[11] = org2[2] + width * right2[2];
1117 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1119 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)
1126 VectorSubtract(origin, r_vieworigin, diff);
1127 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1130 R_Mesh_Matrix(&r_identitymatrix);
1131 GL_BlendFunc(blendfunc1, blendfunc2);
1132 GL_DepthMask(false);
1133 GL_DepthTest(!depthdisable);
1135 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1136 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1137 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1138 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1139 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1140 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1141 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1142 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1143 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1144 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1145 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1146 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1148 memset(&m, 0, sizeof(m));
1149 m.tex[0] = R_GetTexture(texture);
1150 m.pointer_texcoord[0] = spritetexcoord2f;
1151 m.pointer_vertex = varray_vertex3f;
1153 GL_Color(cr, cg, cb, ca);
1154 R_Mesh_Draw(4, 2, polygonelements);