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"};
107 cvar_t developer_texturelogging = {0, "developer_texturelogging", "1"};
109 rtexturepool_t *r_main_texturepool;
110 rtexture_t *r_bloom_texture_screen;
111 rtexture_t *r_bloom_texture_bloom;
112 rtexture_t *r_texture_blanknormalmap;
113 rtexture_t *r_texture_white;
114 rtexture_t *r_texture_black;
115 rtexture_t *r_texture_notexture;
116 rtexture_t *r_texture_whitecube;
117 rtexture_t *r_texture_normalizationcube;
119 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
122 for (i = 0;i < verts;i++)
133 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
136 for (i = 0;i < verts;i++)
148 float fog_density, fog_red, fog_green, fog_blue;
150 qboolean oldgl_fogenable;
151 void R_UpdateFog(void)
153 if (gamemode == GAME_NEHAHRA)
155 if (gl_fogenable.integer)
157 oldgl_fogenable = true;
158 fog_density = gl_fogdensity.value;
159 fog_red = gl_fogred.value;
160 fog_green = gl_foggreen.value;
161 fog_blue = gl_fogblue.value;
163 else if (oldgl_fogenable)
165 oldgl_fogenable = false;
174 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
175 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
176 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
181 fogdensity = -4000.0f / (fog_density * fog_density);
182 // fog color was already set
188 // FIXME: move this to client?
191 if (gamemode == GAME_NEHAHRA)
193 Cvar_Set("gl_fogenable", "0");
194 Cvar_Set("gl_fogdensity", "0.2");
195 Cvar_Set("gl_fogred", "0.3");
196 Cvar_Set("gl_foggreen", "0.3");
197 Cvar_Set("gl_fogblue", "0.3");
199 fog_density = fog_red = fog_green = fog_blue = 0.0f;
202 // FIXME: move this to client?
203 void FOG_registercvars(void)
205 if (gamemode == GAME_NEHAHRA)
207 Cvar_RegisterVariable (&gl_fogenable);
208 Cvar_RegisterVariable (&gl_fogdensity);
209 Cvar_RegisterVariable (&gl_fogred);
210 Cvar_RegisterVariable (&gl_foggreen);
211 Cvar_RegisterVariable (&gl_fogblue);
212 Cvar_RegisterVariable (&gl_fogstart);
213 Cvar_RegisterVariable (&gl_fogend);
217 void gl_main_start(void)
221 vec_t s, t, intensity;
222 qbyte pix[16][16][4];
224 qbyte data[6*NORMSIZE*NORMSIZE*4];
225 r_main_texturepool = R_AllocTexturePool();
226 r_bloom_texture_screen = NULL;
227 r_bloom_texture_bloom = NULL;
228 data[0] = 128; // normal X
229 data[1] = 128; // normal Y
230 data[2] = 255; // normal Z
231 data[3] = 128; // height
232 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
237 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
242 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
243 // this makes a light grey/dark grey checkerboard texture
244 for (y = 0;y < 16;y++)
246 for (x = 0;x < 16;x++)
248 if ((y < 8) ^ (x < 8))
264 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
265 if (gl_texturecubemap)
267 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
268 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
269 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
270 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
271 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
272 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
273 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
274 for (side = 0;side < 6;side++)
276 for (y = 0;y < NORMSIZE;y++)
278 for (x = 0;x < NORMSIZE;x++)
280 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
281 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
315 intensity = 127.0f / sqrt(DotProduct(v, v));
316 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
317 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
318 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
319 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
323 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
327 void gl_main_shutdown(void)
329 R_FreeTexturePool(&r_main_texturepool);
330 r_bloom_texture_screen = NULL;
331 r_bloom_texture_bloom = NULL;
332 r_texture_blanknormalmap = NULL;
333 r_texture_white = NULL;
334 r_texture_black = NULL;
335 r_texture_whitecube = NULL;
336 r_texture_normalizationcube = NULL;
339 extern void CL_ParseEntityLump(char *entitystring);
340 void gl_main_newmap(void)
342 // FIXME: move this code to client
344 char *entities, entname[MAX_QPATH];
348 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
349 l = strlen(entname) - 4;
350 if (l >= 0 && !strcmp(entname + l, ".bsp"))
352 strcpy(entname + l, ".ent");
353 if ((entities = FS_LoadFile(entname, tempmempool, true)))
355 CL_ParseEntityLump(entities);
360 if (cl.worldmodel->brush.entities)
361 CL_ParseEntityLump(cl.worldmodel->brush.entities);
365 void GL_Main_Init(void)
367 Matrix4x4_CreateIdentity(&r_identitymatrix);
368 // FIXME: move this to client?
370 Cvar_RegisterVariable(&r_showtris);
371 Cvar_RegisterVariable(&r_drawentities);
372 Cvar_RegisterVariable(&r_drawviewmodel);
373 Cvar_RegisterVariable(&r_speeds);
374 Cvar_RegisterVariable(&r_fullbrights);
375 Cvar_RegisterVariable(&r_wateralpha);
376 Cvar_RegisterVariable(&r_dynamic);
377 Cvar_RegisterVariable(&r_fullbright);
378 Cvar_RegisterVariable(&r_textureunits);
379 Cvar_RegisterVariable(&r_lerpsprites);
380 Cvar_RegisterVariable(&r_lerpmodels);
381 Cvar_RegisterVariable(&r_waterscroll);
382 Cvar_RegisterVariable(&r_watershader);
383 Cvar_RegisterVariable(&r_drawcollisionbrushes);
384 Cvar_RegisterVariable(&r_bloom);
385 Cvar_RegisterVariable(&r_bloom_intensity);
386 Cvar_RegisterVariable(&r_bloom_blur);
387 Cvar_RegisterVariable(&r_bloom_resolution);
388 Cvar_RegisterVariable(&r_bloom_power);
389 Cvar_RegisterVariable(&developer_texturelogging);
390 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
391 Cvar_SetValue("r_fullbrights", 0);
392 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
395 static vec3_t r_farclip_origin;
396 static vec3_t r_farclip_direction;
397 static vec_t r_farclip_directiondist;
398 static vec_t r_farclip_meshfarclip;
399 static int r_farclip_directionbit0;
400 static int r_farclip_directionbit1;
401 static int r_farclip_directionbit2;
403 // enlarge farclip to accomodate box
404 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
407 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
408 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
409 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
410 if (r_farclip_meshfarclip < d)
411 r_farclip_meshfarclip = d;
414 // return farclip value
415 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
419 VectorCopy(origin, r_farclip_origin);
420 VectorCopy(direction, r_farclip_direction);
421 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
422 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
423 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
424 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
425 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
427 if (r_refdef.worldmodel)
428 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
429 for (i = 0;i < r_refdef.numentities;i++)
430 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
432 return r_farclip_meshfarclip - r_farclip_directiondist;
435 extern void R_Textures_Init(void);
436 extern void Mod_RenderInit(void);
437 extern void GL_Draw_Init(void);
438 extern void GL_Main_Init(void);
439 extern void R_Shadow_Init(void);
440 extern void GL_Models_Init(void);
441 extern void R_Sky_Init(void);
442 extern void GL_Surf_Init(void);
443 extern void R_Crosshairs_Init(void);
444 extern void R_Light_Init(void);
445 extern void R_Particles_Init(void);
446 extern void R_Explosion_Init(void);
447 extern void ui_init(void);
448 extern void gl_backend_init(void);
449 extern void Sbar_Init(void);
450 extern void R_LightningBeams_Init(void);
452 void Render_Init(void)
471 R_LightningBeams_Init();
479 extern char *ENGINE_EXTENSIONS;
482 VID_CheckExtensions();
484 // LordHavoc: report supported extensions
485 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
487 // clear to black (loading plaque will be seen over this)
488 qglClearColor(0,0,0,1);
489 qglClear(GL_COLOR_BUFFER_BIT);
492 int R_CullBox(const vec3_t mins, const vec3_t maxs)
496 for (i = 0;i < 4;i++)
503 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
507 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
511 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
515 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
519 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
523 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
527 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
531 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
539 //==================================================================================
541 static void R_MarkEntities (void)
544 entity_render_t *ent;
546 if (!r_drawentities.integer)
549 r_refdef.worldentity->visframe = r_framecount;
550 renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
551 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
553 // worldmodel can check visibility
554 for (i = 0;i < r_refdef.numentities;i++)
556 ent = r_refdef.entities[i];
557 Mod_CheckLoaded(ent->model);
558 // some of the renderer still relies on origin...
559 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
560 // some of the renderer still relies on scale...
561 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
562 if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_worldleafvisible, ent->mins, ent->maxs)))
564 R_UpdateEntLights(ent);
565 ent->visframe = r_framecount;
571 // no worldmodel or it can't check visibility
572 for (i = 0;i < r_refdef.numentities;i++)
574 ent = r_refdef.entities[i];
575 Mod_CheckLoaded(ent->model);
576 // some of the renderer still relies on origin...
577 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
578 // some of the renderer still relies on scale...
579 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
580 if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
582 R_UpdateEntLights(ent);
583 ent->visframe = r_framecount;
589 // only used if skyrendermasked, and normally returns false
590 int R_DrawBrushModelsSky (void)
593 entity_render_t *ent;
595 if (!r_drawentities.integer)
599 for (i = 0;i < r_refdef.numentities;i++)
601 ent = r_refdef.entities[i];
602 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
604 ent->model->DrawSky(ent);
611 void R_DrawNoModel(entity_render_t *ent);
612 void R_DrawModels(void)
615 entity_render_t *ent;
617 if (!r_drawentities.integer)
620 for (i = 0;i < r_refdef.numentities;i++)
622 ent = r_refdef.entities[i];
623 if (ent->visframe == r_framecount)
625 if (ent->model && ent->model->Draw != NULL)
626 ent->model->Draw(ent);
633 static void R_SetFrustum(void)
635 // break apart the view matrix into vectors for various purposes
636 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
637 VectorNegate(r_viewleft, r_viewright);
639 // LordHavoc: note to all quake engine coders, the special case for 90
640 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
643 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
644 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
645 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
646 PlaneClassify(&frustum[0]);
648 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
649 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
650 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
651 PlaneClassify(&frustum[1]);
653 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
654 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
655 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
656 PlaneClassify(&frustum[2]);
658 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
659 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
660 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
661 PlaneClassify(&frustum[3]);
664 static void R_BlendView(void)
668 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
671 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
674 R_Mesh_Matrix(&r_identitymatrix);
675 // vertex coordinates for a quad that covers the screen exactly
676 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
677 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
678 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
679 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
680 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)
682 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
683 float xoffset, yoffset, r;
685 // set the (poorly named) screenwidth and screenheight variables to
686 // a power of 2 at least as large as the screen, these will define the
687 // size of the texture to allocate
688 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
689 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
690 // allocate textures as needed
691 if (!r_bloom_texture_screen)
692 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
693 if (!r_bloom_texture_bloom)
694 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
695 // set bloomwidth and bloomheight to the bloom resolution that will be
696 // used (often less than the screen resolution for faster rendering)
697 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
698 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
699 // set up a texcoord array for the full resolution screen image
700 // (we have to keep this around to copy back during final render)
701 varray_texcoord2f[0][0] = 0;
702 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
703 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
704 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
705 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
706 varray_texcoord2f[0][5] = 0;
707 varray_texcoord2f[0][6] = 0;
708 varray_texcoord2f[0][7] = 0;
709 // set up a texcoord array for the reduced resolution bloom image
710 // (which will be additive blended over the screen image)
711 varray_texcoord2f[1][0] = 0;
712 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
713 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
714 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
715 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
716 varray_texcoord2f[1][5] = 0;
717 varray_texcoord2f[1][6] = 0;
718 varray_texcoord2f[1][7] = 0;
719 memset(&m, 0, sizeof(m));
720 m.pointer_vertex = varray_vertex3f;
721 m.pointer_texcoord[0] = varray_texcoord2f[0];
722 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
724 // copy view into the full resolution screen image texture
726 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
728 c_bloomcopypixels += r_view_width * r_view_height;
729 // now scale it down to the bloom size and raise to a power of itself
730 // to darken it (this leaves the really bright stuff bright, and
731 // everything else becomes very dark)
732 // TODO: optimize with multitexture or GLSL
733 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
734 GL_BlendFunc(GL_ONE, GL_ZERO);
735 GL_Color(1, 1, 1, 1);
736 R_Mesh_Draw(0, 4, 2, polygonelements);
738 c_bloomdrawpixels += bloomwidth * bloomheight;
739 // render multiple times with a multiply blendfunc to raise to a power
740 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
741 for (x = 1;x < r_bloom_power.integer;x++)
743 R_Mesh_Draw(0, 4, 2, polygonelements);
745 c_bloomdrawpixels += bloomwidth * bloomheight;
747 // we now have a darkened bloom image in the framebuffer, copy it into
748 // the bloom image texture for more processing
749 memset(&m, 0, sizeof(m));
750 m.pointer_vertex = varray_vertex3f;
751 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
752 m.pointer_texcoord[0] = varray_texcoord2f[2];
755 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
757 c_bloomcopypixels += bloomwidth * bloomheight;
758 // blend on at multiple vertical offsets to achieve a vertical blur
759 // TODO: do offset blends using GLSL
760 range = r_bloom_blur.integer * bloomwidth / 320;
761 GL_BlendFunc(GL_ONE, GL_ZERO);
762 for (x = -range;x <= range;x++)
764 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
765 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
766 // compute a texcoord array with the specified x and y offset
767 varray_texcoord2f[2][0] = xoffset+0;
768 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
769 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
770 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
771 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
772 varray_texcoord2f[2][5] = yoffset+0;
773 varray_texcoord2f[2][6] = xoffset+0;
774 varray_texcoord2f[2][7] = yoffset+0;
775 // this r value looks like a 'dot' particle, fading sharply to
776 // black at the edges
777 // (probably not realistic but looks good enough)
778 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
781 GL_Color(r, r, r, 1);
782 R_Mesh_Draw(0, 4, 2, polygonelements);
784 c_bloomdrawpixels += bloomwidth * bloomheight;
785 GL_BlendFunc(GL_ONE, GL_ONE);
787 // copy the vertically blurred bloom view to a texture
789 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
791 c_bloomcopypixels += bloomwidth * bloomheight;
792 // blend the vertically blurred image at multiple offsets horizontally
793 // to finish the blur effect
794 // TODO: do offset blends using GLSL
795 range = r_bloom_blur.integer * bloomwidth / 320;
796 GL_BlendFunc(GL_ONE, GL_ZERO);
797 for (x = -range;x <= range;x++)
799 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
800 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
801 // compute a texcoord array with the specified x and y offset
802 varray_texcoord2f[2][0] = xoffset+0;
803 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
804 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
805 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
806 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
807 varray_texcoord2f[2][5] = yoffset+0;
808 varray_texcoord2f[2][6] = xoffset+0;
809 varray_texcoord2f[2][7] = yoffset+0;
810 // this r value looks like a 'dot' particle, fading sharply to
811 // black at the edges
812 // (probably not realistic but looks good enough)
813 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
816 GL_Color(r, r, r, 1);
817 R_Mesh_Draw(0, 4, 2, polygonelements);
819 c_bloomdrawpixels += bloomwidth * bloomheight;
820 GL_BlendFunc(GL_ONE, GL_ONE);
822 // copy the blurred bloom view to a texture
824 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
826 c_bloomcopypixels += bloomwidth * bloomheight;
827 // go back to full view area
828 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
829 // put the original screen image back in place and blend the bloom
831 memset(&m, 0, sizeof(m));
832 m.pointer_vertex = varray_vertex3f;
833 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
834 m.pointer_texcoord[0] = varray_texcoord2f[0];
836 dobloomblend = false;
838 // do both in one pass if possible
839 if (r_textureunits.integer >= 2 && gl_combine.integer)
841 dobloomblend = false;
842 m.texcombinergb[1] = GL_ADD;
843 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
844 m.pointer_texcoord[1] = varray_texcoord2f[1];
850 GL_BlendFunc(GL_ONE, GL_ZERO);
852 R_Mesh_Draw(0, 4, 2, polygonelements);
854 c_bloomdrawpixels += r_view_width * r_view_height;
855 // now blend on the bloom texture if multipass
858 memset(&m, 0, sizeof(m));
859 m.pointer_vertex = varray_vertex3f;
860 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
861 m.pointer_texcoord[0] = varray_texcoord2f[1];
863 GL_BlendFunc(GL_ONE, GL_ONE);
865 R_Mesh_Draw(0, 4, 2, polygonelements);
867 c_bloomdrawpixels += r_view_width * r_view_height;
870 if (r_refdef.viewblend[3] >= 0.01f)
872 // apply a color tint to the whole view
873 memset(&m, 0, sizeof(m));
874 m.pointer_vertex = varray_vertex3f;
876 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
877 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
878 R_Mesh_Draw(0, 4, 2, polygonelements);
882 void R_RenderScene(void);
889 void R_RenderView(void)
891 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
892 return; //Host_Error ("R_RenderView: NULL worldmodel");
894 r_view_width = bound(0, r_refdef.width, vid.realwidth);
895 r_view_height = bound(0, r_refdef.height, vid.realheight);
897 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
898 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
900 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
901 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
902 r_view_matrix = r_refdef.viewentitymatrix;
903 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
904 r_rtworld = r_shadow_realtime_world.integer;
905 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
906 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
907 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
908 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
910 // GL is weird because it's bottom to top, r_view_y is top to bottom
911 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
912 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
913 GL_ScissorTest(true);
919 R_TimeReport("setup");
921 qglDepthFunc(GL_LEQUAL);
922 qglPolygonOffset(0, 0);
923 qglEnable(GL_POLYGON_OFFSET_FILL);
927 qglPolygonOffset(0, 0);
928 qglDisable(GL_POLYGON_OFFSET_FILL);
931 R_TimeReport("blendview");
933 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
934 GL_ScissorTest(false);
937 extern void R_DrawLightningBeams (void);
938 void R_RenderScene(void)
940 // don't let sound skip if going slow
941 if (r_refdef.extraupdate)
946 R_MeshQueue_BeginScene();
948 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
952 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
953 if (r_rtworldshadows || r_rtdlightshadows)
954 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
956 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
958 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
963 R_TimeReport("worldvis");
966 R_TimeReport("markentity");
968 R_Shadow_UpdateWorldLightSelection();
970 // don't let sound skip if going slow
971 if (r_refdef.extraupdate)
974 GL_ShowTrisColor(0.025, 0.025, 0, 1);
975 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
977 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
978 R_TimeReport("worldsky");
981 if (R_DrawBrushModelsSky())
982 R_TimeReport("bmodelsky");
984 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
985 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
987 r_refdef.worldmodel->Draw(r_refdef.worldentity);
988 R_TimeReport("world");
991 // don't let sound skip if going slow
992 if (r_refdef.extraupdate)
995 GL_ShowTrisColor(0, 0.015, 0, 1);
998 R_TimeReport("models");
1000 // don't let sound skip if going slow
1001 if (r_refdef.extraupdate)
1004 GL_ShowTrisColor(0, 0, 0.033, 1);
1005 R_ShadowVolumeLighting(false);
1006 R_TimeReport("rtlights");
1008 // don't let sound skip if going slow
1009 if (r_refdef.extraupdate)
1012 GL_ShowTrisColor(0.1, 0, 0, 1);
1014 R_DrawLightningBeams();
1015 R_TimeReport("lightning");
1018 R_TimeReport("particles");
1021 R_TimeReport("explosions");
1023 R_MeshQueue_RenderTransparent();
1024 R_TimeReport("drawtrans");
1027 R_TimeReport("coronas");
1029 R_DrawWorldCrosshair();
1030 R_TimeReport("crosshair");
1032 R_MeshQueue_Render();
1033 R_MeshQueue_EndScene();
1035 if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
1037 R_ShadowVolumeLighting(true);
1038 R_TimeReport("visiblevolume");
1041 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1043 // don't let sound skip if going slow
1044 if (r_refdef.extraupdate)
1049 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1052 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1054 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1055 GL_DepthMask(false);
1057 R_Mesh_Matrix(&r_identitymatrix);
1059 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1060 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1061 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1062 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1063 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1064 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1065 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1066 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1067 R_FillColors(color, 8, cr, cg, cb, ca);
1070 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1072 VectorSubtract(v, r_vieworigin, diff);
1073 f2 = exp(fogdensity/DotProduct(diff, diff));
1075 c[0] = c[0] * f1 + fogcolor[0] * f2;
1076 c[1] = c[1] * f1 + fogcolor[1] * f2;
1077 c[2] = c[2] * f1 + fogcolor[2] * f2;
1080 memset(&m, 0, sizeof(m));
1081 m.pointer_vertex = vertex3f;
1082 m.pointer_color = color;
1088 int nomodelelements[24] =
1100 float nomodelvertex3f[6*3] =
1110 float nomodelcolor4f[6*4] =
1112 0.0f, 0.0f, 0.5f, 1.0f,
1113 0.0f, 0.0f, 0.5f, 1.0f,
1114 0.0f, 0.5f, 0.0f, 1.0f,
1115 0.0f, 0.5f, 0.0f, 1.0f,
1116 0.5f, 0.0f, 0.0f, 1.0f,
1117 0.5f, 0.0f, 0.0f, 1.0f
1120 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1122 const entity_render_t *ent = calldata1;
1124 float f1, f2, *c, diff[3];
1127 R_Mesh_Matrix(&ent->matrix);
1129 memset(&m, 0, sizeof(m));
1130 m.pointer_vertex = nomodelvertex3f;
1132 if (ent->flags & EF_ADDITIVE)
1134 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1135 GL_DepthMask(false);
1137 else if (ent->alpha < 1)
1139 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1140 GL_DepthMask(false);
1144 GL_BlendFunc(GL_ONE, GL_ZERO);
1147 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1150 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1151 m.pointer_color = color4f;
1152 VectorSubtract(ent->origin, r_vieworigin, diff);
1153 f2 = exp(fogdensity/DotProduct(diff, diff));
1155 for (i = 0, c = color4f;i < 6;i++, c += 4)
1157 c[0] = (c[0] * f1 + fogcolor[0] * f2);
1158 c[1] = (c[1] * f1 + fogcolor[1] * f2);
1159 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1163 else if (ent->alpha != 1)
1165 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1166 m.pointer_color = color4f;
1167 for (i = 0, c = color4f;i < 6;i++, c += 4)
1171 m.pointer_color = nomodelcolor4f;
1173 R_Mesh_Draw(0, 6, 8, nomodelelements);
1176 void R_DrawNoModel(entity_render_t *ent)
1178 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1179 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1181 // R_DrawNoModelCallback(ent, 0);
1184 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1186 vec3_t right1, right2, diff, normal;
1188 VectorSubtract (org2, org1, normal);
1190 // calculate 'right' vector for start
1191 VectorSubtract (r_vieworigin, org1, diff);
1192 CrossProduct (normal, diff, right1);
1193 VectorNormalize (right1);
1195 // calculate 'right' vector for end
1196 VectorSubtract (r_vieworigin, org2, diff);
1197 CrossProduct (normal, diff, right2);
1198 VectorNormalize (right2);
1200 vert[ 0] = org1[0] + width * right1[0];
1201 vert[ 1] = org1[1] + width * right1[1];
1202 vert[ 2] = org1[2] + width * right1[2];
1203 vert[ 3] = org1[0] - width * right1[0];
1204 vert[ 4] = org1[1] - width * right1[1];
1205 vert[ 5] = org1[2] - width * right1[2];
1206 vert[ 6] = org2[0] - width * right2[0];
1207 vert[ 7] = org2[1] - width * right2[1];
1208 vert[ 8] = org2[2] - width * right2[2];
1209 vert[ 9] = org2[0] + width * right2[0];
1210 vert[10] = org2[1] + width * right2[1];
1211 vert[11] = org2[2] + width * right2[2];
1214 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1216 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)
1223 VectorSubtract(origin, r_vieworigin, diff);
1224 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1227 R_Mesh_Matrix(&r_identitymatrix);
1228 GL_BlendFunc(blendfunc1, blendfunc2);
1229 GL_DepthMask(false);
1230 GL_DepthTest(!depthdisable);
1232 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1233 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1234 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1235 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1236 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1237 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1238 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1239 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1240 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1241 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1242 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1243 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1245 memset(&m, 0, sizeof(m));
1246 m.tex[0] = R_GetTexture(texture);
1247 m.pointer_texcoord[0] = spritetexcoord2f;
1248 m.pointer_vertex = varray_vertex3f;
1250 GL_Color(cr, cg, cb, ca);
1251 R_Mesh_Draw(0, 4, 2, polygonelements);