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;
109 rtexture_t *r_texture_blanknormalmap;
110 rtexture_t *r_texture_white;
111 rtexture_t *r_texture_black;
112 rtexture_t *r_texture_notexture;
113 rtexture_t *r_texture_whitecube;
114 rtexture_t *r_texture_normalizationcube;
116 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
119 for (i = 0;i < verts;i++)
130 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
133 for (i = 0;i < verts;i++)
145 float fog_density, fog_red, fog_green, fog_blue;
147 qboolean oldgl_fogenable;
148 void R_UpdateFog(void)
150 if (gamemode == GAME_NEHAHRA)
152 if (gl_fogenable.integer)
154 oldgl_fogenable = true;
155 fog_density = gl_fogdensity.value;
156 fog_red = gl_fogred.value;
157 fog_green = gl_foggreen.value;
158 fog_blue = gl_fogblue.value;
160 else if (oldgl_fogenable)
162 oldgl_fogenable = false;
171 fogcolor[0] = fog_red = bound(0.0f, fog_red , 1.0f);
172 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
173 fogcolor[2] = fog_blue = bound(0.0f, fog_blue , 1.0f);
178 fogdensity = -4000.0f / (fog_density * fog_density);
179 // fog color was already set
185 // FIXME: move this to client?
188 if (gamemode == GAME_NEHAHRA)
190 Cvar_Set("gl_fogenable", "0");
191 Cvar_Set("gl_fogdensity", "0.2");
192 Cvar_Set("gl_fogred", "0.3");
193 Cvar_Set("gl_foggreen", "0.3");
194 Cvar_Set("gl_fogblue", "0.3");
196 fog_density = fog_red = fog_green = fog_blue = 0.0f;
199 // FIXME: move this to client?
200 void FOG_registercvars(void)
202 if (gamemode == GAME_NEHAHRA)
204 Cvar_RegisterVariable (&gl_fogenable);
205 Cvar_RegisterVariable (&gl_fogdensity);
206 Cvar_RegisterVariable (&gl_fogred);
207 Cvar_RegisterVariable (&gl_foggreen);
208 Cvar_RegisterVariable (&gl_fogblue);
209 Cvar_RegisterVariable (&gl_fogstart);
210 Cvar_RegisterVariable (&gl_fogend);
214 void gl_main_start(void)
218 vec_t s, t, intensity;
219 qbyte pix[16][16][4];
221 qbyte data[6*NORMSIZE*NORMSIZE*4];
222 r_main_texturepool = R_AllocTexturePool();
223 r_bloom_texture_screen = NULL;
224 r_bloom_texture_bloom = NULL;
225 data[0] = 128; // normal X
226 data[1] = 128; // normal Y
227 data[2] = 255; // normal Z
228 data[3] = 128; // height
229 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
234 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
239 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
240 // this makes a light grey/dark grey checkerboard texture
241 for (y = 0;y < 16;y++)
243 for (x = 0;x < 16;x++)
245 if ((y < 8) ^ (x < 8))
261 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
262 if (gl_texturecubemap)
264 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
265 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
266 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
267 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
268 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
269 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
270 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
271 for (side = 0;side < 6;side++)
273 for (y = 0;y < NORMSIZE;y++)
275 for (x = 0;x < NORMSIZE;x++)
277 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
278 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
312 intensity = 127.0f / sqrt(DotProduct(v, v));
313 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+0] = 128.0f + intensity * v[0];
314 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+1] = 128.0f + intensity * v[1];
315 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+2] = 128.0f + intensity * v[2];
316 data[((side*NORMSIZE+y)*NORMSIZE+x)*4+3] = 255;
320 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
324 void gl_main_shutdown(void)
326 R_FreeTexturePool(&r_main_texturepool);
327 r_bloom_texture_screen = NULL;
328 r_bloom_texture_bloom = NULL;
329 r_texture_blanknormalmap = NULL;
330 r_texture_white = NULL;
331 r_texture_black = NULL;
332 r_texture_whitecube = NULL;
333 r_texture_normalizationcube = NULL;
336 extern void CL_ParseEntityLump(char *entitystring);
337 void gl_main_newmap(void)
339 // FIXME: move this code to client
341 char *entities, entname[MAX_QPATH];
345 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
346 l = strlen(entname) - 4;
347 if (l >= 0 && !strcmp(entname + l, ".bsp"))
349 strcpy(entname + l, ".ent");
350 if ((entities = FS_LoadFile(entname, tempmempool, true)))
352 CL_ParseEntityLump(entities);
357 if (cl.worldmodel->brush.entities)
358 CL_ParseEntityLump(cl.worldmodel->brush.entities);
362 void GL_Main_Init(void)
364 Matrix4x4_CreateIdentity(&r_identitymatrix);
365 // FIXME: move this to client?
367 Cvar_RegisterVariable(&r_showtris);
368 Cvar_RegisterVariable(&r_drawentities);
369 Cvar_RegisterVariable(&r_drawviewmodel);
370 Cvar_RegisterVariable(&r_speeds);
371 Cvar_RegisterVariable(&r_fullbrights);
372 Cvar_RegisterVariable(&r_wateralpha);
373 Cvar_RegisterVariable(&r_dynamic);
374 Cvar_RegisterVariable(&r_fullbright);
375 Cvar_RegisterVariable(&r_textureunits);
376 Cvar_RegisterVariable(&r_lerpsprites);
377 Cvar_RegisterVariable(&r_lerpmodels);
378 Cvar_RegisterVariable(&r_waterscroll);
379 Cvar_RegisterVariable(&r_watershader);
380 Cvar_RegisterVariable(&r_drawcollisionbrushes);
381 Cvar_RegisterVariable(&r_bloom);
382 Cvar_RegisterVariable(&r_bloom_intensity);
383 Cvar_RegisterVariable(&r_bloom_blur);
384 Cvar_RegisterVariable(&r_bloom_resolution);
385 Cvar_RegisterVariable(&r_bloom_power);
386 if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
387 Cvar_SetValue("r_fullbrights", 0);
388 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
391 static vec3_t r_farclip_origin;
392 static vec3_t r_farclip_direction;
393 static vec_t r_farclip_directiondist;
394 static vec_t r_farclip_meshfarclip;
395 static int r_farclip_directionbit0;
396 static int r_farclip_directionbit1;
397 static int r_farclip_directionbit2;
399 // enlarge farclip to accomodate box
400 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
403 d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
404 + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
405 + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
406 if (r_farclip_meshfarclip < d)
407 r_farclip_meshfarclip = d;
410 // return farclip value
411 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
415 VectorCopy(origin, r_farclip_origin);
416 VectorCopy(direction, r_farclip_direction);
417 r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
418 r_farclip_directionbit0 = r_farclip_direction[0] < 0;
419 r_farclip_directionbit1 = r_farclip_direction[1] < 0;
420 r_farclip_directionbit2 = r_farclip_direction[2] < 0;
421 r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
423 if (r_refdef.worldmodel)
424 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
425 for (i = 0;i < r_refdef.numentities;i++)
426 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
428 return r_farclip_meshfarclip - r_farclip_directiondist;
431 extern void R_Textures_Init(void);
432 extern void Mod_RenderInit(void);
433 extern void GL_Draw_Init(void);
434 extern void GL_Main_Init(void);
435 extern void R_Shadow_Init(void);
436 extern void GL_Models_Init(void);
437 extern void R_Sky_Init(void);
438 extern void GL_Surf_Init(void);
439 extern void R_Crosshairs_Init(void);
440 extern void R_Light_Init(void);
441 extern void R_Particles_Init(void);
442 extern void R_Explosion_Init(void);
443 extern void ui_init(void);
444 extern void gl_backend_init(void);
445 extern void Sbar_Init(void);
446 extern void R_LightningBeams_Init(void);
448 void Render_Init(void)
467 R_LightningBeams_Init();
475 extern char *ENGINE_EXTENSIONS;
478 VID_CheckExtensions();
480 // LordHavoc: report supported extensions
481 Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
483 // clear to black (loading plaque will be seen over this)
484 qglClearColor(0,0,0,1);
485 qglClear(GL_COLOR_BUFFER_BIT);
488 int R_CullBox(const vec3_t mins, const vec3_t maxs)
492 for (i = 0;i < 4;i++)
499 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
503 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
507 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
511 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
515 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
519 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
523 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
527 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
535 //==================================================================================
537 static void R_MarkEntities (void)
540 entity_render_t *ent;
542 if (!r_drawentities.integer)
545 renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
546 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
548 // worldmodel can check visibility
549 for (i = 0;i < r_refdef.numentities;i++)
551 ent = r_refdef.entities[i];
552 Mod_CheckLoaded(ent->model);
553 // some of the renderer still relies on origin...
554 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
555 // some of the renderer still relies on scale...
556 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
557 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)))
559 R_UpdateEntLights(ent);
560 ent->visframe = r_framecount;
566 // no worldmodel or it can't check visibility
567 for (i = 0;i < r_refdef.numentities;i++)
569 ent = r_refdef.entities[i];
570 Mod_CheckLoaded(ent->model);
571 // some of the renderer still relies on origin...
572 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
573 // some of the renderer still relies on scale...
574 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
575 if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
577 R_UpdateEntLights(ent);
578 ent->visframe = r_framecount;
584 // only used if skyrendermasked, and normally returns false
585 int R_DrawBrushModelsSky (void)
588 entity_render_t *ent;
590 if (!r_drawentities.integer)
594 for (i = 0;i < r_refdef.numentities;i++)
596 ent = r_refdef.entities[i];
597 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
599 ent->model->DrawSky(ent);
606 void R_DrawNoModel(entity_render_t *ent);
607 void R_DrawModels(void)
610 entity_render_t *ent;
612 if (!r_drawentities.integer)
615 for (i = 0;i < r_refdef.numentities;i++)
617 ent = r_refdef.entities[i];
618 if (ent->visframe == r_framecount)
620 if (ent->model && ent->model->Draw != NULL)
621 ent->model->Draw(ent);
628 static void R_SetFrustum(void)
630 // break apart the view matrix into vectors for various purposes
631 Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
632 VectorNegate(r_viewleft, r_viewright);
634 // LordHavoc: note to all quake engine coders, the special case for 90
635 // degrees assumed a square view (wrong), so I removed it, Quake2 has it
638 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
639 RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
640 frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
641 PlaneClassify(&frustum[0]);
643 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
644 RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
645 frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
646 PlaneClassify(&frustum[1]);
648 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
649 RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
650 frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
651 PlaneClassify(&frustum[2]);
653 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
654 RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
655 frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
656 PlaneClassify(&frustum[3]);
659 static void R_BlendView(void)
663 if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
666 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
669 R_Mesh_Matrix(&r_identitymatrix);
670 // vertex coordinates for a quad that covers the screen exactly
671 varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
672 varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
673 varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
674 varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
675 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)
677 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
678 float xoffset, yoffset, r;
680 // set the (poorly named) screenwidth and screenheight variables to
681 // a power of 2 at least as large as the screen, these will define the
682 // size of the texture to allocate
683 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
684 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
685 // allocate textures as needed
686 if (!r_bloom_texture_screen)
687 r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
688 if (!r_bloom_texture_bloom)
689 r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
690 // set bloomwidth and bloomheight to the bloom resolution that will be
691 // used (often less than the screen resolution for faster rendering)
692 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
693 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
694 // set up a texcoord array for the full resolution screen image
695 // (we have to keep this around to copy back during final render)
696 varray_texcoord2f[0][0] = 0;
697 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
698 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
699 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
700 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
701 varray_texcoord2f[0][5] = 0;
702 varray_texcoord2f[0][6] = 0;
703 varray_texcoord2f[0][7] = 0;
704 // set up a texcoord array for the reduced resolution bloom image
705 // (which will be additive blended over the screen image)
706 varray_texcoord2f[1][0] = 0;
707 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
708 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
709 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
710 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
711 varray_texcoord2f[1][5] = 0;
712 varray_texcoord2f[1][6] = 0;
713 varray_texcoord2f[1][7] = 0;
714 memset(&m, 0, sizeof(m));
715 m.pointer_vertex = varray_vertex3f;
716 m.pointer_texcoord[0] = varray_texcoord2f[0];
717 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
719 // copy view into the full resolution screen image texture
721 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
723 c_bloomcopypixels += r_view_width * r_view_height;
724 // now scale it down to the bloom size and raise to a power of itself
725 // to darken it (this leaves the really bright stuff bright, and
726 // everything else becomes very dark)
727 // TODO: optimize with multitexture or GLSL
728 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
729 GL_BlendFunc(GL_ONE, GL_ZERO);
730 GL_Color(1, 1, 1, 1);
731 R_Mesh_Draw(0, 4, 2, polygonelements);
733 c_bloomdrawpixels += bloomwidth * bloomheight;
734 // render multiple times with a multiply blendfunc to raise to a power
735 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
736 for (x = 1;x < r_bloom_power.integer;x++)
738 R_Mesh_Draw(0, 4, 2, polygonelements);
740 c_bloomdrawpixels += bloomwidth * bloomheight;
742 // we now have a darkened bloom image in the framebuffer, copy it into
743 // the bloom image texture for more processing
744 memset(&m, 0, sizeof(m));
745 m.pointer_vertex = varray_vertex3f;
746 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
747 m.pointer_texcoord[0] = varray_texcoord2f[2];
750 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
752 c_bloomcopypixels += bloomwidth * bloomheight;
753 // blend on at multiple vertical offsets to achieve a vertical blur
754 // TODO: do offset blends using GLSL
755 range = r_bloom_blur.integer * bloomwidth / 320;
756 GL_BlendFunc(GL_ONE, GL_ZERO);
757 for (x = -range;x <= range;x++)
759 xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
760 yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
761 // compute a texcoord array with the specified x and y offset
762 varray_texcoord2f[2][0] = xoffset+0;
763 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
764 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
765 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
766 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
767 varray_texcoord2f[2][5] = yoffset+0;
768 varray_texcoord2f[2][6] = xoffset+0;
769 varray_texcoord2f[2][7] = yoffset+0;
770 // this r value looks like a 'dot' particle, fading sharply to
771 // black at the edges
772 // (probably not realistic but looks good enough)
773 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
776 GL_Color(r, r, r, 1);
777 R_Mesh_Draw(0, 4, 2, polygonelements);
779 c_bloomdrawpixels += bloomwidth * bloomheight;
780 GL_BlendFunc(GL_ONE, GL_ONE);
782 // copy the vertically blurred bloom view to a texture
784 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
786 c_bloomcopypixels += bloomwidth * bloomheight;
787 // blend the vertically blurred image at multiple offsets horizontally
788 // to finish the blur effect
789 // TODO: do offset blends using GLSL
790 range = r_bloom_blur.integer * bloomwidth / 320;
791 GL_BlendFunc(GL_ONE, GL_ZERO);
792 for (x = -range;x <= range;x++)
794 xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
795 yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
796 // compute a texcoord array with the specified x and y offset
797 varray_texcoord2f[2][0] = xoffset+0;
798 varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
799 varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
800 varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
801 varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
802 varray_texcoord2f[2][5] = yoffset+0;
803 varray_texcoord2f[2][6] = xoffset+0;
804 varray_texcoord2f[2][7] = yoffset+0;
805 // this r value looks like a 'dot' particle, fading sharply to
806 // black at the edges
807 // (probably not realistic but looks good enough)
808 r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
811 GL_Color(r, r, r, 1);
812 R_Mesh_Draw(0, 4, 2, polygonelements);
814 c_bloomdrawpixels += bloomwidth * bloomheight;
815 GL_BlendFunc(GL_ONE, GL_ONE);
817 // copy the blurred bloom view to a texture
819 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
821 c_bloomcopypixels += bloomwidth * bloomheight;
822 // go back to full view area
823 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
824 // put the original screen image back in place and blend the bloom
826 memset(&m, 0, sizeof(m));
827 m.pointer_vertex = varray_vertex3f;
828 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
829 m.pointer_texcoord[0] = varray_texcoord2f[0];
831 dobloomblend = false;
833 // do both in one pass if possible
834 if (r_textureunits.integer >= 2 && gl_combine.integer)
836 dobloomblend = false;
837 m.texcombinergb[1] = GL_ADD;
838 m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
839 m.pointer_texcoord[1] = varray_texcoord2f[1];
845 GL_BlendFunc(GL_ONE, GL_ZERO);
847 R_Mesh_Draw(0, 4, 2, polygonelements);
849 c_bloomdrawpixels += r_view_width * r_view_height;
850 // now blend on the bloom texture if multipass
853 memset(&m, 0, sizeof(m));
854 m.pointer_vertex = varray_vertex3f;
855 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
856 m.pointer_texcoord[0] = varray_texcoord2f[1];
858 GL_BlendFunc(GL_ONE, GL_ONE);
860 R_Mesh_Draw(0, 4, 2, polygonelements);
862 c_bloomdrawpixels += r_view_width * r_view_height;
865 if (r_refdef.viewblend[3] >= 0.01f)
867 // apply a color tint to the whole view
868 memset(&m, 0, sizeof(m));
869 m.pointer_vertex = varray_vertex3f;
871 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
872 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
873 R_Mesh_Draw(0, 4, 2, polygonelements);
877 void R_RenderScene(void);
884 void R_RenderView(void)
886 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
887 return; //Host_Error ("R_RenderView: NULL worldmodel");
889 r_view_width = bound(0, r_refdef.width, vid.realwidth);
890 r_view_height = bound(0, r_refdef.height, vid.realheight);
892 r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
893 r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
895 r_view_fov_x = bound(1, r_refdef.fov_x, 170);
896 r_view_fov_y = bound(1, r_refdef.fov_y, 170);
897 r_view_matrix = r_refdef.viewentitymatrix;
898 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
899 r_rtworld = r_shadow_realtime_world.integer;
900 r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
901 r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
902 r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
903 r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
905 // GL is weird because it's bottom to top, r_view_y is top to bottom
906 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
907 GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
908 GL_ScissorTest(true);
914 R_TimeReport("setup");
916 qglDepthFunc(GL_LEQUAL);
917 qglPolygonOffset(0, 0);
918 qglEnable(GL_POLYGON_OFFSET_FILL);
922 qglPolygonOffset(0, 0);
923 qglDisable(GL_POLYGON_OFFSET_FILL);
926 R_TimeReport("blendview");
928 GL_Scissor(0, 0, vid.realwidth, vid.realheight);
929 GL_ScissorTest(false);
932 extern void R_DrawLightningBeams (void);
933 void R_RenderScene(void)
935 // don't let sound skip if going slow
936 if (r_refdef.extraupdate)
941 R_MeshQueue_BeginScene();
943 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
947 r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
948 if (r_rtworldshadows || r_rtdlightshadows)
949 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
951 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
953 GL_SetupView_Orientation_FromEntity(&r_view_matrix);
958 R_TimeReport("worldvis");
961 R_TimeReport("markentity");
963 R_Shadow_UpdateWorldLightSelection();
965 // don't let sound skip if going slow
966 if (r_refdef.extraupdate)
969 GL_ShowTrisColor(0.025, 0.025, 0, 1);
970 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
972 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
973 R_TimeReport("worldsky");
976 if (R_DrawBrushModelsSky())
977 R_TimeReport("bmodelsky");
979 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
980 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
982 r_refdef.worldmodel->Draw(r_refdef.worldentity);
983 R_TimeReport("world");
986 // don't let sound skip if going slow
987 if (r_refdef.extraupdate)
990 GL_ShowTrisColor(0, 0.015, 0, 1);
993 R_TimeReport("models");
995 // don't let sound skip if going slow
996 if (r_refdef.extraupdate)
999 GL_ShowTrisColor(0, 0, 0.033, 1);
1000 R_ShadowVolumeLighting(false, false);
1001 R_TimeReport("rtlights");
1003 // don't let sound skip if going slow
1004 if (r_refdef.extraupdate)
1007 GL_ShowTrisColor(0.1, 0, 0, 1);
1009 R_DrawLightningBeams();
1010 R_TimeReport("lightning");
1013 R_TimeReport("particles");
1016 R_TimeReport("explosions");
1018 R_MeshQueue_RenderTransparent();
1019 R_TimeReport("drawtrans");
1022 R_TimeReport("coronas");
1024 R_DrawWorldCrosshair();
1025 R_TimeReport("crosshair");
1027 R_MeshQueue_Render();
1028 R_MeshQueue_EndScene();
1030 if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
1032 R_ShadowVolumeLighting(r_shadow_visiblelighting.integer, r_shadow_visiblevolumes.integer);
1033 R_TimeReport("shadowvolume");
1036 GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1038 // don't let sound skip if going slow
1039 if (r_refdef.extraupdate)
1044 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1047 float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1049 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1050 GL_DepthMask(false);
1052 R_Mesh_Matrix(&r_identitymatrix);
1054 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1055 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1056 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1057 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1058 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1059 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1060 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1061 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1062 R_FillColors(color, 8, cr, cg, cb, ca);
1065 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1067 VectorSubtract(v, r_vieworigin, diff);
1068 f2 = exp(fogdensity/DotProduct(diff, diff));
1070 c[0] = c[0] * f1 + fogcolor[0] * f2;
1071 c[1] = c[1] * f1 + fogcolor[1] * f2;
1072 c[2] = c[2] * f1 + fogcolor[2] * f2;
1075 memset(&m, 0, sizeof(m));
1076 m.pointer_vertex = vertex3f;
1077 m.pointer_color = color;
1083 int nomodelelements[24] =
1095 float nomodelvertex3f[6*3] =
1105 float nomodelcolor4f[6*4] =
1107 0.0f, 0.0f, 0.5f, 1.0f,
1108 0.0f, 0.0f, 0.5f, 1.0f,
1109 0.0f, 0.5f, 0.0f, 1.0f,
1110 0.0f, 0.5f, 0.0f, 1.0f,
1111 0.5f, 0.0f, 0.0f, 1.0f,
1112 0.5f, 0.0f, 0.0f, 1.0f
1115 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1117 const entity_render_t *ent = calldata1;
1119 float f1, f2, *c, diff[3];
1122 R_Mesh_Matrix(&ent->matrix);
1124 memset(&m, 0, sizeof(m));
1125 m.pointer_vertex = nomodelvertex3f;
1127 if (ent->flags & EF_ADDITIVE)
1129 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1130 GL_DepthMask(false);
1132 else if (ent->alpha < 1)
1134 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1135 GL_DepthMask(false);
1139 GL_BlendFunc(GL_ONE, GL_ZERO);
1142 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1145 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1146 m.pointer_color = color4f;
1147 VectorSubtract(ent->origin, r_vieworigin, diff);
1148 f2 = exp(fogdensity/DotProduct(diff, diff));
1150 for (i = 0, c = color4f;i < 6;i++, c += 4)
1152 c[0] = (c[0] * f1 + fogcolor[0] * f2);
1153 c[1] = (c[1] * f1 + fogcolor[1] * f2);
1154 c[2] = (c[2] * f1 + fogcolor[2] * f2);
1158 else if (ent->alpha != 1)
1160 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1161 m.pointer_color = color4f;
1162 for (i = 0, c = color4f;i < 6;i++, c += 4)
1166 m.pointer_color = nomodelcolor4f;
1168 R_Mesh_Draw(0, 6, 8, nomodelelements);
1171 void R_DrawNoModel(entity_render_t *ent)
1173 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1174 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1176 // R_DrawNoModelCallback(ent, 0);
1179 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1181 vec3_t right1, right2, diff, normal;
1183 VectorSubtract (org2, org1, normal);
1185 // calculate 'right' vector for start
1186 VectorSubtract (r_vieworigin, org1, diff);
1187 CrossProduct (normal, diff, right1);
1188 VectorNormalize (right1);
1190 // calculate 'right' vector for end
1191 VectorSubtract (r_vieworigin, org2, diff);
1192 CrossProduct (normal, diff, right2);
1193 VectorNormalize (right2);
1195 vert[ 0] = org1[0] + width * right1[0];
1196 vert[ 1] = org1[1] + width * right1[1];
1197 vert[ 2] = org1[2] + width * right1[2];
1198 vert[ 3] = org1[0] - width * right1[0];
1199 vert[ 4] = org1[1] - width * right1[1];
1200 vert[ 5] = org1[2] - width * right1[2];
1201 vert[ 6] = org2[0] - width * right2[0];
1202 vert[ 7] = org2[1] - width * right2[1];
1203 vert[ 8] = org2[2] - width * right2[2];
1204 vert[ 9] = org2[0] + width * right2[0];
1205 vert[10] = org2[1] + width * right2[1];
1206 vert[11] = org2[2] + width * right2[2];
1209 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1211 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)
1218 VectorSubtract(origin, r_vieworigin, diff);
1219 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1222 R_Mesh_Matrix(&r_identitymatrix);
1223 GL_BlendFunc(blendfunc1, blendfunc2);
1224 GL_DepthMask(false);
1225 GL_DepthTest(!depthdisable);
1227 varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1228 varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1229 varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1230 varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1231 varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1232 varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1233 varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1234 varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1235 varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1236 varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1237 varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1238 varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1240 memset(&m, 0, sizeof(m));
1241 m.tex[0] = R_GetTexture(texture);
1242 m.pointer_texcoord[0] = spritetexcoord2f;
1243 m.pointer_vertex = varray_vertex3f;
1245 GL_Color(cr, cg, cb, ca);
1246 R_Mesh_Draw(0, 4, 2, polygonelements);