Added in_mouse_x and in_mouse_y, which contain the rel. coords of the mouse.
[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 extern void R_Model_Brush_DrawLightForSurfaceList(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, msurface_t **surflist, int numsurfaces, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
528 void R_ShadowVolumeLighting(int visiblevolumes)
529 {
530         int i;
531         entity_render_t *ent;
532         int lnum;
533         float f, lightradius, cullradius;
534         vec3_t relativelightorigin, relativeeyeorigin, lightcolor, clipmins, clipmaxs;
535         worldlight_t *wl;
536         rdlight_t *rd;
537         rmeshstate_t m;
538         matrix4x4_t matrix;
539         matrix4x4_t matrix_worldtofilter, matrix_worldtoattenuationxyz, matrix_worldtoattenuationz;
540         matrix4x4_t matrix_modeltofilter, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz;
541
542         if (visiblevolumes)
543         {
544                 memset(&m, 0, sizeof(m));
545                 R_Mesh_State_Texture(&m);
546
547                 GL_BlendFunc(GL_ONE, GL_ONE);
548                 GL_DepthMask(false);
549                 GL_DepthTest(r_shadow_visiblevolumes.integer < 2);
550                 qglDisable(GL_CULL_FACE);
551                 GL_Color(0.0, 0.0125, 0.1, 1);
552         }
553         else
554                 R_Shadow_Stage_Begin();
555         shadowframecount++;
556         if (r_shadow_realtime_world.integer)
557         {
558                 R_Shadow_LoadWorldLightsIfNeeded();
559                 for (lnum = 0, wl = r_shadow_worldlightchain;wl;wl = wl->next, lnum++)
560                 {
561                         if (d_lightstylevalue[wl->style] <= 0)
562                                 continue;
563                         if (VIS_CullBox(wl->mins, wl->maxs))
564                                 continue;
565                         if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer)
566                                 continue;
567                         if (R_Shadow_ScissorForBBox(wl->mins, wl->maxs))
568                                 continue;
569
570                         cullradius = wl->cullradius;
571                         lightradius = wl->lightradius;
572                         VectorCopy(wl->mins, clipmins);
573                         VectorCopy(wl->maxs, clipmaxs);
574
575                         f = d_lightstylevalue[wl->style] * (1.0f / 256.0f);
576                         VectorScale(wl->light, f, lightcolor);
577                         if (wl->selected)
578                         {
579                                 f = 2 + sin(realtime * M_PI * 4.0);
580                                 VectorScale(lightcolor, f, lightcolor);
581                         }
582
583                         if (wl->castshadows && (gl_stencil || visiblevolumes))
584                         {
585                                 if (!visiblevolumes)
586                                         R_Shadow_Stage_ShadowVolumes();
587                                 ent = &cl_entities[0].render;
588                                 if (wl->shadowvolume && r_shadow_staticworldlights.integer)
589                                         R_Shadow_DrawWorldLightShadowVolume(&ent->matrix, wl);
590                                 else
591                                         R_TestAndDrawShadowVolume(ent, wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
592                                 if (r_drawentities.integer)
593                                         for (i = 0;i < r_refdef.numentities;i++)
594                                                 R_TestAndDrawShadowVolume(r_refdef.entities[i], wl->origin, cullradius, lightradius, wl->mins, wl->maxs, clipmins, clipmaxs, true);
595                         }
596
597                         if (!visiblevolumes)
598                         {
599                                 if (wl->castshadows && gl_stencil)
600                                         R_Shadow_Stage_LightWithShadows();
601                                 else
602                                         R_Shadow_Stage_LightWithoutShadows();
603
604                                 // calculate world to filter matrix
605                                 Matrix4x4_CreateFromQuakeEntity(&matrix, wl->origin[0], wl->origin[1], wl->origin[2], wl->angles[0], wl->angles[1], wl->angles[2], lightradius);
606                                 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
607                                 // calculate world to attenuationxyz/xy matrix
608                                 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
609                                 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
610                                 // calculate world to attenuationz matrix
611                                 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
612                                 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
613                                 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
614                                 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
615                                 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
616
617                                 ent = &cl_entities[0].render;
618                                 if (ent->model && ent->model->DrawLight)
619                                 {
620                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
621                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
622                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
623                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
624                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
625                                         if (wl->numsurfaces)
626                                                 R_Model_Brush_DrawLightForSurfaceList(ent, relativelightorigin, relativeeyeorigin, lightradius, lightcolor, wl->surfaces, wl->numsurfaces, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
627                                         else
628                                                 ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
629                                 }
630                                 if (r_drawentities.integer)
631                                 {
632                                         for (i = 0;i < r_refdef.numentities;i++)
633                                         {
634                                                 ent = r_refdef.entities[i];
635                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
636                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
637                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
638                                                 {
639                                                         Matrix4x4_Transform(&ent->inversematrix, wl->origin, relativelightorigin);
640                                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
641                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
642                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
643                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
644                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
645                                                 }
646                                         }
647                                 }
648                         }
649                 }
650         }
651         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
652         {
653                 for (lnum = 0, rd = r_dlight;lnum < r_numdlights;lnum++, rd++)
654                 {
655                         lightradius = rd->cullradius;
656                         clipmins[0] = rd->origin[0] - lightradius;
657                         clipmins[1] = rd->origin[1] - lightradius;
658                         clipmins[2] = rd->origin[2] - lightradius;
659                         clipmaxs[0] = rd->origin[0] + lightradius;
660                         clipmaxs[1] = rd->origin[1] + lightradius;
661                         clipmaxs[2] = rd->origin[2] + lightradius;
662                         if (VIS_CullBox(clipmins, clipmaxs) || R_Shadow_ScissorForBBox(clipmins, clipmaxs))
663                                 continue;
664
665                         cullradius = RadiusFromBoundsAndOrigin(clipmins, clipmaxs, rd->origin);
666                         VectorScale(rd->light, (1.0f / 4096.0f), lightcolor);
667
668                         if (r_shadow_shadows.integer && (gl_stencil || visiblevolumes))
669                         {
670                                 if (!visiblevolumes)
671                                         R_Shadow_Stage_ShadowVolumes();
672                                 ent = &cl_entities[0].render;
673                                 R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
674                                 if (r_drawentities.integer)
675                                 {
676                                         for (i = 0;i < r_refdef.numentities;i++)
677                                         {
678                                                 ent = r_refdef.entities[i];
679                                                 if (ent != rd->ent)
680                                                         R_TestAndDrawShadowVolume(ent, rd->origin, cullradius, lightradius, clipmins, clipmaxs, clipmins, clipmaxs, false);
681                                         }
682                                 }
683                         }
684
685                         if (!visiblevolumes)
686                         {
687                                 if (r_shadow_shadows.integer && gl_stencil)
688                                         R_Shadow_Stage_LightWithShadows();
689                                 else
690                                         R_Shadow_Stage_LightWithoutShadows();
691
692                                 // calculate world to filter matrix
693                                 Matrix4x4_CreateFromQuakeEntity(&matrix, rd->origin[0], rd->origin[1], rd->origin[2], 0, 0, 0, lightradius);
694                                 Matrix4x4_Invert_Simple(&matrix_worldtofilter, &matrix);
695                                 // calculate world to attenuationxyz/xy matrix
696                                 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5, 0.5, 0.5, 0, 0, 0, 0.5);
697                                 Matrix4x4_Concat(&matrix_worldtoattenuationxyz, &matrix, &matrix_worldtofilter);
698                                 // calculate world to attenuationz matrix
699                                 matrix.m[0][0] = 0;matrix.m[0][1] = 0;matrix.m[0][2] = 0.5;matrix.m[0][3] = 0.5;
700                                 matrix.m[1][0] = 0;matrix.m[1][1] = 0;matrix.m[1][2] = 0  ;matrix.m[1][3] = 0.5;
701                                 matrix.m[2][0] = 0;matrix.m[2][1] = 0;matrix.m[2][2] = 0  ;matrix.m[2][3] = 0.5;
702                                 matrix.m[3][0] = 0;matrix.m[3][1] = 0;matrix.m[3][2] = 0  ;matrix.m[3][3] = 1;
703                                 Matrix4x4_Concat(&matrix_worldtoattenuationz, &matrix, &matrix_worldtofilter);
704
705                                 ent = &cl_entities[0].render;
706                                 if (ent->model && ent->model->DrawLight)
707                                 {
708                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
709                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
710                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
711                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
712                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
713                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
714                                 }
715                                 if (r_drawentities.integer)
716                                 {
717                                         for (i = 0;i < r_refdef.numentities;i++)
718                                         {
719                                                 ent = r_refdef.entities[i];
720                                                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawLight
721                                                  && BoxesOverlap(ent->mins, ent->maxs, clipmins, clipmaxs)
722                                                  && !(ent->effects & EF_ADDITIVE) && ent->alpha == 1)
723                                                 {
724                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, relativelightorigin);
725                                                         Matrix4x4_Transform(&ent->inversematrix, r_origin, relativeeyeorigin);
726                                                         Matrix4x4_Concat(&matrix_modeltofilter, &matrix_worldtofilter, &ent->matrix);
727                                                         Matrix4x4_Concat(&matrix_modeltoattenuationxyz, &matrix_worldtoattenuationxyz, &ent->matrix);
728                                                         Matrix4x4_Concat(&matrix_modeltoattenuationz, &matrix_worldtoattenuationz, &ent->matrix);
729                                                         ent->model->DrawLight(ent, relativelightorigin, relativeeyeorigin, lightradius / ent->scale, lightcolor, &matrix_modeltofilter, &matrix_modeltoattenuationxyz, &matrix_modeltoattenuationz);
730                                                 }
731                                         }
732                                 }
733                         }
734                 }
735         }
736
737         if (visiblevolumes)
738                 qglEnable(GL_CULL_FACE);
739         else
740                 R_Shadow_Stage_End();
741         qglDisable(GL_SCISSOR_TEST);
742 }
743
744 static void R_SetFrustum (void)
745 {
746         // LordHavoc: note to all quake engine coders, the special case for 90
747         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
748         // disabled as well.
749
750         // rotate VPN right by FOV_X/2 degrees
751         RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
752         frustum[0].dist = DotProduct (r_origin, frustum[0].normal);
753         PlaneClassify(&frustum[0]);
754
755         // rotate VPN left by FOV_X/2 degrees
756         RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
757         frustum[1].dist = DotProduct (r_origin, frustum[1].normal);
758         PlaneClassify(&frustum[1]);
759
760         // rotate VPN up by FOV_X/2 degrees
761         RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
762         frustum[2].dist = DotProduct (r_origin, frustum[2].normal);
763         PlaneClassify(&frustum[2]);
764
765         // rotate VPN down by FOV_X/2 degrees
766         RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
767         frustum[3].dist = DotProduct (r_origin, frustum[3].normal);
768         PlaneClassify(&frustum[3]);
769 }
770
771 /*
772 ===============
773 R_SetupFrame
774 ===============
775 */
776 static void R_SetupFrame (void)
777 {
778 // don't allow cheats in multiplayer
779         if (!cl.islocalgame)
780         {
781                 if (r_fullbright.integer != 0)
782                         Cvar_Set ("r_fullbright", "0");
783                 if (r_ambient.value != 0)
784                         Cvar_Set ("r_ambient", "0");
785         }
786
787         r_framecount++;
788
789 // build the transformation matrix for the given view angles
790         VectorCopy (r_refdef.vieworg, r_origin);
791
792         AngleVectors (r_refdef.viewangles, vpn, vright, vup);
793
794         R_AnimateLight ();
795 }
796
797
798 static void R_BlendView(void)
799 {
800         rmeshstate_t m;
801         float r;
802         float vertex3f[3*3];
803
804         if (r_refdef.viewblend[3] < 0.01f)
805                 return;
806
807         R_Mesh_Matrix(&r_identitymatrix);
808
809         memset(&m, 0, sizeof(m));
810         R_Mesh_State_Texture(&m);
811
812         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
813         GL_DepthMask(true);
814         GL_DepthTest(false); // magic
815         GL_VertexPointer(vertex3f);
816         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
817         r = 64000;
818         vertex3f[0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
819         vertex3f[1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
820         vertex3f[2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
821         vertex3f[3] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r + vup[0] * r * 3;
822         vertex3f[4] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r + vup[1] * r * 3;
823         vertex3f[5] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r + vup[2] * r * 3;
824         vertex3f[6] = r_origin[0] + vpn[0] * 1.5 + vright[0] * r * 3 - vup[0] * r;
825         vertex3f[7] = r_origin[1] + vpn[1] * 1.5 + vright[1] * r * 3 - vup[1] * r;
826         vertex3f[8] = r_origin[2] + vpn[2] * 1.5 + vright[2] * r * 3 - vup[2] * r;
827         R_Mesh_Draw(3, 1, polygonelements);
828 }
829
830 /*
831 ================
832 R_RenderView
833
834 r_refdef must be set before the first call
835 ================
836 */
837 extern void R_DrawLightningBeams (void);
838 void R_RenderView (void)
839 {
840         entity_render_t *world;
841         if (!r_refdef.entities/* || !cl.worldmodel*/)
842                 return; //Host_Error ("R_RenderView: NULL worldmodel");
843
844         if (r_shadow_realtime_world.integer)
845         {
846                 if (!gl_stencil)
847                 {
848                         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");
849                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
850                 }
851         }
852
853         world = &cl_entities[0].render;
854
855         // FIXME: move to client
856         R_MoveExplosions();
857         R_TimeReport("mexplosion");
858
859         R_Textures_Frame();
860         R_SetupFrame();
861         R_SetFrustum();
862         R_SetupFog();
863         R_SkyStartFrame();
864         R_BuildLightList();
865         R_TimeReport("setup");
866
867         if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
868                 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_origin, 2, r_pvsbits, sizeof(r_pvsbits));
869
870         R_WorldVisibility(world);
871         R_TimeReport("worldvis");
872
873         R_FarClip_Start(r_origin, vpn, 768.0f);
874         R_MarkEntities();
875         r_farclip = R_FarClip_Finish() + 256.0f;
876         R_TimeReport("markentity");
877
878         GL_SetupView_ViewPort(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
879         if ((r_shadow_realtime_world.integer || r_shadow_shadows.integer) && gl_stencil)
880                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
881         else
882                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
883         GL_SetupView_Orientation_FromEntity (r_refdef.vieworg, r_refdef.viewangles);
884         qglDepthFunc(GL_LEQUAL);
885
886         R_Mesh_Start();
887         R_MeshQueue_BeginScene();
888
889         R_Shadow_UpdateWorldLightSelection();
890
891         if (R_DrawBrushModelsSky())
892                 R_TimeReport("bmodelsky");
893
894         // must occur early because it can draw sky
895         R_DrawWorld(world);
896         R_TimeReport("world");
897
898         // don't let sound skip if going slow
899         if (!intimerefresh && !r_speeds.integer)
900                 S_ExtraUpdate ();
901
902         R_DrawModels();
903         R_TimeReport("models");
904
905         if (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer)
906         {
907                 R_ShadowVolumeLighting(false);
908                 R_TimeReport("dynlight");
909         }
910
911         R_DrawLightningBeams();
912         R_TimeReport("lightning");
913
914         R_DrawParticles();
915         R_TimeReport("particles");
916
917         R_DrawExplosions();
918         R_TimeReport("explosions");
919
920         R_MeshQueue_RenderTransparent();
921         R_TimeReport("drawtrans");
922
923         R_DrawCoronas();
924         R_TimeReport("coronas");
925
926         R_DrawWorldCrosshair();
927         R_TimeReport("crosshair");
928
929         R_BlendView();
930         R_TimeReport("blendview");
931
932         R_MeshQueue_Render();
933         R_MeshQueue_EndScene();
934
935         if (r_shadow_visiblevolumes.integer)
936         {
937                 R_ShadowVolumeLighting(true);
938                 R_TimeReport("shadowvolume");
939         }
940
941         R_Mesh_Finish();
942         R_TimeReport("meshfinish");
943 }
944
945 /*
946 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
947 {
948         int i;
949         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
950         rmeshstate_t m;
951         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
952         GL_DepthMask(false);
953         GL_DepthTest(true);
954         R_Mesh_Matrix(&r_identitymatrix);
955
956         memset(&m, 0, sizeof(m));
957         R_Mesh_State_Texture(&m);
958
959         R_Mesh_GetSpace(8);
960         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
961         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
962         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
963         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
964         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
965         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
966         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
967         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
968         GL_ColorPointer(color);
969         R_FillColors(color, 8, cr, cg, cb, ca);
970         if (fogenabled)
971         {
972                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
973                 {
974                         VectorSubtract(v, r_origin, diff);
975                         f2 = exp(fogdensity/DotProduct(diff, diff));
976                         f1 = 1 - f2;
977                         c[0] = c[0] * f1 + fogcolor[0] * f2;
978                         c[1] = c[1] * f1 + fogcolor[1] * f2;
979                         c[2] = c[2] * f1 + fogcolor[2] * f2;
980                 }
981         }
982         R_Mesh_Draw(8, 12);
983 }
984 */
985
986 int nomodelelements[24] =
987 {
988         5, 2, 0,
989         5, 1, 2,
990         5, 0, 3,
991         5, 3, 1,
992         0, 2, 4,
993         2, 1, 4,
994         3, 0, 4,
995         1, 3, 4
996 };
997
998 float nomodelvertex3f[6*3] =
999 {
1000         -16,   0,   0,
1001          16,   0,   0,
1002           0, -16,   0,
1003           0,  16,   0,
1004           0,   0, -16,
1005           0,   0,  16
1006 };
1007
1008 float nomodelcolor4f[6*4] =
1009 {
1010         0.0f, 0.0f, 0.5f, 1.0f,
1011         0.0f, 0.0f, 0.5f, 1.0f,
1012         0.0f, 0.5f, 0.0f, 1.0f,
1013         0.0f, 0.5f, 0.0f, 1.0f,
1014         0.5f, 0.0f, 0.0f, 1.0f,
1015         0.5f, 0.0f, 0.0f, 1.0f
1016 };
1017
1018 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
1019 {
1020         const entity_render_t *ent = calldata1;
1021         int i;
1022         float f1, f2, *c, diff[3];
1023         float color4f[6*4];
1024         rmeshstate_t m;
1025         R_Mesh_Matrix(&ent->matrix);
1026
1027         memset(&m, 0, sizeof(m));
1028         R_Mesh_State_Texture(&m);
1029
1030         if (ent->flags & EF_ADDITIVE)
1031         {
1032                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1033                 GL_DepthMask(false);
1034         }
1035         else if (ent->alpha < 1)
1036         {
1037                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1038                 GL_DepthMask(false);
1039         }
1040         else
1041         {
1042                 GL_BlendFunc(GL_ONE, GL_ZERO);
1043                 GL_DepthMask(true);
1044         }
1045         GL_DepthTest(true);
1046         GL_VertexPointer(nomodelvertex3f);
1047         if (fogenabled)
1048         {
1049                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1050                 GL_ColorPointer(color4f);
1051                 VectorSubtract(ent->origin, r_origin, diff);
1052                 f2 = exp(fogdensity/DotProduct(diff, diff));
1053                 f1 = 1 - f2;
1054                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1055                 {
1056                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
1057                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
1058                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
1059                         c[3] *= ent->alpha;
1060                 }
1061         }
1062         else if (ent->alpha != 1)
1063         {
1064                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
1065                 GL_ColorPointer(color4f);
1066                 for (i = 0, c = color4f;i < 6;i++, c += 4)
1067                         c[3] *= ent->alpha;
1068         }
1069         else
1070                 GL_ColorPointer(nomodelcolor4f);
1071         R_Mesh_Draw(6, 8, nomodelelements);
1072 }
1073
1074 void R_DrawNoModel(entity_render_t *ent)
1075 {
1076         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
1077                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
1078         //else
1079         //      R_DrawNoModelCallback(ent, 0);
1080 }
1081
1082 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
1083 {
1084         vec3_t right1, right2, diff, normal;
1085
1086         VectorSubtract (org2, org1, normal);
1087         VectorNormalizeFast (normal);
1088
1089         // calculate 'right' vector for start
1090         VectorSubtract (r_origin, org1, diff);
1091         VectorNormalizeFast (diff);
1092         CrossProduct (normal, diff, right1);
1093
1094         // calculate 'right' vector for end
1095         VectorSubtract (r_origin, org2, diff);
1096         VectorNormalizeFast (diff);
1097         CrossProduct (normal, diff, right2);
1098
1099         vert[ 0] = org1[0] + width * right1[0];
1100         vert[ 1] = org1[1] + width * right1[1];
1101         vert[ 2] = org1[2] + width * right1[2];
1102         vert[ 3] = org1[0] - width * right1[0];
1103         vert[ 4] = org1[1] - width * right1[1];
1104         vert[ 5] = org1[2] - width * right1[2];
1105         vert[ 6] = org2[0] - width * right2[0];
1106         vert[ 7] = org2[1] - width * right2[1];
1107         vert[ 8] = org2[2] - width * right2[2];
1108         vert[ 9] = org2[0] + width * right2[0];
1109         vert[10] = org2[1] + width * right2[1];
1110         vert[11] = org2[2] + width * right2[2];
1111 }
1112
1113 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
1114
1115 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)
1116 {
1117         float diff[3];
1118         rmeshstate_t m;
1119
1120         if (fogenabled)
1121         {
1122                 VectorSubtract(origin, r_origin, diff);
1123                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
1124         }
1125
1126         R_Mesh_Matrix(&r_identitymatrix);
1127         GL_Color(cr, cg, cb, ca);
1128         GL_VertexPointer(varray_vertex3f);
1129         GL_BlendFunc(blendfunc1, blendfunc2);
1130         GL_DepthMask(false);
1131         GL_DepthTest(!depthdisable);
1132
1133         memset(&m, 0, sizeof(m));
1134         m.tex[0] = R_GetTexture(texture);
1135         m.pointer_texcoord[0] = spritetexcoord2f;
1136         R_Mesh_State_Texture(&m);
1137
1138         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
1139         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
1140         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
1141         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
1142         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
1143         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
1144         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
1145         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
1146         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
1147         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
1148         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
1149         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
1150         R_Mesh_Draw(4, 2, polygonelements);
1151 }
1152