2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 // used for dlight push checking and other things
30 matrix4x4_t r_identitymatrix;
32 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights, c_meshs, c_meshelements, c_rt_lights, c_rt_clears, c_rt_scissored, c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris, c_rtcached_shadowmeshes, c_rtcached_shadowtris, c_bloom, c_bloomcopies, c_bloomcopypixels, c_bloomdraws, c_bloomdrawpixels;
34 // true during envmap command capture
37 // maximum visible distance (recalculated from world box each frame)
39 // brightness of world lightmaps and related lighting
40 // (often reduced when world rtlights are enabled)
41 float r_lightmapintensity;
42 // whether to draw world lights realtime, dlights realtime, and their shadows
44 qboolean r_rtworldshadows;
46 qboolean r_rtdlightshadows;
49 // forces all rendering to draw triangle outlines
66 matrix4x4_t r_view_matrix;
73 // 8.8 fraction of base light value
74 unsigned short d_lightstylevalue[256];
76 cvar_t r_showtris = {0, "r_showtris", "0"};
77 cvar_t r_drawentities = {0, "r_drawentities","1"};
78 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
79 cvar_t r_speeds = {0, "r_speeds","0"};
80 cvar_t r_fullbright = {0, "r_fullbright","0"};
81 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
82 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
83 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
84 cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
86 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
87 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
88 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
89 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
90 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
91 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
92 cvar_t gl_fogend = {0, "gl_fogend","0"};
94 cvar_t r_textureunits = {0, "r_textureunits", "32"};
96 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
97 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
98 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
99 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
101 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"};
102 cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"};
103 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
104 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
105 cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
106 rtexturepool_t *r_main_texturepool;
107 rtexture_t *r_bloom_texture_screen;
108 rtexture_t *r_bloom_texture_bloom;
110 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
113 for (i = 0;i < verts;i++)
124 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
127 for (i = 0;i < verts;i++)
139 float fog_density, fog_red, fog_green, fog_blue;
141 qboolean oldgl_fogenable;
142 void R_UpdateFog(void)
144 if (gamemode == GAME_NEHAHRA)
146 if (gl_fogenable.integer)
148 oldgl_fogenable = true;
149 fog_density = gl_fogdensity.value;
150 fog_red = gl_fogred.value;
151 fog_green = gl_foggreen.value;
152 fog_blue = gl_fogblue.value;
154 else if (oldgl_fogenable)
156 oldgl_fogenable = false;
165 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
166 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
167 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
172 fogdensity = -4000.0f / (fog_density * fog_density);
173 // fog color was already set
179 // FIXME: move this to client?
182 if (gamemode == GAME_NEHAHRA)
184 Cvar_Set("gl_fogenable", "0");
185 Cvar_Set("gl_fogdensity", "0.2");
186 Cvar_Set("gl_fogred", "0.3");
187 Cvar_Set("gl_foggreen", "0.3");
188 Cvar_Set("gl_fogblue", "0.3");
190 fog_density = fog_red = fog_green = fog_blue = 0.0f;
193 // FIXME: move this to client?
194 void FOG_registercvars(void)
196 if (gamemode == GAME_NEHAHRA)
198 Cvar_RegisterVariable (&gl_fogenable);
199 Cvar_RegisterVariable (&gl_fogdensity);
200 Cvar_RegisterVariable (&gl_fogred);
201 Cvar_RegisterVariable (&gl_foggreen);
202 Cvar_RegisterVariable (&gl_fogblue);
203 Cvar_RegisterVariable (&gl_fogstart);
204 Cvar_RegisterVariable (&gl_fogend);
208 void gl_main_start(void)
210 r_main_texturepool = R_AllocTexturePool();
211 r_bloom_texture_screen = NULL;
212 r_bloom_texture_bloom = NULL;
215 void gl_main_shutdown(void)
217 R_FreeTexturePool(&r_main_texturepool);
218 r_bloom_texture_screen = NULL;
219 r_bloom_texture_bloom = NULL;
222 extern void CL_ParseEntityLump(char *entitystring);
223 void gl_main_newmap(void)
225 // FIXME: move this code to client
227 char *entities, entname[MAX_QPATH];
231 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
232 l = strlen(entname) - 4;
233 if (l >= 0 && !strcmp(entname + l, ".bsp"))
235 strcpy(entname + l, ".ent");
236 if ((entities = FS_LoadFile(entname, tempmempool, true)))
238 CL_ParseEntityLump(entities);
243 if (cl.worldmodel->brush.entities)
244 CL_ParseEntityLump(cl.worldmodel->brush.entities);
248 void GL_Main_Init(void)
250 Matrix4x4_CreateIdentity(&r_identitymatrix);
251 // FIXME: move this to client?
253 Cvar_RegisterVariable(&r_showtris);
254 Cvar_RegisterVariable(&r_drawentities);
255 Cvar_RegisterVariable(&r_drawviewmodel);
256 Cvar_RegisterVariable(&r_speeds);
257 Cvar_RegisterVariable(&r_fullbrights);
258 Cvar_RegisterVariable(&r_wateralpha);
259 Cvar_RegisterVariable(&r_dynamic);
260 Cvar_RegisterVariable(&r_fullbright);
261 Cvar_RegisterVariable(&r_textureunits);
262 Cvar_RegisterVariable(&r_lerpsprites);
263 Cvar_RegisterVariable(&r_lerpmodels);
264 Cvar_RegisterVariable(&r_waterscroll);
265 Cvar_RegisterVariable(&r_watershader);
266 Cvar_RegisterVariable(&r_drawcollisionbrushes);
267 Cvar_RegisterVariable(&r_bloom);
268 Cvar_RegisterVariable(&r_bloom_intensity);
269 Cvar_RegisterVariable(&r_bloom_blur);
270 Cvar_RegisterVariable(&r_bloom_resolution);
271 Cvar_RegisterVariable(&r_bloom_power);
272 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
273 Cvar_SetValue("r_fullbrights", 0);
274 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
277 static vec3_t r_farclip_origin;
278 static vec3_t r_farclip_direction;
279 static vec_t r_farclip_directiondist;
280 static vec_t r_farclip_meshfarclip;
281 static int r_farclip_directionbit0;
282 static int r_farclip_directionbit1;
283 static int r_farclip_directionbit2;
285 // enlarge farclip to accomodate box
286 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
289 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
290 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
291 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
292 if (r_farclip_meshfarclip < d)
293 r_farclip_meshfarclip = d;
296 // return farclip value
297 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
301 VectorCopy(origin, r_farclip_origin);
302 VectorCopy(direction, r_farclip_direction);
303 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
304 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
305 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
306 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
307 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
309 if (r_refdef.worldmodel)
310 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
311 for (i = 0;i < r_refdef.numentities;i++)
312 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
314 return r_farclip_meshfarclip - r_farclip_directiondist;
317 extern void R_Textures_Init(void);
318 extern void Mod_RenderInit(void);
319 extern void GL_Draw_Init(void);
320 extern void GL_Main_Init(void);
321 extern void R_Shadow_Init(void);
322 extern void GL_Models_Init(void);
323 extern void R_Sky_Init(void);
324 extern void GL_Surf_Init(void);
325 extern void R_Crosshairs_Init(void);
326 extern void R_Light_Init(void);
327 extern void R_Particles_Init(void);
328 extern void R_Explosion_Init(void);
329 extern void ui_init(void);
330 extern void gl_backend_init(void);
331 extern void Sbar_Init(void);
332 extern void R_LightningBeams_Init(void);
334 void Render_Init(void)
353 R_LightningBeams_Init();
361 extern char *ENGINE_EXTENSIONS;
364 VID_CheckExtensions();
366 // LordHavoc: report supported extensions
367 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
369 // clear to black (loading plaque will be seen over this)
370 qglClearColor(0,0,0,1);
371 qglClear(GL_COLOR_BUFFER_BIT);
374 int R_CullBox(const vec3_t mins, const vec3_t maxs)
378 for (i = 0;i < 4;i++)
385 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
389 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
393 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
397 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
401 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
405 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
409 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
413 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
421 //==================================================================================
423 static void R_MarkEntities (void)
426 entity_render_t *ent;
428 if (!r_drawentities.integer)
431 for (i = 0;i < r_refdef.numentities;i++)
433 ent = r_refdef.entities[i];
434 Mod_CheckLoaded(ent->model);
435 // some of the renderer still relies on origin...
436 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
437 // some of the renderer still relies on scale...
438 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
439 R_UpdateEntLights(ent);
440 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
441 && (!VIS_CullBox(ent->mins, ent->maxs) || (ent->effects & EF_NODEPTHTEST))
442 && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
443 ent->visframe = r_framecount;
447 // only used if skyrendermasked, and normally returns false
448 int R_DrawBrushModelsSky (void)
451 entity_render_t *ent;
453 if (!r_drawentities.integer)
457 for (i = 0;i < r_refdef.numentities;i++)
459 ent = r_refdef.entities[i];
460 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
462 ent->model->DrawSky(ent);
469 void R_DrawNoModel(entity_render_t *ent);
470 void R_DrawModels(void)
473 entity_render_t *ent;
475 if (!r_drawentities.integer)
478 for (i = 0;i < r_refdef.numentities;i++)
480 ent = r_refdef.entities[i];
481 if (ent->visframe == r_framecount)
483 if (ent->model && ent->model->Draw != NULL)
484 ent->model->Draw(ent);
491 static void R_SetFrustum(void)
493 // break apart the view matrix into vectors for various purposes
494 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
495 VectorNegate(r_viewleft, r_viewright);
497 // LordHavoc: note to all quake engine coders, the special case for 90
498 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
501 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
502 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
503 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
504 PlaneClassify(&frustum[0]);
506 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
507 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
508 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
509 PlaneClassify(&frustum[1]);
511 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
512 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
513 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
514 PlaneClassify(&frustum[2]);
516 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
517 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
518 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
519 PlaneClassify(&frustum[3]);
522 static void R_BlendView(void)
526 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
529 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
532 R_Mesh_Matrix(&r_identitymatrix);
533 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
534 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
535 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
536 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
537 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)
539 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
540 float xoffset, yoffset, r;
542 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
543 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
544 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
545 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
546 varray_texcoord2f[0][0] = 0;
547 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
548 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
549 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
550 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
551 varray_texcoord2f[0][5] = 0;
552 varray_texcoord2f[0][6] = 0;
553 varray_texcoord2f[0][7] = 0;
554 varray_texcoord2f[1][0] = 0;
555 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
556 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
557 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
558 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
559 varray_texcoord2f[1][5] = 0;
560 varray_texcoord2f[1][6] = 0;
561 varray_texcoord2f[1][7] = 0;
562 if (!r_bloom_texture_screen)
563 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
564 if (!r_bloom_texture_bloom)
565 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
566 memset(&m, 0, sizeof(m));
567 m.pointer_vertex = varray_vertex3f;
568 m.pointer_texcoord[0] = varray_texcoord2f[0];
569 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
571 // copy view to a texture
573 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
575 c_bloomcopypixels += r_view_width * r_view_height;
576 // now scale it down to the bloom size and raise to a power of itself
577 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
578 // TODO: optimize with multitexture or GLSL
579 GL_BlendFunc(GL_ONE, GL_ZERO);
580 GL_Color(1, 1, 1, 1);
581 R_Mesh_Draw(4, 2, polygonelements);
583 c_bloomdrawpixels += bloomwidth * bloomheight;
584 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
585 for (x = 1;x < r_bloom_power.integer;x++)
587 R_Mesh_Draw(4, 2, polygonelements);
589 c_bloomdrawpixels += bloomwidth * bloomheight;
591 // copy the bloom view to a texture
592 memset(&m, 0, sizeof(m));
593 m.pointer_vertex = varray_vertex3f;
594 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
595 m.pointer_texcoord[0] = varray_texcoord2f[2];
598 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
600 c_bloomcopypixels += bloomwidth * bloomheight;
601 // blend on at multiple offsets vertically
602 // TODO: do offset blends using GLSL
603 range = r_bloom_blur.integer * bloomwidth / 320;
604 GL_BlendFunc(GL_ONE, GL_ZERO);
605 for (x = -range;x <= range;x++)
607 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
608 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
609 varray_texcoord2f[2][0] = xoffset+0;
610 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
611 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
612 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
613 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
614 varray_texcoord2f[2][5] = yoffset+0;
615 varray_texcoord2f[2][6] = xoffset+0;
616 varray_texcoord2f[2][7] = yoffset+0;
617 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
620 GL_Color(r, r, r, 1);
621 R_Mesh_Draw(4, 2, polygonelements);
623 c_bloomdrawpixels += bloomwidth * bloomheight;
624 GL_BlendFunc(GL_ONE, GL_ONE);
626 // copy the blurred bloom view to a texture
628 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
630 c_bloomcopypixels += bloomwidth * bloomheight;
631 // blend on at multiple offsets horizontally
632 // TODO: do offset blends using GLSL
633 range = r_bloom_blur.integer * bloomwidth / 320;
634 GL_BlendFunc(GL_ONE, GL_ZERO);
635 for (x = -range;x <= range;x++)
637 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
638 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
639 varray_texcoord2f[2][0] = xoffset+0;
640 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
641 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
642 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
643 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
644 varray_texcoord2f[2][5] = yoffset+0;
645 varray_texcoord2f[2][6] = xoffset+0;
646 varray_texcoord2f[2][7] = yoffset+0;
647 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
650 GL_Color(r, r, r, 1);
651 R_Mesh_Draw(4, 2, polygonelements);
653 c_bloomdrawpixels += bloomwidth * bloomheight;
654 GL_BlendFunc(GL_ONE, GL_ONE);
656 // copy the blurred bloom view to a texture
658 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
660 c_bloomcopypixels += bloomwidth * bloomheight;
661 // go back to full view area
662 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
663 // put the original view back in place
664 memset(&m, 0, sizeof(m));
665 m.pointer_vertex = varray_vertex3f;
666 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
667 m.pointer_texcoord[0] = varray_texcoord2f[0];
669 dobloomblend = false;
671 // do both in one pass if possible
672 if (r_textureunits.integer >= 2 && gl_combine.integer)
674 dobloomblend = false;
675 m.texcombinergb[1] = GL_ADD;
676 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
677 m.pointer_texcoord[1] = varray_texcoord2f[1];
683 GL_BlendFunc(GL_ONE, GL_ZERO);
685 R_Mesh_Draw(4, 2, polygonelements);
687 c_bloomdrawpixels += r_view_width * r_view_height;
688 // now blend on the bloom texture if multipass
691 memset(&m, 0, sizeof(m));
692 m.pointer_vertex = varray_vertex3f;
693 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
694 m.pointer_texcoord[0] = varray_texcoord2f[1];
696 GL_BlendFunc(GL_ONE, GL_ONE);
698 R_Mesh_Draw(4, 2, polygonelements);
700 c_bloomdrawpixels += r_view_width * r_view_height;
703 if (r_refdef.viewblend[3] >= 0.01f)
705 // apply a color tint to the whole view
706 memset(&m, 0, sizeof(m));
707 m.pointer_vertex = varray_vertex3f;
709 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
710 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
711 R_Mesh_Draw(4, 2, polygonelements);
715 void R_RenderScene(void);
722 void R_RenderView(void)
724 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
725 return; //Host_Error ("R_RenderView: NULL worldmodel");
727 r_view_width = bound(0, r_refdef.width, vid.realwidth);
728 r_view_height = bound(0, r_refdef.height, vid.realheight);
730 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
731 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
733 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
734 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
735 r_view_matrix = r_refdef.viewentitymatrix;
736 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
737 r_rtworld = r_shadow_realtime_world.integer;
738 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
739 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
740 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
741 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
743 // GL is weird because it's bottom to top, r_view_y is top to bottom
744 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
745 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
746 GL_ScissorTest(true);
752 R_TimeReport("setup");
754 qglDepthFunc(GL_LEQUAL);
755 qglPolygonOffset(0, 0);
756 qglEnable(GL_POLYGON_OFFSET_FILL);
760 qglPolygonOffset(0, 0);
761 qglDisable(GL_POLYGON_OFFSET_FILL);
764 R_TimeReport("blendview");
766 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
767 GL_ScissorTest(false);
770 extern void R_DrawLightningBeams (void);
771 void R_RenderScene(void)
773 // don't let sound skip if going slow
774 if (r_refdef.extraupdate)
779 R_MeshQueue_BeginScene();
781 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
785 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
786 if (r_rtworldshadows || r_rtdlightshadows)
787 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
789 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
791 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
796 R_TimeReport("worldvis");
799 R_TimeReport("markentity");
801 R_Shadow_UpdateWorldLightSelection();
803 // don't let sound skip if going slow
804 if (r_refdef.extraupdate)
807 GL_ShowTrisColor(0.025, 0.025, 0, 1);
808 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
810 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
811 R_TimeReport("worldsky");
814 if (R_DrawBrushModelsSky())
815 R_TimeReport("bmodelsky");
817 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
818 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
820 r_refdef.worldmodel->Draw(r_refdef.worldentity);
821 R_TimeReport("world");
824 // don't let sound skip if going slow
825 if (r_refdef.extraupdate)
828 GL_ShowTrisColor(0, 0.015, 0, 1);
831 R_TimeReport("models");
833 // don't let sound skip if going slow
834 if (r_refdef.extraupdate)
837 GL_ShowTrisColor(0, 0, 0.033, 1);
838 R_ShadowVolumeLighting(false);
839 R_TimeReport("rtlights");
841 // don't let sound skip if going slow
842 if (r_refdef.extraupdate)
845 GL_ShowTrisColor(0.1, 0, 0, 1);
847 R_DrawLightningBeams();
848 R_TimeReport("lightning");
851 R_TimeReport("particles");
854 R_TimeReport("explosions");
856 R_MeshQueue_RenderTransparent();
857 R_TimeReport("drawtrans");
860 R_TimeReport("coronas");
862 R_DrawWorldCrosshair();
863 R_TimeReport("crosshair");
865 R_MeshQueue_Render();
866 R_MeshQueue_EndScene();
868 if (r_shadow_visiblevolumes.integer && !r_showtrispass)
870 R_ShadowVolumeLighting(true);
871 R_TimeReport("shadowvolume");
874 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
876 // don't let sound skip if going slow
877 if (r_refdef.extraupdate)
882 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
885 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
887 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
890 R_Mesh_Matrix(&r_identitymatrix);
892 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
893 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
894 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
895 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
896 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
897 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
898 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
899 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
900 R_FillColors(color, 8, cr, cg, cb, ca);
903 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
905 VectorSubtract(v, r_vieworigin, diff);
906 f2 = exp(fogdensity/DotProduct(diff, diff));
908 c[0] = c[0] * f1 + fogcolor[0] * f2;
909 c[1] = c[1] * f1 + fogcolor[1] * f2;
910 c[2] = c[2] * f1 + fogcolor[2] * f2;
913 memset(&m, 0, sizeof(m));
914 m.pointer_vertex = vertex3f;
915 m.pointer_color = color;
921 int nomodelelements[24] =
933 float nomodelvertex3f[6*3] =
943 float nomodelcolor4f[6*4] =
945 0.0f, 0.0f, 0.5f, 1.0f,
946 0.0f, 0.0f, 0.5f, 1.0f,
947 0.0f, 0.5f, 0.0f, 1.0f,
948 0.0f, 0.5f, 0.0f, 1.0f,
949 0.5f, 0.0f, 0.0f, 1.0f,
950 0.5f, 0.0f, 0.0f, 1.0f
953 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
955 const entity_render_t *ent = calldata1;
957 float f1, f2, *c, diff[3];
960 R_Mesh_Matrix(&ent->matrix);
962 memset(&m, 0, sizeof(m));
963 m.pointer_vertex = nomodelvertex3f;
965 if (ent->flags & EF_ADDITIVE)
967 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
970 else if (ent->alpha < 1)
972 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
977 GL_BlendFunc(GL_ONE, GL_ZERO);
980 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
983 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
984 m.pointer_color = color4f;
985 VectorSubtract(ent->origin, r_vieworigin, diff);
986 f2 = exp(fogdensity/DotProduct(diff, diff));
988 for (i = 0, c = color4f;i < 6;i++, c += 4)
990 c[0] = (c[0] * f1 + fogcolor[0] * f2);
991 c[1] = (c[1] * f1 + fogcolor[1] * f2);
992 c[2] = (c[2] * f1 + fogcolor[2] * f2);
996 else if (ent->alpha != 1)
998 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
999 m.pointer_color = color4f;
1000 for (i = 0, c = color4f;i < 6;i++, c += 4)
1004 m.pointer_color = nomodelcolor4f;
1006 R_Mesh_Draw(6, 8, nomodelelements);
1009 void R_DrawNoModel(entity_render_t *ent)
1011 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1012 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1014 // R_DrawNoModelCallback(ent, 0);
1017 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1019 vec3_t right1, right2, diff, normal;
1021 VectorSubtract (org2, org1, normal);
1023 // calculate 'right' vector for start
1024 VectorSubtract (r_vieworigin, org1, diff);
1025 CrossProduct (normal, diff, right1);
1026 VectorNormalize (right1);
1028 // calculate 'right' vector for end
1029 VectorSubtract (r_vieworigin, org2, diff);
1030 CrossProduct (normal, diff, right2);
1031 VectorNormalize (right2);
1033 vert[ 0] = org1[0] + width * right1[0];
1034 vert[ 1] = org1[1] + width * right1[1];
1035 vert[ 2] = org1[2] + width * right1[2];
1036 vert[ 3] = org1[0] - width * right1[0];
1037 vert[ 4] = org1[1] - width * right1[1];
1038 vert[ 5] = org1[2] - width * right1[2];
1039 vert[ 6] = org2[0] - width * right2[0];
1040 vert[ 7] = org2[1] - width * right2[1];
1041 vert[ 8] = org2[2] - width * right2[2];
1042 vert[ 9] = org2[0] + width * right2[0];
1043 vert[10] = org2[1] + width * right2[1];
1044 vert[11] = org2[2] + width * right2[2];
1047 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1049 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)
1056 VectorSubtract(origin, r_vieworigin, diff);
1057 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1060 R_Mesh_Matrix(&r_identitymatrix);
1061 GL_BlendFunc(blendfunc1, blendfunc2);
1062 GL_DepthMask(false);
1063 GL_DepthTest(!depthdisable);
1065 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1066 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1067 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1068 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1069 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1070 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1071 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1072 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1073 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1074 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1075 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1076 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1078 memset(&m, 0, sizeof(m));
1079 m.tex[0] = R_GetTexture(texture);
1080 m.pointer_texcoord[0] = spritetexcoord2f;
1081 m.pointer_vertex = varray_vertex3f;
1083 GL_Color(cr, cg, cb, ca);
1084 R_Mesh_Draw(4, 2, polygonelements);