now always uses glPolygonOffset, and collision brush rendering has been fixed with...
[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_SetupFog(void)
146 {
147         if (gamemode == GAME_NEHAHRA)
148         {
149                 if (gl_fogenable.integer)
150                 {
151                         oldgl_fogenable = true;
152                         fog_density = gl_fogdensity.value;
153                         fog_red = gl_fogred.value;
154                         fog_green = gl_foggreen.value;
155                         fog_blue = gl_fogblue.value;
156                 }
157                 else if (oldgl_fogenable)
158                 {
159                         oldgl_fogenable = false;
160                         fog_density = 0;
161                         fog_red = 0;
162                         fog_green = 0;
163                         fog_blue = 0;
164                 }
165         }
166         if (fog_density)
167         {
168                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
169                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
170                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
171         }
172         if (fog_density)
173         {
174                 fogenabled = true;
175                 fogdensity = -4000.0f / (fog_density * fog_density);
176                 // fog color was already set
177         }
178         else
179                 fogenabled = false;
180 }
181
182 // FIXME: move this to client?
183 void FOG_clear(void)
184 {
185         if (gamemode == GAME_NEHAHRA)
186         {
187                 Cvar_Set("gl_fogenable", "0");
188                 Cvar_Set("gl_fogdensity", "0.2");
189                 Cvar_Set("gl_fogred", "0.3");
190                 Cvar_Set("gl_foggreen", "0.3");
191                 Cvar_Set("gl_fogblue", "0.3");
192         }
193         fog_density = fog_red = fog_green = fog_blue = 0.0f;
194 }
195
196 // FIXME: move this to client?
197 void FOG_registercvars(void)
198 {
199         if (gamemode == GAME_NEHAHRA)
200         {
201                 Cvar_RegisterVariable (&gl_fogenable);
202                 Cvar_RegisterVariable (&gl_fogdensity);
203                 Cvar_RegisterVariable (&gl_fogred);
204                 Cvar_RegisterVariable (&gl_foggreen);
205                 Cvar_RegisterVariable (&gl_fogblue);
206                 Cvar_RegisterVariable (&gl_fogstart);
207                 Cvar_RegisterVariable (&gl_fogend);
208         }
209 }
210
211 void gl_main_start(void)
212 {
213 }
214
215 void gl_main_shutdown(void)
216 {
217 }
218
219 extern void CL_ParseEntityLump(char *entitystring);
220 void gl_main_newmap(void)
221 {
222         int l;
223         char *entities, entname[MAX_QPATH];
224         r_framecount = 1;
225         if (cl.worldmodel)
226         {
227                 strcpy(entname, cl.worldmodel->name);
228                 l = strlen(entname) - 4;
229                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
230                 {
231                         strcpy(entname + l, ".ent");
232                         if ((entities = FS_LoadFile(entname, true)))
233                         {
234                                 CL_ParseEntityLump(entities);
235                                 Mem_Free(entities);
236                                 return;
237                         }
238                 }
239                 if (cl.worldmodel->brush.entities)
240                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
241         }
242 }
243
244 void GL_Main_Init(void)
245 {
246         Matrix4x4_CreateIdentity(&r_identitymatrix);
247 // FIXME: move this to client?
248         FOG_registercvars();
249         Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
250         Cvar_RegisterVariable(&r_drawentities);
251         Cvar_RegisterVariable(&r_drawviewmodel);
252         Cvar_RegisterVariable(&r_shadow_staticworldlights);
253         Cvar_RegisterVariable(&r_speeds);
254         Cvar_RegisterVariable(&r_fullbrights);
255         Cvar_RegisterVariable(&r_wateralpha);
256         Cvar_RegisterVariable(&r_dynamic);
257         Cvar_RegisterVariable(&r_fullbright);
258         Cvar_RegisterVariable(&r_textureunits);
259         Cvar_RegisterVariable(&r_shadow_cull);
260         Cvar_RegisterVariable(&r_lerpsprites);
261         Cvar_RegisterVariable(&r_lerpmodels);
262         Cvar_RegisterVariable(&r_waterscroll);
263         Cvar_RegisterVariable(&r_watershader);
264         Cvar_RegisterVariable(&r_drawcollisionbrushes);
265         if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ)
266                 Cvar_SetValue("r_fullbrights", 0);
267         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
268 }
269
270 vec3_t r_farclip_origin;
271 vec3_t r_farclip_direction;
272 vec_t r_farclip_directiondist;
273 vec_t r_farclip_meshfarclip;
274 int r_farclip_directionbit0;
275 int r_farclip_directionbit1;
276 int r_farclip_directionbit2;
277
278 // start a farclip measuring session
279 void R_FarClip_Start(vec3_t origin, vec3_t direction, vec_t startfarclip)
280 {
281         VectorCopy(origin, r_farclip_origin);
282         VectorCopy(direction, r_farclip_direction);
283         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
284         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
285         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
286         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
287         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
288 }
289
290 // enlarge farclip to accomodate box
291 void R_FarClip_Box(vec3_t mins, vec3_t maxs)
292 {
293         float d;
294         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
295           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
296           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
297         if (r_farclip_meshfarclip < d)
298                 r_farclip_meshfarclip = d;
299 }
300
301 // return farclip value
302 float R_FarClip_Finish(void)
303 {
304         return r_farclip_meshfarclip - r_farclip_directiondist;
305 }
306
307 extern void R_Textures_Init(void);
308 extern void Mod_RenderInit(void);
309 extern void GL_Draw_Init(void);
310 extern void GL_Main_Init(void);
311 extern void R_Shadow_Init(void);
312 extern void GL_Models_Init(void);
313 extern void R_Sky_Init(void);
314 extern void GL_Surf_Init(void);
315 extern void R_Crosshairs_Init(void);
316 extern void R_Light_Init(void);
317 extern void R_Particles_Init(void);
318 extern void R_Explosion_Init(void);
319 extern void ui_init(void);
320 extern void gl_backend_init(void);
321 extern void Sbar_Init(void);
322 extern void R_LightningBeams_Init(void);
323
324 void Render_Init(void)
325 {
326         R_Textures_Init();
327         Mod_RenderInit();
328         gl_backend_init();
329         R_MeshQueue_Init();
330         GL_Draw_Init();
331         GL_Main_Init();
332         R_Shadow_Init();
333         GL_Models_Init();
334         R_Sky_Init();
335         GL_Surf_Init();
336         R_Crosshairs_Init();
337         R_Light_Init();
338         R_Particles_Init();
339         R_Explosion_Init();
340         //ui_init();
341         UI_Init();
342         Sbar_Init();
343         R_LightningBeams_Init();
344 }
345
346 /*
347 ===============
348 GL_Init
349 ===============
350 */
351 extern char *ENGINE_EXTENSIONS;
352 void GL_Init (void)
353 {
354         VID_CheckExtensions();
355
356         // LordHavoc: report supported extensions
357         Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
358 }
359
360 int R_CullBox(const vec3_t mins, const vec3_t maxs)
361 {
362         int i;
363         mplane_t *p;
364         for (i = 0;i < 4;i++)
365         {
366                 p = frustum + i;
367                 switch(p->signbits)
368                 {
369                 default:
370                 case 0:
371                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
372                                 return true;
373                         break;
374                 case 1:
375                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
376                                 return true;
377                         break;
378                 case 2:
379                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
380                                 return true;
381                         break;
382                 case 3:
383                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
384                                 return true;
385                         break;
386                 case 4:
387                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
388                                 return true;
389                         break;
390                 case 5:
391                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
392                                 return true;
393                         break;
394                 case 6:
395                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
396                                 return true;
397                         break;
398                 case 7:
399                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
400                                 return true;
401                         break;
402                 }
403         }
404         return false;
405 }
406
407 #define VIS_CullBox(mins,maxs) (R_CullBox((mins), (maxs)) || (cl.worldmodel && cl.worldmodel->brush.BoxTouchingPVS && !cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, r_pvsbits, (mins), (maxs))))
408
409 //==================================================================================
410
411 static void R_MarkEntities (void)
412 {
413         int i;
414         entity_render_t *ent;
415
416         ent = &cl_entities[0].render;
417         Matrix4x4_CreateIdentity(&ent->matrix);
418         Matrix4x4_CreateIdentity(&ent->inversematrix);
419
420         if (cl.worldmodel)
421                 R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
422
423         if (!r_drawentities.integer)
424                 return;
425
426         for (i = 0;i < r_refdef.numentities;i++)
427         {
428                 ent = r_refdef.entities[i];
429                 Mod_CheckLoaded(ent->model);
430                 // some of the renderer still relies on origin...
431                 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
432                 // some of the renderer still relies on scale...
433                 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
434                 R_LerpAnimation(ent);
435                 R_UpdateEntLights(ent);
436                 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
437                  && !VIS_CullBox(ent->mins, ent->maxs)
438                  && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
439                 {
440                         ent->visframe = r_framecount;
441                         R_FarClip_Box(ent->mins, ent->maxs);
442                 }
443         }
444 }
445
446 // only used if skyrendermasked, and normally returns false
447 int R_DrawBrushModelsSky (void)
448 {
449         int i, sky;
450         entity_render_t *ent;
451
452         if (!r_drawentities.integer)
453                 return false;
454
455         sky = false;
456         for (i = 0;i < r_refdef.numentities;i++)
457         {
458                 ent = r_refdef.entities[i];
459                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
460                 {
461                         ent->model->DrawSky(ent);
462                         sky = true;
463                 }
464         }
465         return sky;
466 }
467
468 /*
469 =============
470 R_DrawViewModel
471 =============
472 */
473 /*
474 void R_DrawViewModel (void)
475 {
476         entity_render_t *ent;
477
478         // FIXME: move these checks to client
479         if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
480                 return;
481
482         ent = &cl.viewent.render;
483         Mod_CheckLoaded(ent->model);
484         R_LerpAnimation(ent);
485         Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
486         Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
487         R_UpdateEntLights(ent);
488         ent->model->Draw(ent);
489 }
490 */
491
492 void R_DrawNoModel(entity_render_t *ent);
493 void R_DrawModels(void)
494 {
495         int i;
496         entity_render_t *ent;
497
498         if (!r_drawentities.integer)
499                 return;
500
501         for (i = 0;i < r_refdef.numentities;i++)
502         {
503                 ent = r_refdef.entities[i];
504                 if (ent->visframe == r_framecount)
505                 {
506                         if (ent->model && ent->model->Draw != NULL)
507                                 ent->model->Draw(ent);
508                         else
509                                 R_DrawNoModel(ent);
510                 }
511         }
512 }
513
514 #include "r_shadow.h"
515
516 int shadowframecount = 0;
517
518 void R_TestAndDrawShadowVolume(entity_render_t *ent, vec3_t lightorigin, float cullradius, float lightradius, vec3_t lightmins, vec3_t lightmaxs, vec3_t clipmins, vec3_t clipmaxs, int lightmarked)
519 {
520         vec3_t relativelightorigin;
521         // rough checks
522         if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawShadowVolume && !(r_shadow_cull.integer && (ent->maxs[0] < lightmins[0] || ent->mins[0] > lightmaxs[0] || ent->maxs[1] < lightmins[1] || ent->mins[1] > lightmaxs[1] || ent->maxs[2] < lightmins[2] || ent->mins[2] > lightmaxs[2])))
523         {
524                 Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
525                 ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
526         }
527 }
528
529 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
530
531 void R_ShadowVolumeLighting(int visiblevolumes)
532 {
533         int i;
534         entity_render_t *ent;
535         int lnum;
536         float f, lightradius, cullradius;
537         vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
538         worldlight_t *wl;
539         rdlight_t *rd;
540         rmeshstate_t m;
541         matrix4x4_t matrix;
542         matrix4x4_t matrix_worldtofilter, matrix_worldtoattenuationxyz, matrix_worldtoattenuationz;
543         matrix4x4_t matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
544
545         if (visiblevolumes)
546         {
547                 memset(&m, 0, sizeof(m));
548                 R_Mesh_State_Texture(&m);
549
550                 GL_BlendFunc(GL_ONE, GL_ONE);
551                 GL_DepthMask(false);
552                 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
553                 qglDisable(GL_CULL_FACE);
554                 GL_Color(0.0, 0.0125, 0.1, 1);
555         }
556         else
557                 R_Shadow_Stage_Begin();
558         shadowframecount++;
559         if (r_shadow_realtime_world.integer)
560         {
561                 R_Shadow_LoadWorldLightsIfNeeded();
562                 for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++)
563                 {
564                         if (d_lightstylevalue[wl->style] <= 0)
565                                 continue;
566                         if (VIS_CullBox(wl->mins, wl->maxs))
567                                 continue;
568                         if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
569                                 continue;
570                         if (R_Shadow_ScissorForBBox(wl->mins, wl->maxs))
571                                 continue;
572
573                         cullradius = wl->cullradius;
574                         lightradius = wl->lightradius;
575                         VectorCopy(wl->mins, clipmins);
576                         VectorCopy(wl->maxs, clipmaxs);
577
578                         f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
579                         VectorScale(wl->light, f, lightcolor);
580                         if (wl->selected)
581                         {
582                                 f = 2 + sin(realtime * M_PI * 4.0);
583                                 VectorScale(lightcolor, f, lightcolor);
584                         }
585
586                         if (wl->castshadows && (gl_stencil || visiblevolumes))
587                         {
588                                 if (!visiblevolumes)
589                                         R_Shadow_Stage_ShadowVolumes();
590                                 ent = &cl_entities[0].render;
591                                 if (r_shadow_staticworldlights.integer)
592                                         R_Shadow_DrawStaticWorldLight_Shadow(wl, &ent->matrix);
593                                 else
594                                         R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
595                                 if (r_drawentities.integer)
596                                         for (i = 0;i < r_refdef.numentities;i++)
597                                                 R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
598                         }
599
600                         if (!visiblevolumes)
601                         {
602                                 if (wl->castshadows && gl_stencil)
603                                         R_Shadow_Stage_LightWithShadows();
604                                 else
605                                         R_Shadow_Stage_LightWithoutShadows();
606
607                                 // calculate world to filter matrix
608                                 Matrix4x4_CreateFromQuakeEntity(&matrix, wl->origin[0], wl->origin[1], wl->origin[2], wl->angles[0], wl->angles[1], wl->angles[2], lightradius);
609                                 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
610                                 // calculate world to attenuationxyz/xy matrix
611                                 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
612                                 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
613                                 // calculate world to attenuationz matrix
614                                 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
615                                 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
616                                 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
617                                 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
618                                 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
619
620                                 ent = &cl_entities[0].render;
621                                 if (ent->model && ent->model->DrawLight)
622                                 {
623                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
624                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
625                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
626                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
627                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
628                                         if (r_shadow_staticworldlights.integer)
629                                                 R_Shadow_DrawStaticWorldLight_Light(wl, &ent->matrix, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
630                                         else
631                                                 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
632                                 }
633                                 if (r_drawentities.integer)
634                                 {
635                                         for (i = 0;i < r_refdef.numentities;i++)
636                                         {
637                                                 ent = r_refdef.entities[i];
638                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
639                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
640                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
641                                                 {
642                                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
643                                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
644                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
645                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
646                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
647                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
648                                                 }
649                                         }
650                                 }
651                         }
652                 }
653         }
654         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
655         {
656                 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
657                 {
658                         lightradius = rd->cullradius;
659                         clipmins[0] = rd->origin[0] - lightradius;
660                         clipmins[1] = rd->origin[1] - lightradius;
661                         clipmins[2] = rd->origin[2] - lightradius;
662                         clipmaxs[0] = rd->origin[0] + lightradius;
663                         clipmaxs[1] = rd->origin[1] + lightradius;
664                         clipmaxs[2] = rd->origin[2] + lightradius;
665                         if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
666                                 continue;
667
668                         cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
669                         VectorScale(rd->light, (1.0f / 4096.0f), lightcolor);
670
671                         if (r_shadow_shadows.integer && (gl_stencil || visiblevolumes))
672                         {
673                                 if (!visiblevolumes)
674                                         R_Shadow_Stage_ShadowVolumes();
675                                 ent = &cl_entities[0].render;
676                                 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
677                                 if (r_drawentities.integer)
678                                 {
679                                         for (i = 0;i < r_refdef.numentities;i++)
680                                         {
681                                                 ent = r_refdef.entities[i];
682                                                 if (ent != rd->ent)
683                                                         R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
684                                         }
685                                 }
686                         }
687
688                         if (!visiblevolumes)
689                         {
690                                 if (r_shadow_shadows.integer && gl_stencil)
691                                         R_Shadow_Stage_LightWithShadows();
692                                 else
693                                         R_Shadow_Stage_LightWithoutShadows();
694
695                                 // calculate world to filter matrix
696                                 Matrix4x4_CreateFromQuakeEntity(&matrix, rd->origin[0], rd->origin[1], rd->origin[2], 0, 0, 0, lightradius);
697                                 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
698                                 // calculate world to attenuationxyz/xy matrix
699                                 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
700                                 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
701                                 // calculate world to attenuationz matrix
702                                 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
703                                 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
704                                 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
705                                 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
706                                 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
707
708                                 ent = &cl_entities[0].render;
709                                 if (ent->model && ent->model->DrawLight)
710                                 {
711                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
712                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
713                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
714                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
715                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
716                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
717                                 }
718                                 if (r_drawentities.integer)
719                                 {
720                                         for (i = 0;i < r_refdef.numentities;i++)
721                                         {
722                                                 ent = r_refdef.entities[i];
723                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
724                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
725                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
726                                                 {
727                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
728                                                         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, relativeeyeorigin);
729                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
730                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
731                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
732                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
733                                                 }
734                                         }
735                                 }
736                         }
737                 }
738         }
739
740         if (visiblevolumes)
741                 qglEnable(GL_CULL_FACE);
742         else
743                 R_Shadow_Stage_End();
744         qglDisable(GL_SCISSOR_TEST);
745 }
746
747 static void R_SetFrustum (void)
748 {
749         // LordHavoc: note to all quake engine coders, the special case for 90
750         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
751         // disabled as well.
752
753         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
754         RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_refdef.fov_x / 2));
755         frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
756         PlaneClassify(&frustum[0]);
757
758         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
759         RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_refdef.fov_x / 2));
760         frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
761         PlaneClassify(&frustum[1]);
762
763         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
764         RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_refdef.fov_y / 2));
765         frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
766         PlaneClassify(&frustum[2]);
767
768         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
769         RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_refdef.fov_y / 2));
770         frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
771         PlaneClassify(&frustum[3]);
772 }
773
774 /*
775 ===============
776 R_SetupFrame
777 ===============
778 */
779 static void R_SetupFrame (void)
780 {
781 // don't allow cheats in multiplayer
782         if (!cl.islocalgame)
783         {
784                 if (r_fullbright.integer != 0)
785                         Cvar_Set ("r_fullbright", "0");
786                 if (r_ambient.value != 0)
787                         Cvar_Set ("r_ambient", "0");
788         }
789
790         r_framecount++;
791
792         // break apart the viewentity matrix into vectors for various purposes
793         Matrix4x4_ToVectors(&r_refdef.viewentitymatrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
794         VectorNegate(r_viewleft, r_viewright);
795
796         GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
797         if ((r_shadow_realtime_world.integer || r_shadow_shadows.integer) && gl_stencil)
798                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
799         else
800                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
801         GL_SetupView_Orientation_FromEntity(&r_refdef.viewentitymatrix);
802
803         R_AnimateLight();
804 }
805
806
807 static void R_BlendView(void)
808 {
809         rmeshstate_t m;
810         float r;
811         float vertex3f[3*3];
812
813         if (r_refdef.viewblend[3] < 0.01f)
814                 return;
815
816         R_Mesh_Matrix(&r_identitymatrix);
817
818         memset(&m, 0, sizeof(m));
819         R_Mesh_State_Texture(&m);
820
821         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
822         GL_DepthMask(true);
823         GL_DepthTest(false); // magic
824         GL_VertexPointer(vertex3f);
825         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
826         r = 64000;
827         vertex3f[0] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r - r_viewup[0] * r;
828         vertex3f[1] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r - r_viewup[1] * r;
829         vertex3f[2] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r - r_viewup[2] * r;
830         vertex3f[3] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r + r_viewup[0] * r * 3;
831         vertex3f[4] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r + r_viewup[1] * r * 3;
832         vertex3f[5] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r + r_viewup[2] * r * 3;
833         vertex3f[6] = r_vieworigin[0] + r_viewforward[0] * 1.5 - r_viewleft[0] * r * 3 - r_viewup[0] * r;
834         vertex3f[7] = r_vieworigin[1] + r_viewforward[1] * 1.5 - r_viewleft[1] * r * 3 - r_viewup[1] * r;
835         vertex3f[8] = r_vieworigin[2] + r_viewforward[2] * 1.5 - r_viewleft[2] * r * 3 - r_viewup[2] * r;
836         R_Mesh_Draw(3, 1, polygonelements);
837 }
838
839 /*
840 ================
841 R_RenderView
842
843 r_refdef must be set before the first call
844 ================
845 */
846 extern void R_DrawLightningBeams (void);
847 void R_RenderView (void)
848 {
849         entity_render_t *world;
850         if (!r_refdef.entities/* || !cl.worldmodel*/)
851                 return; //Host_Error ("R_RenderView: NULL worldmodel");
852
853         if (r_shadow_realtime_world.integer)
854         {
855                 if (!gl_stencil)
856                 {
857                         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");
858                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
859                 }
860         }
861
862         world = &cl_entities[0].render;
863
864         // FIXME: move to client
865         R_MoveExplosions();
866         R_TimeReport("mexplosion");
867
868         qglPolygonOffset(0, 0);
869         qglEnable(GL_POLYGON_OFFSET_FILL);
870
871         R_Textures_Frame();
872         R_SetupFrame();
873         R_SetFrustum();
874         R_SetupFog();
875         R_SkyStartFrame();
876         R_BuildLightList();
877         R_TimeReport("setup");
878
879         if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
880                 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
881
882         R_WorldVisibility(world);
883         R_TimeReport("worldvis");
884
885         R_FarClip_Start(r_vieworigin, r_viewforward, 768.0f);
886         R_MarkEntities();
887         r_farclip = R_FarClip_Finish() + 256.0f;
888         R_TimeReport("markentity");
889
890         qglDepthFunc(GL_LEQUAL);
891
892         R_Mesh_Start();
893         R_MeshQueue_BeginScene();
894
895         R_Shadow_UpdateWorldLightSelection();
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         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
912         {
913                 R_ShadowVolumeLighting(false);
914                 R_TimeReport("dynlight");
915         }
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_BlendView();
936         R_TimeReport("blendview");
937
938         R_MeshQueue_Render();
939         R_MeshQueue_EndScene();
940
941         if (r_shadow_visiblevolumes.integer)
942         {
943                 R_ShadowVolumeLighting(true);
944                 R_TimeReport("shadowvolume");
945         }
946
947         R_Mesh_Finish();
948         R_TimeReport("meshfinish");
949
950         qglPolygonOffset(0, 0);
951         qglDisable(GL_POLYGON_OFFSET_FILL);
952 }
953
954 /*
955 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
956 {
957         int i;
958         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
959         rmeshstate_t m;
960         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
961         GL_DepthMask(false);
962         GL_DepthTest(true);
963         R_Mesh_Matrix(&r_identitymatrix);
964
965         memset(&m, 0, sizeof(m));
966         R_Mesh_State_Texture(&m);
967
968         R_Mesh_GetSpace(8);
969         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
970         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
971         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
972         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
973         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
974         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
975         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
976         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
977         GL_ColorPointer(color);
978         R_FillColors(color, 8, cr, cg, cb, ca);
979         if (fogenabled)
980         {
981                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
982                 {
983                         VectorSubtract(v, r_vieworigin, diff);
984                         f2 = exp(fogdensity/DotProduct(diff, diff));
985                         f1 = 1 - f2;
986                         c[0] = c[0] * f1 + fogcolor[0] * f2;
987                         c[1] = c[1] * f1 + fogcolor[1] * f2;
988                         c[2] = c[2] * f1 + fogcolor[2] * f2;
989                 }
990         }
991         R_Mesh_Draw(8, 12);
992 }
993 */
994
995 int nomodelelements[24] =
996 {
997         5, 2, 0,
998         5, 1, 2,
999         5, 0, 3,
1000         5, 3, 1,
1001         0, 2, 4,
1002         2, 1, 4,
1003         3, 0, 4,
1004         1, 3, 4
1005 };
1006
1007 float nomodelvertex3f[6*3] =
1008 {
1009         -16,   0,   0,
1010          16,   0,   0,
1011           0, -16,   0,
1012           0,  16,   0,
1013           0,   0, -16,
1014           0,   0,  16
1015 };
1016
1017 float nomodelcolor4f[6*4] =
1018 {
1019         0.0f, 0.0f, 0.5f, 1.0f,
1020         0.0f, 0.0f, 0.5f, 1.0f,
1021         0.0f, 0.5f, 0.0f, 1.0f,
1022         0.0f, 0.5f, 0.0f, 1.0f,
1023         0.5f, 0.0f, 0.0f, 1.0f,
1024         0.5f, 0.0f, 0.0f, 1.0f
1025 };
1026
1027 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1028 {
1029         const entity_render_t *ent = calldata1;
1030         int i;
1031         float f1, f2, *c, diff[3];
1032         float color4f[6*4];
1033         rmeshstate_t m;
1034         R_Mesh_Matrix(&ent->matrix);
1035
1036         memset(&m, 0, sizeof(m));
1037         R_Mesh_State_Texture(&m);
1038
1039         if (ent->flags & EF_ADDITIVE)
1040         {
1041                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1042                 GL_DepthMask(false);
1043         }
1044         else if (ent->alpha < 1)
1045         {
1046                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1047                 GL_DepthMask(false);
1048         }
1049         else
1050         {
1051                 GL_BlendFunc(GL_ONE, GL_ZERO);
1052                 GL_DepthMask(true);
1053         }
1054         GL_DepthTest(true);
1055         GL_VertexPointer(nomodelvertex3f);
1056         if (fogenabled)
1057         {
1058                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1059                 GL_ColorPointer(color4f);
1060                 VectorSubtract(ent->origin, r_vieworigin, diff);
1061                 f2 = exp(fogdensity/DotProduct(diff, diff));
1062                 f1 = 1 - f2;
1063                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1064                 {
1065                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
1066                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
1067                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
1068                         c[3] *= ent->alpha;
1069                 }
1070         }
1071         else if (ent->alpha != 1)
1072         {
1073                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1074                 GL_ColorPointer(color4f);
1075                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1076                         c[3] *= ent->alpha;
1077         }
1078         else
1079                 GL_ColorPointer(nomodelcolor4f);
1080         R_Mesh_Draw(6, 8, nomodelelements);
1081 }
1082
1083 void R_DrawNoModel(entity_render_t *ent)
1084 {
1085         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1086                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1087         //else
1088         //      R_DrawNoModelCallback(ent, 0);
1089 }
1090
1091 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1092 {
1093         vec3_t right1, right2, diff, normal;
1094
1095         VectorSubtract (org2, org1, normal);
1096         VectorNormalizeFast (normal);
1097
1098         // calculate 'right' vector for start
1099         VectorSubtract (r_vieworigin, org1, diff);
1100         VectorNormalizeFast (diff);
1101         CrossProduct (normal, diff, right1);
1102
1103         // calculate 'right' vector for end
1104         VectorSubtract (r_vieworigin, org2, diff);
1105         VectorNormalizeFast (diff);
1106         CrossProduct (normal, diff, right2);
1107
1108         vert[ 0] = org1[0] + width * right1[0];
1109         vert[ 1] = org1[1] + width * right1[1];
1110         vert[ 2] = org1[2] + width * right1[2];
1111         vert[ 3] = org1[0] - width * right1[0];
1112         vert[ 4] = org1[1] - width * right1[1];
1113         vert[ 5] = org1[2] - width * right1[2];
1114         vert[ 6] = org2[0] - width * right2[0];
1115         vert[ 7] = org2[1] - width * right2[1];
1116         vert[ 8] = org2[2] - width * right2[2];
1117         vert[ 9] = org2[0] + width * right2[0];
1118         vert[10] = org2[1] + width * right2[1];
1119         vert[11] = org2[2] + width * right2[2];
1120 }
1121
1122 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1123
1124 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)
1125 {
1126         float diff[3];
1127         rmeshstate_t m;
1128
1129         if (fogenabled)
1130         {
1131                 VectorSubtract(origin, r_vieworigin, diff);
1132                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1133         }
1134
1135         R_Mesh_Matrix(&r_identitymatrix);
1136         GL_Color(cr, cg, cb, ca);
1137         GL_VertexPointer(varray_vertex3f);
1138         GL_BlendFunc(blendfunc1, blendfunc2);
1139         GL_DepthMask(false);
1140         GL_DepthTest(!depthdisable);
1141
1142         memset(&m, 0, sizeof(m));
1143         m.tex[0] = R_GetTexture(texture);
1144         m.pointer_texcoord[0] = spritetexcoord2f;
1145         R_Mesh_State_Texture(&m);
1146
1147         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1148         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1149         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1150         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1151         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1152         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1153         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1154         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1155         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1156         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1157         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1158         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1159         R_Mesh_Draw(4, 2, polygonelements);
1160 }
1161