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
28 // used for visibility checking
29 qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3];
33 matrix4x4_t r_identitymatrix;
35 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;
37 // true during envmap command capture
40 // maximum visible distance (recalculated from world box each frame)
42 // brightness of world lightmaps and related lighting
43 // (often reduced when world rtlights are enabled)
44 float r_lightmapintensity;
45 // whether to draw world lights realtime, dlights realtime, and their shadows
47 qboolean r_rtworldshadows;
49 qboolean r_rtdlightshadows;
52 // forces all rendering to draw triangle outlines
69 matrix4x4_t r_view_matrix;
76 // 8.8 fraction of base light value
77 unsigned short d_lightstylevalue[256];
79 cvar_t r_showtris = {0, "r_showtris", "0"};
80 cvar_t r_drawentities = {0, "r_drawentities","1"};
81 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
82 cvar_t r_speeds = {0, "r_speeds","0"};
83 cvar_t r_fullbright = {0, "r_fullbright","0"};
84 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
85 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
86 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
87 cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
89 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
90 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
91 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
92 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
93 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
94 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
95 cvar_t gl_fogend = {0, "gl_fogend","0"};
97 cvar_t r_textureunits = {0, "r_textureunits", "32"};
99 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
100 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
101 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
102 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
104 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"};
105 cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"};
106 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
107 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "256"};
108 cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
109 rtexturepool_t *r_main_texturepool;
110 rtexture_t *r_bloom_texture_screen;
111 rtexture_t *r_bloom_texture_bloom;
113 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
116 for (i = 0;i < verts;i++)
127 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
130 for (i = 0;i < verts;i++)
142 float fog_density, fog_red, fog_green, fog_blue;
144 qboolean oldgl_fogenable;
145 void R_UpdateFog(void)
147 if (gamemode == GAME_NEHAHRA)
149 if (gl_fogenable.integer)
151 oldgl_fogenable = true;
152 fog_density = gl_fogdensity.value;
153 fog_red = gl_fogred.value;
154 fog_green = gl_foggreen.value;
155 fog_blue = gl_fogblue.value;
157 else if (oldgl_fogenable)
159 oldgl_fogenable = false;
168 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
169 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
170 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
175 fogdensity = -4000.0f / (fog_density * fog_density);
176 // fog color was already set
182 // FIXME: move this to client?
185 if (gamemode == GAME_NEHAHRA)
187 Cvar_Set("gl_fogenable", "0");
188 Cvar_Set("gl_fogdensity", "0.2");
189 Cvar_Set("gl_fogred", "0.3");
190 Cvar_Set("gl_foggreen", "0.3");
191 Cvar_Set("gl_fogblue", "0.3");
193 fog_density = fog_red = fog_green = fog_blue = 0.0f;
196 // FIXME: move this to client?
197 void FOG_registercvars(void)
199 if (gamemode == GAME_NEHAHRA)
201 Cvar_RegisterVariable (&gl_fogenable);
202 Cvar_RegisterVariable (&gl_fogdensity);
203 Cvar_RegisterVariable (&gl_fogred);
204 Cvar_RegisterVariable (&gl_foggreen);
205 Cvar_RegisterVariable (&gl_fogblue);
206 Cvar_RegisterVariable (&gl_fogstart);
207 Cvar_RegisterVariable (&gl_fogend);
211 void gl_main_start(void)
213 r_main_texturepool = R_AllocTexturePool();
214 r_bloom_texture_screen = NULL;
215 r_bloom_texture_bloom = NULL;
218 void gl_main_shutdown(void)
220 // this seems to cause a already freed crash after a couple vid_restarts...
221 //R_FreeTexturePool(&r_main_texturepool);
222 r_main_texturepool = NULL;
223 r_bloom_texture_screen = NULL;
224 r_bloom_texture_bloom = NULL;
227 extern void CL_ParseEntityLump(char *entitystring);
228 void gl_main_newmap(void)
230 // FIXME: move this code to client
232 char *entities, entname[MAX_QPATH];
236 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
237 l = strlen(entname) - 4;
238 if (l >= 0 && !strcmp(entname + l, ".bsp"))
240 strcpy(entname + l, ".ent");
241 if ((entities = FS_LoadFile(entname, tempmempool, true)))
243 CL_ParseEntityLump(entities);
248 if (cl.worldmodel->brush.entities)
249 CL_ParseEntityLump(cl.worldmodel->brush.entities);
253 void GL_Main_Init(void)
255 Matrix4x4_CreateIdentity(&r_identitymatrix);
256 // FIXME: move this to client?
258 Cvar_RegisterVariable(&r_showtris);
259 Cvar_RegisterVariable(&r_drawentities);
260 Cvar_RegisterVariable(&r_drawviewmodel);
261 Cvar_RegisterVariable(&r_speeds);
262 Cvar_RegisterVariable(&r_fullbrights);
263 Cvar_RegisterVariable(&r_wateralpha);
264 Cvar_RegisterVariable(&r_dynamic);
265 Cvar_RegisterVariable(&r_fullbright);
266 Cvar_RegisterVariable(&r_textureunits);
267 Cvar_RegisterVariable(&r_lerpsprites);
268 Cvar_RegisterVariable(&r_lerpmodels);
269 Cvar_RegisterVariable(&r_waterscroll);
270 Cvar_RegisterVariable(&r_watershader);
271 Cvar_RegisterVariable(&r_drawcollisionbrushes);
272 Cvar_RegisterVariable(&r_bloom);
273 Cvar_RegisterVariable(&r_bloom_intensity);
274 Cvar_RegisterVariable(&r_bloom_blur);
275 Cvar_RegisterVariable(&r_bloom_resolution);
276 Cvar_RegisterVariable(&r_bloom_power);
277 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
278 Cvar_SetValue("r_fullbrights", 0);
279 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
282 static vec3_t r_farclip_origin;
283 static vec3_t r_farclip_direction;
284 static vec_t r_farclip_directiondist;
285 static vec_t r_farclip_meshfarclip;
286 static int r_farclip_directionbit0;
287 static int r_farclip_directionbit1;
288 static int r_farclip_directionbit2;
290 // enlarge farclip to accomodate box
291 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
294 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
295 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
296 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
297 if (r_farclip_meshfarclip < d)
298 r_farclip_meshfarclip = d;
301 // return farclip value
302 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
306 VectorCopy(origin, r_farclip_origin);
307 VectorCopy(direction, r_farclip_direction);
308 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
309 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
310 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
311 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
312 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
314 if (r_refdef.worldmodel)
315 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
316 for (i = 0;i < r_refdef.numentities;i++)
317 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
319 return r_farclip_meshfarclip - r_farclip_directiondist;
322 extern void R_Textures_Init(void);
323 extern void Mod_RenderInit(void);
324 extern void GL_Draw_Init(void);
325 extern void GL_Main_Init(void);
326 extern void R_Shadow_Init(void);
327 extern void GL_Models_Init(void);
328 extern void R_Sky_Init(void);
329 extern void GL_Surf_Init(void);
330 extern void R_Crosshairs_Init(void);
331 extern void R_Light_Init(void);
332 extern void R_Particles_Init(void);
333 extern void R_Explosion_Init(void);
334 extern void ui_init(void);
335 extern void gl_backend_init(void);
336 extern void Sbar_Init(void);
337 extern void R_LightningBeams_Init(void);
339 void Render_Init(void)
358 R_LightningBeams_Init();
366 extern char *ENGINE_EXTENSIONS;
369 VID_CheckExtensions();
371 // LordHavoc: report supported extensions
372 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
374 // clear to black (loading plaque will be seen over this)
375 qglClearColor(0,0,0,1);
376 qglClear(GL_COLOR_BUFFER_BIT);
379 int R_CullBox(const vec3_t mins, const vec3_t maxs)
383 for (i = 0;i < 4;i++)
390 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
394 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
398 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
402 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
406 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
410 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
414 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
418 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
426 //==================================================================================
428 static void R_MarkEntities (void)
431 entity_render_t *ent;
433 if (!r_drawentities.integer)
436 for (i = 0;i < r_refdef.numentities;i++)
438 ent = r_refdef.entities[i];
439 Mod_CheckLoaded(ent->model);
440 // some of the renderer still relies on origin...
441 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
442 // some of the renderer still relies on scale...
443 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
444 R_UpdateEntLights(ent);
445 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
446 && (!VIS_CullBox(ent->mins, ent->maxs) || (ent->effects & EF_NODEPTHTEST))
447 && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
448 ent->visframe = r_framecount;
452 // only used if skyrendermasked, and normally returns false
453 int R_DrawBrushModelsSky (void)
456 entity_render_t *ent;
458 if (!r_drawentities.integer)
462 for (i = 0;i < r_refdef.numentities;i++)
464 ent = r_refdef.entities[i];
465 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
467 ent->model->DrawSky(ent);
474 void R_DrawNoModel(entity_render_t *ent);
475 void R_DrawModels(void)
478 entity_render_t *ent;
480 if (!r_drawentities.integer)
483 for (i = 0;i < r_refdef.numentities;i++)
485 ent = r_refdef.entities[i];
486 if (ent->visframe == r_framecount)
488 if (ent->model && ent->model->Draw != NULL)
489 ent->model->Draw(ent);
496 static void R_SetFrustum(void)
498 // break apart the view matrix into vectors for various purposes
499 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
500 VectorNegate(r_viewleft, r_viewright);
502 // LordHavoc: note to all quake engine coders, the special case for 90
503 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
506 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
507 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
508 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
509 PlaneClassify(&frustum[0]);
511 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
512 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
513 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
514 PlaneClassify(&frustum[1]);
516 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
517 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
518 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
519 PlaneClassify(&frustum[2]);
521 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
522 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
523 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
524 PlaneClassify(&frustum[3]);
527 static void R_BlendView(void)
531 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
534 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
537 R_Mesh_Matrix(&r_identitymatrix);
538 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
539 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
540 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
541 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
542 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)
544 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
545 float xoffset, yoffset, r;
547 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
548 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
549 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
550 bloomheight = min(r_view_height, r_bloom_resolution.integer);
551 varray_texcoord2f[0][0] = 0;
552 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
553 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
554 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
555 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
556 varray_texcoord2f[0][5] = 0;
557 varray_texcoord2f[0][6] = 0;
558 varray_texcoord2f[0][7] = 0;
559 varray_texcoord2f[1][0] = 0;
560 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
561 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
562 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
563 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
564 varray_texcoord2f[1][5] = 0;
565 varray_texcoord2f[1][6] = 0;
566 varray_texcoord2f[1][7] = 0;
567 if (!r_bloom_texture_screen)
568 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
569 if (!r_bloom_texture_bloom)
570 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
571 memset(&m, 0, sizeof(m));
572 m.pointer_vertex = varray_vertex3f;
573 m.pointer_texcoord[0] = varray_texcoord2f[0];
574 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
576 // copy view to a texture
578 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
580 c_bloomcopypixels += r_view_width * r_view_height;
581 // now scale it down to the bloom size and raise to a power of itself
582 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
583 // TODO: optimize with multitexture or GLSL
584 GL_BlendFunc(GL_ONE, GL_ZERO);
585 GL_Color(1, 1, 1, 1);
586 R_Mesh_Draw(4, 2, polygonelements);
588 c_bloomdrawpixels += bloomwidth * bloomheight;
589 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
590 for (x = 1;x < r_bloom_power.integer;x++)
592 R_Mesh_Draw(4, 2, polygonelements);
594 c_bloomdrawpixels += bloomwidth * bloomheight;
596 // copy the bloom view to a texture
597 memset(&m, 0, sizeof(m));
598 m.pointer_vertex = varray_vertex3f;
599 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
600 m.pointer_texcoord[0] = varray_texcoord2f[2];
603 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
605 c_bloomcopypixels += bloomwidth * bloomheight;
606 // blend on at multiple offsets vertically
607 // TODO: do offset blends using GLSL
608 range = r_bloom_blur.integer;//(int)(r_bloom_blur.value * bloomwidth / 320);
609 GL_BlendFunc(GL_ONE, GL_ZERO);
610 for (x = -range;x <= range;x++)
612 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
613 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
614 varray_texcoord2f[2][0] = xoffset+0;
615 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
616 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
617 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
618 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
619 varray_texcoord2f[2][5] = yoffset+0;
620 varray_texcoord2f[2][6] = xoffset+0;
621 varray_texcoord2f[2][7] = yoffset+0;
622 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
625 GL_Color(r, r, r, 1);
626 R_Mesh_Draw(4, 2, polygonelements);
628 c_bloomdrawpixels += bloomwidth * bloomheight;
629 GL_BlendFunc(GL_ONE, GL_ONE);
631 // copy the blurred bloom view to a texture
633 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
635 c_bloomcopypixels += bloomwidth * bloomheight;
636 // blend on at multiple offsets horizontally
637 // TODO: do offset blends using GLSL
638 range = r_bloom_blur.integer * bloomheight / r_view_height;//(int)(r_bloom_blur.value * bloomwidth / 320);
639 GL_BlendFunc(GL_ONE, GL_ZERO);
640 for (x = -range;x <= range;x++)
642 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
643 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
644 varray_texcoord2f[2][0] = xoffset+0;
645 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
646 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
647 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
648 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
649 varray_texcoord2f[2][5] = yoffset+0;
650 varray_texcoord2f[2][6] = xoffset+0;
651 varray_texcoord2f[2][7] = yoffset+0;
652 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
655 GL_Color(r, r, r, 1);
656 R_Mesh_Draw(4, 2, polygonelements);
658 c_bloomdrawpixels += bloomwidth * bloomheight;
659 GL_BlendFunc(GL_ONE, GL_ONE);
661 // copy the blurred bloom view to a texture
663 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
665 c_bloomcopypixels += bloomwidth * bloomheight;
666 // go back to full view area
667 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
668 // put the original view back in place
669 memset(&m, 0, sizeof(m));
670 m.pointer_vertex = varray_vertex3f;
671 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
672 m.pointer_texcoord[0] = varray_texcoord2f[0];
674 dobloomblend = false;
676 // do both in one pass if possible
677 if (r_textureunits.integer >= 2 && gl_combine.integer)
679 dobloomblend = false;
680 m.texcombinergb[1] = GL_ADD;
681 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
682 m.pointer_texcoord[1] = varray_texcoord2f[1];
688 GL_BlendFunc(GL_ONE, GL_ZERO);
690 R_Mesh_Draw(4, 2, polygonelements);
692 c_bloomdrawpixels += r_view_width * r_view_height;
693 // now blend on the bloom texture if multipass
696 memset(&m, 0, sizeof(m));
697 m.pointer_vertex = varray_vertex3f;
698 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
699 m.pointer_texcoord[0] = varray_texcoord2f[1];
701 GL_BlendFunc(GL_ONE, GL_ONE);
703 R_Mesh_Draw(4, 2, polygonelements);
705 c_bloomdrawpixels += r_view_width * r_view_height;
708 if (r_refdef.viewblend[3] >= 0.01f)
710 // apply a color tint to the whole view
711 memset(&m, 0, sizeof(m));
712 m.pointer_vertex = varray_vertex3f;
714 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
715 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
716 R_Mesh_Draw(4, 2, polygonelements);
720 void R_RenderScene(void);
727 void R_RenderView(void)
729 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
730 return; //Host_Error ("R_RenderView: NULL worldmodel");
732 r_view_width = bound(0, r_refdef.width, vid.realwidth);
733 r_view_height = bound(0, r_refdef.height, vid.realheight);
735 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
736 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
738 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
739 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
740 r_view_matrix = r_refdef.viewentitymatrix;
741 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
742 r_rtworld = r_shadow_realtime_world.integer;
743 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
744 r_rtdlight = r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer;
745 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
746 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
748 // GL is weird because it's bottom to top, r_view_y is top to bottom
749 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
750 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
751 GL_ScissorTest(true);
757 R_TimeReport("setup");
759 qglDepthFunc(GL_LEQUAL);
760 qglPolygonOffset(0, 0);
761 qglEnable(GL_POLYGON_OFFSET_FILL);
765 qglPolygonOffset(0, 0);
766 qglDisable(GL_POLYGON_OFFSET_FILL);
769 R_TimeReport("blendview");
771 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
772 GL_ScissorTest(false);
775 extern void R_DrawLightningBeams (void);
776 void R_RenderScene(void)
778 // don't let sound skip if going slow
779 if (r_refdef.extraupdate)
784 R_MeshQueue_BeginScene();
786 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
790 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
791 if (r_rtworldshadows || r_rtdlightshadows)
792 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
794 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
796 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
800 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.FatPVS)
801 r_refdef.worldmodel->brush.FatPVS(r_refdef.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
803 R_TimeReport("worldvis");
806 R_TimeReport("markentity");
808 R_Shadow_UpdateWorldLightSelection();
810 // don't let sound skip if going slow
811 if (r_refdef.extraupdate)
814 GL_ShowTrisColor(0.025, 0.025, 0, 1);
815 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
817 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
818 R_TimeReport("worldsky");
821 if (R_DrawBrushModelsSky())
822 R_TimeReport("bmodelsky");
824 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
825 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
827 r_refdef.worldmodel->Draw(r_refdef.worldentity);
828 R_TimeReport("world");
831 // don't let sound skip if going slow
832 if (r_refdef.extraupdate)
835 GL_ShowTrisColor(0, 0.015, 0, 1);
838 R_TimeReport("models");
840 // don't let sound skip if going slow
841 if (r_refdef.extraupdate)
844 GL_ShowTrisColor(0, 0, 0.033, 1);
845 R_ShadowVolumeLighting(false);
846 R_TimeReport("rtlights");
848 // don't let sound skip if going slow
849 if (r_refdef.extraupdate)
852 GL_ShowTrisColor(0.1, 0, 0, 1);
854 R_DrawLightningBeams();
855 R_TimeReport("lightning");
858 R_TimeReport("particles");
861 R_TimeReport("explosions");
863 R_MeshQueue_RenderTransparent();
864 R_TimeReport("drawtrans");
867 R_TimeReport("coronas");
869 R_DrawWorldCrosshair();
870 R_TimeReport("crosshair");
872 R_MeshQueue_Render();
873 R_MeshQueue_EndScene();
875 if (r_shadow_visiblevolumes.integer && !r_showtrispass)
877 R_ShadowVolumeLighting(true);
878 R_TimeReport("shadowvolume");
881 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
883 // don't let sound skip if going slow
884 if (r_refdef.extraupdate)
889 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
892 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
894 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
897 R_Mesh_Matrix(&r_identitymatrix);
899 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
900 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
901 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
902 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
903 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
904 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
905 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
906 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
907 R_FillColors(color, 8, cr, cg, cb, ca);
910 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
912 VectorSubtract(v, r_vieworigin, diff);
913 f2 = exp(fogdensity/DotProduct(diff, diff));
915 c[0] = c[0] * f1 + fogcolor[0] * f2;
916 c[1] = c[1] * f1 + fogcolor[1] * f2;
917 c[2] = c[2] * f1 + fogcolor[2] * f2;
920 memset(&m, 0, sizeof(m));
921 m.pointer_vertex = vertex3f;
922 m.pointer_color = color;
928 int nomodelelements[24] =
940 float nomodelvertex3f[6*3] =
950 float nomodelcolor4f[6*4] =
952 0.0f, 0.0f, 0.5f, 1.0f,
953 0.0f, 0.0f, 0.5f, 1.0f,
954 0.0f, 0.5f, 0.0f, 1.0f,
955 0.0f, 0.5f, 0.0f, 1.0f,
956 0.5f, 0.0f, 0.0f, 1.0f,
957 0.5f, 0.0f, 0.0f, 1.0f
960 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
962 const entity_render_t *ent = calldata1;
964 float f1, f2, *c, diff[3];
967 R_Mesh_Matrix(&ent->matrix);
969 memset(&m, 0, sizeof(m));
970 m.pointer_vertex = nomodelvertex3f;
972 if (ent->flags & EF_ADDITIVE)
974 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
977 else if (ent->alpha < 1)
979 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
984 GL_BlendFunc(GL_ONE, GL_ZERO);
987 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
990 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
991 m.pointer_color = color4f;
992 VectorSubtract(ent->origin, r_vieworigin, diff);
993 f2 = exp(fogdensity/DotProduct(diff, diff));
995 for (i = 0, c = color4f;i < 6;i++, c += 4)
997 c[0] = (c[0] * f1 + fogcolor[0] * f2);
998 c[1] = (c[1] * f1 + fogcolor[1] * f2);
999 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1003 else if (ent->alpha != 1)
1005 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1006 m.pointer_color = color4f;
1007 for (i = 0, c = color4f;i < 6;i++, c += 4)
1011 m.pointer_color = nomodelcolor4f;
1013 R_Mesh_Draw(6, 8, nomodelelements);
1016 void R_DrawNoModel(entity_render_t *ent)
1018 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1019 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1021 // R_DrawNoModelCallback(ent, 0);
1024 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1026 vec3_t right1, right2, diff, normal;
1028 VectorSubtract (org2, org1, normal);
1029 VectorNormalizeFast (normal);
1031 // calculate 'right' vector for start
1032 VectorSubtract (r_vieworigin, org1, diff);
1033 VectorNormalizeFast (diff);
1034 CrossProduct (normal, diff, right1);
1036 // calculate 'right' vector for end
1037 VectorSubtract (r_vieworigin, org2, diff);
1038 VectorNormalizeFast (diff);
1039 CrossProduct (normal, diff, right2);
1041 vert[ 0] = org1[0] + width * right1[0];
1042 vert[ 1] = org1[1] + width * right1[1];
1043 vert[ 2] = org1[2] + width * right1[2];
1044 vert[ 3] = org1[0] - width * right1[0];
1045 vert[ 4] = org1[1] - width * right1[1];
1046 vert[ 5] = org1[2] - width * right1[2];
1047 vert[ 6] = org2[0] - width * right2[0];
1048 vert[ 7] = org2[1] - width * right2[1];
1049 vert[ 8] = org2[2] - width * right2[2];
1050 vert[ 9] = org2[0] + width * right2[0];
1051 vert[10] = org2[1] + width * right2[1];
1052 vert[11] = org2[2] + width * right2[2];
1055 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1057 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)
1064 VectorSubtract(origin, r_vieworigin, diff);
1065 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1068 R_Mesh_Matrix(&r_identitymatrix);
1069 GL_BlendFunc(blendfunc1, blendfunc2);
1070 GL_DepthMask(false);
1071 GL_DepthTest(!depthdisable);
1073 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1074 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1075 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1076 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1077 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1078 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1079 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1080 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1081 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1082 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1083 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1084 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1086 memset(&m, 0, sizeof(m));
1087 m.tex[0] = R_GetTexture(texture);
1088 m.pointer_texcoord[0] = spritetexcoord2f;
1089 m.pointer_vertex = varray_vertex3f;
1091 GL_Color(cr, cg, cb, ca);
1092 R_Mesh_Draw(4, 2, polygonelements);