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.Drawing ;
2016-04-19 20:40:42 +00:00
using System.Globalization ;
2015-12-31 12:21:44 +00:00
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
{
2016-04-19 20:40:42 +00:00
internal class VisualMiddle3D : BaseVisualGeometrySidedef
2015-12-31 12:21:44 +00:00
{
#region = = = = = = = = = = = = = = = = = = Constants
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
2016-04-19 20:40:42 +00:00
protected Effect3DFloor extrafloor ;
2015-12-31 12:21:44 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Setup
// Constructor
public VisualMiddle3D ( BaseVisualMode mode , VisualSector vs , Sidedef s ) : base ( mode , vs , s )
{
//mxd
geometrytype = VisualGeometryType . WALL_MIDDLE_3D ;
partname = "mid" ;
// We have no destructor
GC . SuppressFinalize ( this ) ;
}
// This builds the geometry. Returns false when no geometry created.
public override bool Setup ( ) { return this . Setup ( this . extrafloor ) ; }
public bool Setup ( Effect3DFloor extrafloor )
{
Sidedef sourceside = extrafloor . Linedef . Front ;
this . extrafloor = extrafloor ;
//mxd. Extrafloor may've become invalid during undo/redo...
if ( sourceside = = null ) return false ;
Vector2D vl , vr ;
//mxd. lightfog flag support
int lightvalue ;
bool lightabsolute ;
GetLightValue ( out lightvalue , out lightabsolute ) ;
Vector2D tscale = new Vector2D ( sourceside . Fields . GetValue ( "scalex_mid" , 1.0f ) ,
sourceside . Fields . GetValue ( "scaley_mid" , 1.0f ) ) ;
Vector2D toffset1 = new Vector2D ( Sidedef . Fields . GetValue ( "offsetx_mid" , 0.0f ) ,
Sidedef . Fields . GetValue ( "offsety_mid" , 0.0f ) ) ;
Vector2D toffset2 = new Vector2D ( sourceside . Fields . GetValue ( "offsetx_mid" , 0.0f ) ,
sourceside . Fields . GetValue ( "offsety_mid" , 0.0f ) ) ;
// Left and right vertices for this sidedef
if ( Sidedef . IsFront )
{
vl = new Vector2D ( Sidedef . Line . Start . Position . x , Sidedef . Line . Start . Position . y ) ;
vr = new Vector2D ( Sidedef . Line . End . Position . x , Sidedef . Line . End . Position . y ) ;
}
else
{
vl = new Vector2D ( Sidedef . Line . End . Position . x , Sidedef . Line . End . Position . y ) ;
vr = new Vector2D ( Sidedef . Line . Start . Position . x , Sidedef . Line . Start . Position . y ) ;
}
// Load sector data
SectorData sd = mode . GetSectorData ( Sidedef . Sector ) ;
2021-10-24 15:21:10 +00:00
2015-12-31 12:21:44 +00:00
//mxd. which texture we must use?
2016-04-19 20:40:42 +00:00
long texturelong = 0 ;
2015-12-31 12:21:44 +00:00
if ( ( sourceside . Line . Args [ 2 ] & ( int ) Effect3DFloor . Flags . UseUpperTexture ) ! = 0 )
{
if ( Sidedef . LongHighTexture ! = MapSet . EmptyLongName )
2016-04-19 20:40:42 +00:00
texturelong = Sidedef . LongHighTexture ;
2015-12-31 12:21:44 +00:00
}
else if ( ( sourceside . Line . Args [ 2 ] & ( int ) Effect3DFloor . Flags . UseLowerTexture ) ! = 0 )
{
if ( Sidedef . LongLowTexture ! = MapSet . EmptyLongName )
2016-04-19 20:40:42 +00:00
texturelong = Sidedef . LongLowTexture ;
2015-12-31 12:21:44 +00:00
}
else if ( sourceside . LongMiddleTexture ! = MapSet . EmptyLongName )
{
2016-04-19 20:40:42 +00:00
texturelong = sourceside . LongMiddleTexture ;
2015-12-31 12:21:44 +00:00
}
// Texture given?
2016-04-19 20:40:42 +00:00
if ( texturelong ! = 0 )
2015-12-31 12:21:44 +00:00
{
// Load texture
2016-04-19 20:40:42 +00:00
base . Texture = General . Map . Data . GetTextureImage ( texturelong ) ;
2015-12-31 12:21:44 +00:00
if ( base . Texture = = null | | base . Texture is UnknownImage )
{
base . Texture = General . Map . Data . UnknownTexture3D ;
2016-04-19 20:40:42 +00:00
setuponloadedtexture = texturelong ;
2015-12-31 12:21:44 +00:00
}
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 = texturelong ;
2015-12-31 12:21:44 +00:00
}
}
else
{
// Use missing texture
base . Texture = General . Map . Data . MissingTexture3D ;
setuponloadedtexture = 0 ;
}
// Get texture scaled size
Vector2D tsz = new Vector2D ( base . Texture . ScaledWidth , base . Texture . ScaledHeight ) ;
tsz = tsz / tscale ;
// Get texture offsets
2016-01-03 14:54:29 +00:00
// MascaraSnake: In SRB2, take only the X offset of the target sidedef and the Y offset of the source sidedef. Yes, this is silly.
Vector2D tof = new Vector2D ( Sidedef . OffsetX , General . Map . SRB2 ? 0.0f : Sidedef . OffsetY ) + new Vector2D ( General . Map . SRB2 ? 0.0f : sourceside . OffsetX , sourceside . OffsetY ) ;
2015-12-31 12:21:44 +00:00
tof = tof + toffset1 + toffset2 ;
tof = tof / tscale ;
if ( General . Map . Config . ScaledTextureOffsets & & ! base . Texture . WorldPanning )
tof = tof * base . Texture . Scale ;
2021-10-24 15:21:10 +00:00
2015-12-31 12:21:44 +00:00
// For Vavoom type 3D floors the ceiling is lower than floor and they are reversed.
// We choose here.
float sourcetopheight = extrafloor . VavoomType ? sourceside . Sector . FloorHeight : sourceside . Sector . CeilHeight ;
float sourcebottomheight = extrafloor . VavoomType ? sourceside . Sector . CeilHeight : sourceside . Sector . FloorHeight ;
2021-10-24 15:21:10 +00:00
2015-12-31 12:21:44 +00:00
// Determine texture coordinates plane as they would be in normal circumstances.
// We can then use this plane to find any texture coordinate we need.
// The logic here is the same as in the original VisualMiddleSingle (except that
// the values are stored in a TexturePlane)
// NOTE: I use a small bias for the floor height, because if the difference in
// height is 0 then the TexturePlane doesn't work!
2021-10-24 15:21:10 +00:00
Vector3D vlt , vlb , vrt , vrb ;
Vector2D tlt , tlb , trt , trb ;
bool skew = General . Map . SRB2 & & sourceside . Line . IsFlagSet ( General . Map . Config . UpperUnpeggedFlag ) ;
float topheight = skew ? extrafloor . Ceiling . plane . GetZ ( vl ) : sourcetopheight ;
float bottomheight = skew ? extrafloor . Floor . plane . GetZ ( vl ) : sourcebottomheight ;
2021-10-24 20:33:25 +00:00
float topheight2 = skew ? extrafloor . Ceiling . plane . GetZ ( vr ) : sourcetopheight ;
float bottomheight2 = skew ? extrafloor . Floor . plane . GetZ ( vr ) : sourcebottomheight ;
//float floorbias = (topheight == bottomheight) ? 1.0f : 0.0f;
//float floorbias2 = (topheight2 == bottomheight2) ? 1.0f : 0.0f;
2021-10-24 15:21:10 +00:00
tlt . x = tlb . x = 0 ;
trt . x = trb . x = Sidedef . Line . Length ;
2021-10-25 18:43:49 +00:00
// For SRB2, invert Lower Unpegged behavior for non-skewed 3D floors
tlt . y = ! ( IsLowerUnpegged ( ) ^ skew ) ? 0 : - ( topheight - bottomheight ) ;
trt . y = ! ( IsLowerUnpegged ( ) ^ skew ) ? 0 : - ( topheight2 - bottomheight2 ) ;
tlb . y = ! ( ! IsLowerUnpegged ( ) ^ skew ) ? 0 : ( topheight - bottomheight ) ;
trb . y = ! ( ! IsLowerUnpegged ( ) ^ skew ) ? 0 : ( topheight2 - bottomheight2 ) ;
2015-12-31 12:21:44 +00:00
// Apply texture offset
2021-10-24 15:21:10 +00:00
tlt + = tof ;
tlb + = tof ;
trb + = tof ;
trt + = tof ;
2015-12-31 12:21:44 +00:00
// Transform pixel coordinates to texture coordinates
2021-10-24 15:21:10 +00:00
tlt / = tsz ;
tlb / = tsz ;
trb / = tsz ;
trt / = tsz ;
// Geometry coordinates
2021-10-24 20:33:25 +00:00
vlt = new Vector3D ( vl . x , vl . y , topheight ) ;
vlb = new Vector3D ( vl . x , vl . y , bottomheight ) ;
2021-10-24 15:21:10 +00:00
vrb = new Vector3D ( vr . x , vr . y , bottomheight2 ) ;
2021-10-24 20:33:25 +00:00
vrt = new Vector3D ( vr . x , vr . y , topheight2 ) ;
2021-10-24 15:21:10 +00:00
TexturePlane tp = new TexturePlane ( ) ;
tp . tlt = IsLowerUnpegged ( ) ? tlb : tlt ;
tp . trb = trb ;
tp . trt = trt ;
tp . vlt = IsLowerUnpegged ( ) ? vlb : vlt ;
tp . vrb = vrb ;
tp . vrt = vrt ;
2015-12-31 12:21:44 +00:00
//mxd. Get ceiling and floor heights. Use our and neighbour sector's data
SectorData sdo = mode . GetSectorData ( Sidedef . Other . Sector ) ;
float flo = sdo . Floor . plane . GetZ ( vl ) ;
float fro = sdo . Floor . plane . GetZ ( vr ) ;
float clo = sdo . Ceiling . plane . GetZ ( vl ) ;
float cro = sdo . Ceiling . plane . GetZ ( vr ) ;
float fle = sd . Floor . plane . GetZ ( vl ) ;
float fre = sd . Floor . plane . GetZ ( vr ) ;
float cle = sd . Ceiling . plane . GetZ ( vl ) ;
float cre = sd . Ceiling . plane . GetZ ( vr ) ;
float fl = flo > fle ? flo : fle ;
float fr = fro > fre ? fro : fre ;
float cl = clo < cle ? clo : cle ;
float cr = cro < cre ? cro : cre ;
// Anything to see?
if ( ( ( cl - fl ) > 0.01f ) | | ( ( cr - fr ) > 0.01f ) )
{
2022-12-19 20:57:31 +00:00
if ( extrafloor . Floor = = null | | extrafloor . Ceiling = = null )
return false ;
2015-12-31 12:21:44 +00:00
// Keep top and bottom planes for intersection testing
top = extrafloor . Floor . plane ;
bottom = extrafloor . Ceiling . plane ;
// Create initial polygon, which is just a quad between floor and ceiling
WallPolygon poly = new WallPolygon ( ) ;
poly . Add ( new Vector3D ( vl . x , vl . y , fl ) ) ;
poly . Add ( new Vector3D ( vl . x , vl . y , cl ) ) ;
poly . Add ( new Vector3D ( vr . x , vr . y , cr ) ) ;
poly . Add ( new Vector3D ( vr . x , vr . y , fr ) ) ;
// Determine initial color
int lightlevel = lightabsolute ? lightvalue : sd . Ceiling . brightnessbelow + lightvalue ;
//mxd. This calculates light with doom-style wall shading
PixelColor wallbrightness = PixelColor . FromInt ( mode . CalculateBrightness ( lightlevel , Sidedef ) ) ;
PixelColor wallcolor = PixelColor . Modulate ( sd . Ceiling . colorbelow , wallbrightness ) ;
2016-01-25 15:50:03 +00:00
fogfactor = CalculateFogFactor ( lightlevel ) ;
poly . color = wallcolor . WithAlpha ( 255 ) . ToInt ( ) ;
2015-12-31 12:21:44 +00:00
// Cut off the part above the 3D floor and below the 3D ceiling
CropPoly ( ref poly , extrafloor . Floor . plane , false ) ;
CropPoly ( ref poly , extrafloor . Ceiling . plane , false ) ;
// Cut out pieces that overlap 3D floors in this sector
List < WallPolygon > polygons = new List < WallPolygon > { poly } ;
2021-06-17 09:05:08 +00:00
bool translucent = ( extrafloor . RenderAdditive | | extrafloor . RenderSubtractive | | extrafloor . RenderReverseSubtractive | | extrafloor . Alpha < 255 ) ;
2015-12-31 12:21:44 +00:00
foreach ( Effect3DFloor ef in sd . ExtraFloors )
{
2022-08-21 02:31:30 +00:00
//Ashnal: sometimes we encounter other 3dfloors that havent been updated and have null floors/ceilings, lets update those first before continuing
if ( ef . Ceiling = = null )
ef . Update ( ) ;
2015-12-31 12:21:44 +00:00
//mxd. Our poly should be clipped when our ond other extrafloors are both solid or both translucent,
// or when only our extrafloor is translucent.
// Our poly should not be clipped when our extrafloor is translucent and the other one isn't and both have renderinside setting.
2021-06-17 09:05:08 +00:00
bool othertranslucent = ( ef . RenderAdditive | | ef . RenderSubtractive | | extrafloor . RenderReverseSubtractive | | ef . Alpha < 255 ) ;
2015-12-31 12:21:44 +00:00
if ( translucent & & ! othertranslucent & & ! ef . ClipSidedefs ) continue ;
if ( ef . ClipSidedefs = = extrafloor . ClipSidedefs | | ef . ClipSidedefs )
{
Sectors, Linedefs, Things modes: optimized text label rendering.
Fixed, Things mode: in some cases selection labels were not updated after editing a thing.
Fixed, Things mode: selection labels were positioned incorrectly on things with FixedSize setting.
Fixed, Sectors mode: fixed a crash when selecting self-referencing sector when selection labels were enabled.
Fixed, Visual mode: in some cases Auto-align texture actions were not working when "use long texture names" Map Options setting was enabled.
Fixed, MD2/MD3 loader: available animation frames upper bound check was performed incorrectly, which would cause a crash in some very special cases.
Fixed, Game configurations: most Hexen/ZDoom teleport actions use TeleportDests as teleport targets, not MapSpots.
2016-04-05 22:24:36 +00:00
//TODO: find out why ef can be not updated at this point
//TODO: [this crashed on me once when performing auto-align on myriad of textures on BoA C1M0]
if ( ef . Floor = = null | | ef . Ceiling = = null ) ef . Update ( ) ;
2015-12-31 12:21:44 +00:00
int num = polygons . Count ;
for ( int pi = 0 ; pi < num ; pi + + )
{
// Split by floor plane of 3D floor
WallPolygon p = polygons [ pi ] ;
WallPolygon np = SplitPoly ( ref p , ef . Ceiling . plane , true ) ;
if ( np . Count > 0 )
{
// Split part below floor by the ceiling plane of 3D floor
// and keep only the part below the ceiling (front)
SplitPoly ( ref np , ef . Floor . plane , true ) ;
if ( p . Count = = 0 )
{
polygons [ pi ] = np ;
}
else
{
polygons [ pi ] = p ;
polygons . Add ( np ) ;
}
}
else
{
polygons [ pi ] = p ;
}
}
}
}
// Process the polygon and create vertices
if ( polygons . Count > 0 )
{
List < WorldVertex > verts = CreatePolygonVertices ( polygons , tp , sd , lightvalue , lightabsolute ) ;
if ( verts . Count > 2 )
{
2016-01-13 18:27:21 +00:00
if ( extrafloor . Sloped3dFloor ) this . RenderPass = RenderPass . Mask ; //mxd
2015-12-31 12:21:44 +00:00
else if ( extrafloor . RenderAdditive ) this . RenderPass = RenderPass . Additive ; //mxd
2021-06-17 09:05:08 +00:00
else if ( extrafloor . RenderSubtractive ) this . RenderPass = RenderPass . Subtractive ;
else if ( extrafloor . RenderReverseSubtractive ) this . RenderPass = RenderPass . ReverseSubtractive ;
2016-01-13 18:27:21 +00:00
else if ( extrafloor . Alpha < 255 | | extrafloor . DontRenderSides ) this . RenderPass = RenderPass . Alpha ;
2015-12-31 12:21:44 +00:00
else this . RenderPass = RenderPass . Mask ;
2016-01-13 18:27:21 +00:00
if ( extrafloor . Alpha < 255 | | extrafloor . DontRenderSides )
2015-12-31 12:21:44 +00:00
{
// Apply alpha to vertices
byte alpha = ( byte ) General . Clamp ( extrafloor . Alpha , 0 , 255 ) ;
2016-01-13 18:27:21 +00:00
if ( extrafloor . DontRenderSides ) alpha = 0 ;
2015-12-31 12:21:44 +00:00
if ( alpha < 255 )
{
for ( int i = 0 ; i < verts . Count ; i + + )
{
WorldVertex v = verts [ i ] ;
v . c = PixelColor . FromInt ( v . c ) . WithAlpha ( alpha ) . ToInt ( ) ;
verts [ i ] = v ;
}
}
}
base . SetVertices ( verts ) ;
return true ;
}
}
}
base . SetVertices ( null ) ; //mxd
return false ;
}
2016-01-03 14:54:29 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
protected override int ChangeOffsetY ( int amount )
{
if ( General . Map . SRB2 )
{
Sidedef sourceside = extrafloor . Linedef . Front ;
sourceside . OffsetY - = amount ;
if ( geometrytype ! = VisualGeometryType . WALL_MIDDLE & & Texture ! = null ) sourceside . OffsetY % = Texture . Height ;
return sourceside . OffsetY ;
}
else return base . ChangeOffsetY ( amount ) ;
}
protected override void UpdateAfterTextureOffsetChange ( )
{
if ( General . Map . SRB2 )
{
//Update all sidedefs in the sector, since the Y offset of the 3D floor may have changed.
foreach ( Sidedef sd in Sidedef . Sector . Sidedefs )
{
VisualSidedefParts parts = Sector . GetSidedefParts ( sd ) ;
parts . SetupAllParts ( ) ;
}
}
else base . UpdateAfterTextureOffsetChange ( ) ;
}
// This performs a fast test in object picking (mxd)
public override bool PickFastReject ( Vector3D from , Vector3D to , Vector3D dir )
2015-12-31 12:21:44 +00:00
{
// Top and bottom are swapped in Vavoom-type 3d floors
if ( extrafloor . VavoomType )
return ( pickintersect . z > = top . GetZ ( pickintersect ) ) & & ( pickintersect . z < = bottom . GetZ ( pickintersect ) ) ;
return base . PickFastReject ( from , to , dir ) ;
}
2016-01-29 10:02:09 +00:00
//mxd. Alpha based picking
public override bool PickAccurate ( Vector3D from , Vector3D to , Vector3D dir , ref float u_ray )
{
if ( ! Texture . IsImageLoaded | | ( ! Texture . IsTranslucent & & ! Texture . IsMasked ) ) return base . PickAccurate ( from , to , dir , ref u_ray ) ;
float u ;
Sidedef sourceside = extrafloor . Linedef . Front ;
new Line2D ( from , to ) . GetIntersection ( Sidedef . Line . Line , out u ) ;
if ( Sidedef ! = Sidedef . Line . Front ) u = 1.0f - u ;
// Get correct offset to texture space...
float texoffsetx = Sidedef . OffsetX + sourceside . OffsetX + UniFields . GetFloat ( Sidedef . Fields , "offsetx_mid" ) + UniFields . GetFloat ( sourceside . Fields , "offsetx_mid" ) ;
int ox = ( int ) Math . Floor ( ( u * Sidedef . Line . Length * UniFields . GetFloat ( sourceside . Fields , "scalex_mid" , 1.0f ) / Texture . Scale . x + texoffsetx ) % Texture . Width ) ;
float texoffsety = Sidedef . OffsetY + sourceside . OffsetY + UniFields . GetFloat ( Sidedef . Fields , "offsety_mid" ) + UniFields . GetFloat ( sourceside . Fields , "offsety_mid" ) ;
int oy = ( int ) Math . Ceiling ( ( ( pickintersect . z - sourceside . Sector . CeilHeight ) * UniFields . GetFloat ( sourceside . Fields , "scaley_mid" , 1.0f ) / Texture . Scale . y - texoffsety ) % Texture . Height ) ;
// Make sure offsets are inside of texture dimensions...
if ( ox < 0 ) ox + = Texture . Width ;
if ( oy < 0 ) oy + = Texture . Height ;
// Check pixel alpha
if ( Texture . GetBitmap ( ) . GetPixel ( General . Clamp ( ox , 0 , Texture . Width - 1 ) , General . Clamp ( Texture . Height - oy , 0 , Texture . Height - 1 ) ) . A > 0 )
{
return base . PickAccurate ( from , to , dir , ref u_ray ) ;
}
return false ;
}
// Return texture name
public override string GetTextureName ( )
2015-12-31 12:21:44 +00:00
{
//mxd
if ( ( extrafloor . Linedef . Args [ 2 ] & ( int ) Effect3DFloor . Flags . UseUpperTexture ) ! = 0 )
return Sidedef . HighTexture ;
if ( ( extrafloor . Linedef . Args [ 2 ] & ( int ) Effect3DFloor . Flags . UseLowerTexture ) ! = 0 )
return Sidedef . LowTexture ;
return extrafloor . Linedef . Front . MiddleTexture ;
}
// This changes the texture
protected override void SetTexture ( string texturename )
{
//mxd
if ( ( extrafloor . Linedef . Args [ 2 ] & ( int ) Effect3DFloor . Flags . UseUpperTexture ) ! = 0 )
Sidedef . SetTextureHigh ( texturename ) ;
if ( ( extrafloor . Linedef . Args [ 2 ] & ( int ) Effect3DFloor . Flags . UseLowerTexture ) ! = 0 )
Sidedef . SetTextureLow ( texturename ) ;
else
extrafloor . Linedef . Front . SetTextureMid ( texturename ) ;
General . Map . Data . UpdateUsedTextures ( ) ;
2016-04-19 20:40:42 +00:00
//mxd. Update model sector
2015-12-31 12:21:44 +00:00
mode . GetVisualSector ( extrafloor . Linedef . Front . Sector ) . UpdateSectorGeometry ( false ) ;
}
protected override void SetTextureOffsetX ( int x )
{
Sidedef . Fields . BeforeFieldsChange ( ) ;
Sidedef . Fields [ "offsetx_mid" ] = new UniValue ( UniversalType . Float , ( float ) x ) ;
}
protected override void SetTextureOffsetY ( int y )
{
Sidedef . Fields . BeforeFieldsChange ( ) ;
Sidedef . Fields [ "offsety_mid" ] = new UniValue ( UniversalType . Float , ( float ) y ) ;
}
protected override void MoveTextureOffset ( Point xy )
{
Sidedef . Fields . BeforeFieldsChange ( ) ;
float oldx = Sidedef . Fields . GetValue ( "offsetx_mid" , 0.0f ) ;
float oldy = Sidedef . Fields . GetValue ( "offsety_mid" , 0.0f ) ;
2016-04-19 20:40:42 +00:00
float scalex = extrafloor . Linedef . Front . Fields . GetValue ( "scalex_mid" , 1.0f ) ; //mxd
float scaley = extrafloor . Linedef . Front . Fields . GetValue ( "scaley_mid" , 1.0f ) ; //mxd
Sidedef . Fields [ "offsetx_mid" ] = new UniValue ( UniversalType . Float , GetRoundedTextureOffset ( oldx , xy . X , scalex , Texture . Width ) ) ; //mxd
Sidedef . Fields [ "offsety_mid" ] = new UniValue ( UniversalType . Float , GetRoundedTextureOffset ( oldy , xy . Y , scaley , Texture . Height ) ) ; //mxd
2015-12-31 12:21:44 +00:00
}
protected override Point GetTextureOffset ( )
{
float oldx = Sidedef . Fields . GetValue ( "offsetx_mid" , 0.0f ) ;
float oldy = Sidedef . Fields . GetValue ( "offsety_mid" , 0.0f ) ;
return new Point ( ( int ) oldx , ( int ) oldy ) ;
}
//mxd
public override Linedef GetControlLinedef ( )
{
return extrafloor . Linedef ;
}
//mxd
public override void OnTextureFit ( FitTextureOptions options )
{
if ( ! General . Map . UDMF ) return ;
if ( string . IsNullOrEmpty ( extrafloor . Linedef . Front . MiddleTexture ) | | extrafloor . Linedef . Front . MiddleTexture = = "-" | | ! Texture . IsImageLoaded ) return ;
FitTexture ( options ) ;
2016-04-19 20:40:42 +00:00
// Update the model sector to update all 3d floors
mode . GetVisualSector ( extrafloor . Linedef . Front . Sector ) . UpdateSectorGeometry ( false ) ;
}
//mxd. Only control sidedef scale is used by GZDoom
public override void OnChangeScale ( int incrementX , int incrementY )
{
if ( ! General . Map . UDMF | | ! Texture . IsImageLoaded ) return ;
if ( ( General . Map . UndoRedo . NextUndo = = null ) | | ( General . Map . UndoRedo . NextUndo . TicketID ! = undoticket ) )
undoticket = mode . CreateUndo ( "Change wall scale" ) ;
Sidedef target = extrafloor . Linedef . Front ;
if ( target = = null ) return ;
float scaleX = target . Fields . GetValue ( "scalex_mid" , 1.0f ) ;
float scaleY = target . Fields . GetValue ( "scaley_mid" , 1.0f ) ;
target . 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 ( target . Fields , "scalex_mid" , 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 ( target . Fields , "scaley_mid" , scaleY , 1.0f ) ;
}
// Update the model sector to update all 3d floors
mode . GetVisualSector ( extrafloor . Linedef . Front . Sector ) . UpdateSectorGeometry ( false ) ;
// Display result
mode . SetActionResult ( "Wall 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
protected override void ResetTextureScale ( )
{
Sidedef target = extrafloor . Linedef . Front ;
target . Fields . BeforeFieldsChange ( ) ;
if ( target . Fields . ContainsKey ( "scalex_mid" ) ) target . Fields . Remove ( "scalex_mid" ) ;
if ( target . Fields . ContainsKey ( "scaley_mid" ) ) target . Fields . Remove ( "scaley_mid" ) ;
}
//mxd
public override void OnResetTextureOffset ( )
{
base . OnResetTextureOffset ( ) ;
// Update the model sector to update all 3d floors
mode . GetVisualSector ( extrafloor . Linedef . Front . Sector ) . UpdateSectorGeometry ( false ) ;
}
//mxd
public override void OnResetLocalTextureOffset ( )
{
if ( ! General . Map . UDMF )
{
OnResetTextureOffset ( ) ;
return ;
}
base . OnResetLocalTextureOffset ( ) ;
2015-12-31 12:21:44 +00:00
// Update the model sector to update all 3d floors
mode . GetVisualSector ( extrafloor . Linedef . Front . Sector ) . UpdateSectorGeometry ( false ) ;
}
#endregion
}
}