1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
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
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 * Here is a core component: drawing the floors and ceilings,
29 * while maintaining a per column clipping list only.
30 * Moreover, the sky areas have to be determined.
32 * MAXVISPLANES is no longer a limit on the number of visplanes,
33 * but a limit on the number of hash slots; larger numbers mean
34 * better performance usually but after a point they are wasted,
35 * and memory and time overheads creep in.
37 * For more information on visplanes, see:
39 * http://classicgaming.com/doom/editing/
43 *-----------------------------------------------------------------------------*/
45 #include "z_zone.h" /* memory allocation wrappers -- killough */
54 #include "rockmacros.h"
56 #define MAXVISPLANES 128 /* must be a power of 2 */
58 static visplane_t
*visplanes
[MAXVISPLANES
] IBSS_ATTR
; // killough
59 static visplane_t
*freetail
; // killough
60 static visplane_t
**freehead
= &freetail
; // killough
61 visplane_t
*floorplane
, *ceilingplane
;
63 // killough -- hash function for visplanes
64 // Empirically verified to be fairly uniform:
66 #define visplane_hash(picnum,lightlevel,height) \
67 ((unsigned)((picnum)*3+(lightlevel)+(height)*7) & (MAXVISPLANES-1))
70 short *openings
,*lastopening
;
72 // Clip values are the solid pixel bounding the range.
73 // floorclip starts out SCREENHEIGHT
74 // ceilingclip starts out -1
76 short floorclip
[MAX_SCREENWIDTH
], ceilingclip
[MAX_SCREENWIDTH
];
78 // spanstart holds the start of a plane span; initialized to 0 at start
80 static int spanstart
[MAX_SCREENHEIGHT
]; // killough 2/8/98
86 static lighttable_t
**planezlight
;
87 static fixed_t planeheight
;
89 // killough 2/8/98: make variables static
91 static fixed_t basexscale
, baseyscale
;
92 static fixed_t cachedheight
[MAX_SCREENHEIGHT
];
93 static fixed_t cacheddistance
[MAX_SCREENHEIGHT
];
94 static fixed_t cachedxstep
[MAX_SCREENHEIGHT
];
95 static fixed_t cachedystep
[MAX_SCREENHEIGHT
];
96 static fixed_t xoffs
, yoffs
; // killough 2/28/98: flat offsets
98 fixed_t yslope
[MAX_SCREENHEIGHT
], distscale
[MAX_SCREENWIDTH
];
102 // Only at game startup.
104 void R_InitPlanes (void)
124 static void R_MapPlane(int y
, int x1
, int x2
)
127 fixed_t distance
, length
;
132 if (x2
< x1
|| x1
<0 || x2
>=viewwidth
|| (unsigned)y
>(unsigned)viewheight
)
133 I_Error ("R_MapPlane: %i, %i at %i",x1
,x2
,y
);
136 if (planeheight
!= cachedheight
[y
])
138 cachedheight
[y
] = planeheight
;
139 distance
= cacheddistance
[y
] = FixedMul (planeheight
, yslope
[y
]);
140 ds_xstep
= cachedxstep
[y
] = FixedMul (distance
,basexscale
);
141 ds_ystep
= cachedystep
[y
] = FixedMul (distance
,baseyscale
);
145 distance
= cacheddistance
[y
];
146 ds_xstep
= cachedxstep
[y
];
147 ds_ystep
= cachedystep
[y
];
150 length
= FixedMul (distance
,distscale
[x1
]);
151 angle
= (viewangle
+ xtoviewangle
[x1
])>>ANGLETOFINESHIFT
;
153 // killough 2/28/98: Add offsets
154 ds_xfrac
= viewx
+ FixedMul(finecosine
[angle
], length
) + xoffs
;
155 ds_yfrac
= -viewy
- FixedMul(finesine
[angle
], length
) + yoffs
;
157 if (!(ds_colormap
= fixedcolormap
))
159 index
= distance
>> LIGHTZSHIFT
;
160 if (index
>= MAXLIGHTZ
)
162 ds_colormap
= planezlight
[index
];
174 // At begining of frame.
177 void R_ClearPlanes(void)
182 // opening / clipping determination
183 for (i
=0 ; i
<viewwidth
; i
++)
184 floorclip
[i
] = viewheight
, ceilingclip
[i
] = -1;
186 for (i
=0;i
<MAXVISPLANES
;i
++) // new code -- killough
187 for (*freehead
= visplanes
[i
], visplanes
[i
] = NULL
; *freehead
; )
188 freehead
= &(*freehead
)->next
;
190 lastopening
= openings
;
192 // texture calculation
193 memset (cachedheight
, 0, sizeof(cachedheight
));
195 // left to right mapping
196 angle
= (viewangle
-ANG90
)>>ANGLETOFINESHIFT
;
198 // scale will be unit scale at SCREENWIDTH/2 distance
199 basexscale
= FixedDiv (finecosine
[angle
],centerxfrac
);
200 baseyscale
= -FixedDiv (finesine
[angle
],centerxfrac
);
203 // New function, by Lee Killough
205 static visplane_t
*new_visplane(unsigned hash
)
207 visplane_t
*check
= freetail
;
209 check
= calloc(1, sizeof *check
);
211 if (!(freetail
= freetail
->next
))
212 freehead
= &freetail
;
213 check
->next
= visplanes
[hash
];
214 visplanes
[hash
] = check
;
221 * cph 2003/04/18 - create duplicate of existing visplane and set initial range
223 visplane_t
*R_DupPlane(const visplane_t
*pl
, int start
, int stop
)
225 unsigned hash
= visplane_hash(pl
->picnum
, pl
->lightlevel
, pl
->height
);
226 visplane_t
*new_pl
= new_visplane(hash
);
228 new_pl
->height
= pl
->height
;
229 new_pl
->picnum
= pl
->picnum
;
230 new_pl
->lightlevel
= pl
->lightlevel
;
231 new_pl
->xoffs
= pl
->xoffs
; // killough 2/28/98
232 new_pl
->yoffs
= pl
->yoffs
;
233 new_pl
->minx
= start
;
235 memset(new_pl
->top
, 0xff, sizeof new_pl
->top
);
242 // killough 2/28/98: Add offsets
244 visplane_t
*R_FindPlane(fixed_t height
, int picnum
, int lightlevel
,
245 fixed_t xoffs
, fixed_t yoffs
)
248 unsigned hash
; // killough
250 if (picnum
== skyflatnum
|| picnum
& PL_SKYFLAT
)
251 height
= lightlevel
= 0; // killough 7/19/98: most skies map together
253 // New visplane algorithm uses hash table -- killough
254 hash
= visplane_hash(picnum
,lightlevel
,height
);
256 for (check
=visplanes
[hash
]; check
; check
=check
->next
) // killough
257 if (height
== check
->height
&&
258 picnum
== check
->picnum
&&
259 lightlevel
== check
->lightlevel
&&
260 xoffs
== check
->xoffs
&& // killough 2/28/98: Add offset checks
261 yoffs
== check
->yoffs
)
264 check
= new_visplane(hash
); // killough
266 check
->height
= height
;
267 check
->picnum
= picnum
;
268 check
->lightlevel
= lightlevel
;
269 check
->minx
= viewwidth
; // Was SCREENWIDTH -- killough 11/98
271 check
->xoffs
= xoffs
; // killough 2/28/98: Save offsets
272 check
->yoffs
= yoffs
;
274 memset (check
->top
, 0xff, sizeof check
->top
);
282 visplane_t
*R_CheckPlane(visplane_t
*pl
, int start
, int stop
)
284 int intrl
, intrh
, unionl
, unionh
, x
;
286 if (start
< pl
->minx
)
287 intrl
= pl
->minx
, unionl
= start
;
289 unionl
= pl
->minx
, intrl
= start
;
292 intrh
= pl
->maxx
, unionh
= stop
;
294 unionh
= pl
->maxx
, intrh
= stop
;
296 for (x
=intrl
; x
<= intrh
&& pl
->top
[x
] == 0xffff; x
++)
300 { /* Can use existing plane; extend range */
305 else /* Cannot use existing plane; create a new one */
306 return R_DupPlane(pl
,start
,stop
);
313 static void R_MakeSpans(int x
, int t1
, int b1
, int t2
, int b2
)
315 for (; t1
< t2
&& t1
<= b1
; t1
++)
316 R_MapPlane(t1
, spanstart
[t1
], x
-1);
317 for (; b1
> b2
&& b1
>= t1
; b1
--)
318 R_MapPlane(b1
, spanstart
[b1
] ,x
-1);
319 while (t2
< t1
&& t2
<= b2
)
321 while (b2
> b1
&& b2
>= t2
)
325 // New function, by Lee Killough
327 static void R_DoDrawPlane(visplane_t
*pl
)
330 if (pl
->minx
<= pl
->maxx
)
332 if (pl
->picnum
== skyflatnum
|| pl
->picnum
& PL_SKYFLAT
)
337 // killough 10/98: allow skies to come from sidedefs.
338 // Allows scrolling and/or animated skies, as well as
339 // arbitrary multiple skies per level without having
340 // to use info lumps.
344 if (pl
->picnum
& PL_SKYFLAT
)
347 const line_t
*l
= &lines
[pl
->picnum
& ~PL_SKYFLAT
];
349 // Sky transferred from first sidedef
350 const side_t
*s
= *l
->sidenum
+ sides
;
352 // Texture comes from upper texture of reference sidedef
353 texture
= texturetranslation
[s
->toptexture
];
355 // Horizontal offset is turned into an angle offset,
356 // to allow sky rotation as well as careful positioning.
357 // However, the offset is scaled very small, so that it
358 // allows a long-period of sky rotation.
360 an
+= s
->textureoffset
;
362 // Vertical offset allows careful sky positioning.
364 dc_texturemid
= s
->rowoffset
- 28*FRACUNIT
;
366 // We sometimes flip the picture horizontally.
368 // Doom always flipped the picture, so we make it optional,
369 // to make it easier to use the new feature, while to still
370 // allow old sky textures to be used.
372 flip
= l
->special
==272 ? 0u : ~0u;
375 { // Normal Doom sky, only one allowed per level
376 dc_texturemid
= skytexturemid
; // Default y-offset
377 texture
= skytexture
; // Default texture
378 flip
= 0; // Doom flips it
381 /* Sky is always drawn full bright, i.e. colormaps[0] is used.
382 * Because of this hack, sky is not affected by INVUL inverse mapping.
383 * Until Boom fixed this. Compat option added in MBF. */
385 if (comp
[comp_skymap
] || !(dc_colormap
= fixedcolormap
))
386 dc_colormap
= fullcolormap
; // killough 3/20/98
387 dc_texheight
= textureheight
[skytexture
]>>FRACBITS
; // killough
388 // proff 09/21/98: Changed for high-res
389 dc_iscale
= FRACUNIT
*200/viewheight
;
391 // killough 10/98: Use sky scrolling offset, and possibly flip picture
392 for (x
= pl
->minx
; (dc_x
= x
) <= pl
->maxx
; x
++)
393 if ((dc_yl
= pl
->top
[x
]) <= (dc_yh
= pl
->bottom
[x
]))
395 dc_source
= R_GetColumn(texture
, ((an
+ xtoviewangle
[x
])^flip
) >>
405 ds_source
= W_CacheLumpNum(firstflat
+ flattranslation
[pl
->picnum
]);
407 xoffs
= pl
->xoffs
; // killough 2/28/98: Add offsets
409 planeheight
= D_abs(pl
->height
-viewz
);
410 light
= (pl
->lightlevel
>> LIGHTSEGSHIFT
) + extralight
;
412 if (light
>= LIGHTLEVELS
)
413 light
= LIGHTLEVELS
-1;
419 planezlight
= zlight
[light
];
420 pl
->top
[pl
->minx
-1] = pl
->top
[stop
] = 0xffff;
422 for (x
= pl
->minx
; x
<= stop
; x
++)
423 R_MakeSpans(x
,pl
->top
[x
-1],pl
->bottom
[x
-1],pl
->top
[x
],pl
->bottom
[x
]);
425 W_UnlockLumpNum(firstflat
+ flattranslation
[pl
->picnum
]);
432 // At the end of each frame.
435 void R_DrawPlanes (void)
439 for (i
=0;i
<MAXVISPLANES
;i
++)
440 for (pl
=visplanes
[i
]; pl
; pl
=pl
->next
)