2015-01-23 12:36:43 +00:00
|
|
|
|
#region ================== Namespaces
|
|
|
|
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using CodeImp.DoomBuilder.Map;
|
|
|
|
|
using CodeImp.DoomBuilder.Rendering;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
namespace CodeImp.DoomBuilder.SoundPropagationMode
|
|
|
|
|
{
|
|
|
|
|
public class SoundPropagationDomain
|
|
|
|
|
{
|
|
|
|
|
#region ================== Variables
|
|
|
|
|
|
2016-07-02 22:27:20 +00:00
|
|
|
|
private HashSet<Sector> sectors;
|
|
|
|
|
private HashSet<Sector> adjacentsectors;
|
2015-01-23 12:36:43 +00:00
|
|
|
|
private FlatVertex[] level1geometry;
|
|
|
|
|
private FlatVertex[] level2geometry;
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ================== Properties
|
|
|
|
|
|
2016-07-02 22:27:20 +00:00
|
|
|
|
public HashSet<Sector> Sectors { get { return sectors; } }
|
|
|
|
|
public HashSet<Sector> AdjacentSectors { get { return adjacentsectors; } }
|
2015-01-23 12:36:43 +00:00
|
|
|
|
public FlatVertex[] Level1Geometry { get { return level1geometry; } }
|
|
|
|
|
public FlatVertex[] Level2Geometry { get { return level2geometry; } }
|
2016-07-02 22:27:20 +00:00
|
|
|
|
public int Color { get; set; } //mxd
|
2015-01-23 12:36:43 +00:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ================== Constructor
|
|
|
|
|
|
|
|
|
|
public SoundPropagationDomain(Sector sector)
|
|
|
|
|
{
|
2016-07-02 22:27:20 +00:00
|
|
|
|
sectors = new HashSet<Sector>();
|
|
|
|
|
adjacentsectors = new HashSet<Sector>();
|
2015-01-23 12:36:43 +00:00
|
|
|
|
|
|
|
|
|
CreateSoundPropagationDomain(sector);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ================== Methods
|
|
|
|
|
|
|
|
|
|
private void CreateSoundPropagationDomain(Sector sourcesector)
|
|
|
|
|
{
|
|
|
|
|
List<Sector> sectorstocheck = new List<Sector> { sourcesector };
|
2016-07-02 22:27:20 +00:00
|
|
|
|
HashSet<Linedef> blockinglines = new HashSet<Linedef>(); //mxd
|
2015-01-23 12:36:43 +00:00
|
|
|
|
|
2015-12-28 15:01:53 +00:00
|
|
|
|
while(sectorstocheck.Count > 0)
|
2015-01-23 12:36:43 +00:00
|
|
|
|
{
|
|
|
|
|
// Make sure to first check all sectors that are not behind a sound blocking line
|
|
|
|
|
Sector sector = sectorstocheck[0];
|
|
|
|
|
|
2015-12-28 15:01:53 +00:00
|
|
|
|
foreach(Sidedef sd in sector.Sidedefs)
|
2015-01-23 12:36:43 +00:00
|
|
|
|
{
|
2015-06-30 18:34:08 +00:00
|
|
|
|
bool blocksound = sd.Line.IsFlagSet(SoundPropagationMode.BlockSoundFlag);
|
2016-07-02 22:27:20 +00:00
|
|
|
|
if(blocksound && sd.Other != null) blockinglines.Add(sd.Line);
|
2015-01-23 12:36:43 +00:00
|
|
|
|
|
|
|
|
|
// If the line is one sided, the sound can travel nowhere, so try the next one
|
2016-06-25 14:09:39 +00:00
|
|
|
|
if(sd.Other == null || blocksound) continue;
|
2015-01-23 12:36:43 +00:00
|
|
|
|
|
|
|
|
|
// Get the sector on the other side of the line we're checking right now
|
2015-05-04 07:19:26 +00:00
|
|
|
|
Sector oppositesector = sd.Other.Sector;
|
|
|
|
|
|
|
|
|
|
bool blockheight = IsSoundBlockedByHeight(sd.Line);
|
2015-01-23 12:36:43 +00:00
|
|
|
|
|
|
|
|
|
// Try next line if sound will not pass through the current one. The last check makes
|
|
|
|
|
// sure that the next line is tried if the current line is blocking sound, and the current
|
|
|
|
|
// sector is already behind a sound blocking line
|
2015-12-28 15:01:53 +00:00
|
|
|
|
if(oppositesector == null || blockheight) continue;
|
2015-01-23 12:36:43 +00:00
|
|
|
|
|
|
|
|
|
// If the opposite sector was not regarded at all yet...
|
2015-12-28 15:01:53 +00:00
|
|
|
|
if(!sectors.Contains(oppositesector) && !sectorstocheck.Contains(oppositesector))
|
2015-01-23 12:36:43 +00:00
|
|
|
|
{
|
|
|
|
|
sectorstocheck.Add(oppositesector);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sectorstocheck.Remove(sector);
|
|
|
|
|
sectors.Add(sector);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-28 15:01:53 +00:00
|
|
|
|
foreach(Linedef ld in blockinglines)
|
2015-01-23 12:36:43 +00:00
|
|
|
|
{
|
2015-05-04 07:19:26 +00:00
|
|
|
|
// Lines that don't have a back side, or where the sound is blocked due to
|
|
|
|
|
// the sector heights on each side can be skipped
|
2016-06-25 14:09:39 +00:00
|
|
|
|
if(IsSoundBlockedByHeight(ld)) continue;
|
2015-12-28 15:01:53 +00:00
|
|
|
|
if(!sectors.Contains(ld.Front.Sector)) adjacentsectors.Add(ld.Front.Sector);
|
|
|
|
|
if(!sectors.Contains(ld.Back.Sector)) adjacentsectors.Add(ld.Back.Sector);
|
2015-01-23 12:36:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<FlatVertex> vertices = new List<FlatVertex>();
|
|
|
|
|
|
2015-12-28 15:01:53 +00:00
|
|
|
|
foreach(Sector s in sectors)
|
2015-01-23 12:36:43 +00:00
|
|
|
|
{
|
|
|
|
|
vertices.AddRange(s.FlatVertices);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
level1geometry = vertices.ToArray();
|
|
|
|
|
level2geometry = vertices.ToArray();
|
|
|
|
|
|
2015-12-28 15:01:53 +00:00
|
|
|
|
for(int i = 0; i < level1geometry.Length; i++)
|
2015-01-23 12:36:43 +00:00
|
|
|
|
{
|
|
|
|
|
level1geometry[i].c = BuilderPlug.Me.Level1Color.WithAlpha(128).ToInt();
|
|
|
|
|
level2geometry[i].c = BuilderPlug.Me.Level2Color.WithAlpha(128).ToInt();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-04 07:19:26 +00:00
|
|
|
|
private static bool IsSoundBlockedByHeight(Linedef ld)
|
|
|
|
|
{
|
2016-06-25 14:09:39 +00:00
|
|
|
|
if(ld.Back == null || ld.Front == null) return false;
|
2015-05-04 07:19:26 +00:00
|
|
|
|
|
|
|
|
|
Sector s1 = ld.Front.Sector;
|
|
|
|
|
Sector s2 = ld.Back.Sector;
|
|
|
|
|
|
|
|
|
|
// Check if the sound will be blocked because of sector floor and ceiling heights
|
|
|
|
|
// (like closed doors, raised lifts etc.)
|
|
|
|
|
return (s1.CeilHeight <= s2.FloorHeight || s1.FloorHeight >= s2.CeilHeight ||
|
2016-07-02 22:27:20 +00:00
|
|
|
|
s2.CeilHeight <= s2.FloorHeight || s1.CeilHeight <= s1.FloorHeight);
|
2015-05-04 07:19:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-23 12:36:43 +00:00
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|