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