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", "320"};
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 R_FreeTexturePool(&r_main_texturepool);
221 r_bloom_texture_screen = NULL;
222 r_bloom_texture_bloom = NULL;
225 extern void CL_ParseEntityLump(char *entitystring);
226 void gl_main_newmap(void)
228 // FIXME: move this code to client
230 char *entities, entname[MAX_QPATH];
234 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
235 l = strlen(entname) - 4;
236 if (l >= 0 && !strcmp(entname + l, ".bsp"))
238 strcpy(entname + l, ".ent");
239 if ((entities = FS_LoadFile(entname, tempmempool, true)))
241 CL_ParseEntityLump(entities);
246 if (cl.worldmodel->brush.entities)
247 CL_ParseEntityLump(cl.worldmodel->brush.entities);
251 void GL_Main_Init(void)
253 Matrix4x4_CreateIdentity(&r_identitymatrix);
254 // FIXME: move this to client?
256 Cvar_RegisterVariable(&r_showtris);
257 Cvar_RegisterVariable(&r_drawentities);
258 Cvar_RegisterVariable(&r_drawviewmodel);
259 Cvar_RegisterVariable(&r_speeds);
260 Cvar_RegisterVariable(&r_fullbrights);
261 Cvar_RegisterVariable(&r_wateralpha);
262 Cvar_RegisterVariable(&r_dynamic);
263 Cvar_RegisterVariable(&r_fullbright);
264 Cvar_RegisterVariable(&r_textureunits);
265 Cvar_RegisterVariable(&r_lerpsprites);
266 Cvar_RegisterVariable(&r_lerpmodels);
267 Cvar_RegisterVariable(&r_waterscroll);
268 Cvar_RegisterVariable(&r_watershader);
269 Cvar_RegisterVariable(&r_drawcollisionbrushes);
270 Cvar_RegisterVariable(&r_bloom);
271 Cvar_RegisterVariable(&r_bloom_intensity);
272 Cvar_RegisterVariable(&r_bloom_blur);
273 Cvar_RegisterVariable(&r_bloom_resolution);
274 Cvar_RegisterVariable(&r_bloom_power);
275 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
276 Cvar_SetValue("r_fullbrights", 0);
277 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
280 static vec3_t r_farclip_origin;
281 static vec3_t r_farclip_direction;
282 static vec_t r_farclip_directiondist;
283 static vec_t r_farclip_meshfarclip;
284 static int r_farclip_directionbit0;
285 static int r_farclip_directionbit1;
286 static int r_farclip_directionbit2;
288 // enlarge farclip to accomodate box
289 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
292 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
293 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
294 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
295 if (r_farclip_meshfarclip < d)
296 r_farclip_meshfarclip = d;
299 // return farclip value
300 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
304 VectorCopy(origin, r_farclip_origin);
305 VectorCopy(direction, r_farclip_direction);
306 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
307 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
308 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
309 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
310 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
312 if (r_refdef.worldmodel)
313 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
314 for (i = 0;i < r_refdef.numentities;i++)
315 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
317 return r_farclip_meshfarclip - r_farclip_directiondist;
320 extern void R_Textures_Init(void);
321 extern void Mod_RenderInit(void);
322 extern void GL_Draw_Init(void);
323 extern void GL_Main_Init(void);
324 extern void R_Shadow_Init(void);
325 extern void GL_Models_Init(void);
326 extern void R_Sky_Init(void);
327 extern void GL_Surf_Init(void);
328 extern void R_Crosshairs_Init(void);
329 extern void R_Light_Init(void);
330 extern void R_Particles_Init(void);
331 extern void R_Explosion_Init(void);
332 extern void ui_init(void);
333 extern void gl_backend_init(void);
334 extern void Sbar_Init(void);
335 extern void R_LightningBeams_Init(void);
337 void Render_Init(void)
356 R_LightningBeams_Init();
364 extern char *ENGINE_EXTENSIONS;
367 VID_CheckExtensions();
369 // LordHavoc: report supported extensions
370 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
372 // clear to black (loading plaque will be seen over this)
373 qglClearColor(0,0,0,1);
374 qglClear(GL_COLOR_BUFFER_BIT);
377 int R_CullBox(const vec3_t mins, const vec3_t maxs)
381 for (i = 0;i < 4;i++)
388 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
392 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
396 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
400 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
404 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
408 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
412 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
416 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
424 //==================================================================================
426 static void R_MarkEntities (void)
429 entity_render_t *ent;
431 if (!r_drawentities.integer)
434 for (i = 0;i < r_refdef.numentities;i++)
436 ent = r_refdef.entities[i];
437 Mod_CheckLoaded(ent->model);
438 // some of the renderer still relies on origin...
439 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
440 // some of the renderer still relies on scale...
441 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
442 R_UpdateEntLights(ent);
443 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
444 && (!VIS_CullBox(ent->mins, ent->maxs) || (ent->effects & EF_NODEPTHTEST))
445 && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
446 ent->visframe = r_framecount;
450 // only used if skyrendermasked, and normally returns false
451 int R_DrawBrushModelsSky (void)
454 entity_render_t *ent;
456 if (!r_drawentities.integer)
460 for (i = 0;i < r_refdef.numentities;i++)
462 ent = r_refdef.entities[i];
463 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
465 ent->model->DrawSky(ent);
472 void R_DrawNoModel(entity_render_t *ent);
473 void R_DrawModels(void)
476 entity_render_t *ent;
478 if (!r_drawentities.integer)
481 for (i = 0;i < r_refdef.numentities;i++)
483 ent = r_refdef.entities[i];
484 if (ent->visframe == r_framecount)
486 if (ent->model && ent->model->Draw != NULL)
487 ent->model->Draw(ent);
494 static void R_SetFrustum(void)
496 // break apart the view matrix into vectors for various purposes
497 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
498 VectorNegate(r_viewleft, r_viewright);
500 // LordHavoc: note to all quake engine coders, the special case for 90
501 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
504 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
505 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
506 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
507 PlaneClassify(&frustum[0]);
509 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
510 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
511 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
512 PlaneClassify(&frustum[1]);
514 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
515 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
516 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
517 PlaneClassify(&frustum[2]);
519 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
520 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
521 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
522 PlaneClassify(&frustum[3]);
525 static void R_BlendView(void)
529 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
532 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
535 R_Mesh_Matrix(&r_identitymatrix);
536 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
537 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
538 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
539 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
540 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)
542 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
543 float xoffset, yoffset, r;
545 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
546 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
547 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
548 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
549 varray_texcoord2f[0][0] = 0;
550 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
551 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
552 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
553 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
554 varray_texcoord2f[0][5] = 0;
555 varray_texcoord2f[0][6] = 0;
556 varray_texcoord2f[0][7] = 0;
557 varray_texcoord2f[1][0] = 0;
558 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
559 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
560 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
561 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
562 varray_texcoord2f[1][5] = 0;
563 varray_texcoord2f[1][6] = 0;
564 varray_texcoord2f[1][7] = 0;
565 if (!r_bloom_texture_screen)
566 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
567 if (!r_bloom_texture_bloom)
568 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
569 memset(&m, 0, sizeof(m));
570 m.pointer_vertex = varray_vertex3f;
571 m.pointer_texcoord[0] = varray_texcoord2f[0];
572 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
574 // copy view to a texture
576 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
578 c_bloomcopypixels += r_view_width * r_view_height;
579 // now scale it down to the bloom size and raise to a power of itself
580 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
581 // TODO: optimize with multitexture or GLSL
582 GL_BlendFunc(GL_ONE, GL_ZERO);
583 GL_Color(1, 1, 1, 1);
584 R_Mesh_Draw(4, 2, polygonelements);
586 c_bloomdrawpixels += bloomwidth * bloomheight;
587 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
588 for (x = 1;x < r_bloom_power.integer;x++)
590 R_Mesh_Draw(4, 2, polygonelements);
592 c_bloomdrawpixels += bloomwidth * bloomheight;
594 // copy the bloom view to a texture
595 memset(&m, 0, sizeof(m));
596 m.pointer_vertex = varray_vertex3f;
597 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
598 m.pointer_texcoord[0] = varray_texcoord2f[2];
601 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
603 c_bloomcopypixels += bloomwidth * bloomheight;
604 // blend on at multiple offsets vertically
605 // TODO: do offset blends using GLSL
606 range = r_bloom_blur.integer * bloomwidth / 320;
607 GL_BlendFunc(GL_ONE, GL_ZERO);
608 for (x = -range;x <= range;x++)
610 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
611 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
612 varray_texcoord2f[2][0] = xoffset+0;
613 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
614 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
615 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
616 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
617 varray_texcoord2f[2][5] = yoffset+0;
618 varray_texcoord2f[2][6] = xoffset+0;
619 varray_texcoord2f[2][7] = yoffset+0;
620 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
623 GL_Color(r, r, r, 1);
624 R_Mesh_Draw(4, 2, polygonelements);
626 c_bloomdrawpixels += bloomwidth * bloomheight;
627 GL_BlendFunc(GL_ONE, GL_ONE);
629 // copy the blurred bloom view to a texture
631 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
633 c_bloomcopypixels += bloomwidth * bloomheight;
634 // blend on at multiple offsets horizontally
635 // TODO: do offset blends using GLSL
636 range = r_bloom_blur.integer * bloomwidth / 320;
637 GL_BlendFunc(GL_ONE, GL_ZERO);
638 for (x = -range;x <= range;x++)
640 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
641 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
642 varray_texcoord2f[2][0] = xoffset+0;
643 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
644 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
645 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
646 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
647 varray_texcoord2f[2][5] = yoffset+0;
648 varray_texcoord2f[2][6] = xoffset+0;
649 varray_texcoord2f[2][7] = yoffset+0;
650 r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
653 GL_Color(r, r, r, 1);
654 R_Mesh_Draw(4, 2, polygonelements);
656 c_bloomdrawpixels += bloomwidth * bloomheight;
657 GL_BlendFunc(GL_ONE, GL_ONE);
659 // copy the blurred bloom view to a texture
661 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
663 c_bloomcopypixels += bloomwidth * bloomheight;
664 // go back to full view area
665 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
666 // put the original view back in place
667 memset(&m, 0, sizeof(m));
668 m.pointer_vertex = varray_vertex3f;
669 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
670 m.pointer_texcoord[0] = varray_texcoord2f[0];
672 dobloomblend = false;
674 // do both in one pass if possible
675 if (r_textureunits.integer >= 2 && gl_combine.integer)
677 dobloomblend = false;
678 m.texcombinergb[1] = GL_ADD;
679 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
680 m.pointer_texcoord[1] = varray_texcoord2f[1];
686 GL_BlendFunc(GL_ONE, GL_ZERO);
688 R_Mesh_Draw(4, 2, polygonelements);
690 c_bloomdrawpixels += r_view_width * r_view_height;
691 // now blend on the bloom texture if multipass
694 memset(&m, 0, sizeof(m));
695 m.pointer_vertex = varray_vertex3f;
696 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
697 m.pointer_texcoord[0] = varray_texcoord2f[1];
699 GL_BlendFunc(GL_ONE, GL_ONE);
701 R_Mesh_Draw(4, 2, polygonelements);
703 c_bloomdrawpixels += r_view_width * r_view_height;
706 if (r_refdef.viewblend[3] >= 0.01f)
708 // apply a color tint to the whole view
709 memset(&m, 0, sizeof(m));
710 m.pointer_vertex = varray_vertex3f;
712 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
713 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
714 R_Mesh_Draw(4, 2, polygonelements);
718 void R_RenderScene(void);
725 void R_RenderView(void)
727 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
728 return; //Host_Error ("R_RenderView: NULL worldmodel");
730 r_view_width = bound(0, r_refdef.width, vid.realwidth);
731 r_view_height = bound(0, r_refdef.height, vid.realheight);
733 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
734 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
736 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
737 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
738 r_view_matrix = r_refdef.viewentitymatrix;
739 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
740 r_rtworld = r_shadow_realtime_world.integer;
741 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
742 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
743 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
744 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
746 // GL is weird because it's bottom to top, r_view_y is top to bottom
747 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
748 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
749 GL_ScissorTest(true);
755 R_TimeReport("setup");
757 qglDepthFunc(GL_LEQUAL);
758 qglPolygonOffset(0, 0);
759 qglEnable(GL_POLYGON_OFFSET_FILL);
763 qglPolygonOffset(0, 0);
764 qglDisable(GL_POLYGON_OFFSET_FILL);
767 R_TimeReport("blendview");
769 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
770 GL_ScissorTest(false);
773 extern void R_DrawLightningBeams (void);
774 void R_RenderScene(void)
776 // don't let sound skip if going slow
777 if (r_refdef.extraupdate)
782 R_MeshQueue_BeginScene();
784 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
788 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
789 if (r_rtworldshadows || r_rtdlightshadows)
790 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
792 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
794 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
798 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.FatPVS)
799 r_refdef.worldmodel->brush.FatPVS(r_refdef.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
801 R_TimeReport("worldvis");
804 R_TimeReport("markentity");
806 R_Shadow_UpdateWorldLightSelection();
808 // don't let sound skip if going slow
809 if (r_refdef.extraupdate)
812 GL_ShowTrisColor(0.025, 0.025, 0, 1);
813 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
815 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
816 R_TimeReport("worldsky");
819 if (R_DrawBrushModelsSky())
820 R_TimeReport("bmodelsky");
822 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
823 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
825 r_refdef.worldmodel->Draw(r_refdef.worldentity);
826 R_TimeReport("world");
829 // don't let sound skip if going slow
830 if (r_refdef.extraupdate)
833 GL_ShowTrisColor(0, 0.015, 0, 1);
836 R_TimeReport("models");
838 // don't let sound skip if going slow
839 if (r_refdef.extraupdate)
842 GL_ShowTrisColor(0, 0, 0.033, 1);
843 R_ShadowVolumeLighting(false);
844 R_TimeReport("rtlights");
846 // don't let sound skip if going slow
847 if (r_refdef.extraupdate)
850 GL_ShowTrisColor(0.1, 0, 0, 1);
852 R_DrawLightningBeams();
853 R_TimeReport("lightning");
856 R_TimeReport("particles");
859 R_TimeReport("explosions");
861 R_MeshQueue_RenderTransparent();
862 R_TimeReport("drawtrans");
865 R_TimeReport("coronas");
867 R_DrawWorldCrosshair();
868 R_TimeReport("crosshair");
870 R_MeshQueue_Render();
871 R_MeshQueue_EndScene();
873 if (r_shadow_visiblevolumes.integer && !r_showtrispass)
875 R_ShadowVolumeLighting(true);
876 R_TimeReport("shadowvolume");
879 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
881 // don't let sound skip if going slow
882 if (r_refdef.extraupdate)
887 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
890 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
892 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
895 R_Mesh_Matrix(&r_identitymatrix);
897 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
898 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
899 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
900 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
901 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
902 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
903 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
904 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
905 R_FillColors(color, 8, cr, cg, cb, ca);
908 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
910 VectorSubtract(v, r_vieworigin, diff);
911 f2 = exp(fogdensity/DotProduct(diff, diff));
913 c[0] = c[0] * f1 + fogcolor[0] * f2;
914 c[1] = c[1] * f1 + fogcolor[1] * f2;
915 c[2] = c[2] * f1 + fogcolor[2] * f2;
918 memset(&m, 0, sizeof(m));
919 m.pointer_vertex = vertex3f;
920 m.pointer_color = color;
926 int nomodelelements[24] =
938 float nomodelvertex3f[6*3] =
948 float nomodelcolor4f[6*4] =
950 0.0f, 0.0f, 0.5f, 1.0f,
951 0.0f, 0.0f, 0.5f, 1.0f,
952 0.0f, 0.5f, 0.0f, 1.0f,
953 0.0f, 0.5f, 0.0f, 1.0f,
954 0.5f, 0.0f, 0.0f, 1.0f,
955 0.5f, 0.0f, 0.0f, 1.0f
958 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
960 const entity_render_t *ent = calldata1;
962 float f1, f2, *c, diff[3];
965 R_Mesh_Matrix(&ent->matrix);
967 memset(&m, 0, sizeof(m));
968 m.pointer_vertex = nomodelvertex3f;
970 if (ent->flags & EF_ADDITIVE)
972 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
975 else if (ent->alpha < 1)
977 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
982 GL_BlendFunc(GL_ONE, GL_ZERO);
985 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
988 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
989 m.pointer_color = color4f;
990 VectorSubtract(ent->origin, r_vieworigin, diff);
991 f2 = exp(fogdensity/DotProduct(diff, diff));
993 for (i = 0, c = color4f;i < 6;i++, c += 4)
995 c[0] = (c[0] * f1 + fogcolor[0] * f2);
996 c[1] = (c[1] * f1 + fogcolor[1] * f2);
997 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1001 else if (ent->alpha != 1)
1003 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1004 m.pointer_color = color4f;
1005 for (i = 0, c = color4f;i < 6;i++, c += 4)
1009 m.pointer_color = nomodelcolor4f;
1011 R_Mesh_Draw(6, 8, nomodelelements);
1014 void R_DrawNoModel(entity_render_t *ent)
1016 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1017 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1019 // R_DrawNoModelCallback(ent, 0);
1022 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1024 vec3_t right1, right2, diff, normal;
1026 VectorSubtract (org2, org1, normal);
1028 // calculate 'right' vector for start
1029 VectorSubtract (r_vieworigin, org1, diff);
1030 CrossProduct (normal, diff, right1);
1031 VectorNormalize (right1);
1033 // calculate 'right' vector for end
1034 VectorSubtract (r_vieworigin, org2, diff);
1035 CrossProduct (normal, diff, right2);
1036 VectorNormalize (right2);
1038 vert[ 0] = org1[0] + width * right1[0];
1039 vert[ 1] = org1[1] + width * right1[1];
1040 vert[ 2] = org1[2] + width * right1[2];
1041 vert[ 3] = org1[0] - width * right1[0];
1042 vert[ 4] = org1[1] - width * right1[1];
1043 vert[ 5] = org1[2] - width * right1[2];
1044 vert[ 6] = org2[0] - width * right2[0];
1045 vert[ 7] = org2[1] - width * right2[1];
1046 vert[ 8] = org2[2] - width * right2[2];
1047 vert[ 9] = org2[0] + width * right2[0];
1048 vert[10] = org2[1] + width * right2[1];
1049 vert[11] = org2[2] + width * right2[2];
1052 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1054 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)
1061 VectorSubtract(origin, r_vieworigin, diff);
1062 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1065 R_Mesh_Matrix(&r_identitymatrix);
1066 GL_BlendFunc(blendfunc1, blendfunc2);
1067 GL_DepthMask(false);
1068 GL_DepthTest(!depthdisable);
1070 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1071 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1072 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1073 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1074 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1075 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1076 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1077 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1078 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1079 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1080 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1081 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1083 memset(&m, 0, sizeof(m));
1084 m.tex[0] = R_GetTexture(texture);
1085 m.pointer_texcoord[0] = spritetexcoord2f;
1086 m.pointer_vertex = varray_vertex3f;
1088 GL_Color(cr, cg, cb, ca);
1089 R_Mesh_Draw(4, 2, polygonelements);