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 // $Log:$
18 //
19 // DESCRIPTION:
20 //		Sector utility functions.
21 //
22 //-----------------------------------------------------------------------------
23 
24 #include "p_spec.h"
25 #include "c_cvars.h"
26 #include "doomstat.h"
27 #include "g_level.h"
28 #include "nodebuild.h"
29 #include "p_terrain.h"
30 #include "po_man.h"
31 #include "farchive.h"
32 #include "r_utility.h"
33 #include "a_sharedglobal.h"
34 #include "r_data/colormaps.h"
35 
36 
37 // [RH]
38 // P_NextSpecialSector()
39 //
40 // Returns the next special sector attached to this sector
41 // with a certain special.
NextSpecialSector(int type,sector_t * nogood) const42 sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const
43 {
44 	sector_t *tsec;
45 	int i;
46 
47 	for (i = 0; i < linecount; i++)
48 	{
49 		line_t *ln = lines[i];
50 
51 		if (NULL != (tsec = getNextSector (ln, this)) &&
52 			tsec != nogood &&
53 			tsec->special == type)
54 		{
55 			return tsec;
56 		}
57 	}
58 	return NULL;
59 }
60 
61 //
62 // P_FindLowestFloorSurrounding()
63 // FIND LOWEST FLOOR HEIGHT IN SURROUNDING SECTORS
64 //
FindLowestFloorSurrounding(vertex_t ** v) const65 fixed_t sector_t::FindLowestFloorSurrounding (vertex_t **v) const
66 {
67 	int i;
68 	sector_t *other;
69 	line_t *check;
70 	fixed_t floor;
71 	fixed_t ofloor;
72 	vertex_t *spot;
73 
74 	if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
75 
76 	spot = lines[0]->v1;
77 	floor = floorplane.ZatPoint (spot);
78 
79 	for (i = 0; i < linecount; i++)
80 	{
81 		check = lines[i];
82 		if (NULL != (other = getNextSector (check, this)))
83 		{
84 			ofloor = other->floorplane.ZatPoint (check->v1);
85 			if (ofloor < floor && ofloor < floorplane.ZatPoint (check->v1))
86 			{
87 				floor = ofloor;
88 				spot = check->v1;
89 			}
90 			ofloor = other->floorplane.ZatPoint (check->v2);
91 			if (ofloor < floor && ofloor < floorplane.ZatPoint (check->v2))
92 			{
93 				floor = ofloor;
94 				spot = check->v2;
95 			}
96 		}
97 	}
98 	if (v != NULL)
99 		*v = spot;
100 	return floor;
101 }
102 
103 
104 
105 //
106 // P_FindHighestFloorSurrounding()
107 // FIND HIGHEST FLOOR HEIGHT IN SURROUNDING SECTORS
108 //
FindHighestFloorSurrounding(vertex_t ** v) const109 fixed_t sector_t::FindHighestFloorSurrounding (vertex_t **v) const
110 {
111 	int i;
112 	line_t *check;
113 	sector_t *other;
114 	fixed_t floor;
115 	fixed_t ofloor;
116 	vertex_t *spot;
117 
118 	if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
119 
120 	spot = lines[0]->v1;
121 	floor = FIXED_MIN;
122 
123 	for (i = 0; i < linecount; i++)
124 	{
125 		check = lines[i];
126 		if (NULL != (other = getNextSector (check, this)))
127 		{
128 			ofloor = other->floorplane.ZatPoint (check->v1);
129 			if (ofloor > floor)
130 			{
131 				floor = ofloor;
132 				spot = check->v1;
133 			}
134 			ofloor = other->floorplane.ZatPoint (check->v2);
135 			if (ofloor > floor)
136 			{
137 				floor = ofloor;
138 				spot = check->v2;
139 			}
140 		}
141 	}
142 	if (v != NULL)
143 		*v = spot;
144 	return floor;
145 }
146 
147 
148 
149 //
150 // P_FindNextHighestFloor()
151 //
152 // Passed a sector and a floor height, returns the fixed point value
153 // of the smallest floor height in a surrounding sector larger than
154 // the floor height passed. If no such height exists the floorheight
155 // passed is returned.
156 //
157 // Rewritten by Lee Killough to avoid fixed array and to be faster
158 //
FindNextHighestFloor(vertex_t ** v) const159 fixed_t sector_t::FindNextHighestFloor (vertex_t **v) const
160 {
161 	fixed_t height;
162 	fixed_t heightdiff;
163 	fixed_t ofloor, floor;
164 	sector_t *other;
165 	vertex_t *spot;
166 	line_t *check;
167 	int i;
168 
169 	if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
170 
171 	spot = lines[0]->v1;
172 	height = floorplane.ZatPoint (spot);
173 	heightdiff = FIXED_MAX;
174 
175 	for (i = 0; i < linecount; i++)
176 	{
177 		check = lines[i];
178 		if (NULL != (other = getNextSector (check, this)))
179 		{
180 			ofloor = other->floorplane.ZatPoint (check->v1);
181 			floor = floorplane.ZatPoint (check->v1);
182 			if (ofloor > floor && ofloor - floor < heightdiff && !IsLinked(other, false))
183 			{
184 				heightdiff = ofloor - floor;
185 				height = ofloor;
186 				spot = check->v1;
187 			}
188 			ofloor = other->floorplane.ZatPoint (check->v2);
189 			floor = floorplane.ZatPoint (check->v2);
190 			if (ofloor > floor && ofloor - floor < heightdiff && !IsLinked(other, false))
191 			{
192 				heightdiff = ofloor - floor;
193 				height = ofloor;
194 				spot = check->v2;
195 			}
196 		}
197 	}
198 	if (v != NULL)
199 		*v = spot;
200 	return height;
201 }
202 
203 
204 //
205 // P_FindNextLowestFloor()
206 //
207 // Passed a sector and a floor height, returns the fixed point value
208 // of the largest floor height in a surrounding sector smaller than
209 // the floor height passed. If no such height exists the floorheight
210 // passed is returned.
211 //
212 // jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
213 //
FindNextLowestFloor(vertex_t ** v) const214 fixed_t sector_t::FindNextLowestFloor (vertex_t **v) const
215 {
216 	fixed_t height;
217 	fixed_t heightdiff;
218 	fixed_t ofloor, floor;
219 	sector_t *other;
220 	vertex_t *spot;
221 	line_t *check;
222 	int i;
223 
224 	if (linecount == 0) return GetPlaneTexZ(sector_t::floor);
225 
226 	spot = lines[0]->v1;
227 	height = floorplane.ZatPoint (spot);
228 	heightdiff = FIXED_MAX;
229 
230 	for (i = 0; i < linecount; i++)
231 	{
232 		check = lines[i];
233 		if (NULL != (other = getNextSector (check, this)))
234 		{
235 			ofloor = other->floorplane.ZatPoint (check->v1);
236 			floor = floorplane.ZatPoint (check->v1);
237 			if (ofloor < floor && floor - ofloor < heightdiff && !IsLinked(other, false))
238 			{
239 				heightdiff = floor - ofloor;
240 				height = ofloor;
241 				spot = check->v1;
242 			}
243 			ofloor = other->floorplane.ZatPoint (check->v2);
244 			floor = floorplane.ZatPoint (check->v2);
245 			if (ofloor < floor && floor - ofloor < heightdiff && !IsLinked(other, false))
246 			{
247 				heightdiff = floor - ofloor;
248 				height = ofloor;
249 				spot = check->v2;
250 			}
251 		}
252 	}
253 	if (v != NULL)
254 		*v = spot;
255 	return height;
256 }
257 
258 //
259 // P_FindNextLowestCeiling()
260 //
261 // Passed a sector and a ceiling height, returns the fixed point value
262 // of the largest ceiling height in a surrounding sector smaller than
263 // the ceiling height passed. If no such height exists the ceiling height
264 // passed is returned.
265 //
266 // jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
267 //
FindNextLowestCeiling(vertex_t ** v) const268 fixed_t sector_t::FindNextLowestCeiling (vertex_t **v) const
269 {
270 	fixed_t height;
271 	fixed_t heightdiff;
272 	fixed_t oceil, ceil;
273 	sector_t *other;
274 	vertex_t *spot;
275 	line_t *check;
276 	int i;
277 
278 
279 	if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
280 
281 	spot = lines[0]->v1;
282 	height = ceilingplane.ZatPoint (spot);
283 	heightdiff = FIXED_MAX;
284 
285 	for (i = 0; i < linecount; i++)
286 	{
287 		check = lines[i];
288 		if (NULL != (other = getNextSector (check, this)))
289 		{
290 			oceil = other->ceilingplane.ZatPoint (check->v1);
291 			ceil = ceilingplane.ZatPoint (check->v1);
292 			if (oceil < ceil && ceil - oceil < heightdiff && !IsLinked(other, true))
293 			{
294 				heightdiff = ceil - oceil;
295 				height = oceil;
296 				spot = check->v1;
297 			}
298 			oceil = other->ceilingplane.ZatPoint (check->v2);
299 			ceil = ceilingplane.ZatPoint (check->v2);
300 			if (oceil < ceil && ceil - oceil < heightdiff && !IsLinked(other, true))
301 			{
302 				heightdiff = ceil - oceil;
303 				height = oceil;
304 				spot = check->v2;
305 			}
306 		}
307 	}
308 	if (v != NULL)
309 		*v = spot;
310 	return height;
311 }
312 
313 //
314 // P_FindNextHighestCeiling()
315 //
316 // Passed a sector and a ceiling height, returns the fixed point value
317 // of the smallest ceiling height in a surrounding sector larger than
318 // the ceiling height passed. If no such height exists the ceiling height
319 // passed is returned.
320 //
321 // jff 02/03/98 Twiddled Lee's P_FindNextHighestFloor to make this
322 //
FindNextHighestCeiling(vertex_t ** v) const323 fixed_t sector_t::FindNextHighestCeiling (vertex_t **v) const
324 {
325 	fixed_t height;
326 	fixed_t heightdiff;
327 	fixed_t oceil, ceil;
328 	sector_t *other;
329 	vertex_t *spot;
330 	line_t *check;
331 	int i;
332 
333 	if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
334 
335 	spot = lines[0]->v1;
336 	height = ceilingplane.ZatPoint (spot);
337 	heightdiff = FIXED_MAX;
338 
339 	for (i = 0; i < linecount; i++)
340 	{
341 		check = lines[i];
342 		if (NULL != (other = getNextSector (check, this)))
343 		{
344 			oceil = other->ceilingplane.ZatPoint (check->v1);
345 			ceil = ceilingplane.ZatPoint (check->v1);
346 			if (oceil > ceil && oceil - ceil < heightdiff && !IsLinked(other, true))
347 			{
348 				heightdiff = oceil - ceil;
349 				height = oceil;
350 				spot = check->v1;
351 			}
352 			oceil = other->ceilingplane.ZatPoint (check->v2);
353 			ceil = ceilingplane.ZatPoint (check->v2);
354 			if (oceil > ceil && oceil - ceil < heightdiff && !IsLinked(other, true))
355 			{
356 				heightdiff = oceil - ceil;
357 				height = oceil;
358 				spot = check->v2;
359 			}
360 		}
361 	}
362 	if (v != NULL)
363 		*v = spot;
364 	return height;
365 }
366 
367 //
368 // FIND LOWEST CEILING IN THE SURROUNDING SECTORS
369 //
FindLowestCeilingSurrounding(vertex_t ** v) const370 fixed_t sector_t::FindLowestCeilingSurrounding (vertex_t **v) const
371 {
372 	fixed_t height;
373 	fixed_t oceil;
374 	sector_t *other;
375 	vertex_t *spot;
376 	line_t *check;
377 	int i;
378 
379 	if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
380 
381 	spot = lines[0]->v1;
382 	height = FIXED_MAX;
383 
384 	for (i = 0; i < linecount; i++)
385 	{
386 		check = lines[i];
387 		if (NULL != (other = getNextSector (check, this)))
388 		{
389 			oceil = other->ceilingplane.ZatPoint (check->v1);
390 			if (oceil < height)
391 			{
392 				height = oceil;
393 				spot = check->v1;
394 			}
395 			oceil = other->ceilingplane.ZatPoint (check->v2);
396 			if (oceil < height)
397 			{
398 				height = oceil;
399 				spot = check->v2;
400 			}
401 		}
402 	}
403 	if (v != NULL)
404 		*v = spot;
405 	return height;
406 }
407 
408 
409 //
410 // FIND HIGHEST CEILING IN THE SURROUNDING SECTORS
411 //
FindHighestCeilingSurrounding(vertex_t ** v) const412 fixed_t sector_t::FindHighestCeilingSurrounding (vertex_t **v) const
413 {
414 	fixed_t height;
415 	fixed_t oceil;
416 	sector_t *other;
417 	vertex_t *spot;
418 	line_t *check;
419 	int i;
420 
421 	if (linecount == 0) return GetPlaneTexZ(sector_t::ceiling);
422 
423 	spot = lines[0]->v1;
424 	height = FIXED_MIN;
425 
426 	for (i = 0; i < linecount; i++)
427 	{
428 		check = lines[i];
429 		if (NULL != (other = getNextSector (check, this)))
430 		{
431 			oceil = other->ceilingplane.ZatPoint (check->v1);
432 			if (oceil > height)
433 			{
434 				height = oceil;
435 				spot = check->v1;
436 			}
437 			oceil = other->ceilingplane.ZatPoint (check->v2);
438 			if (oceil > height)
439 			{
440 				height = oceil;
441 				spot = check->v2;
442 			}
443 		}
444 	}
445 	if (v != NULL)
446 		*v = spot;
447 	return height;
448 }
449 
450 //
451 // P_FindShortestTextureAround()
452 //
453 // Passed a sector number, returns the shortest lower texture on a
454 // linedef bounding the sector.
455 //
456 // jff 02/03/98 Add routine to find shortest lower texture
457 //
458 
CheckShortestTex(FTextureID texnum,fixed_t & minsize)459 static inline void CheckShortestTex (FTextureID texnum, fixed_t &minsize)
460 {
461 	if (texnum.isValid() || (texnum.isNull() && (i_compatflags & COMPATF_SHORTTEX)))
462 	{
463 		FTexture *tex = TexMan[texnum];
464 		if (tex != NULL)
465 		{
466 			fixed_t h = tex->GetScaledHeight()<<FRACBITS;
467 			if (h < minsize)
468 			{
469 				minsize = h;
470 			}
471 		}
472 	}
473 }
474 
FindShortestTextureAround() const475 fixed_t sector_t::FindShortestTextureAround () const
476 {
477 	fixed_t minsize = FIXED_MAX;
478 
479 	for (int i = 0; i < linecount; i++)
480 	{
481 		if (lines[i]->flags & ML_TWOSIDED)
482 		{
483 			CheckShortestTex (lines[i]->sidedef[0]->GetTexture(side_t::bottom), minsize);
484 			CheckShortestTex (lines[i]->sidedef[1]->GetTexture(side_t::bottom), minsize);
485 		}
486 	}
487 	return minsize < FIXED_MAX ? minsize : TexMan[0]->GetHeight() * FRACUNIT;
488 }
489 
490 
491 //
492 // P_FindShortestUpperAround()
493 //
494 // Passed a sector number, returns the shortest upper texture on a
495 // linedef bounding the sector.
496 //
497 // Note: If no upper texture exists MAXINT is returned.
498 //
499 // jff 03/20/98 Add routine to find shortest upper texture
500 //
FindShortestUpperAround() const501 fixed_t sector_t::FindShortestUpperAround () const
502 {
503 	fixed_t minsize = FIXED_MAX;
504 
505 	for (int i = 0; i < linecount; i++)
506 	{
507 		if (lines[i]->flags & ML_TWOSIDED)
508 		{
509 			CheckShortestTex (lines[i]->sidedef[0]->GetTexture(side_t::top), minsize);
510 			CheckShortestTex (lines[i]->sidedef[1]->GetTexture(side_t::top), minsize);
511 		}
512 	}
513 	return minsize < FIXED_MAX ? minsize : TexMan[0]->GetHeight() * FRACUNIT;
514 }
515 
516 
517 //
518 // P_FindModelFloorSector()
519 //
520 // Passed a floor height and a sector number, return a pointer to a
521 // a sector with that floor height across the lowest numbered two sided
522 // line surrounding the sector.
523 //
524 // Note: If no sector at that height bounds the sector passed, return NULL
525 //
526 // jff 02/03/98 Add routine to find numeric model floor
527 //  around a sector specified by sector number
528 // jff 3/14/98 change first parameter to plain height to allow call
529 //  from routine not using floormove_t
530 //
FindModelFloorSector(fixed_t floordestheight) const531 sector_t *sector_t::FindModelFloorSector (fixed_t floordestheight) const
532 {
533 	int i;
534 	sector_t *sec;
535 
536 	//jff 5/23/98 don't disturb sec->linecount while searching
537 	// but allow early exit in old demos
538 	for (i = 0; i < linecount; i++)
539 	{
540 		sec = getNextSector (lines[i], this);
541 		if (sec != NULL &&
542 			(sec->floorplane.ZatPoint (lines[i]->v1) == floordestheight ||
543 			 sec->floorplane.ZatPoint (lines[i]->v2) == floordestheight))
544 		{
545 			return sec;
546 		}
547 	}
548 	return NULL;
549 }
550 
551 
552 //
553 // P_FindModelCeilingSector()
554 //
555 // Passed a ceiling height and a sector number, return a pointer to a
556 // a sector with that ceiling height across the lowest numbered two sided
557 // line surrounding the sector.
558 //
559 // Note: If no sector at that height bounds the sector passed, return NULL
560 //
561 // jff 02/03/98 Add routine to find numeric model ceiling
562 //  around a sector specified by sector number
563 //  used only from generalized ceiling types
564 // jff 3/14/98 change first parameter to plain height to allow call
565 //  from routine not using ceiling_t
566 //
FindModelCeilingSector(fixed_t floordestheight) const567 sector_t *sector_t::FindModelCeilingSector (fixed_t floordestheight) const
568 {
569 	int i;
570 	sector_t *sec;
571 
572 	//jff 5/23/98 don't disturb sec->linecount while searching
573 	// but allow early exit in old demos
574 	for (i = 0; i < linecount; i++)
575 	{
576 		sec = getNextSector (lines[i], this);
577 		if (sec != NULL &&
578 			(sec->ceilingplane.ZatPoint (lines[i]->v1) == floordestheight ||
579 			 sec->ceilingplane.ZatPoint (lines[i]->v2) == floordestheight))
580 		{
581 			return sec;
582 		}
583 	}
584 	return NULL;
585 }
586 
587 //
588 // Find minimum light from an adjacent sector
589 //
FindMinSurroundingLight(int min) const590 int sector_t::FindMinSurroundingLight (int min) const
591 {
592 	int 		i;
593 	line_t* 	line;
594 	sector_t*	check;
595 
596 	for (i = 0; i < linecount; i++)
597 	{
598 		line = lines[i];
599 		if (NULL != (check = getNextSector (line, this)) &&
600 			check->lightlevel < min)
601 		{
602 			min = check->lightlevel;
603 		}
604 	}
605 	return min;
606 }
607 
608 //
609 // Find the highest point on the floor of the sector
610 //
FindHighestFloorPoint(vertex_t ** v) const611 fixed_t sector_t::FindHighestFloorPoint (vertex_t **v) const
612 {
613 	int i;
614 	line_t *line;
615 	fixed_t height = FIXED_MIN;
616 	fixed_t probeheight;
617 	vertex_t *spot = NULL;
618 
619 	if ((floorplane.a | floorplane.b) == 0)
620 	{
621 		if (v != NULL)
622 		{
623 			if (linecount == 0) *v = &vertexes[0];
624 			else *v = lines[0]->v1;
625 		}
626 		return -floorplane.d;
627 	}
628 
629 	for (i = 0; i < linecount; i++)
630 	{
631 		line = lines[i];
632 		probeheight = floorplane.ZatPoint (line->v1);
633 		if (probeheight > height)
634 		{
635 			height = probeheight;
636 			spot = line->v1;
637 		}
638 		probeheight = floorplane.ZatPoint (line->v2);
639 		if (probeheight > height)
640 		{
641 			height = probeheight;
642 			spot = line->v2;
643 		}
644 	}
645 	if (v != NULL)
646 		*v = spot;
647 	return height;
648 }
649 
650 //
651 // Find the lowest point on the ceiling of the sector
652 //
FindLowestCeilingPoint(vertex_t ** v) const653 fixed_t sector_t::FindLowestCeilingPoint (vertex_t **v) const
654 {
655 	int i;
656 	line_t *line;
657 	fixed_t height = FIXED_MAX;
658 	fixed_t probeheight;
659 	vertex_t *spot = NULL;
660 
661 	if ((ceilingplane.a | ceilingplane.b) == 0)
662 	{
663 		if (v != NULL)
664 		{
665 			if (linecount == 0) *v = &vertexes[0];
666 			else *v = lines[0]->v1;
667 		}
668 		return ceilingplane.d;
669 	}
670 
671 	for (i = 0; i < linecount; i++)
672 	{
673 		line = lines[i];
674 		probeheight = ceilingplane.ZatPoint (line->v1);
675 		if (probeheight < height)
676 		{
677 			height = probeheight;
678 			spot = line->v1;
679 		}
680 		probeheight = ceilingplane.ZatPoint (line->v2);
681 		if (probeheight < height)
682 		{
683 			height = probeheight;
684 			spot = line->v2;
685 		}
686 	}
687 	if (v != NULL)
688 		*v = spot;
689 	return height;
690 }
691 
692 
SetColor(int r,int g,int b,int desat)693 void sector_t::SetColor(int r, int g, int b, int desat)
694 {
695 	PalEntry color = PalEntry (r,g,b);
696 	ColorMap = GetSpecialLights (color, ColorMap->Fade, desat);
697 	P_RecalculateAttachedLights(this);
698 }
699 
SetFade(int r,int g,int b)700 void sector_t::SetFade(int r, int g, int b)
701 {
702 	PalEntry fade = PalEntry (r,g,b);
703 	ColorMap = GetSpecialLights (ColorMap->Color, fade, ColorMap->Desaturate);
704 	P_RecalculateAttachedLights(this);
705 }
706 
707 //===========================================================================
708 //
709 // sector_t :: ClosestPoint
710 //
711 // Given a point (x,y), returns the point (ox,oy) on the sector's defining
712 // lines that is nearest to (x,y).
713 //
714 //===========================================================================
715 
ClosestPoint(fixed_t fx,fixed_t fy,fixed_t & ox,fixed_t & oy) const716 void sector_t::ClosestPoint(fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy) const
717 {
718 	int i;
719 	double x = fx, y = fy;
720 	double bestdist = HUGE_VAL;
721 	double bestx = 0, besty = 0;
722 
723 	for (i = 0; i < linecount; ++i)
724 	{
725 		vertex_t *v1 = lines[i]->v1;
726 		vertex_t *v2 = lines[i]->v2;
727 		double a = v2->x - v1->x;
728 		double b = v2->y - v1->y;
729 		double den = a*a + b*b;
730 		double ix, iy, dist;
731 
732 		if (den == 0)
733 		{ // Line is actually a point!
734 			ix = v1->x;
735 			iy = v1->y;
736 		}
737 		else
738 		{
739 			double num = (x - v1->x) * a + (y - v1->y) * b;
740 			double u = num / den;
741 			if (u <= 0)
742 			{
743 				ix = v1->x;
744 				iy = v1->y;
745 			}
746 			else if (u >= 1)
747 			{
748 				ix = v2->x;
749 				iy = v2->y;
750 			}
751 			else
752 			{
753 				ix = v1->x + u * a;
754 				iy = v1->y + u * b;
755 			}
756 		}
757 		a = (ix - x);
758 		b = (iy - y);
759 		dist = a*a + b*b;
760 		if (dist < bestdist)
761 		{
762 			bestdist = dist;
763 			bestx = ix;
764 			besty = iy;
765 		}
766 	}
767 	ox = fixed_t(bestx);
768 	oy = fixed_t(besty);
769 }
770 
771 
PlaneMoving(int pos)772 bool sector_t::PlaneMoving(int pos)
773 {
774 	if (pos == floor)
775 		return (floordata != NULL || (planes[floor].Flags & PLANEF_BLOCKED));
776 	else
777 		return (ceilingdata != NULL || (planes[ceiling].Flags & PLANEF_BLOCKED));
778 }
779 
780 
GetFloorLight() const781 int sector_t::GetFloorLight () const
782 {
783 	if (GetFlags(sector_t::floor) & PLANEF_ABSLIGHTING)
784 	{
785 		return GetPlaneLight(floor);
786 	}
787 	else
788 	{
789 		return ClampLight(lightlevel + GetPlaneLight(floor));
790 	}
791 }
792 
GetCeilingLight() const793 int sector_t::GetCeilingLight () const
794 {
795 	if (GetFlags(ceiling) & PLANEF_ABSLIGHTING)
796 	{
797 		return GetPlaneLight(ceiling);
798 	}
799 	else
800 	{
801 		return ClampLight(lightlevel + GetPlaneLight(ceiling));
802 	}
803 }
804 
805 
GetSkyBox(int which)806 ASkyViewpoint *sector_t::GetSkyBox(int which)
807 {
808 	if (SkyBoxes[which] != NULL) return SkyBoxes[which];
809 	if (MoreFlags & (SECF_NOFLOORSKYBOX << which)) return NULL;
810 	return level.DefaultSkybox;
811 }
812 
813 
GetHeightSec() const814 sector_t *sector_t::GetHeightSec() const
815 {
816 	if (heightsec == NULL)
817 	{
818 		return NULL;
819 	}
820 	if (heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC)
821 	{
822 		return NULL;
823 	}
824 	if (e && e->XFloor.ffloors.Size())
825 	{
826 		// If any of these fake floors render their planes, ignore heightsec.
827 		for (unsigned i = e->XFloor.ffloors.Size(); i-- > 0; )
828 		{
829 			if ((e->XFloor.ffloors[i]->flags & (FF_EXISTS | FF_RENDERPLANES)) == (FF_EXISTS | FF_RENDERPLANES))
830 			{
831 				return NULL;
832 			}
833 		}
834 	}
835 	return heightsec;
836 }
837 
838 
GetSpecial(secspecial_t * spec)839 void sector_t::GetSpecial(secspecial_t *spec)
840 {
841 	spec->special = special;
842 	spec->damageamount = damageamount;
843 	spec->damagetype = damagetype;
844 	spec->damageinterval = damageinterval;
845 	spec->leakydamage = leakydamage;
846 	spec->Flags = Flags & SECF_SPECIALFLAGS;
847 }
848 
SetSpecial(const secspecial_t * spec)849 void sector_t::SetSpecial(const secspecial_t *spec)
850 {
851 	special = spec->special;
852 	damageamount = spec->damageamount;
853 	damagetype = spec->damagetype;
854 	damageinterval = spec->damageinterval;
855 	leakydamage = spec->leakydamage;
856 	Flags = (Flags & ~SECF_SPECIALFLAGS) | (spec->Flags & SECF_SPECIALFLAGS);
857 }
858 
TransferSpecial(sector_t * model)859 void sector_t::TransferSpecial(sector_t *model)
860 {
861 	special = model->special;
862 	damageamount = model->damageamount;
863 	damagetype = model->damagetype;
864 	damageinterval = model->damageinterval;
865 	leakydamage = model->leakydamage;
866 	Flags = (Flags&~SECF_SPECIALFLAGS) | (model->Flags & SECF_SPECIALFLAGS);
867 }
868 
GetTerrain(int pos) const869 int sector_t::GetTerrain(int pos) const
870 {
871 	return terrainnum[pos] >= 0 ? terrainnum[pos] : TerrainTypes[GetTexture(pos)];
872 }
873 
operator <<(FArchive & arc,secspecial_t & p)874 FArchive &operator<< (FArchive &arc, secspecial_t &p)
875 {
876 	if (SaveVersion < 4529)
877 	{
878 		int special;
879 		arc << special;
880 		sector_t sec;
881 		memset(&sec, 0, sizeof(sec));
882 		P_InitSectorSpecial(&sec, special, true);
883 		sec.GetSpecial(&p);
884 	}
885 	else
886 	{
887 		arc << p.special
888 			<< p.damageamount
889 			<< p.damagetype
890 			<< p.damageinterval
891 			<< p.leakydamage
892 			<< p.Flags;
893 	}
894 	return arc;
895 }
896 
897 
898 
CopyPlaneIfValid(secplane_t * dest,const secplane_t * opp) const899 bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const
900 {
901 	bool copy = false;
902 
903 	// If the planes do not have matching slopes, then always copy them
904 	// because clipping would require creating new sectors.
905 	if (a != dest->a || b != dest->b || c != dest->c)
906 	{
907 		copy = true;
908 	}
909 	else if (opp->a != -dest->a || opp->b != -dest->b || opp->c != -dest->c)
910 	{
911 		if (d < dest->d)
912 		{
913 			copy = true;
914 		}
915 	}
916 	else if (d < dest->d && d > -opp->d)
917 	{
918 		copy = true;
919 	}
920 
921 	if (copy)
922 	{
923 		*dest = *this;
924 	}
925 
926 	return copy;
927 }
928 
operator <<(FArchive & arc,secplane_t & plane)929 FArchive &operator<< (FArchive &arc, secplane_t &plane)
930 {
931 	arc << plane.a << plane.b << plane.c << plane.d;
932 	//if (plane.c != 0)
933 	{	// plane.c should always be non-0. Otherwise, the plane
934 		// would be perfectly vertical.
935 		plane.ic = DivScale32 (1, plane.c);
936 	}
937 	return arc;
938 }
939 
940 //==========================================================================
941 //
942 // P_AlignFlat
943 //
944 //==========================================================================
945 
P_AlignFlat(int linenum,int side,int fc)946 bool P_AlignFlat (int linenum, int side, int fc)
947 {
948 	line_t *line = lines + linenum;
949 	sector_t *sec = side ? line->backsector : line->frontsector;
950 
951 	if (!sec)
952 		return false;
953 
954 	fixed_t x = line->v1->x;
955 	fixed_t y = line->v1->y;
956 
957 	angle_t angle = R_PointToAngle2 (x, y, line->v2->x, line->v2->y);
958 	angle_t norm = (angle-ANGLE_90) >> ANGLETOFINESHIFT;
959 
960 	fixed_t dist = -DMulScale16 (finecosine[norm], x, finesine[norm], y);
961 
962 	if (side)
963 	{
964 		angle = angle + ANGLE_180;
965 		dist = -dist;
966 	}
967 
968 	sec->SetBase(fc, dist & ((1<<(FRACBITS+8))-1), 0-angle);
969 	return true;
970 }
971 
972 //==========================================================================
973 //
974 // P_BuildPolyBSP
975 //
976 //==========================================================================
977 static FNodeBuilder::FLevel PolyNodeLevel;
978 static FNodeBuilder PolyNodeBuilder(PolyNodeLevel);
979 
BuildPolyBSP()980 void subsector_t::BuildPolyBSP()
981 {
982 	assert((BSP == NULL || BSP->bDirty) && "BSP computed more than once");
983 
984 	// Set up level information for the node builder.
985 	PolyNodeLevel.Sides = sides;
986 	PolyNodeLevel.NumSides = numsides;
987 	PolyNodeLevel.Lines = lines;
988 	PolyNodeLevel.NumLines = numlines;
989 
990 	// Feed segs to the nodebuilder and build the nodes.
991 	PolyNodeBuilder.Clear();
992 	PolyNodeBuilder.AddSegs(firstline, numlines);
993 	for (FPolyNode *pn = polys; pn != NULL; pn = pn->pnext)
994 	{
995 		PolyNodeBuilder.AddPolySegs(&pn->segs[0], (int)pn->segs.Size());
996 	}
997 	PolyNodeBuilder.BuildMini(false);
998 	if (BSP == NULL)
999 	{
1000 		BSP = new FMiniBSP;
1001 	}
1002 	PolyNodeBuilder.ExtractMini(BSP);
1003 	for (unsigned int i = 0; i < BSP->Subsectors.Size(); ++i)
1004 	{
1005 		BSP->Subsectors[i].sector = sector;
1006 	}
1007 }
1008 
1009 //==========================================================================
1010 //
1011 //
1012 //
1013 //==========================================================================
1014 
1015 CUSTOM_CVAR(Int, r_fakecontrast, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
1016 {
1017 	if (self < 0) self = 1;
1018 	else if (self > 2) self = 2;
1019 }
1020 
1021 //==========================================================================
1022 //
1023 //
1024 //
1025 //==========================================================================
1026 
GetLightLevel(bool foggy,int baselight,bool is3dlight,int * pfakecontrast) const1027 int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfakecontrast) const
1028 {
1029 	if (!is3dlight && (Flags & WALLF_ABSLIGHTING))
1030 	{
1031 		baselight = Light;
1032 	}
1033 
1034 	if (pfakecontrast != NULL)
1035 	{
1036 		*pfakecontrast = 0;
1037 	}
1038 
1039 	if (!foggy || level.flags3 & LEVEL3_FORCEFAKECONTRAST) // Don't do relative lighting in foggy sectors
1040 	{
1041 		if (!(Flags & WALLF_NOFAKECONTRAST) && r_fakecontrast != 0)
1042 		{
1043 			int rel;
1044 			if (((level.flags2 & LEVEL2_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_fakecontrast == 2) &&
1045 				linedef->dx != 0)
1046 			{
1047 				rel = xs_RoundToInt // OMG LEE KILLOUGH LIVES! :/
1048 					(
1049 						level.WallHorizLight
1050 						+ fabs(atan(double(linedef->dy) / linedef->dx) / 1.57079)
1051 						* (level.WallVertLight - level.WallHorizLight)
1052 					);
1053 			}
1054 			else
1055 			{
1056 				rel = linedef->dx == 0 ? level.WallVertLight :
1057 					  linedef->dy == 0 ? level.WallHorizLight : 0;
1058 			}
1059 			if (pfakecontrast != NULL)
1060 			{
1061 				*pfakecontrast = rel;
1062 			}
1063 			else
1064 			{
1065 				baselight += rel;
1066 			}
1067 		}
1068 	}
1069 	if (!is3dlight && !(Flags & WALLF_ABSLIGHTING) && (!foggy || (Flags & WALLF_LIGHT_FOG)))
1070 	{
1071 		baselight += this->Light;
1072 	}
1073 	return baselight;
1074 }
1075 
1076