aboutsummaryrefslogtreecommitdiff
path: root/src/r_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/r_main.c')
-rw-r--r--src/r_main.c649
1 files changed, 649 insertions, 0 deletions
diff --git a/src/r_main.c b/src/r_main.c
new file mode 100644
index 0000000..cab5997
--- /dev/null
+++ b/src/r_main.c
@@ -0,0 +1,649 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Rendering main loop and setup functions,
31 * utility functions (BSP, geometry, trigonometry).
32 * See tables.c, too.
33 *
34 *-----------------------------------------------------------------------------*/
35
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40#ifdef USE_SDL
41#include "SDL.h"
42#endif
43#include "doomstat.h"
44#include "d_net.h"
45#include "w_wad.h"
46#include "r_main.h"
47#include "r_things.h"
48#include "r_plane.h"
49#include "r_bsp.h"
50#include "r_draw.h"
51#include "m_bbox.h"
52#include "r_sky.h"
53#include "v_video.h"
54#include "lprintf.h"
55#include "st_stuff.h"
56#include "i_main.h"
57#include "i_system.h"
58#include "g_game.h"
59#include "r_demo.h"
60#include "r_fps.h"
61
62// Fineangles in the SCREENWIDTH wide window.
63#define FIELDOFVIEW 2048
64
65// killough: viewangleoffset is a legacy from the pre-v1.2 days, when Doom
66// had Left/Mid/Right viewing. +/-ANG90 offsets were placed here on each
67// node, by d_net.c, to set up a L/M/R session.
68
69int viewangleoffset;
70int validcount = 1; // increment every time a check is made
71const lighttable_t *fixedcolormap;
72int centerx, centery;
73fixed_t centerxfrac, centeryfrac;
74fixed_t viewheightfrac; //e6y: for correct clipping of things
75fixed_t projection;
76// proff 11/06/98: Added for high-res
77fixed_t projectiony;
78fixed_t viewx, viewy, viewz;
79angle_t viewangle;
80fixed_t viewcos, viewsin;
81player_t *viewplayer;
82extern lighttable_t **walllights;
83
84static mobj_t *oviewer;
85
86//
87// precalculated math tables
88//
89
90angle_t clipangle;
91
92// The viewangletox[viewangle + FINEANGLES/4] lookup
93// maps the visible view angles to screen X coordinates,
94// flattening the arc to a flat projection plane.
95// There will be many angles mapped to the same X.
96
97int viewangletox[FINEANGLES/2];
98
99// The xtoviewangleangle[] table maps a screen pixel
100// to the lowest viewangle that maps back to x ranges
101// from clipangle to -clipangle.
102
103angle_t xtoviewangle[MAX_SCREENWIDTH+1]; // killough 2/8/98
104
105// killough 3/20/98: Support dynamic colormaps, e.g. deep water
106// killough 4/4/98: support dynamic number of them as well
107
108int numcolormaps;
109const lighttable_t *(*c_zlight)[LIGHTLEVELS][MAXLIGHTZ];
110const lighttable_t *(*zlight)[MAXLIGHTZ];
111const lighttable_t *fullcolormap;
112const lighttable_t **colormaps;
113
114// killough 3/20/98, 4/4/98: end dynamic colormaps
115
116int extralight; // bumped light from gun blasts
117
118//
119// R_PointOnSide
120// Traverse BSP (sub) tree,
121// check point against partition plane.
122// Returns side 0 (front) or 1 (back).
123//
124// killough 5/2/98: reformatted
125//
126
127PUREFUNC int R_PointOnSide(fixed_t x, fixed_t y, const node_t *node)
128{
129 if (!node->dx)
130 return x <= node->x ? node->dy > 0 : node->dy < 0;
131
132 if (!node->dy)
133 return y <= node->y ? node->dx < 0 : node->dx > 0;
134
135 x -= node->x;
136 y -= node->y;
137
138 // Try to quickly decide by looking at sign bits.
139 if ((node->dy ^ node->dx ^ x ^ y) < 0)
140 return (node->dy ^ x) < 0; // (left is negative)
141 return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x);
142}
143
144// killough 5/2/98: reformatted
145
146PUREFUNC int R_PointOnSegSide(fixed_t x, fixed_t y, const seg_t *line)
147{
148 fixed_t lx = line->v1->x;
149 fixed_t ly = line->v1->y;
150 fixed_t ldx = line->v2->x - lx;
151 fixed_t ldy = line->v2->y - ly;
152
153 if (!ldx)
154 return x <= lx ? ldy > 0 : ldy < 0;
155
156 if (!ldy)
157 return y <= ly ? ldx < 0 : ldx > 0;
158
159 x -= lx;
160 y -= ly;
161
162 // Try to quickly decide by looking at sign bits.
163 if ((ldy ^ ldx ^ x ^ y) < 0)
164 return (ldy ^ x) < 0; // (left is negative)
165 return FixedMul(y, ldx>>FRACBITS) >= FixedMul(ldy>>FRACBITS, x);
166}
167
168//
169// R_PointToAngle
170// To get a global angle from cartesian coordinates,
171// the coordinates are flipped until they are in
172// the first octant of the coordinate system, then
173// the y (<=x) is scaled and divided by x to get a
174// tangent (slope) value which is looked up in the
175// tantoangle[] table. The +1 size of tantoangle[]
176// is to handle the case when x==y without additional
177// checking.
178//
179// killough 5/2/98: reformatted, cleaned up
180
181#include <math.h>
182
183angle_t R_PointToAngle(fixed_t x, fixed_t y)
184{
185 static fixed_t oldx, oldy;
186 static angle_t oldresult;
187
188 x -= viewx; y -= viewy;
189
190 if ( /* !render_precise && */
191 // e6y: here is where "slime trails" can SOMETIMES occur
192#ifdef GL_DOOM
193 (V_GetMode() != VID_MODEGL) &&
194#endif
195 (x < INT_MAX/4 && x > -INT_MAX/4 && y < INT_MAX/4 && y > -INT_MAX/4)
196 )
197 {
198 // old R_PointToAngle
199 return (x || y) ?
200 x >= 0 ?
201 y >= 0 ?
202 (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0
203 ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1
204 x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8
205 ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7
206 y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3
207 ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2
208 (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4
209 ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5
210 0;
211 }
212
213 // R_PointToAngleEx merged into R_PointToAngle
214 // e6y: The precision of the code above is abysmal so use the CRT atan2 function instead!
215 if (oldx != x || oldy != y)
216 {
217 oldx = x;
218 oldy = y;
219 oldresult = (int)(atan2(y, x) * ANG180/M_PI);
220 }
221 return oldresult;
222}
223
224angle_t R_PointToAngle2(fixed_t viewx, fixed_t viewy, fixed_t x, fixed_t y)
225{
226 return (y -= viewy, (x -= viewx) || y) ?
227 x >= 0 ?
228 y >= 0 ?
229 (x > y) ? tantoangle[SlopeDiv(y,x)] : // octant 0
230 ANG90-1-tantoangle[SlopeDiv(x,y)] : // octant 1
231 x > (y = -y) ? 0-tantoangle[SlopeDiv(y,x)] : // octant 8
232 ANG270+tantoangle[SlopeDiv(x,y)] : // octant 7
233 y >= 0 ? (x = -x) > y ? ANG180-1-tantoangle[SlopeDiv(y,x)] : // octant 3
234 ANG90 + tantoangle[SlopeDiv(x,y)] : // octant 2
235 (x = -x) > (y = -y) ? ANG180+tantoangle[ SlopeDiv(y,x)] : // octant 4
236 ANG270-1-tantoangle[SlopeDiv(x,y)] : // octant 5
237 0;
238}
239
240//
241// R_InitTextureMapping
242//
243// killough 5/2/98: reformatted
244
245static void R_InitTextureMapping (void)
246{
247 register int i,x;
248 fixed_t focallength;
249
250 // Use tangent table to generate viewangletox:
251 // viewangletox will give the next greatest x
252 // after the view angle.
253 //
254 // Calc focallength
255 // so FIELDOFVIEW angles covers SCREENWIDTH.
256
257 focallength = FixedDiv(centerxfrac, finetangent[FINEANGLES/4+FIELDOFVIEW/2]);
258
259 for (i=0 ; i<FINEANGLES/2 ; i++)
260 {
261 int t;
262 if (finetangent[i] > FRACUNIT*2)
263 t = -1;
264 else
265 if (finetangent[i] < -FRACUNIT*2)
266 t = viewwidth+1;
267 else
268 {
269 t = FixedMul(finetangent[i], focallength);
270 t = (centerxfrac - t + FRACUNIT-1) >> FRACBITS;
271 if (t < -1)
272 t = -1;
273 else
274 if (t > viewwidth+1)
275 t = viewwidth+1;
276 }
277 viewangletox[i] = t;
278 }
279
280 // Scan viewangletox[] to generate xtoviewangle[]:
281 // xtoviewangle will give the smallest view angle
282 // that maps to x.
283
284 for (x=0; x<=viewwidth; x++)
285 {
286 for (i=0; viewangletox[i] > x; i++)
287 ;
288 xtoviewangle[x] = (i<<ANGLETOFINESHIFT)-ANG90;
289 }
290
291 // Take out the fencepost cases from viewangletox.
292 for (i=0; i<FINEANGLES/2; i++)
293 if (viewangletox[i] == -1)
294 viewangletox[i] = 0;
295 else
296 if (viewangletox[i] == viewwidth+1)
297 viewangletox[i] = viewwidth;
298
299 clipangle = xtoviewangle[0];
300}
301
302//
303// R_InitLightTables
304//
305
306#define DISTMAP 2
307
308static void R_InitLightTables (void)
309{
310 int i;
311
312 // killough 4/4/98: dynamic colormaps
313 c_zlight = malloc(sizeof(*c_zlight) * numcolormaps);
314
315 // Calculate the light levels to use
316 // for each level / distance combination.
317 for (i=0; i< LIGHTLEVELS; i++)
318 {
319 int j, startmap = ((LIGHTLEVELS-1-i)*2)*NUMCOLORMAPS/LIGHTLEVELS;
320 for (j=0; j<MAXLIGHTZ; j++)
321 {
322 // CPhipps - use 320 here instead of SCREENWIDTH, otherwise hires is
323 // brighter than normal res
324 int scale = FixedDiv ((320/2*FRACUNIT), (j+1)<<LIGHTZSHIFT);
325 int t, level = startmap - (scale >>= LIGHTSCALESHIFT)/DISTMAP;
326
327 if (level < 0)
328 level = 0;
329 else
330 if (level >= NUMCOLORMAPS)
331 level = NUMCOLORMAPS-1;
332
333 // killough 3/20/98: Initialize multiple colormaps
334 level *= 256;
335 for (t=0; t<numcolormaps; t++) // killough 4/4/98
336 c_zlight[t][i][j] = colormaps[t] + level;
337 }
338 }
339}
340
341//
342// R_SetViewSize
343// Do not really change anything here,
344// because it might be in the middle of a refresh.
345// The change will take effect next refresh.
346//
347
348boolean setsizeneeded;
349int setblocks;
350
351void R_SetViewSize(int blocks)
352{
353 setsizeneeded = true;
354 setblocks = blocks;
355}
356
357//
358// R_ExecuteSetViewSize
359//
360
361void R_ExecuteSetViewSize (void)
362{
363 int i;
364
365 setsizeneeded = false;
366
367 if (setblocks == 11)
368 {
369 scaledviewwidth = SCREENWIDTH;
370 viewheight = SCREENHEIGHT;
371 }
372// proff 09/24/98: Added for high-res
373 else if (setblocks == 10)
374 {
375 scaledviewwidth = SCREENWIDTH;
376 viewheight = SCREENHEIGHT-ST_SCALED_HEIGHT;
377 }
378 else
379 {
380// proff 08/17/98: Changed for high-res
381 scaledviewwidth = setblocks*SCREENWIDTH/10;
382 viewheight = (setblocks*(SCREENHEIGHT-ST_SCALED_HEIGHT)/10) & ~7;
383 }
384
385 viewwidth = scaledviewwidth;
386
387 viewheightfrac = viewheight<<FRACBITS;//e6y
388
389 centery = viewheight/2;
390 centerx = viewwidth/2;
391 centerxfrac = centerx<<FRACBITS;
392 centeryfrac = centery<<FRACBITS;
393 projection = centerxfrac;
394// proff 11/06/98: Added for high-res
395 projectiony = ((SCREENHEIGHT * centerx * 320) / 200) / SCREENWIDTH * FRACUNIT;
396
397 R_InitBuffer (scaledviewwidth, viewheight);
398
399 R_InitTextureMapping();
400
401 // psprite scales
402// proff 08/17/98: Changed for high-res
403 pspritescale = FRACUNIT*viewwidth/320;
404 pspriteiscale = FRACUNIT*320/viewwidth;
405// proff 11/06/98: Added for high-res
406 pspriteyscale = (((SCREENHEIGHT*viewwidth)/SCREENWIDTH) << FRACBITS) / 200;
407
408 // thing clipping
409 for (i=0 ; i<viewwidth ; i++)
410 screenheightarray[i] = viewheight;
411
412 // planes
413 for (i=0 ; i<viewheight ; i++)
414 { // killough 5/2/98: reformatted
415 fixed_t dy = D_abs(((i-viewheight/2)<<FRACBITS)+FRACUNIT/2);
416// proff 08/17/98: Changed for high-res
417 yslope[i] = FixedDiv(projectiony, dy);
418 }
419
420 for (i=0 ; i<viewwidth ; i++)
421 {
422 fixed_t cosadj = D_abs(finecosine[xtoviewangle[i]>>ANGLETOFINESHIFT]);
423 distscale[i] = FixedDiv(FRACUNIT,cosadj);
424 }
425
426}
427
428//
429// R_Init
430//
431
432extern int screenblocks;
433
434void R_Init (void)
435{
436 // CPhipps - R_DrawColumn isn't constant anymore, so must
437 // initialise in code
438 // current column draw function
439 lprintf(LO_INFO, "\nR_LoadTrigTables: ");
440 R_LoadTrigTables();
441 lprintf(LO_INFO, "\nR_InitData: ");
442 R_InitData();
443 R_SetViewSize(screenblocks);
444 lprintf(LO_INFO, "\nR_Init: R_InitPlanes ");
445 R_InitPlanes();
446 lprintf(LO_INFO, "R_InitLightTables ");
447 R_InitLightTables();
448 lprintf(LO_INFO, "R_InitSkyMap ");
449 R_InitSkyMap();
450 lprintf(LO_INFO, "R_InitTranslationsTables ");
451 R_InitTranslationTables();
452 lprintf(LO_INFO, "R_InitPatches ");
453 R_InitPatches();
454}
455
456//
457// R_PointInSubsector
458//
459// killough 5/2/98: reformatted, cleaned up
460
461subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
462{
463 int nodenum = numnodes-1;
464
465 // special case for trivial maps (single subsector, no nodes)
466 if (numnodes == 0)
467 return subsectors;
468
469 while (!(nodenum & NF_SUBSECTOR))
470 nodenum = nodes[nodenum].children[R_PointOnSide(x, y, nodes+nodenum)];
471 return &subsectors[nodenum & ~NF_SUBSECTOR];
472}
473
474//
475// R_SetupFrame
476//
477
478static void R_SetupFrame (player_t *player)
479{
480 int cm;
481 boolean NoInterpolate = paused || (menuactive && !demoplayback);
482
483 viewplayer = player;
484
485 if (player->mo != oviewer || NoInterpolate)
486 {
487 R_ResetViewInterpolation ();
488 oviewer = player->mo;
489 }
490 tic_vars.frac = I_GetTimeFrac ();
491 if (NoInterpolate)
492 tic_vars.frac = FRACUNIT;
493 R_InterpolateView (player, tic_vars.frac);
494
495 extralight = player->extralight;
496
497 viewsin = finesine[viewangle>>ANGLETOFINESHIFT];
498 viewcos = finecosine[viewangle>>ANGLETOFINESHIFT];
499
500 R_DoInterpolations(tic_vars.frac);
501
502 // killough 3/20/98, 4/4/98: select colormap based on player status
503
504 if (player->mo->subsector->sector->heightsec != -1)
505 {
506 const sector_t *s = player->mo->subsector->sector->heightsec + sectors;
507 cm = viewz < s->floorheight ? s->bottommap : viewz > s->ceilingheight ?
508 s->topmap : s->midmap;
509 if (cm < 0 || cm > numcolormaps)
510 cm = 0;
511 }
512 else
513 cm = 0;
514
515 fullcolormap = colormaps[cm];
516 zlight = c_zlight[cm];
517
518 if (player->fixedcolormap)
519 {
520 fixedcolormap = fullcolormap // killough 3/20/98: use fullcolormap
521 + player->fixedcolormap*256*sizeof(lighttable_t);
522 }
523 else
524 fixedcolormap = 0;
525
526 validcount++;
527}
528
529int autodetect_hom = 0; // killough 2/7/98: HOM autodetection flag
530
531//
532// R_ShowStats
533//
534int rendered_visplanes, rendered_segs, rendered_vissprites;
535boolean rendering_stats;
536
537static void R_ShowStats(void)
538{
539//e6y
540#if USE_SDL
541 static unsigned int FPS_SavedTick = 0, FPS_FrameCount = 0;
542 unsigned int tick = SDL_GetTicks();
543 FPS_FrameCount++;
544 if(tick >= FPS_SavedTick + 1000)
545 {
546 doom_printf((V_GetMode() == VID_MODEGL)
547 ?"Frame rate %d fps\nWalls %d, Flats %d, Sprites %d"
548 :"Frame rate %d fps\nSegs %d, Visplanes %d, Sprites %d",
549 1000 * FPS_FrameCount / (tick - FPS_SavedTick), rendered_segs,
550 rendered_visplanes, rendered_vissprites);
551 FPS_SavedTick = tick;
552 FPS_FrameCount = 0;
553 }
554#else
555
556#define KEEPTIMES 10
557 static int keeptime[KEEPTIMES], showtime;
558 int now = I_GetTime();
559
560 if (now - showtime > 35) {
561 doom_printf((V_GetMode() == VID_MODEGL)
562 ?"Frame rate %d fps\nWalls %d, Flats %d, Sprites %d"
563 :"Frame rate %d fps\nSegs %d, Visplanes %d, Sprites %d",
564 (35*KEEPTIMES)/(now - keeptime[0]), rendered_segs,
565 rendered_visplanes, rendered_vissprites);
566 showtime = now;
567 }
568 memmove(keeptime, keeptime+1, sizeof(keeptime[0]) * (KEEPTIMES-1));
569 keeptime[KEEPTIMES-1] = now;
570
571#endif //e6y
572}
573
574//
575// R_RenderView
576//
577void R_RenderPlayerView (player_t* player)
578{
579 R_SetupFrame (player);
580
581 // Clear buffers.
582 R_ClearClipSegs ();
583 R_ClearDrawSegs ();
584 R_ClearPlanes ();
585 R_ClearSprites ();
586
587 rendered_segs = rendered_visplanes = 0;
588 if (V_GetMode() == VID_MODEGL)
589 {
590#ifdef GL_DOOM
591 // proff 11/99: clear buffers
592 gld_InitDrawScene();
593 // proff 11/99: switch to perspective mode
594 gld_StartDrawScene();
595#endif
596 } else {
597 if (autodetect_hom)
598 { // killough 2/10/98: add flashing red HOM indicators
599 unsigned char color=(gametic % 20) < 9 ? 0xb0 : 0;
600 V_FillRect(0, viewwindowx, viewwindowy, viewwidth, viewheight, color);
601 R_DrawViewBorder();
602 }
603 }
604
605 // check for new console commands.
606#ifdef HAVE_NET
607 NetUpdate ();
608#endif
609
610 // The head node is the last node output.
611 R_RenderBSPNode (numnodes-1);
612 R_ResetColumnBuffer();
613
614 // Check for new console commands.
615#ifdef HAVE_NET
616 NetUpdate ();
617#endif
618
619 if (V_GetMode() != VID_MODEGL)
620 R_DrawPlanes ();
621
622 // Check for new console commands.
623#ifdef HAVE_NET
624 NetUpdate ();
625#endif
626
627 if (V_GetMode() != VID_MODEGL) {
628 R_DrawMasked ();
629 R_ResetColumnBuffer();
630 }
631
632 // Check for new console commands.
633#ifdef HAVE_NET
634 NetUpdate ();
635#endif
636
637 if (V_GetMode() == VID_MODEGL) {
638#ifdef GL_DOOM
639 // proff 11/99: draw the scene
640 gld_DrawScene(player);
641 // proff 11/99: finishing off
642 gld_EndDrawScene();
643#endif
644 }
645
646 if (rendering_stats) R_ShowStats();
647
648 R_RestoreInterpolations();
649}