fixed GL_Scissor call in rtlight code (apparently I need to feed it a top to bottom...
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23
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_UpdateFog(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 static vec3_t r_farclip_origin;
271 static vec3_t r_farclip_direction;
272 static vec_t r_farclip_directiondist;
273 static vec_t r_farclip_meshfarclip;
274 static int r_farclip_directionbit0;
275 static int r_farclip_directionbit1;
276 static int r_farclip_directionbit2;
277
278 // enlarge farclip to accomodate box
279 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
280 {
281         float d;
282         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
283           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
284           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
285         if (r_farclip_meshfarclip < d)
286                 r_farclip_meshfarclip = d;
287 }
288
289 // return farclip value
290 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
291 {
292         int i;
293
294         VectorCopy(origin, r_farclip_origin);
295         VectorCopy(direction, r_farclip_direction);
296         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
297         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
298         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
299         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
300         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
301
302         if (cl.worldmodel)
303                 R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
304         for (i = 0;i < r_refdef.numentities;i++)
305                 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
306         
307         return r_farclip_meshfarclip - r_farclip_directiondist;
308 }
309
310 extern void R_Textures_Init(void);
311 extern void Mod_RenderInit(void);
312 extern void GL_Draw_Init(void);
313 extern void GL_Main_Init(void);
314 extern void R_Shadow_Init(void);
315 extern void GL_Models_Init(void);
316 extern void R_Sky_Init(void);
317 extern void GL_Surf_Init(void);
318 extern void R_Crosshairs_Init(void);
319 extern void R_Light_Init(void);
320 extern void R_Particles_Init(void);
321 extern void R_Explosion_Init(void);
322 extern void ui_init(void);
323 extern void gl_backend_init(void);
324 extern void Sbar_Init(void);
325 extern void R_LightningBeams_Init(void);
326
327 void Render_Init(void)
328 {
329         R_Textures_Init();
330         Mod_RenderInit();
331         gl_backend_init();
332         R_MeshQueue_Init();
333         GL_Draw_Init();
334         GL_Main_Init();
335         R_Shadow_Init();
336         GL_Models_Init();
337         R_Sky_Init();
338         GL_Surf_Init();
339         R_Crosshairs_Init();
340         R_Light_Init();
341         R_Particles_Init();
342         R_Explosion_Init();
343         //ui_init();
344         UI_Init();
345         Sbar_Init();
346         R_LightningBeams_Init();
347 }
348
349 /*
350 ===============
351 GL_Init
352 ===============
353 */
354 extern char *ENGINE_EXTENSIONS;
355 void GL_Init (void)
356 {
357         VID_CheckExtensions();
358
359         // LordHavoc: report supported extensions
360         Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
361 }
362
363 int R_CullBox(const vec3_t mins, const vec3_t maxs)
364 {
365         int i;
366         mplane_t *p;
367         for (i = 0;i < 4;i++)
368         {
369                 p = frustum + i;
370                 switch(p->signbits)
371                 {
372                 default:
373                 case 0:
374                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
375                                 return true;
376                         break;
377                 case 1:
378                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
379                                 return true;
380                         break;
381                 case 2:
382                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
383                                 return true;
384                         break;
385                 case 3:
386                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
387                                 return true;
388                         break;
389                 case 4:
390                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
391                                 return true;
392                         break;
393                 case 5:
394                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
395                                 return true;
396                         break;
397                 case 6:
398                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
399                                 return true;
400                         break;
401                 case 7:
402                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
403                                 return true;
404                         break;
405                 }
406         }
407         return false;
408 }
409
410 #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))))
411
412 //==================================================================================
413
414 static void R_MarkEntities (void)
415 {
416         int i;
417         entity_render_t *ent;
418
419         ent = &cl_entities[0].render;
420         Matrix4x4_CreateIdentity(&ent->matrix);
421         Matrix4x4_CreateIdentity(&ent->inversematrix);
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                         ent->visframe = r_framecount;
440         }
441 }
442
443 // only used if skyrendermasked, and normally returns false
444 int R_DrawBrushModelsSky (void)
445 {
446         int i, sky;
447         entity_render_t *ent;
448
449         if (!r_drawentities.integer)
450                 return false;
451
452         sky = false;
453         for (i = 0;i < r_refdef.numentities;i++)
454         {
455                 ent = r_refdef.entities[i];
456                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
457                 {
458                         ent->model->DrawSky(ent);
459                         sky = true;
460                 }
461         }
462         return sky;
463 }
464
465 /*
466 =============
467 R_DrawViewModel
468 =============
469 */
470 /*
471 void R_DrawViewModel (void)
472 {
473         entity_render_t *ent;
474
475         // FIXME: move these checks to client
476         if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
477                 return;
478
479         ent = &cl.viewent.render;
480         Mod_CheckLoaded(ent->model);
481         R_LerpAnimation(ent);
482         Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
483         Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
484         R_UpdateEntLights(ent);
485         ent->model->Draw(ent);
486 }
487 */
488
489 void R_DrawNoModel(entity_render_t *ent);
490 void R_DrawModels(void)
491 {
492         int i;
493         entity_render_t *ent;
494
495         if (!r_drawentities.integer)
496                 return;
497
498         for (i = 0;i < r_refdef.numentities;i++)
499         {
500                 ent = r_refdef.entities[i];
501                 if (ent->visframe == r_framecount)
502                 {
503                         if (ent->model && ent->model->Draw != NULL)
504                                 ent->model->Draw(ent);
505                         else
506                                 R_DrawNoModel(ent);
507                 }
508         }
509 }
510
511 #include "r_shadow.h"
512
513 int shadowframecount = 0;
514
515 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)
516 {
517         vec3_t relativelightorigin;
518         // rough checks
519         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])))
520         {
521                 Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
522                 ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
523         }
524 }
525
526 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
527
528 void R_ShadowVolumeLighting(int visiblevolumes)
529 {
530         int i;
531         entity_render_t *ent;
532         int lnum;
533         float f, lightradius, cullradius;
534         vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
535         worldlight_t *wl;
536         rdlight_t *rd;
537         rmeshstate_t m;
538         rtexture_t *cubemaptexture;
539         matrix4x4_t matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
540
541         if (visiblevolumes)
542         {
543                 memset(&m, 0, sizeof(m));
544                 R_Mesh_State_Texture(&m);
545
546                 GL_BlendFunc(GL_ONE, GL_ONE);
547                 GL_DepthMask(false);
548                 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
549                 qglDisable(GL_CULL_FACE);
550                 GL_Color(0.0, 0.0125, 0.1, 1);
551         }
552         else
553                 R_Shadow_Stage_Begin();
554         shadowframecount++;
555         if (r_shadow_realtime_world.integer)
556         {
557                 R_Shadow_LoadWorldLightsIfNeeded();
558                 for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++)
559                 {
560                         if (d_lightstylevalue[wl->style] <= 0)
561                                 continue;
562                         if (R_CullBox(wl->mins, wl->maxs))
563                                 continue;
564                         for (i = 0;i < wl->numclusters;i++)
565                                 if (CHECKPVSBIT(r_pvsbits, wl->clusterindices[i]))
566                                         break;
567                         if (i == wl->numclusters)
568                                 continue;
569                         if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
570                                 continue;
571                         if (R_Shadow_ScissorForBBox(wl->mins, wl->maxs))
572                                 continue;
573
574                         cullradius = wl->cullradius;
575                         lightradius = wl->radius;
576                         VectorCopy(wl->mins, clipmins);
577                         VectorCopy(wl->maxs, clipmaxs);
578
579                         f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
580                         VectorScale(wl->color, f, lightcolor);
581                         if (wl->selected)
582                         {
583                                 f = 2 + sin(realtime * M_PI * 4.0);
584                                 VectorScale(lightcolor, f, lightcolor);
585                         }
586
587                         if (r_shadow_worldshadows.integer && wl->drawshadows && (gl_stencil || visiblevolumes))
588                         {
589                                 if (!visiblevolumes)
590                                         R_Shadow_Stage_ShadowVolumes();
591                                 ent = &cl_entities[0].render;
592                                 if (r_shadow_staticworldlights.integer)
593                                         R_Shadow_DrawStaticWorldLight_Shadow(wl, &ent->matrix);
594                                 else
595                                         R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
596                                 if (r_drawentities.integer)
597                                         for (i = 0;i < r_refdef.numentities;i++)
598                                                 R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
599                         }
600
601                         if (!visiblevolumes)
602                         {
603                                 if (r_shadow_worldshadows.integer && wl->drawshadows && gl_stencil)
604                                         R_Shadow_Stage_LightWithShadows();
605                                 else
606                                         R_Shadow_Stage_LightWithoutShadows();
607
608                                 ent = &cl_entities[0].render;
609                                 if (ent->model && ent->model->DrawLight)
610                                 {
611                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
612                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
613                                         Matrix4x4_Concat(&matrix_modeltolight, &wl->matrix_worldtolight, &ent->matrix);
614                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &wl->matrix_worldtoattenuationxyz, &ent->matrix);
615                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &wl->matrix_worldtoattenuationz, &ent->matrix);
616                                         if (r_shadow_staticworldlights.integer)
617                                                 R_Shadow_DrawStaticWorldLight_Light(wl, &ent->matrix, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
618                                         else
619                                                 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, wl->cubemap);
620                                 }
621                                 if (r_drawentities.integer)
622                                 {
623                                         for (i = 0;i < r_refdef.numentities;i++)
624                                         {
625                                                 ent = r_refdef.entities[i];
626                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
627                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
628                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
629                                                 {
630                                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
631                                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
632                                                         Matrix4x4_Concat(&matrix_modeltolight, &wl->matrix_worldtolight, &ent->matrix);
633                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &wl->matrix_worldtoattenuationxyz, &ent->matrix);
634                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &wl->matrix_worldtoattenuationz, &ent->matrix);
635                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, wl->cubemap);
636                                                 }
637                                         }
638                                 }
639                         }
640                 }
641         }
642         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
643         {
644                 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
645                 {
646                         lightradius = rd->radius;
647                         clipmins[0] = rd->origin[0] - lightradius;
648                         clipmins[1] = rd->origin[1] - lightradius;
649                         clipmins[2] = rd->origin[2] - lightradius;
650                         clipmaxs[0] = rd->origin[0] + lightradius;
651                         clipmaxs[1] = rd->origin[1] + lightradius;
652                         clipmaxs[2] = rd->origin[2] + lightradius;
653                         if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
654                                 continue;
655
656                         cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
657                         VectorCopy(rd->color, lightcolor);
658
659                         if (rd->cubemapnum > 0)
660                                 cubemaptexture = R_Shadow_Cubemap(va("cubemaps/%i", rd->cubemapnum));
661                         else
662                                 cubemaptexture = NULL;
663
664                         if (r_shadow_dlightshadows.integer && rd->shadow && (gl_stencil || visiblevolumes))
665                         {
666                                 if (!visiblevolumes)
667                                         R_Shadow_Stage_ShadowVolumes();
668                                 ent = &cl_entities[0].render;
669                                 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
670                                 if (r_drawentities.integer)
671                                 {
672                                         for (i = 0;i < r_refdef.numentities;i++)
673                                         {
674                                                 ent = r_refdef.entities[i];
675                                                 if (ent != rd->ent)
676                                                         R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
677                                         }
678                                 }
679                         }
680
681                         if (!visiblevolumes)
682                         {
683                                 if (r_shadow_dlightshadows.integer && gl_stencil && rd->shadow)
684                                         R_Shadow_Stage_LightWithShadows();
685                                 else
686                                         R_Shadow_Stage_LightWithoutShadows();
687
688                                 ent = &cl_entities[0].render;
689                                 if (ent->model && ent->model->DrawLight)
690                                 {
691                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
692                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
693                                         Matrix4x4_Concat(&matrix_modeltolight, &rd->matrix_worldtolight, &ent->matrix);
694                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rd->matrix_worldtoattenuationxyz, &ent->matrix);
695                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rd->matrix_worldtoattenuationz, &ent->matrix);
696                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
697                                 }
698                                 if (r_drawentities.integer)
699                                 {
700                                         for (i = 0;i < r_refdef.numentities;i++)
701                                         {
702                                                 ent = r_refdef.entities[i];
703                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
704                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
705                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
706                                                 {
707                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
708                                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
709                                                         Matrix4x4_Concat(&matrix_modeltolight, &rd->matrix_worldtolight, &ent->matrix);
710                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rd->matrix_worldtoattenuationxyz, &ent->matrix);
711                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rd->matrix_worldtoattenuationz, &ent->matrix);
712                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
713                                                 }
714                                         }
715                                 }
716                         }
717                 }
718         }
719
720         if (visiblevolumes)
721         {
722                 qglEnable(GL_CULL_FACE);
723                 GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
724         }
725         else
726                 R_Shadow_Stage_End();
727 }
728
729 static void R_SetFrustum(void)
730 {
731         // break apart the viewentity matrix into vectors for various purposes
732         Matrix4x4_ToVectors(&r_refdef.viewentitymatrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
733         VectorNegate(r_viewleft, r_viewright);
734
735         // LordHavoc: note to all quake engine coders, the special case for 90
736         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
737         // disabled as well.
738
739         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
740         RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_refdef.fov_x / 2));
741         frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
742         PlaneClassify(&frustum[0]);
743
744         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
745         RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_refdef.fov_x / 2));
746         frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
747         PlaneClassify(&frustum[1]);
748
749         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
750         RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_refdef.fov_y / 2));
751         frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
752         PlaneClassify(&frustum[2]);
753
754         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
755         RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_refdef.fov_y / 2));
756         frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
757         PlaneClassify(&frustum[3]);
758 }
759
760 static void R_BlendView(void)
761 {
762         rmeshstate_t m;
763         float r;
764         float vertex3f[3*3];
765
766         if (r_refdef.viewblend[3] < 0.01f)
767                 return;
768
769         R_Mesh_Matrix(&r_identitymatrix);
770
771         memset(&m, 0, sizeof(m));
772         R_Mesh_State_Texture(&m);
773
774         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
775         GL_DepthMask(true);
776         GL_DepthTest(false); // magic
777         GL_VertexPointer(vertex3f);
778         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
779         r = 64;
780         vertex3f[0] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r - r_viewup[0] * r;
781         vertex3f[1] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r - r_viewup[1] * r;
782         vertex3f[2] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r - r_viewup[2] * r;
783         vertex3f[3] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r + r_viewup[0] * r * 3;
784         vertex3f[4] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r + r_viewup[1] * r * 3;
785         vertex3f[5] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r + r_viewup[2] * r * 3;
786         vertex3f[6] = r_vieworigin[0] + r_viewforward[0] * 1.5 - r_viewleft[0] * r * 3 - r_viewup[0] * r;
787         vertex3f[7] = r_vieworigin[1] + r_viewforward[1] * 1.5 - r_viewleft[1] * r * 3 - r_viewup[1] * r;
788         vertex3f[8] = r_vieworigin[2] + r_viewforward[2] * 1.5 - r_viewleft[2] * r * 3 - r_viewup[2] * r;
789         R_Mesh_Draw(3, 1, polygonelements);
790 }
791
792 void R_UpdateWorld(void)
793 {
794         if (!r_refdef.entities/* || !cl.worldmodel*/)
795                 return; //Host_Error ("R_RenderView: NULL worldmodel");
796
797         if (r_shadow_realtime_world.integer && !gl_stencil)
798         {
799                 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");
800                 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
801         }
802
803         // don't allow cheats in multiplayer
804         if (!cl.islocalgame)
805         {
806                 if (r_fullbright.integer != 0)
807                         Cvar_Set ("r_fullbright", "0");
808                 if (r_ambient.value != 0)
809                         Cvar_Set ("r_ambient", "0");
810         }
811
812         R_Textures_Frame();
813         R_UpdateFog();
814         R_UpdateLights();
815 }
816
817 void R_RenderScene(void);
818
819 /*
820 ================
821 R_RenderView
822 ================
823 */
824 void R_RenderView(void)
825 {
826         if (!r_refdef.entities/* || !cl.worldmodel*/)
827                 return; //Host_Error ("R_RenderView: NULL worldmodel");
828         
829         r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
830         r_refdef.height = bound(0, r_refdef.height, vid.realheight);
831         r_refdef.x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
832         r_refdef.y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
833         r_refdef.fov_x = bound(1, r_refdef.fov_x, 170);
834         r_refdef.fov_y = bound(1, r_refdef.fov_y, 170);
835
836         // GL is weird because it's bottom to top, r_refdef.y is top to bottom
837         qglViewport(r_refdef.x, vid.realheight - (r_refdef.y + r_refdef.height), r_refdef.width, r_refdef.height);
838         GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
839         GL_ScissorTest(true);
840         R_ClearScreen();
841
842         R_SetFrustum();
843         r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
844
845         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)))
846                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
847         else
848                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
849
850         GL_SetupView_Orientation_FromEntity(&r_refdef.viewentitymatrix);
851         R_TimeReport("setup");
852
853         R_RenderScene();
854
855         R_BlendView();
856         R_TimeReport("blendview");
857         
858         GL_Scissor(0, 0, vid.realwidth, vid.realheight);
859         GL_ScissorTest(false);
860 }
861
862 extern void R_DrawLightningBeams (void);
863 void R_RenderScene(void)
864 {
865         entity_render_t *world;
866
867         // don't let sound skip if going slow
868         if (!intimerefresh && !r_speeds.integer)
869                 S_ExtraUpdate ();
870
871         r_framecount++;
872
873         R_SkyStartFrame();
874
875         if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
876                 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
877         world = &cl_entities[0].render;
878         R_WorldVisibility(world);
879         R_TimeReport("worldvis");
880
881         R_MarkEntities();
882         R_TimeReport("markentity");
883
884         qglDepthFunc(GL_LEQUAL);
885         qglPolygonOffset(0, 0);
886         qglEnable(GL_POLYGON_OFFSET_FILL);
887
888         R_Mesh_Start();
889         R_MeshQueue_BeginScene();
890
891         R_Shadow_UpdateWorldLightSelection();
892
893         // don't let sound skip if going slow
894         if (!intimerefresh && !r_speeds.integer)
895                 S_ExtraUpdate ();
896
897         if (R_DrawBrushModelsSky())
898                 R_TimeReport("bmodelsky");
899
900         // must occur early because it can draw sky
901         R_DrawWorld(world);
902         R_TimeReport("world");
903
904         // don't let sound skip if going slow
905         if (!intimerefresh && !r_speeds.integer)
906                 S_ExtraUpdate ();
907
908         R_DrawModels();
909         R_TimeReport("models");
910
911         // don't let sound skip if going slow
912         if (!intimerefresh && !r_speeds.integer)
913                 S_ExtraUpdate ();
914
915         R_ShadowVolumeLighting(false);
916         R_TimeReport("rtlights");
917
918         // don't let sound skip if going slow
919         if (!intimerefresh && !r_speeds.integer)
920                 S_ExtraUpdate ();
921
922         R_DrawLightningBeams();
923         R_TimeReport("lightning");
924
925         R_DrawParticles();
926         R_TimeReport("particles");
927
928         R_DrawExplosions();
929         R_TimeReport("explosions");
930
931         R_MeshQueue_RenderTransparent();
932         R_TimeReport("drawtrans");
933
934         R_DrawCoronas();
935         R_TimeReport("coronas");
936
937         R_DrawWorldCrosshair();
938         R_TimeReport("crosshair");
939
940         R_MeshQueue_Render();
941         R_MeshQueue_EndScene();
942
943         if (r_shadow_visiblevolumes.integer)
944         {
945                 R_ShadowVolumeLighting(true);
946                 R_TimeReport("shadowvolume");
947         }
948
949         R_Mesh_Finish();
950         R_TimeReport("meshfinish");
951
952         qglPolygonOffset(0, 0);
953         qglDisable(GL_POLYGON_OFFSET_FILL);
954
955         // don't let sound skip if going slow
956         if (!intimerefresh && !r_speeds.integer)
957                 S_ExtraUpdate ();
958 }
959
960 /*
961 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
962 {
963         int i;
964         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
965         rmeshstate_t m;
966         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
967         GL_DepthMask(false);
968         GL_DepthTest(true);
969         R_Mesh_Matrix(&r_identitymatrix);
970
971         memset(&m, 0, sizeof(m));
972         R_Mesh_State_Texture(&m);
973
974         R_Mesh_GetSpace(8);
975         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
976         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
977         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
978         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
979         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
980         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
981         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
982         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
983         GL_ColorPointer(color);
984         R_FillColors(color, 8, cr, cg, cb, ca);
985         if (fogenabled)
986         {
987                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
988                 {
989                         VectorSubtract(v, r_vieworigin, diff);
990                         f2 = exp(fogdensity/DotProduct(diff, diff));
991                         f1 = 1 - f2;
992                         c[0] = c[0] * f1 + fogcolor[0] * f2;
993                         c[1] = c[1] * f1 + fogcolor[1] * f2;
994                         c[2] = c[2] * f1 + fogcolor[2] * f2;
995                 }
996         }
997         R_Mesh_Draw(8, 12);
998 }
999 */
1000
1001 int nomodelelements[24] =
1002 {
1003         5, 2, 0,
1004         5, 1, 2,
1005         5, 0, 3,
1006         5, 3, 1,
1007         0, 2, 4,
1008         2, 1, 4,
1009         3, 0, 4,
1010         1, 3, 4
1011 };
1012
1013 float nomodelvertex3f[6*3] =
1014 {
1015         -16,   0,   0,
1016          16,   0,   0,
1017           0, -16,   0,
1018           0,  16,   0,
1019           0,   0, -16,
1020           0,   0,  16
1021 };
1022
1023 float nomodelcolor4f[6*4] =
1024 {
1025         0.0f, 0.0f, 0.5f, 1.0f,
1026         0.0f, 0.0f, 0.5f, 1.0f,
1027         0.0f, 0.5f, 0.0f, 1.0f,
1028         0.0f, 0.5f, 0.0f, 1.0f,
1029         0.5f, 0.0f, 0.0f, 1.0f,
1030         0.5f, 0.0f, 0.0f, 1.0f
1031 };
1032
1033 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1034 {
1035         const entity_render_t *ent = calldata1;
1036         int i;
1037         float f1, f2, *c, diff[3];
1038         float color4f[6*4];
1039         rmeshstate_t m;
1040         R_Mesh_Matrix(&ent->matrix);
1041
1042         memset(&m, 0, sizeof(m));
1043         R_Mesh_State_Texture(&m);
1044
1045         if (ent->flags & EF_ADDITIVE)
1046         {
1047                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1048                 GL_DepthMask(false);
1049         }
1050         else if (ent->alpha < 1)
1051         {
1052                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1053                 GL_DepthMask(false);
1054         }
1055         else
1056         {
1057                 GL_BlendFunc(GL_ONE, GL_ZERO);
1058                 GL_DepthMask(true);
1059         }
1060         GL_DepthTest(true);
1061         GL_VertexPointer(nomodelvertex3f);
1062         if (fogenabled)
1063         {
1064                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1065                 GL_ColorPointer(color4f);
1066                 VectorSubtract(ent->origin, r_vieworigin, diff);
1067                 f2 = exp(fogdensity/DotProduct(diff, diff));
1068                 f1 = 1 - f2;
1069                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1070                 {
1071                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
1072                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
1073                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
1074                         c[3] *= ent->alpha;
1075                 }
1076         }
1077         else if (ent->alpha != 1)
1078         {
1079                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1080                 GL_ColorPointer(color4f);
1081                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1082                         c[3] *= ent->alpha;
1083         }
1084         else
1085                 GL_ColorPointer(nomodelcolor4f);
1086         R_Mesh_Draw(6, 8, nomodelelements);
1087 }
1088
1089 void R_DrawNoModel(entity_render_t *ent)
1090 {
1091         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1092                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1093         //else
1094         //      R_DrawNoModelCallback(ent, 0);
1095 }
1096
1097 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1098 {
1099         vec3_t right1, right2, diff, normal;
1100
1101         VectorSubtract (org2, org1, normal);
1102         VectorNormalizeFast (normal);
1103
1104         // calculate 'right' vector for start
1105         VectorSubtract (r_vieworigin, org1, diff);
1106         VectorNormalizeFast (diff);
1107         CrossProduct (normal, diff, right1);
1108
1109         // calculate 'right' vector for end
1110         VectorSubtract (r_vieworigin, org2, diff);
1111         VectorNormalizeFast (diff);
1112         CrossProduct (normal, diff, right2);
1113
1114         vert[ 0] = org1[0] + width * right1[0];
1115         vert[ 1] = org1[1] + width * right1[1];
1116         vert[ 2] = org1[2] + width * right1[2];
1117         vert[ 3] = org1[0] - width * right1[0];
1118         vert[ 4] = org1[1] - width * right1[1];
1119         vert[ 5] = org1[2] - width * right1[2];
1120         vert[ 6] = org2[0] - width * right2[0];
1121         vert[ 7] = org2[1] - width * right2[1];
1122         vert[ 8] = org2[2] - width * right2[2];
1123         vert[ 9] = org2[0] + width * right2[0];
1124         vert[10] = org2[1] + width * right2[1];
1125         vert[11] = org2[2] + width * right2[2];
1126 }
1127
1128 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1129
1130 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)
1131 {
1132         float diff[3];
1133         rmeshstate_t m;
1134
1135         if (fogenabled)
1136         {
1137                 VectorSubtract(origin, r_vieworigin, diff);
1138                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1139         }
1140
1141         R_Mesh_Matrix(&r_identitymatrix);
1142         GL_Color(cr, cg, cb, ca);
1143         GL_VertexPointer(varray_vertex3f);
1144         GL_BlendFunc(blendfunc1, blendfunc2);
1145         GL_DepthMask(false);
1146         GL_DepthTest(!depthdisable);
1147
1148         memset(&m, 0, sizeof(m));
1149         m.tex[0] = R_GetTexture(texture);
1150         m.pointer_texcoord[0] = spritetexcoord2f;
1151         R_Mesh_State_Texture(&m);
1152
1153         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1154         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1155         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1156         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1157         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1158         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1159         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1160         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1161         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1162         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1163         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1164         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1165         R_Mesh_Draw(4, 2, polygonelements);
1166 }
1167