2009-04-19 18:07:22 +00:00
#region = = = = = = = = = = = = = = = = = = Copyright ( c ) 2007 Pascal vd Heiden
/ *
* Copyright ( c ) 2007 Pascal vd Heiden , www . codeimp . com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* /
#endregion
#region = = = = = = = = = = = = = = = = = = Namespaces
using System ;
using System.Collections.Generic ;
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Rendering ;
using CodeImp.DoomBuilder.Geometry ;
using CodeImp.DoomBuilder.VisualModes ;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class BaseVisualSector : VisualSector
{
#region = = = = = = = = = = = = = = = = = = Constants
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
2016-02-15 14:06:46 +00:00
private readonly BaseVisualMode mode ;
2015-10-02 14:47:34 +00:00
private VisualFloor floor ;
private VisualCeiling ceiling ;
private List < VisualFloor > extrafloors ;
private List < VisualCeiling > extraceilings ;
2016-02-15 14:06:46 +00:00
private readonly List < VisualFloor > extrabackfloors ; //mxd
private readonly List < VisualCeiling > extrabackceilings ; //mxd
2015-10-02 14:47:34 +00:00
private Dictionary < Sidedef , VisualSidedefParts > sides ;
2009-04-19 18:07:22 +00:00
2009-05-01 20:31:17 +00:00
// If this is set to true, the sector will be rebuilt after the action is performed.
2015-10-02 14:47:34 +00:00
private bool changed ;
2012-11-27 21:12:20 +00:00
// Prevent recursion
2015-10-02 14:47:34 +00:00
private bool isupdating ;
2009-05-01 20:31:17 +00:00
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
2012-11-27 21:12:20 +00:00
2009-04-19 18:07:22 +00:00
public VisualFloor Floor { get { return floor ; } }
public VisualCeiling Ceiling { get { return ceiling ; } }
2012-11-27 21:12:20 +00:00
public List < VisualFloor > ExtraFloors { get { return extrafloors ; } }
public List < VisualCeiling > ExtraCeilings { get { return extraceilings ; } }
2013-03-18 13:52:27 +00:00
public List < VisualFloor > ExtraBackFloors { get { return extrabackfloors ; } } //mxd
public List < VisualCeiling > ExtraBackCeilings { get { return extrabackceilings ; } } //mxd
public Dictionary < Sidedef , VisualSidedefParts > Sides { get { return sides ; } } //mxd
2009-05-01 20:31:17 +00:00
public bool Changed { get { return changed ; } set { changed | = value ; } }
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// Constructor
public BaseVisualSector ( BaseVisualMode mode , Sector s ) : base ( s )
{
this . mode = mode ;
2012-11-27 21:12:20 +00:00
this . extrafloors = new List < VisualFloor > ( 2 ) ;
this . extraceilings = new List < VisualCeiling > ( 2 ) ;
2015-12-04 12:29:22 +00:00
this . extrabackfloors = new List < VisualFloor > ( 2 ) ; //mxd
this . extrabackceilings = new List < VisualCeiling > ( 2 ) ; //mxd
2009-04-19 18:07:22 +00:00
// Initialize
Rebuild ( ) ;
// We have no destructor
GC . SuppressFinalize ( this ) ;
}
// Disposer
public override void Dispose ( )
{
// Not already disposed?
if ( ! IsDisposed )
{
// Clean up
sides = null ;
floor = null ;
ceiling = null ;
2012-11-27 21:12:20 +00:00
extrafloors = null ;
extraceilings = null ;
2009-04-19 18:07:22 +00:00
// Dispose base
base . Dispose ( ) ;
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
2009-05-09 13:41:26 +00:00
2012-11-27 21:12:20 +00:00
// This retreives the sector data for this sector
public SectorData GetSectorData ( )
{
return mode . GetSectorData ( this . Sector ) ;
}
// This updates this virtual the sector and neightbours if needed
2013-03-18 13:52:27 +00:00
override public void UpdateSectorGeometry ( bool includeneighbours )
2009-05-09 13:41:26 +00:00
{
2014-01-13 08:06:56 +00:00
if ( isupdating ) return ;
2012-11-27 21:12:20 +00:00
isupdating = true ;
changed = true ;
// Not sure what from this part we need, so commented out for now
2016-02-15 18:53:56 +00:00
SectorData data = mode . GetSectorDataEx ( this . Sector ) ; //mxd
if ( data ! = null ) //mxd
2012-11-27 21:12:20 +00:00
{
2016-04-19 20:40:42 +00:00
data . Reset ( false ) ;
2016-02-15 18:53:56 +00:00
// Update sectors that rely on this sector
foreach ( KeyValuePair < Sector , bool > s in data . UpdateAlso )
2012-11-27 21:12:20 +00:00
{
2016-04-19 20:40:42 +00:00
SectorData other = mode . GetSectorDataEx ( s . Key ) ;
if ( other ! = null ) other . Reset ( s . Value ) ;
2012-11-27 21:12:20 +00:00
}
}
2009-05-09 13:41:26 +00:00
// Go for all things in this sector
foreach ( Thing t in General . Map . Map . Things )
{
if ( t . Sector = = this . Sector )
{
if ( mode . VisualThingExists ( t ) )
{
// Update thing
2016-04-19 20:40:42 +00:00
BaseVisualThing vt = ( BaseVisualThing ) mode . GetVisualThing ( t ) ;
2009-05-09 13:41:26 +00:00
vt . Changed = true ;
}
}
}
2009-04-19 18:07:22 +00:00
2009-05-09 13:41:26 +00:00
if ( includeneighbours )
{
// Also rebuild surrounding sectors, because outside sidedefs may need to be adjusted
foreach ( Sidedef sd in this . Sector . Sidedefs )
{
if ( sd . Other ! = null )
{
if ( mode . VisualSectorExists ( sd . Other . Sector ) )
{
2016-04-19 20:40:42 +00:00
SectorData other = mode . GetSectorDataEx ( sd . Other . Sector ) ;
2019-03-27 20:47:47 +00:00
2016-04-27 10:10:57 +00:00
if ( other ! = null )
{
2019-03-27 20:47:47 +00:00
other . Reset ( other . UpdateAlso . Count > 0 ? true : false ) ; // biwa. Make sure to reset the update status of dependend sectors. This fixes #250, where 3D floors where not updated when the control sector was sloped using line action 181
2016-04-27 10:10:57 +00:00
}
else
{
BaseVisualSector vs = ( BaseVisualSector ) mode . GetVisualSector ( sd . Other . Sector ) ;
vs . Changed = true ;
}
2009-05-09 13:41:26 +00:00
}
}
}
}
2013-09-11 08:49:45 +00:00
Sector . UpdateFogColor ( ) ; //mxd
2012-11-27 21:12:20 +00:00
isupdating = false ;
2009-05-09 13:41:26 +00:00
}
2012-11-27 21:12:20 +00:00
2013-09-11 09:47:53 +00:00
//mxd. call this to update sector and things in it when Sector.Fields are changed
2014-12-03 23:15:26 +00:00
override public void UpdateSectorData ( )
{
2013-09-11 09:47:53 +00:00
//update sector data
SectorData data = GetSectorData ( ) ;
data . UpdateForced ( ) ;
//update sector
Rebuild ( ) ;
//update things in this sector
2015-12-28 15:01:53 +00:00
foreach ( Thing t in General . Map . Map . Things )
2014-12-03 23:15:26 +00:00
{
2015-12-28 15:01:53 +00:00
if ( t . Sector = = this . Sector )
2014-12-03 23:15:26 +00:00
{
2015-12-28 15:01:53 +00:00
if ( mode . VisualThingExists ( t ) )
2014-12-03 23:15:26 +00:00
{
2013-09-11 09:47:53 +00:00
// Update thing
2016-04-19 20:40:42 +00:00
BaseVisualThing vt = ( BaseVisualThing ) mode . GetVisualThing ( t ) ;
2013-09-11 09:47:53 +00:00
vt . Rebuild ( ) ;
}
}
}
}
2009-05-09 13:41:26 +00:00
2009-04-19 18:07:22 +00:00
// This (re)builds the visual sector, calculating all geometry from scratch
public void Rebuild ( )
{
// Forget old geometry
base . ClearGeometry ( ) ;
2012-11-27 21:12:20 +00:00
// Get sector data
SectorData data = GetSectorData ( ) ;
if ( ! data . Updated ) data . Update ( ) ;
2009-04-19 18:07:22 +00:00
// Create floor
2015-10-02 14:47:34 +00:00
floor = ( floor ? ? new VisualFloor ( mode , this ) ) ;
if ( floor . Setup ( data . Floor , null ) ) AddGeometry ( floor ) ;
2012-11-27 21:12:20 +00:00
2009-04-19 18:07:22 +00:00
// Create ceiling
2015-10-02 14:47:34 +00:00
ceiling = ( ceiling ? ? new VisualCeiling ( mode , this ) ) ;
if ( ceiling . Setup ( data . Ceiling , null ) ) AddGeometry ( ceiling ) ;
2012-11-27 21:12:20 +00:00
// Create 3D floors
for ( int i = 0 ; i < data . ExtraFloors . Count ; i + + )
{
Effect3DFloor ef = data . ExtraFloors [ i ] ;
2013-07-31 12:38:47 +00:00
bool floorRequired = ef . VavoomType ; //mxd
bool ceilingRequired = ef . VavoomType ; //mxd
2013-03-18 13:52:27 +00:00
2014-12-03 23:15:26 +00:00
if ( ef . VavoomType | | ! ef . IgnoreBottomHeight )
{
2014-07-18 11:25:08 +00:00
//mxd. check if 3d floor is between real floor and ceiling
2014-12-03 23:15:26 +00:00
if ( ! ef . VavoomType )
{
2015-12-28 15:01:53 +00:00
if ( ef . Ceiling . plane . GetInverted ( ) . Normal ! = floor . Level . plane . Normal
2014-12-03 23:15:26 +00:00
| | ef . Ceiling . plane . Normal ! = ceiling . Level . plane . Normal )
{
2014-08-25 09:41:21 +00:00
//mxd. check if at least one vertex of 3d floor is between floor and ceiling
floorRequired = Check3dFloorPlane ( floor . Vertices , ceiling . Vertices , ef . Ceiling . plane ) ;
2014-12-03 23:15:26 +00:00
}
2014-08-26 11:08:34 +00:00
//if floor, ceiling and 3d floor are not sloped, compare offsets
2014-12-03 23:15:26 +00:00
else if ( - floor . Level . plane . Offset < ef . Ceiling . plane . Offset
& & ceiling . Level . plane . Offset > ef . Ceiling . plane . Offset )
{
2014-08-26 11:08:34 +00:00
floorRequired = true ;
2013-03-18 13:52:27 +00:00
}
}
//mxd. Create a floor
2014-12-03 23:15:26 +00:00
if ( floorRequired )
{
2013-03-18 13:52:27 +00:00
VisualFloor vf = ( i < extrafloors . Count ) ? extrafloors [ i ] : new VisualFloor ( mode , this ) ;
2014-12-03 23:15:26 +00:00
if ( vf . Setup ( ef . Ceiling , ef ) )
{
2013-03-18 13:52:27 +00:00
base . AddGeometry ( vf ) ;
//mxd. add backside as well
2014-12-03 23:15:26 +00:00
if ( ! ef . VavoomType & & ef . RenderInside )
{
2013-03-18 13:52:27 +00:00
VisualFloor vfb = ( i < extrabackfloors . Count ) ? extrabackfloors [ i ] : new VisualFloor ( mode , this ) ;
2014-08-26 11:08:34 +00:00
if ( vfb . Setup ( ef . Ceiling , ef , true ) ) base . AddGeometry ( vfb ) ;
if ( i > = extrabackfloors . Count ) extrabackfloors . Add ( vfb ) ;
2013-03-18 13:52:27 +00:00
}
}
2014-08-26 11:08:34 +00:00
if ( i > = extrafloors . Count ) extrafloors . Add ( vf ) ;
2013-03-18 13:52:27 +00:00
}
}
2014-07-18 11:25:08 +00:00
//mxd. check if 3d ceiling is between real floor and ceiling
2014-12-03 23:15:26 +00:00
if ( ! ef . VavoomType )
{
2015-12-28 15:01:53 +00:00
if ( ef . Floor . plane . GetInverted ( ) . Normal ! = ceiling . Level . plane . Normal
2014-12-03 23:15:26 +00:00
| | ef . Floor . plane . Normal ! = floor . Level . plane . Normal )
{
2014-08-25 09:41:21 +00:00
//mxd. check if at least one vertex of 3d ceiling is between floor and ceiling
ceilingRequired = Check3dFloorPlane ( floor . Vertices , ceiling . Vertices , ef . Floor . plane ) ;
2014-12-03 23:15:26 +00:00
}
2014-08-26 11:08:34 +00:00
//if floor, ceiling and 3d ceiling are not sloped, compare offsets
2014-12-03 23:15:26 +00:00
else if ( ceiling . Level . plane . Offset > - ef . Floor . plane . Offset
& & floor . Level . plane . Offset > ef . Floor . plane . Offset )
{
2014-08-26 11:08:34 +00:00
ceilingRequired = true ;
2013-03-18 13:52:27 +00:00
}
}
//mxd. Create a ceiling
2014-12-03 23:15:26 +00:00
if ( ceilingRequired )
{
2013-03-18 13:52:27 +00:00
VisualCeiling vc = ( i < extraceilings . Count ) ? extraceilings [ i ] : new VisualCeiling ( mode , this ) ;
2014-12-03 23:15:26 +00:00
if ( vc . Setup ( ef . Floor , ef ) )
{
2013-03-18 13:52:27 +00:00
base . AddGeometry ( vc ) ;
2009-04-19 18:07:22 +00:00
2013-03-18 13:52:27 +00:00
//mxd. add backside as well
2014-12-03 23:15:26 +00:00
if ( ! ef . VavoomType & & ( ef . RenderInside | | ef . IgnoreBottomHeight ) )
{
2013-03-18 13:52:27 +00:00
VisualCeiling vcb = ( i < extrabackceilings . Count ) ? extrabackceilings [ i ] : new VisualCeiling ( mode , this ) ;
2014-08-26 11:08:34 +00:00
if ( vcb . Setup ( ef . Floor , ef , true ) ) base . AddGeometry ( vcb ) ;
if ( i > = extrabackceilings . Count ) extrabackceilings . Add ( vcb ) ;
2013-03-18 13:52:27 +00:00
}
}
2014-08-26 11:08:34 +00:00
if ( i > = extraceilings . Count ) extraceilings . Add ( vc ) ;
2013-03-18 13:52:27 +00:00
}
2012-11-27 21:12:20 +00:00
}
2009-04-19 18:07:22 +00:00
// Go for all sidedefs
2009-05-01 20:31:17 +00:00
Dictionary < Sidedef , VisualSidedefParts > oldsides = sides ? ? new Dictionary < Sidedef , VisualSidedefParts > ( 1 ) ;
2009-04-19 18:07:22 +00:00
sides = new Dictionary < Sidedef , VisualSidedefParts > ( base . Sector . Sidedefs . Count ) ;
foreach ( Sidedef sd in base . Sector . Sidedefs )
{
2009-05-01 20:31:17 +00:00
// VisualSidedef already exists?
VisualSidedefParts parts = oldsides . ContainsKey ( sd ) ? oldsides [ sd ] : new VisualSidedefParts ( ) ;
2009-04-19 18:07:22 +00:00
// Doublesided or singlesided?
2014-05-21 09:22:37 +00:00
if ( sd . Other ! = null & & sd . Line . IsFlagSet ( General . Map . Config . DoubleSidedFlag ) )
2009-04-19 18:07:22 +00:00
{
// Create upper part
2009-05-01 20:31:17 +00:00
VisualUpper vu = parts . upper ? ? new VisualUpper ( mode , this , sd ) ;
2014-01-13 08:06:56 +00:00
if ( vu . Setup ( ) ) base . AddGeometry ( vu ) ;
2009-04-19 18:07:22 +00:00
// Create lower part
2009-05-01 20:31:17 +00:00
VisualLower vl = parts . lower ? ? new VisualLower ( mode , this , sd ) ;
2014-01-13 08:06:56 +00:00
if ( vl . Setup ( ) ) base . AddGeometry ( vl ) ;
2009-04-19 18:07:22 +00:00
// Create middle part
2009-05-01 20:31:17 +00:00
VisualMiddleDouble vm = parts . middledouble ? ? new VisualMiddleDouble ( mode , this , sd ) ;
2014-01-13 08:06:56 +00:00
if ( vm . Setup ( ) ) base . AddGeometry ( vm ) ;
2015-12-04 12:29:22 +00:00
//mxd. Create fog boundary
VisualFogBoundary vb = parts . fogboundary ? ? new VisualFogBoundary ( mode , this , sd ) ;
if ( vb . Setup ( ) )
{
vm . FogFactor = 0 ; // Avoid double-fogging the middle part
base . AddGeometry ( vb ) ;
}
2012-11-27 21:12:20 +00:00
// Create 3D wall parts
SectorData osd = mode . GetSectorData ( sd . Other . Sector ) ;
if ( ! osd . Updated ) osd . Update ( ) ;
List < VisualMiddle3D > middles = parts . middle3d ? ? new List < VisualMiddle3D > ( osd . ExtraFloors . Count ) ;
for ( int i = 0 ; i < osd . ExtraFloors . Count ; i + + )
{
Effect3DFloor ef = osd . ExtraFloors [ i ] ;
2013-07-31 12:38:47 +00:00
if ( ! ef . VavoomType & & ef . IgnoreBottomHeight ) continue ; //mxd
2009-04-19 18:07:22 +00:00
2012-11-27 21:12:20 +00:00
VisualMiddle3D vm3 = ( i < middles . Count ) ? middles [ i ] : new VisualMiddle3D ( mode , this , sd ) ;
2014-01-13 08:06:56 +00:00
if ( vm3 . Setup ( ef ) ) base . AddGeometry ( vm3 ) ;
if ( i > = middles . Count ) middles . Add ( vm3 ) ;
2012-11-27 21:12:20 +00:00
}
2013-03-18 13:52:27 +00:00
//mxd. Create backsides
List < VisualMiddleBack > middlebacks = new List < VisualMiddleBack > ( ) ;
2015-12-04 12:29:22 +00:00
for ( int i = 0 ; i < data . ExtraFloors . Count ; i + + )
2014-12-03 23:15:26 +00:00
{
2013-03-18 13:52:27 +00:00
Effect3DFloor ef = data . ExtraFloors [ i ] ;
2015-12-04 12:29:22 +00:00
if ( ! ef . VavoomType & & ef . RenderInside & & ! ef . IgnoreBottomHeight )
2014-12-03 23:15:26 +00:00
{
2013-03-18 13:52:27 +00:00
VisualMiddleBack vms = new VisualMiddleBack ( mode , this , sd ) ;
2015-12-04 12:29:22 +00:00
if ( vms . Setup ( ef ) ) base . AddGeometry ( vms ) ;
2013-03-18 13:52:27 +00:00
middlebacks . Add ( vms ) ;
}
}
2012-11-27 21:12:20 +00:00
2009-04-19 18:07:22 +00:00
// Store
2015-12-04 12:29:22 +00:00
sides . Add ( sd , new VisualSidedefParts ( vu , vl , vm , vb , middles , middlebacks ) ) ;
2009-04-19 18:07:22 +00:00
}
else
{
// Create middle part
2009-05-01 20:31:17 +00:00
VisualMiddleSingle vm = parts . middlesingle ? ? new VisualMiddleSingle ( mode , this , sd ) ;
2014-01-13 08:06:56 +00:00
if ( vm . Setup ( ) ) base . AddGeometry ( vm ) ;
2009-04-19 18:07:22 +00:00
// Store
sides . Add ( sd , new VisualSidedefParts ( vm ) ) ;
}
}
2009-05-01 20:31:17 +00:00
// Done
changed = false ;
2009-04-19 18:07:22 +00:00
}
// This returns the visual sidedef parts for a given sidedef
public VisualSidedefParts GetSidedefParts ( Sidedef sd )
{
2015-12-04 12:29:22 +00:00
return ( sides . ContainsKey ( sd ) ? sides [ sd ] : new VisualSidedefParts ( ) ) ;
2009-04-19 18:07:22 +00:00
}
2013-03-18 13:52:27 +00:00
2014-08-25 09:41:21 +00:00
//mxd. Checks if given plane is between given floor and ceiling vertices
private static bool Check3dFloorPlane ( WorldVertex [ ] floorverts , WorldVertex [ ] ceilingverts , Plane plane )
{
bool show = false ;
//check floor
2014-12-03 23:15:26 +00:00
for ( int c = 0 ; c < floorverts . Length ; c + + )
{
2015-12-04 12:29:22 +00:00
if ( plane . GetZ ( new Vector2D ( floorverts [ c ] . x , floorverts [ c ] . y ) ) > Math . Round ( floorverts [ c ] . z , 3 ) )
2014-08-25 09:41:21 +00:00
{
show = true ;
break ;
}
2013-03-18 13:52:27 +00:00
}
2014-08-25 09:41:21 +00:00
2015-12-04 12:29:22 +00:00
if ( ! show ) return false ;
2014-08-25 09:41:21 +00:00
//check ceiling
for ( int c = 0 ; c < ceilingverts . Length ; c + + )
{
if ( plane . GetZ ( new Vector2D ( ceilingverts [ c ] . x , ceilingverts [ c ] . y ) ) < Math . Round ( ceilingverts [ c ] . z , 3 ) )
2013-03-18 13:52:27 +00:00
return true ;
}
2014-08-25 09:41:21 +00:00
2013-03-18 13:52:27 +00:00
return false ;
}
2009-04-19 18:07:22 +00:00
#endregion
}
}