]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
fix PBLEND_MOD in fog
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24
25 // used for dlight push checking and other things
26 int r_framecount;
27
28 mplane_t frustum[4];
29
30 matrix4x4_t r_identitymatrix;
31
32 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights, c_meshs, c_meshelements, c_rt_lights, c_rt_clears, c_rt_scissored, c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris, c_rtcached_shadowmeshes, c_rtcached_shadowtris, c_bloom, c_bloomcopies, c_bloomcopypixels, c_bloomdraws, c_bloomdrawpixels;
33
34 // true during envmap command capture
35 qboolean envmap;
36
37 // maximum visible distance (recalculated from world box each frame)
38 float r_farclip;
39 // brightness of world lightmaps and related lighting
40 // (often reduced when world rtlights are enabled)
41 float r_lightmapintensity;
42 // whether to draw world lights realtime, dlights realtime, and their shadows
43 qboolean r_rtworld;
44 qboolean r_rtworldshadows;
45 qboolean r_rtdlight;
46 qboolean r_rtdlightshadows;
47
48
49 // forces all rendering to draw triangle outlines
50 int r_showtrispass;
51
52 // view origin
53 vec3_t r_vieworigin;
54 vec3_t r_viewforward;
55 vec3_t r_viewleft;
56 vec3_t r_viewright;
57 vec3_t r_viewup;
58 int r_view_x;
59 int r_view_y;
60 int r_view_z;
61 int r_view_width;
62 int r_view_height;
63 int r_view_depth;
64 float r_view_fov_x;
65 float r_view_fov_y;
66 matrix4x4_t r_view_matrix;
67
68 //
69 // screen size info
70 //
71 refdef_t r_refdef;
72
73 // 8.8 fraction of base light value
74 unsigned short d_lightstylevalue[256];
75
76 cvar_t r_showtris = {0, "r_showtris", "0"};
77 cvar_t r_drawentities = {0, "r_drawentities","1"};
78 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
79 cvar_t r_speeds = {0, "r_speeds","0"};
80 cvar_t r_fullbright = {0, "r_fullbright","0"};
81 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
82 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
83 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
84 cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
85
86 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
87 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
88 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
89 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
90 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
91 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
92 cvar_t gl_fogend = {0, "gl_fogend","0"};
93
94 cvar_t r_textureunits = {0, "r_textureunits", "32"};
95
96 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
97 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
98 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
99 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
100
101 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0"};
102 cvar_t r_bloom_intensity = {CVAR_SAVE, "r_bloom_intensity", "2"};
103 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "8"};
104 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320"};
105 cvar_t r_bloom_power = {CVAR_SAVE, "r_bloom_power", "4"};
106 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         varray_vertex3f[0] = 0;varray_vertex3f[1] = 0;varray_vertex3f[2] = 0;
604         varray_vertex3f[3] = 1;varray_vertex3f[4] = 0;varray_vertex3f[5] = 0;
605         varray_vertex3f[6] = 1;varray_vertex3f[7] = 1;varray_vertex3f[8] = 0;
606         varray_vertex3f[9] = 0;varray_vertex3f[10] = 1;varray_vertex3f[11] = 0;
607         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)
608         {
609                 int screenwidth, screenheight, bloomwidth, bloomheight, x, dobloomblend, range;
610                 float xoffset, yoffset, r;
611                 c_bloom++;
612                 for (screenwidth = 1;screenwidth < vid.realwidth;screenwidth *= 2);
613                 for (screenheight = 1;screenheight < vid.realheight;screenheight *= 2);
614                 bloomwidth = min(r_view_width, r_bloom_resolution.integer);
615                 bloomheight = min(r_view_height, bloomwidth * r_view_height / r_view_width);
616                 varray_texcoord2f[0][0] = 0;
617                 varray_texcoord2f[0][1] = (float)r_view_height / (float)screenheight;
618                 varray_texcoord2f[0][2] = (float)r_view_width / (float)screenwidth;
619                 varray_texcoord2f[0][3] = (float)r_view_height / (float)screenheight;
620                 varray_texcoord2f[0][4] = (float)r_view_width / (float)screenwidth;
621                 varray_texcoord2f[0][5] = 0;
622                 varray_texcoord2f[0][6] = 0;
623                 varray_texcoord2f[0][7] = 0;
624                 varray_texcoord2f[1][0] = 0;
625                 varray_texcoord2f[1][1] = (float)bloomheight / (float)screenheight;
626                 varray_texcoord2f[1][2] = (float)bloomwidth / (float)screenwidth;
627                 varray_texcoord2f[1][3] = (float)bloomheight / (float)screenheight;
628                 varray_texcoord2f[1][4] = (float)bloomwidth / (float)screenwidth;
629                 varray_texcoord2f[1][5] = 0;
630                 varray_texcoord2f[1][6] = 0;
631                 varray_texcoord2f[1][7] = 0;
632                 if (!r_bloom_texture_screen)
633                         r_bloom_texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
634                 if (!r_bloom_texture_bloom)
635                         r_bloom_texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", screenwidth, screenheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
636                 memset(&m, 0, sizeof(m));
637                 m.pointer_vertex = varray_vertex3f;
638                 m.pointer_texcoord[0] = varray_texcoord2f[0];
639                 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
640                 R_Mesh_State(&m);
641                 // copy view to a texture
642                 GL_ActiveTexture(0);
643                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
644                 c_bloomcopies++;
645                 c_bloomcopypixels += r_view_width * r_view_height;
646                 // now scale it down to the bloom size and raise to a power of itself
647                 qglViewport(r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
648                 // TODO: optimize with multitexture or GLSL
649                 GL_BlendFunc(GL_ONE, GL_ZERO);
650                 GL_Color(1, 1, 1, 1);
651                 R_Mesh_Draw(4, 2, polygonelements);
652                 c_bloomdraws++;
653                 c_bloomdrawpixels += bloomwidth * bloomheight;
654                 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
655                 for (x = 1;x < r_bloom_power.integer;x++)
656                 {
657                         R_Mesh_Draw(4, 2, polygonelements);
658                         c_bloomdraws++;
659                         c_bloomdrawpixels += bloomwidth * bloomheight;
660                 }
661                 // copy the bloom view to a texture
662                 memset(&m, 0, sizeof(m));
663                 m.pointer_vertex = varray_vertex3f;
664                 m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
665                 m.pointer_texcoord[0] = varray_texcoord2f[2];
666                 R_Mesh_State(&m);
667                 GL_ActiveTexture(0);
668                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
669                 c_bloomcopies++;
670                 c_bloomcopypixels += bloomwidth * bloomheight;
671                 // blend on at multiple offsets vertically
672                 // TODO: do offset blends using GLSL
673                 range = r_bloom_blur.integer * bloomwidth / 320;
674                 GL_BlendFunc(GL_ONE, GL_ZERO);
675                 for (x = -range;x <= range;x++)
676                 {
677                         xoffset = 0 / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
678                         yoffset = x / (float)bloomheight * (float)bloomheight / (float)screenheight;
679                         varray_texcoord2f[2][0] = xoffset+0;
680                         varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
681                         varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
682                         varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
683                         varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
684                         varray_texcoord2f[2][5] = yoffset+0;
685                         varray_texcoord2f[2][6] = xoffset+0;
686                         varray_texcoord2f[2][7] = yoffset+0;
687                         r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
688                         if (r < 0.01f)
689                                 continue;
690                         GL_Color(r, r, r, 1);
691                         R_Mesh_Draw(4, 2, polygonelements);
692                         c_bloomdraws++;
693                         c_bloomdrawpixels += bloomwidth * bloomheight;
694                         GL_BlendFunc(GL_ONE, GL_ONE);
695                 }
696                 // copy the blurred bloom view to a texture
697                 GL_ActiveTexture(0);
698                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
699                 c_bloomcopies++;
700                 c_bloomcopypixels += bloomwidth * bloomheight;
701                 // blend on at multiple offsets horizontally
702                 // TODO: do offset blends using GLSL
703                 range = r_bloom_blur.integer * bloomwidth / 320;
704                 GL_BlendFunc(GL_ONE, GL_ZERO);
705                 for (x = -range;x <= range;x++)
706                 {
707                         xoffset = x / (float)bloomwidth * (float)bloomwidth / (float)screenwidth;
708                         yoffset = 0 / (float)bloomheight * (float)bloomheight / (float)screenheight;
709                         varray_texcoord2f[2][0] = xoffset+0;
710                         varray_texcoord2f[2][1] = yoffset+(float)bloomheight / (float)screenheight;
711                         varray_texcoord2f[2][2] = xoffset+(float)bloomwidth / (float)screenwidth;
712                         varray_texcoord2f[2][3] = yoffset+(float)bloomheight / (float)screenheight;
713                         varray_texcoord2f[2][4] = xoffset+(float)bloomwidth / (float)screenwidth;
714                         varray_texcoord2f[2][5] = yoffset+0;
715                         varray_texcoord2f[2][6] = xoffset+0;
716                         varray_texcoord2f[2][7] = yoffset+0;
717                         r = r_bloom_intensity.value/(range*2+1)*(1 - fabs(x*x)/(float)(range*range));
718                         if (r < 0.01f)
719                                 continue;
720                         GL_Color(r, r, r, 1);
721                         R_Mesh_Draw(4, 2, polygonelements);
722                         c_bloomdraws++;
723                         c_bloomdrawpixels += bloomwidth * bloomheight;
724                         GL_BlendFunc(GL_ONE, GL_ONE);
725                 }
726                 // copy the blurred bloom view to a texture
727                 GL_ActiveTexture(0);
728                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view_x, vid.realheight - (r_view_y + bloomheight), bloomwidth, bloomheight);
729                 c_bloomcopies++;
730                 c_bloomcopypixels += bloomwidth * bloomheight;
731                 // go back to full view area
732                 qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
733                 // put the original view back in place
734                 memset(&m, 0, sizeof(m));
735                 m.pointer_vertex = varray_vertex3f;
736                 m.tex[0] = R_GetTexture(r_bloom_texture_screen);
737                 m.pointer_texcoord[0] = varray_texcoord2f[0];
738 #if 0
739                 dobloomblend = false;
740 #else
741                 // do both in one pass if possible
742                 if (r_textureunits.integer >= 2 && gl_combine.integer)
743                 {
744                         dobloomblend = false;
745                         m.texcombinergb[1] = GL_ADD;
746                         m.tex[1] = R_GetTexture(r_bloom_texture_bloom);
747                         m.pointer_texcoord[1] = varray_texcoord2f[1];
748                 }
749                 else
750                         dobloomblend = true;
751 #endif
752                 R_Mesh_State(&m);
753                 GL_BlendFunc(GL_ONE, GL_ZERO);
754                 GL_Color(1,1,1,1);
755                 R_Mesh_Draw(4, 2, polygonelements);
756                 c_bloomdraws++;
757                 c_bloomdrawpixels += r_view_width * r_view_height;
758                 // now blend on the bloom texture if multipass
759                 if (dobloomblend)
760                 {
761                         memset(&m, 0, sizeof(m));
762                         m.pointer_vertex = varray_vertex3f;
763                         m.tex[0] = R_GetTexture(r_bloom_texture_bloom);
764                         m.pointer_texcoord[0] = varray_texcoord2f[1];
765                         R_Mesh_State(&m);
766                         GL_BlendFunc(GL_ONE, GL_ONE);
767                         GL_Color(1,1,1,1);
768                         R_Mesh_Draw(4, 2, polygonelements);
769                         c_bloomdraws++;
770                         c_bloomdrawpixels += r_view_width * r_view_height;
771                 }
772         }
773         if (r_refdef.viewblend[3] >= 0.01f)
774         {
775                 // apply a color tint to the whole view
776                 memset(&m, 0, sizeof(m));
777                 m.pointer_vertex = varray_vertex3f;
778                 R_Mesh_State(&m);
779                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
780                 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
781                 R_Mesh_Draw(4, 2, polygonelements);
782         }
783 }
784
785 void R_RenderScene(void);
786
787 /*
788 ================
789 R_RenderView
790 ================
791 */
792 void R_RenderView(void)
793 {
794         if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
795                 return; //Host_Error ("R_RenderView: NULL worldmodel");
796
797         r_view_width = bound(0, r_refdef.width, vid.realwidth);
798         r_view_height = bound(0, r_refdef.height, vid.realheight);
799         r_view_depth = 1;
800         r_view_x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
801         r_view_y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
802         r_view_z = 0;
803         r_view_fov_x = bound(1, r_refdef.fov_x, 170);
804         r_view_fov_y = bound(1, r_refdef.fov_y, 170);
805         r_view_matrix = r_refdef.viewentitymatrix;
806         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
807         r_rtworld = r_shadow_realtime_world.integer;
808         r_rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
809         r_rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer;
810         r_rtdlightshadows = r_rtdlight && (r_rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
811         r_lightmapintensity = r_rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
812
813         // GL is weird because it's bottom to top, r_view_y is top to bottom
814         qglViewport(r_view_x, vid.realheight - (r_view_y + r_view_height), r_view_width, r_view_height);
815         GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
816         GL_ScissorTest(true);
817         GL_DepthMask(true);
818         R_ClearScreen();
819         R_Textures_Frame();
820         R_UpdateFog();
821         R_UpdateLights();
822         R_TimeReport("setup");
823
824         qglDepthFunc(GL_LEQUAL);
825         qglPolygonOffset(0, 0);
826         qglEnable(GL_POLYGON_OFFSET_FILL);
827
828         R_RenderScene();
829
830         qglPolygonOffset(0, 0);
831         qglDisable(GL_POLYGON_OFFSET_FILL);
832
833         R_BlendView();
834         R_TimeReport("blendview");
835
836         GL_Scissor(0, 0, vid.realwidth, vid.realheight);
837         GL_ScissorTest(false);
838 }
839
840 extern void R_DrawLightningBeams (void);
841 void R_RenderScene(void)
842 {
843         // don't let sound skip if going slow
844         if (r_refdef.extraupdate)
845                 S_ExtraUpdate ();
846
847         r_framecount++;
848
849         R_MeshQueue_BeginScene();
850
851         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
852
853         R_SetFrustum();
854
855         r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
856         if (r_rtworldshadows || r_rtdlightshadows)
857                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view_fov_x, r_view_fov_y, 1.0f);
858         else
859                 GL_SetupView_Mode_Perspective(r_view_fov_x, r_view_fov_y, 1.0f, r_farclip);
860
861         GL_SetupView_Orientation_FromEntity(&r_view_matrix);
862
863         R_SkyStartFrame();
864
865         R_WorldVisibility();
866         R_TimeReport("worldvis");
867
868         R_MarkEntities();
869         R_TimeReport("markentity");
870
871         R_Shadow_UpdateWorldLightSelection();
872
873         // don't let sound skip if going slow
874         if (r_refdef.extraupdate)
875                 S_ExtraUpdate ();
876
877         GL_ShowTrisColor(0.025, 0.025, 0, 1);
878         if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
879         {
880                 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
881                 R_TimeReport("worldsky");
882         }
883
884         if (R_DrawBrushModelsSky())
885                 R_TimeReport("bmodelsky");
886
887         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
888         if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
889         {
890                 r_refdef.worldmodel->Draw(r_refdef.worldentity);
891                 R_TimeReport("world");
892         }
893
894         // don't let sound skip if going slow
895         if (r_refdef.extraupdate)
896                 S_ExtraUpdate ();
897
898         GL_ShowTrisColor(0, 0.015, 0, 1);
899
900         R_DrawModels();
901         R_TimeReport("models");
902
903         // don't let sound skip if going slow
904         if (r_refdef.extraupdate)
905                 S_ExtraUpdate ();
906
907         GL_ShowTrisColor(0, 0, 0.033, 1);
908         R_ShadowVolumeLighting(false);
909         R_TimeReport("rtlights");
910
911         // don't let sound skip if going slow
912         if (r_refdef.extraupdate)
913                 S_ExtraUpdate ();
914
915         GL_ShowTrisColor(0.1, 0, 0, 1);
916
917         R_DrawLightningBeams();
918         R_TimeReport("lightning");
919
920         R_DrawParticles();
921         R_TimeReport("particles");
922
923         R_DrawExplosions();
924         R_TimeReport("explosions");
925
926         R_MeshQueue_RenderTransparent();
927         R_TimeReport("drawtrans");
928
929         R_DrawCoronas();
930         R_TimeReport("coronas");
931
932         R_DrawWorldCrosshair();
933         R_TimeReport("crosshair");
934
935         R_MeshQueue_Render();
936         R_MeshQueue_EndScene();
937
938         if (r_shadow_visiblevolumes.integer && !r_showtrispass)
939         {
940                 R_ShadowVolumeLighting(true);
941                 R_TimeReport("shadowvolume");
942         }
943
944         GL_ShowTrisColor(0.05, 0.05, 0.05, 1);
945
946         // don't let sound skip if going slow
947         if (r_refdef.extraupdate)
948                 S_ExtraUpdate ();
949 }
950
951 /*
952 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
953 {
954         int i;
955         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
956         rmeshstate_t m;
957         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
958         GL_DepthMask(false);
959         GL_DepthTest(true);
960         R_Mesh_Matrix(&r_identitymatrix);
961
962         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
963         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
964         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
965         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
966         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
967         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
968         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
969         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
970         R_FillColors(color, 8, cr, cg, cb, ca);
971         if (fogenabled)
972         {
973                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
974                 {
975                         VectorSubtract(v, r_vieworigin, diff);
976                         f2 = exp(fogdensity/DotProduct(diff, diff));
977                         f1 = 1 - f2;
978                         c[0] = c[0] * f1 + fogcolor[0] * f2;
979                         c[1] = c[1] * f1 + fogcolor[1] * f2;
980                         c[2] = c[2] * f1 + fogcolor[2] * f2;
981                 }
982         }
983         memset(&m, 0, sizeof(m));
984         m.pointer_vertex = vertex3f;
985         m.pointer_color = color;
986         R_Mesh_State(&m);
987         R_Mesh_Draw(8, 12);
988 }
989 */
990
991 int nomodelelements[24] =
992 {
993         5, 2, 0,
994         5, 1, 2,
995         5, 0, 3,
996         5, 3, 1,
997         0, 2, 4,
998         2, 1, 4,
999         3, 0, 4,
1000         1, 3, 4
1001 };
1002
1003 float nomodelvertex3f[6*3] =
1004 {
1005         -16,   0,   0,
1006          16,   0,   0,
1007           0, -16,   0,
1008           0,  16,   0,
1009           0,   0, -16,
1010           0,   0,  16
1011 };
1012
1013 float nomodelcolor4f[6*4] =
1014 {
1015         0.0f, 0.0f, 0.5f, 1.0f,
1016         0.0f, 0.0f, 0.5f, 1.0f,
1017         0.0f, 0.5f, 0.0f, 1.0f,
1018         0.0f, 0.5f, 0.0f, 1.0f,
1019         0.5f, 0.0f, 0.0f, 1.0f,
1020         0.5f, 0.0f, 0.0f, 1.0f
1021 };
1022
1023 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1024 {
1025         const entity_render_t *ent = calldata1;
1026         int i;
1027         float f1, f2, *c, diff[3];
1028         float color4f[6*4];
1029         rmeshstate_t m;
1030         R_Mesh_Matrix(&ent->matrix);
1031
1032         memset(&m, 0, sizeof(m));
1033         m.pointer_vertex = nomodelvertex3f;
1034
1035         if (ent->flags & EF_ADDITIVE)
1036         {
1037                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1038                 GL_DepthMask(false);
1039         }
1040         else if (ent->alpha < 1)
1041         {
1042                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1043                 GL_DepthMask(false);
1044         }
1045         else
1046         {
1047                 GL_BlendFunc(GL_ONE, GL_ZERO);
1048                 GL_DepthMask(true);
1049         }
1050         GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1051         if (fogenabled)
1052         {
1053                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1054                 m.pointer_color = color4f;
1055                 VectorSubtract(ent->origin, r_vieworigin, diff);
1056                 f2 = exp(fogdensity/DotProduct(diff, diff));
1057                 f1 = 1 - f2;
1058                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1059                 {
1060                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
1061                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
1062                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
1063                         c[3] *= ent->alpha;
1064                 }
1065         }
1066         else if (ent->alpha != 1)
1067         {
1068                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1069                 m.pointer_color = color4f;
1070                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1071                         c[3] *= ent->alpha;
1072         }
1073         else
1074                 m.pointer_color = nomodelcolor4f;
1075         R_Mesh_State(&m);
1076         R_Mesh_Draw(6, 8, nomodelelements);
1077 }
1078
1079 void R_DrawNoModel(entity_render_t *ent)
1080 {
1081         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1082                 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : ent->origin, R_DrawNoModelCallback, ent, 0);
1083         //else
1084         //      R_DrawNoModelCallback(ent, 0);
1085 }
1086
1087 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1088 {
1089         vec3_t right1, right2, diff, normal;
1090
1091         VectorSubtract (org2, org1, normal);
1092
1093         // calculate 'right' vector for start
1094         VectorSubtract (r_vieworigin, org1, diff);
1095         CrossProduct (normal, diff, right1);
1096         VectorNormalize (right1);
1097
1098         // calculate 'right' vector for end
1099         VectorSubtract (r_vieworigin, org2, diff);
1100         CrossProduct (normal, diff, right2);
1101         VectorNormalize (right2);
1102
1103         vert[ 0] = org1[0] + width * right1[0];
1104         vert[ 1] = org1[1] + width * right1[1];
1105         vert[ 2] = org1[2] + width * right1[2];
1106         vert[ 3] = org1[0] - width * right1[0];
1107         vert[ 4] = org1[1] - width * right1[1];
1108         vert[ 5] = org1[2] - width * right1[2];
1109         vert[ 6] = org2[0] - width * right2[0];
1110         vert[ 7] = org2[1] - width * right2[1];
1111         vert[ 8] = org2[2] - width * right2[2];
1112         vert[ 9] = org2[0] + width * right2[0];
1113         vert[10] = org2[1] + width * right2[1];
1114         vert[11] = org2[2] + width * right2[2];
1115 }
1116
1117 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1118
1119 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)
1120 {
1121         float diff[3];
1122         rmeshstate_t m;
1123
1124         if (fogenabled)
1125         {
1126                 VectorSubtract(origin, r_vieworigin, diff);
1127                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1128         }
1129
1130         R_Mesh_Matrix(&r_identitymatrix);
1131         GL_BlendFunc(blendfunc1, blendfunc2);
1132         GL_DepthMask(false);
1133         GL_DepthTest(!depthdisable);
1134
1135         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1136         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1137         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1138         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1139         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1140         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1141         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1142         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1143         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1144         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1145         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1146         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1147
1148         memset(&m, 0, sizeof(m));
1149         m.tex[0] = R_GetTexture(texture);
1150         m.pointer_texcoord[0] = spritetexcoord2f;
1151         m.pointer_vertex = varray_vertex3f;
1152         R_Mesh_State(&m);
1153         GL_Color(cr, cg, cb, ca);
1154         R_Mesh_Draw(4, 2, polygonelements);
1155 }
1156