]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
upgraded network protocol to DP5, now sends precise entity angles (except for EF_LOWP...
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24
25 // used for dlight push checking and other things
26 int r_framecount;
27
28 // used for visibility checking
29 qbyte r_pvsbits[(MAX_MAP_LEAFS+7)>>3];
30
31 mplane_t frustum[4];
32
33 matrix4x4_t r_identitymatrix;
34
35 int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
36
37 // true during envmap command capture
38 qboolean envmap;
39
40 float r_farclip;
41
42 // view origin
43 vec3_t r_vieworigin;
44 vec3_t r_viewforward;
45 vec3_t r_viewleft;
46 vec3_t r_viewright;
47 vec3_t r_viewup;
48
49 //
50 // screen size info
51 //
52 refdef_t r_refdef;
53
54 // 8.8 fraction of base light value
55 unsigned short d_lightstylevalue[256];
56
57 cvar_t r_drawentities = {0, "r_drawentities","1"};
58 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
59 cvar_t r_speeds = {0, "r_speeds","0"};
60 cvar_t r_fullbright = {0, "r_fullbright","0"};
61 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
62 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
63 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
64 cvar_t r_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 timestart, timedelta, oldangles[3];
121
122         intimerefresh = 1;
123         VectorCopy(cl.viewangles, oldangles);
124         VectorClear(cl.viewangles);
125
126         timestart = Sys_DoubleTime();
127         for (i = 0;i < 128;i++)
128         {
129                 Matrix4x4_CreateFromQuakeEntity(&r_refdef.viewentitymatrix, r_vieworigin[0], r_vieworigin[1], r_vieworigin[2], 0, i / 128.0 * 360.0, 0, 1);
130                 CL_UpdateScreen();
131         }
132         timedelta = Sys_DoubleTime() - timestart;
133
134         VectorCopy(oldangles, cl.viewangles);
135         intimerefresh = 0;
136         Con_Printf ("%f seconds (%f fps)\n", timedelta, 128/timedelta);
137 }
138
139 vec3_t fogcolor;
140 vec_t fogdensity;
141 float fog_density, fog_red, fog_green, fog_blue;
142 qboolean fogenabled;
143 qboolean oldgl_fogenable;
144 void R_UpdateFog(void)
145 {
146         if (gamemode == GAME_NEHAHRA)
147         {
148                 if (gl_fogenable.integer)
149                 {
150                         oldgl_fogenable = true;
151                         fog_density = gl_fogdensity.value;
152                         fog_red = gl_fogred.value;
153                         fog_green = gl_foggreen.value;
154                         fog_blue = gl_fogblue.value;
155                 }
156                 else if (oldgl_fogenable)
157                 {
158                         oldgl_fogenable = false;
159                         fog_density = 0;
160                         fog_red = 0;
161                         fog_green = 0;
162                         fog_blue = 0;
163                 }
164         }
165         if (fog_density)
166         {
167                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
168                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
169                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
170         }
171         if (fog_density)
172         {
173                 fogenabled = true;
174                 fogdensity = -4000.0f / (fog_density * fog_density);
175                 // fog color was already set
176         }
177         else
178                 fogenabled = false;
179 }
180
181 // FIXME: move this to client?
182 void FOG_clear(void)
183 {
184         if (gamemode == GAME_NEHAHRA)
185         {
186                 Cvar_Set("gl_fogenable", "0");
187                 Cvar_Set("gl_fogdensity", "0.2");
188                 Cvar_Set("gl_fogred", "0.3");
189                 Cvar_Set("gl_foggreen", "0.3");
190                 Cvar_Set("gl_fogblue", "0.3");
191         }
192         fog_density = fog_red = fog_green = fog_blue = 0.0f;
193 }
194
195 // FIXME: move this to client?
196 void FOG_registercvars(void)
197 {
198         if (gamemode == GAME_NEHAHRA)
199         {
200                 Cvar_RegisterVariable (&gl_fogenable);
201                 Cvar_RegisterVariable (&gl_fogdensity);
202                 Cvar_RegisterVariable (&gl_fogred);
203                 Cvar_RegisterVariable (&gl_foggreen);
204                 Cvar_RegisterVariable (&gl_fogblue);
205                 Cvar_RegisterVariable (&gl_fogstart);
206                 Cvar_RegisterVariable (&gl_fogend);
207         }
208 }
209
210 void gl_main_start(void)
211 {
212 }
213
214 void gl_main_shutdown(void)
215 {
216 }
217
218 extern void CL_ParseEntityLump(char *entitystring);
219 void gl_main_newmap(void)
220 {
221         int l;
222         char *entities, entname[MAX_QPATH];
223         r_framecount = 1;
224         if (cl.worldmodel)
225         {
226                 strcpy(entname, cl.worldmodel->name);
227                 l = strlen(entname) - 4;
228                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
229                 {
230                         strcpy(entname + l, ".ent");
231                         if ((entities = FS_LoadFile(entname, true)))
232                         {
233                                 CL_ParseEntityLump(entities);
234                                 Mem_Free(entities);
235                                 return;
236                         }
237                 }
238                 if (cl.worldmodel->brush.entities)
239                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
240         }
241 }
242
243 void GL_Main_Init(void)
244 {
245         Matrix4x4_CreateIdentity(&r_identitymatrix);
246 // FIXME: move this to client?
247         FOG_registercvars();
248         Cmd_AddCommand("timerefresh", R_TimeRefresh_f);
249         Cvar_RegisterVariable(&r_drawentities);
250         Cvar_RegisterVariable(&r_drawviewmodel);
251         Cvar_RegisterVariable(&r_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_lerpsprites);
258         Cvar_RegisterVariable(&r_lerpmodels);
259         Cvar_RegisterVariable(&r_waterscroll);
260         Cvar_RegisterVariable(&r_watershader);
261         Cvar_RegisterVariable(&r_drawcollisionbrushes);
262         if (gamemode == GAME_NEHAHRA || gamemode == GAME_NEXUIZ || gamemode == GAME_TENEBRAE)
263                 Cvar_SetValue("r_fullbrights", 0);
264         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
265 }
266
267 static vec3_t r_farclip_origin;
268 static vec3_t r_farclip_direction;
269 static vec_t r_farclip_directiondist;
270 static vec_t r_farclip_meshfarclip;
271 static int r_farclip_directionbit0;
272 static int r_farclip_directionbit1;
273 static int r_farclip_directionbit2;
274
275 // enlarge farclip to accomodate box
276 static void R_FarClip_Box(vec3_t mins, vec3_t maxs)
277 {
278         float d;
279         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
280           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
281           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
282         if (r_farclip_meshfarclip < d)
283                 r_farclip_meshfarclip = d;
284 }
285
286 // return farclip value
287 static float R_FarClip(vec3_t origin, vec3_t direction, vec_t startfarclip)
288 {
289         int i;
290
291         VectorCopy(origin, r_farclip_origin);
292         VectorCopy(direction, r_farclip_direction);
293         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
294         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
295         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
296         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
297         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
298
299         if (cl.worldmodel)
300                 R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
301         for (i = 0;i < r_refdef.numentities;i++)
302                 R_FarClip_Box(r_refdef.entities[i]->mins, r_refdef.entities[i]->maxs);
303         
304         return r_farclip_meshfarclip - r_farclip_directiondist;
305 }
306
307 extern void R_Textures_Init(void);
308 extern void Mod_RenderInit(void);
309 extern void GL_Draw_Init(void);
310 extern void GL_Main_Init(void);
311 extern void R_Shadow_Init(void);
312 extern void GL_Models_Init(void);
313 extern void R_Sky_Init(void);
314 extern void GL_Surf_Init(void);
315 extern void R_Crosshairs_Init(void);
316 extern void R_Light_Init(void);
317 extern void R_Particles_Init(void);
318 extern void R_Explosion_Init(void);
319 extern void ui_init(void);
320 extern void gl_backend_init(void);
321 extern void Sbar_Init(void);
322 extern void R_LightningBeams_Init(void);
323
324 void Render_Init(void)
325 {
326         R_Textures_Init();
327         Mod_RenderInit();
328         gl_backend_init();
329         R_MeshQueue_Init();
330         GL_Draw_Init();
331         GL_Main_Init();
332         R_Shadow_Init();
333         GL_Models_Init();
334         R_Sky_Init();
335         GL_Surf_Init();
336         R_Crosshairs_Init();
337         R_Light_Init();
338         R_Particles_Init();
339         R_Explosion_Init();
340         //ui_init();
341         UI_Init();
342         Sbar_Init();
343         R_LightningBeams_Init();
344 }
345
346 /*
347 ===============
348 GL_Init
349 ===============
350 */
351 extern char *ENGINE_EXTENSIONS;
352 void GL_Init (void)
353 {
354         VID_CheckExtensions();
355
356         // LordHavoc: report supported extensions
357         Con_DPrintf("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
358 }
359
360 int R_CullBox(const vec3_t mins, const vec3_t maxs)
361 {
362         int i;
363         mplane_t *p;
364         for (i = 0;i < 4;i++)
365         {
366                 p = frustum + i;
367                 switch(p->signbits)
368                 {
369                 default:
370                 case 0:
371                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
372                                 return true;
373                         break;
374                 case 1:
375                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
376                                 return true;
377                         break;
378                 case 2:
379                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
380                                 return true;
381                         break;
382                 case 3:
383                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
384                                 return true;
385                         break;
386                 case 4:
387                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
388                                 return true;
389                         break;
390                 case 5:
391                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
392                                 return true;
393                         break;
394                 case 6:
395                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
396                                 return true;
397                         break;
398                 case 7:
399                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
400                                 return true;
401                         break;
402                 }
403         }
404         return false;
405 }
406
407 //==================================================================================
408
409 static void R_MarkEntities (void)
410 {
411         int i;
412         entity_render_t *ent;
413
414         ent = &cl_entities[0].render;
415         Matrix4x4_CreateIdentity(&ent->matrix);
416         Matrix4x4_CreateIdentity(&ent->inversematrix);
417
418         if (!r_drawentities.integer)
419                 return;
420
421         for (i = 0;i < r_refdef.numentities;i++)
422         {
423                 ent = r_refdef.entities[i];
424                 Mod_CheckLoaded(ent->model);
425                 // some of the renderer still relies on origin...
426                 Matrix4x4_OriginFromMatrix(&ent->matrix, ent->origin);
427                 // some of the renderer still relies on scale...
428                 ent->scale = Matrix4x4_ScaleFromMatrix(&ent->matrix);
429                 R_LerpAnimation(ent);
430                 R_UpdateEntLights(ent);
431                 if ((chase_active.integer || !(ent->flags & RENDER_EXTERIORMODEL))
432                  && !VIS_CullBox(ent->mins, ent->maxs)
433                  && (!envmap || !(ent->flags & (RENDER_VIEWMODEL | RENDER_EXTERIORMODEL))))
434                         ent->visframe = r_framecount;
435         }
436 }
437
438 // only used if skyrendermasked, and normally returns false
439 int R_DrawBrushModelsSky (void)
440 {
441         int i, sky;
442         entity_render_t *ent;
443
444         if (!r_drawentities.integer)
445                 return false;
446
447         sky = false;
448         for (i = 0;i < r_refdef.numentities;i++)
449         {
450                 ent = r_refdef.entities[i];
451                 if (ent->visframe == r_framecount && ent->model && ent->model->DrawSky)
452                 {
453                         ent->model->DrawSky(ent);
454                         sky = true;
455                 }
456         }
457         return sky;
458 }
459
460 /*
461 =============
462 R_DrawViewModel
463 =============
464 */
465 /*
466 void R_DrawViewModel (void)
467 {
468         entity_render_t *ent;
469
470         // FIXME: move these checks to client
471         if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
472                 return;
473
474         ent = &cl.viewent.render;
475         Mod_CheckLoaded(ent->model);
476         R_LerpAnimation(ent);
477         Matrix4x4_CreateFromQuakeEntity(&ent->matrix, ent->origin[0], ent->origin[1], ent->origin[2], -ent->angles[0], ent->angles[1], ent->angles[2], ent->scale);
478         Matrix4x4_Invert_Simple(&ent->inversematrix, &ent->matrix);
479         R_UpdateEntLights(ent);
480         ent->model->Draw(ent);
481 }
482 */
483
484 void R_DrawNoModel(entity_render_t *ent);
485 void R_DrawModels(void)
486 {
487         int i;
488         entity_render_t *ent;
489
490         if (!r_drawentities.integer)
491                 return;
492
493         for (i = 0;i < r_refdef.numentities;i++)
494         {
495                 ent = r_refdef.entities[i];
496                 if (ent->visframe == r_framecount)
497                 {
498                         if (ent->model && ent->model->Draw != NULL)
499                                 ent->model->Draw(ent);
500                         else
501                                 R_DrawNoModel(ent);
502                 }
503         }
504 }
505
506 static void R_SetFrustum(void)
507 {
508         // break apart the viewentity matrix into vectors for various purposes
509         Matrix4x4_ToVectors(&r_refdef.viewentitymatrix, r_viewforward, r_viewleft, r_viewup, r_vieworigin);
510         VectorNegate(r_viewleft, r_viewright);
511
512         // LordHavoc: note to all quake engine coders, the special case for 90
513         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
514         // disabled as well.
515
516         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
517         RotatePointAroundVector( frustum[0].normal, r_viewup, r_viewforward, -(90 - r_refdef.fov_x / 2));
518         frustum[0].dist = DotProduct (r_vieworigin, frustum[0].normal);
519         PlaneClassify(&frustum[0]);
520
521         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
522         RotatePointAroundVector( frustum[1].normal, r_viewup, r_viewforward, (90 - r_refdef.fov_x / 2));
523         frustum[1].dist = DotProduct (r_vieworigin, frustum[1].normal);
524         PlaneClassify(&frustum[1]);
525
526         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
527         RotatePointAroundVector( frustum[2].normal, r_viewleft, r_viewforward, -(90 - r_refdef.fov_y / 2));
528         frustum[2].dist = DotProduct (r_vieworigin, frustum[2].normal);
529         PlaneClassify(&frustum[2]);
530
531         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
532         RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_refdef.fov_y / 2));
533         frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
534         PlaneClassify(&frustum[3]);
535 }
536
537 static void R_BlendView(void)
538 {
539         rmeshstate_t m;
540         float r;
541         float vertex3f[3*3];
542
543         if (r_refdef.viewblend[3] < 0.01f)
544                 return;
545
546         R_Mesh_Matrix(&r_identitymatrix);
547
548         memset(&m, 0, sizeof(m));
549         R_Mesh_State_Texture(&m);
550
551         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
552         GL_DepthMask(true);
553         GL_DepthTest(false); // magic
554         GL_VertexPointer(vertex3f);
555         GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
556         r = 64;
557         vertex3f[0] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r - r_viewup[0] * r;
558         vertex3f[1] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r - r_viewup[1] * r;
559         vertex3f[2] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r - r_viewup[2] * r;
560         vertex3f[3] = r_vieworigin[0] + r_viewforward[0] * 1.5 + r_viewleft[0] * r + r_viewup[0] * r * 3;
561         vertex3f[4] = r_vieworigin[1] + r_viewforward[1] * 1.5 + r_viewleft[1] * r + r_viewup[1] * r * 3;
562         vertex3f[5] = r_vieworigin[2] + r_viewforward[2] * 1.5 + r_viewleft[2] * r + r_viewup[2] * r * 3;
563         vertex3f[6] = r_vieworigin[0] + r_viewforward[0] * 1.5 - r_viewleft[0] * r * 3 - r_viewup[0] * r;
564         vertex3f[7] = r_vieworigin[1] + r_viewforward[1] * 1.5 - r_viewleft[1] * r * 3 - r_viewup[1] * r;
565         vertex3f[8] = r_vieworigin[2] + r_viewforward[2] * 1.5 - r_viewleft[2] * r * 3 - r_viewup[2] * r;
566         R_Mesh_Draw(3, 1, polygonelements);
567 }
568
569 void R_UpdateWorld(void)
570 {
571         if (!r_refdef.entities/* || !cl.worldmodel*/)
572                 return; //Host_Error ("R_RenderView: NULL worldmodel");
573
574         if (r_shadow_realtime_world.integer && !gl_stencil)
575         {
576                 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");
577                 Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
578         }
579
580         // don't allow cheats in multiplayer
581         if (!cl.islocalgame)
582         {
583                 if (r_fullbright.integer != 0)
584                         Cvar_Set ("r_fullbright", "0");
585                 if (r_ambient.value != 0)
586                         Cvar_Set ("r_ambient", "0");
587         }
588
589         R_Textures_Frame();
590         R_UpdateFog();
591         R_UpdateLights();
592 }
593
594 void R_RenderScene(void);
595
596 /*
597 ================
598 R_RenderView
599 ================
600 */
601 void R_RenderView(void)
602 {
603         if (!r_refdef.entities/* || !cl.worldmodel*/)
604                 return; //Host_Error ("R_RenderView: NULL worldmodel");
605         
606         r_refdef.width = bound(0, r_refdef.width, vid.realwidth);
607         r_refdef.height = bound(0, r_refdef.height, vid.realheight);
608         r_refdef.x = bound(0, r_refdef.x, vid.realwidth - r_refdef.width);
609         r_refdef.y = bound(0, r_refdef.y, vid.realheight - r_refdef.height);
610         r_refdef.fov_x = bound(1, r_refdef.fov_x, 170);
611         r_refdef.fov_y = bound(1, r_refdef.fov_y, 170);
612
613         // GL is weird because it's bottom to top, r_refdef.y is top to bottom
614         qglViewport(r_refdef.x, vid.realheight - (r_refdef.y + r_refdef.height), r_refdef.width, r_refdef.height);
615         GL_Scissor(r_refdef.x, r_refdef.y, r_refdef.width, r_refdef.height);
616         GL_ScissorTest(true);
617         R_ClearScreen();
618
619         R_SetFrustum();
620         r_farclip = R_FarClip(r_vieworigin, r_viewforward, 768.0f) + 256.0f;
621
622         if (gl_stencil && ((r_shadow_realtime_world.integer && r_shadow_worldshadows.integer) || ((r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && r_shadow_dlightshadows.integer)))
623                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.fov_x, r_refdef.fov_y, 1.0f);
624         else
625                 GL_SetupView_Mode_Perspective(r_refdef.fov_x, r_refdef.fov_y, 1.0f, r_farclip);
626
627         GL_SetupView_Orientation_FromEntity(&r_refdef.viewentitymatrix);
628         R_TimeReport("setup");
629
630         R_RenderScene();
631
632         R_BlendView();
633         R_TimeReport("blendview");
634         
635         GL_Scissor(0, 0, vid.realwidth, vid.realheight);
636         GL_ScissorTest(false);
637 }
638
639 extern void R_DrawLightningBeams (void);
640 void R_RenderScene(void)
641 {
642         entity_render_t *world;
643
644         // don't let sound skip if going slow
645         if (!intimerefresh && !r_speeds.integer)
646                 S_ExtraUpdate ();
647
648         r_framecount++;
649
650         R_SkyStartFrame();
651
652         if (cl.worldmodel && cl.worldmodel->brush.FatPVS)
653                 cl.worldmodel->brush.FatPVS(cl.worldmodel, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
654         world = &cl_entities[0].render;
655         R_WorldVisibility(world);
656         R_TimeReport("worldvis");
657
658         R_MarkEntities();
659         R_TimeReport("markentity");
660
661         qglDepthFunc(GL_LEQUAL);
662         qglPolygonOffset(0, 0);
663         qglEnable(GL_POLYGON_OFFSET_FILL);
664
665         R_Mesh_Start();
666         R_MeshQueue_BeginScene();
667
668         R_Shadow_UpdateWorldLightSelection();
669
670         // don't let sound skip if going slow
671         if (!intimerefresh && !r_speeds.integer)
672                 S_ExtraUpdate ();
673
674         if (R_DrawBrushModelsSky())
675                 R_TimeReport("bmodelsky");
676
677         // must occur early because it can draw sky
678         R_DrawWorld(world);
679         R_TimeReport("world");
680
681         // don't let sound skip if going slow
682         if (!intimerefresh && !r_speeds.integer)
683                 S_ExtraUpdate ();
684
685         R_DrawModels();
686         R_TimeReport("models");
687
688         // don't let sound skip if going slow
689         if (!intimerefresh && !r_speeds.integer)
690                 S_ExtraUpdate ();
691
692         R_ShadowVolumeLighting(false);
693         R_TimeReport("rtlights");
694
695         // don't let sound skip if going slow
696         if (!intimerefresh && !r_speeds.integer)
697                 S_ExtraUpdate ();
698
699         R_DrawLightningBeams();
700         R_TimeReport("lightning");
701
702         R_DrawParticles();
703         R_TimeReport("particles");
704
705         R_DrawExplosions();
706         R_TimeReport("explosions");
707
708         R_MeshQueue_RenderTransparent();
709         R_TimeReport("drawtrans");
710
711         R_DrawCoronas();
712         R_TimeReport("coronas");
713
714         R_DrawWorldCrosshair();
715         R_TimeReport("crosshair");
716
717         R_MeshQueue_Render();
718         R_MeshQueue_EndScene();
719
720         if (r_shadow_visiblevolumes.integer)
721         {
722                 R_ShadowVolumeLighting(true);
723                 R_TimeReport("shadowvolume");
724         }
725
726         R_Mesh_Finish();
727         R_TimeReport("meshfinish");
728
729         qglPolygonOffset(0, 0);
730         qglDisable(GL_POLYGON_OFFSET_FILL);
731
732         // don't let sound skip if going slow
733         if (!intimerefresh && !r_speeds.integer)
734                 S_ExtraUpdate ();
735 }
736
737 /*
738 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
739 {
740         int i;
741         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
742         rmeshstate_t m;
743         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
744         GL_DepthMask(false);
745         GL_DepthTest(true);
746         R_Mesh_Matrix(&r_identitymatrix);
747
748         memset(&m, 0, sizeof(m));
749         R_Mesh_State_Texture(&m);
750
751         R_Mesh_GetSpace(8);
752         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
753         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
754         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
755         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
756         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
757         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
758         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
759         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
760         GL_ColorPointer(color);
761         R_FillColors(color, 8, cr, cg, cb, ca);
762         if (fogenabled)
763         {
764                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
765                 {
766                         VectorSubtract(v, r_vieworigin, diff);
767                         f2 = exp(fogdensity/DotProduct(diff, diff));
768                         f1 = 1 - f2;
769                         c[0] = c[0] * f1 + fogcolor[0] * f2;
770                         c[1] = c[1] * f1 + fogcolor[1] * f2;
771                         c[2] = c[2] * f1 + fogcolor[2] * f2;
772                 }
773         }
774         R_Mesh_Draw(8, 12);
775 }
776 */
777
778 int nomodelelements[24] =
779 {
780         5, 2, 0,
781         5, 1, 2,
782         5, 0, 3,
783         5, 3, 1,
784         0, 2, 4,
785         2, 1, 4,
786         3, 0, 4,
787         1, 3, 4
788 };
789
790 float nomodelvertex3f[6*3] =
791 {
792         -16,   0,   0,
793          16,   0,   0,
794           0, -16,   0,
795           0,  16,   0,
796           0,   0, -16,
797           0,   0,  16
798 };
799
800 float nomodelcolor4f[6*4] =
801 {
802         0.0f, 0.0f, 0.5f, 1.0f,
803         0.0f, 0.0f, 0.5f, 1.0f,
804         0.0f, 0.5f, 0.0f, 1.0f,
805         0.0f, 0.5f, 0.0f, 1.0f,
806         0.5f, 0.0f, 0.0f, 1.0f,
807         0.5f, 0.0f, 0.0f, 1.0f
808 };
809
810 void R_DrawNoModelCallback(const void *calldata1, int calldata2)
811 {
812         const entity_render_t *ent = calldata1;
813         int i;
814         float f1, f2, *c, diff[3];
815         float color4f[6*4];
816         rmeshstate_t m;
817         R_Mesh_Matrix(&ent->matrix);
818
819         memset(&m, 0, sizeof(m));
820         R_Mesh_State_Texture(&m);
821
822         if (ent->flags & EF_ADDITIVE)
823         {
824                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
825                 GL_DepthMask(false);
826         }
827         else if (ent->alpha < 1)
828         {
829                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
830                 GL_DepthMask(false);
831         }
832         else
833         {
834                 GL_BlendFunc(GL_ONE, GL_ZERO);
835                 GL_DepthMask(true);
836         }
837         GL_DepthTest(true);
838         GL_VertexPointer(nomodelvertex3f);
839         if (fogenabled)
840         {
841                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
842                 GL_ColorPointer(color4f);
843                 VectorSubtract(ent->origin, r_vieworigin, diff);
844                 f2 = exp(fogdensity/DotProduct(diff, diff));
845                 f1 = 1 - f2;
846                 for (i = 0, c = color4f;i < 6;i++, c += 4)
847                 {
848                         c[0] = (c[0] * f1 + fogcolor[0] * f2);
849                         c[1] = (c[1] * f1 + fogcolor[1] * f2);
850                         c[2] = (c[2] * f1 + fogcolor[2] * f2);
851                         c[3] *= ent->alpha;
852                 }
853         }
854         else if (ent->alpha != 1)
855         {
856                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
857                 GL_ColorPointer(color4f);
858                 for (i = 0, c = color4f;i < 6;i++, c += 4)
859                         c[3] *= ent->alpha;
860         }
861         else
862                 GL_ColorPointer(nomodelcolor4f);
863         R_Mesh_Draw(6, 8, nomodelelements);
864 }
865
866 void R_DrawNoModel(entity_render_t *ent)
867 {
868         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
869                 R_MeshQueue_AddTransparent(ent->origin, R_DrawNoModelCallback, ent, 0);
870         //else
871         //      R_DrawNoModelCallback(ent, 0);
872 }
873
874 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
875 {
876         vec3_t right1, right2, diff, normal;
877
878         VectorSubtract (org2, org1, normal);
879         VectorNormalizeFast (normal);
880
881         // calculate 'right' vector for start
882         VectorSubtract (r_vieworigin, org1, diff);
883         VectorNormalizeFast (diff);
884         CrossProduct (normal, diff, right1);
885
886         // calculate 'right' vector for end
887         VectorSubtract (r_vieworigin, org2, diff);
888         VectorNormalizeFast (diff);
889         CrossProduct (normal, diff, right2);
890
891         vert[ 0] = org1[0] + width * right1[0];
892         vert[ 1] = org1[1] + width * right1[1];
893         vert[ 2] = org1[2] + width * right1[2];
894         vert[ 3] = org1[0] - width * right1[0];
895         vert[ 4] = org1[1] - width * right1[1];
896         vert[ 5] = org1[2] - width * right1[2];
897         vert[ 6] = org2[0] - width * right2[0];
898         vert[ 7] = org2[1] - width * right2[1];
899         vert[ 8] = org2[2] - width * right2[2];
900         vert[ 9] = org2[0] + width * right2[0];
901         vert[10] = org2[1] + width * right2[1];
902         vert[11] = org2[2] + width * right2[2];
903 }
904
905 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
906
907 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)
908 {
909         float diff[3];
910         rmeshstate_t m;
911
912         if (fogenabled)
913         {
914                 VectorSubtract(origin, r_vieworigin, diff);
915                 ca *= 1 - exp(fogdensity/DotProduct(diff,diff));
916         }
917
918         R_Mesh_Matrix(&r_identitymatrix);
919         GL_Color(cr, cg, cb, ca);
920         GL_VertexPointer(varray_vertex3f);
921         GL_BlendFunc(blendfunc1, blendfunc2);
922         GL_DepthMask(false);
923         GL_DepthTest(!depthdisable);
924
925         memset(&m, 0, sizeof(m));
926         m.tex[0] = R_GetTexture(texture);
927         m.pointer_texcoord[0] = spritetexcoord2f;
928         R_Mesh_State_Texture(&m);
929
930         varray_vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
931         varray_vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
932         varray_vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
933         varray_vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
934         varray_vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
935         varray_vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
936         varray_vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
937         varray_vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
938         varray_vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
939         varray_vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
940         varray_vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
941         varray_vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
942         R_Mesh_Draw(4, 2, polygonelements);
943 }
944