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