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