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