mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-30 23:52:38 +00:00
269 lines
6.1 KiB
C#
269 lines
6.1 KiB
C#
|
|
#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;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using CodeImp.DoomBuilder.Windows;
|
|
using CodeImp.DoomBuilder.IO;
|
|
using CodeImp.DoomBuilder.Map;
|
|
using CodeImp.DoomBuilder.Rendering;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using CodeImp.DoomBuilder.Editing;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.BuilderModes
|
|
{
|
|
internal class Clipper
|
|
{
|
|
#region ================== Constants
|
|
|
|
private const float MULTIPLIER = 10000f;
|
|
private const int MAXRANGE = (int)(Angle2D.PI2 * MULTIPLIER);
|
|
private const int HALFRANGE = (int)(Angle2D.PI * MULTIPLIER);
|
|
private const int MINRANGE = 0;
|
|
|
|
#endregion
|
|
|
|
#region ================== ClipRange struct
|
|
|
|
// ClipRange structure
|
|
private struct ClipRange
|
|
{
|
|
// Variables
|
|
public int low;
|
|
public int high;
|
|
|
|
// Constructor
|
|
public ClipRange(int low, int high)
|
|
{
|
|
this.low = low;
|
|
this.high = high;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Variables
|
|
|
|
// Position where we are viewing from
|
|
private Vector2D position;
|
|
|
|
// Clipping ranges
|
|
private LinkedList<ClipRange> ranges;
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
// Constructor
|
|
public Clipper(Vector2D pos)
|
|
{
|
|
// Initialize
|
|
this.position = pos;
|
|
this.ranges = new LinkedList<ClipRange>();
|
|
}
|
|
|
|
// Constructor
|
|
public Clipper(Clipper copy)
|
|
{
|
|
// Initialize
|
|
this.position = copy.position;
|
|
this.ranges = new LinkedList<ClipRange>(copy.ranges);
|
|
}
|
|
|
|
// Disposer
|
|
public void Dispose()
|
|
{
|
|
this.ranges.Clear();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Testing methods
|
|
|
|
// This tests a range to see if it is at least partially visible
|
|
public bool TestRange(Vector2D a, Vector2D b)
|
|
{
|
|
int i1, i2, c1, c2, m;
|
|
float a1, a2;
|
|
|
|
// Get angles
|
|
a1 = Angle2D.Normalized(Vector2D.GetAngle(position, a));
|
|
a2 = Angle2D.Normalized(Vector2D.GetAngle(position, b));
|
|
|
|
// Convert angles to ranges
|
|
i1 = (int)(a1 * MULTIPLIER);
|
|
i2 = (int)(a2 * MULTIPLIER);
|
|
c1 = Math.Min(i1, i2);
|
|
c2 = Math.Max(i1, i2);
|
|
|
|
// Determine rotation direction
|
|
m = c2 - c1;
|
|
if(m < MINRANGE) m += MAXRANGE;
|
|
if(m < HALFRANGE)
|
|
{
|
|
// Check if the range goes through zero point
|
|
if(c2 < c1)
|
|
{
|
|
// Test two ranges
|
|
return RangeVisible(new ClipRange(c1, MAXRANGE)) ||
|
|
RangeVisible(new ClipRange(MINRANGE, c2));
|
|
}
|
|
else
|
|
{
|
|
// Test a single range
|
|
return RangeVisible(new ClipRange(c1, c2));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check if the range goes through zero point
|
|
if(c2 > c1)
|
|
{
|
|
// Test two ranges
|
|
return RangeVisible(new ClipRange(MINRANGE, c1)) ||
|
|
RangeVisible(new ClipRange(c2, MAXRANGE));
|
|
}
|
|
else
|
|
{
|
|
// Test a single range
|
|
return RangeVisible(new ClipRange(c2, c1));
|
|
}
|
|
}
|
|
}
|
|
|
|
// This tests a single range for visibility
|
|
private bool RangeVisible(ClipRange r)
|
|
{
|
|
// Go for all clipped ranges
|
|
foreach(ClipRange c in ranges)
|
|
{
|
|
// Does clipped range completely hide the given range?
|
|
if((c.low <= r.low) && (c.high >= r.high))
|
|
{
|
|
// No further testing needed, range is clipped
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Not completely clipped
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Clipping methods
|
|
|
|
// This tests a range to see if it is at least partially visible
|
|
public bool InsertRange(Vector2D a, Vector2D b)
|
|
{
|
|
int i1, i2, c1, c2, m;
|
|
float a1, a2;
|
|
|
|
// Get angles
|
|
a1 = Angle2D.Normalized(Vector2D.GetAngle(position, a));
|
|
a2 = Angle2D.Normalized(Vector2D.GetAngle(position, b));
|
|
|
|
// Convert angles to ranges
|
|
i1 = (int)(a1 * MULTIPLIER);
|
|
i2 = (int)(a2 * MULTIPLIER);
|
|
c1 = Math.Min(i1, i2);
|
|
c2 = Math.Max(i1, i2);
|
|
|
|
// Determine rotation direction
|
|
m = c2 - c1;
|
|
if(m < MINRANGE) m += MAXRANGE;
|
|
if(m < HALFRANGE)
|
|
{
|
|
// Check if the range goes through zero point
|
|
if(c2 < c1)
|
|
{
|
|
// Add two ranges
|
|
return AddRange(new ClipRange(c1, MAXRANGE)) ||
|
|
AddRange(new ClipRange(MINRANGE, c2));
|
|
}
|
|
else
|
|
{
|
|
// Add a single range
|
|
return AddRange(new ClipRange(c1, c2));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check if the range goes through zero point
|
|
if(c2 > c1)
|
|
{
|
|
// Add two ranges
|
|
return AddRange(new ClipRange(MINRANGE, c1)) ||
|
|
AddRange(new ClipRange(c2, MAXRANGE));
|
|
}
|
|
else
|
|
{
|
|
// Add a single range
|
|
return AddRange(new ClipRange(c2, c1));
|
|
}
|
|
}
|
|
}
|
|
|
|
// This tests a single range for visibility
|
|
// Returns true when the entire range has been clipped
|
|
private bool AddRange(ClipRange r)
|
|
{
|
|
LinkedListNode<ClipRange> current, next;
|
|
ClipRange c;
|
|
|
|
// Go for all ranges to find overlappings
|
|
current = ranges.First;
|
|
while(current != null)
|
|
{
|
|
// Keep reference to the next
|
|
next = current.Next;
|
|
c = current.Value;
|
|
|
|
// Check if ranges overlap
|
|
if((c.low <= (r.high + 1)) && (c.high >= (r.low - 1)))
|
|
{
|
|
// Remove old range from list
|
|
ranges.Remove(current);
|
|
|
|
// Extend range with overlapping range
|
|
if(c.low < r.low) r.low = c.low;
|
|
if(c.high > r.high) r.high = c.high;
|
|
}
|
|
|
|
// Move to the next
|
|
current = next;
|
|
}
|
|
|
|
// Insert the new range
|
|
ranges.AddLast(r);
|
|
|
|
// Return true when entire range is now clipped
|
|
return (r.low == MINRANGE) && (r.high == MAXRANGE);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|