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