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