mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-27 14:12:16 +00:00
4389870162
In Sound Propagation Mode you can set the start (default: Shift+S) and end (default: Shift+E) sectors between which a path the sound can travel will be found and displayed.
148 lines
4.6 KiB
C#
148 lines
4.6 KiB
C#
#region ================== Copyright (c) 2023 Boris Iwanski
|
|
|
|
/*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
*
|
|
* it under the terms of the GNU General Public License as published by
|
|
*
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program.If not, see<http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#endregion
|
|
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using CodeImp.DoomBuilder.Map;
|
|
using CodeImp.DoomBuilder.Rendering;
|
|
|
|
namespace CodeImp.DoomBuilder.SoundPropagationMode
|
|
{
|
|
internal class SoundNode
|
|
{
|
|
public Vector2D Position { get; set; }
|
|
public List<SoundNode> Neighbors { get; set; }
|
|
public SoundNode From { get; set; }
|
|
public double G { get; set; }
|
|
public double H { get; }
|
|
public double F { get; set; } // It's G + H, but computing it on the fly is too expensive
|
|
public bool IsBlocking { get; }
|
|
public bool IsSkip { get; set; }
|
|
|
|
public SoundNode(Vector2D position)
|
|
{
|
|
Position = position;
|
|
G = double.MaxValue;
|
|
H = double.MaxValue;
|
|
IsBlocking = false;
|
|
IsSkip = false;
|
|
Neighbors = new List<SoundNode>();
|
|
}
|
|
|
|
public SoundNode(Vector2D position, SoundNode destination): this(position)
|
|
{
|
|
H = Vector2D.Distance(Position, destination.Position);
|
|
}
|
|
|
|
public SoundNode(Linedef linedef, SoundNode destination) : this(linedef.Line.GetCoordinatesAt(0.5), destination)
|
|
{
|
|
IsBlocking = linedef.IsFlagSet(SoundPropagationMode.BlockSoundFlag);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recomputes the values for the sound node's neighbors
|
|
/// </summary>
|
|
/// <param name="openset">The open set, the add the neighbor to if necessary</param>
|
|
/// <param name="start">The start sound node</param>
|
|
public void ProcessNeighbors(List<SoundNode> openset, SoundNode start)
|
|
{
|
|
bool blockinginpath = HasBlockingInPath(start);
|
|
|
|
foreach (SoundNode neighbor in Neighbors)
|
|
{
|
|
// Skip neighbors that are blocking if there's already a blocking sound node in the path
|
|
// Also skip neighbors that are set to be skipped
|
|
if ((neighbor.IsBlocking && blockinginpath) || neighbor.IsSkip)
|
|
continue;
|
|
|
|
double newg = G + Vector2D.Distance(Position, neighbor.Position);
|
|
|
|
// Compute new values if the path is better
|
|
if (newg < neighbor.G)
|
|
{
|
|
neighbor.From = this;
|
|
neighbor.G = newg;
|
|
neighbor.F = neighbor.G + neighbor.H;
|
|
|
|
if (!openset.Contains(neighbor))
|
|
openset.Add(neighbor);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the path from this sound node to the start sound node has a blocking sound node
|
|
/// </summary>
|
|
/// <param name="start">The start sound node</param>
|
|
/// <returns>true if there is a blocking sound node in the path, false if there isn't</returns>
|
|
private bool HasBlockingInPath(SoundNode start)
|
|
{
|
|
SoundNode current = this;
|
|
while(current != start)
|
|
{
|
|
if (current.IsBlocking)
|
|
return true;
|
|
current = current.From;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the sound node's G and F values, and the sound node that leads here
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
From = null;
|
|
G = double.MaxValue;
|
|
F = double.MaxValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renders the path from this node to the beginning. Traces the path from this sound node back to the start sound node
|
|
/// </summary>
|
|
/// <param name="renderer">The Renderer2D to render with</param>
|
|
internal void RenderPath(IRenderer2D renderer)
|
|
{
|
|
SoundNode current = this;
|
|
|
|
// If the current node is null we have reached the beginning
|
|
while(current != null)
|
|
{
|
|
// Do not render the start and end sound nodes
|
|
if (current != this && current.From != null)
|
|
{
|
|
RectangleF rectangle = new RectangleF((float)(current.Position.x - 4 / renderer.Scale), (float)(current.Position.y - 4 / renderer.Scale), 8 / renderer.Scale, 8 / renderer.Scale);
|
|
renderer.RenderRectangleFilled(rectangle, PixelColor.FromColor(Color.Red), true);
|
|
}
|
|
|
|
if(current.From != null)
|
|
renderer.RenderLine(current.Position, current.From.Position, 1.0f, PixelColor.FromColor(Color.Red), true);
|
|
|
|
// One step back
|
|
current = current.From;
|
|
}
|
|
}
|
|
}
|
|
}
|