1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16
17 //**************************************************************************
18 //**
19 //** R_SEGS.C
20 //**
21 //** This version has the tall-sector-crossing-precision-bug fixed.
22 //**
23 //**************************************************************************
24
25 #include <stdlib.h>
26
27 #include "doomdef.h"
28 #include "r_local.h"
29
30 // OPTIMIZE: closed two sided lines as single sided
31
32 boolean segtextured; // true if any of the segs textures might be vis
33 boolean markfloor; // false if the back side is the same plane
34 boolean markceiling;
35 boolean maskedtexture;
36 int toptexture, bottomtexture, midtexture;
37
38
39 angle_t rw_normalangle;
40 int rw_angle1; // angle to line origin
41
42 //
43 // wall
44 //
45 int rw_x;
46 int rw_stopx;
47 angle_t rw_centerangle;
48 fixed_t rw_offset;
49 fixed_t rw_distance;
50 fixed_t rw_scale;
51 fixed_t rw_scalestep;
52 fixed_t rw_midtexturemid;
53 fixed_t rw_toptexturemid;
54 fixed_t rw_bottomtexturemid;
55
56 int worldtop, worldbottom, worldhigh, worldlow;
57
58 fixed_t pixhigh, pixlow;
59 fixed_t pixhighstep, pixlowstep;
60 fixed_t topfrac, topstep;
61 fixed_t bottomfrac, bottomstep;
62
63
64 lighttable_t **walllights;
65
66 short *maskedtexturecol;
67
68 /*
69 ================
70 =
71 = R_RenderMaskedSegRange
72 =
73 ================
74 */
75
R_RenderMaskedSegRange(drawseg_t * ds,int x1,int x2)76 void R_RenderMaskedSegRange(drawseg_t * ds, int x1, int x2)
77 {
78 unsigned index;
79 column_t *col;
80 int lightnum;
81 int texnum;
82
83 //
84 // calculate light table
85 // use different light tables for horizontal / vertical / diagonal
86 // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
87 curline = ds->curline;
88 frontsector = curline->frontsector;
89 backsector = curline->backsector;
90 texnum = texturetranslation[curline->sidedef->midtexture];
91
92 lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
93 if (curline->v1->y == curline->v2->y)
94 lightnum--;
95 else if (curline->v1->x == curline->v2->x)
96 lightnum++;
97 if (lightnum < 0)
98 walllights = scalelight[0];
99 else if (lightnum >= LIGHTLEVELS)
100 walllights = scalelight[LIGHTLEVELS - 1];
101 else
102 walllights = scalelight[lightnum];
103
104 maskedtexturecol = ds->maskedtexturecol;
105
106 rw_scalestep = ds->scalestep;
107 spryscale = ds->scale1 + (x1 - ds->x1) * rw_scalestep;
108 mfloorclip = ds->sprbottomclip;
109 mceilingclip = ds->sprtopclip;
110
111 //
112 // find positioning
113 //
114 if (curline->linedef->flags & ML_DONTPEGBOTTOM)
115 {
116 dc_texturemid = frontsector->floorheight > backsector->floorheight
117 ? frontsector->floorheight : backsector->floorheight;
118 dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
119 }
120 else
121 {
122 dc_texturemid = frontsector->ceilingheight < backsector->ceilingheight
123 ? frontsector->ceilingheight : backsector->ceilingheight;
124 dc_texturemid = dc_texturemid - viewz;
125 }
126 dc_texturemid += curline->sidedef->rowoffset;
127
128 if (fixedcolormap)
129 dc_colormap = fixedcolormap;
130 //
131 // draw the columns
132 //
133 for (dc_x = x1; dc_x <= x2; dc_x++)
134 {
135 // calculate lighting
136 if (maskedtexturecol[dc_x] != SHRT_MAX)
137 {
138 if (!fixedcolormap)
139 {
140 index = spryscale >> LIGHTSCALESHIFT;
141 if (index >= MAXLIGHTSCALE)
142 index = MAXLIGHTSCALE - 1;
143 dc_colormap = walllights[index];
144 }
145
146 sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
147 dc_iscale = 0xffffffffu / (unsigned) spryscale;
148
149 //
150 // draw the texture
151 //
152 col = (column_t *) ((byte *)
153 R_GetColumn(texnum,
154 maskedtexturecol[dc_x]) - 3);
155
156 R_DrawMaskedColumn(col, -1);
157 maskedtexturecol[dc_x] = SHRT_MAX;
158 }
159 spryscale += rw_scalestep;
160 }
161
162 }
163
164 /*
165 ================
166 =
167 = R_RenderSegLoop
168 =
169 = Draws zero, one, or two textures (and possibly a masked texture) for walls
170 = Can draw or mark the starting pixel of floor and ceiling textures
171 =
172 = CALLED: CORE LOOPING ROUTINE
173 ================
174 */
175
176 #define HEIGHTBITS 12
177 #define HEIGHTUNIT (1<<HEIGHTBITS)
178
R_RenderSegLoop(void)179 void R_RenderSegLoop(void)
180 {
181 angle_t angle;
182 unsigned index;
183 int yl, yh, mid;
184 fixed_t texturecolumn;
185 int top, bottom;
186
187 texturecolumn = 0; // shut up compiler warning
188
189 for (; rw_x < rw_stopx; rw_x++)
190 {
191 //
192 // mark floor / ceiling areas
193 //
194 yl = (topfrac + HEIGHTUNIT - 1) >> HEIGHTBITS;
195 if (yl < ceilingclip[rw_x] + 1)
196 yl = ceilingclip[rw_x] + 1; // no space above wall
197 if (markceiling)
198 {
199 top = ceilingclip[rw_x] + 1;
200 bottom = yl - 1;
201 if (bottom >= floorclip[rw_x])
202 bottom = floorclip[rw_x] - 1;
203 if (top <= bottom)
204 {
205 ceilingplane->top[rw_x] = top;
206 ceilingplane->bottom[rw_x] = bottom;
207 }
208 }
209
210 yh = bottomfrac >> HEIGHTBITS;
211 if (yh >= floorclip[rw_x])
212 yh = floorclip[rw_x] - 1;
213 if (markfloor)
214 {
215 top = yh + 1;
216 bottom = floorclip[rw_x] - 1;
217 if (top <= ceilingclip[rw_x])
218 top = ceilingclip[rw_x] + 1;
219 if (top <= bottom)
220 {
221 floorplane->top[rw_x] = top;
222 floorplane->bottom[rw_x] = bottom;
223 }
224 }
225
226 //
227 // texturecolumn and lighting are independent of wall tiers
228 //
229 if (segtextured)
230 {
231 // calculate texture offset
232 angle = (rw_centerangle + xtoviewangle[rw_x]) >> ANGLETOFINESHIFT;
233 texturecolumn =
234 rw_offset - FixedMul(finetangent[angle], rw_distance);
235 texturecolumn >>= FRACBITS;
236 // calculate lighting
237 index = rw_scale >> LIGHTSCALESHIFT;
238 if (index >= MAXLIGHTSCALE)
239 index = MAXLIGHTSCALE - 1;
240 dc_colormap = walllights[index];
241 dc_x = rw_x;
242 dc_iscale = 0xffffffffu / (unsigned) rw_scale;
243 }
244
245 //
246 // draw the wall tiers
247 //
248 if (midtexture)
249 { // single sided line
250 dc_yl = yl;
251 dc_yh = yh;
252 dc_texturemid = rw_midtexturemid;
253 dc_source = R_GetColumn(midtexture, texturecolumn);
254 colfunc();
255 ceilingclip[rw_x] = viewheight;
256 floorclip[rw_x] = -1;
257 }
258 else
259 { // two sided line
260 if (toptexture)
261 { // top wall
262 mid = pixhigh >> HEIGHTBITS;
263 pixhigh += pixhighstep;
264 if (mid >= floorclip[rw_x])
265 mid = floorclip[rw_x] - 1;
266 if (mid >= yl)
267 {
268 dc_yl = yl;
269 dc_yh = mid;
270 dc_texturemid = rw_toptexturemid;
271 dc_source = R_GetColumn(toptexture, texturecolumn);
272 colfunc();
273 ceilingclip[rw_x] = mid;
274 }
275 else
276 ceilingclip[rw_x] = yl - 1;
277 }
278 else
279 { // no top wall
280 if (markceiling)
281 ceilingclip[rw_x] = yl - 1;
282 }
283
284 if (bottomtexture)
285 { // bottom wall
286 mid = (pixlow + HEIGHTUNIT - 1) >> HEIGHTBITS;
287 pixlow += pixlowstep;
288 if (mid <= ceilingclip[rw_x])
289 mid = ceilingclip[rw_x] + 1; // no space above wall
290 if (mid <= yh)
291 {
292 dc_yl = mid;
293 dc_yh = yh;
294 dc_texturemid = rw_bottomtexturemid;
295 dc_source = R_GetColumn(bottomtexture, texturecolumn);
296 colfunc();
297 floorclip[rw_x] = mid;
298 }
299 else
300 floorclip[rw_x] = yh + 1;
301 }
302 else
303 { // no bottom wall
304 if (markfloor)
305 floorclip[rw_x] = yh + 1;
306 }
307
308 if (maskedtexture)
309 { // save texturecol for backdrawing of masked mid texture
310 maskedtexturecol[rw_x] = texturecolumn;
311 }
312 }
313
314 rw_scale += rw_scalestep;
315 topfrac += topstep;
316 bottomfrac += bottomstep;
317 }
318
319 }
320
321
322
323 /*
324 =====================
325 =
326 = R_StoreWallRange
327 =
328 = A wall segment will be drawn between start and stop pixels (inclusive)
329 =
330 ======================
331 */
332
R_StoreWallRange(int start,int stop)333 void R_StoreWallRange(int start, int stop)
334 {
335 fixed_t hyp;
336 fixed_t sineval;
337 angle_t distangle, offsetangle;
338 fixed_t vtop;
339 int lightnum;
340
341 if (ds_p == &drawsegs[MAXDRAWSEGS])
342 return; // don't overflow and crash
343
344 #ifdef RANGECHECK
345 if (start >= viewwidth || start > stop)
346 I_Error("Bad R_RenderWallRange: %i to %i", start, stop);
347 #endif
348
349 sidedef = curline->sidedef;
350 linedef = curline->linedef;
351
352 // mark the segment as visible for auto map
353 linedef->flags |= ML_MAPPED;
354
355 //
356 // calculate rw_distance for scale calculation
357 //
358 rw_normalangle = curline->angle + ANG90;
359 offsetangle = abs(rw_normalangle - rw_angle1);
360 if (offsetangle > ANG90)
361 offsetangle = ANG90;
362 distangle = ANG90 - offsetangle;
363 hyp = R_PointToDist(curline->v1->x, curline->v1->y);
364 sineval = finesine[distangle >> ANGLETOFINESHIFT];
365 rw_distance = FixedMul(hyp, sineval);
366
367
368 ds_p->x1 = rw_x = start;
369 ds_p->x2 = stop;
370 ds_p->curline = curline;
371 rw_stopx = stop + 1;
372
373 //
374 // calculate scale at both ends and step
375 //
376 ds_p->scale1 = rw_scale =
377 R_ScaleFromGlobalAngle(viewangle + xtoviewangle[start]);
378 if (stop > start)
379 {
380 ds_p->scale2 = R_ScaleFromGlobalAngle(viewangle + xtoviewangle[stop]);
381 ds_p->scalestep = rw_scalestep =
382 (ds_p->scale2 - rw_scale) / (stop - start);
383 }
384 else
385 {
386 //
387 // try to fix the stretched line bug
388 //
389 #if 0
390 if (rw_distance < FRACUNIT / 2)
391 {
392 fixed_t trx, try;
393 fixed_t gxt, gyt;
394
395 trx = curline->v1->x - viewx;
396 try = curline->v1->y - viewy;
397
398 gxt = FixedMul(trx, viewcos);
399 gyt = -FixedMul(try, viewsin);
400 ds_p->scale1 = FixedDiv(projection, gxt - gyt);
401 }
402 #endif
403 ds_p->scale2 = ds_p->scale1;
404 }
405
406
407 //
408 // calculate texture boundaries and decide if floor / ceiling marks
409 // are needed
410 //
411 worldtop = frontsector->ceilingheight - viewz;
412 worldbottom = frontsector->floorheight - viewz;
413
414 midtexture = toptexture = bottomtexture = maskedtexture = 0;
415 ds_p->maskedtexturecol = NULL;
416
417 if (!backsector)
418 {
419 //
420 // single sided line
421 //
422 midtexture = texturetranslation[sidedef->midtexture];
423 // a single sided line is terminal, so it must mark ends
424 markfloor = markceiling = true;
425 if (linedef->flags & ML_DONTPEGBOTTOM)
426 {
427 vtop = frontsector->floorheight +
428 textureheight[sidedef->midtexture];
429 rw_midtexturemid = vtop - viewz; // bottom of texture at bottom
430 }
431 else
432 rw_midtexturemid = worldtop; // top of texture at top
433 rw_midtexturemid += sidedef->rowoffset;
434 ds_p->silhouette = SIL_BOTH;
435 ds_p->sprtopclip = screenheightarray;
436 ds_p->sprbottomclip = negonearray;
437 ds_p->bsilheight = INT_MAX;
438 ds_p->tsilheight = INT_MIN;
439 }
440 else
441 {
442 //
443 // two sided line
444 //
445 ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
446 ds_p->silhouette = 0;
447 if (frontsector->floorheight > backsector->floorheight)
448 {
449 ds_p->silhouette = SIL_BOTTOM;
450 ds_p->bsilheight = frontsector->floorheight;
451 }
452 else if (backsector->floorheight > viewz)
453 {
454 ds_p->silhouette = SIL_BOTTOM;
455 ds_p->bsilheight = INT_MAX;
456 // ds_p->sprbottomclip = negonearray;
457 }
458 if (frontsector->ceilingheight < backsector->ceilingheight)
459 {
460 ds_p->silhouette |= SIL_TOP;
461 ds_p->tsilheight = frontsector->ceilingheight;
462 }
463 else if (backsector->ceilingheight < viewz)
464 {
465 ds_p->silhouette |= SIL_TOP;
466 ds_p->tsilheight = INT_MIN;
467 // ds_p->sprtopclip = screenheightarray;
468 }
469
470 if (backsector->ceilingheight <= frontsector->floorheight)
471 {
472 ds_p->sprbottomclip = negonearray;
473 ds_p->bsilheight = INT_MAX;
474 ds_p->silhouette |= SIL_BOTTOM;
475 }
476 if (backsector->floorheight >= frontsector->ceilingheight)
477 {
478 ds_p->sprtopclip = screenheightarray;
479 ds_p->tsilheight = INT_MIN;
480 ds_p->silhouette |= SIL_TOP;
481 }
482 worldhigh = backsector->ceilingheight - viewz;
483 worldlow = backsector->floorheight - viewz;
484
485 // hack to allow height changes in outdoor areas
486 if (frontsector->ceilingpic == skyflatnum
487 && backsector->ceilingpic == skyflatnum)
488 worldtop = worldhigh;
489
490 if (worldlow != worldbottom
491 || backsector->floorpic != frontsector->floorpic
492 || backsector->lightlevel != frontsector->lightlevel)
493 markfloor = true;
494 else
495 markfloor = false; // same plane on both sides
496
497 if (worldhigh != worldtop
498 || backsector->ceilingpic != frontsector->ceilingpic
499 || backsector->lightlevel != frontsector->lightlevel)
500 markceiling = true;
501 else
502 markceiling = false; // same plane on both sides
503
504 if (backsector->ceilingheight <= frontsector->floorheight
505 || backsector->floorheight >= frontsector->ceilingheight)
506 markceiling = markfloor = true; // closed door
507
508 if (worldhigh < worldtop)
509 { // top texture
510 toptexture = texturetranslation[sidedef->toptexture];
511 if (linedef->flags & ML_DONTPEGTOP)
512 rw_toptexturemid = worldtop; // top of texture at top
513 else
514 {
515 vtop = backsector->ceilingheight +
516 textureheight[sidedef->toptexture];
517 rw_toptexturemid = vtop - viewz; // bottom of texture
518 }
519 }
520 if (worldlow > worldbottom)
521 { // bottom texture
522 bottomtexture = texturetranslation[sidedef->bottomtexture];
523 if (linedef->flags & ML_DONTPEGBOTTOM)
524 { // bottom of texture at bottom
525 rw_bottomtexturemid = worldtop; // top of texture at top
526 }
527 else // top of texture at top
528 rw_bottomtexturemid = worldlow;
529 }
530 rw_toptexturemid += sidedef->rowoffset;
531 rw_bottomtexturemid += sidedef->rowoffset;
532
533 //
534 // allocate space for masked texture tables
535 //
536 if (sidedef->midtexture)
537 { // masked midtexture
538 maskedtexture = true;
539 ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
540 lastopening += rw_stopx - rw_x;
541 }
542 }
543
544 //
545 // calculate rw_offset (only needed for textured lines)
546 //
547 segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
548
549 if (segtextured)
550 {
551 offsetangle = rw_normalangle - rw_angle1;
552 if (offsetangle > ANG180)
553 offsetangle = -offsetangle;
554 if (offsetangle > ANG90)
555 offsetangle = ANG90;
556 sineval = finesine[offsetangle >> ANGLETOFINESHIFT];
557 rw_offset = FixedMul(hyp, sineval);
558 if (rw_normalangle - rw_angle1 < ANG180)
559 rw_offset = -rw_offset;
560 rw_offset += sidedef->textureoffset + curline->offset;
561 rw_centerangle = ANG90 + viewangle - rw_normalangle;
562
563 //
564 // calculate light table
565 // use different light tables for horizontal / vertical / diagonal
566 // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
567 if (!fixedcolormap)
568 {
569 lightnum =
570 (frontsector->lightlevel >> LIGHTSEGSHIFT) + extralight;
571 if (curline->v1->y == curline->v2->y)
572 lightnum--;
573 else if (curline->v1->x == curline->v2->x)
574 lightnum++;
575 if (lightnum < 0)
576 walllights = scalelight[0];
577 else if (lightnum >= LIGHTLEVELS)
578 walllights = scalelight[LIGHTLEVELS - 1];
579 else
580 walllights = scalelight[lightnum];
581 }
582 }
583
584
585 //
586 // if a floor / ceiling plane is on the wrong side of the view plane
587 // it is definately invisible and doesn't need to be marked
588 //
589 if (frontsector->floorheight >= viewz)
590 markfloor = false; // above view plane
591 if (frontsector->ceilingheight <= viewz
592 && frontsector->ceilingpic != skyflatnum)
593 markceiling = false; // below view plane
594
595 //
596 // calculate incremental stepping values for texture edges
597 //
598 worldtop >>= 4;
599 worldbottom >>= 4;
600
601 topstep = -FixedMul(rw_scalestep, worldtop);
602 topfrac = (centeryfrac >> 4) - FixedMul(worldtop, rw_scale);
603
604 bottomstep = -FixedMul(rw_scalestep, worldbottom);
605 bottomfrac = (centeryfrac >> 4) - FixedMul(worldbottom, rw_scale);
606
607 if (backsector)
608 {
609 worldhigh >>= 4;
610 worldlow >>= 4;
611
612 if (worldhigh < worldtop)
613 {
614 pixhigh = (centeryfrac >> 4) - FixedMul(worldhigh, rw_scale);
615 pixhighstep = -FixedMul(rw_scalestep, worldhigh);
616 }
617 if (worldlow > worldbottom)
618 {
619 pixlow = (centeryfrac >> 4) - FixedMul(worldlow, rw_scale);
620 pixlowstep = -FixedMul(rw_scalestep, worldlow);
621 }
622 }
623
624 //
625 // render it
626 //
627 if (markceiling)
628 ceilingplane = R_CheckPlane(ceilingplane, rw_x, rw_stopx - 1);
629 if (markfloor)
630 floorplane = R_CheckPlane(floorplane, rw_x, rw_stopx - 1);
631
632 R_RenderSegLoop();
633
634 //
635 // save sprite clipping info
636 //
637 if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip)
638 {
639 memcpy(lastopening, ceilingclip + start, 2 * (rw_stopx - start));
640 ds_p->sprtopclip = lastopening - start;
641 lastopening += rw_stopx - start;
642 }
643 if (((ds_p->silhouette & SIL_BOTTOM) || maskedtexture)
644 && !ds_p->sprbottomclip)
645 {
646 memcpy(lastopening, floorclip + start, 2 * (rw_stopx - start));
647 ds_p->sprbottomclip = lastopening - start;
648 lastopening += rw_stopx - start;
649 }
650 if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
651 {
652 ds_p->silhouette |= SIL_TOP;
653 ds_p->tsilheight = INT_MIN;
654 }
655 if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
656 {
657 ds_p->silhouette |= SIL_BOTTOM;
658 ds_p->bsilheight = INT_MAX;
659 }
660 ds_p++;
661 }
662