2021-03-18 11:32:31 +00:00
/*
* * hw_bunchdrawer . cpp
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2021-03-18 20:50:02 +00:00
* * Copyright 2008 - 2021 Christoph Oelckers
2021-03-18 11:32:31 +00:00
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
# include "hw_drawinfo.h"
# include "hw_bunchdrawer.h"
# include "hw_clipper.h"
# include "hw_clock.h"
# include "hw_drawstructs.h"
# include "automap.h"
2021-03-18 11:49:33 +00:00
# include "gamefuncs.h"
2021-03-25 15:45:40 +00:00
# include "hw_portal.h"
2021-04-03 19:40:32 +00:00
# include "gamestruct.h"
2021-04-05 11:55:36 +00:00
# include "hw_voxels.h"
2021-04-24 18:00:54 +00:00
# include "mapinfo.h"
# include "gamecontrol.h"
2021-05-02 22:15:09 +00:00
# include "hw_sections.h"
2021-12-04 18:08:50 +00:00
# include "coreactor.h"
2022-12-08 17:26:09 +00:00
# include "texinfo.h"
2022-12-09 21:16:38 +00:00
# include "buildtiles.h"
2021-03-18 11:32:31 +00:00
2022-01-09 11:05:36 +00:00
//#define DEBUG_CLIPPER
2021-03-18 11:32:31 +00:00
//==========================================================================
//
//
//
//==========================================================================
2022-09-16 17:13:06 +00:00
void BunchDrawer : : Init ( HWDrawInfo * _di , Clipper * c , const DVector2 & view , angle_t a1 , angle_t a2 )
2021-03-18 11:32:31 +00:00
{
2022-08-27 09:54:55 +00:00
ang1 = a1 ;
ang2 = a2 ;
2021-05-14 08:50:22 +00:00
angrange = ang2 - ang1 ;
2021-03-18 11:32:31 +00:00
di = _di ;
clipper = c ;
2022-09-16 17:13:06 +00:00
viewx = view . X ;
viewy = view . Y ;
2021-12-19 17:53:53 +00:00
viewz = ( float ) di - > Viewpoint . Pos . Z ;
2022-08-22 16:15:11 +00:00
2021-03-18 11:32:31 +00:00
StartScene ( ) ;
2021-03-25 22:16:32 +00:00
2022-08-27 13:56:17 +00:00
gcosang = g_cosbam ( di - > Viewpoint . RotAngle ) ;
gsinang = g_sinbam ( di - > Viewpoint . RotAngle ) ;
2021-03-25 22:16:32 +00:00
2021-12-21 09:51:41 +00:00
for ( auto & w : wall )
2021-03-18 11:32:31 +00:00
{
// Precalculate the clip angles to avoid doing this repeatedly during level traversal.
2022-09-16 17:13:06 +00:00
DVector2 vv ;
vv . X = w . pos . X - view . X ;
vv . Y = w . pos . Y + view . Y ; // beware of different coordinate systems!
2023-08-19 16:08:27 +00:00
w . clipangle = vv . Angle ( ) . BAMs ( ) ;
2021-03-18 11:32:31 +00:00
}
2021-12-06 19:54:21 +00:00
memset ( sectionstartang . Data ( ) , - 1 , sectionstartang . Size ( ) * sizeof ( sectionstartang [ 0 ] ) ) ;
memset ( sectionendang . Data ( ) , - 1 , sectionendang . Size ( ) * sizeof ( sectionendang [ 0 ] ) ) ;
2021-12-21 09:51:41 +00:00
//blockwall.Resize(wall.Size());
2021-03-18 11:32:31 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
void BunchDrawer : : StartScene ( )
{
2021-12-15 12:08:09 +00:00
unsigned numsections = sections . Size ( ) ;
2021-03-18 11:32:31 +00:00
LastBunch = 0 ;
StartTime = I_msTime ( ) ;
Bunches . Clear ( ) ;
CompareData . Clear ( ) ;
2021-12-21 09:51:41 +00:00
gotsector . Resize ( sector . Size ( ) ) ;
2021-03-18 11:32:31 +00:00
gotsector . Zero ( ) ;
2021-12-15 11:32:53 +00:00
gotsection2 . Resize ( numsections ) ;
2021-05-02 22:15:09 +00:00
gotsection2 . Zero ( ) ;
2022-01-04 16:16:34 +00:00
gotwall . Resize ( wall . Size ( ) ) ;
2021-04-06 22:02:36 +00:00
gotwall . Zero ( ) ;
2021-12-15 11:32:53 +00:00
sectionstartang . Resize ( numsections ) ;
sectionendang . Resize ( numsections ) ;
2021-12-20 11:49:44 +00:00
//blockwall.Zero();
2021-03-18 11:32:31 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
2022-08-27 09:54:55 +00:00
bool BunchDrawer : : StartBunch ( int sectnum , int linenum , angle_t startan , angle_t endan , bool portal )
2021-03-18 11:32:31 +00:00
{
FBunch * bunch = & Bunches [ LastBunch = Bunches . Reserve ( 1 ) ] ;
2021-12-01 23:01:45 +00:00
bunch - > sectornum = sectnum ;
2021-03-18 11:32:31 +00:00
bunch - > startline = bunch - > endline = linenum ;
2022-08-27 09:54:55 +00:00
bunch - > startangle = startan ;
bunch - > endangle = endan ;
2021-04-06 17:25:40 +00:00
bunch - > portal = portal ;
2022-08-27 09:29:58 +00:00
assert ( bunch - > endangle > = bunch - > startangle ) ;
2022-08-27 09:38:37 +00:00
return bunch - > endangle ! = angrange ;
2021-03-18 11:32:31 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
2022-08-27 09:54:55 +00:00
bool BunchDrawer : : AddLineToBunch ( int line , angle_t newan )
2021-03-18 11:32:31 +00:00
{
Bunches [ LastBunch ] . endline + + ;
2022-08-27 09:54:55 +00:00
assert ( newan > Bunches [ LastBunch ] . endangle ) ;
Bunches [ LastBunch ] . endangle = newan ;
2022-08-27 09:29:58 +00:00
assert ( Bunches [ LastBunch ] . endangle > Bunches [ LastBunch ] . startangle ) ;
2022-08-27 09:38:37 +00:00
return Bunches [ LastBunch ] . endangle ! = angrange ;
2021-03-18 11:32:31 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
void BunchDrawer : : DeleteBunch ( int index )
{
Bunches [ index ] = Bunches . Last ( ) ;
Bunches . Pop ( ) ;
}
2021-12-19 17:53:53 +00:00
bool BunchDrawer : : CheckClip ( walltype * wal , float * topclip , float * bottomclip )
2021-03-18 11:32:31 +00:00
{
2021-11-26 19:55:13 +00:00
auto pt2 = wal - > point2Wall ( ) ;
sectortype * backsector = wal - > nextSector ( ) ;
sectortype * frontsector = wal - > sectorp ( ) ;
2021-03-22 15:02:52 +00:00
2021-03-18 11:32:31 +00:00
float bs_floorheight1 ;
float bs_floorheight2 ;
float bs_ceilingheight1 ;
float bs_ceilingheight2 ;
float fs_floorheight1 ;
float fs_floorheight2 ;
float fs_ceilingheight1 ;
float fs_ceilingheight2 ;
// Mirrors and horizons always block the view
//if (linedef->special==Line_Mirror || linedef->special==Line_Horizon) return true;
2022-01-27 18:27:27 +00:00
PlanesAtPoint ( frontsector , wal - > pos . X , wal - > pos . Y , & fs_ceilingheight1 , & fs_floorheight1 ) ;
PlanesAtPoint ( frontsector , pt2 - > pos . X , pt2 - > pos . Y , & fs_ceilingheight2 , & fs_floorheight2 ) ;
2021-03-18 11:32:31 +00:00
2022-01-27 18:27:27 +00:00
PlanesAtPoint ( backsector , wal - > pos . X , wal - > pos . Y , & bs_ceilingheight1 , & bs_floorheight1 ) ;
PlanesAtPoint ( backsector , pt2 - > pos . X , pt2 - > pos . Y , & bs_ceilingheight2 , & bs_floorheight2 ) ;
2021-03-18 11:32:31 +00:00
2021-12-26 22:57:00 +00:00
* bottomclip = max ( min ( bs_floorheight1 , bs_floorheight2 ) , min ( fs_floorheight1 , fs_floorheight2 ) ) ;
2021-12-19 17:53:53 +00:00
// if one plane is sky on both sides, the line must not clip.
if ( frontsector - > ceilingstat & backsector - > ceilingstat & CSTAT_SECTOR_SKY )
{
// save some processing with outside areas - no need to add to the clipper if back sector is higher.
2022-01-13 18:46:04 +00:00
/*if (fs_ceilingheight1 <= bs_floorheight1 && fs_ceilingheight2 <= bs_floorheight2)*/ * bottomclip = - FLT_MAX ;
2021-12-19 17:53:53 +00:00
* topclip = FLT_MAX ;
return false ;
}
2021-12-26 22:57:00 +00:00
* topclip = min ( max ( bs_ceilingheight1 , bs_ceilingheight2 ) , max ( fs_ceilingheight1 , fs_ceilingheight2 ) ) ;
2021-12-19 17:53:53 +00:00
if ( frontsector - > floorstat & backsector - > floorstat & CSTAT_SECTOR_SKY )
{
* bottomclip = - FLT_MAX ;
return false ;
}
// now check for closed sectors.
2021-03-18 11:32:31 +00:00
if ( bs_ceilingheight1 < = fs_floorheight1 & & bs_ceilingheight2 < = fs_floorheight2 )
{
// backsector's ceiling is below frontsector's floor.
return true ;
}
if ( fs_ceilingheight1 < = bs_floorheight1 & & fs_ceilingheight2 < = bs_floorheight2 )
{
// backsector's floor is above frontsector's ceiling
return true ;
}
if ( bs_ceilingheight1 < = bs_floorheight1 & & bs_ceilingheight2 < = bs_floorheight2 )
{
// backsector is closed
return true ;
}
return false ;
}
//==========================================================================
//
// ClipLine
// Clips the given segment
//
//==========================================================================
2021-05-02 22:15:09 +00:00
int BunchDrawer : : ClipLine ( int aline , bool portal )
2021-03-18 11:32:31 +00:00
{
2021-05-02 22:15:09 +00:00
auto cline = & sectionLines [ aline ] ;
int section = cline - > section ;
int line = cline - > wall ;
2021-03-18 11:32:31 +00:00
2021-05-14 08:50:22 +00:00
auto startAngleBam = ClipAngle ( cline - > startpoint ) ;
auto endAngleBam = ClipAngle ( cline - > endpoint ) ;
2021-03-18 11:32:31 +00:00
2021-04-24 10:08:38 +00:00
// Back side, i.e. backface culling - read: endAngle <= startAngle!
2022-08-27 09:54:55 +00:00
if ( startAngleBam - endAngleBam < ANGLE_180 )
2021-03-18 11:32:31 +00:00
{
return CL_Skip ;
}
2021-12-20 11:49:44 +00:00
//if (line >= 0 && blockwall[line]) return CL_Draw;
2021-05-02 22:15:09 +00:00
2021-04-24 10:08:38 +00:00
// convert to clipper coordinates and clamp to valid range.
2022-08-27 09:54:55 +00:00
int startAngle = startAngleBam ;
int endAngle = endAngleBam ;
2021-04-24 10:08:38 +00:00
if ( startAngle < 0 ) startAngle = 0 ;
2022-08-27 09:38:37 +00:00
if ( endAngle < 0 | | endAngle > ( int ) angrange ) endAngle = angrange ;
2021-04-24 10:08:38 +00:00
// since these values are derived from previous calls of this function they cannot be out of range.
2021-05-02 22:15:09 +00:00
int sectStartAngle = sectionstartang [ section ] ;
auto sectEndAngle = sectionendang [ section ] ;
2021-04-24 10:08:38 +00:00
// check against the maximum possible viewing range of the sector.
// Todo: check if this is sufficient or if we really have to do a more costly check against the single visible segments.
2021-12-12 18:38:36 +00:00
// Note: These walls may be excluded from the clipper, but not from being drawn!
2022-01-09 19:38:07 +00:00
// if sectors got dragged around there may be overlaps which this code does not handle well do it may not run on such sectors.
2021-12-12 18:38:36 +00:00
bool dontclip = false ;
2022-01-29 08:59:29 +00:00
if ( sectStartAngle ! = - 1 & & ! ( sector [ sections [ section ] . sector ] . exflags & SECTOREX_DRAGGED ) )
2021-04-24 10:08:38 +00:00
{
2022-01-09 19:38:07 +00:00
if ( ( sectStartAngle > endAngle | | sectEndAngle < startAngle ) )
2021-12-12 18:38:36 +00:00
{
dontclip = true ;
}
else
{
2021-12-12 20:39:01 +00:00
if ( sectStartAngle > startAngle ) startAngle = sectStartAngle ;
if ( sectEndAngle < endAngle ) endAngle = sectEndAngle ;
if ( endAngle < = startAngle ) return CL_Skip ; // can this even happen?
2021-12-12 18:38:36 +00:00
}
2021-04-24 10:08:38 +00:00
}
2021-03-18 11:32:31 +00:00
2021-04-24 10:08:38 +00:00
if ( ! portal & & ! clipper - > IsRangeVisible ( startAngle , endAngle ) )
2021-03-18 11:32:31 +00:00
{
2023-09-23 11:32:09 +00:00
//Printf("\nWall %d from %2.3f - %2.3f (clipped away)\n", line, DAngle::fromBam(startAngle).Degrees(), DAngle::fromBam(endAngle).Degrees());
2021-03-18 11:32:31 +00:00
return CL_Skip ;
}
2021-12-19 17:53:53 +00:00
float topclip = 0 , bottomclip = 0 ;
2023-09-23 11:32:09 +00:00
if ( line > = 0 & & ( cline - > partner = = - 1 | | ( wall [ line ] . cstat & CSTAT_WALL_1WAY ) | | CheckClip ( & wall [ line ] , & topclip , & bottomclip ) ) )
2021-03-18 11:32:31 +00:00
{
// one-sided
2022-06-26 07:36:01 +00:00
if ( ! portal & & ! dontclip & & ! ( sector [ sections [ section ] . sector ] . exflags & SECTOREX_DONTCLIP ) )
2021-12-19 17:53:53 +00:00
{
clipper - > AddClipRange ( startAngle , endAngle ) ;
2023-09-23 11:32:09 +00:00
//Printf("\nWall %d from %2.3f - %2.3f (blocking)\n", line, DAngle::fromBam(startAngle).Degrees(), DAngle::fromBam(endAngle).Degrees());
2021-12-20 14:34:50 +00:00
//clipper->DumpClipper();
2021-12-19 17:53:53 +00:00
}
2021-03-18 11:32:31 +00:00
return CL_Draw ;
}
else
{
2023-09-23 11:32:09 +00:00
if ( line > 0 )
2021-12-19 17:53:53 +00:00
{
2023-09-23 11:32:09 +00:00
if ( portal ) clipper - > RemoveClipRange ( startAngle , endAngle ) ;
else
2021-12-19 17:53:53 +00:00
{
2023-09-23 11:32:09 +00:00
if ( ( topclip < FLT_MAX | | bottomclip > - FLT_MAX ) & & ! dontclip )
{
clipper - > AddWindowRange ( startAngle , endAngle , topclip , bottomclip , viewz ) ;
//Printf("\nWall %d from %2.3f - %2.3f, (%2.3f, %2.3f) (passing)\n", line, DAngle::fromBam(startAngle).Degrees(), DAngle::fromBam(endAngle).Degrees(), topclip, bottomclip);
//clipper->DumpClipper();
}
2021-12-19 17:53:53 +00:00
}
}
2021-04-24 10:08:38 +00:00
// set potentially visible viewing range for this line's back sector.
2021-05-02 22:15:09 +00:00
int nsection = cline - > partnersection ;
if ( sectionstartang [ nsection ] = = - 1 )
2021-04-24 10:08:38 +00:00
{
2021-05-02 22:15:09 +00:00
sectionstartang [ nsection ] = startAngle ;
sectionendang [ nsection ] = endAngle ;
2021-04-24 10:08:38 +00:00
}
else
{
2021-05-02 22:15:09 +00:00
if ( startAngle < sectionstartang [ nsection ] ) sectionstartang [ nsection ] = startAngle ;
if ( endAngle > sectionendang [ nsection ] ) sectionendang [ nsection ] = endAngle ;
2021-04-24 10:08:38 +00:00
}
2023-09-23 11:32:09 +00:00
return line < 0 ? CL_Pass : dontclip ? CL_Draw : CL_Draw | CL_Pass ;
2021-03-18 11:32:31 +00:00
}
}
//==========================================================================
//
//
//
//==========================================================================
void BunchDrawer : : ProcessBunch ( int bnch )
{
FBunch * bunch = & Bunches [ bnch ] ;
2021-05-08 07:16:06 +00:00
int start = bunch - > startline ;
int end = bunch - > endline ;
2021-03-18 11:32:31 +00:00
ClipWall . Clock ( ) ;
2021-05-08 07:16:06 +00:00
for ( int i = start ; i < = end ; i + + )
2021-03-18 11:32:31 +00:00
{
2021-05-08 07:16:06 +00:00
bunch = & Bunches [ bnch ] ; // re-get the pointer in case of reallocation.
2021-04-06 17:25:40 +00:00
int clipped = ClipLine ( i , bunch - > portal ) ;
2021-03-18 11:32:31 +00:00
if ( clipped & CL_Draw )
{
2021-05-03 15:48:35 +00:00
int ww = sectionLines [ i ] . wall ;
if ( ww ! = - 1 )
2021-03-18 11:32:31 +00:00
{
2021-05-03 15:48:35 +00:00
show2dwall . Set ( ww ) ;
if ( ! gotwall [ i ] )
{
2023-09-23 11:32:09 +00:00
//Printf("\nWall %d processed\n", i);
2021-05-03 15:48:35 +00:00
gotwall . Set ( i ) ;
ClipWall . Unclock ( ) ;
Bsp . Unclock ( ) ;
SetupWall . Clock ( ) ;
HWWall hwwall ;
2021-12-01 23:01:45 +00:00
hwwall . Process ( di , & wall [ ww ] , & sector [ bunch - > sectornum ] , wall [ ww ] . nextsector < 0 ? nullptr : & sector [ wall [ ww ] . nextsector ] ) ;
2021-05-03 15:48:35 +00:00
SetupWall . Unclock ( ) ;
Bsp . Clock ( ) ;
ClipWall . Clock ( ) ;
}
2021-03-18 11:32:31 +00:00
}
}
if ( clipped & CL_Pass )
{
ClipWall . Unclock ( ) ;
2021-05-02 22:15:09 +00:00
ProcessSection ( sectionLines [ i ] . partnersection , false ) ;
2021-03-18 11:32:31 +00:00
ClipWall . Clock ( ) ;
}
}
ClipWall . Unclock ( ) ;
}
//==========================================================================
//
//
//
//==========================================================================
2021-05-02 22:15:09 +00:00
int BunchDrawer : : WallInFront ( int line1 , int line2 )
2021-03-18 11:32:31 +00:00
{
2021-05-02 22:15:09 +00:00
int wall1s = sectionLines [ line1 ] . startpoint ;
int wall1e = sectionLines [ line1 ] . endpoint ;
int wall2s = sectionLines [ line2 ] . startpoint ;
int wall2e = sectionLines [ line2 ] . endpoint ;
2022-09-16 17:37:22 +00:00
double x1s = wall [ wall1s ] . pos . X ;
double y1s = - wall [ wall1s ] . pos . Y ;
double x1e = wall [ wall1e ] . pos . X ;
double y1e = - wall [ wall1e ] . pos . Y ;
double x2s = wall [ wall2s ] . pos . X ;
double y2s = - wall [ wall2s ] . pos . Y ;
double x2e = wall [ wall2e ] . pos . X ;
double y2e = - wall [ wall2e ] . pos . Y ;
2021-03-18 11:32:31 +00:00
2022-01-09 11:05:36 +00:00
retry :
2022-01-05 23:12:19 +00:00
double dx1 = x1e - x1s ;
double dy1 = y1e - y1s ;
2021-03-18 11:32:31 +00:00
2022-01-05 23:12:19 +00:00
double t1 = PointOnLineSide ( x2s , y2s , x1s , y1s , dx1 , dy1 ) ;
double t2 = PointOnLineSide ( x2e , y2e , x1s , y1s , dx1 , dy1 ) ;
2021-03-18 11:32:31 +00:00
if ( t1 = = 0 )
{
2022-01-09 11:05:36 +00:00
if ( t2 = = 0 ) return - 1 ;
2021-03-18 11:32:31 +00:00
t1 = t2 ;
}
if ( t2 = = 0 ) t2 = t1 ;
if ( ( t1 * t2 ) > = 0 )
{
2022-01-05 23:12:19 +00:00
t2 = PointOnLineSide ( viewx , viewy , x1s , y1s , dx1 , dy1 ) ;
2022-01-09 11:05:36 +00:00
return ( t2 * t1 ) < = 0 ;
2021-03-18 11:32:31 +00:00
}
2022-01-05 23:12:19 +00:00
double dx2 = x2e - x2s ;
double dy2 = y2e - y2s ;
double t3 = PointOnLineSide ( x1s , y1s , x2s , y2s , dx2 , dy2 ) ;
double t4 = PointOnLineSide ( x1e , y1e , x2s , y2s , dx2 , dy2 ) ;
if ( t3 = = 0 )
2021-03-18 11:32:31 +00:00
{
2022-01-09 11:05:36 +00:00
if ( t4 = = 0 ) return - 1 ;
2022-01-05 23:12:19 +00:00
t3 = t4 ;
2021-03-18 11:32:31 +00:00
}
2022-01-05 23:12:19 +00:00
if ( t4 = = 0 ) t4 = t3 ;
if ( ( t3 * t4 ) > = 0 )
{
t4 = PointOnLineSide ( viewx , viewy , x2s , y2s , dx2 , dy2 ) ;
2022-01-09 11:05:36 +00:00
return ( t4 * t3 ) > 0 ;
2022-01-05 23:12:19 +00:00
}
// If we got here the walls intersect. Most of the time this is just a tiny sliver intruding into the other wall.
// If that is the case we can ignore that sliver and pretend it is completely on the other side.
const double max_dist = 3 ;
const double side_threshold = ( max_dist * max_dist ) / ( 16. * 16. ) ; // we are operating in render coordinate space but want 3 map units tolerance.
double d1 = SquareDistToLine ( x2s , y2s , x1s , y1s , x1e , y1e ) ;
if ( d1 < side_threshold ) t1 = t2 ;
double d2 = SquareDistToLine ( x2e , y2e , x1s , y1s , x1e , y1e ) ;
if ( d2 < side_threshold ) t2 = t1 ;
if ( ( fabs ( d1 ) < side_threshold ) ^ ( fabs ( d2 ) < side_threshold ) ) // only acceptable if only one end of the wall got adjusted.
{
t2 = PointOnLineSide ( viewx , viewy , x1s , y1s , dx1 , dy1 ) ;
return ( ( t2 * t1 ) < = 0 ) ;
}
double d3 = SquareDistToLine ( x1s , y1s , x2s , y2s , x2e , y2e ) ;
if ( d3 < side_threshold ) t1 = t2 ;
double d4 = SquareDistToLine ( x1e , y1e , x2s , y2s , x2e , y2e ) ;
if ( d4 < side_threshold ) t2 = t1 ;
if ( ( fabs ( d3 ) < side_threshold ) ^ ( fabs ( d4 ) < side_threshold ) ) // only acceptable if only one end of the wall got adjusted.
2021-03-18 11:32:31 +00:00
{
2022-01-05 23:12:19 +00:00
t2 = PointOnLineSide ( viewx , viewy , x2s , y2s , dx2 , dy2 ) ;
return ( ( t2 * t1 ) < = 0 ) ;
2021-03-18 11:32:31 +00:00
}
2022-01-05 23:12:19 +00:00
2022-01-09 11:05:36 +00:00
// let's try some last ditch effort here: compare the longer sections of the two walls from the intersection point.
// Only do this if the distance of the smaller one is not too large.
const double max_overlap = 2 * 2 ;
if ( max ( min ( d1 , d2 ) , min ( d3 , d4 ) ) < max_overlap )
{
// if one of the walls is too short, let colinearBunchInFront decide. This case normally only happens with doors where this will yield the correct result.
if ( ( d1 < max_overlap & & d2 < max_overlap ) | | ( d3 < max_overlap & & d4 < max_overlap ) )
return - 1 ;
DVector2 intersect ;
2022-01-30 13:55:36 +00:00
SquareDistToWall ( x1s , - y1s , & wall [ line2 ] , & intersect ) ;
intersect . Y = - intersect . Y ;
2022-01-09 11:05:36 +00:00
if ( d3 < max_overlap )
{
x1s = intersect . X ;
y1s = intersect . Y ;
}
else
{
x1e = intersect . X ;
y1e = intersect . Y ;
}
if ( d1 < max_overlap )
{
x2s = intersect . X ;
y2s = intersect . Y ;
}
else
{
x2e = intersect . X ;
y2e = intersect . Y ;
}
goto retry ;
}
return - 2 ;
2021-03-18 11:32:31 +00:00
}
//==========================================================================
//
// Rules:
// 1. Any bunch can span at most 180°.
// 2. 2 bunches can never overlap at both ends
// 3. if there is an overlap one of the 2 starting points must be in the
// overlapping area.
//
//==========================================================================
2021-05-21 12:31:12 +00:00
int BunchDrawer : : ColinearBunchInFront ( FBunch * b1 , FBunch * b2 )
{
// Unable to determine the order. The only option left is to see if the sectors within the bunch can be ordered.
for ( int i = b1 - > startline ; i < = b1 - > endline ; i + + )
{
int wall1s = sectionLines [ i ] . wall ;
if ( wall1s = = - 1 ) continue ;
int sect1 = wall [ wall1s ] . sector ;
int nsect1 = wall [ wall1s ] . nextsector ;
for ( int j = b2 - > startline ; j < = b2 - > endline ; j + + )
{
int wall2s = sectionLines [ j ] . wall ;
if ( wall2s = = - 1 ) continue ;
int sect2 = wall [ wall2s ] . sector ;
int nsect2 = wall [ wall2s ] . nextsector ;
if ( sect1 = = nsect2 ) return 1 ; // bunch 2 is in front
if ( sect2 = = nsect1 ) return 0 ; // bunch 1 is in front
}
}
return - 1 ;
}
2021-03-18 11:32:31 +00:00
int BunchDrawer : : BunchInFront ( FBunch * b1 , FBunch * b2 )
{
2022-08-27 09:54:55 +00:00
angle_t anglecheck , endang ;
2021-05-21 12:31:12 +00:00
bool colinear = false ;
2021-03-18 11:32:31 +00:00
2022-08-27 09:29:58 +00:00
if ( b2 - > startangle > = b1 - > startangle & & b2 - > startangle < b1 - > endangle )
2021-03-18 11:32:31 +00:00
{
// we have an overlap at b2->startangle
2022-08-27 09:54:55 +00:00
anglecheck = b2 - > startangle ;
2021-03-18 11:32:31 +00:00
// Find the wall in b1 that overlaps b2->startangle
for ( int i = b1 - > startline ; i < = b1 - > endline ; i + + )
{
2021-12-15 15:12:42 +00:00
endang = ClipAngle ( sectionLines [ i ] . endpoint ) ;
2022-08-27 09:54:55 +00:00
if ( endang > anglecheck )
2021-03-18 11:32:31 +00:00
{
// found a line
int ret = WallInFront ( b2 - > startline , i ) ;
2021-05-21 12:31:12 +00:00
if ( ret = = - 1 )
{
ret = ColinearBunchInFront ( b1 , b2 ) ;
if ( ret = = - 1 )
{
colinear = true ;
continue ;
}
}
2021-03-18 11:32:31 +00:00
return ret ;
}
}
}
2022-08-27 09:29:58 +00:00
else if ( b1 - > startangle > = b2 - > startangle & & b1 - > startangle < b2 - > endangle )
2021-03-18 11:32:31 +00:00
{
// we have an overlap at b1->startangle
2022-08-27 09:54:55 +00:00
anglecheck = b1 - > startangle ;
2021-03-18 11:32:31 +00:00
// Find the wall in b2 that overlaps b1->startangle
for ( int i = b2 - > startline ; i < = b2 - > endline ; i + + )
{
2021-12-15 15:12:42 +00:00
endang = ClipAngle ( sectionLines [ i ] . endpoint ) ;
2022-08-27 09:54:55 +00:00
if ( endang > anglecheck )
2021-03-18 11:32:31 +00:00
{
// found a line
int ret = WallInFront ( i , b1 - > startline ) ;
2021-05-21 12:31:12 +00:00
if ( ret = = - 1 )
{
ret = ColinearBunchInFront ( b1 , b2 ) ;
if ( ret = = - 1 )
{
colinear = true ;
continue ;
}
}
2021-03-18 11:32:31 +00:00
return ret ;
}
}
}
2021-05-21 12:31:12 +00:00
if ( colinear )
{
2022-01-09 11:05:36 +00:00
return - 2 ;
2021-05-21 12:31:12 +00:00
}
2021-03-18 11:32:31 +00:00
// we have no overlap
return - 1 ;
}
//==========================================================================
//
//
//
//==========================================================================
int BunchDrawer : : FindClosestBunch ( )
{
int closest = 0 ; //Almost works, but not quite :(
CompareData . Clear ( ) ;
for ( unsigned i = 1 ; i < Bunches . Size ( ) ; i + + )
{
switch ( BunchInFront ( & Bunches [ i ] , & Bunches [ closest ] ) )
{
case 0 : // i is in front
closest = i ;
continue ;
case 1 : // i is behind
continue ;
default : // can't determine
CompareData . Push ( i ) ; // mark for later comparison
continue ;
}
}
// we need to do a second pass to see how the marked bunches relate to the currently closest one.
for ( unsigned i = 0 ; i < CompareData . Size ( ) ; i + + )
{
switch ( BunchInFront ( & Bunches [ CompareData [ i ] ] , & Bunches [ closest ] ) )
{
case 0 : // is in front
closest = CompareData [ i ] ;
CompareData [ i ] = CompareData . Last ( ) ;
CompareData . Pop ( ) ;
2021-03-23 18:20:06 +00:00
i = - 1 ; // we need to recheck everything that's still marked. -1 because this will get incremented before being used.
2021-03-18 11:32:31 +00:00
continue ;
case 1 : // is behind
CompareData [ i ] = CompareData . Last ( ) ;
CompareData . Pop ( ) ;
i - - ;
continue ;
default :
continue ;
}
}
2022-01-09 11:05:36 +00:00
/*
int nsection = sectionLines [ Bunches [ closest ] . startline ] . section ;
Printf ( " \n ===================================== \n picked bunch starting at sector %d, wall %d - Range at (%2.3f - %2.3f) \n " ,
sections [ nsection ] . sector , Bunches [ closest ] . startline ,
2023-09-23 11:32:09 +00:00
DAngle : : fromBam ( sectionstartang [ nsection ] ) . Degrees ( ) , DAngle : : fromBam ( sectionendang [ nsection ] ) . Degrees ( ) ) ;
2022-01-09 11:05:36 +00:00
*/
2021-03-18 11:32:31 +00:00
return closest ;
}
//==========================================================================
//
//
//
//==========================================================================
2021-05-02 22:15:09 +00:00
void BunchDrawer : : ProcessSection ( int sectionnum , bool portal )
2021-03-18 11:32:31 +00:00
{
2021-05-02 22:15:09 +00:00
if ( gotsection2 [ sectionnum ] ) return ;
gotsection2 . Set ( sectionnum ) ;
2021-03-18 11:32:31 +00:00
bool inbunch ;
2021-03-25 22:16:32 +00:00
2021-12-15 12:08:09 +00:00
int sectnum = sections [ sectionnum ] . sector ;
2021-04-07 14:52:17 +00:00
if ( ! gotsector [ sectnum ] )
2021-03-25 22:16:32 +00:00
{
2022-01-13 23:15:33 +00:00
Bsp . Unclock ( ) ;
SetupSprite . Clock ( ) ;
2021-04-07 14:52:17 +00:00
gotsector . Set ( sectnum ) ;
2021-12-04 18:08:50 +00:00
CoreSectIterator it ( sectnum ) ;
while ( auto actor = it . Next ( ) )
2021-04-07 14:52:17 +00:00
{
2022-10-07 21:33:37 +00:00
if ( ( actor - > spr . cstat & CSTAT_SPRITE_INVISIBLE ) | | actor - > spr . scale . X = = 0 | | actor - > spr . scale . Y = = 0 ) // skip invisible sprites
2021-04-07 14:52:17 +00:00
continue ;
2021-03-25 22:16:32 +00:00
2023-05-20 10:55:58 +00:00
auto tex = actor - > spr . spritetexture ( ) ;
if ( ! tex . isValid ( ) ) continue ;
auto tx = TexMan . GetGameTexture ( tex ) ;
2023-06-05 21:35:24 +00:00
if ( tx - > GetUseType ( ) = = ETextureType : : FirstDefined & & ( actor - > spr . cstat & CSTAT_SPRITE_ALIGNMENT_MASK ) = = CSTAT_SPRITE_ALIGNMENT_FACING ) continue ;
2023-05-20 10:55:58 +00:00
2022-08-22 16:15:11 +00:00
auto viewvec = actor - > spr . pos . XY ( ) - DVector2 ( viewx , - viewy ) ; // note that viewy is in render coordinates
2021-03-25 22:16:32 +00:00
2021-04-07 14:52:17 +00:00
// this checks if the sprite is it behind the camera, which will not work if the pitch is high enough to necessitate a FOV of more than 180°.
2021-12-22 22:14:16 +00:00
//if ((actor->spr.cstat & CSTAT_SPRITE_ALIGNMENT_MASK) || (hw_models && tile2model[actor->spr.picnum].modelid >= 0) || ((sx * gcosang) + (sy * gsinang) > 0))
2021-04-07 14:52:17 +00:00
{
2021-12-22 22:14:16 +00:00
if ( ( actor - > spr . cstat & ( CSTAT_SPRITE_ONE_SIDE | CSTAT_SPRITE_ALIGNMENT_MASK ) ) ! = ( CSTAT_SPRITE_ONE_SIDE | CSTAT_SPRITE_ALIGNMENT_WALL ) | |
2022-12-08 17:26:09 +00:00
tilehasvoxel ( actor - > spr . spritetexture ( ) ) | |
2022-11-25 12:13:50 +00:00
( actor - > spr . Angles . Yaw . Cos ( ) * viewvec . X ) + ( actor - > spr . Angles . Yaw . Sin ( ) * viewvec . Y ) < 0 )
2022-08-07 08:25:15 +00:00
if ( ! renderAddTsprite ( di - > tsprites , actor ) )
2021-04-07 14:52:17 +00:00
break ;
}
2021-03-25 22:16:32 +00:00
}
2021-04-07 14:52:17 +00:00
SetupSprite . Unclock ( ) ;
2022-01-13 23:15:33 +00:00
Bsp . Clock ( ) ;
2021-03-25 22:16:32 +00:00
}
2021-04-01 18:47:05 +00:00
if ( automapping )
show2dsector . Set ( sectnum ) ;
2021-03-25 22:16:32 +00:00
2022-01-13 23:15:33 +00:00
Bsp . Unclock ( ) ;
2021-03-18 20:50:02 +00:00
SetupFlat . Clock ( ) ;
HWFlat flat ;
2021-12-15 11:23:50 +00:00
flat . ProcessSector ( di , & sector [ sectnum ] , sectionnum ) ;
2021-03-18 20:50:02 +00:00
SetupFlat . Unclock ( ) ;
2022-01-13 23:15:33 +00:00
Bsp . Clock ( ) ;
2021-03-18 11:32:31 +00:00
//Todo: process subsectors
inbunch = false ;
2021-12-15 12:08:09 +00:00
auto section = & sections [ sectionnum ] ;
2021-05-02 22:15:09 +00:00
for ( unsigned i = 0 ; i < section - > lines . Size ( ) ; i + + )
2021-03-18 11:32:31 +00:00
{
2021-05-02 22:15:09 +00:00
auto thisline = & sectionLines [ section - > lines [ i ] ] ;
2021-03-18 11:32:31 +00:00
2022-08-27 09:54:55 +00:00
angle_t walang1 = ClipAngle ( thisline - > startpoint ) ;
angle_t walang2 = ClipAngle ( thisline - > endpoint ) ;
2021-03-18 11:32:31 +00:00
2021-04-06 22:02:36 +00:00
// outside the visible area or seen from the backside.
2022-08-27 09:54:55 +00:00
if ( ( walang1 > angrange & & walang2 > angrange & & walang1 < walang2 ) | |
( walang1 - walang2 < ANGLE_180 ) )
2021-03-18 11:32:31 +00:00
{
inbunch = false ;
}
else
{
2022-08-27 09:54:55 +00:00
if ( walang1 > = angrange ) { walang1 = 0 ; inbunch = false ; }
if ( walang2 > = angrange ) walang2 = angrange ;
2021-12-21 09:51:41 +00:00
if ( section - > lines [ i ] > = ( int ) wall . Size ( ) ) inbunch = false ;
2021-05-14 10:56:37 +00:00
if ( ! inbunch )
{
2022-01-06 15:34:04 +00:00
//Printf("Starting bunch, Sector %d\n\tWall %d\n", section->sector, section->lines[i]);
2021-05-14 10:56:37 +00:00
inbunch = StartBunch ( sectnum , section - > lines [ i ] , walang1 , walang2 , portal ) ;
}
else
{
//Printf("\tWall %d\n", section->lines[i]);
inbunch = AddLineToBunch ( section - > lines [ i ] , walang2 ) ;
}
2021-03-18 11:32:31 +00:00
}
2021-05-02 22:15:09 +00:00
if ( thisline - > endpoint ! = section - > lines [ i ] + 1 ) inbunch = false ;
2021-03-18 11:32:31 +00:00
}
}
//==========================================================================
//
//
//
//==========================================================================
2021-04-06 17:25:40 +00:00
void BunchDrawer : : RenderScene ( const int * viewsectors , unsigned sectcount , bool portal )
2021-03-18 11:32:31 +00:00
{
2021-12-20 14:49:05 +00:00
//Printf("----------------------------------------- \nstart at sector %d, z = %2.3f\n", viewsectors[0], viewz);
2021-04-06 22:02:36 +00:00
auto process = [ & ] ( )
{
2022-08-27 09:47:20 +00:00
clipper - > Clear ( ang1 ) ;
2021-04-24 10:08:38 +00:00
for ( unsigned i = 0 ; i < sectcount ; i + + )
{
2021-12-15 12:08:09 +00:00
for ( auto j : sectionsPerSector [ viewsectors [ i ] ] )
2021-05-02 22:15:09 +00:00
{
2022-02-20 12:14:39 +00:00
sectionstartang [ j ] = 0 ;
2022-08-27 09:38:37 +00:00
sectionendang [ j ] = int ( angrange ) ;
2021-05-02 22:15:09 +00:00
}
2021-04-24 10:08:38 +00:00
}
2021-04-06 22:02:36 +00:00
for ( unsigned i = 0 ; i < sectcount ; i + + )
2021-05-02 22:15:09 +00:00
{
2021-12-15 12:08:09 +00:00
for ( auto j : sectionsPerSector [ viewsectors [ i ] ] )
2021-05-02 22:15:09 +00:00
{
2022-02-20 12:14:39 +00:00
ProcessSection ( j , portal ) ;
2021-05-02 22:15:09 +00:00
}
}
2021-04-06 22:02:36 +00:00
while ( Bunches . Size ( ) > 0 )
{
int closest = FindClosestBunch ( ) ;
ProcessBunch ( closest ) ;
DeleteBunch ( closest ) ;
}
} ;
2021-04-05 09:54:28 +00:00
Bsp . Clock ( ) ;
2022-08-27 09:38:37 +00:00
if ( ang1 ! = 0 | | ang2 ! = 0 )
2021-04-06 22:02:36 +00:00
{
process ( ) ;
}
else
2021-03-18 11:32:31 +00:00
{
2021-04-06 22:02:36 +00:00
// with a 360° field of view we need to split the scene into two halves.
// The BunchInFront check can fail with angles that may wrap around.
auto rotang = di - > Viewpoint . RotAngle ;
2022-08-27 09:38:37 +00:00
ang1 = rotang - ANGLE_90 ;
ang2 = rotang + ANGLE_90 - 1 ;
2021-05-14 08:50:22 +00:00
angrange = ang2 - ang1 ;
2021-04-06 22:02:36 +00:00
process ( ) ;
2021-05-02 22:15:09 +00:00
gotsection2 . Zero ( ) ;
2022-08-27 09:38:37 +00:00
ang1 = rotang + ANGLE_90 ;
ang2 = rotang - ANGLE_90 - 1 ;
2021-05-14 08:50:22 +00:00
angrange = ang2 - ang1 ;
2021-04-06 22:02:36 +00:00
process ( ) ;
2021-03-18 11:32:31 +00:00
}
2021-04-05 09:54:28 +00:00
Bsp . Unclock ( ) ;
2021-03-18 11:32:31 +00:00
}