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