1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id:$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
11 //
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
16 //
17 // DESCRIPTION:
18 // All the clipping: columns, horizontal spans, sky columns.
19 //
20 // This file contains some code from the Build Engine.
21 //
22 // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
23 // Ken Silverman's official web site: "http://www.advsys.net/ken"
24 // See the included license file "BUILDLIC.TXT" for license info.
25 //
26 //-----------------------------------------------------------------------------
27
28 #include <stdlib.h>
29 #include <stddef.h>
30
31 #include "templates.h"
32 #include "i_system.h"
33
34 #include "doomdef.h"
35 #include "doomstat.h"
36 #include "doomdata.h"
37 #include "p_lnspec.h"
38
39 #include "r_local.h"
40 #include "r_sky.h"
41 #include "v_video.h"
42
43 #include "m_swap.h"
44 #include "w_wad.h"
45 #include "stats.h"
46 #include "a_sharedglobal.h"
47 #include "d_net.h"
48 #include "g_level.h"
49 #include "r_bsp.h"
50 #include "r_plane.h"
51 #include "r_segs.h"
52 #include "r_3dfloors.h"
53 #include "v_palette.h"
54 #include "r_data/colormaps.h"
55
56 #define WALLYREPEAT 8
57
58
59 CVAR(Bool, r_np2, true, 0)
60
61 //CVAR (Int, ty, 8, 0)
62 //CVAR (Int, tx, 8, 0)
63
64 #define HEIGHTBITS 12
65 #define HEIGHTSHIFT (FRACBITS-HEIGHTBITS)
66
67 extern fixed_t globaluclip, globaldclip;
68
69
70 // OPTIMIZE: closed two sided lines as single sided
71
72 // killough 1/6/98: replaced globals with statics where appropriate
73
74 static bool segtextured; // True if any of the segs textures might be visible.
75 bool markfloor; // False if the back side is the same plane.
76 bool markceiling;
77 FTexture *toptexture;
78 FTexture *bottomtexture;
79 FTexture *midtexture;
80 fixed_t rw_offset_top;
81 fixed_t rw_offset_mid;
82 fixed_t rw_offset_bottom;
83
84
85 int wallshade;
86
87 short walltop[MAXWIDTH]; // [RH] record max extents of wall
88 short wallbottom[MAXWIDTH];
89 short wallupper[MAXWIDTH];
90 short walllower[MAXWIDTH];
91 fixed_t swall[MAXWIDTH];
92 fixed_t lwall[MAXWIDTH];
93 fixed_t lwallscale;
94
95 //
96 // regular wall
97 //
98 extern fixed_t rw_backcz1, rw_backcz2;
99 extern fixed_t rw_backfz1, rw_backfz2;
100 extern fixed_t rw_frontcz1, rw_frontcz2;
101 extern fixed_t rw_frontfz1, rw_frontfz2;
102
103 int rw_ceilstat, rw_floorstat;
104 bool rw_mustmarkfloor, rw_mustmarkceiling;
105 bool rw_prepped;
106 bool rw_markmirror;
107 bool rw_havehigh;
108 bool rw_havelow;
109
110 fixed_t rw_light; // [RH] Scale lights with viewsize adjustments
111 fixed_t rw_lightstep;
112 fixed_t rw_lightleft;
113
114 static fixed_t rw_frontlowertop;
115
116 static int rw_x;
117 static int rw_stopx;
118 fixed_t rw_offset;
119 static fixed_t rw_scalestep;
120 static fixed_t rw_midtexturemid;
121 static fixed_t rw_toptexturemid;
122 static fixed_t rw_bottomtexturemid;
123 static fixed_t rw_midtexturescalex;
124 static fixed_t rw_midtexturescaley;
125 static fixed_t rw_toptexturescalex;
126 static fixed_t rw_toptexturescaley;
127 static fixed_t rw_bottomtexturescalex;
128 static fixed_t rw_bottomtexturescaley;
129
130 FTexture *rw_pic;
131
132 static fixed_t *maskedtexturecol;
133
134 static void R_RenderDecal (side_t *wall, DBaseDecal *first, drawseg_t *clipper, int pass);
135 static void WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans));
136 void wallscan_np2(int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat, fixed_t top, fixed_t bot, bool mask);
137 static void wallscan_np2_ds(drawseg_t *ds, int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat);
138 static void call_wallscan(int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat, bool mask);
139
140 //=============================================================================
141 //
142 // CVAR r_fogboundary
143 //
144 // If true, makes fog look more "real" by shading the walls separating two
145 // sectors with different fog.
146 //=============================================================================
147
148 CVAR(Bool, r_fogboundary, true, 0)
149
IsFogBoundary(sector_t * front,sector_t * back)150 inline bool IsFogBoundary (sector_t *front, sector_t *back)
151 {
152 return r_fogboundary && fixedcolormap == NULL && front->ColorMap->Fade &&
153 front->ColorMap->Fade != back->ColorMap->Fade &&
154 (front->GetTexture(sector_t::ceiling) != skyflatnum || back->GetTexture(sector_t::ceiling) != skyflatnum);
155 }
156
157 //=============================================================================
158 //
159 // CVAR r_drawmirrors
160 //
161 // Set to false to disable rendering of mirrors
162 //=============================================================================
163
164 CVAR(Bool, r_drawmirrors, true, 0)
165
166 //
167 // R_RenderMaskedSegRange
168 //
169 fixed_t *MaskedSWall;
170 fixed_t MaskedScaleY;
171
BlastMaskedColumn(void (* blastfunc)(const BYTE * pixels,const FTexture::Span * spans),FTexture * tex)172 static void BlastMaskedColumn (void (*blastfunc)(const BYTE *pixels, const FTexture::Span *spans), FTexture *tex)
173 {
174 // calculate lighting
175 if (fixedcolormap == NULL && fixedlightlev < 0)
176 {
177 dc_colormap = basecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
178 }
179
180 dc_iscale = MulScale18 (MaskedSWall[dc_x], MaskedScaleY);
181 if (sprflipvert)
182 sprtopscreen = centeryfrac + FixedMul(dc_texturemid, spryscale);
183 else
184 sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
185
186 // killough 1/25/98: here's where Medusa came in, because
187 // it implicitly assumed that the column was all one patch.
188 // Originally, Doom did not construct complete columns for
189 // multipatched textures, so there were no header or trailer
190 // bytes in the column referred to below, which explains
191 // the Medusa effect. The fix is to construct true columns
192 // when forming multipatched textures (see r_data.c).
193
194 // draw the texture
195 const FTexture::Span *spans;
196 const BYTE *pixels = tex->GetColumn (maskedtexturecol[dc_x] >> FRACBITS, &spans);
197 blastfunc (pixels, spans);
198 rw_light += rw_lightstep;
199 spryscale += rw_scalestep;
200 }
201
202 // Clip a midtexture to the floor and ceiling of the sector in front of it.
ClipMidtex(int x1,int x2)203 void ClipMidtex(int x1, int x2)
204 {
205 short most[MAXWIDTH];
206
207 WallMost(most, curline->frontsector->ceilingplane, &WallC);
208 for (int i = x1; i < x2; ++i)
209 {
210 if (wallupper[i] < most[i])
211 wallupper[i] = most[i];
212 }
213 WallMost(most, curline->frontsector->floorplane, &WallC);
214 for (int i = x1; i < x2; ++i)
215 {
216 if (walllower[i] > most[i])
217 walllower[i] = most[i];
218 }
219 }
220
221 void R_RenderFakeWallRange(drawseg_t *ds, int x1, int x2);
222
R_RenderMaskedSegRange(drawseg_t * ds,int x1,int x2)223 void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2)
224 {
225 FTexture *tex;
226 int i;
227 sector_t tempsec; // killough 4/13/98
228 fixed_t texheight, texheightscale;
229 bool notrelevant = false;
230 fixed_t rowoffset;
231
232 const sector_t *sec;
233
234 sprflipvert = false;
235
236 curline = ds->curline;
237
238 // killough 4/11/98: draw translucent 2s normal textures
239 // [RH] modified because we don't use user-definable translucency maps
240 ESPSResult drawmode;
241
242 drawmode = R_SetPatchStyle (LegacyRenderStyles[curline->linedef->flags & ML_ADDTRANS ? STYLE_Add : STYLE_Translucent],
243 MIN(curline->linedef->Alpha, FRACUNIT), 0, 0);
244
245 if ((drawmode == DontDraw && !ds->bFogBoundary && !ds->bFakeBoundary))
246 {
247 return;
248 }
249
250 NetUpdate ();
251
252 frontsector = curline->frontsector;
253 backsector = curline->backsector;
254
255 tex = TexMan(curline->sidedef->GetTexture(side_t::mid), true);
256 if (i_compatflags & COMPATF_MASKEDMIDTEX)
257 {
258 tex = tex->GetRawTexture();
259 }
260
261 // killough 4/13/98: get correct lightlevel for 2s normal textures
262 sec = R_FakeFlat (frontsector, &tempsec, NULL, NULL, false);
263
264 basecolormap = sec->ColorMap; // [RH] Set basecolormap
265
266 wallshade = ds->shade;
267 rw_lightstep = ds->lightstep;
268 rw_light = ds->light + (x1 - ds->x1) * rw_lightstep;
269
270 if (fixedlightlev < 0)
271 {
272 for (i = frontsector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
273 {
274 if (!(fake3D & FAKE3D_CLIPTOP))
275 {
276 sclipTop = sec->ceilingplane.ZatPoint(viewx, viewy);
277 }
278 if (sclipTop <= frontsector->e->XFloor.lightlist[i].plane.ZatPoint(viewx, viewy))
279 {
280 lightlist_t *lit = &frontsector->e->XFloor.lightlist[i];
281 basecolormap = lit->extra_colormap;
282 wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource == NULL) + r_actualextralight);
283 break;
284 }
285 }
286 }
287
288 mfloorclip = openings + ds->sprbottomclip - ds->x1;
289 mceilingclip = openings + ds->sprtopclip - ds->x1;
290
291 // [RH] Draw fog partition
292 if (ds->bFogBoundary)
293 {
294 R_DrawFogBoundary (x1, x2, mceilingclip, mfloorclip);
295 if (ds->maskedtexturecol == -1)
296 {
297 goto clearfog;
298 }
299 }
300 if ((ds->bFakeBoundary && !(ds->bFakeBoundary & 4)) || drawmode == DontDraw)
301 {
302 goto clearfog;
303 }
304
305 MaskedSWall = (fixed_t *)(openings + ds->swall) - ds->x1;
306 MaskedScaleY = ds->yrepeat;
307 maskedtexturecol = (fixed_t *)(openings + ds->maskedtexturecol) - ds->x1;
308 spryscale = ds->iscale + ds->iscalestep * (x1 - ds->x1);
309 rw_scalestep = ds->iscalestep;
310
311 if (fixedlightlev >= 0)
312 dc_colormap = basecolormap->Maps + fixedlightlev;
313 else if (fixedcolormap != NULL)
314 dc_colormap = fixedcolormap;
315
316 // find positioning
317 texheight = tex->GetScaledHeight() << FRACBITS;
318 texheightscale = abs(curline->sidedef->GetTextureYScale(side_t::mid));
319 if (texheightscale != FRACUNIT)
320 {
321 texheight = FixedDiv(texheight, texheightscale);
322 }
323 if (curline->linedef->flags & ML_DONTPEGBOTTOM)
324 {
325 dc_texturemid = MAX (frontsector->GetPlaneTexZ(sector_t::floor), backsector->GetPlaneTexZ(sector_t::floor)) + texheight;
326 }
327 else
328 {
329 dc_texturemid = MIN (frontsector->GetPlaneTexZ(sector_t::ceiling), backsector->GetPlaneTexZ(sector_t::ceiling));
330 }
331
332 rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid);
333
334 if (!(curline->linedef->flags & ML_WRAP_MIDTEX) &&
335 !(curline->sidedef->Flags & WALLF_WRAP_MIDTEX))
336 { // Texture does not wrap vertically.
337 fixed_t textop;
338
339 if (MaskedScaleY < 0)
340 {
341 MaskedScaleY = -MaskedScaleY;
342 sprflipvert = true;
343 }
344 if (tex->bWorldPanning)
345 {
346 // rowoffset is added before the MulScale3 so that the masked texture will
347 // still be positioned in world units rather than texels.
348 dc_texturemid += rowoffset - viewz;
349 textop = dc_texturemid;
350 dc_texturemid = MulScale16 (dc_texturemid, MaskedScaleY);
351 }
352 else
353 {
354 // rowoffset is added outside the multiply so that it positions the texture
355 // by texels instead of world units.
356 textop = dc_texturemid - viewz + SafeDivScale16 (rowoffset, MaskedScaleY);
357 dc_texturemid = MulScale16 (dc_texturemid - viewz, MaskedScaleY) + rowoffset;
358 }
359 if (sprflipvert)
360 {
361 MaskedScaleY = -MaskedScaleY;
362 dc_texturemid -= tex->GetHeight() << FRACBITS;
363 }
364
365 // [RH] Don't bother drawing segs that are completely offscreen
366 if (MulScale12 (globaldclip, ds->sz1) < -textop &&
367 MulScale12 (globaldclip, ds->sz2) < -textop)
368 { // Texture top is below the bottom of the screen
369 goto clearfog;
370 }
371
372 if (MulScale12 (globaluclip, ds->sz1) > texheight - textop &&
373 MulScale12 (globaluclip, ds->sz2) > texheight - textop)
374 { // Texture bottom is above the top of the screen
375 goto clearfog;
376 }
377
378 if ((fake3D & FAKE3D_CLIPBOTTOM) && textop < sclipBottom - viewz)
379 {
380 notrelevant = true;
381 goto clearfog;
382 }
383 if ((fake3D & FAKE3D_CLIPTOP) && textop - texheight > sclipTop - viewz)
384 {
385 notrelevant = true;
386 goto clearfog;
387 }
388
389 WallC.sz1 = ds->sz1;
390 WallC.sz2 = ds->sz2;
391 WallC.sx1 = ds->sx1;
392 WallC.sx2 = ds->sx2;
393
394 if (fake3D & FAKE3D_CLIPTOP)
395 {
396 OWallMost(wallupper, textop < sclipTop - viewz ? textop : sclipTop - viewz, &WallC);
397 }
398 else
399 {
400 OWallMost(wallupper, textop, &WallC);
401 }
402 if (fake3D & FAKE3D_CLIPBOTTOM)
403 {
404 OWallMost(walllower, textop - texheight > sclipBottom - viewz ? textop - texheight : sclipBottom - viewz, &WallC);
405 }
406 else
407 {
408 OWallMost(walllower, textop - texheight, &WallC);
409 }
410
411 for (i = x1; i < x2; i++)
412 {
413 if (wallupper[i] < mceilingclip[i])
414 wallupper[i] = mceilingclip[i];
415 }
416 for (i = x1; i < x2; i++)
417 {
418 if (walllower[i] > mfloorclip[i])
419 walllower[i] = mfloorclip[i];
420 }
421
422 if (CurrentSkybox)
423 { // Midtex clipping doesn't work properly with skyboxes, since you're normally below the floor
424 // or above the ceiling, so the appropriate end won't be clipped automatically when adding
425 // this drawseg.
426 if ((curline->linedef->flags & ML_CLIP_MIDTEX) ||
427 (curline->sidedef->Flags & WALLF_CLIP_MIDTEX))
428 {
429 ClipMidtex(x1, x2);
430 }
431 }
432
433 mfloorclip = walllower;
434 mceilingclip = wallupper;
435
436 // draw the columns one at a time
437 if (drawmode == DoDraw0)
438 {
439 for (dc_x = x1; dc_x < x2; ++dc_x)
440 {
441 BlastMaskedColumn (R_DrawMaskedColumn, tex);
442 }
443 }
444 else
445 {
446 // [RH] Draw up to four columns at once
447 int stop = x2 & ~3;
448
449 if (x1 >= x2)
450 goto clearfog;
451
452 dc_x = x1;
453
454 while ((dc_x < stop) && (dc_x & 3))
455 {
456 BlastMaskedColumn (R_DrawMaskedColumn, tex);
457 dc_x++;
458 }
459
460 while (dc_x < stop)
461 {
462 rt_initcols();
463 BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++;
464 BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++;
465 BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++;
466 BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex);
467 rt_draw4cols (dc_x - 3);
468 dc_x++;
469 }
470
471 while (dc_x < x2)
472 {
473 BlastMaskedColumn (R_DrawMaskedColumn, tex);
474 dc_x++;
475 }
476 }
477 }
478 else
479 { // Texture does wrap vertically.
480 if (tex->bWorldPanning)
481 {
482 // rowoffset is added before the MulScale3 so that the masked texture will
483 // still be positioned in world units rather than texels.
484 dc_texturemid += rowoffset - viewz;
485 dc_texturemid = MulScale16 (dc_texturemid, MaskedScaleY);
486 }
487 else
488 {
489 // rowoffset is added outside the multiply so that it positions the texture
490 // by texels instead of world units.
491 dc_texturemid = MulScale16 (dc_texturemid - viewz, MaskedScaleY) + rowoffset;
492 }
493
494 WallC.sz1 = ds->sz1;
495 WallC.sz2 = ds->sz2;
496 WallC.sx1 = ds->sx1;
497 WallC.sx2 = ds->sx2;
498
499 if (CurrentSkybox)
500 { // Midtex clipping doesn't work properly with skyboxes, since you're normally below the floor
501 // or above the ceiling, so the appropriate end won't be clipped automatically when adding
502 // this drawseg.
503 if ((curline->linedef->flags & ML_CLIP_MIDTEX) ||
504 (curline->sidedef->Flags & WALLF_CLIP_MIDTEX))
505 {
506 ClipMidtex(x1, x2);
507 }
508 }
509
510 if (fake3D & FAKE3D_CLIPTOP)
511 {
512 OWallMost(wallupper, sclipTop - viewz, &WallC);
513 for (i = x1; i < x2; i++)
514 {
515 if (wallupper[i] < mceilingclip[i])
516 wallupper[i] = mceilingclip[i];
517 }
518 mceilingclip = wallupper;
519 }
520 if (fake3D & FAKE3D_CLIPBOTTOM)
521 {
522 OWallMost(walllower, sclipBottom - viewz, &WallC);
523 for (i = x1; i < x2; i++)
524 {
525 if (walllower[i] > mfloorclip[i])
526 walllower[i] = mfloorclip[i];
527 }
528 mfloorclip = walllower;
529 }
530
531 rw_offset = 0;
532 rw_pic = tex;
533 wallscan_np2_ds(ds, x1, x2, mceilingclip, mfloorclip, MaskedSWall, maskedtexturecol, ds->yrepeat);
534 }
535
536 clearfog:
537 R_FinishSetPatchStyle ();
538 if (ds->bFakeBoundary & 3)
539 {
540 R_RenderFakeWallRange(ds, x1, x2);
541 }
542 if (!notrelevant)
543 {
544 if (fake3D & FAKE3D_REFRESHCLIP)
545 {
546 assert(ds->bkup >= 0);
547 memcpy(openings + ds->sprtopclip, openings + ds->bkup, (ds->x2 - ds->x1) * 2);
548 }
549 else
550 {
551 clearbufshort(openings + ds->sprtopclip - ds->x1 + x1, x2 - x1, viewheight);
552 }
553 }
554 return;
555 }
556
557 // kg3D - render one fake wall
R_RenderFakeWall(drawseg_t * ds,int x1,int x2,F3DFloor * rover)558 void R_RenderFakeWall(drawseg_t *ds, int x1, int x2, F3DFloor *rover)
559 {
560 int i;
561 fixed_t xscale, yscale;
562
563 fixed_t Alpha = Scale(rover->alpha, OPAQUE, 255);
564 ESPSResult drawmode;
565 drawmode = R_SetPatchStyle (LegacyRenderStyles[rover->flags & FF_ADDITIVETRANS ? STYLE_Add : STYLE_Translucent],
566 Alpha, 0, 0);
567
568 if(drawmode == DontDraw) {
569 R_FinishSetPatchStyle();
570 return;
571 }
572
573 rw_lightstep = ds->lightstep;
574 rw_light = ds->light + (x1 - ds->x1) * rw_lightstep;
575
576 mfloorclip = openings + ds->sprbottomclip - ds->x1;
577 mceilingclip = openings + ds->sprtopclip - ds->x1;
578
579 spryscale = ds->iscale + ds->iscalestep * (x1 - ds->x1);
580 rw_scalestep = ds->iscalestep;
581 MaskedSWall = (fixed_t *)(openings + ds->swall) - ds->x1;
582
583 // find positioning
584 side_t *scaledside;
585 side_t::ETexpart scaledpart;
586 if (rover->flags & FF_UPPERTEXTURE)
587 {
588 scaledside = curline->sidedef;
589 scaledpart = side_t::top;
590 }
591 else if (rover->flags & FF_LOWERTEXTURE)
592 {
593 scaledside = curline->sidedef;
594 scaledpart = side_t::bottom;
595 }
596 else
597 {
598 scaledside = rover->master->sidedef[0];
599 scaledpart = side_t::mid;
600 }
601 xscale = FixedMul(rw_pic->xScale, scaledside->GetTextureXScale(scaledpart));
602 yscale = FixedMul(rw_pic->yScale, scaledside->GetTextureYScale(scaledpart));
603
604 fixed_t rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid);
605 dc_texturemid = rover->model->GetPlaneTexZ(sector_t::ceiling);
606 rw_offset = curline->sidedef->GetTextureXOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureXOffset(side_t::mid);
607 if (rowoffset < 0)
608 {
609 rowoffset += rw_pic->GetHeight() << FRACBITS;
610 }
611 if (rw_pic->bWorldPanning)
612 {
613 // rowoffset is added before the MulScale3 so that the masked texture will
614 // still be positioned in world units rather than texels.
615
616 dc_texturemid = MulScale16(dc_texturemid - viewz + rowoffset, yscale);
617 rw_offset = MulScale16 (rw_offset, xscale);
618 }
619 else
620 {
621 // rowoffset is added outside the multiply so that it positions the texture
622 // by texels instead of world units.
623 dc_texturemid = MulScale16(dc_texturemid - viewz, yscale) + rowoffset;
624 }
625
626 if (fixedlightlev >= 0)
627 dc_colormap = basecolormap->Maps + fixedlightlev;
628 else if (fixedcolormap != NULL)
629 dc_colormap = fixedcolormap;
630
631 WallC.sz1 = ds->sz1;
632 WallC.sz2 = ds->sz2;
633 WallC.sx1 = ds->sx1;
634 WallC.sx2 = ds->sx2;
635 WallC.tx1 = ds->cx;
636 WallC.ty1 = ds->cy;
637 WallC.tx2 = ds->cx + ds->cdx;
638 WallC.ty2 = ds->cy + ds->cdy;
639 WallT = ds->tmapvals;
640
641 OWallMost(wallupper, sclipTop - viewz, &WallC);
642 OWallMost(walllower, sclipBottom - viewz, &WallC);
643
644 for (i = x1; i < x2; i++)
645 {
646 if (wallupper[i] < mceilingclip[i])
647 wallupper[i] = mceilingclip[i];
648 }
649 for (i = x1; i < x2; i++)
650 {
651 if (walllower[i] > mfloorclip[i])
652 walllower[i] = mfloorclip[i];
653 }
654
655 PrepLWall (lwall, curline->sidedef->TexelLength*xscale, ds->sx1, ds->sx2);
656 wallscan_np2_ds(ds, x1, x2, wallupper, walllower, MaskedSWall, lwall, yscale);
657 R_FinishSetPatchStyle();
658 }
659
660 // kg3D - walls of fake floors
R_RenderFakeWallRange(drawseg_t * ds,int x1,int x2)661 void R_RenderFakeWallRange (drawseg_t *ds, int x1, int x2)
662 {
663 FTexture *const DONT_DRAW = ((FTexture*)(intptr_t)-1);
664 int i,j;
665 F3DFloor *rover, *fover = NULL;
666 int passed, last;
667 fixed_t floorheight;
668 fixed_t ceilingheight;
669
670 sprflipvert = false;
671 curline = ds->curline;
672
673 frontsector = curline->frontsector;
674 backsector = curline->backsector;
675
676 if (backsector == NULL)
677 {
678 return;
679 }
680 if ((ds->bFakeBoundary & 3) == 2)
681 {
682 sector_t *sec = backsector;
683 backsector = frontsector;
684 frontsector = sec;
685 }
686
687 floorheight = backsector->CenterFloor();
688 ceilingheight = backsector->CenterCeiling();
689
690 // maybe fix clipheights
691 if (!(fake3D & FAKE3D_CLIPBOTTOM)) sclipBottom = floorheight;
692 if (!(fake3D & FAKE3D_CLIPTOP)) sclipTop = ceilingheight;
693
694 // maybe not visible
695 if (sclipBottom >= frontsector->CenterCeiling()) return;
696 if (sclipTop <= frontsector->CenterFloor()) return;
697
698 if (fake3D & FAKE3D_DOWN2UP)
699 { // bottom to viewz
700 last = 0;
701 for (i = backsector->e->XFloor.ffloors.Size() - 1; i >= 0; i--)
702 {
703 rover = backsector->e->XFloor.ffloors[i];
704 if (!(rover->flags & FF_EXISTS)) continue;
705
706 // visible?
707 passed = 0;
708 if (!(rover->flags & FF_RENDERSIDES) ||
709 rover->top.plane->a || rover->top.plane->b ||
710 rover->bottom.plane->a || rover->bottom.plane->b ||
711 rover->top.plane->Zat0() <= sclipBottom ||
712 rover->bottom.plane->Zat0() >= ceilingheight ||
713 rover->top.plane->Zat0() <= floorheight)
714 {
715 if (!i)
716 {
717 passed = 1;
718 }
719 else
720 {
721 continue;
722 }
723 }
724
725 rw_pic = NULL;
726 if (rover->bottom.plane->Zat0() >= sclipTop || passed)
727 {
728 if (last)
729 {
730 break;
731 }
732 // maybe wall from inside rendering?
733 fover = NULL;
734 for (j = frontsector->e->XFloor.ffloors.Size() - 1; j >= 0; j--)
735 {
736 fover = frontsector->e->XFloor.ffloors[j];
737 if (fover->model == rover->model)
738 { // never
739 fover = NULL;
740 break;
741 }
742 if (!(fover->flags & FF_EXISTS)) continue;
743 if (!(fover->flags & FF_RENDERSIDES)) continue;
744 // no sloped walls, it's bugged
745 if (fover->top.plane->a || fover->top.plane->b || fover->bottom.plane->a || fover->bottom.plane->b) continue;
746
747 // visible?
748 if (fover->top.plane->Zat0() <= sclipBottom) continue; // no
749 if (fover->bottom.plane->Zat0() >= sclipTop)
750 { // no, last possible
751 fover = NULL;
752 break;
753 }
754 // it is, render inside?
755 if (!(fover->flags & (FF_BOTHPLANES|FF_INVERTPLANES)))
756 { // no
757 fover = NULL;
758 }
759 break;
760 }
761 // nothing
762 if (!fover || j == -1)
763 {
764 break;
765 }
766 // correct texture
767 if (fover->flags & rover->flags & FF_SWIMMABLE)
768 { // don't ever draw (but treat as something has been found)
769 rw_pic = DONT_DRAW;
770 }
771 else if(fover->flags & FF_UPPERTEXTURE)
772 {
773 rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top), true);
774 }
775 else if(fover->flags & FF_LOWERTEXTURE)
776 {
777 rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom), true);
778 }
779 else
780 {
781 rw_pic = TexMan(fover->master->sidedef[0]->GetTexture(side_t::mid), true);
782 }
783 }
784 else if (frontsector->e->XFloor.ffloors.Size())
785 {
786 // maybe not visible?
787 fover = NULL;
788 for (j = frontsector->e->XFloor.ffloors.Size() - 1; j >= 0; j--)
789 {
790 fover = frontsector->e->XFloor.ffloors[j];
791 if (fover->model == rover->model) // never
792 {
793 break;
794 }
795 if (!(fover->flags & FF_EXISTS)) continue;
796 if (!(fover->flags & FF_RENDERSIDES)) continue;
797 // no sloped walls, it's bugged
798 if (fover->top.plane->a || fover->top.plane->b || fover->bottom.plane->a || fover->bottom.plane->b) continue;
799
800 // visible?
801 if (fover->top.plane->Zat0() <= sclipBottom) continue; // no
802 if (fover->bottom.plane->Zat0() >= sclipTop)
803 { // visible, last possible
804 fover = NULL;
805 break;
806 }
807 if ((fover->flags & FF_SOLID) == (rover->flags & FF_SOLID) &&
808 !(!(fover->flags & FF_SOLID) && (fover->alpha == 255 || rover->alpha == 255))
809 )
810 {
811 break;
812 }
813 if (fover->flags & rover->flags & FF_SWIMMABLE)
814 { // don't ever draw (but treat as something has been found)
815 rw_pic = DONT_DRAW;
816 }
817 fover = NULL; // visible
818 break;
819 }
820 if (fover && j != -1)
821 {
822 fover = NULL;
823 last = 1;
824 continue; // not visible
825 }
826 }
827 if (!rw_pic)
828 {
829 fover = NULL;
830 if (rover->flags & FF_UPPERTEXTURE)
831 {
832 rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top), true);
833 }
834 else if(rover->flags & FF_LOWERTEXTURE)
835 {
836 rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom), true);
837 }
838 else
839 {
840 rw_pic = TexMan(rover->master->sidedef[0]->GetTexture(side_t::mid), true);
841 }
842 }
843 // correct colors now
844 basecolormap = frontsector->ColorMap;
845 wallshade = ds->shade;
846 if (fixedlightlev < 0)
847 {
848 if ((ds->bFakeBoundary & 3) == 2)
849 {
850 for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
851 {
852 if (sclipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
853 {
854 lightlist_t *lit = &backsector->e->XFloor.lightlist[j];
855 basecolormap = lit->extra_colormap;
856 wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != NULL) + r_actualextralight);
857 break;
858 }
859 }
860 }
861 else
862 {
863 for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
864 {
865 if (sclipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
866 {
867 lightlist_t *lit = &frontsector->e->XFloor.lightlist[j];
868 basecolormap = lit->extra_colormap;
869 wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != NULL) + r_actualextralight);
870 break;
871 }
872 }
873 }
874 }
875 if (rw_pic != DONT_DRAW)
876 {
877 R_RenderFakeWall(ds, x1, x2, fover ? fover : rover);
878 }
879 else rw_pic = NULL;
880 break;
881 }
882 }
883 else
884 { // top to viewz
885 for (i = 0; i < (int)backsector->e->XFloor.ffloors.Size(); i++)
886 {
887 rover = backsector->e->XFloor.ffloors[i];
888 if (!(rover->flags & FF_EXISTS)) continue;
889
890 // visible?
891 passed = 0;
892 if (!(rover->flags & FF_RENDERSIDES) ||
893 rover->top.plane->a || rover->top.plane->b ||
894 rover->bottom.plane->a || rover->bottom.plane->b ||
895 rover->bottom.plane->Zat0() >= sclipTop ||
896 rover->top.plane->Zat0() <= floorheight ||
897 rover->bottom.plane->Zat0() >= ceilingheight)
898 {
899 if ((unsigned)i == backsector->e->XFloor.ffloors.Size() - 1)
900 {
901 passed = 1;
902 }
903 else
904 {
905 continue;
906 }
907 }
908 rw_pic = NULL;
909 if (rover->top.plane->Zat0() <= sclipBottom || passed)
910 { // maybe wall from inside rendering?
911 fover = NULL;
912 for (j = 0; j < (int)frontsector->e->XFloor.ffloors.Size(); j++)
913 {
914 fover = frontsector->e->XFloor.ffloors[j];
915 if (fover->model == rover->model)
916 { // never
917 fover = NULL;
918 break;
919 }
920 if (!(fover->flags & FF_EXISTS)) continue;
921 if (!(fover->flags & FF_RENDERSIDES)) continue;
922 // no sloped walls, it's bugged
923 if (fover->top.plane->a || fover->top.plane->b || fover->bottom.plane->a || fover->bottom.plane->b) continue;
924
925 // visible?
926 if (fover->bottom.plane->Zat0() >= sclipTop) continue; // no
927 if (fover->top.plane->Zat0() <= sclipBottom)
928 { // no, last possible
929 fover = NULL;
930 break;
931 }
932 // it is, render inside?
933 if (!(fover->flags & (FF_BOTHPLANES|FF_INVERTPLANES)))
934 { // no
935 fover = NULL;
936 }
937 break;
938 }
939 // nothing
940 if (!fover || (unsigned)j == frontsector->e->XFloor.ffloors.Size())
941 {
942 break;
943 }
944 // correct texture
945 if (fover->flags & rover->flags & FF_SWIMMABLE)
946 {
947 rw_pic = DONT_DRAW; // don't ever draw (but treat as something has been found)
948 }
949 else if (fover->flags & FF_UPPERTEXTURE)
950 {
951 rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top), true);
952 }
953 else if (fover->flags & FF_LOWERTEXTURE)
954 {
955 rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom), true);
956 }
957 else
958 {
959 rw_pic = TexMan(fover->master->sidedef[0]->GetTexture(side_t::mid), true);
960 }
961 }
962 else if (frontsector->e->XFloor.ffloors.Size())
963 { // maybe not visible?
964 fover = NULL;
965 for (j = 0; j < (int)frontsector->e->XFloor.ffloors.Size(); j++)
966 {
967 fover = frontsector->e->XFloor.ffloors[j];
968 if (fover->model == rover->model)
969 { // never
970 break;
971 }
972 if (!(fover->flags & FF_EXISTS)) continue;
973 if (!(fover->flags & FF_RENDERSIDES)) continue;
974 // no sloped walls, its bugged
975 if(fover->top.plane->a || fover->top.plane->b || fover->bottom.plane->a || fover->bottom.plane->b) continue;
976
977 // visible?
978 if (fover->bottom.plane->Zat0() >= sclipTop) continue; // no
979 if (fover->top.plane->Zat0() <= sclipBottom)
980 { // visible, last possible
981 fover = NULL;
982 break;
983 }
984 if ((fover->flags & FF_SOLID) == (rover->flags & FF_SOLID) &&
985 !(!(rover->flags & FF_SOLID) && (fover->alpha == 255 || rover->alpha == 255))
986 )
987 {
988 break;
989 }
990 if (fover->flags & rover->flags & FF_SWIMMABLE)
991 { // don't ever draw (but treat as something has been found)
992 rw_pic = DONT_DRAW;
993 }
994 fover = NULL; // visible
995 break;
996 }
997 if (fover && (unsigned)j != frontsector->e->XFloor.ffloors.Size())
998 { // not visible
999 break;
1000 }
1001 }
1002 if (rw_pic == NULL)
1003 {
1004 fover = NULL;
1005 if (rover->flags & FF_UPPERTEXTURE)
1006 {
1007 rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top), true);
1008 }
1009 else if (rover->flags & FF_LOWERTEXTURE)
1010 {
1011 rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom), true);
1012 }
1013 else
1014 {
1015 rw_pic = TexMan(rover->master->sidedef[0]->GetTexture(side_t::mid), true);
1016 }
1017 }
1018 // correct colors now
1019 basecolormap = frontsector->ColorMap;
1020 wallshade = ds->shade;
1021 if (fixedlightlev < 0)
1022 {
1023 if ((ds->bFakeBoundary & 3) == 2)
1024 {
1025 for (j = backsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
1026 {
1027 if (sclipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0())
1028 {
1029 lightlist_t *lit = &backsector->e->XFloor.lightlist[j];
1030 basecolormap = lit->extra_colormap;
1031 wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != NULL) + r_actualextralight);
1032 break;
1033 }
1034 }
1035 }
1036 else
1037 {
1038 for (j = frontsector->e->XFloor.lightlist.Size() - 1; j >= 0; j--)
1039 {
1040 if(sclipTop <= frontsector->e->XFloor.lightlist[j].plane.Zat0())
1041 {
1042 lightlist_t *lit = &frontsector->e->XFloor.lightlist[j];
1043 basecolormap = lit->extra_colormap;
1044 wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != NULL) + r_actualextralight);
1045 break;
1046 }
1047 }
1048 }
1049 }
1050
1051 if (rw_pic != DONT_DRAW)
1052 {
1053 R_RenderFakeWall(ds, x1, x2, fover ? fover : rover);
1054 }
1055 else
1056 {
1057 rw_pic = NULL;
1058 }
1059 break;
1060 }
1061 }
1062 return;
1063 }
1064
1065 // prevlineasm1 is like vlineasm1 but skips the loop if only drawing one pixel
prevline1(fixed_t vince,BYTE * colormap,int count,fixed_t vplce,const BYTE * bufplce,BYTE * dest)1066 inline fixed_t prevline1 (fixed_t vince, BYTE *colormap, int count, fixed_t vplce, const BYTE *bufplce, BYTE *dest)
1067 {
1068 dc_iscale = vince;
1069 dc_colormap = colormap;
1070 dc_count = count;
1071 dc_texturefrac = vplce;
1072 dc_source = bufplce;
1073 dc_dest = dest;
1074 return doprevline1 ();
1075 }
1076
wallscan(int x1,int x2,short * uwal,short * dwal,fixed_t * swal,fixed_t * lwal,fixed_t yrepeat,const BYTE * (* getcol)(FTexture * tex,int x))1077 void wallscan (int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal,
1078 fixed_t yrepeat, const BYTE *(*getcol)(FTexture *tex, int x))
1079 {
1080 int x, shiftval;
1081 int y1ve[4], y2ve[4], u4, d4, z;
1082 char bad;
1083 fixed_t light = rw_light - rw_lightstep;
1084 SDWORD texturemid, xoffset;
1085 BYTE *basecolormapdata;
1086
1087 // This function also gets used to draw skies. Unlike BUILD, skies are
1088 // drawn by visplane instead of by bunch, so these checks are invalid.
1089 //if ((uwal[x1] > viewheight) && (uwal[x2] > viewheight)) return;
1090 //if ((dwal[x1] < 0) && (dwal[x2] < 0)) return;
1091
1092 if (rw_pic->UseType == FTexture::TEX_Null)
1093 {
1094 return;
1095 }
1096
1097 //extern cycle_t WallScanCycles;
1098 //clock (WallScanCycles);
1099
1100 rw_pic->GetHeight(); // Make sure texture size is loaded
1101 shiftval = rw_pic->HeightBits;
1102 setupvline (32-shiftval);
1103 yrepeat >>= 2 + shiftval;
1104 texturemid = dc_texturemid << (16 - shiftval);
1105 xoffset = rw_offset;
1106 basecolormapdata = basecolormap->Maps;
1107
1108 x = x1;
1109 //while ((umost[x] > dmost[x]) && (x < x2)) x++;
1110
1111 bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0);
1112 if (fixed)
1113 {
1114 palookupoffse[0] = dc_colormap;
1115 palookupoffse[1] = dc_colormap;
1116 palookupoffse[2] = dc_colormap;
1117 palookupoffse[3] = dc_colormap;
1118 }
1119
1120 for(; (x < x2) && (x & 3); ++x)
1121 {
1122 light += rw_lightstep;
1123 y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
1124 y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
1125 if (y2ve[0] <= y1ve[0]) continue;
1126 assert (y1ve[0] < viewheight);
1127 assert (y2ve[0] <= viewheight);
1128
1129 if (!fixed)
1130 { // calculate lighting
1131 dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
1132 }
1133
1134 dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
1135 dc_dest = ylookup[y1ve[0]] + x + dc_destorg;
1136 dc_iscale = swal[x] * yrepeat;
1137 dc_count = y2ve[0] - y1ve[0];
1138 dc_texturefrac = texturemid + FixedMul (dc_iscale, (y1ve[0]<<FRACBITS)-centeryfrac+FRACUNIT);
1139
1140 dovline1();
1141 }
1142
1143 for(; x < x2-3; x += 4)
1144 {
1145 bad = 0;
1146 for (z = 3; z>= 0; --z)
1147 {
1148 y1ve[z] = uwal[x+z];//max(uwal[x+z],umost[x+z]);
1149 y2ve[z] = dwal[x+z];//min(dwal[x+z],dmost[x+z])-1;
1150 if (y2ve[z] <= y1ve[z]) { bad += 1<<z; continue; }
1151 assert (y1ve[z] < viewheight);
1152 assert (y2ve[z] <= viewheight);
1153
1154 bufplce[z] = getcol (rw_pic, (lwal[x+z] + xoffset) >> FRACBITS);
1155 vince[z] = swal[x+z] * yrepeat;
1156 vplce[z] = texturemid + FixedMul (vince[z], (y1ve[z]<<FRACBITS)-centeryfrac+FRACUNIT);
1157 }
1158 if (bad == 15)
1159 {
1160 light += rw_lightstep << 2;
1161 continue;
1162 }
1163
1164 if (!fixed)
1165 {
1166 for (z = 0; z < 4; ++z)
1167 {
1168 light += rw_lightstep;
1169 palookupoffse[z] = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
1170 }
1171 }
1172
1173 u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3]));
1174 d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3]));
1175
1176 if ((bad != 0) || (u4 >= d4))
1177 {
1178 for (z = 0; z < 4; ++z)
1179 {
1180 if (!(bad & 1))
1181 {
1182 prevline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+x+z+dc_destorg);
1183 }
1184 bad >>= 1;
1185 }
1186 continue;
1187 }
1188
1189 for (z = 0; z < 4; ++z)
1190 {
1191 if (u4 > y1ve[z])
1192 {
1193 vplce[z] = prevline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+x+z+dc_destorg);
1194 }
1195 }
1196
1197 if (d4 > u4)
1198 {
1199 dc_count = d4-u4;
1200 dc_dest = ylookup[u4]+x+dc_destorg;
1201 dovline4();
1202 }
1203
1204 BYTE *i = x+ylookup[d4]+dc_destorg;
1205 for (z = 0; z < 4; ++z)
1206 {
1207 if (y2ve[z] > d4)
1208 {
1209 prevline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z);
1210 }
1211 }
1212 }
1213 for(;x<x2;x++)
1214 {
1215 light += rw_lightstep;
1216 y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
1217 y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
1218 if (y2ve[0] <= y1ve[0]) continue;
1219 assert (y1ve[0] < viewheight);
1220 assert (y2ve[0] <= viewheight);
1221
1222 if (!fixed)
1223 { // calculate lighting
1224 dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
1225 }
1226
1227 dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
1228 dc_dest = ylookup[y1ve[0]] + x + dc_destorg;
1229 dc_iscale = swal[x] * yrepeat;
1230 dc_count = y2ve[0] - y1ve[0];
1231 dc_texturefrac = texturemid + FixedMul (dc_iscale, (y1ve[0]<<FRACBITS)-centeryfrac+FRACUNIT);
1232
1233 dovline1();
1234 }
1235
1236 //unclock (WallScanCycles);
1237
1238 NetUpdate ();
1239 }
1240
wallscan_striped(int x1,int x2,short * uwal,short * dwal,fixed_t * swal,fixed_t * lwal,fixed_t yrepeat)1241 void wallscan_striped (int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat)
1242 {
1243 FDynamicColormap *startcolormap = basecolormap;
1244 int startshade = wallshade;
1245 bool fogginess = foggy;
1246
1247 short most1[MAXWIDTH], most2[MAXWIDTH], most3[MAXWIDTH];
1248 short *up, *down;
1249
1250 up = uwal;
1251 down = most1;
1252
1253 assert(WallC.sx1 <= x1);
1254 assert(WallC.sx2 >= x2);
1255
1256 // kg3D - fake floors instead of zdoom light list
1257 for (unsigned int i = 0; i < frontsector->e->XFloor.lightlist.Size(); i++)
1258 {
1259 int j = WallMost (most3, frontsector->e->XFloor.lightlist[i].plane, &WallC);
1260 if (j != 3)
1261 {
1262 for (int j = x1; j < x2; ++j)
1263 {
1264 down[j] = clamp (most3[j], up[j], dwal[j]);
1265 }
1266 wallscan (x1, x2, up, down, swal, lwal, yrepeat);
1267 up = down;
1268 down = (down == most1) ? most2 : most1;
1269 }
1270
1271 lightlist_t *lit = &frontsector->e->XFloor.lightlist[i];
1272 basecolormap = lit->extra_colormap;
1273 wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(fogginess,
1274 *lit->p_lightlevel, lit->lightsource != NULL) + r_actualextralight);
1275 }
1276
1277 wallscan (x1, x2, up, dwal, swal, lwal, yrepeat);
1278 basecolormap = startcolormap;
1279 wallshade = startshade;
1280 }
1281
call_wallscan(int x1,int x2,short * uwal,short * dwal,fixed_t * swal,fixed_t * lwal,fixed_t yrepeat,bool mask)1282 static void call_wallscan(int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat, bool mask)
1283 {
1284 if (mask)
1285 {
1286 if (colfunc == basecolfunc)
1287 {
1288 maskwallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat);
1289 }
1290 else
1291 {
1292 transmaskwallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat);
1293 }
1294 }
1295 else
1296 {
1297 if (fixedcolormap != NULL || fixedlightlev >= 0 || !(frontsector->e && frontsector->e->XFloor.lightlist.Size()))
1298 {
1299 wallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat);
1300 }
1301 else
1302 {
1303 wallscan_striped(x1, x2, uwal, dwal, swal, lwal, yrepeat);
1304 }
1305 }
1306 }
1307
1308 //=============================================================================
1309 //
1310 // wallscan_np2
1311 //
1312 // This is a wrapper around wallscan that helps it tile textures whose heights
1313 // are not powers of 2. It divides the wall into texture-sized strips and calls
1314 // wallscan for each of those. Since only one repetition of the texture fits
1315 // in each strip, wallscan will not tile.
1316 //
1317 //=============================================================================
1318
wallscan_np2(int x1,int x2,short * uwal,short * dwal,fixed_t * swal,fixed_t * lwal,fixed_t yrepeat,fixed_t top,fixed_t bot,bool mask)1319 void wallscan_np2(int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat, fixed_t top, fixed_t bot, bool mask)
1320 {
1321 if (!r_np2)
1322 {
1323 call_wallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat, mask);
1324 }
1325 else
1326 {
1327 short most1[MAXWIDTH], most2[MAXWIDTH], most3[MAXWIDTH];
1328 short *up, *down;
1329 fixed_t texheight = rw_pic->GetHeight() << FRACBITS;
1330 fixed_t scaledtexheight = FixedDiv(texheight, yrepeat);
1331 fixed_t partition;
1332
1333 if (yrepeat >= 0)
1334 { // normal orientation: draw strips from top to bottom
1335 partition = top - (top - FixedDiv(dc_texturemid, yrepeat) - viewz) % scaledtexheight;
1336 up = uwal;
1337 down = most1;
1338 dc_texturemid = FixedMul(partition - viewz, yrepeat) + texheight;
1339 while (partition > bot)
1340 {
1341 int j = OWallMost(most3, partition - viewz, &WallC);
1342 if (j != 3)
1343 {
1344 for (int j = x1; j < x2; ++j)
1345 {
1346 down[j] = clamp(most3[j], up[j], dwal[j]);
1347 }
1348 call_wallscan(x1, x2, up, down, swal, lwal, yrepeat, mask);
1349 up = down;
1350 down = (down == most1) ? most2 : most1;
1351 }
1352 partition -= scaledtexheight;
1353 dc_texturemid -= texheight;
1354 }
1355 call_wallscan(x1, x2, up, dwal, swal, lwal, yrepeat, mask);
1356 }
1357 else
1358 { // upside down: draw strips from bottom to top
1359 partition = bot - (bot - FixedDiv(dc_texturemid, yrepeat) - viewz) % scaledtexheight;
1360 up = most1;
1361 down = dwal;
1362 dc_texturemid = FixedMul(partition - viewz, yrepeat) + texheight;
1363 while (partition < top)
1364 {
1365 int j = OWallMost(most3, partition - viewz, &WallC);
1366 if (j != 12)
1367 {
1368 for (int j = x1; j < x2; ++j)
1369 {
1370 up[j] = clamp(most3[j], uwal[j], down[j]);
1371 }
1372 call_wallscan(x1, x2, up, down, swal, lwal, yrepeat, mask);
1373 down = up;
1374 up = (up == most1) ? most2 : most1;
1375 }
1376 partition -= scaledtexheight;
1377 dc_texturemid -= texheight;
1378 }
1379 call_wallscan(x1, x2, uwal, down, swal, lwal, yrepeat, mask);
1380 }
1381 }
1382 }
1383
wallscan_np2_ds(drawseg_t * ds,int x1,int x2,short * uwal,short * dwal,fixed_t * swal,fixed_t * lwal,fixed_t yrepeat)1384 static void wallscan_np2_ds(drawseg_t *ds, int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal, fixed_t yrepeat)
1385 {
1386 if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits)
1387 {
1388 fixed_t frontcz1 = ds->curline->frontsector->ceilingplane.ZatPoint(ds->curline->v1->x, ds->curline->v1->y);
1389 fixed_t frontfz1 = ds->curline->frontsector->floorplane.ZatPoint(ds->curline->v1->x, ds->curline->v1->y);
1390 fixed_t frontcz2 = ds->curline->frontsector->ceilingplane.ZatPoint(ds->curline->v2->x, ds->curline->v2->y);
1391 fixed_t frontfz2 = ds->curline->frontsector->floorplane.ZatPoint(ds->curline->v2->x, ds->curline->v2->y);
1392 fixed_t top = MAX(frontcz1, frontcz2);
1393 fixed_t bot = MIN(frontfz1, frontfz2);
1394 if (fake3D & FAKE3D_CLIPTOP)
1395 {
1396 top = MIN(top, sclipTop);
1397 }
1398 if (fake3D & FAKE3D_CLIPBOTTOM)
1399 {
1400 bot = MAX(bot, sclipBottom);
1401 }
1402 wallscan_np2(x1, x2, uwal, dwal, swal, lwal, yrepeat, top, bot, true);
1403 }
1404 else
1405 {
1406 call_wallscan(x1, x2, uwal, dwal, swal, lwal, yrepeat, true);
1407 }
1408 }
1409
mvline1(fixed_t vince,BYTE * colormap,int count,fixed_t vplce,const BYTE * bufplce,BYTE * dest)1410 inline fixed_t mvline1 (fixed_t vince, BYTE *colormap, int count, fixed_t vplce, const BYTE *bufplce, BYTE *dest)
1411 {
1412 dc_iscale = vince;
1413 dc_colormap = colormap;
1414 dc_count = count;
1415 dc_texturefrac = vplce;
1416 dc_source = bufplce;
1417 dc_dest = dest;
1418 return domvline1 ();
1419 }
1420
maskwallscan(int x1,int x2,short * uwal,short * dwal,fixed_t * swal,fixed_t * lwal,fixed_t yrepeat,const BYTE * (* getcol)(FTexture * tex,int x))1421 void maskwallscan (int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal,
1422 fixed_t yrepeat, const BYTE *(*getcol)(FTexture *tex, int x))
1423 {
1424 int x, shiftval;
1425 BYTE *p;
1426 int y1ve[4], y2ve[4], u4, d4, startx, dax, z;
1427 char bad;
1428 fixed_t light = rw_light - rw_lightstep;
1429 SDWORD texturemid, xoffset;
1430 BYTE *basecolormapdata;
1431
1432 if (rw_pic->UseType == FTexture::TEX_Null)
1433 {
1434 return;
1435 }
1436
1437 if (!rw_pic->bMasked)
1438 { // Textures that aren't masked can use the faster wallscan.
1439 wallscan (x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol);
1440 return;
1441 }
1442
1443 //extern cycle_t WallScanCycles;
1444 //clock (WallScanCycles);
1445
1446 rw_pic->GetHeight(); // Make sure texture size is loaded
1447 shiftval = rw_pic->HeightBits;
1448 setupmvline (32-shiftval);
1449 yrepeat >>= 2 + shiftval;
1450 texturemid = dc_texturemid << (16 - shiftval);
1451 xoffset = rw_offset;
1452 basecolormapdata = basecolormap->Maps;
1453
1454 x = startx = x1;
1455 p = x + dc_destorg;
1456
1457 bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0);
1458 if (fixed)
1459 {
1460 palookupoffse[0] = dc_colormap;
1461 palookupoffse[1] = dc_colormap;
1462 palookupoffse[2] = dc_colormap;
1463 palookupoffse[3] = dc_colormap;
1464 }
1465
1466 for(; (x < x2) && ((size_t)p & 3); ++x, ++p)
1467 {
1468 light += rw_lightstep;
1469 y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
1470 y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
1471 if (y2ve[0] <= y1ve[0]) continue;
1472
1473 if (!fixed)
1474 { // calculate lighting
1475 dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
1476 }
1477
1478 dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
1479 dc_dest = ylookup[y1ve[0]] + p;
1480 dc_iscale = swal[x] * yrepeat;
1481 dc_count = y2ve[0] - y1ve[0];
1482 dc_texturefrac = texturemid + FixedMul (dc_iscale, (y1ve[0]<<FRACBITS)-centeryfrac+FRACUNIT);
1483
1484 domvline1();
1485 }
1486
1487 for(; x < x2-3; x += 4, p+= 4)
1488 {
1489 bad = 0;
1490 for (z = 3, dax = x+3; z >= 0; --z, --dax)
1491 {
1492 y1ve[z] = uwal[dax];
1493 y2ve[z] = dwal[dax];
1494 if (y2ve[z] <= y1ve[z]) { bad += 1<<z; continue; }
1495
1496 bufplce[z] = getcol (rw_pic, (lwal[dax] + xoffset) >> FRACBITS);
1497 vince[z] = swal[dax] * yrepeat;
1498 vplce[z] = texturemid + FixedMul (vince[z], (y1ve[z]<<FRACBITS)-centeryfrac+FRACUNIT);
1499 }
1500 if (bad == 15)
1501 {
1502 light += rw_lightstep << 2;
1503 continue;
1504 }
1505
1506 if (!fixed)
1507 {
1508 for (z = 0; z < 4; ++z)
1509 {
1510 light += rw_lightstep;
1511 palookupoffse[z] = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
1512 }
1513 }
1514
1515 u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3]));
1516 d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3]));
1517
1518 if ((bad != 0) || (u4 >= d4))
1519 {
1520 for (z = 0; z < 4; ++z)
1521 {
1522 if (!(bad & 1))
1523 {
1524 mvline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z);
1525 }
1526 bad >>= 1;
1527 }
1528 continue;
1529 }
1530
1531 for (z = 0; z < 4; ++z)
1532 {
1533 if (u4 > y1ve[z])
1534 {
1535 vplce[z] = mvline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z);
1536 }
1537 }
1538
1539 if (d4 > u4)
1540 {
1541 dc_count = d4-u4;
1542 dc_dest = ylookup[u4]+p;
1543 domvline4();
1544 }
1545
1546 BYTE *i = p+ylookup[d4];
1547 for (z = 0; z < 4; ++z)
1548 {
1549 if (y2ve[z] > d4)
1550 {
1551 mvline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z);
1552 }
1553 }
1554 }
1555 for(; x < x2; ++x, ++p)
1556 {
1557 light += rw_lightstep;
1558 y1ve[0] = uwal[x];
1559 y2ve[0] = dwal[x];
1560 if (y2ve[0] <= y1ve[0]) continue;
1561
1562 if (!fixed)
1563 { // calculate lighting
1564 dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
1565 }
1566
1567 dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
1568 dc_dest = ylookup[y1ve[0]] + p;
1569 dc_iscale = swal[x] * yrepeat;
1570 dc_count = y2ve[0] - y1ve[0];
1571 dc_texturefrac = texturemid + FixedMul (dc_iscale, (y1ve[0]<<FRACBITS)-centeryfrac+FRACUNIT);
1572
1573 domvline1();
1574 }
1575
1576 //unclock(WallScanCycles);
1577
1578 NetUpdate ();
1579 }
1580
preptmvline1(fixed_t vince,BYTE * colormap,int count,fixed_t vplce,const BYTE * bufplce,BYTE * dest)1581 inline void preptmvline1 (fixed_t vince, BYTE *colormap, int count, fixed_t vplce, const BYTE *bufplce, BYTE *dest)
1582 {
1583 dc_iscale = vince;
1584 dc_colormap = colormap;
1585 dc_count = count;
1586 dc_texturefrac = vplce;
1587 dc_source = bufplce;
1588 dc_dest = dest;
1589 }
1590
transmaskwallscan(int x1,int x2,short * uwal,short * dwal,fixed_t * swal,fixed_t * lwal,fixed_t yrepeat,const BYTE * (* getcol)(FTexture * tex,int x))1591 void transmaskwallscan (int x1, int x2, short *uwal, short *dwal, fixed_t *swal, fixed_t *lwal,
1592 fixed_t yrepeat, const BYTE *(*getcol)(FTexture *tex, int x))
1593 {
1594 fixed_t (*tmvline1)();
1595 void (*tmvline4)();
1596 int x, shiftval;
1597 BYTE *p;
1598 int y1ve[4], y2ve[4], u4, d4, startx, dax, z;
1599 char bad;
1600 fixed_t light = rw_light - rw_lightstep;
1601 SDWORD texturemid, xoffset;
1602 BYTE *basecolormapdata;
1603
1604 if (rw_pic->UseType == FTexture::TEX_Null)
1605 {
1606 return;
1607 }
1608
1609 if (!R_GetTransMaskDrawers (&tmvline1, &tmvline4))
1610 {
1611 // The current translucency is unsupported, so draw with regular maskwallscan instead.
1612 maskwallscan (x1, x2, uwal, dwal, swal, lwal, yrepeat, getcol);
1613 return;
1614 }
1615
1616 //extern cycle_t WallScanCycles;
1617 //clock (WallScanCycles);
1618
1619 rw_pic->GetHeight(); // Make sure texture size is loaded
1620 shiftval = rw_pic->HeightBits;
1621 setuptmvline (32-shiftval);
1622 yrepeat >>= 2 + shiftval;
1623 texturemid = dc_texturemid << (16 - shiftval);
1624 xoffset = rw_offset;
1625 basecolormapdata = basecolormap->Maps;
1626
1627 x = startx = x1;
1628 p = x + dc_destorg;
1629
1630 bool fixed = (fixedcolormap != NULL || fixedlightlev >= 0);
1631 if (fixed)
1632 {
1633 palookupoffse[0] = dc_colormap;
1634 palookupoffse[1] = dc_colormap;
1635 palookupoffse[2] = dc_colormap;
1636 palookupoffse[3] = dc_colormap;
1637 }
1638
1639 for(; (x < x2) && ((size_t)p & 3); ++x, ++p)
1640 {
1641 light += rw_lightstep;
1642 y1ve[0] = uwal[x];//max(uwal[x],umost[x]);
1643 y2ve[0] = dwal[x];//min(dwal[x],dmost[x]);
1644 if (y2ve[0] <= y1ve[0]) continue;
1645
1646 if (!fixed)
1647 { // calculate lighting
1648 dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
1649 }
1650
1651 dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
1652 dc_dest = ylookup[y1ve[0]] + p;
1653 dc_iscale = swal[x] * yrepeat;
1654 dc_count = y2ve[0] - y1ve[0];
1655 dc_texturefrac = texturemid + FixedMul (dc_iscale, (y1ve[0]<<FRACBITS)-centeryfrac+FRACUNIT);
1656
1657 tmvline1();
1658 }
1659
1660 for(; x < x2-3; x += 4, p+= 4)
1661 {
1662 bad = 0;
1663 for (z = 3, dax = x+3; z >= 0; --z, --dax)
1664 {
1665 y1ve[z] = uwal[dax];
1666 y2ve[z] = dwal[dax];
1667 if (y2ve[z] <= y1ve[z]) { bad += 1<<z; continue; }
1668
1669 bufplce[z] = getcol (rw_pic, (lwal[dax] + xoffset) >> FRACBITS);
1670 vince[z] = swal[dax] * yrepeat;
1671 vplce[z] = texturemid + FixedMul (vince[z], (y1ve[z]<<FRACBITS)-centeryfrac+FRACUNIT);
1672 }
1673 if (bad == 15)
1674 {
1675 light += rw_lightstep << 2;
1676 continue;
1677 }
1678
1679 if (!fixed)
1680 {
1681 for (z = 0; z < 4; ++z)
1682 {
1683 light += rw_lightstep;
1684 palookupoffse[z] = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
1685 }
1686 }
1687
1688 u4 = MAX(MAX(y1ve[0],y1ve[1]),MAX(y1ve[2],y1ve[3]));
1689 d4 = MIN(MIN(y2ve[0],y2ve[1]),MIN(y2ve[2],y2ve[3]));
1690
1691 if ((bad != 0) || (u4 >= d4))
1692 {
1693 for (z = 0; z < 4; ++z)
1694 {
1695 if (!(bad & 1))
1696 {
1697 preptmvline1(vince[z],palookupoffse[z],y2ve[z]-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z);
1698 tmvline1();
1699 }
1700 bad >>= 1;
1701 }
1702 continue;
1703 }
1704
1705 for (z = 0; z < 4; ++z)
1706 {
1707 if (u4 > y1ve[z])
1708 {
1709 preptmvline1(vince[z],palookupoffse[z],u4-y1ve[z],vplce[z],bufplce[z],ylookup[y1ve[z]]+p+z);
1710 vplce[z] = tmvline1();
1711 }
1712 }
1713
1714 if (d4 > u4)
1715 {
1716 dc_count = d4-u4;
1717 dc_dest = ylookup[u4]+p;
1718 tmvline4();
1719 }
1720
1721 BYTE *i = p+ylookup[d4];
1722 for (z = 0; z < 4; ++z)
1723 {
1724 if (y2ve[z] > d4)
1725 {
1726 preptmvline1(vince[z],palookupoffse[0],y2ve[z]-d4,vplce[z],bufplce[z],i+z);
1727 tmvline1();
1728 }
1729 }
1730 }
1731 for(; x < x2; ++x, ++p)
1732 {
1733 light += rw_lightstep;
1734 y1ve[0] = uwal[x];
1735 y2ve[0] = dwal[x];
1736 if (y2ve[0] <= y1ve[0]) continue;
1737
1738 if (!fixed)
1739 { // calculate lighting
1740 dc_colormap = basecolormapdata + (GETPALOOKUP (light, wallshade) << COLORMAPSHIFT);
1741 }
1742
1743 dc_source = getcol (rw_pic, (lwal[x] + xoffset) >> FRACBITS);
1744 dc_dest = ylookup[y1ve[0]] + p;
1745 dc_iscale = swal[x] * yrepeat;
1746 dc_count = y2ve[0] - y1ve[0];
1747 dc_texturefrac = texturemid + FixedMul (dc_iscale, (y1ve[0]<<FRACBITS)-centeryfrac+FRACUNIT);
1748
1749 tmvline1();
1750 }
1751
1752 //unclock(WallScanCycles);
1753
1754 NetUpdate ();
1755 }
1756
1757 //
1758 // R_RenderSegLoop
1759 // Draws zero, one, or two textures for walls.
1760 // Can draw or mark the starting pixel of floor and ceiling textures.
1761 // CALLED: CORE LOOPING ROUTINE.
1762 //
1763 // [RH] Rewrote this to use Build's wallscan, so it's quite far
1764 // removed from the original Doom routine.
1765 //
1766
R_RenderSegLoop()1767 void R_RenderSegLoop ()
1768 {
1769 int x1 = rw_x;
1770 int x2 = rw_stopx;
1771 int x;
1772 fixed_t xscale, yscale;
1773 fixed_t xoffset = rw_offset;
1774
1775 if (fixedlightlev >= 0)
1776 dc_colormap = basecolormap->Maps + fixedlightlev;
1777 else if (fixedcolormap != NULL)
1778 dc_colormap = fixedcolormap;
1779
1780 // clip wall to the floor and ceiling
1781 for (x = x1; x < x2; ++x)
1782 {
1783 if (walltop[x] < ceilingclip[x])
1784 {
1785 walltop[x] = ceilingclip[x];
1786 }
1787 if (wallbottom[x] > floorclip[x])
1788 {
1789 wallbottom[x] = floorclip[x];
1790 }
1791 }
1792
1793 // mark ceiling areas
1794 if (markceiling)
1795 {
1796 for (x = x1; x < x2; ++x)
1797 {
1798 short top = (fakeFloor && fake3D & 2) ? fakeFloor->ceilingclip[x] : ceilingclip[x];
1799 short bottom = MIN (walltop[x], floorclip[x]);
1800 if (top < bottom)
1801 {
1802 ceilingplane->top[x] = top;
1803 ceilingplane->bottom[x] = bottom;
1804 }
1805 }
1806 }
1807
1808 // mark floor areas
1809 if (markfloor)
1810 {
1811 for (x = x1; x < x2; ++x)
1812 {
1813 short top = MAX (wallbottom[x], ceilingclip[x]);
1814 short bottom = (fakeFloor && fake3D & 1) ? fakeFloor->floorclip[x] : floorclip[x];
1815 if (top < bottom)
1816 {
1817 assert (bottom <= viewheight);
1818 floorplane->top[x] = top;
1819 floorplane->bottom[x] = bottom;
1820 }
1821 }
1822 }
1823
1824 // kg3D - fake planes clipping
1825 if (fake3D & FAKE3D_REFRESHCLIP)
1826 {
1827 if (fake3D & FAKE3D_CLIPBOTFRONT)
1828 {
1829 memcpy (fakeFloor->floorclip+x1, wallbottom+x1, (x2-x1)*sizeof(short));
1830 }
1831 else
1832 {
1833 for (x = x1; x < x2; ++x)
1834 {
1835 walllower[x] = MIN (MAX (walllower[x], ceilingclip[x]), wallbottom[x]);
1836 }
1837 memcpy (fakeFloor->floorclip+x1, walllower+x1, (x2-x1)*sizeof(short));
1838 }
1839 if (fake3D & FAKE3D_CLIPTOPFRONT)
1840 {
1841 memcpy (fakeFloor->ceilingclip+x1, walltop+x1, (x2-x1)*sizeof(short));
1842 }
1843 else
1844 {
1845 for (x = x1; x < x2; ++x)
1846 {
1847 wallupper[x] = MAX (MIN (wallupper[x], floorclip[x]), walltop[x]);
1848 }
1849 memcpy (fakeFloor->ceilingclip+x1, wallupper+x1, (x2-x1)*sizeof(short));
1850 }
1851 }
1852 if(fake3D & 7) return;
1853
1854 // draw the wall tiers
1855 if (midtexture)
1856 { // one sided line
1857 if (midtexture->UseType != FTexture::TEX_Null && viewactive)
1858 {
1859 dc_texturemid = rw_midtexturemid;
1860 rw_pic = midtexture;
1861 xscale = FixedMul(rw_pic->xScale, rw_midtexturescalex);
1862 yscale = FixedMul(rw_pic->yScale, rw_midtexturescaley);
1863 if (xscale != lwallscale)
1864 {
1865 PrepLWall (lwall, curline->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2);
1866 lwallscale = xscale;
1867 }
1868 if (midtexture->bWorldPanning)
1869 {
1870 rw_offset = MulScale16 (rw_offset_mid, xscale);
1871 }
1872 else
1873 {
1874 rw_offset = rw_offset_mid;
1875 }
1876 if (xscale < 0)
1877 {
1878 rw_offset = -rw_offset;
1879 }
1880 if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits)
1881 {
1882 wallscan_np2(x1, x2, walltop, wallbottom, swall, lwall, yscale, MAX(rw_frontcz1, rw_frontcz2), MIN(rw_frontfz1, rw_frontfz2), false);
1883 }
1884 else
1885 {
1886 call_wallscan(x1, x2, walltop, wallbottom, swall, lwall, yscale, false);
1887 }
1888 }
1889 clearbufshort (ceilingclip+x1, x2-x1, viewheight);
1890 clearbufshort (floorclip+x1, x2-x1, 0xffff);
1891 }
1892 else
1893 { // two sided line
1894 if (toptexture != NULL && toptexture->UseType != FTexture::TEX_Null)
1895 { // top wall
1896 for (x = x1; x < x2; ++x)
1897 {
1898 wallupper[x] = MAX (MIN (wallupper[x], floorclip[x]), walltop[x]);
1899 }
1900 if (viewactive)
1901 {
1902 dc_texturemid = rw_toptexturemid;
1903 rw_pic = toptexture;
1904 xscale = FixedMul(rw_pic->xScale, rw_toptexturescalex);
1905 yscale = FixedMul(rw_pic->yScale, rw_toptexturescaley);
1906 if (xscale != lwallscale)
1907 {
1908 PrepLWall (lwall, curline->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2);
1909 lwallscale = xscale;
1910 }
1911 if (toptexture->bWorldPanning)
1912 {
1913 rw_offset = MulScale16 (rw_offset_top, xscale);
1914 }
1915 else
1916 {
1917 rw_offset = rw_offset_top;
1918 }
1919 if (xscale < 0)
1920 {
1921 rw_offset = -rw_offset;
1922 }
1923 if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits)
1924 {
1925 wallscan_np2(x1, x2, walltop, wallupper, swall, lwall, yscale, MAX(rw_frontcz1, rw_frontcz2), MIN(rw_backcz1, rw_backcz2), false);
1926 }
1927 else
1928 {
1929 call_wallscan(x1, x2, walltop, wallupper, swall, lwall, yscale, false);
1930 }
1931 }
1932 memcpy (ceilingclip+x1, wallupper+x1, (x2-x1)*sizeof(short));
1933 }
1934 else if (markceiling)
1935 { // no top wall
1936 memcpy (ceilingclip+x1, walltop+x1, (x2-x1)*sizeof(short));
1937 }
1938
1939
1940 if (bottomtexture != NULL && bottomtexture->UseType != FTexture::TEX_Null)
1941 { // bottom wall
1942 for (x = x1; x < x2; ++x)
1943 {
1944 walllower[x] = MIN (MAX (walllower[x], ceilingclip[x]), wallbottom[x]);
1945 }
1946 if (viewactive)
1947 {
1948 dc_texturemid = rw_bottomtexturemid;
1949 rw_pic = bottomtexture;
1950 xscale = FixedMul(rw_pic->xScale, rw_bottomtexturescalex);
1951 yscale = FixedMul(rw_pic->yScale, rw_bottomtexturescaley);
1952 if (xscale != lwallscale)
1953 {
1954 PrepLWall (lwall, curline->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2);
1955 lwallscale = xscale;
1956 }
1957 if (bottomtexture->bWorldPanning)
1958 {
1959 rw_offset = MulScale16 (rw_offset_bottom, xscale);
1960 }
1961 else
1962 {
1963 rw_offset = rw_offset_bottom;
1964 }
1965 if (xscale < 0)
1966 {
1967 rw_offset = -rw_offset;
1968 }
1969 if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits)
1970 {
1971 wallscan_np2(x1, x2, walllower, wallbottom, swall, lwall, yscale, MAX(rw_backfz1, rw_backfz2), MIN(rw_frontfz1, rw_frontfz2), false);
1972 }
1973 else
1974 {
1975 call_wallscan(x1, x2, walllower, wallbottom, swall, lwall, yscale, false);
1976 }
1977 }
1978 memcpy (floorclip+x1, walllower+x1, (x2-x1)*sizeof(short));
1979 }
1980 else if (markfloor)
1981 { // no bottom wall
1982 memcpy (floorclip+x1, wallbottom+x1, (x2-x1)*sizeof(short));
1983 }
1984 }
1985 rw_offset = xoffset;
1986 }
1987
R_NewWall(bool needlights)1988 void R_NewWall (bool needlights)
1989 {
1990 fixed_t rowoffset, yrepeat;
1991
1992 rw_markmirror = false;
1993
1994 sidedef = curline->sidedef;
1995 linedef = curline->linedef;
1996
1997 // mark the segment as visible for auto map
1998 if (!r_dontmaplines) linedef->flags |= ML_MAPPED;
1999
2000 midtexture = toptexture = bottomtexture = 0;
2001
2002 if (backsector == NULL)
2003 {
2004 // single sided line
2005 // a single sided line is terminal, so it must mark ends
2006 markfloor = markceiling = true;
2007 // [RH] Render mirrors later, but mark them now.
2008 if (linedef->special != Line_Mirror || !r_drawmirrors)
2009 {
2010 // [RH] Horizon lines do not need to be textured
2011 if (linedef->special != Line_Horizon)
2012 {
2013 midtexture = TexMan(sidedef->GetTexture(side_t::mid), true);
2014 rw_offset_mid = sidedef->GetTextureXOffset(side_t::mid);
2015 rowoffset = sidedef->GetTextureYOffset(side_t::mid);
2016 rw_midtexturescalex = sidedef->GetTextureXScale(side_t::mid);
2017 rw_midtexturescaley = sidedef->GetTextureYScale(side_t::mid);
2018 yrepeat = FixedMul(midtexture->yScale, rw_midtexturescaley);
2019 if (yrepeat >= 0)
2020 { // normal orientation
2021 if (linedef->flags & ML_DONTPEGBOTTOM)
2022 { // bottom of texture at bottom
2023 rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS);
2024 }
2025 else
2026 { // top of texture at top
2027 rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat);
2028 if (rowoffset < 0 && midtexture != NULL)
2029 {
2030 rowoffset += midtexture->GetHeight() << FRACBITS;
2031 }
2032 }
2033 }
2034 else
2035 { // upside down
2036 rowoffset = -rowoffset;
2037 if (linedef->flags & ML_DONTPEGBOTTOM)
2038 { // top of texture at bottom
2039 rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat);
2040 }
2041 else
2042 { // bottom of texture at top
2043 rw_midtexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat) + (midtexture->GetHeight() << FRACBITS);
2044 }
2045 }
2046 if (midtexture->bWorldPanning)
2047 {
2048 rw_midtexturemid += MulScale16(rowoffset, yrepeat);
2049 }
2050 else
2051 {
2052 // rowoffset is added outside the multiply so that it positions the texture
2053 // by texels instead of world units.
2054 rw_midtexturemid += rowoffset;
2055 }
2056 }
2057 }
2058 else
2059 {
2060 rw_markmirror = true;
2061 }
2062 }
2063 else
2064 { // two-sided line
2065 // hack to allow height changes in outdoor areas
2066
2067 rw_frontlowertop = frontsector->GetPlaneTexZ(sector_t::ceiling);
2068
2069 if (frontsector->GetTexture(sector_t::ceiling) == skyflatnum &&
2070 backsector->GetTexture(sector_t::ceiling) == skyflatnum)
2071 {
2072 if (rw_havehigh)
2073 { // front ceiling is above back ceiling
2074 memcpy (&walltop[WallC.sx1], &wallupper[WallC.sx1], (WallC.sx2 - WallC.sx1)*sizeof(walltop[0]));
2075 rw_havehigh = false;
2076 }
2077 else if (rw_havelow && frontsector->ceilingplane != backsector->ceilingplane)
2078 { // back ceiling is above front ceiling
2079 // The check for rw_havelow is not Doom-compliant, but it avoids HoM that
2080 // would otherwise occur because there is space made available for this
2081 // wall but nothing to draw for it.
2082 // Recalculate walltop so that the wall is clipped by the back sector's
2083 // ceiling instead of the front sector's ceiling.
2084 WallMost (walltop, backsector->ceilingplane, &WallC);
2085 }
2086 // Putting sky ceilings on the front and back of a line alters the way unpegged
2087 // positioning works.
2088 rw_frontlowertop = backsector->GetPlaneTexZ(sector_t::ceiling);
2089 }
2090
2091 if ((rw_backcz1 <= rw_frontfz1 && rw_backcz2 <= rw_frontfz2) ||
2092 (rw_backfz1 >= rw_frontcz1 && rw_backfz2 >= rw_frontcz2))
2093 {
2094 // closed door
2095 markceiling = markfloor = true;
2096 }
2097 else
2098 {
2099 markfloor = rw_mustmarkfloor
2100 || backsector->floorplane != frontsector->floorplane
2101 || backsector->lightlevel != frontsector->lightlevel
2102 || backsector->GetTexture(sector_t::floor) != frontsector->GetTexture(sector_t::floor)
2103
2104 // killough 3/7/98: Add checks for (x,y) offsets
2105 || backsector->GetXOffset(sector_t::floor) != frontsector->GetXOffset(sector_t::floor)
2106 || backsector->GetYOffset(sector_t::floor) != frontsector->GetYOffset(sector_t::floor)
2107 || backsector->GetAlpha(sector_t::floor) != frontsector->GetAlpha(sector_t::floor)
2108
2109 // killough 4/15/98: prevent 2s normals
2110 // from bleeding through deep water
2111 || frontsector->heightsec
2112
2113 || backsector->GetPlaneLight(sector_t::floor) != frontsector->GetPlaneLight(sector_t::floor)
2114 || backsector->GetFlags(sector_t::floor) != frontsector->GetFlags(sector_t::floor)
2115
2116 // [RH] Add checks for colormaps
2117 || backsector->ColorMap != frontsector->ColorMap
2118
2119 || backsector->GetXScale(sector_t::floor) != frontsector->GetXScale(sector_t::floor)
2120 || backsector->GetYScale(sector_t::floor) != frontsector->GetYScale(sector_t::floor)
2121
2122 || backsector->GetAngle(sector_t::floor) != frontsector->GetAngle(sector_t::floor)
2123
2124 // kg3D - add fake lights
2125 || (frontsector->e && frontsector->e->XFloor.lightlist.Size())
2126 || (backsector->e && backsector->e->XFloor.lightlist.Size())
2127
2128 || (sidedef->GetTexture(side_t::mid).isValid() &&
2129 ((linedef->flags & (ML_CLIP_MIDTEX|ML_WRAP_MIDTEX)) ||
2130 (sidedef->Flags & (WALLF_CLIP_MIDTEX|WALLF_WRAP_MIDTEX))))
2131 ;
2132
2133 markceiling = (frontsector->GetTexture(sector_t::ceiling) != skyflatnum ||
2134 backsector->GetTexture(sector_t::ceiling) != skyflatnum) &&
2135 (rw_mustmarkceiling
2136 || backsector->ceilingplane != frontsector->ceilingplane
2137 || backsector->lightlevel != frontsector->lightlevel
2138 || backsector->GetTexture(sector_t::ceiling) != frontsector->GetTexture(sector_t::ceiling)
2139
2140 // killough 3/7/98: Add checks for (x,y) offsets
2141 || backsector->GetXOffset(sector_t::ceiling) != frontsector->GetXOffset(sector_t::ceiling)
2142 || backsector->GetYOffset(sector_t::ceiling) != frontsector->GetYOffset(sector_t::ceiling)
2143 || backsector->GetAlpha(sector_t::ceiling) != frontsector->GetAlpha(sector_t::ceiling)
2144
2145 // killough 4/15/98: prevent 2s normals
2146 // from bleeding through fake ceilings
2147 || (frontsector->heightsec && frontsector->GetTexture(sector_t::ceiling) != skyflatnum)
2148
2149 || backsector->GetPlaneLight(sector_t::ceiling) != frontsector->GetPlaneLight(sector_t::ceiling)
2150 || backsector->GetFlags(sector_t::ceiling) != frontsector->GetFlags(sector_t::ceiling)
2151
2152 // [RH] Add check for colormaps
2153 || backsector->ColorMap != frontsector->ColorMap
2154
2155 || backsector->GetXScale(sector_t::ceiling) != frontsector->GetXScale(sector_t::ceiling)
2156 || backsector->GetYScale(sector_t::ceiling) != frontsector->GetYScale(sector_t::ceiling)
2157
2158 || backsector->GetAngle(sector_t::ceiling) != frontsector->GetAngle(sector_t::ceiling)
2159
2160 // kg3D - add fake lights
2161 || (frontsector->e && frontsector->e->XFloor.lightlist.Size())
2162 || (backsector->e && backsector->e->XFloor.lightlist.Size())
2163
2164 || (sidedef->GetTexture(side_t::mid).isValid() &&
2165 ((linedef->flags & (ML_CLIP_MIDTEX|ML_WRAP_MIDTEX)) ||
2166 (sidedef->Flags & (WALLF_CLIP_MIDTEX|WALLF_WRAP_MIDTEX))))
2167 );
2168 }
2169
2170 if (rw_havehigh)
2171 { // top texture
2172 toptexture = TexMan(sidedef->GetTexture(side_t::top), true);
2173
2174 rw_offset_top = sidedef->GetTextureXOffset(side_t::top);
2175 rowoffset = sidedef->GetTextureYOffset(side_t::top);
2176 rw_toptexturescalex = sidedef->GetTextureXScale(side_t::top);
2177 rw_toptexturescaley = sidedef->GetTextureYScale(side_t::top);
2178 yrepeat = FixedMul(toptexture->yScale, rw_toptexturescaley);
2179 if (yrepeat >= 0)
2180 { // normal orientation
2181 if (linedef->flags & ML_DONTPEGTOP)
2182 { // top of texture at top
2183 rw_toptexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat);
2184 if (rowoffset < 0 && toptexture != NULL)
2185 {
2186 rowoffset += toptexture->GetHeight() << FRACBITS;
2187 }
2188 }
2189 else
2190 { // bottom of texture at bottom
2191 rw_toptexturemid = MulScale16(backsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat) + (toptexture->GetHeight() << FRACBITS);
2192 }
2193 }
2194 else
2195 { // upside down
2196 rowoffset = -rowoffset;
2197 if (linedef->flags & ML_DONTPEGTOP)
2198 { // bottom of texture at top
2199 rw_toptexturemid = MulScale16(frontsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat) + (toptexture->GetHeight() << FRACBITS);
2200 }
2201 else
2202 { // top of texture at bottom
2203 rw_toptexturemid = MulScale16(backsector->GetPlaneTexZ(sector_t::ceiling) - viewz, yrepeat);
2204 }
2205 }
2206 if (toptexture->bWorldPanning)
2207 {
2208 rw_toptexturemid += MulScale16(rowoffset, yrepeat);
2209 }
2210 else
2211 {
2212 rw_toptexturemid += rowoffset;
2213 }
2214 }
2215 if (rw_havelow)
2216 { // bottom texture
2217 bottomtexture = TexMan(sidedef->GetTexture(side_t::bottom), true);
2218
2219 rw_offset_bottom = sidedef->GetTextureXOffset(side_t::bottom);
2220 rowoffset = sidedef->GetTextureYOffset(side_t::bottom);
2221 rw_bottomtexturescalex = sidedef->GetTextureXScale(side_t::bottom);
2222 rw_bottomtexturescaley = sidedef->GetTextureYScale(side_t::bottom);
2223 yrepeat = FixedMul(bottomtexture->yScale, rw_bottomtexturescaley);
2224 if (yrepeat >= 0)
2225 { // normal orientation
2226 if (linedef->flags & ML_DONTPEGBOTTOM)
2227 { // bottom of texture at bottom
2228 rw_bottomtexturemid = MulScale16(rw_frontlowertop - viewz, yrepeat);
2229 }
2230 else
2231 { // top of texture at top
2232 rw_bottomtexturemid = MulScale16(backsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat);
2233 if (rowoffset < 0 && bottomtexture != NULL)
2234 {
2235 rowoffset += bottomtexture->GetHeight() << FRACBITS;
2236 }
2237 }
2238 }
2239 else
2240 { // upside down
2241 rowoffset = -rowoffset;
2242 if (linedef->flags & ML_DONTPEGBOTTOM)
2243 { // top of texture at bottom
2244 rw_bottomtexturemid = MulScale16(rw_frontlowertop - viewz, yrepeat);
2245 }
2246 else
2247 { // bottom of texture at top
2248 rw_bottomtexturemid = MulScale16(backsector->GetPlaneTexZ(sector_t::floor) - viewz, yrepeat) + (bottomtexture->GetHeight() << FRACBITS);
2249 }
2250 }
2251 if (bottomtexture->bWorldPanning)
2252 {
2253 rw_bottomtexturemid += MulScale16(rowoffset, yrepeat);
2254 }
2255 else
2256 {
2257 rw_bottomtexturemid += rowoffset;
2258 }
2259 }
2260 }
2261
2262 // if a floor / ceiling plane is on the wrong side of the view plane,
2263 // it is definitely invisible and doesn't need to be marked.
2264
2265 // killough 3/7/98: add deep water check
2266 if (frontsector->GetHeightSec() == NULL)
2267 {
2268 int planeside;
2269
2270 planeside = frontsector->floorplane.PointOnSide(viewx, viewy, viewz);
2271 if (frontsector->floorplane.c < 0) // 3D floors have the floor backwards
2272 planeside = -planeside;
2273 if (planeside <= 0) // above view plane
2274 markfloor = false;
2275
2276 if (frontsector->GetTexture(sector_t::ceiling) != skyflatnum)
2277 {
2278 planeside = frontsector->ceilingplane.PointOnSide(viewx, viewy, viewz);
2279 if (frontsector->ceilingplane.c > 0) // 3D floors have the ceiling backwards
2280 planeside = -planeside;
2281 if (planeside <= 0) // below view plane
2282 markceiling = false;
2283 }
2284 }
2285
2286 FTexture *midtex = TexMan(sidedef->GetTexture(side_t::mid), true);
2287
2288 segtextured = midtex != NULL || toptexture != NULL || bottomtexture != NULL;
2289
2290 // calculate light table
2291 if (needlights && (segtextured || (backsector && IsFogBoundary(frontsector, backsector))))
2292 {
2293 lwallscale =
2294 midtex ? FixedMul(midtex->xScale, sidedef->GetTextureXScale(side_t::mid)) :
2295 toptexture ? FixedMul(toptexture->xScale, sidedef->GetTextureXScale(side_t::top)) :
2296 bottomtexture ? FixedMul(bottomtexture->xScale, sidedef->GetTextureXScale(side_t::bottom)) :
2297 FRACUNIT;
2298
2299 PrepWall (swall, lwall, sidedef->TexelLength * lwallscale, WallC.sx1, WallC.sx2);
2300
2301 if (fixedcolormap == NULL && fixedlightlev < 0)
2302 {
2303 wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, frontsector->lightlevel)
2304 + r_actualextralight);
2305 GlobVis = r_WallVisibility;
2306 rw_lightleft = SafeDivScale12 (GlobVis, WallC.sz1);
2307 rw_lightstep = (SafeDivScale12 (GlobVis, WallC.sz2) - rw_lightleft) / (WallC.sx2 - WallC.sx1);
2308 }
2309 else
2310 {
2311 rw_lightleft = FRACUNIT;
2312 rw_lightstep = 0;
2313 }
2314 }
2315 }
2316
2317
2318 //
2319 // R_CheckDrawSegs
2320 //
2321
R_CheckDrawSegs()2322 void R_CheckDrawSegs ()
2323 {
2324 if (ds_p == &drawsegs[MaxDrawSegs])
2325 { // [RH] Grab some more drawsegs
2326 size_t newdrawsegs = MaxDrawSegs ? MaxDrawSegs*2 : 32;
2327 ptrdiff_t firstofs = firstdrawseg - drawsegs;
2328 drawsegs = (drawseg_t *)M_Realloc (drawsegs, newdrawsegs * sizeof(drawseg_t));
2329 firstdrawseg = drawsegs + firstofs;
2330 ds_p = drawsegs + MaxDrawSegs;
2331 MaxDrawSegs = newdrawsegs;
2332 DPrintf ("MaxDrawSegs increased to %zu\n", MaxDrawSegs);
2333 }
2334 }
2335
2336 //
2337 // R_CheckOpenings
2338 //
2339
R_NewOpening(ptrdiff_t len)2340 ptrdiff_t R_NewOpening (ptrdiff_t len)
2341 {
2342 ptrdiff_t res = lastopening;
2343 lastopening += len;
2344 if ((size_t)lastopening > maxopenings)
2345 {
2346 do
2347 maxopenings = maxopenings ? maxopenings*2 : 16384;
2348 while ((size_t)lastopening > maxopenings);
2349 openings = (short *)M_Realloc (openings, maxopenings * sizeof(*openings));
2350 DPrintf ("MaxOpenings increased to %zu\n", maxopenings);
2351 }
2352 return res;
2353 }
2354
2355
2356 //
2357 // R_StoreWallRange
2358 // A wall segment will be drawn between start and stop pixels (inclusive).
2359 //
2360
R_StoreWallRange(int start,int stop)2361 void R_StoreWallRange (int start, int stop)
2362 {
2363 int i;
2364 bool maskedtexture = false;
2365
2366 #ifdef RANGECHECK
2367 if (start >= viewwidth || start >= stop)
2368 I_FatalError ("Bad R_StoreWallRange: %i to %i", start , stop);
2369 #endif
2370
2371 // don't overflow and crash
2372 R_CheckDrawSegs ();
2373
2374 if (!rw_prepped)
2375 {
2376 rw_prepped = true;
2377 R_NewWall (true);
2378 }
2379
2380 rw_offset = sidedef->GetTextureXOffset(side_t::mid);
2381 rw_light = rw_lightleft + rw_lightstep * (start - WallC.sx1);
2382
2383 ds_p->sx1 = WallC.sx1;
2384 ds_p->sx2 = WallC.sx2;
2385 ds_p->sz1 = WallC.sz1;
2386 ds_p->sz2 = WallC.sz2;
2387 ds_p->cx = WallC.tx1;
2388 ds_p->cy = WallC.ty1;
2389 ds_p->cdx = WallC.tx2 - WallC.tx1;
2390 ds_p->cdy = WallC.ty2 - WallC.ty1;
2391 ds_p->tmapvals = WallT;
2392 ds_p->siz1 = (DWORD)DivScale32 (1, WallC.sz1) >> 1;
2393 ds_p->siz2 = (DWORD)DivScale32 (1, WallC.sz2) >> 1;
2394 ds_p->x1 = rw_x = start;
2395 ds_p->x2 = stop;
2396 ds_p->curline = curline;
2397 rw_stopx = stop;
2398 ds_p->bFogBoundary = false;
2399 ds_p->bFakeBoundary = false;
2400 if(fake3D & 7) ds_p->fake = 1;
2401 else ds_p->fake = 0;
2402
2403 // killough 1/6/98, 2/1/98: remove limit on openings
2404 ds_p->sprtopclip = ds_p->sprbottomclip = ds_p->maskedtexturecol = ds_p->bkup = ds_p->swall = -1;
2405
2406 if (rw_markmirror)
2407 {
2408 size_t drawsegnum = ds_p - drawsegs;
2409 WallMirrors.Push (drawsegnum);
2410 ds_p->silhouette = SIL_BOTH;
2411 }
2412 else if (backsector == NULL)
2413 {
2414 ds_p->sprtopclip = R_NewOpening (stop - start);
2415 ds_p->sprbottomclip = R_NewOpening (stop - start);
2416 clearbufshort (openings + ds_p->sprtopclip, stop-start, viewheight);
2417 memset (openings + ds_p->sprbottomclip, -1, (stop-start)*sizeof(short));
2418 ds_p->silhouette = SIL_BOTH;
2419 }
2420 else
2421 {
2422 // two sided line
2423 ds_p->silhouette = 0;
2424
2425 if (rw_frontfz1 > rw_backfz1 || rw_frontfz2 > rw_backfz2 ||
2426 backsector->floorplane.PointOnSide(viewx, viewy, viewz) < 0)
2427 {
2428 ds_p->silhouette = SIL_BOTTOM;
2429 }
2430
2431 if (rw_frontcz1 < rw_backcz1 || rw_frontcz2 < rw_backcz2 ||
2432 backsector->ceilingplane.PointOnSide(viewx, viewy, viewz) < 0)
2433 {
2434 ds_p->silhouette |= SIL_TOP;
2435 }
2436
2437 // killough 1/17/98: this test is required if the fix
2438 // for the automap bug (r_bsp.c) is used, or else some
2439 // sprites will be displayed behind closed doors. That
2440 // fix prevents lines behind closed doors with dropoffs
2441 // from being displayed on the automap.
2442 //
2443 // killough 4/7/98: make doorclosed external variable
2444
2445 {
2446 extern int doorclosed; // killough 1/17/98, 2/8/98, 4/7/98
2447 if (doorclosed || (rw_backcz1 <= rw_frontfz1 && rw_backcz2 <= rw_frontfz2))
2448 {
2449 ds_p->sprbottomclip = R_NewOpening (stop - start);
2450 memset (openings + ds_p->sprbottomclip, -1, (stop-start)*sizeof(short));
2451 ds_p->silhouette |= SIL_BOTTOM;
2452 }
2453 if (doorclosed || (rw_backfz1 >= rw_frontcz1 && rw_backfz2 >= rw_frontcz2))
2454 { // killough 1/17/98, 2/8/98
2455 ds_p->sprtopclip = R_NewOpening (stop - start);
2456 clearbufshort (openings + ds_p->sprtopclip, stop - start, viewheight);
2457 ds_p->silhouette |= SIL_TOP;
2458 }
2459 }
2460
2461 if(!ds_p->fake && r_3dfloors && backsector->e && backsector->e->XFloor.ffloors.Size()) {
2462 for(i = 0; i < (int)backsector->e->XFloor.ffloors.Size(); i++) {
2463 F3DFloor *rover = backsector->e->XFloor.ffloors[i];
2464 if(rover->flags & FF_RENDERSIDES && (!(rover->flags & FF_INVERTSIDES) || rover->flags & FF_ALLSIDES)) {
2465 ds_p->bFakeBoundary |= 1;
2466 break;
2467 }
2468 }
2469 }
2470 if(!ds_p->fake && r_3dfloors && frontsector->e && frontsector->e->XFloor.ffloors.Size()) {
2471 for(i = 0; i < (int)frontsector->e->XFloor.ffloors.Size(); i++) {
2472 F3DFloor *rover = frontsector->e->XFloor.ffloors[i];
2473 if(rover->flags & FF_RENDERSIDES && (rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) {
2474 ds_p->bFakeBoundary |= 2;
2475 break;
2476 }
2477 }
2478 }
2479 // kg3D - no for fakes
2480 if(!ds_p->fake)
2481 // allocate space for masked texture tables, if needed
2482 // [RH] Don't just allocate the space; fill it in too.
2483 if ((TexMan(sidedef->GetTexture(side_t::mid), true)->UseType != FTexture::TEX_Null || ds_p->bFakeBoundary || IsFogBoundary (frontsector, backsector)) &&
2484 (rw_ceilstat != 12 || !sidedef->GetTexture(side_t::top).isValid()) &&
2485 (rw_floorstat != 3 || !sidedef->GetTexture(side_t::bottom).isValid()) &&
2486 (WallC.sz1 >= TOO_CLOSE_Z && WallC.sz2 >= TOO_CLOSE_Z))
2487 {
2488 fixed_t *swal;
2489 fixed_t *lwal;
2490 int i;
2491
2492 maskedtexture = true;
2493
2494 // kg3D - backup for mid and fake walls
2495 ds_p->bkup = R_NewOpening(stop - start);
2496 memcpy(openings + ds_p->bkup, &ceilingclip[start], sizeof(short)*(stop - start));
2497
2498 ds_p->bFogBoundary = IsFogBoundary (frontsector, backsector);
2499 if (sidedef->GetTexture(side_t::mid).isValid() || ds_p->bFakeBoundary)
2500 {
2501 if(sidedef->GetTexture(side_t::mid).isValid())
2502 ds_p->bFakeBoundary |= 4; // it is also mid texture
2503
2504 ds_p->maskedtexturecol = R_NewOpening ((stop - start) * 2);
2505 ds_p->swall = R_NewOpening ((stop - start) * 2);
2506
2507 lwal = (fixed_t *)(openings + ds_p->maskedtexturecol);
2508 swal = (fixed_t *)(openings + ds_p->swall);
2509 FTexture *pic = TexMan(sidedef->GetTexture(side_t::mid), true);
2510 fixed_t yrepeat = FixedMul(pic->yScale, sidedef->GetTextureYScale(side_t::mid));
2511 fixed_t xoffset = sidedef->GetTextureXOffset(side_t::mid);
2512
2513 if (pic->bWorldPanning)
2514 {
2515 xoffset = MulScale16 (xoffset, lwallscale);
2516 }
2517
2518 for (i = start; i < stop; i++)
2519 {
2520 *lwal++ = lwall[i] + xoffset;
2521 *swal++ = swall[i];
2522 }
2523
2524 fixed_t istart = MulScale18 (*((fixed_t *)(openings + ds_p->swall)), yrepeat);
2525 fixed_t iend = MulScale18 (*(swal - 1), yrepeat);
2526
2527 if (istart < 3 && istart >= 0) istart = 3;
2528 if (istart > -3 && istart < 0) istart = -3;
2529 if (iend < 3 && iend >= 0) iend = 3;
2530 if (iend > -3 && iend < 0) iend = -3;
2531 istart = DivScale32 (1, istart);
2532 iend = DivScale32 (1, iend);
2533 ds_p->yrepeat = yrepeat;
2534 ds_p->iscale = istart;
2535 if (stop - start > 0)
2536 {
2537 ds_p->iscalestep = (iend - istart) / (stop - start);
2538 }
2539 else
2540 {
2541 ds_p->iscalestep = 0;
2542 }
2543 }
2544 ds_p->light = rw_light;
2545 ds_p->lightstep = rw_lightstep;
2546
2547 // Masked midtextures should get the light level from the sector they reference,
2548 // not from the current subsector, which is what the current wallshade value
2549 // comes from. We make an exeption for polyobjects, however, since their "home"
2550 // sector should be whichever one they move into.
2551 if (curline->sidedef->Flags & WALLF_POLYOBJ)
2552 {
2553 ds_p->shade = wallshade;
2554 }
2555 else
2556 {
2557 ds_p->shade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, curline->frontsector->lightlevel)
2558 + r_actualextralight);
2559 }
2560
2561 if (ds_p->bFogBoundary || ds_p->maskedtexturecol != -1)
2562 {
2563 size_t drawsegnum = ds_p - drawsegs;
2564 InterestingDrawsegs.Push (drawsegnum);
2565 }
2566 }
2567 }
2568
2569 // render it
2570 if (markceiling)
2571 {
2572 if (ceilingplane)
2573 { // killough 4/11/98: add NULL ptr checks
2574 ceilingplane = R_CheckPlane (ceilingplane, start, stop);
2575 }
2576 else
2577 {
2578 markceiling = false;
2579 }
2580 }
2581
2582 if (markfloor)
2583 {
2584 if (floorplane)
2585 { // killough 4/11/98: add NULL ptr checks
2586 floorplane = R_CheckPlane (floorplane, start, stop);
2587 }
2588 else
2589 {
2590 markfloor = false;
2591 }
2592 }
2593
2594 R_RenderSegLoop ();
2595
2596 if(fake3D & 7) {
2597 ds_p++;
2598 return;
2599 }
2600
2601 // save sprite clipping info
2602 if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture) && ds_p->sprtopclip == -1)
2603 {
2604 ds_p->sprtopclip = R_NewOpening (stop - start);
2605 memcpy (openings + ds_p->sprtopclip, &ceilingclip[start], sizeof(short)*(stop-start));
2606 }
2607
2608 if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture) && ds_p->sprbottomclip == -1)
2609 {
2610 ds_p->sprbottomclip = R_NewOpening (stop - start);
2611 memcpy (openings + ds_p->sprbottomclip, &floorclip[start], sizeof(short)*(stop-start));
2612 }
2613
2614 if (maskedtexture && curline->sidedef->GetTexture(side_t::mid).isValid())
2615 {
2616 ds_p->silhouette |= SIL_TOP | SIL_BOTTOM;
2617 }
2618
2619 // [RH] Draw any decals bound to the seg
2620 for (DBaseDecal *decal = curline->sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext)
2621 {
2622 R_RenderDecal (curline->sidedef, decal, ds_p, 0);
2623 }
2624
2625 ds_p++;
2626 }
2627
OWallMost(short * mostbuf,fixed_t z,const FWallCoords * wallc)2628 int OWallMost (short *mostbuf, fixed_t z, const FWallCoords *wallc)
2629 {
2630 int bad, y, ix1, ix2, iy1, iy2;
2631 fixed_t s1, s2, s3, s4;
2632
2633 z = -(z >> 4);
2634 s1 = MulScale16 (globaluclip, wallc->sz1); s2 = MulScale16 (globaluclip, wallc->sz2);
2635 s3 = MulScale16 (globaldclip, wallc->sz1); s4 = MulScale16 (globaldclip, wallc->sz2);
2636 bad = (z<s1)+((z<s2)<<1)+((z>s3)<<2)+((z>s4)<<3);
2637
2638 #if 1
2639 if ((bad&3) == 3)
2640 {
2641 memset (&mostbuf[wallc->sx1], 0, (wallc->sx2 - wallc->sx1)*sizeof(mostbuf[0]));
2642 return bad;
2643 }
2644
2645 if ((bad&12) == 12)
2646 {
2647 clearbufshort (&mostbuf[wallc->sx1], wallc->sx2 - wallc->sx1, viewheight);
2648 return bad;
2649 }
2650 #endif
2651 ix1 = wallc->sx1; iy1 = wallc->sz1;
2652 ix2 = wallc->sx2; iy2 = wallc->sz2;
2653 #if 1
2654 if (bad & 3)
2655 {
2656 int t = DivScale30 (z-s1, s2-s1);
2657 int inty = wallc->sz1 + MulScale30 (wallc->sz2 - wallc->sz1, t);
2658 int xcross = wallc->sx1 + Scale (MulScale30 (wallc->sz2, t), wallc->sx2 - wallc->sx1, inty);
2659
2660 if ((bad & 3) == 2)
2661 {
2662 if (wallc->sx1 <= xcross) { iy2 = inty; ix2 = xcross; }
2663 if (wallc->sx2 > xcross) memset (&mostbuf[xcross], 0, (wallc->sx2-xcross)*sizeof(mostbuf[0]));
2664 }
2665 else
2666 {
2667 if (xcross <= wallc->sx2) { iy1 = inty; ix1 = xcross; }
2668 if (xcross > wallc->sx1) memset (&mostbuf[wallc->sx1], 0, (xcross-wallc->sx1)*sizeof(mostbuf[0]));
2669 }
2670 }
2671
2672 if (bad & 12)
2673 {
2674 int t = DivScale30 (z-s3, s4-s3);
2675 int inty = wallc->sz1 + MulScale30 (wallc->sz2 - wallc->sz1, t);
2676 int xcross = wallc->sx1 + Scale (MulScale30 (wallc->sz2, t), wallc->sx2 - wallc->sx1, inty);
2677
2678 if ((bad & 12) == 8)
2679 {
2680 if (wallc->sx1 <= xcross) { iy2 = inty; ix2 = xcross; }
2681 if (wallc->sx2 > xcross) clearbufshort (&mostbuf[xcross], wallc->sx2 - xcross, viewheight);
2682 }
2683 else
2684 {
2685 if (xcross <= wallc->sx2) { iy1 = inty; ix1 = xcross; }
2686 if (xcross > wallc->sx1) clearbufshort (&mostbuf[wallc->sx1], xcross - wallc->sx1, viewheight);
2687 }
2688 }
2689
2690 y = Scale (z, InvZtoScale, iy1);
2691 if (ix2 == ix1)
2692 {
2693 mostbuf[ix1] = (short)((y + centeryfrac) >> FRACBITS);
2694 }
2695 else
2696 {
2697 fixed_t yinc = (Scale (z, InvZtoScale, iy2) - y) / (ix2 - ix1);
2698 qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, y + centeryfrac, yinc);
2699 }
2700 #else
2701 double max = viewheight;
2702 double zz = z / 65536.0;
2703 #if 0
2704 double z1 = zz * InvZtoScale / wallc->sz1;
2705 double z2 = zz * InvZtoScale / wallc->sz2 - z1;
2706 z2 /= (wallc->sx2 - wallc->sx1);
2707 z1 += centeryfrac / 65536.0;
2708
2709 for (int x = wallc->sx1; x < wallc->sx2; ++x)
2710 {
2711 mostbuf[x] = xs_RoundToInt(clamp(z1, 0.0, max));
2712 z1 += z2;
2713 }
2714 #else
2715 double top, bot, i;
2716
2717 i = wallc->sx1 - centerx;
2718 top = WallT.UoverZorg + WallT.UoverZstep * i;
2719 bot = WallT.InvZorg + WallT.InvZstep * i;
2720 double cy = centeryfrac / 65536.0;
2721
2722 for (int x = wallc->sx1; x < wallc->sx2; x++)
2723 {
2724 double frac = top / bot;
2725 double scale = frac * WallT.DepthScale + WallT.DepthOrg;
2726 mostbuf[x] = xs_RoundToInt(clamp(zz / scale + cy, 0.0, max));
2727 top += WallT.UoverZstep;
2728 bot += WallT.InvZstep;
2729 }
2730 #endif
2731 #endif
2732 if (mostbuf[ix1] < 0) mostbuf[ix1] = 0;
2733 else if (mostbuf[ix1] > viewheight) mostbuf[ix1] = (short)viewheight;
2734 if (mostbuf[ix2-1] < 0) mostbuf[ix2-1] = 0;
2735 else if (mostbuf[ix2-1] > viewheight) mostbuf[ix2-1] = (short)viewheight;
2736
2737 return bad;
2738 }
2739
WallMost(short * mostbuf,const secplane_t & plane,const FWallCoords * wallc)2740 int WallMost (short *mostbuf, const secplane_t &plane, const FWallCoords *wallc)
2741 {
2742 if ((plane.a | plane.b) == 0)
2743 {
2744 return OWallMost (mostbuf, ((plane.c < 0) ? plane.d : -plane.d) - viewz, wallc);
2745 }
2746
2747 fixed_t x, y, den, z1, z2, oz1, oz2;
2748 fixed_t s1, s2, s3, s4;
2749 int bad, ix1, ix2, iy1, iy2;
2750
2751 if (MirrorFlags & RF_XFLIP)
2752 {
2753 x = curline->v2->x;
2754 y = curline->v2->y;
2755 if (wallc->sx1 == 0 && 0 != (den = wallc->tx1 - wallc->tx2 + wallc->ty1 - wallc->ty2))
2756 {
2757 int frac = SafeDivScale30 (wallc->ty1 + wallc->tx1, den);
2758 x -= MulScale30 (frac, x - curline->v1->x);
2759 y -= MulScale30 (frac, y - curline->v1->y);
2760 }
2761 z1 = viewz - plane.ZatPoint (x, y);
2762
2763 if (wallc->sx2 > wallc->sx1 + 1)
2764 {
2765 x = curline->v1->x;
2766 y = curline->v1->y;
2767 if (wallc->sx2 == viewwidth && 0 != (den = wallc->tx1 - wallc->tx2 - wallc->ty1 + wallc->ty2))
2768 {
2769 int frac = SafeDivScale30 (wallc->ty2 - wallc->tx2, den);
2770 x += MulScale30 (frac, curline->v2->x - x);
2771 y += MulScale30 (frac, curline->v2->y - y);
2772 }
2773 z2 = viewz - plane.ZatPoint (x, y);
2774 }
2775 else
2776 {
2777 z2 = z1;
2778 }
2779 }
2780 else
2781 {
2782 x = curline->v1->x;
2783 y = curline->v1->y;
2784 if (wallc->sx1 == 0 && 0 != (den = wallc->tx1 - wallc->tx2 + wallc->ty1 - wallc->ty2))
2785 {
2786 int frac = SafeDivScale30 (wallc->ty1 + wallc->tx1, den);
2787 x += MulScale30 (frac, curline->v2->x - x);
2788 y += MulScale30 (frac, curline->v2->y - y);
2789 }
2790 z1 = viewz - plane.ZatPoint (x, y);
2791
2792 if (wallc->sx2 > wallc->sx1 + 1)
2793 {
2794 x = curline->v2->x;
2795 y = curline->v2->y;
2796 if (wallc->sx2 == viewwidth && 0 != (den = wallc->tx1 - wallc->tx2 - wallc->ty1 + wallc->ty2))
2797 {
2798 int frac = SafeDivScale30 (wallc->ty2 - wallc->tx2, den);
2799 x -= MulScale30 (frac, x - curline->v1->x);
2800 y -= MulScale30 (frac, y - curline->v1->y);
2801 }
2802 z2 = viewz - plane.ZatPoint (x, y);
2803 }
2804 else
2805 {
2806 z2 = z1;
2807 }
2808 }
2809
2810 s1 = MulScale12 (globaluclip, wallc->sz1); s2 = MulScale12 (globaluclip, wallc->sz2);
2811 s3 = MulScale12 (globaldclip, wallc->sz1); s4 = MulScale12 (globaldclip, wallc->sz2);
2812 bad = (z1<s1)+((z2<s2)<<1)+((z1>s3)<<2)+((z2>s4)<<3);
2813
2814 ix1 = wallc->sx1; ix2 = wallc->sx2;
2815 iy1 = wallc->sz1; iy2 = wallc->sz2;
2816 oz1 = z1; oz2 = z2;
2817
2818 if ((bad&3) == 3)
2819 {
2820 memset (&mostbuf[ix1], -1, (ix2-ix1)*sizeof(mostbuf[0]));
2821 return bad;
2822 }
2823
2824 if ((bad&12) == 12)
2825 {
2826 clearbufshort (&mostbuf[ix1], ix2-ix1, viewheight);
2827 return bad;
2828
2829 }
2830
2831 if (bad&3)
2832 {
2833 //inty = intz / (globaluclip>>16)
2834 int t = SafeDivScale30 (oz1-s1, s2-s1+oz1-oz2);
2835 int inty = wallc->sz1 + MulScale30 (wallc->sz2-wallc->sz1,t);
2836 int intz = oz1 + MulScale30 (oz2-oz1,t);
2837 int xcross = wallc->sx1 + Scale (MulScale30 (wallc->sz2, t), wallc->sx2-wallc->sx1, inty);
2838
2839 //t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4));
2840 //inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
2841 //intz = z1 + mulscale30(z2-z1,t);
2842
2843 if ((bad&3) == 2)
2844 {
2845 if (wallc->sx1 <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; }
2846 memset (&mostbuf[xcross], 0, (wallc->sx2-xcross)*sizeof(mostbuf[0]));
2847 }
2848 else
2849 {
2850 if (xcross <= wallc->sx2) { z1 = intz; iy1 = inty; ix1 = xcross; }
2851 memset (&mostbuf[wallc->sx1], 0, (xcross-wallc->sx1)*sizeof(mostbuf[0]));
2852 }
2853 }
2854
2855 if (bad&12)
2856 {
2857 //inty = intz / (globaldclip>>16)
2858 int t = SafeDivScale30 (oz1-s3, s4-s3+oz1-oz2);
2859 int inty = wallc->sz1 + MulScale30 (wallc->sz2-wallc->sz1,t);
2860 int intz = oz1 + MulScale30 (oz2-oz1,t);
2861 int xcross = wallc->sx1 + Scale (MulScale30 (wallc->sz2, t), wallc->sx2-wallc->sx1,inty);
2862
2863 //t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4));
2864 //inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t);
2865 //intz = z1 + mulscale30(z2-z1,t);
2866
2867 if ((bad&12) == 8)
2868 {
2869 if (wallc->sx1 <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; }
2870 if (wallc->sx2 > xcross) clearbufshort (&mostbuf[xcross], wallc->sx2-xcross, viewheight);
2871 }
2872 else
2873 {
2874 if (xcross <= wallc->sx2) { z1 = intz; iy1 = inty; ix1 = xcross; }
2875 if (xcross > wallc->sx1) clearbufshort (&mostbuf[wallc->sx1], xcross-wallc->sx1, viewheight);
2876 }
2877 }
2878
2879 y = Scale (z1>>4, InvZtoScale, iy1);
2880 if (ix2 == ix1)
2881 {
2882 mostbuf[ix1] = (short)((y + centeryfrac) >> FRACBITS);
2883 }
2884 else
2885 {
2886 fixed_t yinc = (Scale (z2>>4, InvZtoScale, iy2) - y) / (ix2-ix1);
2887 qinterpolatedown16short (&mostbuf[ix1], ix2-ix1, y + centeryfrac,yinc);
2888 }
2889
2890 if (mostbuf[ix1] < 0) mostbuf[ix1] = 0;
2891 else if (mostbuf[ix1] > viewheight) mostbuf[ix1] = (short)viewheight;
2892 if (mostbuf[ix2-1] < 0) mostbuf[ix2-1] = 0;
2893 else if (mostbuf[ix2-1] > viewheight) mostbuf[ix2-1] = (short)viewheight;
2894
2895 return bad;
2896 }
2897
PrepWallRoundFix(fixed_t * lwall,fixed_t walxrepeat,int x1,int x2)2898 static void PrepWallRoundFix(fixed_t *lwall, fixed_t walxrepeat, int x1, int x2)
2899 {
2900 // fix for rounding errors
2901 walxrepeat = abs(walxrepeat);
2902 fixed_t fix = (MirrorFlags & RF_XFLIP) ? walxrepeat-1 : 0;
2903 int x;
2904
2905 if (x1 > 0)
2906 {
2907 for (x = x1; x < x2; x++)
2908 {
2909 if ((unsigned)lwall[x] >= (unsigned)walxrepeat)
2910 {
2911 lwall[x] = fix;
2912 }
2913 else
2914 {
2915 break;
2916 }
2917 }
2918 }
2919 fix = walxrepeat - 1 - fix;
2920 for (x = x2-1; x >= x1; x--)
2921 {
2922 if ((unsigned)lwall[x] >= (unsigned)walxrepeat)
2923 {
2924 lwall[x] = fix;
2925 }
2926 else
2927 {
2928 break;
2929 }
2930 }
2931 }
2932
PrepWall(fixed_t * swall,fixed_t * lwall,fixed_t walxrepeat,int x1,int x2)2933 void PrepWall (fixed_t *swall, fixed_t *lwall, fixed_t walxrepeat, int x1, int x2)
2934 { // swall = scale, lwall = texturecolumn
2935 double top, bot, i;
2936 double xrepeat = fabs((double)walxrepeat);
2937 double depth_scale = WallT.InvZstep * WallTMapScale2;
2938 double depth_org = -WallT.UoverZstep * WallTMapScale2;
2939
2940 i = x1 - centerx;
2941 top = WallT.UoverZorg + WallT.UoverZstep * i;
2942 bot = WallT.InvZorg + WallT.InvZstep * i;
2943
2944 for (int x = x1; x < x2; x++)
2945 {
2946 double frac = top / bot;
2947 if (walxrepeat < 0)
2948 {
2949 lwall[x] = xs_RoundToInt(xrepeat - frac * xrepeat);
2950 }
2951 else
2952 {
2953 lwall[x] = xs_RoundToInt(frac * xrepeat);
2954 }
2955 swall[x] = xs_RoundToInt(frac * depth_scale + depth_org);
2956 top += WallT.UoverZstep;
2957 bot += WallT.InvZstep;
2958 }
2959 PrepWallRoundFix(lwall, walxrepeat, x1, x2);
2960 }
2961
PrepLWall(fixed_t * lwall,fixed_t walxrepeat,int x1,int x2)2962 void PrepLWall (fixed_t *lwall, fixed_t walxrepeat, int x1, int x2)
2963 { // lwall = texturecolumn
2964 double top, bot, i;
2965 double xrepeat = fabs((double)walxrepeat);
2966 double topstep;
2967
2968 i = x1 - centerx;
2969 top = WallT.UoverZorg + WallT.UoverZstep * i;
2970 bot = WallT.InvZorg + WallT.InvZstep * i;
2971
2972 top *= xrepeat;
2973 topstep = WallT.UoverZstep * xrepeat;
2974
2975 for (int x = x1; x < x2; x++)
2976 {
2977 if (walxrepeat < 0)
2978 {
2979 lwall[x] = xs_RoundToInt(xrepeat - top / bot);
2980 }
2981 else
2982 {
2983 lwall[x] = xs_RoundToInt(top / bot);
2984 }
2985 top += topstep;
2986 bot += WallT.InvZstep;
2987 }
2988 PrepWallRoundFix(lwall, walxrepeat, x1, x2);
2989 }
2990
2991 // pass = 0: when seg is first drawn
2992 // = 1: drawing masked textures (including sprites)
2993 // Currently, only pass = 0 is done or used
2994
R_RenderDecal(side_t * wall,DBaseDecal * decal,drawseg_t * clipper,int pass)2995 static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, int pass)
2996 {
2997 fixed_t lx, ly, lx2, ly2, decalx, decaly;
2998 int x1, x2;
2999 fixed_t xscale, yscale;
3000 fixed_t topoff;
3001 BYTE flipx;
3002 fixed_t zpos;
3003 int needrepeat = 0;
3004 sector_t *front, *back;
3005 bool calclighting;
3006 bool rereadcolormap;
3007 FDynamicColormap *usecolormap;
3008
3009 if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid())
3010 return;
3011
3012 // Determine actor z
3013 zpos = decal->Z;
3014 front = curline->frontsector;
3015 back = (curline->backsector != NULL) ? curline->backsector : curline->frontsector;
3016 switch (decal->RenderFlags & RF_RELMASK)
3017 {
3018 default:
3019 zpos = decal->Z;
3020 break;
3021 case RF_RELUPPER:
3022 if (curline->linedef->flags & ML_DONTPEGTOP)
3023 {
3024 zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
3025 }
3026 else
3027 {
3028 zpos = decal->Z + back->GetPlaneTexZ(sector_t::ceiling);
3029 }
3030 break;
3031 case RF_RELLOWER:
3032 if (curline->linedef->flags & ML_DONTPEGBOTTOM)
3033 {
3034 zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
3035 }
3036 else
3037 {
3038 zpos = decal->Z + back->GetPlaneTexZ(sector_t::floor);
3039 }
3040 break;
3041 case RF_RELMID:
3042 if (curline->linedef->flags & ML_DONTPEGBOTTOM)
3043 {
3044 zpos = decal->Z + front->GetPlaneTexZ(sector_t::floor);
3045 }
3046 else
3047 {
3048 zpos = decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
3049 }
3050 }
3051
3052 xscale = decal->ScaleX;
3053 yscale = decal->ScaleY;
3054
3055 WallSpriteTile = TexMan(decal->PicNum, true);
3056 flipx = (BYTE)(decal->RenderFlags & RF_XFLIP);
3057
3058 if (WallSpriteTile == NULL || WallSpriteTile->UseType == FTexture::TEX_Null)
3059 {
3060 return;
3061 }
3062
3063 // Determine left and right edges of sprite. Since this sprite is bound
3064 // to a wall, we use the wall's angle instead of the decal's. This is
3065 // pretty much the same as what R_AddLine() does.
3066
3067 FWallCoords savecoord = WallC;
3068
3069 x2 = WallSpriteTile->GetWidth();
3070 x1 = WallSpriteTile->LeftOffset;
3071 x2 = x2 - x1;
3072
3073 x1 *= xscale;
3074 x2 *= xscale;
3075
3076 decal->GetXY (wall, decalx, decaly);
3077
3078 angle_t ang = R_PointToAngle2 (curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y) >> ANGLETOFINESHIFT;
3079 lx = decalx - FixedMul (x1, finecosine[ang]) - viewx;
3080 lx2 = decalx + FixedMul (x2, finecosine[ang]) - viewx;
3081 ly = decaly - FixedMul (x1, finesine[ang]) - viewy;
3082 ly2 = decaly + FixedMul (x2, finesine[ang]) - viewy;
3083
3084 if (WallC.Init(lx, ly, lx2, ly2, TOO_CLOSE_Z))
3085 goto done;
3086
3087 x1 = WallC.sx1;
3088 x2 = WallC.sx2;
3089
3090 if (x1 >= clipper->x2 || x2 <= clipper->x1)
3091 goto done;
3092
3093 WallT.InitFromWallCoords(&WallC);
3094
3095 // Get the top and bottom clipping arrays
3096 switch (decal->RenderFlags & RF_CLIPMASK)
3097 {
3098 case RF_CLIPFULL:
3099 if (curline->backsector == NULL)
3100 {
3101 if (pass != 0)
3102 {
3103 goto done;
3104 }
3105 mceilingclip = walltop;
3106 mfloorclip = wallbottom;
3107 }
3108 else if (pass == 0)
3109 {
3110 mceilingclip = walltop;
3111 mfloorclip = ceilingclip;
3112 needrepeat = 1;
3113 }
3114 else
3115 {
3116 mceilingclip = openings + clipper->sprtopclip - clipper->x1;
3117 mfloorclip = openings + clipper->sprbottomclip - clipper->x1;
3118 }
3119 break;
3120
3121 case RF_CLIPUPPER:
3122 if (pass != 0)
3123 {
3124 goto done;
3125 }
3126 mceilingclip = walltop;
3127 mfloorclip = ceilingclip;
3128 break;
3129
3130 case RF_CLIPMID:
3131 if (curline->backsector != NULL && pass != 2)
3132 {
3133 goto done;
3134 }
3135 mceilingclip = openings + clipper->sprtopclip - clipper->x1;
3136 mfloorclip = openings + clipper->sprbottomclip - clipper->x1;
3137 break;
3138
3139 case RF_CLIPLOWER:
3140 if (pass != 0)
3141 {
3142 goto done;
3143 }
3144 mceilingclip = floorclip;
3145 mfloorclip = wallbottom;
3146 break;
3147 }
3148
3149 topoff = WallSpriteTile->TopOffset << FRACBITS;
3150 dc_texturemid = topoff + FixedDiv (zpos - viewz, yscale);
3151
3152 // Clip sprite to drawseg
3153 x1 = MAX<int>(clipper->x1, x1);
3154 x2 = MIN<int>(clipper->x2, x2);
3155 if (x1 >= x2)
3156 {
3157 goto done;
3158 }
3159
3160 PrepWall (swall, lwall, WallSpriteTile->GetWidth() << FRACBITS, x1, x2);
3161
3162 if (flipx)
3163 {
3164 int i;
3165 int right = (WallSpriteTile->GetWidth() << FRACBITS) - 1;
3166
3167 for (i = x1; i < x2; i++)
3168 {
3169 lwall[i] = right - lwall[i];
3170 }
3171 }
3172
3173 // Prepare lighting
3174 calclighting = false;
3175 usecolormap = basecolormap;
3176 rereadcolormap = true;
3177
3178 // Decals that are added to the scene must fade to black.
3179 if (decal->RenderStyle == LegacyRenderStyles[STYLE_Add] && usecolormap->Fade != 0)
3180 {
3181 usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate);
3182 rereadcolormap = false;
3183 }
3184
3185 rw_light = rw_lightleft + (x1 - WallC.sx1) * rw_lightstep;
3186 if (fixedlightlev >= 0)
3187 dc_colormap = usecolormap->Maps + fixedlightlev;
3188 else if (fixedcolormap != NULL)
3189 dc_colormap = fixedcolormap;
3190 else if (!foggy && (decal->RenderFlags & RF_FULLBRIGHT))
3191 dc_colormap = usecolormap->Maps;
3192 else
3193 calclighting = true;
3194
3195 // Draw it
3196 if (decal->RenderFlags & RF_YFLIP)
3197 {
3198 sprflipvert = true;
3199 yscale = -yscale;
3200 dc_texturemid = dc_texturemid - (WallSpriteTile->GetHeight() << FRACBITS);
3201 }
3202 else
3203 {
3204 sprflipvert = false;
3205 }
3206
3207 // rw_offset is used as the texture's vertical scale
3208 rw_offset = SafeDivScale30(1, yscale);
3209
3210 do
3211 {
3212 dc_x = x1;
3213 ESPSResult mode;
3214
3215 mode = R_SetPatchStyle (decal->RenderStyle, decal->Alpha, decal->Translation, decal->AlphaColor);
3216
3217 // R_SetPatchStyle can modify basecolormap.
3218 if (rereadcolormap)
3219 {
3220 usecolormap = basecolormap;
3221 }
3222
3223 if (mode == DontDraw)
3224 {
3225 needrepeat = 0;
3226 }
3227 else
3228 {
3229 int stop4;
3230
3231 if (mode == DoDraw0)
3232 { // 1 column at a time
3233 stop4 = dc_x;
3234 }
3235 else // DoDraw1
3236 { // up to 4 columns at a time
3237 stop4 = x2 & ~3;
3238 }
3239
3240 while ((dc_x < stop4) && (dc_x & 3))
3241 {
3242 if (calclighting)
3243 { // calculate lighting
3244 dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
3245 }
3246 R_WallSpriteColumn (R_DrawMaskedColumn);
3247 dc_x++;
3248 }
3249
3250 while (dc_x < stop4)
3251 {
3252 if (calclighting)
3253 { // calculate lighting
3254 dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
3255 }
3256 rt_initcols();
3257 for (int zz = 4; zz; --zz)
3258 {
3259 R_WallSpriteColumn (R_DrawMaskedColumnHoriz);
3260 dc_x++;
3261 }
3262 rt_draw4cols (dc_x - 4);
3263 }
3264
3265 while (dc_x < x2)
3266 {
3267 if (calclighting)
3268 { // calculate lighting
3269 dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT);
3270 }
3271 R_WallSpriteColumn (R_DrawMaskedColumn);
3272 dc_x++;
3273 }
3274 }
3275
3276 // If this sprite is RF_CLIPFULL on a two-sided line, needrepeat will
3277 // be set 1 if we need to draw on the lower wall. In all other cases,
3278 // needrepeat will be 0, and the while will fail.
3279 mceilingclip = floorclip;
3280 mfloorclip = wallbottom;
3281 R_FinishSetPatchStyle ();
3282 } while (needrepeat--);
3283
3284 colfunc = basecolfunc;
3285 hcolfunc_post1 = rt_map1col;
3286 hcolfunc_post4 = rt_map4cols;
3287
3288 R_FinishSetPatchStyle ();
3289 done:
3290 WallC = savecoord;
3291 }
3292