be9c5aaec45ffaf584cdb573f3b1deaabd3cad66
[xonotic/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
107 cvar_t developer_texturelogging = {0, "developer_texturelogging", "1"};
108
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;
118 rtexture_t *r_texture_detailtextures[NUM_DETAILTEXTURES];
119 rtexture_t *r_texture_distorttexture[64];
120
121 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
122 {
123         int i;
124         for (i = 0;i < verts;i++)
125         {
126                 out[0] = in[0] * r;
127                 out[1] = in[1] * g;
128                 out[2] = in[2] * b;
129                 out[3] = in[3];
130                 in += 4;
131                 out += 4;
132         }
133 }
134
135 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
136 {
137         int i;
138         for (i = 0;i < verts;i++)
139         {
140                 out[0] = r;
141                 out[1] = g;
142                 out[2] = b;
143                 out[3] = a;
144                 out += 4;
145         }
146 }
147
148 vec3_t fogcolor;
149 vec_t fogdensity;
150 float fog_density, fog_red, fog_green, fog_blue;
151 qboolean fogenabled;
152 qboolean oldgl_fogenable;
153 void R_UpdateFog(void)
154 {
155         if (gamemode == GAME_NEHAHRA)
156         {
157                 if (gl_fogenable.integer)
158                 {
159                         oldgl_fogenable = true;
160                         fog_density = gl_fogdensity.value;
161                         fog_red = gl_fogred.value;
162                         fog_green = gl_foggreen.value;
163                         fog_blue = gl_fogblue.value;
164                 }
165                 else if (oldgl_fogenable)
166                 {
167                         oldgl_fogenable = false;
168                         fog_density = 0;
169                         fog_red = 0;
170                         fog_green = 0;
171                         fog_blue = 0;
172                 }
173         }
174         if (fog_density)
175         {
176                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
177                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
178                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
179         }
180         if (fog_density)
181         {
182                 fogenabled = true;
183                 fogdensity = -4000.0f / (fog_density * fog_density);
184                 // fog color was already set
185         }
186         else
187                 fogenabled = false;
188 }
189
190 // FIXME: move this to client?
191 void FOG_clear(void)
192 {
193         if (gamemode == GAME_NEHAHRA)
194         {
195                 Cvar_Set("gl_fogenable", "0");
196                 Cvar_Set("gl_fogdensity", "0.2");
197                 Cvar_Set("gl_fogred", "0.3");
198                 Cvar_Set("gl_foggreen", "0.3");
199                 Cvar_Set("gl_fogblue", "0.3");
200         }
201         fog_density = fog_red = fog_green = fog_blue = 0.0f;
202 }
203
204 // FIXME: move this to client?
205 void FOG_registercvars(void)
206 {
207         if (gamemode == GAME_NEHAHRA)
208         {
209                 Cvar_RegisterVariable (&gl_fogenable);
210                 Cvar_RegisterVariable (&gl_fogdensity);
211                 Cvar_RegisterVariable (&gl_fogred);
212                 Cvar_RegisterVariable (&gl_foggreen);
213                 Cvar_RegisterVariable (&gl_fogblue);
214                 Cvar_RegisterVariable (&gl_fogstart);
215                 Cvar_RegisterVariable (&gl_fogend);
216         }
217 }
218
219 static void R_BuildDetailTextures (void)
220 {
221         int i, x, y, light;
222         float vc[3], vx[3], vy[3], vn[3], lightdir[3];
223 #define DETAILRESOLUTION 256
224         qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION];
225         lightdir[0] = 0.5;
226         lightdir[1] = 1;
227         lightdir[2] = -0.25;
228         VectorNormalize(lightdir);
229         for (i = 0;i < NUM_DETAILTEXTURES;i++)
230         {
231                 fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
232                 for (y = 0;y < DETAILRESOLUTION;y++)
233                 {
234                         for (x = 0;x < DETAILRESOLUTION;x++)
235                         {
236                                 vc[0] = x;
237                                 vc[1] = y;
238                                 vc[2] = noise[y][x] * (1.0f / 32.0f);
239                                 vx[0] = x + 1;
240                                 vx[1] = y;
241                                 vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
242                                 vy[0] = x;
243                                 vy[1] = y + 1;
244                                 vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
245                                 VectorSubtract(vx, vc, vx);
246                                 VectorSubtract(vy, vc, vy);
247                                 CrossProduct(vx, vy, vn);
248                                 VectorNormalize(vn);
249                                 light = 128 - DotProduct(vn, lightdir) * 128;
250                                 light = bound(0, light, 255);
251                                 data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
252                                 data[y][x][3] = 255;
253                         }
254                 }
255                 r_texture_detailtextures[i] = R_LoadTexture2D(r_main_texturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE, NULL);
256         }
257 }
258
259 static qbyte R_MorphDistortTexture (double y0, double y1, double y2, double y3, double morph)
260 {
261         int m = (int)(((y1 + y3 - (y0 + y2)) * morph * morph * morph) +
262                         ((2 * (y0 - y1) + y2 - y3) * morph * morph) +
263                         ((y2 - y0) * morph) +
264                         (y1));
265         return (qbyte)bound(0, m, 255);
266 }
267
268 static void R_BuildDistortTexture (void)
269 {
270         int x, y, i, j;
271 #define DISTORTRESOLUTION 32
272         qbyte data[5][DISTORTRESOLUTION][DISTORTRESOLUTION][2];
273
274         for (i=0; i<4; i++)
275         {
276                 for (y=0; y<DISTORTRESOLUTION; y++)
277                 {
278                         for (x=0; x<DISTORTRESOLUTION; x++)
279                         {
280                                 data[i][y][x][0] = rand () & 255;
281                                 data[i][y][x][1] = rand () & 255;
282                         }
283                 }
284         }
285
286         for (i=0; i<4; i++)
287         {
288                 for (j=0; j<16; j++)
289                 {
290                         r_texture_distorttexture[i*16+j] = NULL;
291                         if (gl_textureshader)
292                         {
293                                 for (y=0; y<DISTORTRESOLUTION; y++)
294                                 {
295                                         for (x=0; x<DISTORTRESOLUTION; x++)
296                                         {
297                                                 data[4][y][x][0] = R_MorphDistortTexture (data[(i-1)&3][y][x][0], data[i][y][x][0], data[(i+1)&3][y][x][0], data[(i+2)&3][y][x][0], 0.0625*j);
298                                                 data[4][y][x][1] = R_MorphDistortTexture (data[(i-1)&3][y][x][1], data[i][y][x][1], data[(i+1)&3][y][x][1], data[(i+2)&3][y][x][1], 0.0625*j);
299                                         }
300                                 }
301                                 r_texture_distorttexture[i*16+j] = R_LoadTexture2D(r_main_texturepool, va("distorttexture%i", i*16+j), DISTORTRESOLUTION, DISTORTRESOLUTION, &data[4][0][0][0], TEXTYPE_DSDT, TEXF_PRECACHE, NULL);
302                         }
303                 }
304         }
305 }
306
307 static void R_BuildBlankTextures(void)
308 {
309         qbyte data[4];
310         data[0] = 128; // normal X
311         data[1] = 128; // normal Y
312         data[2] = 255; // normal Z
313         data[3] = 128; // height
314         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
315         data[0] = 255;
316         data[1] = 255;
317         data[2] = 255;
318         data[3] = 255;
319         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
320         data[0] = 0;
321         data[1] = 0;
322         data[2] = 0;
323         data[3] = 255;
324         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
325 }
326
327 static void R_BuildNoTexture(void)
328 {
329         int x, y;
330         qbyte pix[16][16][4];
331         // this makes a light grey/dark grey checkerboard texture
332         for (y = 0;y < 16;y++)
333         {
334                 for (x = 0;x < 16;x++)
335                 {
336                         if ((y < 8) ^ (x < 8))
337                         {
338                                 pix[y][x][0] = 128;
339                                 pix[y][x][1] = 128;
340                                 pix[y][x][2] = 128;
341                                 pix[y][x][3] = 255;
342                         }
343                         else
344                         {
345                                 pix[y][x][0] = 64;
346                                 pix[y][x][1] = 64;
347                                 pix[y][x][2] = 64;
348                                 pix[y][x][3] = 255;
349                         }
350                 }
351         }
352         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
353 }
354
355 static void R_BuildWhiteCube(void)
356 {
357         qbyte data[6*1*1*4];
358         data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
359         data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
360         data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
361         data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
362         data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
363         data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
364         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
365 }
366
367 static void R_BuildNormalizationCube(void)
368 {
369         int x, y, side;
370         vec3_t v;
371         vec_t s, t, intensity;
372 #define NORMSIZE 64
373         qbyte data[6][NORMSIZE][NORMSIZE][4];
374         for (side = 0;side < 6;side++)
375         {
376                 for (y = 0;y < NORMSIZE;y++)
377                 {
378                         for (x = 0;x < NORMSIZE;x++)
379                         {
380                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
381                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
382                                 switch(side)
383                                 {
384                                 case 0:
385                                         v[0] = 1;
386                                         v[1] = -t;
387                                         v[2] = -s;
388                                         break;
389                                 case 1:
390                                         v[0] = -1;
391                                         v[1] = -t;
392                                         v[2] = s;
393                                         break;
394                                 case 2:
395                                         v[0] = s;
396                                         v[1] = 1;
397                                         v[2] = t;
398                                         break;
399                                 case 3:
400                                         v[0] = s;
401                                         v[1] = -1;
402                                         v[2] = -t;
403                                         break;
404                                 case 4:
405                                         v[0] = s;
406                                         v[1] = -t;
407                                         v[2] = 1;
408                                         break;
409                                 case 5:
410                                         v[0] = -s;
411                                         v[1] = -t;
412                                         v[2] = -1;
413                                         break;
414                                 }
415                                 intensity = 127.0f / sqrt(DotProduct(v, v));
416                                 data[side][y][x][0] = 128.0f + intensity * v[0];
417                                 data[side][y][x][1] = 128.0f + intensity * v[1];
418                                 data[side][y][x][2] = 128.0f + intensity * v[2];
419                                 data[side][y][x][3] = 255;
420                         }
421                 }
422         }
423         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
424 }
425
426 void gl_main_start(void)
427 {
428         r_main_texturepool = R_AllocTexturePool();
429         r_bloom_texture_screen = NULL;
430         r_bloom_texture_bloom = NULL;
431         R_BuildBlankTextures();
432         R_BuildNoTexture();
433         R_BuildDetailTextures();
434         R_BuildDistortTexture();
435         if (gl_texturecubemap)
436         {
437                 R_BuildWhiteCube();
438                 R_BuildNormalizationCube();
439         }
440 }
441
442 void gl_main_shutdown(void)
443 {
444         R_FreeTexturePool(&r_main_texturepool);
445         r_bloom_texture_screen = NULL;
446         r_bloom_texture_bloom = NULL;
447         r_texture_blanknormalmap = NULL;
448         r_texture_white = NULL;
449         r_texture_black = NULL;
450         r_texture_whitecube = NULL;
451         r_texture_normalizationcube = NULL;
452 }
453
454 extern void CL_ParseEntityLump(char *entitystring);
455 void gl_main_newmap(void)
456 {
457         // FIXME: move this code to client
458         int l;
459         char *entities, entname[MAX_QPATH];
460         r_framecount = 1;
461         if (cl.worldmodel)
462         {
463                 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
464                 l = strlen(entname) - 4;
465                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
466                 {
467                         strcpy(entname + l, ".ent");
468                         if ((entities = FS_LoadFile(entname, tempmempool, true)))
469                         {
470                                 CL_ParseEntityLump(entities);
471                                 Mem_Free(entities);
472                                 return;
473                         }
474                 }
475                 if (cl.worldmodel->brush.entities)
476                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
477         }
478 }
479
480 void GL_Main_Init(void)
481 {
482         Matrix4x4_CreateIdentity(&r_identitymatrix);
483 // FIXME: move this to client?
484         FOG_registercvars();
485         Cvar_RegisterVariable(&r_showtris);
486         Cvar_RegisterVariable(&r_drawentities);
487         Cvar_RegisterVariable(&r_drawviewmodel);
488         Cvar_RegisterVariable(&r_speeds);
489         Cvar_RegisterVariable(&r_fullbrights);
490         Cvar_RegisterVariable(&r_wateralpha);
491         Cvar_RegisterVariable(&r_dynamic);
492         Cvar_RegisterVariable(&r_fullbright);
493         Cvar_RegisterVariable(&r_textureunits);
494         Cvar_RegisterVariable(&r_lerpsprites);
495         Cvar_RegisterVariable(&r_lerpmodels);
496         Cvar_RegisterVariable(&r_waterscroll);
497         Cvar_RegisterVariable(&r_watershader);
498         Cvar_RegisterVariable(&r_drawcollisionbrushes);
499         Cvar_RegisterVariable(&r_bloom);
500         Cvar_RegisterVariable(&r_bloom_intensity);
501         Cvar_RegisterVariable(&r_bloom_blur);
502         Cvar_RegisterVariable(&r_bloom_resolution);
503         Cvar_RegisterVariable(&r_bloom_power);
504         Cvar_RegisterVariable(&developer_texturelogging);
505         if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
506                 Cvar_SetValue("r_fullbrights", 0);
507         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
508 }
509
510 static vec3_t r_farclip_origin;
511 static vec3_t r_farclip_direction;
512 static vec_t r_farclip_directiondist;
513 static vec_t r_farclip_meshfarclip;
514 static int r_farclip_directionbit0;
515 static int r_farclip_directionbit1;
516 static int r_farclip_directionbit2;
517
518 // enlarge farclip to accomodate box
519 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
520 {
521         float d;
522         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
523           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
524           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
525         if (r_farclip_meshfarclip < d)
526                 r_farclip_meshfarclip = d;
527 }
528
529 // return farclip value
530 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
531 {
532         int i;
533
534         VectorCopy(origin, r_farclip_origin);
535         VectorCopy(direction, r_farclip_direction);
536         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
537         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
538         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
539         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
540         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
541
542         if (r_refdef.worldmodel)
543                 R_FarClip_Box(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
544         for (i = 0;i < r_refdef.numentities;i++)
545                 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
546
547         return r_farclip_meshfarclip - r_farclip_directiondist;
548 }
549
550 extern void R_Textures_Init(void);
551 extern void GL_Draw_Init(void);
552 extern void GL_Main_Init(void);
553 extern void R_Shadow_Init(void);
554 extern void R_Sky_Init(void);
555 extern void GL_Surf_Init(void);
556 extern void R_Crosshairs_Init(void);
557 extern void R_Light_Init(void);
558 extern void R_Particles_Init(void);
559 extern void R_Explosion_Init(void);
560 extern void gl_backend_init(void);
561 extern void Sbar_Init(void);
562 extern void R_LightningBeams_Init(void);
563 extern void Mod_RenderInit(void);
564
565 void Render_Init(void)
566 {
567         gl_backend_init();
568         R_Textures_Init();
569         Mod_RenderInit();
570         R_MeshQueue_Init();
571         GL_Main_Init();
572         GL_Draw_Init();
573         R_Shadow_Init();
574         R_Sky_Init();
575         GL_Surf_Init();
576         R_Crosshairs_Init();
577         R_Light_Init();
578         R_Particles_Init();
579         R_Explosion_Init();
580         UI_Init();
581         Sbar_Init();
582         R_LightningBeams_Init();
583 }
584
585 /*
586 ===============
587 GL_Init
588 ===============
589 */
590 extern char *ENGINE_EXTENSIONS;
591 void GL_Init (void)
592 {
593         VID_CheckExtensions();
594
595         // LordHavoc: report supported extensions
596         Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
597
598         // clear to black (loading plaque will be seen over this)
599         qglClearColor(0,0,0,1);
600         qglClear(GL_COLOR_BUFFER_BIT);
601 }
602
603 int R_CullBox(const vec3_t mins, const vec3_t maxs)
604 {
605         int i;
606         mplane_t *p;
607         for (i = 0;i < 4;i++)
608         {
609                 p = frustum + i;
610                 switch(p->signbits)
611                 {
612                 default:
613                 case 0:
614                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
615                                 return true;
616                         break;
617                 case 1:
618                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
619                                 return true;
620                         break;
621                 case 2:
622                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
623                                 return true;
624                         break;
625                 case 3:
626                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
627                                 return true;
628                         break;
629                 case 4:
630                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
631                                 return true;
632                         break;
633                 case 5:
634                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
635                                 return true;
636                         break;
637                 case 6:
638                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
639                                 return true;
640                         break;
641                 case 7:
642                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
643                                 return true;
644                         break;
645                 }
646         }
647         return false;
648 }
649
650 //==================================================================================
651
652 static void R_MarkEntities (void)
653 {
654         int i, renderimask;
655         entity_render_t *ent;
656
657         if (!r_drawentities.integer)
658                 return;
659
660         r_refdef.worldentity->visframe = r_framecount;
661         renderimask = envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
662         if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
663         {
664                 // worldmodel can check visibility
665                 for (i = 0;i < r_refdef.numentities;i++)
666                 {
667                         ent = r_refdef.entities[i];
668                         Mod_CheckLoaded(ent->model);
669                         // some of the renderer still relies on origin...
670                         Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
671                         // some of the renderer still relies on scale...
672                         ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
673                         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)))
674                         {
675                                 R_UpdateEntLights(ent);
676                                 ent->visframe = r_framecount;
677                         }
678                 }
679         }
680         else
681         {
682                 // no worldmodel or it can't check visibility
683                 for (i = 0;i < r_refdef.numentities;i++)
684                 {
685                         ent = r_refdef.entities[i];
686                         Mod_CheckLoaded(ent->model);
687                         // some of the renderer still relies on origin...
688                         Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
689                         // some of the renderer still relies on scale...
690                         ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
691                         if (!(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && (ent->effects & EF_NODEPTHTEST))
692                         {
693                                 R_UpdateEntLights(ent);
694                                 ent->visframe = r_framecount;
695                         }
696                 }
697         }
698 }
699
700 // only used if skyrendermasked, and normally returns false
701 int R_DrawBrushModelsSky (void)
702 {
703         int i, sky;
704         entity_render_t *ent;
705
706         if (!r_drawentities.integer)
707                 return false;
708
709         sky = false;
710         for (i = 0;i < r_refdef.numentities;i++)
711         {
712                 ent = r_refdef.entities[i];
713                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
714                 {
715                         ent->model->DrawSky(ent);
716                         sky = true;
717                 }
718         }
719         return sky;
720 }
721
722 void R_DrawNoModel(entity_render_t *ent);
723 void R_DrawModels(void)
724 {
725         int i;
726         entity_render_t *ent;
727
728         if (!r_drawentities.integer)
729                 return;
730
731         for (i = 0;i < r_refdef.numentities;i++)
732         {
733                 ent = r_refdef.entities[i];
734                 if (ent->visframe == r_framecount)
735                 {
736                         if (ent->model && ent->model->Draw != NULL)
737                                 ent->model->Draw(ent);
738                         else
739                                 R_DrawNoModel(ent);
740                 }
741         }
742 }
743
744 static void R_SetFrustum(void)
745 {
746         // break apart the view matrix into vectors for various purposes
747         Matrix4x4_ToVectors(&r_view_matrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
748         VectorNegate(r_viewleft, r_viewright);
749
750         // LordHavoc: note to all quake engine coders, the special case for 90
751         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
752         // disabled as well.
753
754         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
755         RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_view_fov_x / 2));
756         frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
757         PlaneClassify(&frustum[0]);
758
759         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
760         RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_view_fov_x / 2));
761         frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
762         PlaneClassify(&frustum[1]);
763
764         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
765         RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_view_fov_y / 2));
766         frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
767         PlaneClassify(&frustum[2]);
768
769         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
770         RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
771         frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
772         PlaneClassify(&frustum[3]);
773 }
774
775 static void R_BlendView(void)
776 {
777         rmeshstate_t m;
778
779         if (r_refdef.viewblend[3] < 0.01f && !r_bloom.integer)
780                 return;
781
782         GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
783         GL_DepthMask(true);
784         GL_DepthTest(false);
785         R_Mesh_Matrix(&r_identitymatrix);
786         // vertex coordinates for a quad that covers the screen exactly
787         varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
788         varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
789         varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
790         varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
791         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)
792         {
793                 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
794                 float xoffset, yoffset, r;
795                 c_bloom++;
796                 // set the (poorly named) screenwidth and screenheight variables to
797                 // a power of 2 at least as large as the screen, these will define the
798                 // size of the texture to allocate
799                 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
800                 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
801                 // allocate textures as needed
802                 if (!r_bloom_texture_screen)
803                         r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
804                 if (!r_bloom_texture_bloom)
805                         r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
806                 // set bloomwidth and bloomheight to the bloom resolution that will be
807                 // used (often less than the screen resolution for faster rendering)
808                 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
809                 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
810                 // set up a texcoord array for the full resolution screen image
811                 // (we have to keep this around to copy back during final render)
812                 varray_texcoord2f[0][0] = 0;
813                 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
814                 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
815                 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
816                 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
817                 varray_texcoord2f[0][5] = 0;
818                 varray_texcoord2f[0][6] = 0;
819                 varray_texcoord2f[0][7] = 0;
820                 // set up a texcoord array for the reduced resolution bloom image
821                 // (which will be additive blended over the screen image)
822                 varray_texcoord2f[1][0] = 0;
823                 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
824                 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
825                 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
826                 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
827                 varray_texcoord2f[1][5] = 0;
828                 varray_texcoord2f[1][6] = 0;
829                 varray_texcoord2f[1][7] = 0;
830                 memset(&m, 0, sizeof(m));
831                 m.pointer_vertex = varray_vertex3f;
832                 m.pointer_texcoord[0] = varray_texcoord2f[0];
833                 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
834                 R_Mesh_State(&m);
835                 // copy view into the full resolution screen image texture
836                 GL_ActiveTexture(0);
837                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
838                 c_bloomcopies++;
839                 c_bloomcopypixels += r_view_width * r_view_height;
840                 // now scale it down to the bloom size and raise to a power of itself
841                 // to darken it (this leaves the really bright stuff bright, and
842                 // everything else becomes very dark)
843                 // TODO: optimize with multitexture or GLSL
844                 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
845                 GL_BlendFunc(GL_ONE, GL_ZERO);
846                 GL_Color(1, 1, 1, 1);
847                 R_Mesh_Draw(0, 4, 2, polygonelements);
848                 c_bloomdraws++;
849                 c_bloomdrawpixels += bloomwidth * bloomheight;
850                 // render multiple times with a multiply blendfunc to raise to a power
851                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
852                 for (x = 1;x < r_bloom_power.integer;x++)
853                 {
854                         R_Mesh_Draw(0, 4, 2, polygonelements);
855                         c_bloomdraws++;
856                         c_bloomdrawpixels += bloomwidth * bloomheight;
857                 }
858                 // we now have a darkened bloom image in the framebuffer, copy it into
859                 // the bloom image texture for more processing
860                 memset(&m, 0, sizeof(m));
861                 m.pointer_vertex = varray_vertex3f;
862                 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
863                 m.pointer_texcoord[0] = varray_texcoord2f[2];
864                 R_Mesh_State(&m);
865                 GL_ActiveTexture(0);
866                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
867                 c_bloomcopies++;
868                 c_bloomcopypixels += bloomwidth * bloomheight;
869                 // blend on at multiple vertical offsets to achieve a vertical blur
870                 // TODO: do offset blends using GLSL
871                 range = r_bloom_blur.integer * bloomwidth / 320;
872                 GL_BlendFunc(GL_ONE, GL_ZERO);
873                 for (x = -range;x <= range;x++)
874                 {
875                         xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
876                         yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
877                         // compute a texcoord array with the specified x and y offset
878                         varray_texcoord2f[2][0] = xoffset+0;
879                         varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
880                         varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
881                         varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
882                         varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
883                         varray_texcoord2f[2][5] = yoffset+0;
884                         varray_texcoord2f[2][6] = xoffset+0;
885                         varray_texcoord2f[2][7] = yoffset+0;
886                         // this r value looks like a 'dot' particle, fading sharply to
887                         // black at the edges
888                         // (probably not realistic but looks good enough)
889                         r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
890                         if (r < 0.01f)
891                                 continue;
892                         GL_Color(r, r, r, 1);
893                         R_Mesh_Draw(0, 4, 2, polygonelements);
894                         c_bloomdraws++;
895                         c_bloomdrawpixels += bloomwidth * bloomheight;
896                         GL_BlendFunc(GL_ONE, GL_ONE);
897                 }
898                 // copy the vertically blurred bloom view to a texture
899                 GL_ActiveTexture(0);
900                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
901                 c_bloomcopies++;
902                 c_bloomcopypixels += bloomwidth * bloomheight;
903                 // blend the vertically blurred image at multiple offsets horizontally
904                 // to finish the blur effect
905                 // TODO: do offset blends using GLSL
906                 range = r_bloom_blur.integer * bloomwidth / 320;
907                 GL_BlendFunc(GL_ONE, GL_ZERO);
908                 for (x = -range;x <= range;x++)
909                 {
910                         xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
911                         yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
912                         // compute a texcoord array with the specified x and y offset
913                         varray_texcoord2f[2][0] = xoffset+0;
914                         varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
915                         varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
916                         varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
917                         varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
918                         varray_texcoord2f[2][5] = yoffset+0;
919                         varray_texcoord2f[2][6] = xoffset+0;
920                         varray_texcoord2f[2][7] = yoffset+0;
921                         // this r value looks like a 'dot' particle, fading sharply to
922                         // black at the edges
923                         // (probably not realistic but looks good enough)
924                         r = r_bloom_intensity.value/(range*2+1)*(1 - x*x/(float)(range*range));
925                         if (r < 0.01f)
926                                 continue;
927                         GL_Color(r, r, r, 1);
928                         R_Mesh_Draw(0, 4, 2, polygonelements);
929                         c_bloomdraws++;
930                         c_bloomdrawpixels += bloomwidth * bloomheight;
931                         GL_BlendFunc(GL_ONE, GL_ONE);
932                 }
933                 // copy the blurred bloom view to a texture
934                 GL_ActiveTexture(0);
935                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
936                 c_bloomcopies++;
937                 c_bloomcopypixels += bloomwidth * bloomheight;
938                 // go back to full view area
939                 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
940                 // put the original screen image back in place and blend the bloom
941                 // texture on it
942                 memset(&m, 0, sizeof(m));
943                 m.pointer_vertex = varray_vertex3f;
944                 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
945                 m.pointer_texcoord[0] = varray_texcoord2f[0];
946 #if 0
947                 dobloomblend = false;
948 #else
949                 // do both in one pass if possible
950                 if (r_textureunits.integer >= 2 && gl_combine.integer)
951                 {
952                         dobloomblend = false;
953                         m.texcombinergb[1] = GL_ADD;
954                         m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
955                         m.pointer_texcoord[1] = varray_texcoord2f[1];
956                 }
957                 else
958                         dobloomblend = true;
959 #endif
960                 R_Mesh_State(&m);
961                 GL_BlendFunc(GL_ONE, GL_ZERO);
962                 GL_Color(1,1,1,1);
963                 R_Mesh_Draw(0, 4, 2, polygonelements);
964                 c_bloomdraws++;
965                 c_bloomdrawpixels += r_view_width * r_view_height;
966                 // now blend on the bloom texture if multipass
967                 if (dobloomblend)
968                 {
969                         memset(&m, 0, sizeof(m));
970                         m.pointer_vertex = varray_vertex3f;
971                         m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
972                         m.pointer_texcoord[0] = varray_texcoord2f[1];
973                         R_Mesh_State(&m);
974                         GL_BlendFunc(GL_ONE, GL_ONE);
975                         GL_Color(1,1,1,1);
976                         R_Mesh_Draw(0, 4, 2, polygonelements);
977                         c_bloomdraws++;
978                         c_bloomdrawpixels += r_view_width * r_view_height;
979                 }
980         }
981         if (r_refdef.viewblend[3] >= 0.01f)
982         {
983                 // apply a color tint to the whole view
984                 memset(&m, 0, sizeof(m));
985                 m.pointer_vertex = varray_vertex3f;
986                 R_Mesh_State(&m);
987                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
988                 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
989                 R_Mesh_Draw(0, 4, 2, polygonelements);
990         }
991 }
992
993 void R_RenderScene(void);
994
995 /*
996 ================
997 R_RenderView
998 ================
999 */
1000 void R_RenderView(void)
1001 {
1002         if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
1003                 return; //Host_Error ("R_RenderView: NULL worldmodel");
1004
1005         r_view_width = bound(0, r_refdef.width, vid.realwidth);
1006         r_view_height = bound(0, r_refdef.height, vid.realheight);
1007         r_view_depth = 1;
1008         r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
1009         r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
1010         r_view_z = 0;
1011         r_view_fov_x = bound(1, r_refdef.fov_x, 170);
1012         r_view_fov_y = bound(1, r_refdef.fov_y, 170);
1013         r_view_matrix = r_refdef.viewentitymatrix;
1014         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1015         r_rtworld = r_shadow_realtime_world.integer;
1016         r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
1017         r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
1018         r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
1019         r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
1020
1021         // GL is weird because it's bottom to top, r_view_y is top to bottom
1022         qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
1023         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
1024         GL_ScissorTest(true);
1025         GL_DepthMask(true);
1026         R_ClearScreen();
1027         R_Textures_Frame();
1028         R_UpdateFog();
1029         R_UpdateLights();
1030         R_TimeReport("setup");
1031
1032         qglDepthFunc(GL_LEQUAL);
1033         qglPolygonOffset(0, 0);
1034         qglEnable(GL_POLYGON_OFFSET_FILL);
1035
1036         R_RenderScene();
1037
1038         qglPolygonOffset(0, 0);
1039         qglDisable(GL_POLYGON_OFFSET_FILL);
1040
1041         R_BlendView();
1042         R_TimeReport("blendview");
1043
1044         GL_Scissor(0, 0, vid.realwidth, vid.realheight);
1045         GL_ScissorTest(false);
1046 }
1047
1048 extern void R_DrawLightningBeams (void);
1049 void R_RenderScene(void)
1050 {
1051         // don't let sound skip if going slow
1052         if (r_refdef.extraupdate)
1053                 S_ExtraUpdate ();
1054
1055         r_framecount++;
1056
1057         R_MeshQueue_BeginScene();
1058
1059         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1060
1061         R_SetFrustum();
1062
1063         r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
1064         if (r_rtworldshadows || r_rtdlightshadows)
1065                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
1066         else
1067                 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
1068
1069         GL_SetupView_Orientation_FromEntity(&r_view_matrix);
1070
1071         R_SkyStartFrame();
1072
1073         R_WorldVisibility();
1074         R_TimeReport("worldvis");
1075
1076         R_MarkEntities();
1077         R_TimeReport("markentity");
1078
1079         R_Shadow_UpdateWorldLightSelection();
1080
1081         // don't let sound skip if going slow
1082         if (r_refdef.extraupdate)
1083                 S_ExtraUpdate ();
1084
1085         GL_ShowTrisColor(0.025, 0.025, 0, 1);
1086         if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
1087         {
1088                 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
1089                 R_TimeReport("worldsky");
1090         }
1091
1092         if (R_DrawBrushModelsSky())
1093                 R_TimeReport("bmodelsky");
1094
1095         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1096         if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
1097         {
1098                 r_refdef.worldmodel->Draw(r_refdef.worldentity);
1099                 R_TimeReport("world");
1100         }
1101
1102         // don't let sound skip if going slow
1103         if (r_refdef.extraupdate)
1104                 S_ExtraUpdate ();
1105
1106         GL_ShowTrisColor(0, 0.015, 0, 1);
1107
1108         R_DrawModels();
1109         R_TimeReport("models");
1110
1111         // don't let sound skip if going slow
1112         if (r_refdef.extraupdate)
1113                 S_ExtraUpdate ();
1114
1115         GL_ShowTrisColor(0, 0, 0.033, 1);
1116         R_ShadowVolumeLighting(false);
1117         R_TimeReport("rtlights");
1118
1119         // don't let sound skip if going slow
1120         if (r_refdef.extraupdate)
1121                 S_ExtraUpdate ();
1122
1123         GL_ShowTrisColor(0.1, 0, 0, 1);
1124
1125         R_DrawLightningBeams();
1126         R_TimeReport("lightning");
1127
1128         R_DrawParticles();
1129         R_TimeReport("particles");
1130
1131         R_DrawExplosions();
1132         R_TimeReport("explosions");
1133
1134         R_MeshQueue_RenderTransparent();
1135         R_TimeReport("drawtrans");
1136
1137         R_DrawCoronas();
1138         R_TimeReport("coronas");
1139
1140         R_DrawWorldCrosshair();
1141         R_TimeReport("crosshair");
1142
1143         R_MeshQueue_Render();
1144         R_MeshQueue_EndScene();
1145
1146         if ((r_shadow_visiblelighting.integer || r_shadow_visiblevolumes.integer) && !r_showtrispass)
1147         {
1148                 R_ShadowVolumeLighting(true);
1149                 R_TimeReport("visiblevolume");
1150         }
1151
1152         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
1153
1154         // don't let sound skip if going slow
1155         if (r_refdef.extraupdate)
1156                 S_ExtraUpdate ();
1157 }
1158
1159 /*
1160 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
1161 {
1162         int i;
1163         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
1164         rmeshstate_t m;
1165         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1166         GL_DepthMask(false);
1167         GL_DepthTest(true);
1168         R_Mesh_Matrix(&r_identitymatrix);
1169
1170         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
1171         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
1172         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
1173         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
1174         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
1175         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
1176         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
1177         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
1178         R_FillColors(color, 8, cr, cg, cb, ca);
1179         if (fogenabled)
1180         {
1181                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
1182                 {
1183                         VectorSubtract(v, r_vieworigin, diff);
1184                         f2 = exp(fogdensity/DotProduct(diff, diff));
1185                         f1 = 1 - f2;
1186                         c[0] = c[0] * f1 + fogcolor[0] * f2;
1187                         c[1] = c[1] * f1 + fogcolor[1] * f2;
1188                         c[2] = c[2] * f1 + fogcolor[2] * f2;
1189                 }
1190         }
1191         memset(&m, 0, sizeof(m));
1192         m.pointer_vertex = vertex3f;
1193         m.pointer_color = color;
1194         R_Mesh_State(&m);
1195         R_Mesh_Draw(8, 12);
1196 }
1197 */
1198
1199 int nomodelelements[24] =
1200 {
1201         5, 2, 0,
1202         5, 1, 2,
1203         5, 0, 3,
1204         5, 3, 1,
1205         0, 2, 4,
1206         2, 1, 4,
1207         3, 0, 4,
1208         1, 3, 4
1209 };
1210
1211 float nomodelvertex3f[6*3] =
1212 {
1213         -16,   0,   0,
1214          16,   0,   0,
1215           0, -16,   0,
1216           0,  16,   0,
1217           0,   0, -16,
1218           0,   0,  16
1219 };
1220
1221 float nomodelcolor4f[6*4] =
1222 {
1223         0.0f, 0.0f, 0.5f, 1.0f,
1224         0.0f, 0.0f, 0.5f, 1.0f,
1225         0.0f, 0.5f, 0.0f, 1.0f,
1226         0.0f, 0.5f, 0.0f, 1.0f,
1227         0.5f, 0.0f, 0.0f, 1.0f,
1228         0.5f, 0.0f, 0.0f, 1.0f
1229 };
1230
1231 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1232 {
1233         const entity_render_t *ent = calldata1;
1234         int i;
1235         float f1, f2, *c, diff[3];
1236         float color4f[6*4];
1237         rmeshstate_t m;
1238         R_Mesh_Matrix(&ent->matrix);
1239
1240         memset(&m, 0, sizeof(m));
1241         m.pointer_vertex = nomodelvertex3f;
1242
1243         if (ent->flags & EF_ADDITIVE)
1244         {
1245                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1246                 GL_DepthMask(false);
1247         }
1248         else if (ent->alpha < 1)
1249         {
1250                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1251                 GL_DepthMask(false);
1252         }
1253         else
1254         {
1255                 GL_BlendFunc(GL_ONE, GL_ZERO);
1256                 GL_DepthMask(true);
1257         }
1258         GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1259         if (fogenabled)
1260         {
1261                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1262                 m.pointer_color = color4f;
1263                 VectorSubtract(ent->origin, r_vieworigin, diff);
1264                 f2 = exp(fogdensity/DotProduct(diff, diff));
1265                 f1 = 1 - f2;
1266                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1267                 {
1268                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
1269                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
1270                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
1271                         c[3] *= ent->alpha;
1272                 }
1273         }
1274         else if (ent->alpha != 1)
1275         {
1276                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1277                 m.pointer_color = color4f;
1278                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1279                         c[3] *= ent->alpha;
1280         }
1281         else
1282                 m.pointer_color = nomodelcolor4f;
1283         R_Mesh_State(&m);
1284         R_Mesh_Draw(0, 6, 8, nomodelelements);
1285 }
1286
1287 void R_DrawNoModel(entity_render_t *ent)
1288 {
1289         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1290                 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1291         //else
1292         //      R_DrawNoModelCallback(ent, 0);
1293 }
1294
1295 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1296 {
1297         vec3_t right1, right2, diff, normal;
1298
1299         VectorSubtract (org2, org1, normal);
1300
1301         // calculate 'right' vector for start
1302         VectorSubtract (r_vieworigin, org1, diff);
1303         CrossProduct (normal, diff, right1);
1304         VectorNormalize (right1);
1305
1306         // calculate 'right' vector for end
1307         VectorSubtract (r_vieworigin, org2, diff);
1308         CrossProduct (normal, diff, right2);
1309         VectorNormalize (right2);
1310
1311         vert[ 0] = org1[0] + width * right1[0];
1312         vert[ 1] = org1[1] + width * right1[1];
1313         vert[ 2] = org1[2] + width * right1[2];
1314         vert[ 3] = org1[0] - width * right1[0];
1315         vert[ 4] = org1[1] - width * right1[1];
1316         vert[ 5] = org1[2] - width * right1[2];
1317         vert[ 6] = org2[0] - width * right2[0];
1318         vert[ 7] = org2[1] - width * right2[1];
1319         vert[ 8] = org2[2] - width * right2[2];
1320         vert[ 9] = org2[0] + width * right2[0];
1321         vert[10] = org2[1] + width * right2[1];
1322         vert[11] = org2[2] + width * right2[2];
1323 }
1324
1325 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1326
1327 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)
1328 {
1329         float diff[3];
1330         rmeshstate_t m;
1331
1332         if (fogenabled)
1333         {
1334                 VectorSubtract(origin, r_vieworigin, diff);
1335                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1336         }
1337
1338         R_Mesh_Matrix(&r_identitymatrix);
1339         GL_BlendFunc(blendfunc1, blendfunc2);
1340         GL_DepthMask(false);
1341         GL_DepthTest(!depthdisable);
1342
1343         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1344         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1345         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1346         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1347         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1348         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1349         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1350         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1351         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1352         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1353         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1354         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1355
1356         memset(&m, 0, sizeof(m));
1357         m.tex[0] = R_GetTexture(texture);
1358         m.pointer_texcoord[0] = spritetexcoord2f;
1359         m.pointer_vertex = varray_vertex3f;
1360         R_Mesh_State(&m);
1361         GL_Color(cr, cg, cb, ca);
1362         R_Mesh_Draw(0, 4, 2, polygonelements);
1363 }
1364