2015-12-31 12:21:44 +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 System.Collections.ObjectModel ;
using System.Drawing ;
using System.Globalization ;
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Geometry ;
using CodeImp.DoomBuilder.Rendering ;
using CodeImp.DoomBuilder.Types ;
using CodeImp.DoomBuilder.VisualModes ;
using CodeImp.DoomBuilder.Data ;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
internal sealed class VisualCeiling : BaseVisualGeometrySector
{
2016-01-23 02:53:31 +00:00
#region = = = = = = = = = = = = = = = = = = Constants
2015-12-31 12:21:44 +00:00
2016-01-23 02:53:31 +00:00
#endregion
2015-12-31 12:21:44 +00:00
2016-01-23 02:53:31 +00:00
#region = = = = = = = = = = = = = = = = = = Variables
2015-12-31 12:21:44 +00:00
2016-01-23 02:53:31 +00:00
private bool innerside ; //mxd
2015-12-31 12:21:44 +00:00
2016-01-23 02:53:31 +00:00
#endregion
2015-12-31 12:21:44 +00:00
2016-01-23 02:53:31 +00:00
#region = = = = = = = = = = = = = = = = = = Properties
2015-12-31 12:21:44 +00:00
2016-01-23 02:53:31 +00:00
#endregion
2015-12-31 12:21:44 +00:00
2016-01-23 02:53:31 +00:00
#region = = = = = = = = = = = = = = = = = = Constructor / Setup
2015-12-31 12:21:44 +00:00
2016-01-23 02:53:31 +00:00
// Constructor
public VisualCeiling ( BaseVisualMode mode , VisualSector vs ) : base ( mode , vs )
2015-12-31 12:21:44 +00:00
{
//mxd
geometrytype = VisualGeometryType . CEILING ;
partname = "ceiling" ;
2016-01-23 02:53:31 +00:00
performautoselection = mode . UseSelectionFromClassicMode & & vs ! = null & & vs . Sector . Selected & & ( General . Map . ViewMode = = ViewMode . CeilingTextures | | General . Map . ViewMode = = ViewMode . Normal ) ;
2015-12-31 12:21:44 +00:00
2016-01-23 02:53:31 +00:00
// We have no destructor
GC . SuppressFinalize ( this ) ;
2015-12-31 12:21:44 +00:00
}
// This builds the geometry. Returns false when no geometry created.
public override bool Setup ( SectorLevel level , Effect3DFloor extrafloor )
{
2016-01-23 02:53:31 +00:00
return Setup ( level , extrafloor , innerside ) ;
2015-12-31 12:21:44 +00:00
}
2016-01-23 02:53:31 +00:00
//mxd
public bool Setup ( SectorLevel level , Effect3DFloor extrafloor , bool innerside )
{
2015-12-31 12:21:44 +00:00
Sector s = level . sector ;
Vector2D texscale ;
2016-01-23 02:53:31 +00:00
this . innerside = innerside ; //mxd
2015-12-31 12:21:44 +00:00
base . Setup ( level , extrafloor ) ;
// Fetch ZDoom fields
float rotate = Angle2D . DegToRad ( s . Fields . GetValue ( "rotationceiling" , 0.0f ) ) ;
Vector2D offset = new Vector2D ( s . Fields . GetValue ( "xpanningceiling" , 0.0f ) ,
s . Fields . GetValue ( "ypanningceiling" , 0.0f ) ) ;
Vector2D scale = new Vector2D ( s . Fields . GetValue ( "xscaleceiling" , 1.0f ) ,
s . Fields . GetValue ( "yscaleceiling" , 1.0f ) ) ;
//Load ceiling texture
if ( s . LongCeilTexture ! = MapSet . EmptyLongName )
{
base . Texture = General . Map . Data . GetFlatImage ( s . LongCeilTexture ) ;
if ( base . Texture = = null | | base . Texture is UnknownImage )
{
base . Texture = General . Map . Data . UnknownTexture3D ;
setuponloadedtexture = s . LongCeilTexture ;
}
2016-04-19 20:40:42 +00:00
else if ( ! base . Texture . IsImageLoaded )
2015-12-31 12:21:44 +00:00
{
2016-04-19 20:40:42 +00:00
setuponloadedtexture = s . LongCeilTexture ;
2015-12-31 12:21:44 +00:00
}
}
else
{
// Use missing texture
base . Texture = General . Map . Data . MissingTexture3D ;
setuponloadedtexture = 0 ;
}
// Determine texture scale
if ( base . Texture . IsImageLoaded )
texscale = new Vector2D ( 1.0f / base . Texture . ScaledWidth , 1.0f / base . Texture . ScaledHeight ) ;
else
texscale = new Vector2D ( 1.0f / 64.0f , 1.0f / 64.0f ) ;
2016-04-19 20:40:42 +00:00
// Determine brightness
2016-04-28 14:02:24 +00:00
byte alpha = ( byte ) General . Clamp ( level . alpha , 0 , 255 ) ;
int color = PixelColor . FromInt ( level . color ) . WithAlpha ( alpha ) . ToInt ( ) ;
2016-04-19 20:40:42 +00:00
int targetbrightness ;
if ( extrafloor ! = null & & ! extrafloor . VavoomType & & ! level . disablelighting )
{
//mxd. Top extrafloor level should calculate fogdensity from the brightness of the level above it
if ( ! innerside )
{
targetbrightness = 0 ;
SectorData sd = mode . GetSectorData ( this . Sector . Sector ) ;
for ( int i = 0 ; i < sd . LightLevels . Count - 1 ; i + + )
{
if ( sd . LightLevels [ i ] = = level )
{
targetbrightness = sd . LightLevels [ i + 1 ] . brightnessbelow ;
break ;
}
}
}
//mxd. Inner extrafloor ceilings must be colored using control sector's color and brightness
else
{
targetbrightness = level . brightnessbelow ;
SectorData sd = mode . GetSectorData ( this . Sector . Sector ) ;
for ( int i = 0 ; i < sd . LightLevels . Count ; i + + )
{
if ( sd . LightLevels [ i ] = = level )
{
2016-04-28 14:02:24 +00:00
if ( i > 0 ) color = PixelColor . FromInt ( sd . LightLevels [ i - 1 ] . color ) . WithAlpha ( alpha ) . ToInt ( ) ;
2016-04-19 20:40:42 +00:00
break ;
}
}
}
}
else
{
targetbrightness = level . brightnessbelow ;
}
2016-01-23 00:30:20 +00:00
//mxd. Determine fog density
2016-01-25 15:50:03 +00:00
fogfactor = CalculateFogFactor ( targetbrightness ) ;
2016-01-23 00:30:20 +00:00
// Make vertices
ReadOnlyCollection < Vector2D > triverts = Sector . Sector . Triangles . Vertices ;
2015-12-31 12:21:44 +00:00
WorldVertex [ ] verts = new WorldVertex [ triverts . Count ] ;
for ( int i = 0 ; i < triverts . Count ; i + + )
{
// Color shading
verts [ i ] . c = color ; //mxd
// Vertex coordinates
verts [ i ] . x = triverts [ i ] . x ;
verts [ i ] . y = triverts [ i ] . y ;
verts [ i ] . z = level . plane . GetZ ( triverts [ i ] ) ;
// Texture coordinates
Vector2D pos = triverts [ i ] ;
pos = pos . GetRotated ( rotate ) ;
pos . y = - pos . y ;
pos = ( pos + offset ) * scale * texscale ;
verts [ i ] . u = pos . x ;
verts [ i ] . v = pos . y ;
}
// The sector triangulation created clockwise triangles that
// are right up for the floor. For the ceiling we must flip
// the triangles upside down.
2016-01-23 02:53:31 +00:00
if ( extrafloor = = null | | extrafloor . VavoomType | | innerside )
2015-12-31 12:21:44 +00:00
SwapTriangleVertices ( verts ) ;
// Determine render pass
if ( extrafloor ! = null )
{
if ( extrafloor . Sloped3dFloor ) //mxd
this . RenderPass = RenderPass . Mask ;
else if ( extrafloor . RenderAdditive ) //mxd
this . RenderPass = RenderPass . Additive ;
2021-06-17 09:05:08 +00:00
else if ( extrafloor . RenderSubtractive )
this . RenderPass = RenderPass . Subtractive ;
else if ( extrafloor . RenderReverseSubtractive )
this . RenderPass = RenderPass . ReverseSubtractive ;
2015-12-31 12:21:44 +00:00
else if ( level . alpha < 255 )
this . RenderPass = RenderPass . Alpha ;
else
this . RenderPass = RenderPass . Mask ;
}
else
{
this . RenderPass = RenderPass . Solid ;
}
2016-01-23 00:30:20 +00:00
//mxd. Update sky render flag
UpdateSkyRenderFlag ( ) ;
// Apply vertices
base . SetVertices ( verts ) ;
2015-12-31 12:21:44 +00:00
return ( verts . Length > 0 ) ;
}
2016-01-23 00:30:20 +00:00
//mxd
2016-01-23 00:36:59 +00:00
protected override void UpdateSkyRenderFlag ( )
2016-01-23 00:30:20 +00:00
{
bool isrenderedassky = renderassky ;
renderassky = ( level . sector . CeilTexture = = General . Map . Config . SkyFlatName ) ;
if ( isrenderedassky ! = renderassky & & Sector . Sides ! = null )
{
// Upper/middle geometry may need updating...
foreach ( Sidedef side in level . sector . Sidedefs )
{
VisualSidedefParts parts = Sector . GetSidedefParts ( side ) ;
if ( parts . upper ! = null ) parts . upper . UpdateSkyRenderFlag ( ) ;
else if ( parts . middlesingle ! = null ) parts . middlesingle . UpdateSkyRenderFlag ( ) ;
2016-01-23 00:36:59 +00:00
// On the other side as well...
2021-10-21 10:21:27 +00:00
if ( side . Other ! = null & & side . Other . Sector ! = null )
2016-01-23 00:36:59 +00:00
{
BaseVisualSector other = ( BaseVisualSector ) mode . GetVisualSector ( side . Other . Sector ) ;
if ( other ! = null & & other . Sides ! = null )
{
parts = other . GetSidedefParts ( side . Other ) ;
if ( parts . upper ! = null ) parts . upper . UpdateSkyRenderFlag ( ) ;
}
}
2016-01-23 00:30:20 +00:00
}
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
2016-09-06 12:05:47 +00:00
//mxd
public override void OnChangeScale ( int incrementX , int incrementY )
{
// Only do this when not done yet in this call
// Because we may be able to select the same 3D floor multiple times through multiple sectors
SectorData sd = mode . GetSectorData ( level . sector ) ;
if ( ! sd . CeilingChanged )
{
sd . CeilingChanged = true ;
base . OnChangeScale ( incrementX , incrementY ) ;
}
}
//mxd
public override void OnChangeTextureRotation ( float angle )
{
// Only do this when not done yet in this call
// Because we may be able to select the same 3D floor multiple times through multiple sectors
SectorData sd = mode . GetSectorData ( level . sector ) ;
if ( ! sd . CeilingChanged )
{
sd . CeilingChanged = true ;
base . OnChangeTextureRotation ( angle ) ;
}
}
// Return texture coordinates
protected override Point GetTextureOffset ( )
2015-12-31 12:21:44 +00:00
{
return new Point { X = ( int ) Sector . Sector . Fields . GetValue ( "xpanningceiling" , 0.0f ) ,
Y = ( int ) Sector . Sector . Fields . GetValue ( "ypanningceiling" , 0.0f ) } ;
}
2016-09-06 12:05:47 +00:00
//mxd
public override void OnChangeTextureOffset ( int horizontal , int vertical , bool doSurfaceAngleCorrection )
{
// Only do this when not done yet in this call
// Because we may be able to select the same 3D floor multiple times through multiple sectors
SectorData sd = mode . GetSectorData ( level . sector ) ;
if ( ! sd . CeilingChanged )
{
sd . CeilingChanged = true ;
base . OnChangeTextureOffset ( horizontal , vertical , doSurfaceAngleCorrection ) ;
}
}
2015-12-31 12:21:44 +00:00
// Move texture coordinates
2016-09-06 12:05:47 +00:00
protected override void MoveTextureOffset ( int offsetx , int offsety )
2015-12-31 12:21:44 +00:00
{
//mxd
Sector s = GetControlSector ( ) ;
s . Fields . BeforeFieldsChange ( ) ;
2021-06-04 23:36:37 +00:00
if ( General . Map . SRB2 )
{
Linedef alignment = null ;
foreach ( Sidedef side in s . Sidedefs )
2021-08-26 11:59:31 +00:00
if ( side . Line . IsFlatAlignment & & side . Line . Tag = = 0 & & side . Line . Front . Sector = = s ) alignment = side . Line ;
2021-06-04 23:36:37 +00:00
if ( alignment = = null )
{
mode . SetActionResult ( "Sector has no flat alignment line!" ) ;
return ;
}
else
{
if ( alignment . IsFlagSet ( "4096" ) )
alignment . SetFlag ( "4096" , false ) ;
if ( ! alignment . IsFlagSet ( "8192" ) )
alignment . SetFlag ( "8192" , true ) ;
2016-09-06 12:05:47 +00:00
alignment . Front . OffsetX + = offsetx ;
alignment . Front . OffsetY + = offsety ;
2021-06-04 23:36:37 +00:00
float rotation = General . ClampAngle ( 90f - alignment . Angle * Angle2D . PIDEG ) ;
float rotationrad = rotation / Angle2D . PIDEG ;
float rx = ( float ) Math . Cos ( rotationrad ) * alignment . Front . OffsetX - ( float ) Math . Sin ( rotationrad ) * - alignment . Front . OffsetY ;
float ry = ( float ) Math . Sin ( rotationrad ) * alignment . Front . OffsetX + ( float ) Math . Cos ( rotationrad ) * - alignment . Front . OffsetY ;
if ( s . Fields . ContainsKey ( "xpanningceiling" ) ) s . Fields [ "xpanningceiling" ] = new UniValue ( UniversalType . Float , rx ) ;
else s . Fields . Add ( "xpanningceiling" , new UniValue ( UniversalType . Float , rx ) ) ;
if ( s . Fields . ContainsKey ( "ypanningceiling" ) ) s . Fields [ "ypanningceiling" ] = new UniValue ( UniversalType . Float , - ry ) ;
else s . Fields . Add ( "ypanningceiling" , new UniValue ( UniversalType . Float , - ry ) ) ;
if ( s . Fields . ContainsKey ( "rotationfloor" ) ) s . Fields [ "rotationfloor" ] = new UniValue ( UniversalType . Float , rotation ) ;
else s . Fields . Add ( "rotationfloor" , new UniValue ( UniversalType . Float , rotation ) ) ;
if ( s . Fields . ContainsKey ( "rotationceiling" ) ) s . Fields [ "rotationceiling" ] = new UniValue ( UniversalType . Float , rotation ) ;
else s . Fields . Add ( "rotationceiling" , new UniValue ( UniversalType . Float , rotation ) ) ;
s . UpdateNeeded = true ;
mode . SetActionResult ( "Changed ceiling texture offsets to " + alignment . Front . OffsetX + ", " + alignment . Front . OffsetY + "." ) ;
}
}
else
{
2016-09-06 12:05:47 +00:00
float nx = ( s . Fields . GetValue ( "xpanningceiling" , 0.0f ) + offsetx ) % ( Texture . ScaledWidth / s . Fields . GetValue ( "xscaleceiling" , 1.0f ) ) ;
float ny = ( s . Fields . GetValue ( "ypanningceiling" , 0.0f ) + offsety ) % ( Texture . ScaledHeight / s . Fields . GetValue ( "yscaleceiling" , 1.0f ) ) ;
2021-06-04 23:36:37 +00:00
s . Fields [ "xpanningceiling" ] = new UniValue ( UniversalType . Float , nx ) ;
s . Fields [ "ypanningceiling" ] = new UniValue ( UniversalType . Float , ny ) ;
s . UpdateNeeded = true ;
2015-12-31 12:21:44 +00:00
2021-06-04 23:36:37 +00:00
mode . SetActionResult ( "Changed ceiling texture offsets to " + nx + ", " + ny + "." ) ;
}
2015-12-31 12:21:44 +00:00
}
//mxd. Texture scale change
protected override void ChangeTextureScale ( int incrementX , int incrementY )
{
2016-09-02 19:18:37 +00:00
if ( Texture = = null | | ! Texture . IsImageLoaded ) return ;
2015-12-31 12:21:44 +00:00
Sector s = GetControlSector ( ) ;
float scaleX = s . Fields . GetValue ( "xscaleceiling" , 1.0f ) ;
float scaleY = s . Fields . GetValue ( "yscaleceiling" , 1.0f ) ;
s . Fields . BeforeFieldsChange ( ) ;
if ( incrementX ! = 0 )
{
float pix = ( int ) Math . Round ( Texture . Width * scaleX ) - incrementX ;
float newscaleX = ( float ) Math . Round ( pix / Texture . Width , 3 ) ;
scaleX = ( newscaleX = = 0 ? scaleX * - 1 : newscaleX ) ;
UniFields . SetFloat ( s . Fields , "xscaleceiling" , scaleX , 1.0f ) ;
}
if ( incrementY ! = 0 )
{
float pix = ( int ) Math . Round ( Texture . Height * scaleY ) - incrementY ;
float newscaleY = ( float ) Math . Round ( pix / Texture . Height , 3 ) ;
scaleY = ( newscaleY = = 0 ? scaleY * - 1 : newscaleY ) ;
UniFields . SetFloat ( s . Fields , "yscaleceiling" , scaleY , 1.0f ) ;
}
mode . SetActionResult ( "Ceiling scale changed to " + scaleX . ToString ( "F03" , CultureInfo . InvariantCulture ) + ", " + scaleY . ToString ( "F03" , CultureInfo . InvariantCulture ) + " (" + ( int ) Math . Round ( Texture . Width / scaleX ) + " x " + ( int ) Math . Round ( Texture . Height / scaleY ) + ")." ) ;
}
//mxd
2021-06-04 23:36:37 +00:00
public override void OnResetTextureOffset ( )
2015-12-31 12:21:44 +00:00
{
2021-06-04 23:36:37 +00:00
if ( General . Map . SRB2 )
{
Sector s = GetControlSector ( ) ;
foreach ( Sidedef side in s . Sidedefs )
if ( side . Line . IsFlatAlignment & & side . Line . Tag = = 0 & & side . Sector = = s & & side . Line . IsFlagSet ( "8192" ) )
{
float rotation = General . ClampAngle ( 90f - side . Angle * Angle2D . PIDEG ) ;
if ( s . Fields . ContainsKey ( "rotationfloor" ) ) s . Fields [ "rotationfloor" ] = new UniValue ( UniversalType . Float , rotation ) ;
else s . Fields . Add ( "rotationfloor" , new UniValue ( UniversalType . Float , rotation ) ) ;
if ( s . Fields . ContainsKey ( "rotationceiling" ) ) s . Fields [ "rotationceiling" ] = new UniValue ( UniversalType . Float , rotation ) ;
else s . Fields . Add ( "rotationceiling" , new UniValue ( UniversalType . Float , rotation ) ) ;
side . Line . Front . OffsetX = side . Line . Front . OffsetY = 0 ;
ClearFields ( new [ ] { "xpanningfloor" , "ypanningfloor" , "xpanningceiling" , "ypanningceiling" } ,
"Reset texture offsets" , "Texture offsets reset." ) ;
return ;
}
}
else
ClearFields ( new [ ] { "xpanningceiling" , "ypanningceiling" } , "Reset texture offsets" , "Texture offsets reset." ) ;
2015-12-31 12:21:44 +00:00
}
//mxd
public override void OnResetLocalTextureOffset ( )
{
ClearFields ( new [ ] { "xpanningceiling" , "ypanningceiling" , "xscaleceiling" , "yscaleceiling" , "rotationceiling" , "lightceiling" , "lightceilingabsolute" } ,
"Reset texture offsets, scale, rotation and brightness" , "Texture offsets, scale, rotation and brightness reset." ) ;
}
// Paste texture
public override void OnPasteTexture ( )
{
if ( BuilderPlug . Me . CopiedFlat ! = null )
{
2022-11-25 17:14:35 +00:00
mode . CreateUndo ( "Paste ceiling \"" + BuilderPlug . Me . CopiedFlat + "\"" ) ;
mode . SetActionResult ( "Pasted flat \"" + BuilderPlug . Me . CopiedFlat + "\" on ceiling." ) ;
2015-12-31 12:21:44 +00:00
SetTexture ( BuilderPlug . Me . CopiedFlat ) ;
2016-04-19 20:40:42 +00:00
// Update
if ( mode . VisualSectorExists ( level . sector ) )
{
BaseVisualSector vs = ( BaseVisualSector ) mode . GetVisualSector ( level . sector ) ;
vs . UpdateSectorGeometry ( false ) ;
}
2015-12-31 12:21:44 +00:00
}
}
// Call to change the height
public override void OnChangeTargetHeight ( int amount )
{
// Only do this when not done yet in this call
// Because we may be able to select the same 3D floor multiple times through multiple sectors
SectorData sd = mode . GetSectorData ( level . sector ) ;
if ( ! sd . CeilingChanged )
{
sd . CeilingChanged = true ;
base . OnChangeTargetHeight ( amount ) ;
}
}
// This changes the height
protected override void ChangeHeight ( int amount )
{
mode . CreateUndo ( "Change ceiling height" , UndoGroup . CeilingHeightChange , level . sector . FixedIndex ) ;
level . sector . CeilHeight + = amount ;
if ( General . Map . UDMF )
{
//mxd. Modify vertex offsets?
if ( level . sector . Sidedefs . Count = = 3 )
{
ChangeVertexHeight ( amount ) ;
}
//mxd. Modify slope offset?
if ( level . sector . CeilSlope . GetLengthSq ( ) > 0 )
{
Vector3D center = new Vector3D ( level . sector . BBox . X + level . sector . BBox . Width / 2 ,
level . sector . BBox . Y + level . sector . BBox . Height / 2 ,
level . sector . CeilHeight ) ;
Plane p = new Plane ( center ,
level . sector . CeilSlope . GetAngleXY ( ) - Angle2D . PIHALF ,
level . sector . CeilSlope . GetAngleZ ( ) ,
false ) ;
level . sector . CeilSlopeOffset = p . Offset ;
}
}
mode . SetActionResult ( "Changed ceiling height to " + level . sector . CeilHeight + "." ) ;
}
//mxd
private void ChangeVertexHeight ( int amount )
{
2016-05-20 15:04:00 +00:00
HashSet < Vertex > verts = new HashSet < Vertex > ( ) ;
2015-12-31 12:21:44 +00:00
2016-05-20 15:04:00 +00:00
// Do this only if all 3 verts have offsets
2015-12-31 12:21:44 +00:00
foreach ( Sidedef side in level . sector . Sidedefs )
{
if ( float . IsNaN ( side . Line . Start . ZCeiling ) | | float . IsNaN ( side . Line . End . ZCeiling ) ) return ;
2016-05-20 15:04:00 +00:00
verts . Add ( side . Line . Start ) ;
verts . Add ( side . Line . End ) ;
2015-12-31 12:21:44 +00:00
}
foreach ( Vertex v in verts )
mode . GetVisualVertex ( v , false ) . OnChangeTargetHeight ( amount ) ;
}
//mxd. Sector brightness change
public override void OnChangeTargetBrightness ( bool up )
{
if ( level ! = null & & level . sector ! = Sector . Sector )
{
int index = - 1 ;
for ( int i = 0 ; i < Sector . ExtraCeilings . Count ; i + + )
{
if ( Sector . ExtraCeilings [ i ] = = this )
{
index = i + 1 ;
break ;
}
}
if ( index > - 1 & & index < Sector . ExtraCeilings . Count )
( ( BaseVisualSector ) mode . GetVisualSector ( Sector . ExtraCeilings [ index ] . level . sector ) ) . Floor . OnChangeTargetBrightness ( up ) ;
else
base . OnChangeTargetBrightness ( up ) ;
}
else
{
//if a map is not in UDMF format, or this ceiling is part of 3D-floor...
if ( ! General . Map . UDMF | | ( level ! = null & & Sector . Sector ! = level . sector ) )
{
base . OnChangeTargetBrightness ( up ) ;
return ;
}
int light = Sector . Sector . Fields . GetValue ( "lightceiling" , 0 ) ;
bool absolute = Sector . Sector . Fields . GetValue ( "lightceilingabsolute" , false ) ;
int newLight ;
if ( up )
newLight = General . Map . Config . BrightnessLevels . GetNextHigher ( light , absolute ) ;
else
newLight = General . Map . Config . BrightnessLevels . GetNextLower ( light , absolute ) ;
if ( newLight = = light ) return ;
//create undo
mode . CreateUndo ( "Change ceiling brightness" , UndoGroup . SurfaceBrightnessChange , Sector . Sector . FixedIndex ) ;
Sector . Sector . Fields . BeforeFieldsChange ( ) ;
//apply changes
UniFields . SetInteger ( Sector . Sector . Fields , "lightceiling" , newLight , ( absolute ? int . MinValue : 0 ) ) ;
mode . SetActionResult ( "Changed ceiling brightness to " + newLight + "." ) ;
Sector . Sector . UpdateNeeded = true ;
Sector . Sector . UpdateCache ( ) ;
//rebuild sector
Sector . UpdateSectorGeometry ( false ) ;
}
}
// This performs a fast test in object picking
public override bool PickFastReject ( Vector3D from , Vector3D to , Vector3D dir )
{
// Check if our ray starts at the correct side of the plane
2016-01-23 02:53:31 +00:00
if ( ( innerside & & level . plane . Distance ( from ) < 0.0f ) | | ( ! innerside & & level . plane . Distance ( from ) > 0.0f ) ) //mxd
2015-12-31 12:21:44 +00:00
//if(level.plane.Distance(from) > 0.0f)
{
// Calculate the intersection
if ( level . plane . GetIntersection ( from , to , ref pickrayu ) )
{
if ( pickrayu > 0.0f )
{
pickintersect = from + ( to - from ) * pickrayu ;
// Intersection point within bbox?
RectangleF bbox = Sector . Sector . BBox ;
return ( ( pickintersect . x > = bbox . Left ) & & ( pickintersect . x < = bbox . Right ) & &
( pickintersect . y > = bbox . Top ) & & ( pickintersect . y < = bbox . Bottom ) ) ;
}
}
}
return false ;
}
// This performs an accurate test for object picking
public override bool PickAccurate ( Vector3D from , Vector3D to , Vector3D dir , ref float u_ray )
{
u_ray = pickrayu ;
// Check on which side of the nearest sidedef we are
Sidedef sd = MapSet . NearestSidedef ( Sector . Sector . Sidedefs , pickintersect ) ;
float side = sd . Line . SideOfLine ( pickintersect ) ;
2016-01-29 10:02:09 +00:00
2016-06-13 23:37:55 +00:00
//mxd. Alpha based picking. Used only on extrafloors with transparent or masked textures
if ( ( side < = 0.0f & & sd . IsFront ) | | ( side > 0.0f & & ! sd . IsFront ) )
{
if ( ! BuilderPlug . Me . AlphaBasedTextureHighlighting | | ! Texture . IsImageLoaded | | extrafloor = = null | | RenderPass = = RenderPass . Solid | | ( ! Texture . IsTranslucent & & ! Texture . IsMasked ) )
return true ;
2016-01-29 10:02:09 +00:00
// Fetch ZDoom fields
float rotate = Angle2D . DegToRad ( level . sector . Fields . GetValue ( "rotationceiling" , 0.0f ) ) ;
Vector2D offset = new Vector2D ( level . sector . Fields . GetValue ( "xpanningceiling" , 0.0f ) , level . sector . Fields . GetValue ( "ypanningceiling" , 0.0f ) ) ;
Vector2D scale = new Vector2D ( level . sector . Fields . GetValue ( "xscaleceiling" , 1.0f ) , level . sector . Fields . GetValue ( "yscaleceiling" , 1.0f ) ) ;
Vector2D texscale = new Vector2D ( 1.0f / Texture . ScaledWidth , 1.0f / Texture . ScaledHeight ) ;
// Texture coordinates
Vector2D o = pickintersect ;
o = o . GetRotated ( rotate ) ;
o . y = - o . y ;
o = ( o + offset ) * scale * texscale ;
o . x = ( o . x * Texture . Width ) % Texture . Width ;
o . y = ( o . y * Texture . Height ) % Texture . Height ;
// Make sure coordinates are inside of texture dimensions...
if ( o . x < 0 ) o . x + = Texture . Width ;
if ( o . y < 0 ) o . y + = Texture . Height ;
// Make final texture coordinates...
int ox = General . Clamp ( ( int ) Math . Floor ( o . x ) , 0 , Texture . Width - 1 ) ;
int oy = General . Clamp ( ( int ) Math . Floor ( o . y ) , 0 , Texture . Height - 1 ) ;
// Check pixel alpha
return ( Texture . GetBitmap ( ) . GetPixel ( ox , oy ) . A > 0 ) ;
}
return false ;
}
2015-12-31 12:21:44 +00:00
// Return texture name
public override string GetTextureName ( )
{
return level . sector . CeilTexture ;
}
// This changes the texture
protected override void SetTexture ( string texturename )
{
2022-11-25 17:14:35 +00:00
// Set new texture
2015-12-31 12:21:44 +00:00
level . sector . SetCeilTexture ( texturename ) ;
General . Map . Data . UpdateUsedTextures ( ) ;
}
//mxd
public override void SelectNeighbours ( bool select , bool withSameTexture , bool withSameHeight )
{
if ( ! withSameTexture & & ! withSameHeight ) return ;
if ( select & & ! selected )
{
selected = true ;
mode . AddSelectedObject ( this ) ;
}
else if ( ! select & & selected )
{
selected = false ;
mode . RemoveSelectedObject ( this ) ;
}
List < Sector > neighbours = new List < Sector > ( ) ;
bool regularorvavoom = extrafloor = = null | | ( extrafloor ! = null & & extrafloor . VavoomType ) ;
//collect neighbour sectors
foreach ( Sidedef side in Sector . Sector . Sidedefs )
{
if ( side . Other ! = null & & side . Other . Sector ! = Sector . Sector & & ! neighbours . Contains ( side . Other . Sector ) )
{
2016-04-19 20:40:42 +00:00
BaseVisualSector vs = ( BaseVisualSector ) mode . GetVisualSector ( side . Other . Sector ) ;
2015-12-31 12:21:44 +00:00
if ( vs = = null ) continue ;
// When current ceiling is part of a 3d floor, it looks like a floor, so we need to select adjacent floors
if ( level . sector ! = Sector . Sector & & ! regularorvavoom )
{
2016-05-12 11:32:10 +00:00
if ( ( ! withSameTexture | | side . Other . Sector . LongFloorTexture = = level . sector . LongCeilTexture ) & &
( ! withSameHeight | | side . Other . Sector . FloorHeight = = level . sector . CeilHeight ) )
2015-12-31 12:21:44 +00:00
{
neighbours . Add ( side . Other . Sector ) ;
//(de)select regular visual floor?
if ( select ! = vs . Floor . Selected )
vs . Floor . SelectNeighbours ( select , withSameTexture , withSameHeight ) ;
}
}
else // Regular ceiling or vavoom-type extra ceiling
{
// (De)select adjacent ceilings
2016-05-12 11:32:10 +00:00
if ( ( ! withSameTexture | | side . Other . Sector . LongCeilTexture = = level . sector . LongCeilTexture ) & &
( ! withSameHeight | | side . Other . Sector . CeilHeight = = level . sector . CeilHeight ) )
2015-12-31 12:21:44 +00:00
{
neighbours . Add ( side . Other . Sector ) ;
//(de)select regular visual ceiling?
if ( select ! = vs . Ceiling . Selected )
vs . Ceiling . SelectNeighbours ( select , withSameTexture , withSameHeight ) ;
}
}
// (De)select adjacent extra ceilings
foreach ( VisualCeiling ec in vs . ExtraCeilings )
{
if ( select = = ec . Selected | | ec . extrafloor . VavoomType ! = regularorvavoom ) continue ;
2016-05-12 11:32:10 +00:00
if ( ( ! withSameTexture | | level . sector . LongCeilTexture = = ec . level . sector . LongCeilTexture ) & &
( ! withSameHeight | | level . sector . CeilHeight = = ec . level . sector . CeilHeight ) )
2015-12-31 12:21:44 +00:00
{
ec . SelectNeighbours ( select , withSameTexture , withSameHeight ) ;
}
}
// (De)select adjacent extra floors
foreach ( VisualFloor ef in vs . ExtraFloors )
{
if ( select = = ef . Selected | | ef . ExtraFloor . VavoomType = = regularorvavoom ) continue ;
2016-05-12 11:32:10 +00:00
if ( ( ! withSameTexture | | level . sector . LongCeilTexture = = ef . Level . sector . LongFloorTexture ) & &
( ! withSameHeight | | level . sector . CeilHeight = = ef . Level . sector . FloorHeight ) )
2015-12-31 12:21:44 +00:00
{
ef . SelectNeighbours ( select , withSameTexture , withSameHeight ) ;
}
}
}
}
}
//mxd
public void AlignTexture ( bool alignx , bool aligny )
{
if ( ! General . Map . UDMF ) return ;
//is is a surface with line slope?
float slopeAngle = level . plane . Normal . GetAngleZ ( ) - Angle2D . PIHALF ;
if ( slopeAngle = = 0 ) //it's a horizontal plane
{
AlignTextureToClosestLine ( alignx , aligny ) ;
}
else //it can be a surface with line slope
{
Linedef slopeSource = null ;
bool isFront = false ;
foreach ( Sidedef side in Sector . Sector . Sidedefs )
{
2015-12-31 15:46:40 +00:00
// MascaraSnake: Slope handling
2016-01-14 23:47:32 +00:00
if ( side . Line . IsRegularSlope )
2015-12-31 12:21:44 +00:00
{
if ( side . Line . Args [ 1 ] = = 1 & & side . Line . Front ! = null & & side . Line . Front = = side )
{
slopeSource = side . Line ;
isFront = true ;
break ;
}
if ( side . Line . Args [ 1 ] = = 2 & & side . Line . Back ! = null & & side . Line . Back = = side )
{
slopeSource = side . Line ;
break ;
}
}
}
if ( slopeSource ! = null & & slopeSource . Front ! = null & & slopeSource . Front . Sector ! = null & & slopeSource . Back ! = null & & slopeSource . Back . Sector ! = null )
AlignTextureToSlopeLine ( slopeSource , slopeAngle , isFront , alignx , aligny ) ;
else
AlignTextureToClosestLine ( alignx , aligny ) ;
}
}
#endregion
}
}