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