more q3bsp work (and no it still doesn't work right)
[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_origin;
43 vec3_t vpn;
44 vec3_t vright;
45 vec3_t vup;
46
47 //
48 // screen size info
49 //
50 refdef_t r_refdef;
51
52 // 8.8 fraction of base light value
53 unsigned short d_lightstylevalue[256];
54
55 cvar_t r_drawentities = {0, "r_drawentities","1"};
56 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
57 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0"};
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
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 start, stop, time;
122
123         intimerefresh = 1;
124         start = Sys_DoubleTime ();
125         for (i = 0;i < 128;i++)
126         {
127                 r_refdef.viewangles[0] = 0;
128                 r_refdef.viewangles[1] = i/128.0*360.0;
129                 r_refdef.viewangles[2] = 0;
130                 CL_UpdateScreen();
131         }
132
133         stop = Sys_DoubleTime ();
134         intimerefresh = 0;
135         time = stop-start;
136         Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
137 }
138
139 vec3_t fogcolor;
140 vec_t fogdensity;
141 float fog_density, fog_red, fog_green, fog_blue;
142 qboolean fogenabled;
143 qboolean oldgl_fogenable;
144 void R_SetupFog(void)
145 {
146         if (gamemode == GAME_NEHAHRA)
147         {
148                 if (gl_fogenable.integer)
149                 {
150                         oldgl_fogenable = true;
151                         fog_density = gl_fogdensity.value;
152                         fog_red = gl_fogred.value;
153                         fog_green = gl_foggreen.value;
154                         fog_blue = gl_fogblue.value;
155                 }
156                 else if (oldgl_fogenable)
157                 {
158                         oldgl_fogenable = false;
159                         fog_density = 0;
160                         fog_red = 0;
161                         fog_green = 0;
162                         fog_blue = 0;
163                 }
164         }
165         if (fog_density)
166         {
167                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
168                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
169                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
170         }
171         if (fog_density)
172         {
173                 fogenabled = true;
174                 fogdensity = -4000.0f / (fog_density * fog_density);
175                 // fog color was already set
176         }
177         else
178                 fogenabled = false;
179 }
180
181 // FIXME: move this to client?
182 void FOG_clear(void)
183 {
184         if (gamemode == GAME_NEHAHRA)
185         {
186                 Cvar_Set("gl_fogenable", "0");
187                 Cvar_Set("gl_fogdensity", "0.2");
188                 Cvar_Set("gl_fogred", "0.3");
189                 Cvar_Set("gl_foggreen", "0.3");
190                 Cvar_Set("gl_fogblue", "0.3");
191         }
192         fog_density = fog_red = fog_green = fog_blue = 0.0f;
193 }
194
195 // FIXME: move this to client?
196 void FOG_registercvars(void)
197 {
198         if (gamemode == GAME_NEHAHRA)
199         {
200                 Cvar_RegisterVariable (&gl_fogenable);
201                 Cvar_RegisterVariable (&gl_fogdensity);
202                 Cvar_RegisterVariable (&gl_fogred);
203                 Cvar_RegisterVariable (&gl_foggreen);
204                 Cvar_RegisterVariable (&gl_fogblue);
205                 Cvar_RegisterVariable (&gl_fogstart);
206                 Cvar_RegisterVariable (&gl_fogend);
207         }
208 }
209
210 void gl_main_start(void)
211 {
212 }
213
214 void gl_main_shutdown(void)
215 {
216 }
217
218 extern void CL_ParseEntityLump(char *entitystring);
219 void gl_main_newmap(void)
220 {
221         int l;
222         char *entities, entname[MAX_QPATH];
223         r_framecount = 1;
224         if (cl.worldmodel)
225         {
226                 strcpy(entname, cl.worldmodel->name);
227                 l = strlen(entname) - 4;
228                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
229                 {
230                         strcpy(entname + l, ".ent");
231                         if ((entities = FS_LoadFile(entname, true)))
232                         {
233                                 CL_ParseEntityLump(entities);
234                                 Mem_Free(entities);
235                                 return;
236                         }
237                 }
238                 if (cl.worldmodel->brush.entities)
239                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
240         }
241 }
242
243 void GL_Main_Init(void)
244 {
245         Matrix4x4_CreateIdentity(&r_identitymatrix);
246 // FIXME: move this to client?
247         FOG_registercvars();
248         Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
249         Cvar_RegisterVariable(&r_drawentities);
250         Cvar_RegisterVariable(&r_drawviewmodel);
251         Cvar_RegisterVariable(&r_shadows);
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_drawcollisionbrushes);
264         if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ)
265                 Cvar_SetValue("r_fullbrights", 0);
266         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
267 }
268
269 vec3_t r_farclip_origin;
270 vec3_t r_farclip_direction;
271 vec_t r_farclip_directiondist;
272 vec_t r_farclip_meshfarclip;
273 int r_farclip_directionbit0;
274 int r_farclip_directionbit1;
275 int r_farclip_directionbit2;
276
277 // start a farclip measuring session
278 void R_FarClip_Start(vec3_t origin, vec3_t direction, vec_t startfarclip)
279 {
280         VectorCopy(origin, r_farclip_origin);
281         VectorCopy(direction, r_farclip_direction);
282         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
283         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
284         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
285         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
286         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
287 }
288
289 // enlarge farclip to accomodate box
290 void R_FarClip_Box(vec3_t mins, vec3_t maxs)
291 {
292         float d;
293         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
294           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
295           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
296         if (r_farclip_meshfarclip < d)
297                 r_farclip_meshfarclip = d;
298 }
299
300 // return farclip value
301 float R_FarClip_Finish(void)
302 {
303         return r_farclip_meshfarclip - r_farclip_directiondist;
304 }
305
306 extern void R_Textures_Init(void);
307 extern void Mod_RenderInit(void);
308 extern void GL_Draw_Init(void);
309 extern void GL_Main_Init(void);
310 extern void R_Shadow_Init(void);
311 extern void GL_Models_Init(void);
312 extern void R_Sky_Init(void);
313 extern void GL_Surf_Init(void);
314 extern void R_Crosshairs_Init(void);
315 extern void R_Light_Init(void);
316 extern void R_Particles_Init(void);
317 extern void R_Explosion_Init(void);
318 extern void ui_init(void);
319 extern void gl_backend_init(void);
320 extern void Sbar_Init(void);
321 extern void R_LightningBeams_Init(void);
322
323 void Render_Init(void)
324 {
325         R_Textures_Init();
326         Mod_RenderInit();
327         gl_backend_init();
328         R_MeshQueue_Init();
329         GL_Draw_Init();
330         GL_Main_Init();
331         R_Shadow_Init();
332         GL_Models_Init();
333         R_Sky_Init();
334         GL_Surf_Init();
335         R_Crosshairs_Init();
336         R_Light_Init();
337         R_Particles_Init();
338         R_Explosion_Init();
339         ui_init();
340         Sbar_Init();
341         R_LightningBeams_Init();
342 }
343
344 /*
345 ===============
346 GL_Init
347 ===============
348 */
349 extern char *ENGINE_EXTENSIONS;
350 void GL_Init (void)
351 {
352         VID_CheckExtensions();
353
354         // LordHavoc: report supported extensions
355         Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
356 }
357
358 int R_CullBox(const vec3_t mins, const vec3_t maxs)
359 {
360         int i;
361         mplane_t *p;
362         for (i = 0;i < 4;i++)
363         {
364                 p = frustum + i;
365                 switch(p->signbits)
366                 {
367                 default:
368                 case 0:
369                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
370                                 return true;
371                         break;
372                 case 1:
373                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
374                                 return true;
375                         break;
376                 case 2:
377                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
378                                 return true;
379                         break;
380                 case 3:
381                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
382                                 return true;
383                         break;
384                 case 4:
385                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
386                                 return true;
387                         break;
388                 case 5:
389                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
390                                 return true;
391                         break;
392                 case 6:
393                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
394                                 return true;
395                         break;
396                 case 7:
397                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
398                                 return true;
399                         break;
400                 }
401         }
402         return false;
403 }
404
405 #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))))
406
407 //==================================================================================
408
409 static void R_MarkEntities (void)
410 {
411         int i;
412         entity_render_t *ent;
413
414         ent = &cl_entities[0].render;
415         Matrix4x4_CreateIdentity(&ent->matrix);
416         Matrix4x4_CreateIdentity(&ent->inversematrix);
417
418         if (cl.worldmodel)
419                 R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
420
421         if (!r_drawentities.integer)
422                 return;
423
424         for (i = 0;i < r_refdef.numentities;i++)
425         {
426                 ent = r_refdef.entities[i];
427                 Mod_CheckLoaded(ent->model);
428                 // some of the renderer still relies on origin...
429                 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
430                 // some of the renderer still relies on scale...
431                 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
432                 R_LerpAnimation(ent);
433                 R_UpdateEntLights(ent);
434                 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
435                  && !VIS_CullBox(ent->mins, ent->maxs))
436                 {
437                         ent->visframe = r_framecount;
438                         R_FarClip_Box(ent->mins, ent->maxs);
439                 }
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 void R_DrawFakeShadows(void)
512 {
513         int i;
514         entity_render_t *ent;
515
516         ent = &cl_entities[0].render;
517         if (ent->model && ent->model->DrawFakeShadow)
518                 ent->model->DrawFakeShadow(ent);
519
520         if (!r_drawentities.integer)
521                 return;
522         for (i = 0;i < r_refdef.numentities;i++)
523         {
524                 ent = r_refdef.entities[i];
525                 if ((ent->flags & RENDER_SHADOW) && ent->model && ent->model->DrawFakeShadow)
526                         ent->model->DrawFakeShadow(ent);
527         }
528 }
529
530 #include "r_shadow.h"
531
532 int shadowframecount = 0;
533
534 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)
535 {
536         vec3_t relativelightorigin;
537         // rough checks
538         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])))
539         {
540                 Matrix4x4_Transform(&ent->inversematrix, lightorigin, relativelightorigin);
541                 ent->model->DrawShadowVolume (ent, relativelightorigin, lightradius);
542         }
543 }
544
545 void R_Shadow_DrawWorldLightShadowVolume(matrix4x4_t *matrix, worldlight_t *light);
546
547 extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
548 void R_ShadowVolumeLighting(int visiblevolumes)
549 {
550         int i;
551         entity_render_t *ent;
552         int lnum;
553         float f, lightradius, cullradius;
554         vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
555         worldlight_t *wl;
556         rdlight_t *rd;
557         rmeshstate_t m;
558         matrix4x4_t matrix;
559         matrix4x4_t matrix_worldtofilter, matrix_worldtoattenuationxyz, matrix_worldtoattenuationz;
560         matrix4x4_t matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
561
562         if (visiblevolumes)
563         {
564                 memset(&m, 0, sizeof(m));
565                 R_Mesh_State_Texture(&m);
566
567                 GL_BlendFunc(GL_ONE, GL_ONE);
568                 GL_DepthMask(false);
569                 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
570                 qglDisable(GL_CULL_FACE);
571                 GL_Color(0.0 * r_colorscale, 0.0125 * r_colorscale, 0.1 * r_colorscale, 1);
572         }
573         else
574                 R_Shadow_Stage_Begin();
575         shadowframecount++;
576         if (r_shadow_realtime_world.integer)
577         {
578                 R_Shadow_LoadWorldLightsIfNeeded();
579                 for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++)
580                 {
581                         if (d_lightstylevalue[wl->style] <= 0)
582                                 continue;
583                         if (VIS_CullBox(wl->mins, wl->maxs))
584                                 continue;
585                         if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
586                                 continue;
587                         if (R_Shadow_ScissorForBBox(wl->mins, wl->maxs))
588                                 continue;
589
590                         cullradius = wl->cullradius;
591                         lightradius = wl->lightradius;
592                         VectorCopy(wl->mins, clipmins);
593                         VectorCopy(wl->maxs, clipmaxs);
594
595                         f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
596                         VectorScale(wl->light, f, lightcolor);
597                         if (wl->selected)
598                         {
599                                 f = 2 + sin(realtime * M_PI * 4.0);
600                                 VectorScale(lightcolor, f, lightcolor);
601                         }
602
603                         if (wl->castshadows && (gl_stencil || visiblevolumes))
604                         {
605                                 if (!visiblevolumes)
606                                         R_Shadow_Stage_ShadowVolumes();
607                                 ent = &cl_entities[0].render;
608                                 if (wl->shadowvolume && r_shadow_staticworldlights.integer)
609                                         R_Shadow_DrawWorldLightShadowVolume(&ent->matrix, wl);
610                                 else
611                                         R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
612                                 if (r_drawentities.integer)
613                                         for (i = 0;i < r_refdef.numentities;i++)
614                                                 R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
615                         }
616
617                         if (!visiblevolumes)
618                         {
619                                 if (wl->castshadows && gl_stencil)
620                                         R_Shadow_Stage_LightWithShadows();
621                                 else
622                                         R_Shadow_Stage_LightWithoutShadows();
623
624                                 // calculate world to filter matrix
625                                 Matrix4x4_CreateFromQuakeEntity(&matrix, wl->origin[0], wl->origin[1], wl->origin[2], wl->angles[0], wl->angles[1], wl->angles[2], lightradius);
626                                 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
627                                 // calculate world to attenuationxyz/xy matrix
628                                 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
629                                 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
630                                 // calculate world to attenuationz matrix
631                                 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
632                                 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
633                                 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
634                                 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
635                                 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
636
637                                 ent = &cl_entities[0].render;
638                                 if (ent->model && ent->model->DrawLight)
639                                 {
640                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
641                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
642                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
643                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
644                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
645                                         if (wl->numsurfaces)
646                                                 R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
647                                         else
648                                                 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
649                                 }
650                                 if (r_drawentities.integer)
651                                 {
652                                         for (i = 0;i < r_refdef.numentities;i++)
653                                         {
654                                                 ent = r_refdef.entities[i];
655                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
656                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
657                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
658                                                 {
659                                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
660                                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
661                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
662                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
663                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
664                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
665                                                 }
666                                         }
667                                 }
668                         }
669                 }
670         }
671         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
672         {
673                 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
674                 {
675                         lightradius = rd->cullradius;
676                         clipmins[0] = rd->origin[0] - lightradius;
677                         clipmins[1] = rd->origin[1] - lightradius;
678                         clipmins[2] = rd->origin[2] - lightradius;
679                         clipmaxs[0] = rd->origin[0] + lightradius;
680                         clipmaxs[1] = rd->origin[1] + lightradius;
681                         clipmaxs[2] = rd->origin[2] + lightradius;
682                         if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
683                                 continue;
684
685                         cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
686                         VectorScale(rd->light, (1.0f / 4096.0f), lightcolor);
687
688                         if (gl_stencil || visiblevolumes)
689                         {
690                                 if (!visiblevolumes)
691                                         R_Shadow_Stage_ShadowVolumes();
692                                 ent = &cl_entities[0].render;
693                                 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
694                                 if (r_drawentities.integer)
695                                 {
696                                         for (i = 0;i < r_refdef.numentities;i++)
697                                         {
698                                                 ent = r_refdef.entities[i];
699                                                 if (ent != rd->ent)
700                                                         R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
701                                         }
702                                 }
703                         }
704
705                         if (!visiblevolumes)
706                         {
707                                 if (gl_stencil)
708                                         R_Shadow_Stage_LightWithShadows();
709                                 else
710                                         R_Shadow_Stage_LightWithoutShadows();
711
712                                 // calculate world to filter matrix
713                                 Matrix4x4_CreateFromQuakeEntity(&matrix, rd->origin[0], rd->origin[1], rd->origin[2], 0, 0, 0, lightradius);
714                                 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
715                                 // calculate world to attenuationxyz/xy matrix
716                                 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
717                                 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
718                                 // calculate world to attenuationz matrix
719                                 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
720                                 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
721                                 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
722                                 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
723                                 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
724
725                                 ent = &cl_entities[0].render;
726                                 if (ent->model && ent->model->DrawLight)
727                                 {
728                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
729                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
730                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
731                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
732                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
733                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
734                                 }
735                                 if (r_drawentities.integer)
736                                 {
737                                         for (i = 0;i < r_refdef.numentities;i++)
738                                         {
739                                                 ent = r_refdef.entities[i];
740                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
741                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
742                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
743                                                 {
744                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
745                                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
746                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
747                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
748                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
749                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
750                                                 }
751                                         }
752                                 }
753                         }
754                 }
755         }
756
757         if (visiblevolumes)
758                 qglEnable(GL_CULL_FACE);
759         else
760                 R_Shadow_Stage_End();
761         qglDisable(GL_SCISSOR_TEST);
762 }
763
764 static void R_SetFrustum (void)
765 {
766         // LordHavoc: note to all quake engine coders, the special case for 90
767         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
768         // disabled as well.
769
770         // rotate VPN right by FOV_X/2 degrees
771         RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
772         frustum[0].dist = DotProduct (r_origin, frustum[0].normal);
773         PlaneClassify(&frustum[0]);
774
775         // rotate VPN left by FOV_X/2 degrees
776         RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
777         frustum[1].dist = DotProduct (r_origin, frustum[1].normal);
778         PlaneClassify(&frustum[1]);
779
780         // rotate VPN up by FOV_X/2 degrees
781         RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
782         frustum[2].dist = DotProduct (r_origin, frustum[2].normal);
783         PlaneClassify(&frustum[2]);
784
785         // rotate VPN down by FOV_X/2 degrees
786         RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
787         frustum[3].dist = DotProduct (r_origin, frustum[3].normal);
788         PlaneClassify(&frustum[3]);
789 }
790
791 /*
792 ===============
793 R_SetupFrame
794 ===============
795 */
796 static void R_SetupFrame (void)
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_framecount++;
808
809 // build the transformation matrix for the given view angles
810         VectorCopy (r_refdef.vieworg, r_origin);
811
812         AngleVectors (r_refdef.viewangles, vpn, vright, vup);
813
814         R_AnimateLight ();
815 }
816
817
818 static void R_BlendView(void)
819 {
820         rmeshstate_t m;
821         float r;
822         float vertex3f[3*3];
823
824         if (r_refdef.viewblend[3] < 0.01f)
825                 return;
826
827         R_Mesh_Matrix(&r_identitymatrix);
828
829         memset(&m, 0, sizeof(m));
830         R_Mesh_State_Texture(&m);
831
832         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
833         GL_DepthMask(true);
834         GL_DepthTest(false); // magic
835         GL_VertexPointer(vertex3f);
836         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
837         r = 64000;
838         vertex3f[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
839         vertex3f[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
840         vertex3f[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
841         vertex3f[3] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r + vup[0] * r * 3;
842         vertex3f[4] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r + vup[1] * r * 3;
843         vertex3f[5] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r + vup[2] * r * 3;
844         vertex3f[6] = r_origin[0] + vpn[0] * 1.5 + vright[0] * r * 3 - vup[0] * r;
845         vertex3f[7] = r_origin[1] + vpn[1] * 1.5 + vright[1] * r * 3 - vup[1] * r;
846         vertex3f[8] = r_origin[2] + vpn[2] * 1.5 + vright[2] * r * 3 - vup[2] * r;
847         R_Mesh_Draw(3, 1, polygonelements);
848 }
849
850 /*
851 ================
852 R_RenderView
853
854 r_refdef must be set before the first call
855 ================
856 */
857 extern void R_DrawLightningBeams (void);
858 void R_RenderView (void)
859 {
860         entity_render_t *world;
861         if (!r_refdef.entities/* || !cl.worldmodel*/)
862                 return; //Host_Error ("R_RenderView: NULL worldmodel");
863
864         if (r_shadow_realtime_world.integer)
865         {
866                 if (!gl_stencil)
867                 {
868                         Con_Printf("Stencil not enabled, turning off r_shadow_realtime_world, please type vid_stencil 1;vid_bitsperpixel 32;vid_restart and try again\n");
869                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
870                 }
871         }
872
873         world = &cl_entities[0].render;
874
875         // FIXME: move to client
876         R_MoveExplosions();
877         R_TimeReport("mexplosion");
878
879         R_Textures_Frame();
880         R_SetupFrame();
881         R_SetFrustum();
882         R_SetupFog();
883         R_SkyStartFrame();
884         R_BuildLightList();
885         R_TimeReport("setup");
886
887         if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
888                 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_origin, 2, r_pvsbits, sizeof(r_pvsbits));
889
890         R_WorldVisibility(world);
891         R_TimeReport("worldvis");
892
893         R_FarClip_Start(r_origin, vpn, 768.0f);
894         R_MarkEntities();
895         r_farclip = R_FarClip_Finish() + 256.0f;
896         R_TimeReport("markentity");
897
898         GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
899         if (r_shadow_realtime_world.integer || gl_stencil)
900                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
901         else
902                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
903         GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles);
904         qglDepthFunc(GL_LEQUAL);
905
906         R_Mesh_Start();
907         R_MeshQueue_BeginScene();
908
909         R_Shadow_UpdateWorldLightSelection();
910
911         if (R_DrawBrushModelsSky())
912                 R_TimeReport("bmodelsky");
913
914         // must occur early because it can draw sky
915         R_DrawWorld(world);
916         R_TimeReport("world");
917
918         // don't let sound skip if going slow
919         if (!intimerefresh && !r_speeds.integer)
920                 S_ExtraUpdate ();
921
922         R_DrawModels();
923         R_TimeReport("models");
924
925         if (r_shadows.integer == 1 && !r_shadow_realtime_world.integer)
926         {
927                 R_DrawFakeShadows();
928                 R_TimeReport("fakeshadow");
929         }
930
931         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
932         {
933                 R_ShadowVolumeLighting(false);
934                 R_TimeReport("dynlight");
935         }
936
937         R_DrawLightningBeams();
938         R_TimeReport("lightning");
939
940         R_DrawParticles();
941         R_TimeReport("particles");
942
943         R_DrawExplosions();
944         R_TimeReport("explosions");
945
946         R_MeshQueue_RenderTransparent();
947         R_TimeReport("drawtrans");
948
949         R_DrawCoronas();
950         R_TimeReport("coronas");
951
952         R_DrawWorldCrosshair();
953         R_TimeReport("crosshair");
954
955         R_BlendView();
956         R_TimeReport("blendview");
957
958         R_MeshQueue_Render();
959         R_MeshQueue_EndScene();
960
961         if (r_shadow_visiblevolumes.integer)
962         {
963                 R_ShadowVolumeLighting(true);
964                 R_TimeReport("shadowvolume");
965         }
966
967         R_Mesh_Finish();
968         R_TimeReport("meshfinish");
969 }
970
971 /*
972 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
973 {
974         int i;
975         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
976         rmeshstate_t m;
977         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
978         GL_DepthMask(false);
979         GL_DepthTest(true);
980         R_Mesh_Matrix(&r_identitymatrix);
981
982         memset(&m, 0, sizeof(m));
983         R_Mesh_State_Texture(&m);
984
985         R_Mesh_GetSpace(8);
986         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
987         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
988         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
989         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
990         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
991         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
992         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
993         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
994         GL_ColorPointer(color);
995         R_FillColors(color, 8, cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
996         if (fogenabled)
997         {
998                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
999                 {
1000                         VectorSubtract(v, r_origin, diff);
1001                         f2 = exp(fogdensity/DotProduct(diff, diff));
1002                         f1 = 1 - f2;
1003                         f2 *= r_colorscale;
1004                         c[0] = c[0] * f1 + fogcolor[0] * f2;
1005                         c[1] = c[1] * f1 + fogcolor[1] * f2;
1006                         c[2] = c[2] * f1 + fogcolor[2] * f2;
1007                 }
1008         }
1009         R_Mesh_Draw(8, 12);
1010 }
1011 */
1012
1013 int nomodelelements[24] =
1014 {
1015         5, 2, 0,
1016         5, 1, 2,
1017         5, 0, 3,
1018         5, 3, 1,
1019         0, 2, 4,
1020         2, 1, 4,
1021         3, 0, 4,
1022         1, 3, 4
1023 };
1024
1025 float nomodelvertex3f[6*3] =
1026 {
1027         -16,   0,   0,
1028          16,   0,   0,
1029           0, -16,   0,
1030           0,  16,   0,
1031           0,   0, -16,
1032           0,   0,  16
1033 };
1034
1035 float nomodelcolor4f[6*4] =
1036 {
1037         0.0f, 0.0f, 0.5f, 1.0f,
1038         0.0f, 0.0f, 0.5f, 1.0f,
1039         0.0f, 0.5f, 0.0f, 1.0f,
1040         0.0f, 0.5f, 0.0f, 1.0f,
1041         0.5f, 0.0f, 0.0f, 1.0f,
1042         0.5f, 0.0f, 0.0f, 1.0f
1043 };
1044
1045 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1046 {
1047         const entity_render_t *ent = calldata1;
1048         int i;
1049         float f1, f2, *c, diff[3];
1050         float color4f[6*4];
1051         rmeshstate_t m;
1052         R_Mesh_Matrix(&ent->matrix);
1053
1054         memset(&m, 0, sizeof(m));
1055         R_Mesh_State_Texture(&m);
1056
1057         if (ent->flags & EF_ADDITIVE)
1058         {
1059                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1060                 GL_DepthMask(false);
1061         }
1062         else if (ent->alpha < 1)
1063         {
1064                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1065                 GL_DepthMask(false);
1066         }
1067         else
1068         {
1069                 GL_BlendFunc(GL_ONE, GL_ZERO);
1070                 GL_DepthMask(true);
1071         }
1072         GL_DepthTest(true);
1073         GL_VertexPointer(nomodelvertex3f);
1074         if (fogenabled)
1075         {
1076                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1077                 GL_ColorPointer(color4f);
1078                 VectorSubtract(ent->origin, r_origin, diff);
1079                 f2 = exp(fogdensity/DotProduct(diff, diff));
1080                 f1 = 1 - f2;
1081                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1082                 {
1083                         c[0] = (c[0] * f1 + fogcolor[0] * f2) * r_colorscale;
1084                         c[1] = (c[1] * f1 + fogcolor[1] * f2) * r_colorscale;
1085                         c[2] = (c[2] * f1 + fogcolor[2] * f2) * r_colorscale;
1086                         c[3] *= ent->alpha;
1087                 }
1088         }
1089         else if (r_colorscale != 1 || ent->alpha != 1)
1090         {
1091                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1092                 GL_ColorPointer(color4f);
1093                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1094                 {
1095                         c[0] *= r_colorscale;
1096                         c[1] *= r_colorscale;
1097                         c[2] *= r_colorscale;
1098                         c[3] *= ent->alpha;
1099                 }
1100         }
1101         else
1102                 GL_ColorPointer(nomodelcolor4f);
1103         R_Mesh_Draw(6, 8, nomodelelements);
1104 }
1105
1106 void R_DrawNoModel(entity_render_t *ent)
1107 {
1108         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1109                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1110         //else
1111         //      R_DrawNoModelCallback(ent, 0);
1112 }
1113
1114 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1115 {
1116         vec3_t right1, right2, diff, normal;
1117
1118         VectorSubtract (org2, org1, normal);
1119         VectorNormalizeFast (normal);
1120
1121         // calculate 'right' vector for start
1122         VectorSubtract (r_origin, org1, diff);
1123         VectorNormalizeFast (diff);
1124         CrossProduct (normal, diff, right1);
1125
1126         // calculate 'right' vector for end
1127         VectorSubtract (r_origin, org2, diff);
1128         VectorNormalizeFast (diff);
1129         CrossProduct (normal, diff, right2);
1130
1131         vert[ 0] = org1[0] + width * right1[0];
1132         vert[ 1] = org1[1] + width * right1[1];
1133         vert[ 2] = org1[2] + width * right1[2];
1134         vert[ 3] = org1[0] - width * right1[0];
1135         vert[ 4] = org1[1] - width * right1[1];
1136         vert[ 5] = org1[2] - width * right1[2];
1137         vert[ 6] = org2[0] - width * right2[0];
1138         vert[ 7] = org2[1] - width * right2[1];
1139         vert[ 8] = org2[2] - width * right2[2];
1140         vert[ 9] = org2[0] + width * right2[0];
1141         vert[10] = org2[1] + width * right2[1];
1142         vert[11] = org2[2] + width * right2[2];
1143 }
1144
1145 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1146
1147 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)
1148 {
1149         float diff[3];
1150         rmeshstate_t m;
1151
1152         if (fogenabled)
1153         {
1154                 VectorSubtract(origin, r_origin, diff);
1155                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1156         }
1157
1158         R_Mesh_Matrix(&r_identitymatrix);
1159         GL_Color(cr * r_colorscale, cg * r_colorscale, cb * r_colorscale, ca);
1160         GL_VertexPointer(varray_vertex3f);
1161         GL_BlendFunc(blendfunc1, blendfunc2);
1162         GL_DepthMask(false);
1163         GL_DepthTest(!depthdisable);
1164
1165         memset(&m, 0, sizeof(m));
1166         m.tex[0] = R_GetTexture(texture);
1167         m.pointer_texcoord[0] = spritetexcoord2f;
1168         R_Mesh_State_Texture(&m);
1169
1170         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1171         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1172         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1173         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1174         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1175         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1176         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1177         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1178         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1179         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1180         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1181         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1182         R_Mesh_Draw(4, 2, polygonelements);
1183 }
1184