2015-01-23 12:36:43 +00:00
#region = = = = = = = = = = = = = = = = = = Copyright ( c ) 2007 Pascal vd Heiden , 2014 Boris Iwanski
/ *
* Copyright ( c ) 2007 Pascal vd Heiden , www . codeimp . com
* Copyright ( c ) 2014 Boris Iwanski
* 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 ;
2023-08-13 19:19:25 +00:00
using System.ComponentModel ;
2020-10-31 15:09:22 +00:00
using System.Drawing ;
2023-08-13 19:19:25 +00:00
using System.Threading.Tasks ;
2015-01-23 12:36:43 +00:00
using System.Windows.Forms ;
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Rendering ;
using CodeImp.DoomBuilder.Editing ;
using CodeImp.DoomBuilder.Actions ;
2023-08-13 19:19:25 +00:00
using CodeImp.DoomBuilder.Geometry ;
using CodeImp.DoomBuilder.Windows ;
using System.Diagnostics ;
2015-01-23 12:36:43 +00:00
#endregion
namespace CodeImp.DoomBuilder.SoundPropagationMode
{
[ EditMode ( DisplayName = "Sound Propagation Mode" ,
SwitchAction = "soundpropagationmode" , // Action name used to switch to this mode
ButtonImage = "SoundPropagationIcon.png" , // Image resource name for the button
ButtonOrder = int . MinValue + 501 , // Position of the button (lower is more to the left)
ButtonGroup = "000_editing" ,
UseByDefault = true ,
SafeStartMode = false ,
Volatile = false ) ]
public class SoundPropagationMode : ClassicMode
{
#region = = = = = = = = = = = = = = = = = = Variables
// Highlighted item
private Sector highlighted ;
private Linedef highlightedline ; //mxd
private FlatVertex [ ] overlayGeometry ;
private List < Thing > huntingThings ;
private List < SoundPropagationDomain > propagationdomains ;
private Dictionary < Sector , SoundPropagationDomain > sector2domain ;
2023-08-13 19:19:25 +00:00
private LeakFinder leakfinder ;
private PixelColor doublesidedcolor ;
2015-01-23 12:36:43 +00:00
2020-10-31 15:09:22 +00:00
// The blockmap makes is used to make finding lines faster
2023-08-13 19:19:25 +00:00
private BlockMap < BlockEntry > blockmap ;
private Sector leakstartsector ;
private Sector leakendsector ;
private Vector2D leakstartposition ;
private Vector2D leakendposition ;
private TextLabel leakstartlabel ;
private TextLabel leakendlabel ;
private BackgroundWorker worker ;
2020-10-31 15:09:22 +00:00
2015-01-23 12:36:43 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
public override object HighlightedObject { get { return highlighted ; } }
2015-06-30 18:34:08 +00:00
internal static string BlockSoundFlag { get { return ( General . Map . UDMF ? "blocksound" : "64" ) ; } } //mxd
2015-01-23 12:36:43 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// Disposer
public override void Dispose ( )
{
// Not already disposed?
if ( ! isdisposed )
{
// Dispose base
base . Dispose ( ) ;
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
private void UpdateData ( )
{
BuilderPlug . Me . DataIsDirty = false ;
List < FlatVertex > vertsList = new List < FlatVertex > ( ) ;
2016-07-02 22:27:20 +00:00
// Go for all sectors
2015-12-28 15:01:53 +00:00
foreach ( Sector s in General . Map . Map . Sectors ) vertsList . AddRange ( s . FlatVertices ) ;
2015-01-23 12:36:43 +00:00
overlayGeometry = vertsList . ToArray ( ) ;
2015-12-28 15:01:53 +00:00
for ( int i = 0 ; i < overlayGeometry . Length ; i + + )
2015-01-23 12:36:43 +00:00
overlayGeometry [ i ] . c = BuilderPlug . Me . NoSoundColor . WithAlpha ( 128 ) . ToInt ( ) ;
}
// This highlights a new item
private void Highlight ( Sector s )
{
// Set new highlight
highlighted = s ;
UpdateSoundPropagation ( ) ;
}
//mxd
private void ResetSoundPropagation ( )
{
sector2domain . Clear ( ) ;
propagationdomains . Clear ( ) ;
BuilderPlug . Me . BlockingLinedefs . Clear ( ) ;
UpdateSoundPropagation ( ) ;
}
private void UpdateSoundPropagation ( )
{
huntingThings . Clear ( ) ;
2015-05-04 07:19:26 +00:00
BuilderPlug . Me . BlockingLinedefs . Clear ( ) ;
2015-12-28 15:01:53 +00:00
foreach ( Linedef ld in General . Map . Map . Linedefs )
2015-01-23 12:36:43 +00:00
{
2016-07-02 22:27:20 +00:00
if ( ld . IsFlagSet ( BlockSoundFlag ) ) BuilderPlug . Me . BlockingLinedefs . Add ( ld ) ;
2015-01-23 12:36:43 +00:00
}
2016-07-02 22:27:20 +00:00
//mxd. Create sound propagation for the whole map
int counter = 0 ;
foreach ( Sector sector in General . Map . Map . Sectors )
2015-01-23 12:36:43 +00:00
{
2016-07-02 22:27:20 +00:00
if ( ! sector2domain . ContainsKey ( sector ) )
2015-01-23 12:36:43 +00:00
{
2016-07-02 22:27:20 +00:00
SoundPropagationDomain spd = new SoundPropagationDomain ( sector ) ;
foreach ( Sector s in spd . Sectors ) sector2domain [ s ] = spd ;
spd . Color = BuilderPlug . Me . DistinctColors [ counter + + % BuilderPlug . Me . DistinctColors . Count ] . WithAlpha ( 255 ) . ToInt ( ) ;
propagationdomains . Add ( spd ) ;
2015-01-23 12:36:43 +00:00
}
}
2016-07-02 22:27:20 +00:00
if ( highlighted = = null | | highlighted . IsDisposed ) return ;
2015-05-04 07:19:26 +00:00
//mxd. Create the list of sectors, which will be affected by noise made in highlighted sector
2015-01-23 12:36:43 +00:00
SoundPropagationDomain curdomain = sector2domain [ highlighted ] ;
Dictionary < int , Sector > noisysectors = new Dictionary < int , Sector > ( curdomain . Sectors . Count ) ;
foreach ( Sector s in curdomain . Sectors )
{
noisysectors . Add ( s . Index , s ) ;
}
2015-12-28 15:01:53 +00:00
foreach ( Sector s in curdomain . AdjacentSectors )
2015-01-23 12:36:43 +00:00
{
SoundPropagationDomain aspd = sector2domain [ s ] ;
2015-12-28 15:01:53 +00:00
foreach ( Sector adjs in aspd . Sectors )
2015-01-23 12:36:43 +00:00
{
if ( ! noisysectors . ContainsKey ( adjs . Index ) ) noisysectors . Add ( adjs . Index , adjs ) ;
}
}
// Update the list of things that will actually go for the player when hearing a noise
2015-12-28 15:01:53 +00:00
foreach ( Thing thing in General . Map . Map . Things )
2015-01-23 12:36:43 +00:00
{
if ( ! General . Map . ThingsFilter . VisibleThings . Contains ( thing ) ) continue ;
if ( thing . IsFlagSet ( General . Map . UDMF ? "ambush" : "8" ) ) continue ;
if ( thing . Sector ! = null & & noisysectors . ContainsKey ( thing . Sector . Index ) ) huntingThings . Add ( thing ) ;
}
}
2020-10-31 15:09:22 +00:00
/// <summary>
/// Create a blockmap containing linedefs. This is used to speed up determining the closest line
/// to the mouse cursor
/// </summary>
private void CreateBlockmap ( )
{
RectangleF area = MapSet . CreateArea ( General . Map . Map . Vertices ) ;
2023-10-25 18:38:52 +00:00
area = MapSet . IncreaseArea ( area , General . Map . Map . Things ) ;
2020-10-31 15:09:22 +00:00
blockmap = new BlockMap < BlockEntry > ( area ) ;
blockmap . AddLinedefsSet ( General . Map . Map . Linedefs ) ;
2023-08-13 19:19:25 +00:00
blockmap . AddSectorsSet ( General . Map . Map . Sectors ) ;
2020-10-31 15:09:22 +00:00
}
2015-01-23 12:36:43 +00:00
#endregion
2020-10-31 15:09:22 +00:00
2015-01-23 12:36:43 +00:00
#region = = = = = = = = = = = = = = = = = = Events
public override void OnHelp ( )
{
2015-06-01 21:46:28 +00:00
General . ShowHelp ( "gzdb/features/classic_modes/mode_soundpropagation.html" ) ;
2015-01-23 12:36:43 +00:00
}
// Cancel mode
public override void OnCancel ( )
{
// Cancel base class
base . OnCancel ( ) ;
// Return to previous mode
General . Editing . ChangeMode ( new SoundPropagationMode ( ) ) ;
}
// Mode engages
public override void OnEngage ( )
{
base . OnEngage ( ) ;
huntingThings = new List < Thing > ( ) ;
propagationdomains = new List < SoundPropagationDomain > ( ) ;
sector2domain = new Dictionary < Sector , SoundPropagationDomain > ( ) ;
BuilderPlug . Me . BlockingLinedefs = new List < Linedef > ( ) ;
2023-08-13 19:19:25 +00:00
doublesidedcolor = General . Colors . Linedefs . WithAlpha ( General . Settings . DoubleSidedAlphaByte ) ;
2015-01-23 12:36:43 +00:00
UpdateData ( ) ;
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . ColorConfiguration ) ;
CustomPresentation presentation = new CustomPresentation ( ) ;
presentation . AddLayer ( new PresentLayer ( RendererLayer . Background , BlendingMode . Mask , General . Settings . BackgroundAlpha ) ) ;
presentation . AddLayer ( new PresentLayer ( RendererLayer . Grid , BlendingMode . Mask ) ) ;
2023-08-13 19:19:25 +00:00
presentation . AddLayer ( new PresentLayer ( RendererLayer . Overlay , BlendingMode . Alpha , 1.0f , true ) ) ; // First overlay (0)
2015-01-23 12:36:43 +00:00
presentation . AddLayer ( new PresentLayer ( RendererLayer . Things , BlendingMode . Alpha , 1.0f ) ) ;
presentation . AddLayer ( new PresentLayer ( RendererLayer . Geometry , BlendingMode . Alpha , 1.0f , true ) ) ;
2023-08-13 19:19:25 +00:00
presentation . AddLayer ( new PresentLayer ( RendererLayer . Overlay , BlendingMode . Alpha , 1.0f , true ) ) ; // Second overlay (1)
2015-01-23 12:36:43 +00:00
renderer . SetPresentation ( presentation ) ;
2023-08-13 19:19:25 +00:00
leakstartlabel = new TextLabel
{
TransformCoords = true ,
AlignX = TextAlignmentX . Center ,
AlignY = TextAlignmentY . Middle ,
Color = General . Colors . Selection ,
BackColor = General . Colors . Background ,
Text = "S"
} ;
leakendlabel = new TextLabel
{
TransformCoords = true ,
AlignX = TextAlignmentX . Center ,
AlignY = TextAlignmentY . Middle ,
Color = General . Colors . Selection ,
BackColor = General . Colors . Background ,
Text = "E"
} ;
2020-10-31 15:09:22 +00:00
// Create the blockmap
CreateBlockmap ( ) ;
2023-08-13 19:19:25 +00:00
// To show things that will wake up we need to know the sector they are in
Parallel . ForEach ( General . Map . Map . Things , t = > t . DetermineSector ( blockmap ) ) ;
2015-01-23 12:36:43 +00:00
// Convert geometry selection to sectors only
General . Map . Map . ConvertSelection ( SelectionType . Sectors ) ;
2015-05-04 07:19:26 +00:00
UpdateSoundPropagation ( ) ;
2015-01-23 12:36:43 +00:00
}
// Mode disengages
public override void OnDisengage ( )
{
base . OnDisengage ( ) ;
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . ColorConfiguration ) ;
// Hide highlight info
General . Interface . HideInfo ( ) ;
2023-08-13 19:19:25 +00:00
if ( worker ! = null )
{
worker . CancelAsync ( ) ;
worker . Dispose ( ) ;
}
2015-01-23 12:36:43 +00:00
}
// This redraws the display
public override void OnRedrawDisplay ( )
{
List < SoundPropagationDomain > renderedspds = new List < SoundPropagationDomain > ( ) ;
2023-08-13 19:19:25 +00:00
if ( BuilderPlug . Me . DataIsDirty ) UpdateData ( ) ;
2015-01-23 12:36:43 +00:00
2023-08-13 19:19:25 +00:00
// We don't care for the actualy surfaces, but without this the render targets will not be recreated
// when the window is resized
2019-12-30 10:28:08 +00:00
renderer . RedrawSurface ( ) ;
2015-01-23 12:36:43 +00:00
// Render lines and vertices
2019-12-30 10:28:08 +00:00
if ( renderer . StartPlotter ( true ) )
2015-01-23 12:36:43 +00:00
{
// Plot lines by hand, so that no coloring (line specials, 3D floors etc.) distracts from
// the sound propagation. Also don't draw the line's normal. They are not needed here anyway
// and can make it harder to see the sound environment propagation
2023-08-13 19:19:25 +00:00
if ( General . Settings . ParallelizedLinedefPlotting )
{
Parallel . ForEach ( General . Map . Map . Linedefs , ld = >
{
PixelColor c = ld . IsFlagSet ( General . Map . Config . ImpassableFlag ) ? General . Colors . Linedefs : doublesidedcolor ;
renderer . PlotLine ( ld . Start . Position , ld . End . Position , c , BuilderPlug . LINE_LENGTH_SCALER ) ;
} ) ;
}
else
2015-01-23 12:36:43 +00:00
{
2023-08-13 19:19:25 +00:00
foreach ( Linedef ld in General . Map . Map . Linedefs )
{
PixelColor c = ld . IsFlagSet ( General . Map . Config . ImpassableFlag ) ? General . Colors . Linedefs : doublesidedcolor ;
renderer . PlotLine ( ld . Start . Position , ld . End . Position , c , BuilderPlug . LINE_LENGTH_SCALER ) ;
}
2015-01-23 12:36:43 +00:00
}
// Since there will usually be way less blocking linedefs than total linedefs, it's presumably
// faster to draw them on their own instead of checking if each linedef is in BlockingLinedefs
2023-08-13 19:19:25 +00:00
foreach ( Linedef ld in BuilderPlug . Me . BlockingLinedefs )
2016-07-02 22:27:20 +00:00
renderer . PlotLine ( ld . Start . Position , ld . End . Position , BuilderPlug . Me . BlockSoundColor , BuilderPlug . LINE_LENGTH_SCALER ) ;
2015-01-23 12:36:43 +00:00
//mxd. Render highlighted line
2023-08-13 19:19:25 +00:00
if ( highlightedline ! = null )
2016-07-02 22:27:20 +00:00
renderer . PlotLine ( highlightedline . Start . Position , highlightedline . End . Position , General . Colors . Highlight , BuilderPlug . LINE_LENGTH_SCALER ) ;
2015-01-23 12:36:43 +00:00
renderer . Finish ( ) ;
}
// Render things
2023-08-13 19:19:25 +00:00
if ( renderer . StartThings ( true ) )
2015-01-23 12:36:43 +00:00
{
2016-03-30 11:29:39 +00:00
renderer . RenderThingSet ( General . Map . ThingsFilter . HiddenThings , General . Settings . HiddenThingsAlpha ) ;
renderer . RenderThingSet ( General . Map . ThingsFilter . VisibleThings , General . Settings . InactiveThingsAlpha ) ;
2023-08-13 19:19:25 +00:00
renderer . RenderThingSet ( huntingThings , General . Colors . Selection , General . Settings . ActiveThingsAlpha ) ;
2015-01-23 12:36:43 +00:00
renderer . Finish ( ) ;
}
2023-08-13 19:19:25 +00:00
// The sound propagation domain overlay
if ( renderer . StartOverlay ( true ) )
2015-01-23 12:36:43 +00:00
{
2016-07-02 22:27:20 +00:00
// Render highlighted domain and domains adjacent to it
2023-08-13 19:19:25 +00:00
if ( highlighted ! = null & & ! highlighted . IsDisposed )
2015-01-23 12:36:43 +00:00
{
2016-07-02 22:27:20 +00:00
renderer . RenderGeometry ( overlayGeometry , null , true ) ; //mxd
2023-08-13 19:19:25 +00:00
2015-01-23 12:36:43 +00:00
SoundPropagationDomain spd = sector2domain [ highlighted ] ;
2016-05-12 22:35:11 +00:00
renderer . RenderGeometry ( spd . Level1Geometry , null , true ) ;
2015-01-23 12:36:43 +00:00
2023-08-13 19:19:25 +00:00
foreach ( Sector s in spd . AdjacentSectors )
2015-01-23 12:36:43 +00:00
{
SoundPropagationDomain aspd = sector2domain [ s ] ;
2023-08-13 19:19:25 +00:00
if ( ! renderedspds . Contains ( aspd ) )
2015-01-23 12:36:43 +00:00
{
2016-05-12 22:35:11 +00:00
renderer . RenderGeometry ( aspd . Level2Geometry , null , true ) ;
2015-01-23 12:36:43 +00:00
renderedspds . Add ( aspd ) ;
}
}
2016-07-02 22:27:20 +00:00
renderer . RenderHighlight ( highlighted . FlatVertices , BuilderPlug . Me . HighlightColor . WithAlpha ( 128 ) . ToInt ( ) ) ; //mxd
}
else
{
//mxd. Render all domains using domain colors
2023-08-13 19:19:25 +00:00
foreach ( SoundPropagationDomain spd in propagationdomains )
2016-07-02 22:27:20 +00:00
renderer . RenderHighlight ( spd . Level1Geometry , spd . Color ) ;
2015-01-23 12:36:43 +00:00
}
renderer . Finish ( ) ;
}
2023-08-13 19:19:25 +00:00
// The sound leak overlay. This is done so that the path and labels are drawn at the very top
if ( renderer . StartOverlay ( true , 1 ) )
{
if ( leakfinder ! = null & & leakfinder . Finished )
leakfinder . End . RenderPath ( renderer ) ;
if ( leakstartsector ! = null )
renderer . RenderText ( leakstartlabel ) ;
if ( leakendsector ! = null )
renderer . RenderText ( leakendlabel ) ;
renderer . Finish ( ) ;
}
2015-01-23 12:36:43 +00:00
renderer . Present ( ) ;
}
//mxd. If a linedef is highlighted, toggle the sound blocking flag
protected override void OnSelectEnd ( )
{
if ( highlightedline = = null ) return ;
// Make undo
General . Map . UndoRedo . CreateUndo ( "Toggle Linedef Sound Blocking" ) ;
// Toggle flag
2015-06-30 18:34:08 +00:00
highlightedline . SetFlag ( BlockSoundFlag , ! highlightedline . IsFlagSet ( BlockSoundFlag ) ) ;
2015-01-23 12:36:43 +00:00
// Update
ResetSoundPropagation ( ) ;
2023-08-13 19:19:25 +00:00
FindSoundLeak ( ) ;
2015-01-23 12:36:43 +00:00
General . Interface . RedrawDisplay ( ) ;
}
2023-08-13 19:19:25 +00:00
public override bool OnUndoBegin ( )
{
base . OnUndoBegin ( ) ;
if ( worker ! = null )
{
worker . CancelAsync ( ) ;
worker . Dispose ( ) ;
worker = null ;
}
return true ;
}
2016-05-12 22:35:11 +00:00
//mxd
public override void OnUndoEnd ( )
{
base . OnUndoEnd ( ) ;
2020-10-31 15:09:22 +00:00
// Recreate the blockmap
CreateBlockmap ( ) ;
2023-08-13 19:19:25 +00:00
// To show things that will wake up we need to know the sector they are in
Parallel . ForEach ( General . Map . Map . Things , t = > t . DetermineSector ( blockmap ) ) ;
2023-12-02 14:20:50 +00:00
// Recreate the overlay geometry
UpdateData ( ) ;
2016-05-12 22:35:11 +00:00
// Update
ResetSoundPropagation ( ) ;
General . Interface . RedrawDisplay ( ) ;
}
2023-08-13 19:19:25 +00:00
public override bool OnRedoBegin ( )
{
base . OnRedoBegin ( ) ;
if ( worker ! = null )
{
worker . CancelAsync ( ) ;
worker . Dispose ( ) ;
worker = null ;
}
return true ;
}
2016-05-12 22:35:11 +00:00
//mxd
public override void OnRedoEnd ( )
{
base . OnRedoEnd ( ) ;
2020-10-31 15:09:22 +00:00
// Recreate the blockmap
CreateBlockmap ( ) ;
2023-08-13 19:19:25 +00:00
// To show things that will wake up we need to know the sector they are in
Parallel . ForEach ( General . Map . Map . Things , t = > t . DetermineSector ( blockmap ) ) ;
2023-12-02 14:20:50 +00:00
// Recreate the overlay geometry
UpdateData ( ) ;
2016-05-12 22:35:11 +00:00
// Update
ResetSoundPropagation ( ) ;
General . Interface . RedrawDisplay ( ) ;
}
2015-01-23 12:36:43 +00:00
// Mouse moves
public override void OnMouseMove ( MouseEventArgs e )
{
base . OnMouseMove ( e ) ;
// Not holding any buttons?
2015-12-28 15:01:53 +00:00
if ( e . Button = = MouseButtons . None )
2015-01-23 12:36:43 +00:00
{
General . Interface . SetCursor ( Cursors . Default ) ;
2016-07-02 22:27:20 +00:00
//mxd. Find the nearest linedef within default highlight range
2020-10-31 15:09:22 +00:00
Linedef nl = MapSet . NearestLinedefRange ( blockmap , mousemappos , 20 / renderer . Scale ) ;
2016-07-02 22:27:20 +00:00
//mxd. We are not interested in single-sided lines (unless they have "blocksound" flag set)...
if ( nl ! = null & & ( nl . Front = = null | | nl . Back = = null ) & & ! nl . IsFlagSet ( BlockSoundFlag ) ) nl = null ;
//mxd. Set as highlighted
bool redrawrequired = ( highlightedline ! = nl ) ;
highlightedline = nl ;
2015-01-23 12:36:43 +00:00
// Find the nearest linedef within highlight range
2020-10-31 15:09:22 +00:00
Linedef l = MapSet . NearestLinedef ( blockmap , mousemappos ) ;
2015-12-28 15:01:53 +00:00
if ( l ! = null )
2015-01-23 12:36:43 +00:00
{
// Check on which side of the linedef the mouse is
2020-05-21 12:20:02 +00:00
double side = l . SideOfLine ( mousemappos ) ;
2015-12-28 15:01:53 +00:00
if ( side > 0 )
2015-01-23 12:36:43 +00:00
{
// Is there a sidedef here?
2015-12-28 15:01:53 +00:00
if ( l . Back ! = null )
2015-01-23 12:36:43 +00:00
{
// Highlight if not the same
2016-07-02 22:27:20 +00:00
if ( l . Back . Sector ! = highlighted )
{
Highlight ( l . Back . Sector ) ;
redrawrequired = true ; //mxd
}
2015-01-23 12:36:43 +00:00
}
2016-07-02 22:27:20 +00:00
else if ( highlighted ! = null )
2015-01-23 12:36:43 +00:00
{
// Highlight nothing
Highlight ( null ) ;
2016-07-02 22:27:20 +00:00
redrawrequired = true ; //mxd
2015-01-23 12:36:43 +00:00
}
}
else
{
// Is there a sidedef here?
2015-12-28 15:01:53 +00:00
if ( l . Front ! = null )
2015-01-23 12:36:43 +00:00
{
// Highlight if not the same
2016-07-02 22:27:20 +00:00
if ( l . Front . Sector ! = highlighted )
{
Highlight ( l . Front . Sector ) ;
redrawrequired = true ; //mxd
}
2015-01-23 12:36:43 +00:00
}
2016-07-02 22:27:20 +00:00
else if ( highlighted ! = null )
2015-01-23 12:36:43 +00:00
{
// Highlight nothing
Highlight ( null ) ;
2016-07-02 22:27:20 +00:00
redrawrequired = true ; //mxd
2015-01-23 12:36:43 +00:00
}
}
}
2016-07-02 22:27:20 +00:00
else if ( highlighted ! = null )
2015-01-23 12:36:43 +00:00
{
// Highlight nothing
Highlight ( null ) ;
2016-07-02 22:27:20 +00:00
redrawrequired = true ; //mxd
2015-01-23 12:36:43 +00:00
}
2016-07-02 22:27:20 +00:00
//mxd
if ( redrawrequired )
2015-01-23 12:36:43 +00:00
{
2016-07-02 22:27:20 +00:00
// Show highlight info
if ( highlightedline ! = null & & ! highlightedline . IsDisposed )
General . Interface . ShowLinedefInfo ( highlightedline ) ;
else if ( highlighted ! = null & & ! highlighted . IsDisposed )
General . Interface . ShowSectorInfo ( highlighted ) ;
else
General . Interface . HideInfo ( ) ;
2023-08-13 19:19:25 +00:00
2016-07-02 22:27:20 +00:00
// Redraw display
2015-01-23 12:36:43 +00:00
General . Interface . RedrawDisplay ( ) ;
}
}
}
// Mouse leaves
public override void OnMouseLeave ( EventArgs e )
{
base . OnMouseLeave ( e ) ;
// Highlight nothing
Highlight ( null ) ;
}
2023-08-13 19:19:25 +00:00
/// <summary>
/// Starts finding a sound leak. Finding the actual leak is done by a background worker that's started from this method
/// </summary>
private void FindSoundLeak ( )
{
leakfinder = null ;
// Do not show an error if either start or end is not set, since that'll happen when you start out
if ( leakstartsector = = null | | leakendsector = = null )
return ;
if ( leakendsector = = leakstartsector )
{
General . ToastManager . ShowToast ( ToastMessages . SOUNDPROPAGATIONMODE , ToastType . WARNING , "Sound propagation" , "Stard and end position for sound leak are in the same sector" ) ;
return ;
}
HashSet < Sector > sectors = new HashSet < Sector > ( sector2domain [ leakstartsector ] . Sectors ) ;
// Mash all sectors from the leak start sector's domain and the adjacent domains into one hash set
foreach ( Sector s in sector2domain [ leakstartsector ] . AdjacentSectors )
sectors . UnionWith ( sector2domain [ s ] . Sectors ) ;
// If the leak end sector isn't in the list of sectors there's no way sound can travel between the start and end
if ( ! sectors . Contains ( leakendsector ) )
{
General . ToastManager . ShowToast ( ToastMessages . SOUNDPROPAGATIONMODE , ToastType . WARNING , "Sound propagation" , "Sound can not travel between the selected start and end positions" ) ;
return ;
}
if ( worker ! = null )
{
worker . CancelAsync ( ) ;
worker . Dispose ( ) ;
}
General . Interface . DisplayStatus ( StatusType . Busy , "Searching for sound leak..." ) ;
worker = new BackgroundWorker ( ) ;
worker . WorkerSupportsCancellation = true ;
worker . DoWork + = FindSoundLeakStart ;
worker . RunWorkerCompleted + = FindSoundLeakFinished ;
worker . RunWorkerAsync ( sectors ) ;
}
/// <summary>
/// Method for the background worker that finds a sound leak.
/// </summary>
/// <param name="sender">The sender</param>
/// <param name="e">The event arguments</param>
private void FindSoundLeakStart ( object sender , DoWorkEventArgs e )
{
Stopwatch sw = Stopwatch . StartNew ( ) ;
leakfinder = new LeakFinder ( leakstartsector , leakstartposition , leakendsector , leakendposition , ( HashSet < Sector > ) e . Argument ) ;
if ( leakfinder . FindLeak ( ) = = false )
General . ToastManager . ShowToast ( ToastMessages . SOUNDPROPAGATIONMODE , ToastType . WARNING , "Sound propagation" , "Could not find a leak between the selected start and end positions, even though there should be one. This is weird" ) ;
else
General . Interface . DisplayStatus ( StatusType . Info , string . Format ( @"Searching for sound leak finished. Elapsed time: {0:mm\:ss\.ff}" , sw . Elapsed ) ) ;
}
/// <summary>
/// Method that's called when finding a sound leak finished.
/// </summary>
/// <param name="sender">The sender</param>
/// <param name="e">The event arguments</param>
private void FindSoundLeakFinished ( object sender , RunWorkerCompletedEventArgs e )
{
General . Interface . RedrawDisplay ( ) ;
}
2015-01-23 12:36:43 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Actions
[BeginAction("soundpropagationcolorconfiguration")]
public void ConfigureColors ( )
{
2016-07-02 22:27:20 +00:00
using ( ColorConfiguration cc = new ColorConfiguration ( ) )
2015-01-23 12:36:43 +00:00
{
2023-08-13 19:19:25 +00:00
if ( cc . ShowDialog ( ( Form ) General . Interface ) = = DialogResult . OK )
2016-07-02 22:27:20 +00:00
General . Interface . RedrawDisplay ( ) ;
2015-01-23 12:36:43 +00:00
}
}
2023-08-13 19:19:25 +00:00
[BeginAction("setleakfinderstart")]
public void SetLeakFinderStartSector ( )
{
leakstartsector = highlighted ;
leakstartposition = mousemappos ;
leakstartlabel . Location = mousemappos ;
leakfinder = null ;
// Redraw to show the label
General . Interface . RedrawDisplay ( ) ;
FindSoundLeak ( ) ;
}
[BeginAction("setleakfinderend")]
public void SetLeakFinderEndSector ( )
{
leakendsector = highlighted ;
leakendposition = mousemappos ;
leakendlabel . Location = mousemappos ;
leakfinder = null ;
// Redraw to show the label
General . Interface . RedrawDisplay ( ) ;
FindSoundLeak ( ) ;
}
[BeginAction("clearselection", BaseAction = true)]
public void ClearLeakFinder ( )
{
leakendsector = leakstartsector = null ;
leakfinder = null ;
General . Interface . RedrawDisplay ( ) ;
}
2015-01-23 12:36:43 +00:00
#endregion
}
}