]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rmain.c
fixed a mistake regarding clusterlist
[divverent/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24
25 // used for dlight push checking and other things
26 int r_framecount;
27
28 mplane_t frustum[4];
29
30 matrix4x4_t r_identitymatrix;
31
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;
33
34 // true during envmap command capture
35 qboolean envmap;
36
37 // maximum visible distance (recalculated from world box each frame)
38 float r_farclip;
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
43 qboolean r_rtworld;
44 qboolean r_rtworldshadows;
45 qboolean r_rtdlight;
46 qboolean r_rtdlightshadows;
47
48
49 // forces all rendering to draw triangle outlines
50 int r_showtrispass;
51
52 // view origin
53 vec3_t r_vieworigin;
54 vec3_t r_viewforward;
55 vec3_t r_viewleft;
56 vec3_t r_viewright;
57 vec3_t r_viewup;
58 int r_view_x;
59 int r_view_y;
60 int r_view_z;
61 int r_view_width;
62 int r_view_height;
63 int r_view_depth;
64 float r_view_fov_x;
65 float r_view_fov_y;
66 matrix4x4_t r_view_matrix;
67
68 //
69 // screen size info
70 //
71 refdef_t r_refdef;
72
73 // 8.8 fraction of base light value
74 unsigned short d_lightstylevalue[256];
75
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"};
85
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"};
93
94 cvar_t r_textureunits = {0, "r_textureunits", "32"};
95
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"};
100
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
110 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
111 {
112         int i;
113         for (i = 0;i < verts;i++)
114         {
115                 out[0] = in[0] * r;
116                 out[1] = in[1] * g;
117                 out[2] = in[2] * b;
118                 out[3] = in[3];
119                 in += 4;
120                 out += 4;
121         }
122 }
123
124 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
125 {
126         int i;
127         for (i = 0;i < verts;i++)
128         {
129                 out[0] = r;
130                 out[1] = g;
131                 out[2] = b;
132                 out[3] = a;
133                 out += 4;
134         }
135 }
136
137 vec3_t fogcolor;
138 vec_t fogdensity;
139 float fog_density, fog_red, fog_green, fog_blue;
140 qboolean fogenabled;
141 qboolean oldgl_fogenable;
142 void R_UpdateFog(void)
143 {
144         if (gamemode == GAME_NEHAHRA)
145         {
146                 if (gl_fogenable.integer)
147                 {
148                         oldgl_fogenable = true;
149                         fog_density = gl_fogdensity.value;
150                         fog_red = gl_fogred.value;
151                         fog_green = gl_foggreen.value;
152                         fog_blue = gl_fogblue.value;
153                 }
154                 else if (oldgl_fogenable)
155                 {
156                         oldgl_fogenable = false;
157                         fog_density = 0;
158                         fog_red = 0;
159                         fog_green = 0;
160                         fog_blue = 0;
161                 }
162         }
163         if (fog_density)
164         {
165                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
166                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
167                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
168         }
169         if (fog_density)
170         {
171                 fogenabled = true;
172                 fogdensity = -4000.0f / (fog_density * fog_density);
173                 // fog color was already set
174         }
175         else
176                 fogenabled = false;
177 }
178
179 // FIXME: move this to client?
180 void FOG_clear(void)
181 {
182         if (gamemode == GAME_NEHAHRA)
183         {
184                 Cvar_Set("gl_fogenable", "0");
185                 Cvar_Set("gl_fogdensity", "0.2");
186                 Cvar_Set("gl_fogred", "0.3");
187                 Cvar_Set("gl_foggreen", "0.3");
188                 Cvar_Set("gl_fogblue", "0.3");
189         }
190         fog_density = fog_red = fog_green = fog_blue = 0.0f;
191 }
192
193 // FIXME: move this to client?
194 void FOG_registercvars(void)
195 {
196         if (gamemode == GAME_NEHAHRA)
197         {
198                 Cvar_RegisterVariable (&gl_fogenable);
199                 Cvar_RegisterVariable (&gl_fogdensity);
200                 Cvar_RegisterVariable (&gl_fogred);
201                 Cvar_RegisterVariable (&gl_foggreen);
202                 Cvar_RegisterVariable (&gl_fogblue);
203                 Cvar_RegisterVariable (&gl_fogstart);
204                 Cvar_RegisterVariable (&gl_fogend);
205         }
206 }
207
208 void gl_main_start(void)
209 {
210         r_main_texturepool = R_AllocTexturePool();
211         r_bloom_texture_screen = NULL;
212         r_bloom_texture_bloom = NULL;
213 }
214
215 void gl_main_shutdown(void)
216 {
217         R_FreeTexturePool(&r_main_texturepool);
218         r_bloom_texture_screen = NULL;
219         r_bloom_texture_bloom = NULL;
220 }
221
222 extern void CL_ParseEntityLump(char *entitystring);
223 void gl_main_newmap(void)
224 {
225         // FIXME: move this code to client
226         int l;
227         char *entities, entname[MAX_QPATH];
228         r_framecount = 1;
229         if (cl.worldmodel)
230         {
231                 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
232                 l = strlen(entname) - 4;
233                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
234                 {
235                         strcpy(entname + l, ".ent");
236                         if ((entities = FS_LoadFile(entname, tempmempool, true)))
237                         {
238                                 CL_ParseEntityLump(entities);
239                                 Mem_Free(entities);
240                                 return;
241                         }
242                 }
243                 if (cl.worldmodel->brush.entities)
244                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
245         }
246 }
247
248 void GL_Main_Init(void)
249 {
250         Matrix4x4_CreateIdentity(&r_identitymatrix);
251 // FIXME: move this to client?
252         FOG_registercvars();
253         Cvar_RegisterVariable(&r_showtris);
254         Cvar_RegisterVariable(&r_drawentities);
255         Cvar_RegisterVariable(&r_drawviewmodel);
256         Cvar_RegisterVariable(&r_speeds);
257         Cvar_RegisterVariable(&r_fullbrights);
258         Cvar_RegisterVariable(&r_wateralpha);
259         Cvar_RegisterVariable(&r_dynamic);
260         Cvar_RegisterVariable(&r_fullbright);
261         Cvar_RegisterVariable(&r_textureunits);
262         Cvar_RegisterVariable(&r_lerpsprites);
263         Cvar_RegisterVariable(&r_lerpmodels);
264         Cvar_RegisterVariable(&r_waterscroll);
265         Cvar_RegisterVariable(&r_watershader);
266         Cvar_RegisterVariable(&r_drawcollisionbrushes);
267         Cvar_RegisterVariable(&r_bloom);
268         Cvar_RegisterVariable(&r_bloom_intensity);
269         Cvar_RegisterVariable(&r_bloom_blur);
270         Cvar_RegisterVariable(&r_bloom_resolution);
271         Cvar_RegisterVariable(&r_bloom_power);
272         if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
273                 Cvar_SetValue("r_fullbrights", 0);
274         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
275 }
276
277 static vec3_t r_farclip_origin;
278 static vec3_t r_farclip_direction;
279 static vec_t r_farclip_directiondist;
280 static vec_t r_farclip_meshfarclip;
281 static int r_farclip_directionbit0;
282 static int r_farclip_directionbit1;
283 static int r_farclip_directionbit2;
284
285 // enlarge farclip to accomodate box
286 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
287 {
288         float d;
289         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
290           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
291           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
292         if (r_farclip_meshfarclip < d)
293                 r_farclip_meshfarclip = d;
294 }
295
296 // return farclip value
297 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
298 {
299         int i;
300
301         VectorCopy(origin, r_farclip_origin);
302         VectorCopy(direction, r_farclip_direction);
303         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
304         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
305         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
306         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
307         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
308
309         if (r_refdef.worldmodel)
310                 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
311         for (i = 0;i < r_refdef.numentities;i++)
312                 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
313
314         return r_farclip_meshfarclip - r_farclip_directiondist;
315 }
316
317 extern void R_Textures_Init(void);
318 extern void Mod_RenderInit(void);
319 extern void GL_Draw_Init(void);
320 extern void GL_Main_Init(void);
321 extern void R_Shadow_Init(void);
322 extern void GL_Models_Init(void);
323 extern void R_Sky_Init(void);
324 extern void GL_Surf_Init(void);
325 extern void R_Crosshairs_Init(void);
326 extern void R_Light_Init(void);
327 extern void R_Particles_Init(void);
328 extern void R_Explosion_Init(void);
329 extern void ui_init(void);
330 extern void gl_backend_init(void);
331 extern void Sbar_Init(void);
332 extern void R_LightningBeams_Init(void);
333
334 void Render_Init(void)
335 {
336         R_Textures_Init();
337         Mod_RenderInit();
338         gl_backend_init();
339         R_MeshQueue_Init();
340         GL_Draw_Init();
341         GL_Main_Init();
342         R_Shadow_Init();
343         GL_Models_Init();
344         R_Sky_Init();
345         GL_Surf_Init();
346         R_Crosshairs_Init();
347         R_Light_Init();
348         R_Particles_Init();
349         R_Explosion_Init();
350         //ui_init();
351         UI_Init();
352         Sbar_Init();
353         R_LightningBeams_Init();
354 }
355
356 /*
357 ===============
358 GL_Init
359 ===============
360 */
361 extern char *ENGINE_EXTENSIONS;
362 void GL_Init (void)
363 {
364         VID_CheckExtensions();
365
366         // LordHavoc: report supported extensions
367         Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
368
369         // clear to black (loading plaque will be seen over this)
370         qglClearColor(0,0,0,1);
371         qglClear(GL_COLOR_BUFFER_BIT);
372 }
373
374 int R_CullBox(const vec3_t mins, const vec3_t maxs)
375 {
376         int i;
377         mplane_t *p;
378         for (i = 0;i < 4;i++)
379         {
380                 p = frustum + i;
381                 switch(p->signbits)
382                 {
383                 default:
384                 case 0:
385                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
386                                 return true;
387                         break;
388                 case 1:
389                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
390                                 return true;
391                         break;
392                 case 2:
393                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
394                                 return true;
395                         break;
396                 case 3:
397                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
398                                 return true;
399                         break;
400                 case 4:
401                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
402                                 return true;
403                         break;
404                 case 5:
405                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
406                                 return true;
407                         break;
408                 case 6:
409                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
410                                 return true;
411                         break;
412                 case 7:
413                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
414                                 return true;
415                         break;
416                 }
417         }
418         return false;
419 }
420
421 //==================================================================================
422
423 static void R_MarkEntities (void)
424 {
425         int i;
426         entity_render_t *ent;
427
428         if (!r_drawentities.integer)
429                 return;
430
431         for (i = 0;i < r_refdef.numentities;i++)
432         {
433                 ent = r_refdef.entities[i];
434                 Mod_CheckLoaded(ent->model);
435                 // some of the renderer still relies on origin...
436                 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
437                 // some of the renderer still relies on scale...
438                 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
439                 R_UpdateEntLights(ent);
440                 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
441                  && (!VIS_CullBox(ent->mins, ent->maxs) || (ent->effects & EF_NODEPTHTEST))
442                  && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
443                         ent->visframe = r_framecount;
444         }
445 }
446
447 // only used if skyrendermasked, and normally returns false
448 int R_DrawBrushModelsSky (void)
449 {
450         int i, sky;
451         entity_render_t *ent;
452
453         if (!r_drawentities.integer)
454                 return false;
455
456         sky = false;
457         for (i = 0;i < r_refdef.numentities;i++)
458         {
459                 ent = r_refdef.entities[i];
460                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
461                 {
462                         ent->model->DrawSky(ent);
463                         sky = true;
464                 }
465         }
466         return sky;
467 }
468
469 void R_DrawNoModel(entity_render_t *ent);
470 void R_DrawModels(void)
471 {
472         int i;
473         entity_render_t *ent;
474
475         if (!r_drawentities.integer)
476                 return;
477
478         for (i = 0;i < r_refdef.numentities;i++)
479         {
480                 ent = r_refdef.entities[i];
481                 if (ent->visframe == r_framecount)
482                 {
483                         if (ent->model && ent->model->Draw != NULL)
484                                 ent->model->Draw(ent);
485                         else
486                                 R_DrawNoModel(ent);
487                 }
488         }
489 }
490
491 static void R_SetFrustum(void)
492 {
493         // break apart the view matrix into vectors for various purposes
494         Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
495         VectorNegate(r_viewleft, r_viewright);
496
497         // LordHavoc: note to all quake engine coders, the special case for 90
498         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
499         // disabled as well.
500
501         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
502         RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
503         frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
504         PlaneClassify(&frustum[0]);
505
506         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
507         RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
508         frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
509         PlaneClassify(&frustum[1]);
510
511         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
512         RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
513         frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
514         PlaneClassify(&frustum[2]);
515
516         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
517         RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
518         frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
519         PlaneClassify(&frustum[3]);
520 }
521
522 static void R_BlendView(void)
523 {
524         rmeshstate_t m;
525
526         if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
527                 return;
528
529         GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
530         GL_DepthMask(true);
531         GL_DepthTest(false);
532         R_Mesh_Matrix(&r_identitymatrix);
533         varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
534         varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
535         varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
536         varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
537         if (r_bloom.integer && r_bloom_resolution.value >= 32 && r_bloom_power.integer >= 1 && r_bloom_power.integer < 100 && r_bloom_blur.value >= 0 && r_bloom_blur.value < 512)
538         {
539                 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
540                 float xoffset, yoffset, r;
541                 c_bloom++;
542                 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
543                 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
544                 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
545                 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
546                 varray_texcoord2f[0][0] = 0;
547                 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
548                 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
549                 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
550                 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
551                 varray_texcoord2f[0][5] = 0;
552                 varray_texcoord2f[0][6] = 0;
553                 varray_texcoord2f[0][7] = 0;
554                 varray_texcoord2f[1][0] = 0;
555                 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
556                 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
557                 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
558                 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
559                 varray_texcoord2f[1][5] = 0;
560                 varray_texcoord2f[1][6] = 0;
561                 varray_texcoord2f[1][7] = 0;
562                 if (!r_bloom_texture_screen)
563                         r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
564                 if (!r_bloom_texture_bloom)
565                         r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
566                 memset(&m, 0, sizeof(m));
567                 m.pointer_vertex = varray_vertex3f;
568                 m.pointer_texcoord[0] = varray_texcoord2f[0];
569                 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
570                 R_Mesh_State(&m);
571                 // copy view to a texture
572                 GL_ActiveTexture(0);
573                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
574                 c_bloomcopies++;
575                 c_bloomcopypixels += r_view_width * r_view_height;
576                 // now scale it down to the bloom size and raise to a power of itself
577                 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
578                 // TODO: optimize with multitexture or GLSL
579                 GL_BlendFunc(GL_ONE, GL_ZERO);
580                 GL_Color(1, 1, 1, 1);
581                 R_Mesh_Draw(4, 2, polygonelements);
582                 c_bloomdraws++;
583                 c_bloomdrawpixels += bloomwidth * bloomheight;
584                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
585                 for (x = 1;x < r_bloom_power.integer;x++)
586                 {
587                         R_Mesh_Draw(4, 2, polygonelements);
588                         c_bloomdraws++;
589                         c_bloomdrawpixels += bloomwidth * bloomheight;
590                 }
591                 // copy the bloom view to a texture
592                 memset(&m, 0, sizeof(m));
593                 m.pointer_vertex = varray_vertex3f;
594                 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
595                 m.pointer_texcoord[0] = varray_texcoord2f[2];
596                 R_Mesh_State(&m);
597                 GL_ActiveTexture(0);
598                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
599                 c_bloomcopies++;
600                 c_bloomcopypixels += bloomwidth * bloomheight;
601                 // blend on at multiple offsets vertically
602                 // TODO: do offset blends using GLSL
603                 range = r_bloom_blur.integer * bloomwidth / 320;
604                 GL_BlendFunc(GL_ONE, GL_ZERO);
605                 for (x = -range;x <= range;x++)
606                 {
607                         xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
608                         yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
609                         varray_texcoord2f[2][0] = xoffset+0;
610                         varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
611                         varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
612                         varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
613                         varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
614                         varray_texcoord2f[2][5] = yoffset+0;
615                         varray_texcoord2f[2][6] = xoffset+0;
616                         varray_texcoord2f[2][7] = yoffset+0;
617                         r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
618                         if (r < 0.01f)
619                                 continue;
620                         GL_Color(r, r, r, 1);
621                         R_Mesh_Draw(4, 2, polygonelements);
622                         c_bloomdraws++;
623                         c_bloomdrawpixels += bloomwidth * bloomheight;
624                         GL_BlendFunc(GL_ONE, GL_ONE);
625                 }
626                 // copy the blurred bloom view to a texture
627                 GL_ActiveTexture(0);
628                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
629                 c_bloomcopies++;
630                 c_bloomcopypixels += bloomwidth * bloomheight;
631                 // blend on at multiple offsets horizontally
632                 // TODO: do offset blends using GLSL
633                 range = r_bloom_blur.integer * bloomwidth / 320;
634                 GL_BlendFunc(GL_ONE, GL_ZERO);
635                 for (x = -range;x <= range;x++)
636                 {
637                         xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
638                         yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
639                         varray_texcoord2f[2][0] = xoffset+0;
640                         varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
641                         varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
642                         varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
643                         varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
644                         varray_texcoord2f[2][5] = yoffset+0;
645                         varray_texcoord2f[2][6] = xoffset+0;
646                         varray_texcoord2f[2][7] = yoffset+0;
647                         r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
648                         if (r < 0.01f)
649                                 continue;
650                         GL_Color(r, r, r, 1);
651                         R_Mesh_Draw(4, 2, polygonelements);
652                         c_bloomdraws++;
653                         c_bloomdrawpixels += bloomwidth * bloomheight;
654                         GL_BlendFunc(GL_ONE, GL_ONE);
655                 }
656                 // copy the blurred bloom view to a texture
657                 GL_ActiveTexture(0);
658                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
659                 c_bloomcopies++;
660                 c_bloomcopypixels += bloomwidth * bloomheight;
661                 // go back to full view area
662                 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
663                 // put the original view back in place
664                 memset(&m, 0, sizeof(m));
665                 m.pointer_vertex = varray_vertex3f;
666                 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
667                 m.pointer_texcoord[0] = varray_texcoord2f[0];
668 #if 0
669                 dobloomblend = false;
670 #else
671                 // do both in one pass if possible
672                 if (r_textureunits.integer >= 2 && gl_combine.integer)
673                 {
674                         dobloomblend = false;
675                         m.texcombinergb[1] = GL_ADD;
676                         m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
677                         m.pointer_texcoord[1] = varray_texcoord2f[1];
678                 }
679                 else
680                         dobloomblend = true;
681 #endif
682                 R_Mesh_State(&m);
683                 GL_BlendFunc(GL_ONE, GL_ZERO);
684                 GL_Color(1,1,1,1);
685                 R_Mesh_Draw(4, 2, polygonelements);
686                 c_bloomdraws++;
687                 c_bloomdrawpixels += r_view_width * r_view_height;
688                 // now blend on the bloom texture if multipass
689                 if (dobloomblend)
690                 {
691                         memset(&m, 0, sizeof(m));
692                         m.pointer_vertex = varray_vertex3f;
693                         m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
694                         m.pointer_texcoord[0] = varray_texcoord2f[1];
695                         R_Mesh_State(&m);
696                         GL_BlendFunc(GL_ONE, GL_ONE);
697                         GL_Color(1,1,1,1);
698                         R_Mesh_Draw(4, 2, polygonelements);
699                         c_bloomdraws++;
700                         c_bloomdrawpixels += r_view_width * r_view_height;
701                 }
702         }
703         if (r_refdef.viewblend[3] >= 0.01f)
704         {
705                 // apply a color tint to the whole view
706                 memset(&m, 0, sizeof(m));
707                 m.pointer_vertex = varray_vertex3f;
708                 R_Mesh_State(&m);
709                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
710                 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
711                 R_Mesh_Draw(4, 2, polygonelements);
712         }
713 }
714
715 void R_RenderScene(void);
716
717 /*
718 ================
719 R_RenderView
720 ================
721 */
722 void R_RenderView(void)
723 {
724         if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
725                 return; //Host_Error ("R_RenderView: NULL worldmodel");
726
727         r_view_width = bound(0, r_refdef.width, vid.realwidth);
728         r_view_height = bound(0, r_refdef.height, vid.realheight);
729         r_view_depth = 1;
730         r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
731         r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
732         r_view_z = 0;
733         r_view_fov_x = bound(1, r_refdef.fov_x, 170);
734         r_view_fov_y = bound(1, r_refdef.fov_y, 170);
735         r_view_matrix = r_refdef.viewentitymatrix;
736         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
737         r_rtworld = r_shadow_realtime_world.integer;
738         r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
739         r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
740         r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
741         r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
742
743         // GL is weird because it's bottom to top, r_view_y is top to bottom
744         qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
745         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
746         GL_ScissorTest(true);
747         GL_DepthMask(true);
748         R_ClearScreen();
749         R_Textures_Frame();
750         R_UpdateFog();
751         R_UpdateLights();
752         R_TimeReport("setup");
753
754         qglDepthFunc(GL_LEQUAL);
755         qglPolygonOffset(0, 0);
756         qglEnable(GL_POLYGON_OFFSET_FILL);
757
758         R_RenderScene();
759
760         qglPolygonOffset(0, 0);
761         qglDisable(GL_POLYGON_OFFSET_FILL);
762
763         R_BlendView();
764         R_TimeReport("blendview");
765
766         GL_Scissor(0, 0, vid.realwidth, vid.realheight);
767         GL_ScissorTest(false);
768 }
769
770 extern void R_DrawLightningBeams (void);
771 void R_RenderScene(void)
772 {
773         // don't let sound skip if going slow
774         if (r_refdef.extraupdate)
775                 S_ExtraUpdate ();
776
777         r_framecount++;
778
779         R_MeshQueue_BeginScene();
780
781         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
782
783         R_SetFrustum();
784
785         r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
786         if (r_rtworldshadows || r_rtdlightshadows)
787                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
788         else
789                 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
790
791         GL_SetupView_Orientation_FromEntity(&r_view_matrix);
792
793         R_SkyStartFrame();
794
795         R_WorldVisibility();
796         R_TimeReport("worldvis");
797
798         R_MarkEntities();
799         R_TimeReport("markentity");
800
801         R_Shadow_UpdateWorldLightSelection();
802
803         // don't let sound skip if going slow
804         if (r_refdef.extraupdate)
805                 S_ExtraUpdate ();
806
807         GL_ShowTrisColor(0.025, 0.025, 0, 1);
808         if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
809         {
810                 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
811                 R_TimeReport("worldsky");
812         }
813
814         if (R_DrawBrushModelsSky())
815                 R_TimeReport("bmodelsky");
816
817         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
818         if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
819         {
820                 r_refdef.worldmodel->Draw(r_refdef.worldentity);
821                 R_TimeReport("world");
822         }
823
824         // don't let sound skip if going slow
825         if (r_refdef.extraupdate)
826                 S_ExtraUpdate ();
827
828         GL_ShowTrisColor(0, 0.015, 0, 1);
829
830         R_DrawModels();
831         R_TimeReport("models");
832
833         // don't let sound skip if going slow
834         if (r_refdef.extraupdate)
835                 S_ExtraUpdate ();
836
837         GL_ShowTrisColor(0, 0, 0.033, 1);
838         R_ShadowVolumeLighting(false);
839         R_TimeReport("rtlights");
840
841         // don't let sound skip if going slow
842         if (r_refdef.extraupdate)
843                 S_ExtraUpdate ();
844
845         GL_ShowTrisColor(0.1, 0, 0, 1);
846
847         R_DrawLightningBeams();
848         R_TimeReport("lightning");
849
850         R_DrawParticles();
851         R_TimeReport("particles");
852
853         R_DrawExplosions();
854         R_TimeReport("explosions");
855
856         R_MeshQueue_RenderTransparent();
857         R_TimeReport("drawtrans");
858
859         R_DrawCoronas();
860         R_TimeReport("coronas");
861
862         R_DrawWorldCrosshair();
863         R_TimeReport("crosshair");
864
865         R_MeshQueue_Render();
866         R_MeshQueue_EndScene();
867
868         if (r_shadow_visiblevolumes.integer && !r_showtrispass)
869         {
870                 R_ShadowVolumeLighting(true);
871                 R_TimeReport("shadowvolume");
872         }
873
874         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
875
876         // don't let sound skip if going slow
877         if (r_refdef.extraupdate)
878                 S_ExtraUpdate ();
879 }
880
881 /*
882 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
883 {
884         int i;
885         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
886         rmeshstate_t m;
887         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
888         GL_DepthMask(false);
889         GL_DepthTest(true);
890         R_Mesh_Matrix(&r_identitymatrix);
891
892         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
893         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
894         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
895         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
896         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
897         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
898         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
899         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
900         R_FillColors(color, 8, cr, cg, cb, ca);
901         if (fogenabled)
902         {
903                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
904                 {
905                         VectorSubtract(v, r_vieworigin, diff);
906                         f2 = exp(fogdensity/DotProduct(diff, diff));
907                         f1 = 1 - f2;
908                         c[0] = c[0] * f1 + fogcolor[0] * f2;
909                         c[1] = c[1] * f1 + fogcolor[1] * f2;
910                         c[2] = c[2] * f1 + fogcolor[2] * f2;
911                 }
912         }
913         memset(&m, 0, sizeof(m));
914         m.pointer_vertex = vertex3f;
915         m.pointer_color = color;
916         R_Mesh_State(&m);
917         R_Mesh_Draw(8, 12);
918 }
919 */
920
921 int nomodelelements[24] =
922 {
923         5, 2, 0,
924         5, 1, 2,
925         5, 0, 3,
926         5, 3, 1,
927         0, 2, 4,
928         2, 1, 4,
929         3, 0, 4,
930         1, 3, 4
931 };
932
933 float nomodelvertex3f[6*3] =
934 {
935         -16,   0,   0,
936          16,   0,   0,
937           0, -16,   0,
938           0,  16,   0,
939           0,   0, -16,
940           0,   0,  16
941 };
942
943 float nomodelcolor4f[6*4] =
944 {
945         0.0f, 0.0f, 0.5f, 1.0f,
946         0.0f, 0.0f, 0.5f, 1.0f,
947         0.0f, 0.5f, 0.0f, 1.0f,
948         0.0f, 0.5f, 0.0f, 1.0f,
949         0.5f, 0.0f, 0.0f, 1.0f,
950         0.5f, 0.0f, 0.0f, 1.0f
951 };
952
953 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
954 {
955         const entity_render_t *ent = calldata1;
956         int i;
957         float f1, f2, *c, diff[3];
958         float color4f[6*4];
959         rmeshstate_t m;
960         R_Mesh_Matrix(&ent->matrix);
961
962         memset(&m, 0, sizeof(m));
963         m.pointer_vertex = nomodelvertex3f;
964
965         if (ent->flags & EF_ADDITIVE)
966         {
967                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
968                 GL_DepthMask(false);
969         }
970         else if (ent->alpha < 1)
971         {
972                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
973                 GL_DepthMask(false);
974         }
975         else
976         {
977                 GL_BlendFunc(GL_ONE, GL_ZERO);
978                 GL_DepthMask(true);
979         }
980         GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
981         if (fogenabled)
982         {
983                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
984                 m.pointer_color = color4f;
985                 VectorSubtract(ent->origin, r_vieworigin, diff);
986                 f2 = exp(fogdensity/DotProduct(diff, diff));
987                 f1 = 1 - f2;
988                 for (i = 0, c = color4f;i < 6;i++, c += 4)
989                 {
990                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
991                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
992                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
993                         c[3] *= ent->alpha;
994                 }
995         }
996         else if (ent->alpha != 1)
997         {
998                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
999                 m.pointer_color = color4f;
1000                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1001                         c[3] *= ent->alpha;
1002         }
1003         else
1004                 m.pointer_color = nomodelcolor4f;
1005         R_Mesh_State(&m);
1006         R_Mesh_Draw(6, 8, nomodelelements);
1007 }
1008
1009 void R_DrawNoModel(entity_render_t *ent)
1010 {
1011         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1012                 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1013         //else
1014         //      R_DrawNoModelCallback(ent, 0);
1015 }
1016
1017 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1018 {
1019         vec3_t right1, right2, diff, normal;
1020
1021         VectorSubtract (org2, org1, normal);
1022
1023         // calculate 'right' vector for start
1024         VectorSubtract (r_vieworigin, org1, diff);
1025         CrossProduct (normal, diff, right1);
1026         VectorNormalize (right1);
1027
1028         // calculate 'right' vector for end
1029         VectorSubtract (r_vieworigin, org2, diff);
1030         CrossProduct (normal, diff, right2);
1031         VectorNormalize (right2);
1032
1033         vert[ 0] = org1[0] + width * right1[0];
1034         vert[ 1] = org1[1] + width * right1[1];
1035         vert[ 2] = org1[2] + width * right1[2];
1036         vert[ 3] = org1[0] - width * right1[0];
1037         vert[ 4] = org1[1] - width * right1[1];
1038         vert[ 5] = org1[2] - width * right1[2];
1039         vert[ 6] = org2[0] - width * right2[0];
1040         vert[ 7] = org2[1] - width * right2[1];
1041         vert[ 8] = org2[2] - width * right2[2];
1042         vert[ 9] = org2[0] + width * right2[0];
1043         vert[10] = org2[1] + width * right2[1];
1044         vert[11] = org2[2] + width * right2[2];
1045 }
1046
1047 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1048
1049 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depthdisable, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
1050 {
1051         float diff[3];
1052         rmeshstate_t m;
1053
1054         if (fogenabled)
1055         {
1056                 VectorSubtract(origin, r_vieworigin, diff);
1057                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1058         }
1059
1060         R_Mesh_Matrix(&r_identitymatrix);
1061         GL_BlendFunc(blendfunc1, blendfunc2);
1062         GL_DepthMask(false);
1063         GL_DepthTest(!depthdisable);
1064
1065         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1066         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1067         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1068         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1069         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1070         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1071         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1072         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1073         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1074         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1075         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1076         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1077
1078         memset(&m, 0, sizeof(m));
1079         m.tex[0] = R_GetTexture(texture);
1080         m.pointer_texcoord[0] = spritetexcoord2f;
1081         m.pointer_vertex = varray_vertex3f;
1082         R_Mesh_State(&m);
1083         GL_Color(cr, cg, cb, ca);
1084         R_Mesh_Draw(4, 2, polygonelements);
1085 }
1086