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