a rather hefty 6% speed gain by getting rid of the R_Mesh_UpdateFarClip function...
[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
24 entity_render_t *currentrenderentity;
25
26 // used for dlight push checking and other things
27 int r_framecount;
28
29 mplane_t frustum[4];
30
31 int c_brush_polys, c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights;
32
33 // true during envmap command capture
34 qboolean envmap;
35
36 float r_farclip;
37
38 // view origin
39 vec3_t r_origin;
40 vec3_t vpn;
41 vec3_t vright;
42 vec3_t vup;
43
44 //
45 // screen size info
46 //
47 refdef_t r_refdef;
48
49 mleaf_t *r_viewleaf, *r_oldviewleaf;
50
51 // 8.8 fraction of base light value
52 unsigned short d_lightstylevalue[256];
53
54 cvar_t r_drawentities = {0, "r_drawentities","1"};
55 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1"};
56 cvar_t r_speeds = {0, "r_speeds","0"};
57 cvar_t r_fullbright = {0, "r_fullbright","0"};
58 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1"};
59 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1"};
60 cvar_t r_waterripple = {CVAR_SAVE, "r_waterripple","0"};
61 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1"};
62
63 cvar_t gl_fogenable = {0, "gl_fogenable", "0"};
64 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25"};
65 cvar_t gl_fogred = {0, "gl_fogred","0.3"};
66 cvar_t gl_foggreen = {0, "gl_foggreen","0.3"};
67 cvar_t gl_fogblue = {0, "gl_fogblue","0.3"};
68 cvar_t gl_fogstart = {0, "gl_fogstart", "0"};
69 cvar_t gl_fogend = {0, "gl_fogend","0"};
70
71 cvar_t r_multitexture = {0, "r_multitexture", "1"};
72
73 /*
74 ====================
75 R_TimeRefresh_f
76
77 For program optimization
78 ====================
79 */
80 qboolean intimerefresh = 0;
81 static void R_TimeRefresh_f (void)
82 {
83         int i;
84         float start, stop, time;
85
86         intimerefresh = 1;
87         start = Sys_DoubleTime ();
88         for (i = 0;i < 128;i++)
89         {
90                 r_refdef.viewangles[0] = 0;
91                 r_refdef.viewangles[1] = i/128.0*360.0;
92                 r_refdef.viewangles[2] = 0;
93                 CL_UpdateScreen();
94         }
95
96         stop = Sys_DoubleTime ();
97         intimerefresh = 0;
98         time = stop-start;
99         Con_Printf ("%f seconds (%f fps)\n", time, 128/time);
100 }
101
102 extern cvar_t r_drawportals;
103
104 int R_VisibleCullBox (vec3_t mins, vec3_t maxs)
105 {
106         int sides;
107         mnode_t *nodestack[8192], *node;
108         int stack = 0;
109
110         if (R_CullBox(mins, maxs))
111                 return true;
112
113         node = cl.worldmodel->nodes;
114 loc0:
115         if (node->contents < 0)
116         {
117                 if (((mleaf_t *)node)->visframe == r_framecount)
118                         return false;
119                 if (!stack)
120                         return true;
121                 node = nodestack[--stack];
122                 goto loc0;
123         }
124
125         sides = BOX_ON_PLANE_SIDE(mins, maxs, node->plane);
126
127 // recurse down the contacted sides
128         if (sides & 1)
129         {
130                 if (sides & 2) // 3
131                 {
132                         // put second child on the stack for later examination
133                         nodestack[stack++] = node->children[1];
134                         node = node->children[0];
135                         goto loc0;
136                 }
137                 else // 1
138                 {
139                         node = node->children[0];
140                         goto loc0;
141                 }
142         }
143         // 2
144         node = node->children[1];
145         goto loc0;
146 }
147
148 vec3_t fogcolor;
149 vec_t fogdensity;
150 float fog_density, fog_red, fog_green, fog_blue;
151 qboolean fogenabled;
152 qboolean oldgl_fogenable;
153 void R_SetupFog(void)
154 {
155         if (gamemode == GAME_NEHAHRA)
156         {
157                 if (gl_fogenable.integer)
158                 {
159                         oldgl_fogenable = true;
160                         fog_density = gl_fogdensity.value;
161                         fog_red = gl_fogred.value;
162                         fog_green = gl_foggreen.value;
163                         fog_blue = gl_fogblue.value;
164                 }
165                 else if (oldgl_fogenable)
166                 {
167                         oldgl_fogenable = false;
168                         fog_density = 0;
169                         fog_red = 0;
170                         fog_green = 0;
171                         fog_blue = 0;
172                 }
173         }
174         if (fog_density)
175         {
176                 fogcolor[0] = fog_red   = bound(0.0f, fog_red  , 1.0f);
177                 fogcolor[1] = fog_green = bound(0.0f, fog_green, 1.0f);
178                 fogcolor[2] = fog_blue  = bound(0.0f, fog_blue , 1.0f);
179         }
180         if (fog_density)
181         {
182                 fogenabled = true;
183                 fogdensity = -4000.0f / (fog_density * fog_density);
184                 // fog color was already set
185         }
186         else
187                 fogenabled = false;
188 }
189
190 // FIXME: move this to client?
191 void FOG_clear(void)
192 {
193         if (gamemode == GAME_NEHAHRA)
194         {
195                 Cvar_Set("gl_fogenable", "0");
196                 Cvar_Set("gl_fogdensity", "0.2");
197                 Cvar_Set("gl_fogred", "0.3");
198                 Cvar_Set("gl_foggreen", "0.3");
199                 Cvar_Set("gl_fogblue", "0.3");
200         }
201         fog_density = fog_red = fog_green = fog_blue = 0.0f;
202 }
203
204 // FIXME: move this to client?
205 void FOG_registercvars(void)
206 {
207         if (gamemode == GAME_NEHAHRA)
208         {
209                 Cvar_RegisterVariable (&gl_fogenable);
210                 Cvar_RegisterVariable (&gl_fogdensity);
211                 Cvar_RegisterVariable (&gl_fogred);
212                 Cvar_RegisterVariable (&gl_foggreen);
213                 Cvar_RegisterVariable (&gl_fogblue);
214                 Cvar_RegisterVariable (&gl_fogstart);
215                 Cvar_RegisterVariable (&gl_fogend);
216         }
217 }
218
219 void gl_main_start(void)
220 {
221 }
222
223 void gl_main_shutdown(void)
224 {
225 }
226
227 void gl_main_newmap(void)
228 {
229         r_framecount = 1;
230 }
231
232 void GL_Main_Init(void)
233 {
234 // FIXME: move this to client?
235         FOG_registercvars();
236         Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
237         Cvar_RegisterVariable (&r_drawentities);
238         Cvar_RegisterVariable (&r_drawviewmodel);
239         Cvar_RegisterVariable (&r_speeds);
240         Cvar_RegisterVariable (&r_fullbrights);
241         Cvar_RegisterVariable (&r_wateralpha);
242         Cvar_RegisterVariable (&r_dynamic);
243         Cvar_RegisterVariable (&r_waterripple);
244         Cvar_RegisterVariable (&r_fullbright);
245         Cvar_RegisterVariable (&r_multitexture);
246         if (gamemode == GAME_NEHAHRA)
247                 Cvar_SetValue("r_fullbrights", 0);
248         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
249 }
250
251 vec3_t r_farclip_origin;
252 vec3_t r_farclip_direction;
253 vec_t r_farclip_directiondist;
254 vec_t r_farclip_meshfarclip;
255 int r_farclip_directionbit0;
256 int r_farclip_directionbit1;
257 int r_farclip_directionbit2;
258
259 // start a farclip measuring session
260 void R_FarClip_Start(vec3_t origin, vec3_t direction, vec_t startfarclip)
261 {
262         VectorCopy(origin, r_farclip_origin);
263         VectorCopy(direction, r_farclip_direction);
264         r_farclip_directiondist = DotProduct(r_farclip_origin, r_farclip_direction);
265         r_farclip_directionbit0 = r_farclip_direction[0] < 0;
266         r_farclip_directionbit1 = r_farclip_direction[1] < 0;
267         r_farclip_directionbit2 = r_farclip_direction[2] < 0;
268         r_farclip_meshfarclip = r_farclip_directiondist + startfarclip;
269 }
270
271 // enlarge farclip to accomodate box
272 void R_FarClip_Box(vec3_t mins, vec3_t maxs)
273 {
274         float d;
275         d = (r_farclip_directionbit0 ? mins[0] : maxs[0]) * r_farclip_direction[0]
276           + (r_farclip_directionbit1 ? mins[1] : maxs[1]) * r_farclip_direction[1]
277           + (r_farclip_directionbit2 ? mins[2] : maxs[2]) * r_farclip_direction[2];
278         if (r_farclip_meshfarclip < d)
279                 r_farclip_meshfarclip = d;
280 }
281
282 // return farclip value
283 float R_FarClip_Finish(void)
284 {
285         return r_farclip_meshfarclip - r_farclip_directiondist;
286 }
287
288 /*
289 ===============
290 R_NewMap
291 ===============
292 */
293 void CL_ParseEntityLump(char *entitystring);
294 void R_NewMap (void)
295 {
296         int i;
297
298         for (i = 0;i < 256;i++)
299                 d_lightstylevalue[i] = 264;             // normal light value
300
301         r_viewleaf = NULL;
302         if (cl.worldmodel->entities)
303                 CL_ParseEntityLump(cl.worldmodel->entities);
304         R_Modules_NewMap();
305
306         r_farclip = 64.0f;
307 }
308
309 extern void R_Textures_Init(void);
310 extern void Mod_RenderInit(void);
311 extern void GL_Draw_Init(void);
312 extern void GL_Main_Init(void);
313 extern void GL_Models_Init(void);
314 extern void R_Sky_Init(void);
315 extern void GL_Surf_Init(void);
316 extern void R_Crosshairs_Init(void);
317 extern void R_Light_Init(void);
318 extern void R_Particles_Init(void);
319 extern void R_Explosion_Init(void);
320 extern void ui_init(void);
321 extern void gl_backend_init(void);
322
323 void Render_Init(void)
324 {
325         R_Modules_Shutdown();
326         R_Textures_Init();
327         Mod_RenderInit();
328         gl_backend_init();
329         GL_Draw_Init();
330         GL_Main_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         R_Modules_Start();
340 }
341
342 /*
343 ===============
344 GL_Init
345 ===============
346 */
347 extern char *ENGINE_EXTENSIONS;
348 void GL_Init (void)
349 {
350         VID_CheckExtensions();
351
352         // LordHavoc: report supported extensions
353         Con_Printf ("\nengine extensions: %s\n", ENGINE_EXTENSIONS);
354
355         qglCullFace(GL_FRONT);
356         qglEnable(GL_TEXTURE_2D);
357 }
358
359
360 //==================================================================================
361
362 static void R_MarkEntities (void)
363 {
364         int i;
365         vec3_t v;
366
367         if (!r_drawentities.integer)
368                 return;
369
370         R_FarClip_Box(cl.worldmodel->normalmins, cl.worldmodel->normalmaxs);
371
372         for (i = 0;i < r_refdef.numentities;i++)
373         {
374                 currentrenderentity = r_refdef.entities[i];
375                 Mod_CheckLoaded(currentrenderentity->model);
376
377                 // move view-relative models to where they should be
378                 if (currentrenderentity->flags & RENDER_VIEWMODEL)
379                 {
380                         // remove flag so it will not be repeated incase RelinkEntities is not called again for a while
381                         currentrenderentity->flags -= RENDER_VIEWMODEL;
382                         // transform origin
383                         VectorCopy(currentrenderentity->origin, v);
384                         currentrenderentity->origin[0] = v[0] * vpn[0] + v[1] * vright[0] + v[2] * vup[0] + r_origin[0];
385                         currentrenderentity->origin[1] = v[0] * vpn[1] + v[1] * vright[1] + v[2] * vup[1] + r_origin[1];
386                         currentrenderentity->origin[2] = v[0] * vpn[2] + v[1] * vright[2] + v[2] * vup[2] + r_origin[2];
387                         // adjust angles
388                         VectorAdd(currentrenderentity->angles, r_refdef.viewangles, currentrenderentity->angles);
389                 }
390
391                 if (currentrenderentity->angles[0] || currentrenderentity->angles[2])
392                 {
393                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->rotatedmins, currentrenderentity->mins);
394                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->rotatedmaxs, currentrenderentity->maxs);
395                 }
396                 else if (currentrenderentity->angles[1])
397                 {
398                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->yawmins, currentrenderentity->mins);
399                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->yawmaxs, currentrenderentity->maxs);
400                 }
401                 else
402                 {
403                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->normalmins, currentrenderentity->mins);
404                         VectorMA(currentrenderentity->origin, currentrenderentity->scale, currentrenderentity->model->normalmaxs, currentrenderentity->maxs);
405                 }
406                 if (R_VisibleCullBox(currentrenderentity->mins, currentrenderentity->maxs))
407                         continue;
408
409                 R_LerpAnimation(currentrenderentity);
410                 currentrenderentity->visframe = r_framecount;
411
412                 R_FarClip_Box(currentrenderentity->mins, currentrenderentity->maxs);
413         }
414 }
415
416 // only used if skyrendermasked, and normally returns false
417 int R_DrawBModelSky (void)
418 {
419         int i, sky;
420
421         if (!r_drawentities.integer)
422                 return false;
423
424         sky = false;
425         for (i = 0;i < r_refdef.numentities;i++)
426         {
427                 currentrenderentity = r_refdef.entities[i];
428                 if (currentrenderentity->visframe == r_framecount && currentrenderentity->model->DrawSky)
429                 {
430                         currentrenderentity->model->DrawSky();
431                         sky = true;
432                 }
433         }
434         return sky;
435 }
436
437 void R_DrawModels (void)
438 {
439         int i;
440
441         if (!r_drawentities.integer)
442                 return;
443
444         for (i = 0;i < r_refdef.numentities;i++)
445         {
446                 currentrenderentity = r_refdef.entities[i];
447                 if (currentrenderentity->visframe == r_framecount && currentrenderentity->model->Draw)
448                         currentrenderentity->model->Draw();
449         }
450 }
451
452 /*
453 =============
454 R_DrawViewModel
455 =============
456 */
457 void R_DrawViewModel (void)
458 {
459         // FIXME: move these checks to client
460         if (!r_drawviewmodel.integer || chase_active.integer || envmap || !r_drawentities.integer || cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0 || !cl.viewent.render.model)
461                 return;
462
463         currentrenderentity = &cl.viewent.render;
464         Mod_CheckLoaded(currentrenderentity->model);
465
466         R_LerpAnimation(currentrenderentity);
467
468         currentrenderentity->model->Draw();
469 }
470
471 static void R_SetFrustum (void)
472 {
473         int i;
474
475         // LordHavoc: note to all quake engine coders, the special case for 90
476         // degrees assumed a square view (wrong), so I removed it, Quake2 has it
477         // disabled as well.
478         // rotate VPN right by FOV_X/2 degrees
479         RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );
480         // rotate VPN left by FOV_X/2 degrees
481         RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );
482         // rotate VPN up by FOV_X/2 degrees
483         RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );
484         // rotate VPN down by FOV_X/2 degrees
485         RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );
486
487         for (i = 0;i < 4;i++)
488         {
489                 frustum[i].type = PLANE_ANYZ;
490                 frustum[i].dist = DotProduct (r_origin, frustum[i].normal);
491                 PlaneClassify(&frustum[i]);
492         }
493 }
494
495 /*
496 ===============
497 R_SetupFrame
498 ===============
499 */
500 static void R_SetupFrame (void)
501 {
502 // don't allow cheats in multiplayer
503         if (cl.maxclients > 1)
504         {
505                 if (r_fullbright.integer != 0)
506                         Cvar_Set ("r_fullbright", "0");
507                 if (r_ambient.value != 0)
508                         Cvar_Set ("r_ambient", "0");
509         }
510         if (r_multitexture.integer && gl_textureunits < 2)
511                 Cvar_SetValue("r_multitexture", 0);
512
513         r_framecount++;
514
515 // build the transformation matrix for the given view angles
516         VectorCopy (r_refdef.vieworg, r_origin);
517
518         AngleVectors (r_refdef.viewangles, vpn, vright, vup);
519
520 // current viewleaf
521         r_oldviewleaf = r_viewleaf;
522         r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
523
524         R_AnimateLight ();
525 }
526
527
528 static int blendviewpolyindex[3] = {0, 1, 2};
529
530 static void R_BlendView(void)
531 {
532         rmeshinfo_t m;
533         float tvxyz[3][4], r;
534
535         if (r_refdef.viewblend[3] < 0.01f)
536                 return;
537
538         memset(&m, 0, sizeof(m));
539         m.transparent = false;
540         m.blendfunc1 = GL_SRC_ALPHA;
541         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
542         m.depthdisable = true; // magic
543         m.numtriangles = 1;
544         m.numverts = 3;
545         m.index = blendviewpolyindex;
546         m.vertex = &tvxyz[0][0];
547         m.vertexstep = sizeof(float[4]);
548         m.cr = r_refdef.viewblend[0];
549         m.cg = r_refdef.viewblend[1];
550         m.cb = r_refdef.viewblend[2];
551         m.ca = r_refdef.viewblend[3];
552         r = 64000;
553         tvxyz[0][0] = r_origin[0] + vpn[0] * 1.5 - vright[0] * r - vup[0] * r;
554         tvxyz[0][1] = r_origin[1] + vpn[1] * 1.5 - vright[1] * r - vup[1] * r;
555         tvxyz[0][2] = r_origin[2] + vpn[2] * 1.5 - vright[2] * r - vup[2] * r;
556         r *= 3;
557         tvxyz[1][0] = tvxyz[0][0] + vup[0] * r;
558         tvxyz[1][1] = tvxyz[0][1] + vup[1] * r;
559         tvxyz[1][2] = tvxyz[0][2] + vup[2] * r;
560         tvxyz[2][0] = tvxyz[0][0] + vright[0] * r;
561         tvxyz[2][1] = tvxyz[0][1] + vright[1] * r;
562         tvxyz[2][2] = tvxyz[0][2] + vright[2] * r;
563         R_Mesh_Draw(&m);
564 }
565
566 /*
567 ================
568 R_RenderView
569
570 r_refdef must be set before the first call
571 ================
572 */
573 void R_RenderView (void)
574 {
575         if (!cl.worldmodel)
576                 return; //Host_Error ("R_RenderView: NULL worldmodel");
577
578         // FIXME: move to client
579         R_MoveExplosions();
580         R_TimeReport("mexplosion");
581
582         R_SetupFrame();
583         R_SetFrustum();
584         R_SetupFog();
585         R_SkyStartFrame();
586         R_BuildLightList();
587
588         R_FarClip_Start(r_origin, vpn, 768.0f);
589
590         R_TimeReport("setup");
591
592         R_DrawWorld();
593         R_TimeReport("worldnode");
594
595         R_MarkEntities();
596         R_TimeReport("markentity");
597
598         R_MarkWorldLights();
599         R_TimeReport("marklights");
600
601         r_farclip = R_FarClip_Finish() + 256.0f;
602
603         R_Mesh_Start(r_farclip);
604
605         if (skyrendermasked)
606         {
607                 if (R_DrawBModelSky())
608                         R_TimeReport("bmodelsky");
609         }
610         else
611         {
612                 R_DrawViewModel();
613                 R_TimeReport("viewmodel");
614         }
615
616         R_SetupForWorldRendering();
617         R_PrepareSurfaces();
618         R_TimeReport("surfprep");
619
620         R_DrawSurfaces(SHADERSTAGE_SKY);
621         R_DrawSurfaces(SHADERSTAGE_NORMAL);
622         R_TimeReport("surfdraw");
623
624         if (r_drawportals.integer)
625         {
626                 R_DrawPortals();
627                 R_TimeReport("portals");
628         }
629
630         // don't let sound skip if going slow
631         if (!intimerefresh && !r_speeds.integer)
632                 S_ExtraUpdate ();
633
634         if (skyrendermasked)
635         {
636                 R_DrawViewModel();
637                 R_TimeReport("viewmodel");
638         }
639
640         R_DrawModels();
641         R_TimeReport("models");
642
643         R_DrawParticles();
644         R_TimeReport("particles");
645
646         R_DrawExplosions();
647         R_TimeReport("explosions");
648
649         // draw transparent meshs
650         R_Mesh_AddTransparent();
651         R_TimeReport("addtrans");
652
653         R_DrawCoronas();
654         R_TimeReport("coronas");
655
656         R_BlendView();
657         R_TimeReport("blendview");
658
659         R_DrawCrosshair();
660         R_TimeReport("crosshair");
661
662         // render any queued meshs
663         R_Mesh_Finish();
664         R_TimeReport("meshfinish");
665 }
666