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];
31 // TODO: dynamic resize? 65536 seems enough because q1bsp can't have more
32 // than 32768, and q3bsp compilers have more like a 4096 limit
33 qbyte r_worldsurfacevisible[MAX_MAP_LEAFS];
37 matrix4x4_t r_identitymatrix;
39 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;
41 // true during envmap command capture
44 // maximum visible distance (recalculated from world box each frame)
46 // brightness of world lightmaps and related lighting
47 // (often reduced when world rtlights are enabled)
48 float r_lightmapintensity;
49 // whether to draw world lights realtime, dlights realtime, and their shadows
51 qboolean r_rtworldshadows;
53 qboolean r_rtdlightshadows;
56 // forces all rendering to draw triangle outlines
73 matrix4x4_t r_view_matrix;
80 // 8.8 fraction of base light value
81 unsigned short d_lightstylevalue[256];
83 cvar_t r_showtris = {0, "r_showtris", "0"};
84 cvar_t r_drawentities = {0, "r_drawentities","1"};
85 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
86 cvar_t r_speeds = {0, "r_speeds","0"};
87 cvar_t r_fullbright = {0, "r_fullbright","0"};
88 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
89 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
90 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
91 cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
93 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
94 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
95 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
96 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
97 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
98 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
99 cvar_t gl_fogend = {0, "gl_fogend","0"};
101 cvar_t r_textureunits = {0, "r_textureunits", "32"};
103 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
104 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
105 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
106 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
108 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"};
109 cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"};
110 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
111 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
112 cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
113 rtexturepool_t *r_main_texturepool;
114 rtexture_t *r_bloom_texture_screen;
115 rtexture_t *r_bloom_texture_bloom;
117 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
120 for (i = 0;i < verts;i++)
131 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
134 for (i = 0;i < verts;i++)
146 float fog_density, fog_red, fog_green, fog_blue;
148 qboolean oldgl_fogenable;
149 void R_UpdateFog(void)
151 if (gamemode == GAME_NEHAHRA)
153 if (gl_fogenable.integer)
155 oldgl_fogenable = true;
156 fog_density = gl_fogdensity.value;
157 fog_red = gl_fogred.value;
158 fog_green = gl_foggreen.value;
159 fog_blue = gl_fogblue.value;
161 else if (oldgl_fogenable)
163 oldgl_fogenable = false;
172 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
173 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
174 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
179 fogdensity = -4000.0f / (fog_density * fog_density);
180 // fog color was already set
186 // FIXME: move this to client?
189 if (gamemode == GAME_NEHAHRA)
191 Cvar_Set("gl_fogenable", "0");
192 Cvar_Set("gl_fogdensity", "0.2");
193 Cvar_Set("gl_fogred", "0.3");
194 Cvar_Set("gl_foggreen", "0.3");
195 Cvar_Set("gl_fogblue", "0.3");
197 fog_density = fog_red = fog_green = fog_blue = 0.0f;
200 // FIXME: move this to client?
201 void FOG_registercvars(void)
203 if (gamemode == GAME_NEHAHRA)
205 Cvar_RegisterVariable (&gl_fogenable);
206 Cvar_RegisterVariable (&gl_fogdensity);
207 Cvar_RegisterVariable (&gl_fogred);
208 Cvar_RegisterVariable (&gl_foggreen);
209 Cvar_RegisterVariable (&gl_fogblue);
210 Cvar_RegisterVariable (&gl_fogstart);
211 Cvar_RegisterVariable (&gl_fogend);
215 void gl_main_start(void)
217 r_main_texturepool = R_AllocTexturePool();
218 r_bloom_texture_screen = NULL;
219 r_bloom_texture_bloom = NULL;
222 void gl_main_shutdown(void)
224 R_FreeTexturePool(&r_main_texturepool);
225 r_bloom_texture_screen = NULL;
226 r_bloom_texture_bloom = NULL;
229 extern void CL_ParseEntityLump(char *entitystring);
230 void gl_main_newmap(void)
232 // FIXME: move this code to client
234 char *entities, entname[MAX_QPATH];
238 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
239 l = strlen(entname) - 4;
240 if (l >= 0 && !strcmp(entname + l, ".bsp"))
242 strcpy(entname + l, ".ent");
243 if ((entities = FS_LoadFile(entname, tempmempool, true)))
245 CL_ParseEntityLump(entities);
250 if (cl.worldmodel->brush.entities)
251 CL_ParseEntityLump(cl.worldmodel->brush.entities);
255 void GL_Main_Init(void)
257 Matrix4x4_CreateIdentity(&r_identitymatrix);
258 // FIXME: move this to client?
260 Cvar_RegisterVariable(&r_showtris);
261 Cvar_RegisterVariable(&r_drawentities);
262 Cvar_RegisterVariable(&r_drawviewmodel);
263 Cvar_RegisterVariable(&r_speeds);
264 Cvar_RegisterVariable(&r_fullbrights);
265 Cvar_RegisterVariable(&r_wateralpha);
266 Cvar_RegisterVariable(&r_dynamic);
267 Cvar_RegisterVariable(&r_fullbright);
268 Cvar_RegisterVariable(&r_textureunits);
269 Cvar_RegisterVariable(&r_lerpsprites);
270 Cvar_RegisterVariable(&r_lerpmodels);
271 Cvar_RegisterVariable(&r_waterscroll);
272 Cvar_RegisterVariable(&r_watershader);
273 Cvar_RegisterVariable(&r_drawcollisionbrushes);
274 Cvar_RegisterVariable(&r_bloom);
275 Cvar_RegisterVariable(&r_bloom_intensity);
276 Cvar_RegisterVariable(&r_bloom_blur);
277 Cvar_RegisterVariable(&r_bloom_resolution);
278 Cvar_RegisterVariable(&r_bloom_power);
279 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
280 Cvar_SetValue("r_fullbrights", 0);
281 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
284 static vec3_t r_farclip_origin;
285 static vec3_t r_farclip_direction;
286 static vec_t r_farclip_directiondist;
287 static vec_t r_farclip_meshfarclip;
288 static int r_farclip_directionbit0;
289 static int r_farclip_directionbit1;
290 static int r_farclip_directionbit2;
292 // enlarge farclip to accomodate box
293 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
296 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
297 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
298 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
299 if (r_farclip_meshfarclip < d)
300 r_farclip_meshfarclip = d;
303 // return farclip value
304 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
308 VectorCopy(origin, r_farclip_origin);
309 VectorCopy(direction, r_farclip_direction);
310 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
311 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
312 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
313 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
314 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
316 if (r_refdef.worldmodel)
317 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
318 for (i = 0;i < r_refdef.numentities;i++)
319 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
321 return r_farclip_meshfarclip - r_farclip_directiondist;
324 extern void R_Textures_Init(void);
325 extern void Mod_RenderInit(void);
326 extern void GL_Draw_Init(void);
327 extern void GL_Main_Init(void);
328 extern void R_Shadow_Init(void);
329 extern void GL_Models_Init(void);
330 extern void R_Sky_Init(void);
331 extern void GL_Surf_Init(void);
332 extern void R_Crosshairs_Init(void);
333 extern void R_Light_Init(void);
334 extern void R_Particles_Init(void);
335 extern void R_Explosion_Init(void);
336 extern void ui_init(void);
337 extern void gl_backend_init(void);
338 extern void Sbar_Init(void);
339 extern void R_LightningBeams_Init(void);
341 void Render_Init(void)
360 R_LightningBeams_Init();
368 extern char *ENGINE_EXTENSIONS;
371 VID_CheckExtensions();
373 // LordHavoc: report supported extensions
374 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
376 // clear to black (loading plaque will be seen over this)
377 qglClearColor(0,0,0,1);
378 qglClear(GL_COLOR_BUFFER_BIT);
381 int R_CullBox(const vec3_t mins, const vec3_t maxs)
385 for (i = 0;i < 4;i++)
392 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
396 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
400 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
404 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
408 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
412 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
416 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
420 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
428 //==================================================================================
430 static void R_MarkEntities (void)
433 entity_render_t *ent;
435 if (!r_drawentities.integer)
438 for (i = 0;i < r_refdef.numentities;i++)
440 ent = r_refdef.entities[i];
441 Mod_CheckLoaded(ent->model);
442 // some of the renderer still relies on origin...
443 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
444 // some of the renderer still relies on scale...
445 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
446 R_UpdateEntLights(ent);
447 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
448 && (!VIS_CullBox(ent->mins, ent->maxs) || (ent->effects & EF_NODEPTHTEST))
449 && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
450 ent->visframe = r_framecount;
454 // only used if skyrendermasked, and normally returns false
455 int R_DrawBrushModelsSky (void)
458 entity_render_t *ent;
460 if (!r_drawentities.integer)
464 for (i = 0;i < r_refdef.numentities;i++)
466 ent = r_refdef.entities[i];
467 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
469 ent->model->DrawSky(ent);
476 void R_DrawNoModel(entity_render_t *ent);
477 void R_DrawModels(void)
480 entity_render_t *ent;
482 if (!r_drawentities.integer)
485 for (i = 0;i < r_refdef.numentities;i++)
487 ent = r_refdef.entities[i];
488 if (ent->visframe == r_framecount)
490 if (ent->model && ent->model->Draw != NULL)
491 ent->model->Draw(ent);
498 static void R_SetFrustum(void)
500 // break apart the view matrix into vectors for various purposes
501 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
502 VectorNegate(r_viewleft, r_viewright);
504 // LordHavoc: note to all quake engine coders, the special case for 90
505 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
508 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
509 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
510 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
511 PlaneClassify(&frustum[0]);
513 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
514 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
515 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
516 PlaneClassify(&frustum[1]);
518 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
519 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
520 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
521 PlaneClassify(&frustum[2]);
523 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
524 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
525 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
526 PlaneClassify(&frustum[3]);
529 static void R_BlendView(void)
533 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
536 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
539 R_Mesh_Matrix(&r_identitymatrix);
540 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
541 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
542 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
543 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
544 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)
546 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
547 float xoffset, yoffset, r;
549 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
550 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
551 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
552 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
553 varray_texcoord2f[0][0] = 0;
554 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
555 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
556 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
557 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
558 varray_texcoord2f[0][5] = 0;
559 varray_texcoord2f[0][6] = 0;
560 varray_texcoord2f[0][7] = 0;
561 varray_texcoord2f[1][0] = 0;
562 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
563 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
564 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
565 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
566 varray_texcoord2f[1][5] = 0;
567 varray_texcoord2f[1][6] = 0;
568 varray_texcoord2f[1][7] = 0;
569 if (!r_bloom_texture_screen)
570 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
571 if (!r_bloom_texture_bloom)
572 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
573 memset(&m, 0, sizeof(m));
574 m.pointer_vertex = varray_vertex3f;
575 m.pointer_texcoord[0] = varray_texcoord2f[0];
576 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
578 // copy view to a texture
580 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
582 c_bloomcopypixels += r_view_width * r_view_height;
583 // now scale it down to the bloom size and raise to a power of itself
584 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
585 // TODO: optimize with multitexture or GLSL
586 GL_BlendFunc(GL_ONE, GL_ZERO);
587 GL_Color(1, 1, 1, 1);
588 R_Mesh_Draw(4, 2, polygonelements);
590 c_bloomdrawpixels += bloomwidth * bloomheight;
591 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
592 for (x = 1;x < r_bloom_power.integer;x++)
594 R_Mesh_Draw(4, 2, polygonelements);
596 c_bloomdrawpixels += bloomwidth * bloomheight;
598 // copy the bloom view to a texture
599 memset(&m, 0, sizeof(m));
600 m.pointer_vertex = varray_vertex3f;
601 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
602 m.pointer_texcoord[0] = varray_texcoord2f[2];
605 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
607 c_bloomcopypixels += bloomwidth * bloomheight;
608 // blend on at multiple offsets vertically
609 // TODO: do offset blends using GLSL
610 range = r_bloom_blur.integer * bloomwidth / 320;
611 GL_BlendFunc(GL_ONE, GL_ZERO);
612 for (x = -range;x <= range;x++)
614 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
615 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
616 varray_texcoord2f[2][0] = xoffset+0;
617 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
618 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
619 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
620 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
621 varray_texcoord2f[2][5] = yoffset+0;
622 varray_texcoord2f[2][6] = xoffset+0;
623 varray_texcoord2f[2][7] = yoffset+0;
624 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
627 GL_Color(r, r, r, 1);
628 R_Mesh_Draw(4, 2, polygonelements);
630 c_bloomdrawpixels += bloomwidth * bloomheight;
631 GL_BlendFunc(GL_ONE, GL_ONE);
633 // copy the blurred bloom view to a texture
635 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
637 c_bloomcopypixels += bloomwidth * bloomheight;
638 // blend on at multiple offsets horizontally
639 // TODO: do offset blends using GLSL
640 range = r_bloom_blur.integer * bloomwidth / 320;
641 GL_BlendFunc(GL_ONE, GL_ZERO);
642 for (x = -range;x <= range;x++)
644 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
645 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
646 varray_texcoord2f[2][0] = xoffset+0;
647 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
648 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
649 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
650 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
651 varray_texcoord2f[2][5] = yoffset+0;
652 varray_texcoord2f[2][6] = xoffset+0;
653 varray_texcoord2f[2][7] = yoffset+0;
654 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
657 GL_Color(r, r, r, 1);
658 R_Mesh_Draw(4, 2, polygonelements);
660 c_bloomdrawpixels += bloomwidth * bloomheight;
661 GL_BlendFunc(GL_ONE, GL_ONE);
663 // copy the blurred bloom view to a texture
665 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
667 c_bloomcopypixels += bloomwidth * bloomheight;
668 // go back to full view area
669 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
670 // put the original view back in place
671 memset(&m, 0, sizeof(m));
672 m.pointer_vertex = varray_vertex3f;
673 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
674 m.pointer_texcoord[0] = varray_texcoord2f[0];
676 dobloomblend = false;
678 // do both in one pass if possible
679 if (r_textureunits.integer >= 2 && gl_combine.integer)
681 dobloomblend = false;
682 m.texcombinergb[1] = GL_ADD;
683 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
684 m.pointer_texcoord[1] = varray_texcoord2f[1];
690 GL_BlendFunc(GL_ONE, GL_ZERO);
692 R_Mesh_Draw(4, 2, polygonelements);
694 c_bloomdrawpixels += r_view_width * r_view_height;
695 // now blend on the bloom texture if multipass
698 memset(&m, 0, sizeof(m));
699 m.pointer_vertex = varray_vertex3f;
700 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
701 m.pointer_texcoord[0] = varray_texcoord2f[1];
703 GL_BlendFunc(GL_ONE, GL_ONE);
705 R_Mesh_Draw(4, 2, polygonelements);
707 c_bloomdrawpixels += r_view_width * r_view_height;
710 if (r_refdef.viewblend[3] >= 0.01f)
712 // apply a color tint to the whole view
713 memset(&m, 0, sizeof(m));
714 m.pointer_vertex = varray_vertex3f;
716 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
717 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
718 R_Mesh_Draw(4, 2, polygonelements);
722 void R_RenderScene(void);
729 void R_RenderView(void)
731 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
732 return; //Host_Error ("R_RenderView: NULL worldmodel");
734 r_view_width = bound(0, r_refdef.width, vid.realwidth);
735 r_view_height = bound(0, r_refdef.height, vid.realheight);
737 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
738 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
740 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
741 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
742 r_view_matrix = r_refdef.viewentitymatrix;
743 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
744 r_rtworld = r_shadow_realtime_world.integer;
745 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
746 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
747 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
748 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
750 // GL is weird because it's bottom to top, r_view_y is top to bottom
751 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
752 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
753 GL_ScissorTest(true);
759 R_TimeReport("setup");
761 qglDepthFunc(GL_LEQUAL);
762 qglPolygonOffset(0, 0);
763 qglEnable(GL_POLYGON_OFFSET_FILL);
767 qglPolygonOffset(0, 0);
768 qglDisable(GL_POLYGON_OFFSET_FILL);
771 R_TimeReport("blendview");
773 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
774 GL_ScissorTest(false);
777 extern void R_DrawLightningBeams (void);
778 void R_RenderScene(void)
780 // don't let sound skip if going slow
781 if (r_refdef.extraupdate)
786 R_MeshQueue_BeginScene();
788 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
792 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
793 if (r_rtworldshadows || r_rtdlightshadows)
794 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
796 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
798 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
802 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.FatPVS)
803 r_refdef.worldmodel->brush.FatPVS(r_refdef.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
805 R_TimeReport("worldvis");
808 R_TimeReport("markentity");
810 R_Shadow_UpdateWorldLightSelection();
812 // don't let sound skip if going slow
813 if (r_refdef.extraupdate)
816 GL_ShowTrisColor(0.025, 0.025, 0, 1);
817 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
819 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
820 R_TimeReport("worldsky");
823 if (R_DrawBrushModelsSky())
824 R_TimeReport("bmodelsky");
826 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
827 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
829 r_refdef.worldmodel->Draw(r_refdef.worldentity);
830 R_TimeReport("world");
833 // don't let sound skip if going slow
834 if (r_refdef.extraupdate)
837 GL_ShowTrisColor(0, 0.015, 0, 1);
840 R_TimeReport("models");
842 // don't let sound skip if going slow
843 if (r_refdef.extraupdate)
846 GL_ShowTrisColor(0, 0, 0.033, 1);
847 R_ShadowVolumeLighting(false);
848 R_TimeReport("rtlights");
850 // don't let sound skip if going slow
851 if (r_refdef.extraupdate)
854 GL_ShowTrisColor(0.1, 0, 0, 1);
856 R_DrawLightningBeams();
857 R_TimeReport("lightning");
860 R_TimeReport("particles");
863 R_TimeReport("explosions");
865 R_MeshQueue_RenderTransparent();
866 R_TimeReport("drawtrans");
869 R_TimeReport("coronas");
871 R_DrawWorldCrosshair();
872 R_TimeReport("crosshair");
874 R_MeshQueue_Render();
875 R_MeshQueue_EndScene();
877 if (r_shadow_visiblevolumes.integer && !r_showtrispass)
879 R_ShadowVolumeLighting(true);
880 R_TimeReport("shadowvolume");
883 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
885 // don't let sound skip if going slow
886 if (r_refdef.extraupdate)
891 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
894 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
896 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
899 R_Mesh_Matrix(&r_identitymatrix);
901 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
902 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
903 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
904 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
905 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
906 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
907 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
908 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
909 R_FillColors(color, 8, cr, cg, cb, ca);
912 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
914 VectorSubtract(v, r_vieworigin, diff);
915 f2 = exp(fogdensity/DotProduct(diff, diff));
917 c[0] = c[0] * f1 + fogcolor[0] * f2;
918 c[1] = c[1] * f1 + fogcolor[1] * f2;
919 c[2] = c[2] * f1 + fogcolor[2] * f2;
922 memset(&m, 0, sizeof(m));
923 m.pointer_vertex = vertex3f;
924 m.pointer_color = color;
930 int nomodelelements[24] =
942 float nomodelvertex3f[6*3] =
952 float nomodelcolor4f[6*4] =
954 0.0f, 0.0f, 0.5f, 1.0f,
955 0.0f, 0.0f, 0.5f, 1.0f,
956 0.0f, 0.5f, 0.0f, 1.0f,
957 0.0f, 0.5f, 0.0f, 1.0f,
958 0.5f, 0.0f, 0.0f, 1.0f,
959 0.5f, 0.0f, 0.0f, 1.0f
962 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
964 const entity_render_t *ent = calldata1;
966 float f1, f2, *c, diff[3];
969 R_Mesh_Matrix(&ent->matrix);
971 memset(&m, 0, sizeof(m));
972 m.pointer_vertex = nomodelvertex3f;
974 if (ent->flags & EF_ADDITIVE)
976 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
979 else if (ent->alpha < 1)
981 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
986 GL_BlendFunc(GL_ONE, GL_ZERO);
989 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
992 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
993 m.pointer_color = color4f;
994 VectorSubtract(ent->origin, r_vieworigin, diff);
995 f2 = exp(fogdensity/DotProduct(diff, diff));
997 for (i = 0, c = color4f;i < 6;i++, c += 4)
999 c[0] = (c[0] * f1 + fogcolor[0] * f2);
1000 c[1] = (c[1] * f1 + fogcolor[1] * f2);
1001 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1005 else if (ent->alpha != 1)
1007 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1008 m.pointer_color = color4f;
1009 for (i = 0, c = color4f;i < 6;i++, c += 4)
1013 m.pointer_color = nomodelcolor4f;
1015 R_Mesh_Draw(6, 8, nomodelelements);
1018 void R_DrawNoModel(entity_render_t *ent)
1020 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1021 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1023 // R_DrawNoModelCallback(ent, 0);
1026 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1028 vec3_t right1, right2, diff, normal;
1030 VectorSubtract (org2, org1, normal);
1032 // calculate 'right' vector for start
1033 VectorSubtract (r_vieworigin, org1, diff);
1034 CrossProduct (normal, diff, right1);
1035 VectorNormalize (right1);
1037 // calculate 'right' vector for end
1038 VectorSubtract (r_vieworigin, org2, diff);
1039 CrossProduct (normal, diff, right2);
1040 VectorNormalize (right2);
1042 vert[ 0] = org1[0] + width * right1[0];
1043 vert[ 1] = org1[1] + width * right1[1];
1044 vert[ 2] = org1[2] + width * right1[2];
1045 vert[ 3] = org1[0] - width * right1[0];
1046 vert[ 4] = org1[1] - width * right1[1];
1047 vert[ 5] = org1[2] - width * right1[2];
1048 vert[ 6] = org2[0] - width * right2[0];
1049 vert[ 7] = org2[1] - width * right2[1];
1050 vert[ 8] = org2[2] - width * right2[2];
1051 vert[ 9] = org2[0] + width * right2[0];
1052 vert[10] = org2[1] + width * right2[1];
1053 vert[11] = org2[2] + width * right2[2];
1056 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1058 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)
1065 VectorSubtract(origin, r_vieworigin, diff);
1066 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1069 R_Mesh_Matrix(&r_identitymatrix);
1070 GL_BlendFunc(blendfunc1, blendfunc2);
1071 GL_DepthMask(false);
1072 GL_DepthTest(!depthdisable);
1074 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1075 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1076 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1077 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1078 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1079 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1080 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1081 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1082 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1083 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1084 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1085 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1087 memset(&m, 0, sizeof(m));
1088 m.tex[0] = R_GetTexture(texture);
1089 m.pointer_texcoord[0] = spritetexcoord2f;
1090 m.pointer_vertex = varray_vertex3f;
1092 GL_Color(cr, cg, cb, ca);
1093 R_Mesh_Draw(4, 2, polygonelements);