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 ;
2015-03-03 09:42:54 +00:00
using System.Globalization ;
2009-04-19 18:07:22 +00:00
using System.Windows.Forms ;
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Rendering ;
using CodeImp.DoomBuilder.Geometry ;
using CodeImp.DoomBuilder.VisualModes ;
using CodeImp.DoomBuilder.Config ;
using CodeImp.DoomBuilder.Data ;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
internal class BaseVisualThing : VisualThing , IVisualEventReceiver
{
#region = = = = = = = = = = = = = = = = = = Constants
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
2014-12-22 21:36:49 +00:00
private readonly BaseVisualMode mode ;
2009-04-19 18:07:22 +00:00
private ThingTypeInfo info ;
private bool isloaded ;
2015-03-26 21:31:46 +00:00
private bool nointeraction ; //mxd
2009-04-19 18:07:22 +00:00
private ImageData sprite ;
private float cageradius2 ;
private Vector2D pos2d ;
private Vector3D boxp1 ;
private Vector3D boxp2 ;
2013-07-19 15:30:58 +00:00
private static List < BaseVisualThing > updateList ; //mxd
2009-04-19 18:07:22 +00:00
// Undo/redo
private int undoticket ;
2009-05-01 20:31:17 +00:00
// If this is set to true, the thing will be rebuilt after the action is performed.
protected bool changed ;
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
2009-05-01 20:31:17 +00:00
public bool Changed { get { return changed ; } set { changed | = value ; } }
2014-12-22 21:36:49 +00:00
public ThingTypeInfo Info { get { return info ; } } //mxd
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Setup
// Constructor
public BaseVisualThing ( BaseVisualMode mode , Thing t ) : base ( t )
{
this . mode = mode ;
2011-12-02 23:11:16 +00:00
// Find thing information
info = General . Map . Data . GetThingInfo ( Thing . Type ) ;
2015-03-26 21:31:46 +00:00
//mxd. When true, the thing can be moved below floor/above ceiling
nointeraction = ( info . Actor ! = null & & info . Actor . GetFlagValue ( "nointeraction" , false ) ) ;
2011-12-02 23:11:16 +00:00
// Find sprite texture
if ( info . Sprite . Length > 0 )
{
sprite = General . Map . Data . GetSpriteImage ( info . Sprite ) ;
if ( sprite ! = null ) sprite . AddReference ( ) ;
}
2013-03-18 13:52:27 +00:00
//mxd
2014-12-03 23:15:26 +00:00
if ( mode . UseSelectionFromClassicMode & & t . Selected )
{
2013-03-18 13:52:27 +00:00
this . selected = true ;
mode . AddSelectedObject ( this ) ;
}
2009-04-19 18:07:22 +00:00
// We have no destructor
GC . SuppressFinalize ( this ) ;
}
// This builds the thing geometry. Returns false when nothing was created.
public virtual bool Setup ( )
{
2014-01-03 10:33:45 +00:00
int sectorcolor = new PixelColor ( 255 , 255 , 255 , 255 ) . ToInt ( ) ;
2009-04-19 18:07:22 +00:00
2013-03-18 13:52:27 +00:00
//mxd. Check thing size
float infoRadius , infoHeight ;
2014-12-03 23:15:26 +00:00
if ( ( info . Radius < 0.1f ) | | ( info . Height < 0.1f ) )
{
2013-03-18 13:52:27 +00:00
infoRadius = FIXED_RADIUS ;
infoHeight = FIXED_RADIUS ;
sizeless = true ;
2014-12-03 23:15:26 +00:00
}
else
{
2013-03-18 13:52:27 +00:00
infoRadius = info . Radius ;
infoHeight = info . Height ;
sizeless = false ;
}
2009-04-19 18:07:22 +00:00
2009-08-19 14:06:21 +00:00
// Find the sector in which the thing resides
Thing . DetermineSector ( mode . BlockMap ) ;
2009-04-19 18:07:22 +00:00
if ( sprite ! = null )
{
if ( Thing . Sector ! = null )
{
2012-11-27 21:12:20 +00:00
SectorData sd = mode . GetSectorData ( Thing . Sector ) ;
2015-04-01 12:51:26 +00:00
SectorLevel level = sd . GetLevelAboveOrAt ( new Vector3D ( Thing . Position . x , Thing . Position . y , Thing . Position . z + Thing . Sector . FloorHeight ) ) ;
2015-03-26 21:31:46 +00:00
if ( nointeraction & & level = = null & & sd . LightLevels . Count > 0 ) level = sd . LightLevels [ sd . LightLevels . Count - 1 ] ; //mxd. Use the light level of the highest surface when a thing is above highest sector level.
2012-11-27 21:12:20 +00:00
if ( level ! = null )
{
// Use sector brightness for color shading
PixelColor areabrightness = PixelColor . FromInt ( mode . CalculateBrightness ( level . brightnessbelow ) ) ;
PixelColor areacolor = PixelColor . Modulate ( level . colorbelow , areabrightness ) ;
2014-01-03 10:33:45 +00:00
sectorcolor = areacolor . WithAlpha ( 255 ) . ToInt ( ) ;
2012-11-27 21:12:20 +00:00
}
2009-04-19 18:07:22 +00:00
}
// Check if the texture is loaded
sprite . LoadImage ( ) ;
isloaded = sprite . IsImageLoaded ;
if ( isloaded )
{
float offsetx = 0.0f ;
float offsety = 0.0f ;
base . Texture = sprite ;
// Determine sprite size and offset
float radius = sprite . ScaledWidth * 0.5f ;
float height = sprite . ScaledHeight ;
if ( sprite is SpriteImage )
{
offsetx = ( sprite as SpriteImage ) . OffsetX - radius ;
offsety = ( sprite as SpriteImage ) . OffsetY - height ;
}
2010-07-31 21:17:49 +00:00
// Scale by thing type/actor scale
// We do this after the offset x/y determination above, because that is entirely in sprite pixels space
2010-08-02 08:08:52 +00:00
radius * = info . SpriteScale . Width ;
height * = info . SpriteScale . Height ;
offsetx * = info . SpriteScale . Width ;
offsety * = info . SpriteScale . Height ;
2010-07-31 21:17:49 +00:00
2009-04-19 18:07:22 +00:00
// Make vertices
WorldVertex [ ] verts = new WorldVertex [ 6 ] ;
2013-03-18 13:52:27 +00:00
2014-12-03 23:15:26 +00:00
if ( sizeless ) //mxd
{
2013-03-18 13:52:27 +00:00
float hh = height / 2 ;
2014-01-03 10:33:45 +00:00
verts [ 0 ] = new WorldVertex ( - radius + offsetx , 0.0f , offsety - hh , sectorcolor , 0.0f , 1.0f ) ;
verts [ 1 ] = new WorldVertex ( - radius + offsetx , 0.0f , hh + offsety , sectorcolor , 0.0f , 0.0f ) ;
verts [ 2 ] = new WorldVertex ( + radius + offsetx , 0.0f , hh + offsety , sectorcolor , 1.0f , 0.0f ) ;
2013-03-18 13:52:27 +00:00
verts [ 3 ] = verts [ 0 ] ;
verts [ 4 ] = verts [ 2 ] ;
2014-01-03 10:33:45 +00:00
verts [ 5 ] = new WorldVertex ( + radius + offsetx , 0.0f , offsety - hh , sectorcolor , 1.0f , 1.0f ) ;
2014-12-03 23:15:26 +00:00
}
else
{
2014-01-03 10:33:45 +00:00
verts [ 0 ] = new WorldVertex ( - radius + offsetx , 0.0f , offsety , sectorcolor , 0.0f , 1.0f ) ;
verts [ 1 ] = new WorldVertex ( - radius + offsetx , 0.0f , height + offsety , sectorcolor , 0.0f , 0.0f ) ;
verts [ 2 ] = new WorldVertex ( + radius + offsetx , 0.0f , height + offsety , sectorcolor , 1.0f , 0.0f ) ;
2013-03-18 13:52:27 +00:00
verts [ 3 ] = verts [ 0 ] ;
verts [ 4 ] = verts [ 2 ] ;
2014-01-03 10:33:45 +00:00
verts [ 5 ] = new WorldVertex ( + radius + offsetx , 0.0f , offsety , sectorcolor , 1.0f , 1.0f ) ;
2013-03-18 13:52:27 +00:00
}
2009-04-19 18:07:22 +00:00
SetVertices ( verts ) ;
}
else
{
base . Texture = General . Map . Data . Hourglass3D ;
// Determine sprite size
2013-03-18 13:52:27 +00:00
float radius = Math . Min ( infoRadius , infoHeight / 2f ) ;
float height = Math . Min ( infoRadius * 2f , infoHeight ) ;
2009-04-19 18:07:22 +00:00
// Make vertices
WorldVertex [ ] verts = new WorldVertex [ 6 ] ;
2014-01-03 10:33:45 +00:00
verts [ 0 ] = new WorldVertex ( - radius , 0.0f , 0.0f , sectorcolor , 0.0f , 1.0f ) ;
verts [ 1 ] = new WorldVertex ( - radius , 0.0f , height , sectorcolor , 0.0f , 0.0f ) ;
verts [ 2 ] = new WorldVertex ( + radius , 0.0f , height , sectorcolor , 1.0f , 0.0f ) ;
2009-04-19 18:07:22 +00:00
verts [ 3 ] = verts [ 0 ] ;
verts [ 4 ] = verts [ 2 ] ;
2014-01-03 10:33:45 +00:00
verts [ 5 ] = new WorldVertex ( + radius , 0.0f , 0.0f , sectorcolor , 1.0f , 1.0f ) ;
2009-04-19 18:07:22 +00:00
SetVertices ( verts ) ;
}
}
// Determine position
Vector3D pos = Thing . Position ;
2012-11-27 21:12:20 +00:00
if ( Thing . Type = = 9501 )
{
2014-12-03 23:15:26 +00:00
if ( Thing . Sector ! = null ) //mxd
{
2013-07-29 08:50:50 +00:00
// This is a special thing that needs special positioning
SectorData sd = mode . GetSectorData ( Thing . Sector ) ;
pos . z = sd . Ceiling . sector . CeilHeight + Thing . Position . z ;
}
2012-11-27 21:12:20 +00:00
}
else if ( Thing . Type = = 9500 )
{
2014-12-03 23:15:26 +00:00
if ( Thing . Sector ! = null ) //mxd
{
2013-07-29 08:50:50 +00:00
// This is a special thing that needs special positioning
SectorData sd = mode . GetSectorData ( Thing . Sector ) ;
pos . z = sd . Floor . sector . FloorHeight + Thing . Position . z ;
}
2012-11-27 21:12:20 +00:00
}
else if ( info . AbsoluteZ )
2009-04-19 18:07:22 +00:00
{
// Absolute Z position
pos . z = Thing . Position . z ;
}
else if ( info . Hangs )
{
// Hang from ceiling
2012-11-27 21:12:20 +00:00
if ( Thing . Sector ! = null )
{
SectorData sd = mode . GetSectorData ( Thing . Sector ) ;
2015-01-30 08:10:49 +00:00
float maxz = sd . Ceiling . plane . GetZ ( Thing . Position ) - info . Height ;
pos . z = maxz ;
2012-11-27 21:12:20 +00:00
2015-03-26 21:31:46 +00:00
if ( Thing . Position . z > 0 | | nointeraction ) pos . z - = Thing . Position . z ;
2012-11-27 21:12:20 +00:00
2015-01-30 07:58:09 +00:00
// Check if below floor
2015-03-26 21:31:46 +00:00
if ( ! nointeraction )
{
float minz = sd . Floor . plane . GetZ ( Thing . Position ) ;
if ( pos . z < minz ) pos . z = Math . Min ( minz , maxz ) ;
}
2009-04-19 18:07:22 +00:00
}
}
else
{
// Stand on floor
2012-11-27 21:12:20 +00:00
if ( Thing . Sector ! = null )
{
SectorData sd = mode . GetSectorData ( Thing . Sector ) ;
2015-01-30 08:10:49 +00:00
float minz = sd . Floor . plane . GetZ ( Thing . Position ) ;
pos . z = minz ;
2012-11-27 21:12:20 +00:00
2015-03-26 21:31:46 +00:00
if ( Thing . Position . z > 0 | | nointeraction ) pos . z + = Thing . Position . z ;
2012-11-27 21:12:20 +00:00
2015-01-30 07:58:09 +00:00
// Check if above ceiling
2015-03-26 21:31:46 +00:00
if ( ! nointeraction )
{
float maxz = sd . Ceiling . plane . GetZ ( Thing . Position ) - info . Height ;
if ( pos . z > maxz ) pos . z = Math . Max ( minz , maxz ) ;
}
2009-04-19 18:07:22 +00:00
}
}
// Apply settings
SetPosition ( pos ) ;
2013-03-18 13:52:27 +00:00
SetCageSize ( infoRadius , infoHeight ) ;
2009-04-19 18:07:22 +00:00
SetCageColor ( Thing . Color ) ;
// Keep info for object picking
2013-03-18 13:52:27 +00:00
cageradius2 = infoRadius * Angle2D . SQRT2 ;
2009-04-19 18:07:22 +00:00
cageradius2 = cageradius2 * cageradius2 ;
pos2d = pos ;
2013-03-18 13:52:27 +00:00
2014-12-03 23:15:26 +00:00
if ( sizeless ) //mxd
{
2013-03-18 13:52:27 +00:00
boxp1 = new Vector3D ( pos . x - infoRadius , pos . y - infoRadius , pos . z - infoRadius / 2 ) ;
boxp2 = new Vector3D ( pos . x + infoRadius , pos . y + infoRadius , pos . z + infoRadius / 2 ) ;
2014-12-03 23:15:26 +00:00
}
else
{
2013-03-18 13:52:27 +00:00
boxp1 = new Vector3D ( pos . x - infoRadius , pos . y - infoRadius , pos . z ) ;
boxp2 = new Vector3D ( pos . x + infoRadius , pos . y + infoRadius , pos . z + infoHeight ) ;
}
2009-04-19 18:07:22 +00:00
// Done
2009-05-01 20:31:17 +00:00
changed = false ;
2009-04-19 18:07:22 +00:00
return true ;
}
// Disposing
public override void Dispose ( )
{
if ( ! IsDisposed )
{
if ( sprite ! = null )
{
sprite . RemoveReference ( ) ;
sprite = null ;
}
}
base . Dispose ( ) ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
// This forces to rebuild the whole thing
public void Rebuild ( )
{
2012-06-01 19:53:14 +00:00
// Find thing information
info = General . Map . Data . GetThingInfo ( Thing . Type ) ;
2012-05-11 12:28:20 +00:00
2015-03-26 21:31:46 +00:00
//mxd. When true, the thing can be moved below floor/above ceiling
nointeraction = ( info . Actor ! = null & & info . Actor . GetFlagValue ( "nointeraction" , false ) ) ;
2012-06-01 19:53:14 +00:00
// Find sprite texture
if ( info . Sprite . Length > 0 )
{
sprite = General . Map . Data . GetSpriteImage ( info . Sprite ) ;
if ( sprite ! = null ) sprite . AddReference ( ) ;
}
// Setup visual thing
2009-04-19 18:07:22 +00:00
Setup ( ) ;
}
// This updates the thing when needed
public override void Update ( )
{
if ( ! isloaded )
{
// Rebuild sprite geometry when sprite is loaded
if ( sprite . IsImageLoaded )
{
Setup ( ) ;
}
}
// Let the base update
base . Update ( ) ;
}
// This performs a fast test in object picking
public override bool PickFastReject ( Vector3D from , Vector3D to , Vector3D dir )
{
float distance2 = Line2D . GetDistanceToLineSq ( from , to , pos2d , false ) ;
return ( distance2 < = cageradius2 ) ;
}
// This performs an accurate test for object picking
public override bool PickAccurate ( Vector3D from , Vector3D to , Vector3D dir , ref float u_ray )
{
Vector3D delta = to - from ;
float tfar = float . MaxValue ;
float tnear = float . MinValue ;
// Ray-Box intersection code
2009-07-11 10:28:58 +00:00
// See http://www.masm32.com/board/index.php?topic=9941.0
2009-04-19 18:07:22 +00:00
// Check X slab
if ( delta . x = = 0.0f )
{
if ( from . x > boxp2 . x | | from . x < boxp1 . x )
{
// Ray is parallel to the planes & outside slab
return false ;
}
}
else
{
float tmp = 1.0f / delta . x ;
float t1 = ( boxp1 . x - from . x ) * tmp ;
float t2 = ( boxp2 . x - from . x ) * tmp ;
if ( t1 > t2 ) General . Swap ( ref t1 , ref t2 ) ;
if ( t1 > tnear ) tnear = t1 ;
if ( t2 < tfar ) tfar = t2 ;
if ( tnear > tfar | | tfar < 0.0f )
{
// Ray missed box or box is behind ray
return false ;
}
}
// Check Y slab
if ( delta . y = = 0.0f )
{
if ( from . y > boxp2 . y | | from . y < boxp1 . y )
{
// Ray is parallel to the planes & outside slab
return false ;
}
}
else
{
float tmp = 1.0f / delta . y ;
float t1 = ( boxp1 . y - from . y ) * tmp ;
float t2 = ( boxp2 . y - from . y ) * tmp ;
if ( t1 > t2 ) General . Swap ( ref t1 , ref t2 ) ;
if ( t1 > tnear ) tnear = t1 ;
if ( t2 < tfar ) tfar = t2 ;
if ( tnear > tfar | | tfar < 0.0f )
{
// Ray missed box or box is behind ray
return false ;
}
}
// Check Z slab
if ( delta . z = = 0.0f )
{
if ( from . z > boxp2 . z | | from . z < boxp1 . z )
{
// Ray is parallel to the planes & outside slab
return false ;
}
}
else
{
float tmp = 1.0f / delta . z ;
float t1 = ( boxp1 . z - from . z ) * tmp ;
float t2 = ( boxp2 . z - from . z ) * tmp ;
if ( t1 > t2 ) General . Swap ( ref t1 , ref t2 ) ;
if ( t1 > tnear ) tnear = t1 ;
if ( t2 < tfar ) tfar = t2 ;
if ( tnear > tfar | | tfar < 0.0f )
{
// Ray missed box or box is behind ray
return false ;
}
}
// Set interpolation point
u_ray = ( tnear > 0.0f ) ? tnear : tfar ;
return true ;
}
2013-04-01 11:06:01 +00:00
//mxd
2014-12-03 23:15:26 +00:00
public virtual bool IsSelected ( )
{
2013-04-01 11:06:01 +00:00
return selected ;
}
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Events
// Unused
public virtual void OnSelectBegin ( ) { }
public virtual void OnEditBegin ( ) { }
public virtual void OnMouseMove ( MouseEventArgs e ) { }
public virtual void OnChangeTargetBrightness ( bool up ) { }
2013-04-26 12:32:51 +00:00
public virtual void OnChangeTextureOffset ( int horizontal , int vertical , bool doSurfaceAngleCorrection ) { }
2009-04-19 18:07:22 +00:00
public virtual void OnSelectTexture ( ) { }
public virtual void OnCopyTexture ( ) { }
public virtual void OnPasteTexture ( ) { }
public virtual void OnCopyTextureOffsets ( ) { }
public virtual void OnPasteTextureOffsets ( ) { }
public virtual void OnTextureAlign ( bool alignx , bool aligny ) { }
public virtual void OnToggleUpperUnpegged ( ) { }
public virtual void OnToggleLowerUnpegged ( ) { }
2012-07-12 22:34:12 +00:00
public virtual void OnProcess ( float deltatime ) { }
2009-04-19 18:07:22 +00:00
public virtual void OnTextureFloodfill ( ) { }
public virtual void OnInsert ( ) { }
2014-12-22 21:36:49 +00:00
public virtual void OnTextureFit ( FitTextureOptions options ) { } //mxd
2009-05-03 19:22:32 +00:00
public virtual void ApplyTexture ( string texture ) { }
public virtual void ApplyUpperUnpegged ( bool set ) { }
public virtual void ApplyLowerUnpegged ( bool set ) { }
2013-04-01 11:06:01 +00:00
public virtual void SelectNeighbours ( bool select , bool withSameTexture , bool withSameHeight ) { } //mxd
2009-04-19 18:07:22 +00:00
// Return texture name
public virtual string GetTextureName ( ) { return "" ; }
2009-05-01 20:31:17 +00:00
// Select or deselect
public virtual void OnSelectEnd ( )
{
2009-07-07 11:29:56 +00:00
if ( this . selected )
{
this . selected = false ;
mode . RemoveSelectedObject ( this ) ;
}
else
{
this . selected = true ;
mode . AddSelectedObject ( this ) ;
}
2009-05-01 20:31:17 +00:00
}
2012-07-05 13:48:08 +00:00
2013-09-11 09:47:53 +00:00
//mxd. Delete thing
2014-12-03 23:15:26 +00:00
public virtual void OnDelete ( )
{
2013-07-31 12:38:47 +00:00
mode . CreateUndo ( "Delete thing" ) ;
mode . SetActionResult ( "Deleted a thing." ) ;
this . Thing . Fields . BeforeFieldsChange ( ) ;
this . Thing . Dispose ( ) ;
2013-09-11 09:47:53 +00:00
this . Dispose ( ) ;
2013-07-31 12:38:47 +00:00
General . Map . IsChanged = true ;
General . Map . ThingsFilter . Update ( ) ;
2013-09-11 09:47:53 +00:00
}
2009-04-19 18:07:22 +00:00
// Copy properties
public virtual void OnCopyProperties ( )
{
BuilderPlug . Me . CopiedThingProps = new ThingProperties ( Thing ) ;
2009-05-02 14:59:05 +00:00
mode . SetActionResult ( "Copied thing properties." ) ;
2009-04-19 18:07:22 +00:00
}
// Paste properties
public virtual void OnPasteProperties ( )
{
if ( BuilderPlug . Me . CopiedThingProps ! = null )
{
2009-05-03 19:22:32 +00:00
mode . CreateUndo ( "Paste thing properties" ) ;
2009-05-02 14:59:05 +00:00
mode . SetActionResult ( "Pasted thing properties." ) ;
2009-04-19 18:07:22 +00:00
BuilderPlug . Me . CopiedThingProps . Apply ( Thing ) ;
Thing . UpdateConfiguration ( ) ;
this . Rebuild ( ) ;
mode . ShowTargetInfo ( ) ;
}
}
// Edit button released
public virtual void OnEditEnd ( )
{
2010-08-14 18:07:38 +00:00
if ( General . Interface . IsActiveWindow )
2009-04-19 18:07:22 +00:00
{
2013-07-19 15:30:58 +00:00
2010-08-14 18:07:38 +00:00
List < Thing > things = mode . GetSelectedThings ( ) ;
2013-07-19 15:30:58 +00:00
//mxd
updateList = new List < BaseVisualThing > ( ) ;
2014-12-03 23:15:26 +00:00
foreach ( Thing t in things )
{
2013-07-19 15:30:58 +00:00
VisualThing vt = mode . GetVisualThing ( t ) ;
2014-12-03 23:15:26 +00:00
if ( vt ! = null ) updateList . Add ( vt as BaseVisualThing ) ;
2009-04-19 18:07:22 +00:00
}
2013-07-19 15:30:58 +00:00
2014-02-21 14:42:12 +00:00
General . Interface . OnEditFormValuesChanged + = Interface_OnEditFormValuesChanged ;
2013-07-19 15:30:58 +00:00
mode . StartRealtimeInterfaceUpdate ( SelectionType . Things ) ;
General . Interface . ShowEditThings ( things ) ;
mode . StopRealtimeInterfaceUpdate ( SelectionType . Things ) ;
General . Interface . OnEditFormValuesChanged - = Interface_OnEditFormValuesChanged ;
updateList . Clear ( ) ;
updateList = null ;
2009-04-19 18:07:22 +00:00
}
}
2013-07-19 15:30:58 +00:00
//mxd
2014-12-03 23:15:26 +00:00
private void Interface_OnEditFormValuesChanged ( object sender , EventArgs e )
{
foreach ( BaseVisualThing vt in updateList ) vt . Changed = true ;
2013-07-19 15:30:58 +00:00
}
Added, Visual mode, UDMF: added "Change Pitch Clockwise", "Change Pitch Counterclockwise", "Change Roll Clockwise" and "Change Roll Counterclockwise" actions.
Added, Visual mode, UDMF: added "Increase Scale" and "Decrease Scale" actions.
Added, Visual mode, UDMF: "Reset Texture Offsets" action now resets scale when used on things.
Added, Visual mode, UDMF: "Reset Local Texture Offsets" action now resets scale, pitch and roll when used on things.
Changed, Visual mode, UDMF: "Reset Texture Offsets" action now only resets texture offsets (previously it also reset texture scale).
Changed, Visual mode, UDMF: "Reset Local Texture Offsets" action now resets texture offsets, scale and brightness of sidedefs and also rotation of floors/ceilings.
Changed, Visual mode, UDMF: thing box arrow now displays pitch and roll for things, which have attached model and appropriate MODELDEF flags.
Changed, Thing Edit Form, UDMF: negative pitch and roll can now be entered.
Updated documentation.
2015-03-30 21:44:04 +00:00
//mxd
public virtual void OnResetTextureOffset ( )
{
mode . CreateUndo ( "Reset thing scale" ) ;
mode . SetActionResult ( "Thing scale reset." ) ;
Thing . SetScale ( 1.0f , 1.0f ) ;
// Update what must be updated
this . Changed = true ;
}
//mxd
public virtual void OnResetLocalTextureOffset ( )
{
mode . CreateUndo ( "Reset thing scale, pitch and roll" ) ;
mode . SetActionResult ( "Thing scale, pitch and roll reset." ) ;
Thing . SetScale ( 1.0f , 1.0f ) ;
Thing . SetPitch ( 0 ) ;
Thing . SetRoll ( 0 ) ;
// Update what must be updated
this . Changed = true ;
}
2009-04-19 18:07:22 +00:00
// Raise/lower thing
public virtual void OnChangeTargetHeight ( int amount )
{
if ( General . Map . FormatInterface . HasThingHeight )
{
if ( ( General . Map . UndoRedo . NextUndo = = null ) | | ( General . Map . UndoRedo . NextUndo . TicketID ! = undoticket ) )
2009-05-03 19:22:32 +00:00
undoticket = mode . CreateUndo ( "Change thing height" ) ;
2009-04-19 18:07:22 +00:00
2014-12-22 21:36:49 +00:00
Thing . Move ( Thing . Position + new Vector3D ( 0.0f , 0.0f , ( info . Hangs ? - amount : amount ) ) ) ;
2009-04-19 18:07:22 +00:00
2009-05-02 14:59:05 +00:00
mode . SetActionResult ( "Changed thing height to " + Thing . Position . z + "." ) ;
2012-11-27 21:12:20 +00:00
// Update what must be updated
ThingData td = mode . GetThingData ( this . Thing ) ;
foreach ( KeyValuePair < Sector , bool > s in td . UpdateAlso )
{
if ( mode . VisualSectorExists ( s . Key ) )
{
BaseVisualSector vs = ( BaseVisualSector ) mode . GetVisualSector ( s . Key ) ;
vs . UpdateSectorGeometry ( s . Value ) ;
}
}
2009-05-01 20:31:17 +00:00
this . Changed = true ;
2009-04-19 18:07:22 +00:00
}
}
2012-06-29 14:03:35 +00:00
2015-01-27 14:29:23 +00:00
//mxd
2015-03-03 09:42:54 +00:00
public virtual void OnChangeScale ( int incrementX , int incrementY )
2015-01-27 14:29:23 +00:00
{
2015-03-03 09:42:54 +00:00
if ( ! General . Map . UDMF | | ! sprite . IsImageLoaded ) return ;
2015-01-27 14:29:23 +00:00
if ( ( General . Map . UndoRedo . NextUndo = = null ) | | ( General . Map . UndoRedo . NextUndo . TicketID ! = undoticket ) )
undoticket = mode . CreateUndo ( "Change thing scale" ) ;
2015-03-03 09:42:54 +00:00
float scaleX = Thing . ScaleX ;
float scaleY = Thing . ScaleY ;
2015-01-27 14:29:23 +00:00
if ( incrementX ! = 0 )
{
2015-03-03 09:42:54 +00:00
float pix = ( int ) Math . Round ( sprite . Width * scaleX ) + incrementX ;
float newscaleX = ( float ) Math . Round ( pix / sprite . Width , 3 ) ;
scaleX = ( newscaleX = = 0 ? scaleX * - 1 : newscaleX ) ;
2015-01-27 14:29:23 +00:00
}
if ( incrementY ! = 0 )
{
2015-03-03 09:42:54 +00:00
float pix = ( int ) Math . Round ( sprite . Height * scaleY ) + incrementY ;
float newscaleY = ( float ) Math . Round ( pix / sprite . Height , 3 ) ;
scaleY = ( newscaleY = = 0 ? scaleY * - 1 : newscaleY ) ;
2015-01-27 14:29:23 +00:00
}
2015-03-03 09:42:54 +00:00
Thing . SetScale ( scaleX , scaleY ) ;
mode . SetActionResult ( "Changed thing scale to " + scaleX . ToString ( "F03" , CultureInfo . InvariantCulture ) + ", " + scaleY . ToString ( "F03" , CultureInfo . InvariantCulture ) + " (" + ( int ) Math . Round ( sprite . Width * scaleX ) + " x " + ( int ) Math . Round ( sprite . Height * scaleY ) + ")." ) ;
2015-01-27 14:29:23 +00:00
// Update what must be updated
this . Changed = true ;
}
2013-09-11 09:47:53 +00:00
//mxd
2014-12-03 23:15:26 +00:00
public void OnMove ( Vector3D newPosition )
{
2013-09-11 09:47:53 +00:00
if ( ( General . Map . UndoRedo . NextUndo = = null ) | | ( General . Map . UndoRedo . NextUndo . TicketID ! = undoticket ) )
undoticket = mode . CreateUndo ( "Move thing" ) ;
Thing . Move ( newPosition ) ;
2014-02-21 14:42:12 +00:00
mode . SetActionResult ( "Changed thing position to " + Thing . Position + "." ) ;
2013-09-11 09:47:53 +00:00
// Update what must be updated
ThingData td = mode . GetThingData ( this . Thing ) ;
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < Sector , bool > s in td . UpdateAlso )
{
if ( mode . VisualSectorExists ( s . Key ) )
{
2013-09-11 09:47:53 +00:00
BaseVisualSector vs = ( BaseVisualSector ) mode . GetVisualSector ( s . Key ) ;
vs . UpdateSectorGeometry ( s . Value ) ;
}
}
this . Changed = true ;
}
//mxd
Added, Visual mode, UDMF: added "Change Pitch Clockwise", "Change Pitch Counterclockwise", "Change Roll Clockwise" and "Change Roll Counterclockwise" actions.
Added, Visual mode, UDMF: added "Increase Scale" and "Decrease Scale" actions.
Added, Visual mode, UDMF: "Reset Texture Offsets" action now resets scale when used on things.
Added, Visual mode, UDMF: "Reset Local Texture Offsets" action now resets scale, pitch and roll when used on things.
Changed, Visual mode, UDMF: "Reset Texture Offsets" action now only resets texture offsets (previously it also reset texture scale).
Changed, Visual mode, UDMF: "Reset Local Texture Offsets" action now resets texture offsets, scale and brightness of sidedefs and also rotation of floors/ceilings.
Changed, Visual mode, UDMF: thing box arrow now displays pitch and roll for things, which have attached model and appropriate MODELDEF flags.
Changed, Thing Edit Form, UDMF: negative pitch and roll can now be entered.
Updated documentation.
2015-03-30 21:44:04 +00:00
public void SetAngle ( int newangle )
2014-12-03 23:15:26 +00:00
{
2013-09-11 09:47:53 +00:00
if ( ( General . Map . UndoRedo . NextUndo = = null ) | | ( General . Map . UndoRedo . NextUndo . TicketID ! = undoticket ) )
Added, Visual mode, UDMF: added "Change Pitch Clockwise", "Change Pitch Counterclockwise", "Change Roll Clockwise" and "Change Roll Counterclockwise" actions.
Added, Visual mode, UDMF: added "Increase Scale" and "Decrease Scale" actions.
Added, Visual mode, UDMF: "Reset Texture Offsets" action now resets scale when used on things.
Added, Visual mode, UDMF: "Reset Local Texture Offsets" action now resets scale, pitch and roll when used on things.
Changed, Visual mode, UDMF: "Reset Texture Offsets" action now only resets texture offsets (previously it also reset texture scale).
Changed, Visual mode, UDMF: "Reset Local Texture Offsets" action now resets texture offsets, scale and brightness of sidedefs and also rotation of floors/ceilings.
Changed, Visual mode, UDMF: thing box arrow now displays pitch and roll for things, which have attached model and appropriate MODELDEF flags.
Changed, Thing Edit Form, UDMF: negative pitch and roll can now be entered.
Updated documentation.
2015-03-30 21:44:04 +00:00
undoticket = mode . CreateUndo ( "Change thing angle" ) ;
Thing . Rotate ( newangle ) ;
mode . SetActionResult ( "Changed thing angle to " + Thing . AngleDoom + "." ) ;
this . Changed = true ;
}
//mxd
public void SetPitch ( int newpitch )
{
if ( ! General . Map . UDMF ) return ;
if ( ( General . Map . UndoRedo . NextUndo = = null ) | | ( General . Map . UndoRedo . NextUndo . TicketID ! = undoticket ) )
undoticket = mode . CreateUndo ( "Change thing pitch" ) ;
Thing . SetPitch ( newpitch ) ;
mode . SetActionResult ( "Changed thing pitch to " + Thing . Pitch + "." ) ;
this . Changed = true ;
}
//mxd
public void SetRoll ( int newroll )
{
if ( ! General . Map . UDMF ) return ;
if ( ( General . Map . UndoRedo . NextUndo = = null ) | | ( General . Map . UndoRedo . NextUndo . TicketID ! = undoticket ) )
undoticket = mode . CreateUndo ( "Change thing roll" ) ;
Thing . SetRoll ( newroll ) ;
mode . SetActionResult ( "Changed thing roll to " + Thing . Roll + "." ) ;
2013-09-11 09:47:53 +00:00
this . Changed = true ;
}
2009-04-19 18:07:22 +00:00
#endregion
}
}