1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 // Here is a core component: drawing the floors and ceilings,
17 // while maintaining a per column clipping list only.
18 // Moreover, the sky areas have to be determined.
19 //
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "i_system.h"
26 #include "z_zone.h"
27 #include "w_wad.h"
28
29 #include "doomdef.h"
30 #include "doomstat.h"
31
32 #include "r_local.h"
33 #include "r_sky.h"
34
35
36
37 planefunction_t floorfunc;
38 planefunction_t ceilingfunc;
39
40 //
41 // opening
42 //
43
44 // Here comes the obnoxious "visplane".
45 // haleyjd 08/29/10: [STRIFE] MAXVISPLANES increased to 200
46 #define MAXVISPLANES 200
47 visplane_t visplanes[MAXVISPLANES];
48 visplane_t* lastvisplane;
49 visplane_t* floorplane;
50 visplane_t* ceilingplane;
51
52 // ?
53 #define MAXOPENINGS SCREENWIDTH*64
54 short openings[MAXOPENINGS];
55 short* lastopening;
56
57
58 //
59 // Clip values are the solid pixel bounding the range.
60 // floorclip starts out SCREENHEIGHT
61 // ceilingclip starts out -1
62 //
63 short floorclip[SCREENWIDTH];
64 short ceilingclip[SCREENWIDTH];
65
66 //
67 // spanstart holds the start of a plane span
68 // initialized to 0 at start
69 //
70 int spanstart[SCREENHEIGHT];
71 int spanstop[SCREENHEIGHT];
72
73 //
74 // texture mapping
75 //
76 lighttable_t** planezlight;
77 fixed_t planeheight;
78
79 fixed_t yslope[SCREENHEIGHT];
80 fixed_t distscale[SCREENWIDTH];
81 fixed_t basexscale;
82 fixed_t baseyscale;
83
84 fixed_t cachedheight[SCREENHEIGHT];
85 fixed_t cacheddistance[SCREENHEIGHT];
86 fixed_t cachedxstep[SCREENHEIGHT];
87 fixed_t cachedystep[SCREENHEIGHT];
88
89
90
91 //
92 // R_InitPlanes
93 // Only at game startup.
94 //
R_InitPlanes(void)95 void R_InitPlanes (void)
96 {
97 // Doh!
98 }
99
100
101 //
102 // R_MapPlane
103 //
104 // Uses global vars:
105 // planeheight
106 // ds_source
107 // basexscale
108 // baseyscale
109 // viewx
110 // viewy
111 //
112 // BASIC PRIMITIVE
113 //
114 void
R_MapPlane(int y,int x1,int x2)115 R_MapPlane
116 ( int y,
117 int x1,
118 int x2 )
119 {
120 angle_t angle;
121 fixed_t distance;
122 fixed_t length;
123 unsigned index;
124
125 #ifdef RANGECHECK
126 if (x2 < x1
127 || x1 < 0
128 || x2 >= viewwidth
129 || y > viewheight)
130 {
131 I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y);
132 }
133 #endif
134
135 if (planeheight != cachedheight[y])
136 {
137 cachedheight[y] = planeheight;
138 distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]);
139 ds_xstep = cachedxstep[y] = FixedMul (distance,basexscale);
140 ds_ystep = cachedystep[y] = FixedMul (distance,baseyscale);
141 }
142 else
143 {
144 distance = cacheddistance[y];
145 ds_xstep = cachedxstep[y];
146 ds_ystep = cachedystep[y];
147 }
148
149 length = FixedMul (distance,distscale[x1]);
150 angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT;
151 ds_xfrac = viewx + FixedMul(finecosine[angle], length);
152 ds_yfrac = -viewy - FixedMul(finesine[angle], length);
153
154 if (fixedcolormap)
155 ds_colormap = fixedcolormap;
156 else
157 {
158 index = distance >> LIGHTZSHIFT;
159
160 if (index >= MAXLIGHTZ )
161 index = MAXLIGHTZ-1;
162
163 ds_colormap = planezlight[index];
164 }
165
166 ds_y = y;
167 ds_x1 = x1;
168 ds_x2 = x2;
169
170 // high or low detail
171 spanfunc ();
172 }
173
174
175 //
176 // R_ClearPlanes
177 // At begining of frame.
178 //
R_ClearPlanes(void)179 void R_ClearPlanes (void)
180 {
181 int i;
182 angle_t angle;
183
184 // opening / clipping determination
185 for (i=0 ; i<viewwidth ; i++)
186 {
187 floorclip[i] = viewheight;
188 ceilingclip[i] = -1;
189 }
190
191 lastvisplane = visplanes;
192 lastopening = openings;
193
194 // texture calculation
195 memset (cachedheight, 0, sizeof(cachedheight));
196
197 // left to right mapping
198 angle = (viewangle-ANG90)>>ANGLETOFINESHIFT;
199
200 // scale will be unit scale at SCREENWIDTH/2 distance
201 basexscale = FixedDiv (finecosine[angle],centerxfrac);
202 baseyscale = -FixedDiv (finesine[angle],centerxfrac);
203 }
204
205
206
207
208 //
209 // R_FindPlane
210 //
211 visplane_t*
R_FindPlane(fixed_t height,int picnum,int lightlevel)212 R_FindPlane
213 ( fixed_t height,
214 int picnum,
215 int lightlevel )
216 {
217 visplane_t* check;
218
219 if (picnum == skyflatnum)
220 {
221 height = 0; // all skys map together
222 lightlevel = 0;
223 }
224
225 for (check=visplanes; check<lastvisplane; check++)
226 {
227 if (height == check->height
228 && picnum == check->picnum
229 && lightlevel == check->lightlevel)
230 {
231 break;
232 }
233 }
234
235
236 if (check < lastvisplane)
237 return check;
238
239 if (lastvisplane - visplanes == MAXVISPLANES)
240 I_Error ("R_FindPlane: no more visplanes");
241
242 lastvisplane++;
243
244 check->height = height;
245 check->picnum = picnum;
246 check->lightlevel = lightlevel;
247 check->minx = SCREENWIDTH;
248 check->maxx = -1;
249
250 memset (check->top,0xff,sizeof(check->top));
251
252 return check;
253 }
254
255
256 //
257 // R_CheckPlane
258 //
259 visplane_t*
R_CheckPlane(visplane_t * pl,int start,int stop)260 R_CheckPlane
261 ( visplane_t* pl,
262 int start,
263 int stop )
264 {
265 int intrl;
266 int intrh;
267 int unionl;
268 int unionh;
269 int x;
270
271 if (start < pl->minx)
272 {
273 intrl = pl->minx;
274 unionl = start;
275 }
276 else
277 {
278 unionl = pl->minx;
279 intrl = start;
280 }
281
282 if (stop > pl->maxx)
283 {
284 intrh = pl->maxx;
285 unionh = stop;
286 }
287 else
288 {
289 unionh = pl->maxx;
290 intrh = stop;
291 }
292
293 for (x=intrl ; x<= intrh ; x++)
294 if (pl->top[x] != 0xff)
295 break;
296
297 if (x > intrh)
298 {
299 pl->minx = unionl;
300 pl->maxx = unionh;
301
302 // use the same one
303 return pl;
304 }
305
306 // make a new visplane
307 lastvisplane->height = pl->height;
308 lastvisplane->picnum = pl->picnum;
309 lastvisplane->lightlevel = pl->lightlevel;
310
311 pl = lastvisplane++;
312 pl->minx = start;
313 pl->maxx = stop;
314
315 memset (pl->top,0xff,sizeof(pl->top));
316
317 return pl;
318 }
319
320
321 //
322 // R_MakeSpans
323 //
324 void
R_MakeSpans(int x,int t1,int b1,int t2,int b2)325 R_MakeSpans
326 ( int x,
327 int t1,
328 int b1,
329 int t2,
330 int b2 )
331 {
332 while (t1 < t2 && t1<=b1)
333 {
334 R_MapPlane (t1,spanstart[t1],x-1);
335 t1++;
336 }
337 while (b1 > b2 && b1>=t1)
338 {
339 R_MapPlane (b1,spanstart[b1],x-1);
340 b1--;
341 }
342
343 while (t2 < t1 && t2<=b2)
344 {
345 spanstart[t2] = x;
346 t2++;
347 }
348 while (b2 > b1 && b2>=t2)
349 {
350 spanstart[b2] = x;
351 b2--;
352 }
353 }
354
355
356
357 //
358 // R_DrawPlanes
359 // At the end of each frame.
360 //
R_DrawPlanes(void)361 void R_DrawPlanes (void)
362 {
363 visplane_t* pl;
364 int light;
365 int x;
366 int stop;
367 int angle;
368 int lumpnum;
369
370 #ifdef RANGECHECK
371 if (ds_p - drawsegs > MAXDRAWSEGS)
372 I_Error ("R_DrawPlanes: drawsegs overflow (%i)",
373 ds_p - drawsegs);
374
375 if (lastvisplane - visplanes > MAXVISPLANES)
376 I_Error ("R_DrawPlanes: visplane overflow (%i)",
377 lastvisplane - visplanes);
378
379 if (lastopening - openings > MAXOPENINGS)
380 I_Error ("R_DrawPlanes: opening overflow (%i)",
381 lastopening - openings);
382 #endif
383
384 for (pl = visplanes ; pl < lastvisplane ; pl++)
385 {
386 if (pl->minx > pl->maxx)
387 continue;
388
389
390 // sky flat
391 if (pl->picnum == skyflatnum)
392 {
393 dc_iscale = pspriteiscale>>detailshift;
394
395 // Sky is allways drawn full bright,
396 // i.e. colormaps[0] is used.
397 // Because of this hack, sky is not affected
398 // by INVUL inverse mapping.
399 dc_colormap = colormaps;
400 dc_texturemid = skytexturemid;
401 for (x=pl->minx ; x <= pl->maxx ; x++)
402 {
403 dc_yl = pl->top[x];
404 dc_yh = pl->bottom[x];
405
406 if (dc_yl <= dc_yh)
407 {
408 angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT;
409 dc_x = x;
410 dc_source = R_GetColumn(skytexture, angle);
411 colfunc ();
412 }
413 }
414 continue;
415 }
416
417 // regular flat
418 lumpnum = firstflat + flattranslation[pl->picnum];
419 ds_source = W_CacheLumpNum(lumpnum, PU_STATIC);
420
421 planeheight = abs(pl->height-viewz);
422 light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight;
423
424 if (light >= LIGHTLEVELS)
425 light = LIGHTLEVELS-1;
426
427 if (light < 0)
428 light = 0;
429
430 planezlight = zlight[light];
431
432 pl->top[pl->maxx+1] = 0xff;
433 pl->top[pl->minx-1] = 0xff;
434
435 stop = pl->maxx + 1;
436
437 for (x=pl->minx ; x<= stop ; x++)
438 {
439 R_MakeSpans(x,pl->top[x-1],
440 pl->bottom[x-1],
441 pl->top[x],
442 pl->bottom[x]);
443 }
444
445 W_ReleaseLumpNum(lumpnum);
446 }
447 }
448