]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rmain.c
moved light matrix generation out of the render code and into the light creation...
[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
24 // used for dlight push checking and other things
25 int r_framecount;
26
27 // used for visibility checking
28 qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3];
29
30 mplane_t frustum[4];
31
32 matrix4x4_t r_identitymatrix;
33
34 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
35
36 // true during envmap command capture
37 qboolean envmap;
38
39 float r_farclip;
40
41 // view origin
42 vec3_t r_vieworigin;
43 vec3_t r_viewforward;
44 vec3_t r_viewleft;
45 vec3_t r_viewright;
46 vec3_t r_viewup;
47
48 //
49 // screen size info
50 //
51 refdef_t r_refdef;
52
53 // 8.8 fraction of base light value
54 unsigned short d_lightstylevalue[256];
55
56 cvar_t r_drawentities = {0, "r_drawentities","1"};
57 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
58 cvar_t r_shadow_staticworldlights = {0, "r_shadow_staticworldlights", "1"};
59 cvar_t r_speeds = {0, "r_speeds","0"};
60 cvar_t r_fullbright = {0, "r_fullbright","0"};
61 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
62 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
63 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
64 cvar_t r_shadow_cull = {0, "r_shadow_cull", "1"};
65 cvar_t r_drawcollisionbrushes = {0, "r_drawcollisionbrushes", "0"};
66
67 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
68 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
69 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
70 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
71 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
72 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
73 cvar_t gl_fogend = {0, "gl_fogend","0"};
74
75 cvar_t r_textureunits = {0, "r_textureunits", "32"};
76
77 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1"};
78 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1"};
79 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1"};
80 cvar_t r_watershader = {CVAR_SAVE, "r_watershader", "1"};
81
82
83 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
84 {
85         int i;
86         for (i = 0;i < verts;i++)
87         {
88                 out[0] = in[0] * r;
89                 out[1] = in[1] * g;
90                 out[2] = in[2] * b;
91                 out[3] = in[3];
92                 in += 4;
93                 out += 4;
94         }
95 }
96
97 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
98 {
99         int i;
100         for (i = 0;i < verts;i++)
101         {
102                 out[0] = r;
103                 out[1] = g;
104                 out[2] = b;
105                 out[3] = a;
106                 out += 4;
107         }
108 }
109
110 /*
111 ====================
112 R_TimeRefresh_f
113
114 For program optimization
115 ====================
116 */
117 qboolean intimerefresh = 0;
118 static void R_TimeRefresh_f (void)
119 {
120         int i;
121         float timestart, timedelta, oldangles[3];
122
123         intimerefresh = 1;
124         VectorCopy(cl.viewangles, oldangles);
125         VectorClear(cl.viewangles);
126
127         timestart = Sys_DoubleTime();
128         for (i = 0;i < 128;i++)
129         {
130                 Matrix4x4_CreateFromQuakeEntity(&r_refdef.viewentitymatrix, r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], 0, i / 128.0 * 360.0, 0, 1);
131                 CL_UpdateScreen();
132         }
133         timedelta = Sys_DoubleTime() - timestart;
134
135         VectorCopy(oldangles, cl.viewangles);
136         intimerefresh = 0;
137         Con_Printf ("%f seconds (%f fps)\n", timedelta, 128/timedelta);
138 }
139
140 vec3_t fogcolor;
141 vec_t fogdensity;
142 float fog_density, fog_red, fog_green, fog_blue;
143 qboolean fogenabled;
144 qboolean oldgl_fogenable;
145 void R_SetupFog(void)
146 {
147         if (gamemode == GAME_NEHAHRA)
148         {
149                 if (gl_fogenable.integer)
150                 {
151                         oldgl_fogenable = true;
152                         fog_density = gl_fogdensity.value;
153                         fog_red = gl_fogred.value;
154                         fog_green = gl_foggreen.value;
155                         fog_blue = gl_fogblue.value;
156                 }
157                 else if (oldgl_fogenable)
158                 {
159                         oldgl_fogenable = false;
160                         fog_density = 0;
161                         fog_red = 0;
162                         fog_green = 0;
163                         fog_blue = 0;
164                 }
165         }
166         if (fog_density)
167         {
168                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
169                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
170                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
171         }
172         if (fog_density)
173         {
174                 fogenabled = true;
175                 fogdensity = -4000.0f / (fog_density * fog_density);
176                 // fog color was already set
177         }
178         else
179                 fogenabled = false;
180 }
181
182 // FIXME: move this to client?
183 void FOG_clear(void)
184 {
185         if (gamemode == GAME_NEHAHRA)
186         {
187                 Cvar_Set("gl_fogenable", "0");
188                 Cvar_Set("gl_fogdensity", "0.2");
189                 Cvar_Set("gl_fogred", "0.3");
190                 Cvar_Set("gl_foggreen", "0.3");
191                 Cvar_Set("gl_fogblue", "0.3");
192         }
193         fog_density = fog_red = fog_green = fog_blue = 0.0f;
194 }
195
196 // FIXME: move this to client?
197 void FOG_registercvars(void)
198 {
199         if (gamemode == GAME_NEHAHRA)
200         {
201                 Cvar_RegisterVariable (&gl_fogenable);
202                 Cvar_RegisterVariable (&gl_fogdensity);
203                 Cvar_RegisterVariable (&gl_fogred);
204                 Cvar_RegisterVariable (&gl_foggreen);
205                 Cvar_RegisterVariable (&gl_fogblue);
206                 Cvar_RegisterVariable (&gl_fogstart);
207                 Cvar_RegisterVariable (&gl_fogend);
208         }
209 }
210
211 void gl_main_start(void)
212 {
213 }
214
215 void gl_main_shutdown(void)
216 {
217 }
218
219 extern void CL_ParseEntityLump(char *entitystring);
220 void gl_main_newmap(void)
221 {
222         int l;
223         char *entities, entname[MAX_QPATH];
224         r_framecount = 1;
225         if (cl.worldmodel)
226         {
227                 strcpy(entname, cl.worldmodel->name);
228                 l = strlen(entname) - 4;
229                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
230                 {
231                         strcpy(entname + l, ".ent");
232                         if ((entities = FS_LoadFile(entname, true)))
233                         {
234                                 CL_ParseEntityLump(entities);
235                                 Mem_Free(entities);
236                                 return;
237                         }
238                 }
239                 if (cl.worldmodel->brush.entities)
240                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
241         }
242 }
243
244 void GL_Main_Init(void)
245 {
246         Matrix4x4_CreateIdentity(&r_identitymatrix);
247 // FIXME: move this to client?
248         FOG_registercvars();
249         Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
250         Cvar_RegisterVariable(&r_drawentities);
251         Cvar_RegisterVariable(&r_drawviewmodel);
252         Cvar_RegisterVariable(&r_shadow_staticworldlights);
253         Cvar_RegisterVariable(&r_speeds);
254         Cvar_RegisterVariable(&r_fullbrights);
255         Cvar_RegisterVariable(&r_wateralpha);
256         Cvar_RegisterVariable(&r_dynamic);
257         Cvar_RegisterVariable(&r_fullbright);
258         Cvar_RegisterVariable(&r_textureunits);
259         Cvar_RegisterVariable(&r_shadow_cull);
260         Cvar_RegisterVariable(&r_lerpsprites);
261         Cvar_RegisterVariable(&r_lerpmodels);
262         Cvar_RegisterVariable(&r_waterscroll);
263         Cvar_RegisterVariable(&r_watershader);
264         Cvar_RegisterVariable(&r_drawcollisionbrushes);
265         if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ)
266                 Cvar_SetValue("r_fullbrights", 0);
267         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
268 }
269
270 vec3_t r_farclip_origin;
271 vec3_t r_farclip_direction;
272 vec_t r_farclip_directiondist;
273 vec_t r_farclip_meshfarclip;
274 int r_farclip_directionbit0;
275 int r_farclip_directionbit1;
276 int r_farclip_directionbit2;
277
278 // start a farclip measuring session
279 void R_FarClip_Start(vec3_t origin, vec3_t direction, vec_t startfarclip)
280 {
281         VectorCopy(origin, r_farclip_origin);
282         VectorCopy(direction, r_farclip_direction);
283         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
284         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
285         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
286         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
287         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
288 }
289
290 // enlarge farclip to accomodate box
291 void R_FarClip_Box(vec3_t mins, vec3_t maxs)
292 {
293         float d;
294         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
295           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
296           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
297         if (r_farclip_meshfarclip < d)
298                 r_farclip_meshfarclip = d;
299 }
300
301 // return farclip value
302 float R_FarClip_Finish(void)
303 {
304         return r_farclip_meshfarclip - r_farclip_directiondist;
305 }
306
307 extern void R_Textures_Init(void);
308 extern void Mod_RenderInit(void);
309 extern void GL_Draw_Init(void);
310 extern void GL_Main_Init(void);
311 extern void R_Shadow_Init(void);
312 extern void GL_Models_Init(void);
313 extern void R_Sky_Init(void);
314 extern void GL_Surf_Init(void);
315 extern void R_Crosshairs_Init(void);
316 extern void R_Light_Init(void);
317 extern void R_Particles_Init(void);
318 extern void R_Explosion_Init(void);
319 extern void ui_init(void);
320 extern void gl_backend_init(void);
321 extern void Sbar_Init(void);
322 extern void R_LightningBeams_Init(void);
323
324 void Render_Init(void)
325 {
326         R_Textures_Init();
327         Mod_RenderInit();
328         gl_backend_init();
329         R_MeshQueue_Init();
330         GL_Draw_Init();
331         GL_Main_Init();
332         R_Shadow_Init();
333         GL_Models_Init();
334         R_Sky_Init();
335         GL_Surf_Init();
336         R_Crosshairs_Init();
337         R_Light_Init();
338         R_Particles_Init();
339         R_Explosion_Init();
340         //ui_init();
341         UI_Init();
342         Sbar_Init();
343         R_LightningBeams_Init();
344 }
345
346 /*
347 ===============
348 GL_Init
349 ===============
350 */
351 extern char *ENGINE_EXTENSIONS;
352 void GL_Init (void)
353 {
354         VID_CheckExtensions();
355
356         // LordHavoc: report supported extensions
357         Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
358 }
359
360 int R_CullBox(const vec3_t mins, const vec3_t maxs)
361 {
362         int i;
363         mplane_t *p;
364         for (i = 0;i < 4;i++)
365         {
366                 p = frustum + i;
367                 switch(p->signbits)
368                 {
369                 default:
370                 case 0:
371                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
372                                 return true;
373                         break;
374                 case 1:
375                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
376                                 return true;
377                         break;
378                 case 2:
379                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
380                                 return true;
381                         break;
382                 case 3:
383                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
384                                 return true;
385                         break;
386                 case 4:
387                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
388                                 return true;
389                         break;
390                 case 5:
391                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
392                                 return true;
393                         break;
394                 case 6:
395                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
396                                 return true;
397                         break;
398                 case 7:
399                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
400                                 return true;
401                         break;
402                 }
403         }
404         return false;
405 }
406
407 #define VIS_CullBox(mins,maxs) (R_CullBox((mins), (maxs)) || (cl.worldmodel && cl.worldmodel->brush.BoxTouchingPVS && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, r_pvsbits, (mins), (maxs))))
408
409 //==================================================================================
410
411 static void R_MarkEntities (void)
412 {
413         int i;
414         entity_render_t *ent;
415
416         ent = &cl_entities[0].render;
417         Matrix4x4_CreateIdentity(&ent->matrix);
418         Matrix4x4_CreateIdentity(&ent->inversematrix);
419
420         if (cl.worldmodel)
421                 R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
422
423         if (!r_drawentities.integer)
424                 return;
425
426         for (i = 0;i < r_refdef.numentities;i++)
427         {
428                 ent = r_refdef.entities[i];
429                 Mod_CheckLoaded(ent->model);
430                 // some of the renderer still relies on origin...
431                 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
432                 // some of the renderer still relies on scale...
433                 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
434                 R_LerpAnimation(ent);
435                 R_UpdateEntLights(ent);
436                 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
437                  && !VIS_CullBox(ent->mins, ent->maxs)
438                  && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
439                 {
440                         ent->visframe = r_framecount;
441                         R_FarClip_Box(ent->mins, ent->maxs);
442                 }
443         }
444 }
445
446 // only used if skyrendermasked, and normally returns false
447 int R_DrawBrushModelsSky (void)
448 {
449         int i, sky;
450         entity_render_t *ent;
451
452         if (!r_drawentities.integer)
453                 return false;
454
455         sky = false;
456         for (i = 0;i < r_refdef.numentities;i++)
457         {
458                 ent = r_refdef.entities[i];
459                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
460                 {
461                         ent->model->DrawSky(ent);
462                         sky = true;
463                 }
464         }
465         return sky;
466 }
467
468 /*
469 =============
470 R_DrawViewModel
471 =============
472 */
473 /*
474 void R_DrawViewModel (void)
475 {
476         entity_render_t *ent;
477
478         // FIXME: move these checks to client
479         if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
480                 return;
481
482         ent = &cl.viewent.render;
483         Mod_CheckLoaded(ent->model);
484         R_LerpAnimation(ent);
485         Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
486         Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
487         R_UpdateEntLights(ent);
488         ent->model->Draw(ent);
489 }
490 */
491
492 void R_DrawNoModel(entity_render_t *ent);
493 void R_DrawModels(void)
494 {
495         int i;
496         entity_render_t *ent;
497
498         if (!r_drawentities.integer)
499                 return;
500
501         for (i = 0;i < r_refdef.numentities;i++)
502         {
503                 ent = r_refdef.entities[i];
504                 if (ent->visframe == r_framecount)
505                 {
506                         if (ent->model && ent->model->Draw != NULL)
507                                 ent->model->Draw(ent);
508                         else
509                                 R_DrawNoModel(ent);
510                 }
511         }
512 }
513
514 #include "r_shadow.h"
515
516 int shadowframecount = 0;
517
518 void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t lightmins, vec3_t lightmaxs, vec3_t clipmins, vec3_t clipmaxs, int lightmarked)
519 {
520         vec3_t relativelightorigin;
521         // rough checks
522         if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume && !(r_shadow_cull.integer && (ent->maxs[0] < lightmins[0] || ent->mins[0] > lightmaxs[0] || ent->maxs[1] < lightmins[1] || ent->mins[1] > lightmaxs[1] || ent->maxs[2] < lightmins[2] || ent->mins[2] > lightmaxs[2])))
523         {
524                 Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
525                 ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
526         }
527 }
528
529 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
530
531 void R_ShadowVolumeLighting(int visiblevolumes)
532 {
533         int i;
534         entity_render_t *ent;
535         int lnum;
536         float f, lightradius, cullradius;
537         vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
538         worldlight_t *wl;
539         rdlight_t *rd;
540         rmeshstate_t m;
541         rtexture_t *cubemaptexture;
542         matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
543
544         if (visiblevolumes)
545         {
546                 memset(&m, 0, sizeof(m));
547                 R_Mesh_State_Texture(&m);
548
549                 GL_BlendFunc(GL_ONE, GL_ONE);
550                 GL_DepthMask(false);
551                 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
552                 qglDisable(GL_CULL_FACE);
553                 GL_Color(0.0, 0.0125, 0.1, 1);
554         }
555         else
556                 R_Shadow_Stage_Begin();
557         shadowframecount++;
558         if (r_shadow_realtime_world.integer)
559         {
560                 R_Shadow_LoadWorldLightsIfNeeded();
561                 for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++)
562                 {
563                         if (d_lightstylevalue[wl->style] <= 0)
564                                 continue;
565                         if (VIS_CullBox(wl->mins, wl->maxs))
566                                 continue;
567                         if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
568                                 continue;
569                         if (R_Shadow_ScissorForBBox(wl->mins, wl->maxs))
570                                 continue;
571
572                         cullradius = wl->cullradius;
573                         lightradius = wl->radius;
574                         VectorCopy(wl->mins, clipmins);
575                         VectorCopy(wl->maxs, clipmaxs);
576
577                         f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
578                         VectorScale(wl->color, f, lightcolor);
579                         if (wl->selected)
580                         {
581                                 f = 2 + sin(realtime * M_PI * 4.0);
582                                 VectorScale(lightcolor, f, lightcolor);
583                         }
584
585                         if (r_shadow_worldshadows.integer && wl->drawshadows && (gl_stencil || visiblevolumes))
586                         {
587                                 if (!visiblevolumes)
588                                         R_Shadow_Stage_ShadowVolumes();
589                                 ent = &cl_entities[0].render;
590                                 if (r_shadow_staticworldlights.integer)
591                                         R_Shadow_DrawStaticWorldLight_Shadow(wl, &ent->matrix);
592                                 else
593                                         R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
594                                 if (r_drawentities.integer)
595                                         for (i = 0;i < r_refdef.numentities;i++)
596                                                 R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
597                         }
598
599                         if (!visiblevolumes)
600                         {
601                                 if (r_shadow_worldshadows.integer && wl->drawshadows && gl_stencil)
602                                         R_Shadow_Stage_LightWithShadows();
603                                 else
604                                         R_Shadow_Stage_LightWithoutShadows();
605
606                                 ent = &cl_entities[0].render;
607                                 if (ent->model && ent->model->DrawLight)
608                                 {
609                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
610                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
611                                         Matrix4x4_Concat(&matrix_modeltolight, &wl->matrix_worldtolight, &ent->matrix);
612                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &wl->matrix_worldtoattenuationxyz, &ent->matrix);
613                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &wl->matrix_worldtoattenuationz, &ent->matrix);
614                                         if (r_shadow_staticworldlights.integer)
615                                                 R_Shadow_DrawStaticWorldLight_Light(wl, &ent->matrix, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
616                                         else
617                                                 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, wl->cubemap);
618                                 }
619                                 if (r_drawentities.integer)
620                                 {
621                                         for (i = 0;i < r_refdef.numentities;i++)
622                                         {
623                                                 ent = r_refdef.entities[i];
624                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
625                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
626                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
627                                                 {
628                                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
629                                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
630                                                         Matrix4x4_Concat(&matrix_modeltolight, &wl->matrix_worldtolight, &ent->matrix);
631                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &wl->matrix_worldtoattenuationxyz, &ent->matrix);
632                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &wl->matrix_worldtoattenuationz, &ent->matrix);
633                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, wl->cubemap);
634                                                 }
635                                         }
636                                 }
637                         }
638                 }
639         }
640         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
641         {
642                 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
643                 {
644                         lightradius = rd->radius;
645                         clipmins[0] = rd->origin[0] - lightradius;
646                         clipmins[1] = rd->origin[1] - lightradius;
647                         clipmins[2] = rd->origin[2] - lightradius;
648                         clipmaxs[0] = rd->origin[0] + lightradius;
649                         clipmaxs[1] = rd->origin[1] + lightradius;
650                         clipmaxs[2] = rd->origin[2] + lightradius;
651                         if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
652                                 continue;
653
654                         cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
655                         VectorCopy(rd->color, lightcolor);
656
657                         if (rd->cubemapnum > 0)
658                                 cubemaptexture = R_Shadow_Cubemap(va("cubemaps/%i", rd->cubemapnum));
659                         else
660                                 cubemaptexture = NULL;
661
662                         if (r_shadow_dlightshadows.integer && rd->shadow && (gl_stencil || visiblevolumes))
663                         {
664                                 if (!visiblevolumes)
665                                         R_Shadow_Stage_ShadowVolumes();
666                                 ent = &cl_entities[0].render;
667                                 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
668                                 if (r_drawentities.integer)
669                                 {
670                                         for (i = 0;i < r_refdef.numentities;i++)
671                                         {
672                                                 ent = r_refdef.entities[i];
673                                                 if (ent != rd->ent)
674                                                         R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
675                                         }
676                                 }
677                         }
678
679                         if (!visiblevolumes)
680                         {
681                                 if (r_shadow_dlightshadows.integer && gl_stencil && rd->shadow)
682                                         R_Shadow_Stage_LightWithShadows();
683                                 else
684                                         R_Shadow_Stage_LightWithoutShadows();
685
686                                 ent = &cl_entities[0].render;
687                                 if (ent->model && ent->model->DrawLight)
688                                 {
689                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
690                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
691                                         Matrix4x4_Concat(&matrix_modeltolight, &rd->matrix_worldtolight, &ent->matrix);
692                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rd->matrix_worldtoattenuationxyz, &ent->matrix);
693                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rd->matrix_worldtoattenuationz, &ent->matrix);
694                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
695                                 }
696                                 if (r_drawentities.integer)
697                                 {
698                                         for (i = 0;i < r_refdef.numentities;i++)
699                                         {
700                                                 ent = r_refdef.entities[i];
701                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
702                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
703                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
704                                                 {
705                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
706                                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
707                                                         Matrix4x4_Concat(&matrix_modeltolight, &rd->matrix_worldtolight, &ent->matrix);
708                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rd->matrix_worldtoattenuationxyz, &ent->matrix);
709                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rd->matrix_worldtoattenuationz, &ent->matrix);
710                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
711                                                 }
712                                         }
713                                 }
714                         }
715                 }
716         }
717
718         if (visiblevolumes)
719         {
720                 qglEnable(GL_CULL_FACE);
721                 qglDisable(GL_SCISSOR_TEST);
722         }
723         else
724                 R_Shadow_Stage_End();
725 }
726
727 static void R_SetFrustum (void)
728 {
729         // LordHavoc: note to all quake engine coders, the special case for 90
730         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
731         // disabled as well.
732
733         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
734         RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_refdef.fov_x / 2));
735         frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
736         PlaneClassify(&frustum[0]);
737
738         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
739         RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_refdef.fov_x / 2));
740         frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
741         PlaneClassify(&frustum[1]);
742
743         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
744         RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_refdef.fov_y / 2));
745         frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
746         PlaneClassify(&frustum[2]);
747
748         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
749         RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_refdef.fov_y / 2));
750         frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
751         PlaneClassify(&frustum[3]);
752 }
753
754 /*
755 ===============
756 R_SetupFrame
757 ===============
758 */
759 static void R_SetupFrame (void)
760 {
761 // don't allow cheats in multiplayer
762         if (!cl.islocalgame)
763         {
764                 if (r_fullbright.integer != 0)
765                         Cvar_Set ("r_fullbright", "0");
766                 if (r_ambient.value != 0)
767                         Cvar_Set ("r_ambient", "0");
768         }
769
770         r_framecount++;
771
772         // break apart the viewentity matrix into vectors for various purposes
773         Matrix4x4_ToVectors(&r_refdef.viewentitymatrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
774         VectorNegate(r_viewleft, r_viewright);
775
776         GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
777
778         R_AnimateLight();
779 }
780
781
782 static void R_BlendView(void)
783 {
784         rmeshstate_t m;
785         float r;
786         float vertex3f[3*3];
787
788         if (r_refdef.viewblend[3] < 0.01f)
789                 return;
790
791         R_Mesh_Matrix(&r_identitymatrix);
792
793         memset(&m, 0, sizeof(m));
794         R_Mesh_State_Texture(&m);
795
796         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
797         GL_DepthMask(true);
798         GL_DepthTest(false); // magic
799         GL_VertexPointer(vertex3f);
800         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
801         r = 64;
802         vertex3f[0] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r - r_viewup[0] * r;
803         vertex3f[1] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r - r_viewup[1] * r;
804         vertex3f[2] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r - r_viewup[2] * r;
805         vertex3f[3] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r + r_viewup[0] * r * 3;
806         vertex3f[4] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r + r_viewup[1] * r * 3;
807         vertex3f[5] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r + r_viewup[2] * r * 3;
808         vertex3f[6] = r_vieworigin[0] + r_viewforward[0] * 1.5 - r_viewleft[0] * r * 3 - r_viewup[0] * r;
809         vertex3f[7] = r_vieworigin[1] + r_viewforward[1] * 1.5 - r_viewleft[1] * r * 3 - r_viewup[1] * r;
810         vertex3f[8] = r_vieworigin[2] + r_viewforward[2] * 1.5 - r_viewleft[2] * r * 3 - r_viewup[2] * r;
811         R_Mesh_Draw(3, 1, polygonelements);
812 }
813
814 /*
815 ================
816 R_RenderView
817
818 r_refdef must be set before the first call
819 ================
820 */
821 extern void R_DrawLightningBeams (void);
822 void R_RenderView (void)
823 {
824         entity_render_t *world;
825         if (!r_refdef.entities/* || !cl.worldmodel*/)
826                 return; //Host_Error ("R_RenderView: NULL worldmodel");
827
828         if (r_shadow_realtime_world.integer)
829         {
830                 if (!gl_stencil)
831                 {
832                         Con_Printf("Realtime world lighting requires 32bit color turning off r_shadow_realtime_world, please type vid_bitsperpixel 32;vid_restart and try again\n");
833                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
834                 }
835         }
836
837         world = &cl_entities[0].render;
838
839         // FIXME: move to client
840         R_MoveExplosions();
841         R_TimeReport("mexplosion");
842
843         qglPolygonOffset(0, 0);
844         qglEnable(GL_POLYGON_OFFSET_FILL);
845
846         R_Textures_Frame();
847         R_SetupFrame();
848         R_SetFrustum();
849         R_SetupFog();
850         R_SkyStartFrame();
851         R_BuildLightList();
852         R_TimeReport("setup");
853
854         if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
855                 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
856
857         R_WorldVisibility(world);
858         R_TimeReport("worldvis");
859
860         R_FarClip_Start(r_vieworigin, r_viewforward, 768.0f);
861         R_MarkEntities();
862         r_farclip = R_FarClip_Finish() + 256.0f;
863         if (gl_stencil && ((r_shadow_realtime_world.integer && r_shadow_worldshadows.integer) || ((r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && r_shadow_dlightshadows.integer)))
864                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
865         else
866                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
867         GL_SetupView_Orientation_FromEntity(&r_refdef.viewentitymatrix);
868         R_TimeReport("markentity");
869
870         qglDepthFunc(GL_LEQUAL);
871
872         R_Mesh_Start();
873         R_MeshQueue_BeginScene();
874
875         R_Shadow_UpdateWorldLightSelection();
876
877         if (R_DrawBrushModelsSky())
878                 R_TimeReport("bmodelsky");
879
880         // must occur early because it can draw sky
881         R_DrawWorld(world);
882         R_TimeReport("world");
883
884         // don't let sound skip if going slow
885         if (!intimerefresh && !r_speeds.integer)
886                 S_ExtraUpdate ();
887
888         R_DrawModels();
889         R_TimeReport("models");
890
891         R_ShadowVolumeLighting(false);
892         R_TimeReport("rtlights");
893
894         R_DrawLightningBeams();
895         R_TimeReport("lightning");
896
897         R_DrawParticles();
898         R_TimeReport("particles");
899
900         R_DrawExplosions();
901         R_TimeReport("explosions");
902
903         R_MeshQueue_RenderTransparent();
904         R_TimeReport("drawtrans");
905
906         R_DrawCoronas();
907         R_TimeReport("coronas");
908
909         R_DrawWorldCrosshair();
910         R_TimeReport("crosshair");
911
912         R_BlendView();
913         R_TimeReport("blendview");
914
915         R_MeshQueue_Render();
916         R_MeshQueue_EndScene();
917
918         if (r_shadow_visiblevolumes.integer)
919         {
920                 R_ShadowVolumeLighting(true);
921                 R_TimeReport("shadowvolume");
922         }
923
924         R_Mesh_Finish();
925         R_TimeReport("meshfinish");
926
927         qglPolygonOffset(0, 0);
928         qglDisable(GL_POLYGON_OFFSET_FILL);
929 }
930
931 /*
932 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
933 {
934         int i;
935         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
936         rmeshstate_t m;
937         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
938         GL_DepthMask(false);
939         GL_DepthTest(true);
940         R_Mesh_Matrix(&r_identitymatrix);
941
942         memset(&m, 0, sizeof(m));
943         R_Mesh_State_Texture(&m);
944
945         R_Mesh_GetSpace(8);
946         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
947         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
948         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
949         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
950         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
951         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
952         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
953         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
954         GL_ColorPointer(color);
955         R_FillColors(color, 8, cr, cg, cb, ca);
956         if (fogenabled)
957         {
958                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
959                 {
960                         VectorSubtract(v, r_vieworigin, diff);
961                         f2 = exp(fogdensity/DotProduct(diff, diff));
962                         f1 = 1 - f2;
963                         c[0] = c[0] * f1 + fogcolor[0] * f2;
964                         c[1] = c[1] * f1 + fogcolor[1] * f2;
965                         c[2] = c[2] * f1 + fogcolor[2] * f2;
966                 }
967         }
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         R_Mesh_State_Texture(&m);
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(true);
1032         GL_VertexPointer(nomodelvertex3f);
1033         if (fogenabled)
1034         {
1035                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1036                 GL_ColorPointer(color4f);
1037                 VectorSubtract(ent->origin, r_vieworigin, diff);
1038                 f2 = exp(fogdensity/DotProduct(diff, diff));
1039                 f1 = 1 - f2;
1040                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1041                 {
1042                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
1043                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
1044                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
1045                         c[3] *= ent->alpha;
1046                 }
1047         }
1048         else if (ent->alpha != 1)
1049         {
1050                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1051                 GL_ColorPointer(color4f);
1052                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1053                         c[3] *= ent->alpha;
1054         }
1055         else
1056                 GL_ColorPointer(nomodelcolor4f);
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->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         VectorNormalizeFast (normal);
1074
1075         // calculate 'right' vector for start
1076         VectorSubtract (r_vieworigin, org1, diff);
1077         VectorNormalizeFast (diff);
1078         CrossProduct (normal, diff, right1);
1079
1080         // calculate 'right' vector for end
1081         VectorSubtract (r_vieworigin, org2, diff);
1082         VectorNormalizeFast (diff);
1083         CrossProduct (normal, diff, right2);
1084
1085         vert[ 0] = org1[0] + width * right1[0];
1086         vert[ 1] = org1[1] + width * right1[1];
1087         vert[ 2] = org1[2] + width * right1[2];
1088         vert[ 3] = org1[0] - width * right1[0];
1089         vert[ 4] = org1[1] - width * right1[1];
1090         vert[ 5] = org1[2] - width * right1[2];
1091         vert[ 6] = org2[0] - width * right2[0];
1092         vert[ 7] = org2[1] - width * right2[1];
1093         vert[ 8] = org2[2] - width * right2[2];
1094         vert[ 9] = org2[0] + width * right2[0];
1095         vert[10] = org2[1] + width * right2[1];
1096         vert[11] = org2[2] + width * right2[2];
1097 }
1098
1099 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1100
1101 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)
1102 {
1103         float diff[3];
1104         rmeshstate_t m;
1105
1106         if (fogenabled)
1107         {
1108                 VectorSubtract(origin, r_vieworigin, diff);
1109                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1110         }
1111
1112         R_Mesh_Matrix(&r_identitymatrix);
1113         GL_Color(cr, cg, cb, ca);
1114         GL_VertexPointer(varray_vertex3f);
1115         GL_BlendFunc(blendfunc1, blendfunc2);
1116         GL_DepthMask(false);
1117         GL_DepthTest(!depthdisable);
1118
1119         memset(&m, 0, sizeof(m));
1120         m.tex[0] = R_GetTexture(texture);
1121         m.pointer_texcoord[0] = spritetexcoord2f;
1122         R_Mesh_State_Texture(&m);
1123
1124         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1125         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1126         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1127         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1128         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1129         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1130         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1131         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1132         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1133         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1134         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1135         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1136         R_Mesh_Draw(4, 2, polygonelements);
1137 }
1138