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