fef43b34fcfb7e1053f04a49844ae515cd67ce4d
[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 (VIS_CullBox(wl->mins, wl->maxs))
563                                 continue;
564                         if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
565                                 continue;
566                         if (R_Shadow_ScissorForBBox(wl->mins, wl->maxs))
567                                 continue;
568
569                         cullradius = wl->cullradius;
570                         lightradius = wl->radius;
571                         VectorCopy(wl->mins, clipmins);
572                         VectorCopy(wl->maxs, clipmaxs);
573
574                         f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
575                         VectorScale(wl->color, f, lightcolor);
576                         if (wl->selected)
577                         {
578                                 f = 2 + sin(realtime * M_PI * 4.0);
579                                 VectorScale(lightcolor, f, lightcolor);
580                         }
581
582                         if (r_shadow_worldshadows.integer && wl->drawshadows && (gl_stencil || visiblevolumes))
583                         {
584                                 if (!visiblevolumes)
585                                         R_Shadow_Stage_ShadowVolumes();
586                                 ent = &cl_entities[0].render;
587                                 if (r_shadow_staticworldlights.integer)
588                                         R_Shadow_DrawStaticWorldLight_Shadow(wl, &ent->matrix);
589                                 else
590                                         R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
591                                 if (r_drawentities.integer)
592                                         for (i = 0;i < r_refdef.numentities;i++)
593                                                 R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
594                         }
595
596                         if (!visiblevolumes)
597                         {
598                                 if (r_shadow_worldshadows.integer && wl->drawshadows && gl_stencil)
599                                         R_Shadow_Stage_LightWithShadows();
600                                 else
601                                         R_Shadow_Stage_LightWithoutShadows();
602
603                                 ent = &cl_entities[0].render;
604                                 if (ent->model && ent->model->DrawLight)
605                                 {
606                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
607                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
608                                         Matrix4x4_Concat(&matrix_modeltolight, &wl->matrix_worldtolight, &ent->matrix);
609                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &wl->matrix_worldtoattenuationxyz, &ent->matrix);
610                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &wl->matrix_worldtoattenuationz, &ent->matrix);
611                                         if (r_shadow_staticworldlights.integer)
612                                                 R_Shadow_DrawStaticWorldLight_Light(wl, &ent->matrix, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
613                                         else
614                                                 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, wl->cubemap);
615                                 }
616                                 if (r_drawentities.integer)
617                                 {
618                                         for (i = 0;i < r_refdef.numentities;i++)
619                                         {
620                                                 ent = r_refdef.entities[i];
621                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
622                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
623                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
624                                                 {
625                                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
626                                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
627                                                         Matrix4x4_Concat(&matrix_modeltolight, &wl->matrix_worldtolight, &ent->matrix);
628                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &wl->matrix_worldtoattenuationxyz, &ent->matrix);
629                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &wl->matrix_worldtoattenuationz, &ent->matrix);
630                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, wl->cubemap);
631                                                 }
632                                         }
633                                 }
634                         }
635                 }
636         }
637         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
638         {
639                 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
640                 {
641                         lightradius = rd->radius;
642                         clipmins[0] = rd->origin[0] - lightradius;
643                         clipmins[1] = rd->origin[1] - lightradius;
644                         clipmins[2] = rd->origin[2] - lightradius;
645                         clipmaxs[0] = rd->origin[0] + lightradius;
646                         clipmaxs[1] = rd->origin[1] + lightradius;
647                         clipmaxs[2] = rd->origin[2] + lightradius;
648                         if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
649                                 continue;
650
651                         cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
652                         VectorCopy(rd->color, lightcolor);
653
654                         if (rd->cubemapnum > 0)
655                                 cubemaptexture = R_Shadow_Cubemap(va("cubemaps/%i", rd->cubemapnum));
656                         else
657                                 cubemaptexture = NULL;
658
659                         if (r_shadow_dlightshadows.integer && rd->shadow && (gl_stencil || visiblevolumes))
660                         {
661                                 if (!visiblevolumes)
662                                         R_Shadow_Stage_ShadowVolumes();
663                                 ent = &cl_entities[0].render;
664                                 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
665                                 if (r_drawentities.integer)
666                                 {
667                                         for (i = 0;i < r_refdef.numentities;i++)
668                                         {
669                                                 ent = r_refdef.entities[i];
670                                                 if (ent != rd->ent)
671                                                         R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
672                                         }
673                                 }
674                         }
675
676                         if (!visiblevolumes)
677                         {
678                                 if (r_shadow_dlightshadows.integer && gl_stencil && rd->shadow)
679                                         R_Shadow_Stage_LightWithShadows();
680                                 else
681                                         R_Shadow_Stage_LightWithoutShadows();
682
683                                 ent = &cl_entities[0].render;
684                                 if (ent->model && ent->model->DrawLight)
685                                 {
686                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
687                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
688                                         Matrix4x4_Concat(&matrix_modeltolight, &rd->matrix_worldtolight, &ent->matrix);
689                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rd->matrix_worldtoattenuationxyz, &ent->matrix);
690                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rd->matrix_worldtoattenuationz, &ent->matrix);
691                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
692                                 }
693                                 if (r_drawentities.integer)
694                                 {
695                                         for (i = 0;i < r_refdef.numentities;i++)
696                                         {
697                                                 ent = r_refdef.entities[i];
698                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
699                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
700                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
701                                                 {
702                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
703                                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
704                                                         Matrix4x4_Concat(&matrix_modeltolight, &rd->matrix_worldtolight, &ent->matrix);
705                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &rd->matrix_worldtoattenuationxyz, &ent->matrix);
706                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &rd->matrix_worldtoattenuationz, &ent->matrix);
707                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltolight, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz, cubemaptexture);
708                                                 }
709                                         }
710                                 }
711                         }
712                 }
713         }
714
715         if (visiblevolumes)
716         {
717                 qglEnable(GL_CULL_FACE);
718                 GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
719         }
720         else
721                 R_Shadow_Stage_End();
722 }
723
724 static void R_SetFrustum(void)
725 {
726         // break apart the viewentity matrix into vectors for various purposes
727         Matrix4x4_ToVectors(&r_refdef.viewentitymatrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
728         VectorNegate(r_viewleft, r_viewright);
729
730         // LordHavoc: note to all quake engine coders, the special case for 90
731         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
732         // disabled as well.
733
734         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
735         RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_refdef.fov_x / 2));
736         frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
737         PlaneClassify(&frustum[0]);
738
739         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
740         RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_refdef.fov_x / 2));
741         frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
742         PlaneClassify(&frustum[1]);
743
744         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
745         RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_refdef.fov_y / 2));
746         frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
747         PlaneClassify(&frustum[2]);
748
749         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
750         RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_refdef.fov_y / 2));
751         frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
752         PlaneClassify(&frustum[3]);
753 }
754
755 static void R_BlendView(void)
756 {
757         rmeshstate_t m;
758         float r;
759         float vertex3f[3*3];
760
761         if (r_refdef.viewblend[3] < 0.01f)
762                 return;
763
764         R_Mesh_Matrix(&r_identitymatrix);
765
766         memset(&m, 0, sizeof(m));
767         R_Mesh_State_Texture(&m);
768
769         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
770         GL_DepthMask(true);
771         GL_DepthTest(false); // magic
772         GL_VertexPointer(vertex3f);
773         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
774         r = 64;
775         vertex3f[0] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r - r_viewup[0] * r;
776         vertex3f[1] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r - r_viewup[1] * r;
777         vertex3f[2] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r - r_viewup[2] * r;
778         vertex3f[3] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r + r_viewup[0] * r * 3;
779         vertex3f[4] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r + r_viewup[1] * r * 3;
780         vertex3f[5] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r + r_viewup[2] * r * 3;
781         vertex3f[6] = r_vieworigin[0] + r_viewforward[0] * 1.5 - r_viewleft[0] * r * 3 - r_viewup[0] * r;
782         vertex3f[7] = r_vieworigin[1] + r_viewforward[1] * 1.5 - r_viewleft[1] * r * 3 - r_viewup[1] * r;
783         vertex3f[8] = r_vieworigin[2] + r_viewforward[2] * 1.5 - r_viewleft[2] * r * 3 - r_viewup[2] * r;
784         R_Mesh_Draw(3, 1, polygonelements);
785 }
786
787 void R_UpdateWorld(void)
788 {
789         if (!r_refdef.entities/* || !cl.worldmodel*/)
790                 return; //Host_Error ("R_RenderView: NULL worldmodel");
791
792         if (r_shadow_realtime_world.integer && !gl_stencil)
793         {
794                 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");
795                 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
796         }
797
798         // don't allow cheats in multiplayer
799         if (!cl.islocalgame)
800         {
801                 if (r_fullbright.integer != 0)
802                         Cvar_Set ("r_fullbright", "0");
803                 if (r_ambient.value != 0)
804                         Cvar_Set ("r_ambient", "0");
805         }
806
807         R_Textures_Frame();
808         R_UpdateFog();
809         R_UpdateLights();
810 }
811
812 void R_RenderScene(void);
813
814 /*
815 ================
816 R_RenderView
817 ================
818 */
819 void R_RenderView(void)
820 {
821         if (!r_refdef.entities/* || !cl.worldmodel*/)
822                 return; //Host_Error ("R_RenderView: NULL worldmodel");
823         
824         r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
825         r_refdef.height = bound(0, r_refdef.height, vid.realheight);
826         r_refdef.x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
827         r_refdef.y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
828         r_refdef.fov_x = bound(1, r_refdef.fov_x, 170);
829         r_refdef.fov_y = bound(1, r_refdef.fov_y, 170);
830
831         // GL is weird because it's bottom to top, r_refdef.y is top to bottom
832         qglViewport(r_refdef.x, vid.realheight - (r_refdef.y + r_refdef.height), r_refdef.width, r_refdef.height);
833         GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
834         GL_ScissorTest(true);
835         R_ClearScreen();
836
837         R_SetFrustum();
838         r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
839
840         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)))
841                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
842         else
843                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
844
845         GL_SetupView_Orientation_FromEntity(&r_refdef.viewentitymatrix);
846         R_TimeReport("setup");
847
848         R_RenderScene();
849
850         R_BlendView();
851         R_TimeReport("blendview");
852         
853         GL_Scissor(0, 0, vid.realwidth, vid.realheight);
854         GL_ScissorTest(false);
855 }
856
857 extern void R_DrawLightningBeams (void);
858 void R_RenderScene(void)
859 {
860         entity_render_t *world;
861
862         // don't let sound skip if going slow
863         if (!intimerefresh && !r_speeds.integer)
864                 S_ExtraUpdate ();
865
866         r_framecount++;
867
868         R_SkyStartFrame();
869
870         if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
871                 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
872         world = &cl_entities[0].render;
873         R_WorldVisibility(world);
874         R_TimeReport("worldvis");
875
876         R_MarkEntities();
877         R_TimeReport("markentity");
878
879         qglDepthFunc(GL_LEQUAL);
880         qglPolygonOffset(0, 0);
881         qglEnable(GL_POLYGON_OFFSET_FILL);
882
883         R_Mesh_Start();
884         R_MeshQueue_BeginScene();
885
886         R_Shadow_UpdateWorldLightSelection();
887
888         // don't let sound skip if going slow
889         if (!intimerefresh && !r_speeds.integer)
890                 S_ExtraUpdate ();
891
892         if (R_DrawBrushModelsSky())
893                 R_TimeReport("bmodelsky");
894
895         // must occur early because it can draw sky
896         R_DrawWorld(world);
897         R_TimeReport("world");
898
899         // don't let sound skip if going slow
900         if (!intimerefresh && !r_speeds.integer)
901                 S_ExtraUpdate ();
902
903         R_DrawModels();
904         R_TimeReport("models");
905
906         // don't let sound skip if going slow
907         if (!intimerefresh && !r_speeds.integer)
908                 S_ExtraUpdate ();
909
910         R_ShadowVolumeLighting(false);
911         R_TimeReport("rtlights");
912
913         // don't let sound skip if going slow
914         if (!intimerefresh && !r_speeds.integer)
915                 S_ExtraUpdate ();
916
917         R_DrawLightningBeams();
918         R_TimeReport("lightning");
919
920         R_DrawParticles();
921         R_TimeReport("particles");
922
923         R_DrawExplosions();
924         R_TimeReport("explosions");
925
926         R_MeshQueue_RenderTransparent();
927         R_TimeReport("drawtrans");
928
929         R_DrawCoronas();
930         R_TimeReport("coronas");
931
932         R_DrawWorldCrosshair();
933         R_TimeReport("crosshair");
934
935         R_MeshQueue_Render();
936         R_MeshQueue_EndScene();
937
938         if (r_shadow_visiblevolumes.integer)
939         {
940                 R_ShadowVolumeLighting(true);
941                 R_TimeReport("shadowvolume");
942         }
943
944         R_Mesh_Finish();
945         R_TimeReport("meshfinish");
946
947         qglPolygonOffset(0, 0);
948         qglDisable(GL_POLYGON_OFFSET_FILL);
949
950         // don't let sound skip if going slow
951         if (!intimerefresh && !r_speeds.integer)
952                 S_ExtraUpdate ();
953 }
954
955 /*
956 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
957 {
958         int i;
959         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
960         rmeshstate_t m;
961         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
962         GL_DepthMask(false);
963         GL_DepthTest(true);
964         R_Mesh_Matrix(&r_identitymatrix);
965
966         memset(&m, 0, sizeof(m));
967         R_Mesh_State_Texture(&m);
968
969         R_Mesh_GetSpace(8);
970         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
971         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
972         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
973         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
974         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
975         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
976         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
977         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
978         GL_ColorPointer(color);
979         R_FillColors(color, 8, cr, cg, cb, ca);
980         if (fogenabled)
981         {
982                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
983                 {
984                         VectorSubtract(v, r_vieworigin, diff);
985                         f2 = exp(fogdensity/DotProduct(diff, diff));
986                         f1 = 1 - f2;
987                         c[0] = c[0] * f1 + fogcolor[0] * f2;
988                         c[1] = c[1] * f1 + fogcolor[1] * f2;
989                         c[2] = c[2] * f1 + fogcolor[2] * f2;
990                 }
991         }
992         R_Mesh_Draw(8, 12);
993 }
994 */
995
996 int nomodelelements[24] =
997 {
998         5, 2, 0,
999         5, 1, 2,
1000         5, 0, 3,
1001         5, 3, 1,
1002         0, 2, 4,
1003         2, 1, 4,
1004         3, 0, 4,
1005         1, 3, 4
1006 };
1007
1008 float nomodelvertex3f[6*3] =
1009 {
1010         -16,   0,   0,
1011          16,   0,   0,
1012           0, -16,   0,
1013           0,  16,   0,
1014           0,   0, -16,
1015           0,   0,  16
1016 };
1017
1018 float nomodelcolor4f[6*4] =
1019 {
1020         0.0f, 0.0f, 0.5f, 1.0f,
1021         0.0f, 0.0f, 0.5f, 1.0f,
1022         0.0f, 0.5f, 0.0f, 1.0f,
1023         0.0f, 0.5f, 0.0f, 1.0f,
1024         0.5f, 0.0f, 0.0f, 1.0f,
1025         0.5f, 0.0f, 0.0f, 1.0f
1026 };
1027
1028 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1029 {
1030         const entity_render_t *ent = calldata1;
1031         int i;
1032         float f1, f2, *c, diff[3];
1033         float color4f[6*4];
1034         rmeshstate_t m;
1035         R_Mesh_Matrix(&ent->matrix);
1036
1037         memset(&m, 0, sizeof(m));
1038         R_Mesh_State_Texture(&m);
1039
1040         if (ent->flags & EF_ADDITIVE)
1041         {
1042                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1043                 GL_DepthMask(false);
1044         }
1045         else if (ent->alpha < 1)
1046         {
1047                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1048                 GL_DepthMask(false);
1049         }
1050         else
1051         {
1052                 GL_BlendFunc(GL_ONE, GL_ZERO);
1053                 GL_DepthMask(true);
1054         }
1055         GL_DepthTest(true);
1056         GL_VertexPointer(nomodelvertex3f);
1057         if (fogenabled)
1058         {
1059                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1060                 GL_ColorPointer(color4f);
1061                 VectorSubtract(ent->origin, r_vieworigin, diff);
1062                 f2 = exp(fogdensity/DotProduct(diff, diff));
1063                 f1 = 1 - f2;
1064                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1065                 {
1066                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
1067                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
1068                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
1069                         c[3] *= ent->alpha;
1070                 }
1071         }
1072         else if (ent->alpha != 1)
1073         {
1074                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1075                 GL_ColorPointer(color4f);
1076                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1077                         c[3] *= ent->alpha;
1078         }
1079         else
1080                 GL_ColorPointer(nomodelcolor4f);
1081         R_Mesh_Draw(6, 8, nomodelelements);
1082 }
1083
1084 void R_DrawNoModel(entity_render_t *ent)
1085 {
1086         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1087                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1088         //else
1089         //      R_DrawNoModelCallback(ent, 0);
1090 }
1091
1092 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1093 {
1094         vec3_t right1, right2, diff, normal;
1095
1096         VectorSubtract (org2, org1, normal);
1097         VectorNormalizeFast (normal);
1098
1099         // calculate 'right' vector for start
1100         VectorSubtract (r_vieworigin, org1, diff);
1101         VectorNormalizeFast (diff);
1102         CrossProduct (normal, diff, right1);
1103
1104         // calculate 'right' vector for end
1105         VectorSubtract (r_vieworigin, org2, diff);
1106         VectorNormalizeFast (diff);
1107         CrossProduct (normal, diff, right2);
1108
1109         vert[ 0] = org1[0] + width * right1[0];
1110         vert[ 1] = org1[1] + width * right1[1];
1111         vert[ 2] = org1[2] + width * right1[2];
1112         vert[ 3] = org1[0] - width * right1[0];
1113         vert[ 4] = org1[1] - width * right1[1];
1114         vert[ 5] = org1[2] - width * right1[2];
1115         vert[ 6] = org2[0] - width * right2[0];
1116         vert[ 7] = org2[1] - width * right2[1];
1117         vert[ 8] = org2[2] - width * right2[2];
1118         vert[ 9] = org2[0] + width * right2[0];
1119         vert[10] = org2[1] + width * right2[1];
1120         vert[11] = org2[2] + width * right2[2];
1121 }
1122
1123 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1124
1125 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)
1126 {
1127         float diff[3];
1128         rmeshstate_t m;
1129
1130         if (fogenabled)
1131         {
1132                 VectorSubtract(origin, r_vieworigin, diff);
1133                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1134         }
1135
1136         R_Mesh_Matrix(&r_identitymatrix);
1137         GL_Color(cr, cg, cb, ca);
1138         GL_VertexPointer(varray_vertex3f);
1139         GL_BlendFunc(blendfunc1, blendfunc2);
1140         GL_DepthMask(false);
1141         GL_DepthTest(!depthdisable);
1142
1143         memset(&m, 0, sizeof(m));
1144         m.tex[0] = R_GetTexture(texture);
1145         m.pointer_texcoord[0] = spritetexcoord2f;
1146         R_Mesh_State_Texture(&m);
1147
1148         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1149         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1150         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1151         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1152         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1153         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1154         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1155         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1156         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1157         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1158         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1159         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1160         R_Mesh_Draw(4, 2, polygonelements);
1161 }
1162