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