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