triangulation fixes, put the TriangulatorMode back in and some visibility range checking in visual mode

This commit is contained in:
codeimp 2008-01-18 19:52:19 +00:00
parent 053f87f21e
commit 471a9e3d51
10 changed files with 944 additions and 34 deletions

View file

@ -36,10 +36,12 @@
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Include="Testing\TriangulatorMode.cs" />
<Compile Include="VisualMode\BaseVisualMode.cs" />
<Compile Include="VisualMode\BaseVisualSector.cs" />
<Compile Include="VerticesMode\DragVerticesMode.cs" />
<Compile Include="LinedefsMode\LinedefsMode.cs" />
<Compile Include="VisualMode\Clipper.cs" />
<Compile Include="VisualMode\VisualCeiling.cs" />
<Compile Include="VisualMode\VisualFloor.cs" />
<Compile Include="VisualMode\VisualLower.cs" />

View file

@ -58,3 +58,13 @@ wauthormode
allowmouse = true;
allowscroll = true;
}
triangulatormode
{
title = "Edit: Triangulator Mode";
description = "Switches to Triangulator testing mode.";
allowkeys = true;
allowmouse = true;
allowscroll = true;
debugonly = true;
}

View file

@ -0,0 +1,543 @@
#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.Interface;
using CodeImp.DoomBuilder.IO;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Editing;
using System.Threading;
using System.Drawing;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
#if DEBUG
[EditMode(SwitchAction = "triangulatormode", // Action name used to switch to this mode
ButtonDesc = "Triangulator Mode", // Description on the button in toolbar/menu
ButtonImage = "TriangulatorMode.png", // Image resource name for the button
ButtonOrder = int.MaxValue)] // Position of the button (lower is more to the left)
public class TriangulatorMode : ClassicMode
{
#region ================== Constants
#endregion
#region ================== Variables
// Highlighted item
private Sector highlighted;
#endregion
#region ================== Properties
#endregion
#region ================== Constructor / Disposer
// Constructor
public TriangulatorMode()
{
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// Dispose base
base.Dispose();
}
}
#endregion
#region ================== Methods
// Cancel mode
public override void Cancel()
{
base.Cancel();
// Return to this mode
General.Map.ChangeMode(new SectorsMode());
}
// Mode engages
public override void Engage()
{
base.Engage();
}
// Mode disengages
public override void Disengage()
{
base.Disengage();
// Check which mode we are switching to
if(General.Map.NewMode is VerticesMode)
{
// Convert selection to vertices
// Clear selected sectors
General.Map.Map.ClearSelectedSectors();
}
else if(General.Map.NewMode is LinedefsMode)
{
// Convert selection to linedefs
// Clear selected sectors
General.Map.Map.ClearSelectedSectors();
}
// Hide highlight info
General.Interface.HideInfo();
}
// This redraws the display
public unsafe override void RedrawDisplay()
{
// Start with a clear display
if(renderer.Start(true, true))
{
// Do not show things
renderer.SetThingsRenderOrder(false);
// Render lines and vertices
renderer.RenderLinedefSet(General.Map.Map.Linedefs);
renderer.RenderVerticesSet(General.Map.Map.Vertices);
// Render highlighted item
if((highlighted != null) && !highlighted.IsDisposed)
renderer.RenderSector(highlighted, General.Colors.Highlight);
// Done
renderer.Finish();
}
}
// This highlights a new item
protected void Highlight(Sector s)
{
// Update display
if(renderer.Start(false, false))
{
// Undraw previous highlight
if((highlighted != null) && !highlighted.IsDisposed)
renderer.RenderSector(highlighted);
// Set new highlight
highlighted = s;
// Render highlighted item
if((highlighted != null) && !highlighted.IsDisposed)
renderer.RenderSector(highlighted, General.Colors.Highlight);
// Done
renderer.Finish();
}
// Show highlight info
if((highlighted != null) && !highlighted.IsDisposed)
General.Interface.ShowSectorInfo(highlighted);
else
General.Interface.HideInfo();
}
// Mouse moves
public override void MouseMove(MouseEventArgs e)
{
base.MouseMove(e);
// Find the nearest linedef within highlight range
Linedef l = General.Map.Map.NearestLinedef(mousemappos);
// Check on which side of the linedef the mouse is
float side = l.SideOfLine(mousemappos);
if(side > 0)
{
// Is there a sidedef here?
if(l.Back != null)
{
// Highlight if not the same
if(l.Back.Sector != highlighted) Highlight(l.Back.Sector);
}
else
{
// Highlight nothing
if(highlighted != null) Highlight(null);
}
}
else
{
// Is there a sidedef here?
if(l.Front != null)
{
// Highlight if not the same
if(l.Front.Sector != highlighted) Highlight(l.Front.Sector);
}
else
{
// Highlight nothing
if(highlighted != null) Highlight(null);
}
}
}
// Mouse leaves
public override void MouseLeave(EventArgs e)
{
base.MouseLeave(e);
// Highlight nothing
Highlight(null);
}
// Mouse button pressed
public override void MouseDown(MouseEventArgs e)
{
base.MouseDown(e);
bool front, back;
// Which button is used?
if(e.Button == EditMode.SELECT_BUTTON)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Flip selection
highlighted.Selected = !highlighted.Selected;
// Make update lines selection
foreach(Sidedef sd in highlighted.Sidedefs)
{
if(sd.Line.Front != null) front = sd.Line.Front.Sector.Selected; else front = false;
if(sd.Line.Back != null) back = sd.Line.Back.Sector.Selected; else back = false;
sd.Line.Selected = front | back;
}
// Update display
if(renderer.Start(false, false))
{
// Redraw highlight to show selection
renderer.RenderSector(highlighted);
renderer.Finish();
}
}
}
}
// Mouse released
public override void MouseUp(MouseEventArgs e)
{
ICollection<Sector> selected;
TriangleList triangles;
base.MouseUp(e);
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Which button is used?
if(e.Button == EditMode.SELECT_BUTTON)
{
// Anything selected?
selected = General.Map.Map.GetSectorsSelection(true);
if(selected.Count > 0)
{
// Remove highlight
Highlight(null);
// Clear selection
General.Map.Map.ClearSelectedSectors();
General.Map.Map.ClearSelectedLinedefs();
General.Interface.RedrawDisplay();
// Get a triangulator and bind events
EarClipTriangulator t = new EarClipTriangulator();
t.OnShowLine = new EarClipTriangulator.ShowLine(ShowLine);
t.OnShowPolygon = new EarClipTriangulator.ShowPolygon(ShowPolygon);
t.OnShowPoint = new EarClipTriangulator.ShowPoint(ShowPoint);
t.OnShowEarClip = new EarClipTriangulator.ShowEarClip(ShowEarClip);
// Triangulate this now!
triangles = t.PerformTriangulation(General.GetByIndex<Sector>(selected, 0));
// Start with a clear display
if(renderer.Start(true, true))
{
// Do not show things
renderer.SetThingsRenderOrder(false);
// Render lines and vertices
renderer.RenderLinedefSet(General.Map.Map.Linedefs);
renderer.RenderVerticesSet(General.Map.Map.Vertices);
// Go for all triangle vertices
for(int i = 0; i < triangles.Count; i += 3)
{
renderer.RenderLine(triangles[i + 0], triangles[i + 1], General.Colors.Selection);
renderer.RenderLine(triangles[i + 1], triangles[i + 2], General.Colors.Selection);
renderer.RenderLine(triangles[i + 2], triangles[i + 0], General.Colors.Selection);
}
// Done
renderer.Finish();
Thread.Sleep(200);
}
}
}
else
{
// Get a triangulator and bind events
EarClipTriangulator t = new EarClipTriangulator();
// Triangulate the whole map!
triangles = new TriangleList();
foreach(Sector s in General.Map.Map.Sectors)
triangles.AddRange(t.PerformTriangulation(s));
// Start with a clear display
if(renderer.Start(true, true))
{
// Do not show things
renderer.SetThingsRenderOrder(false);
// Render lines and vertices
renderer.RenderLinedefSet(General.Map.Map.Linedefs);
renderer.RenderVerticesSet(General.Map.Map.Vertices);
// Go for all triangle vertices
for(int i = 0; i < triangles.Count; i += 3)
{
renderer.RenderLine(triangles[i + 0], triangles[i + 1], General.Colors.Selection);
renderer.RenderLine(triangles[i + 1], triangles[i + 2], General.Colors.Selection);
renderer.RenderLine(triangles[i + 2], triangles[i + 0], General.Colors.Selection);
}
// Done
renderer.Finish();
Thread.Sleep(200);
}
}
}
}
// This shows a point
private void ShowPoint(Vector2D v, int c)
{
for(int a = 0; a < 6; a++)
{
RedrawDisplay();
Thread.Sleep(20);
// Start with a clear display
if(renderer.Start(true, true))
{
// Do not show things
renderer.SetThingsRenderOrder(false);
// Render lines and vertices
renderer.RenderLinedefSet(General.Map.Map.Linedefs);
renderer.RenderVerticesSet(General.Map.Map.Vertices);
// Show the point
renderer.RenderVertexAt(v, c);
// Done
renderer.Finish();
}
// Wait a bit
Thread.Sleep(60);
}
}
// This shows a line
private void ShowLine(Vector2D v1, Vector2D v2, PixelColor c)
{
for(int a = 0; a < 6; a++)
{
RedrawDisplay();
Thread.Sleep(20);
Application.DoEvents();
// Start with a clear display
if(renderer.Start(true, true))
{
// Do not show things
renderer.SetThingsRenderOrder(false);
// Render lines and vertices
renderer.RenderLinedefSet(General.Map.Map.Linedefs);
renderer.RenderVerticesSet(General.Map.Map.Vertices);
// Show the line
renderer.RenderLine(v1, v2, c);
// Done
renderer.Finish();
}
// Wait a bit
Thread.Sleep(60);
Application.DoEvents();
}
}
// This shows a polygon
private void ShowPolygon(Polygon p, PixelColor c)
{
LinkedListNode<EarClipVertex> v;
for(int a = 0; a < 5; a++)
{
RedrawDisplay();
Thread.Sleep(10);
// Start with a clear display
if(renderer.Start(true, true))
{
// Do not show things
renderer.SetThingsRenderOrder(false);
// Render lines and vertices
renderer.RenderLinedefSet(General.Map.Map.Linedefs);
renderer.RenderVerticesSet(General.Map.Map.Vertices);
// Go for all vertices in the polygon
v = p.First;
while(v != null)
{
// Show the line
if(v.Next != null) renderer.RenderLine(v.Value.Position, v.Next.Value.Position, c);
v = v.Next;
}
// Show last line as well
renderer.RenderLine(p.Last.Value.Position, p.First.Value.Position, c);
// Done
renderer.Finish();
}
// Wait a bit
Thread.Sleep(50);
}
}
// This shows a polygon
private void ShowEarClip(EarClipVertex[] found, LinkedList<EarClipVertex> remains)
{
EarClipVertex prev, first;
for(int a = 0; a < 5; a++)
{
// Start with a clear display
if(renderer.Start(true, true))
{
// Do not show things
renderer.SetThingsRenderOrder(false);
// Render lines and vertices
renderer.RenderLinedefSet(General.Map.Map.Linedefs);
renderer.RenderVerticesSet(General.Map.Map.Vertices);
// Go for all remaining vertices
prev = null; first = null;
foreach(EarClipVertex v in remains)
{
// Show the line
if(prev != null) renderer.RenderLine(v.Position, prev.Position, PixelColor.FromColor(Color.OrangeRed));
if(prev == null) first = v;
prev = v;
if(v.IsReflex)
renderer.RenderVertexAt(v.Position, ColorCollection.SELECTION);
else
renderer.RenderVertexAt(v.Position, ColorCollection.VERTICES);
}
if(first != null) renderer.RenderLine(first.Position, prev.Position, PixelColor.FromColor(Color.OrangeRed));
if(found != null)
{
renderer.RenderLine(found[0].Position, found[1].Position, PixelColor.FromColor(Color.SkyBlue));
renderer.RenderLine(found[1].Position, found[2].Position, PixelColor.FromColor(Color.SkyBlue));
renderer.RenderLine(found[2].Position, found[0].Position, PixelColor.FromColor(Color.SkyBlue));
renderer.RenderVertexAt(found[1].Position, ColorCollection.ASSOCIATION);
}
// Done
renderer.Finish();
}
Thread.Sleep(10);
// Start with a clear display
if(renderer.Start(true, true))
{
// Do not show things
renderer.SetThingsRenderOrder(false);
// Render lines and vertices
renderer.RenderLinedefSet(General.Map.Map.Linedefs);
renderer.RenderVerticesSet(General.Map.Map.Vertices);
// Go for all remaining vertices
prev = null; first = null;
foreach(EarClipVertex v in remains)
{
// Show the line
if(prev != null) renderer.RenderLine(v.Position, prev.Position, PixelColor.FromColor(Color.OrangeRed));
if(prev == null) first = v;
prev = v;
if(v.IsReflex)
renderer.RenderVertexAt(v.Position, ColorCollection.SELECTION);
else
renderer.RenderVertexAt(v.Position, ColorCollection.VERTICES);
}
if(first != null) renderer.RenderLine(first.Position, prev.Position, PixelColor.FromColor(Color.OrangeRed));
// Done
renderer.Finish();
}
Thread.Sleep(20);
}
}
#endregion
}
#endif
}

View file

@ -54,6 +54,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// List of visible sectors
private Dictionary<Sector, BaseVisualSector> visiblesectors;
// Visual view range ^ 2
private float visualviewrange2;
#endregion
#region ================== Properties
@ -68,6 +71,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Initialize
allsectors = new Dictionary<Sector, BaseVisualSector>(General.Map.Map.Sectors.Count);
visiblesectors = new Dictionary<Sector, BaseVisualSector>();
visualviewrange2 = General.Settings.VisualViewRange * General.Settings.VisualViewRange;
// We have no destructor
GC.SuppressFinalize(this);
@ -131,10 +135,12 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
}
// This recursively finds and adds visible sectors
private void ProcessVisibleSectors(Sector start, Vector2D campos)
private void ProcessVisibleSectors(Sector start, Vector2D campos, Clipper clipper)
{
BaseVisualSector vs;
Clipper newclip;
Sector os;
float side;
// Find the basesector and make it if needed
if(allsectors.ContainsKey(start))
@ -152,6 +158,26 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Add sector to visibility list
visiblesectors.Add(start, vs);
// Go for all sidedefs in the sector
foreach(Sidedef sd in start.Sidedefs)
{
// Camera on the front of this side?
side = sd.Line.SideOfLine(campos);
if(((side > 0) && sd.IsFront) ||
((side < 0) && !sd.IsFront))
{
// Sidedef blocking the view?
if((sd.Other == null) ||
(sd.Other.Sector.FloorHeight >= (sd.Sector.CeilHeight - 0.0001f)) ||
(sd.Other.Sector.CeilHeight <= (sd.Sector.FloorHeight + 0.0001f)) ||
(sd.Other.Sector.FloorHeight >= (sd.Other.Sector.CeilHeight - 0.0001f)))
{
// This blocks the view
//clipper.InsertRange(sd.Line.Start.Position, sd.Line.End.Position);
}
}
}
// Go for all sidedefs in the sector
foreach(Sidedef sd in start.Sidedefs)
{
@ -164,10 +190,21 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Sector not yet added?
if(!visiblesectors.ContainsKey(os))
{
// TODO: Visiblity checking!
// Within view range?
if(sd.Line.DistanceToSq(campos, true) < visualviewrange2)
{
// Process this sector as well
ProcessVisibleSectors(os, campos);
// Check if the sector can be seen
//if(clipper.TestRange(sd.Line.Start.Position, sd.Line.End.Position))
{
// Make a copy of the visibility clipper
newclip = new Clipper(clipper);
// Process this sector as well
ProcessVisibleSectors(os, campos, newclip);
// Done with this clipper
newclip.Dispose();
}
}
}
}
@ -206,6 +243,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
public override void Process()
{
Vector2D campos;
Clipper clipper;
// Process base class first
base.Process();
@ -213,11 +251,17 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Get the 2D camera position
campos = new Vector2D(base.CameraPosition.x, base.CameraPosition.y);
// Make visibility clipper
clipper = new Clipper((Vector2D)base.CameraPosition);
// Make new visibility list
visiblesectors = new Dictionary<Sector, BaseVisualSector>(General.Map.Map.Sectors.Count);
// Process all visible sectors starting with the nearest
ProcessVisibleSectors(FindStartSector(campos), campos);
ProcessVisibleSectors(FindStartSector(campos), campos, clipper);
// Clean up
clipper.Dispose();
}
#endregion

View file

@ -0,0 +1,269 @@
#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.Interface;
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
}
}

View file

@ -49,6 +49,7 @@ namespace CodeImp.DoomBuilder.Config
private int visualfov;
private float visualmousesensx;
private float visualmousesensy;
private float visualviewrange;
#endregion
@ -61,6 +62,7 @@ namespace CodeImp.DoomBuilder.Config
public int VisualFOV { get { return visualfov; } internal set { visualfov = value; } }
public float VisualMouseSensX { get { return visualmousesensx; } internal set { visualmousesensx = value; } }
public float VisualMouseSensY { get { return visualmousesensy; } internal set { visualmousesensy = value; } }
public float VisualViewRange { get { return visualviewrange; } internal set { visualviewrange = value; } }
#endregion
@ -88,8 +90,9 @@ namespace CodeImp.DoomBuilder.Config
stitchdistance = cfg.ReadSetting("stitchdistance", 2.0f);
undolevels = cfg.ReadSetting("undolevels", 20);
visualfov = cfg.ReadSetting("visualfov", 80);
visualmousesensx = cfg.ReadSetting("visualmousesensx", 40);
visualmousesensy = cfg.ReadSetting("visualmousesensy", 40);
visualmousesensx = cfg.ReadSetting("visualmousesensx", 40f);
visualmousesensy = cfg.ReadSetting("visualmousesensy", 40f);
visualviewrange = cfg.ReadSetting("visualviewrange", 1000f);
// Success
return true;
@ -111,6 +114,7 @@ namespace CodeImp.DoomBuilder.Config
cfg.WriteSetting("visualfov", visualfov);
cfg.WriteSetting("visualmousesensx", visualmousesensx);
cfg.WriteSetting("visualmousesensy", visualmousesensy);
cfg.WriteSetting("visualviewrange", visualviewrange);
// Save settings configuration
General.WriteLogLine("Saving program configuration...");

View file

@ -171,7 +171,10 @@ namespace CodeImp.DoomBuilder.Geometry
// Create the polygon
newpoly = path.MakePolygon();
#if DEBUG
if(OnShowPolygon != null) OnShowPolygon(newpoly, General.Colors.Selection);
#endif
// Determine where this polygon goes in our tree
foreach(Polygon p in root)
{
@ -260,6 +263,19 @@ namespace CodeImp.DoomBuilder.Geometry
sides[s] = true;
nextpath = new TracePath(history, s);
if(s.Line.Start == fromhere) nextvertex = s.Line.End; else nextvertex = s.Line.Start;
// TEST
#if DEBUG
if(s.IsFront)
{
if(OnShowLine != null) OnShowLine(s.Line.Start.Position, s.Line.End.Position, PixelColor.FromColor(Color.Chartreuse));
}
else
{
if(OnShowLine != null) OnShowLine(s.Line.Start.Position, s.Line.End.Position, PixelColor.FromColor(Color.DeepSkyBlue));
}
#endif
result = DoTracePath(nextpath, nextvertex, findme, sector, sides);
if(result != null) return result;
}
@ -570,10 +586,6 @@ namespace CodeImp.DoomBuilder.Geometry
v1 = t[0];
v2 = t[2];
#if DEBUG
if(OnShowEarClip != null) OnShowEarClip(t, verts);
#endif
// Test first neighbour
t1 = GetTriangle(v1);
if(IsReflex(t1))

View file

@ -30,40 +30,59 @@ namespace CodeImp.DoomBuilder.Geometry
internal class SidedefAngleSorter : IComparer<Sidedef>
{
// Variables
private float baseangle;
private Sidedef baseside;
private Vertex basevertex;
// Constructor
public SidedefAngleSorter(Sidedef baseside, Vertex basev)
public SidedefAngleSorter(Sidedef baseside, Vertex fromvertex)
{
// Initialize
baseangle = baseside.Angle;
if(baseside.Line.Start == basev) basevertex = baseside.Line.End;
else basevertex = baseside.Line.Start;
this.baseside = baseside;
this.basevertex = fromvertex;
// We have no destructor
GC.SuppressFinalize(this);
}
// This calculates the relative angle between two sides
private float CalculateRelativeAngle(Sidedef a, Sidedef b)
{
float s, n, ana, anb;
Vector2D va, vb;
bool dir;
// Determine angles
ana = a.Line.Angle; if(a.Line.End == basevertex) ana += Angle2D.PI;
anb = b.Line.Angle; if(b.Line.End == basevertex) anb += Angle2D.PI;
// Take the difference from angles
n = Angle2D.Difference(ana, anb);
// Get line end vertices a and b that are not connected to basevertex
if(a.Line.Start == basevertex) va = a.Line.End.Position; else va = a.Line.Start.Position;
if(b.Line.Start == basevertex) vb = b.Line.End.Position; else vb = b.Line.Start.Position;
// Determine rotation direction
dir = baseside.IsFront;
if(baseside.Line.End == basevertex) dir = !dir;
// Check to which side the angle goes and adjust angle as needed
s = Line2D.GetSideOfLine(va, vb, basevertex.Position);
if((s < 0) && dir) n = Angle2D.PI2 - n;
if((s > 0) && !dir) n = Angle2D.PI2 - n;
// Return result
return n;
}
// Comparer
public int Compare(Sidedef x, Sidedef y)
{
float ax, ay;
float sx, sy;
// Calculate x angle
ax = Angle2D.Difference(baseangle, x.Angle);
sx = x.Line.SideOfLine(basevertex.Position);
if((sx < 0) && x.IsFront) ax += Angle2D.PI;
if((sx > 0) && !x.IsFront) ax += Angle2D.PI;
ax = Angle2D.Normalized(ax);
// Calculate y angle
ay = Angle2D.Difference(baseangle, y.Angle);
sy = y.Line.SideOfLine(basevertex.Position);
if((sy < 0) && x.IsFront) ay += Angle2D.PI;
if((sy > 0) && !x.IsFront) ay += Angle2D.PI;
ay = Angle2D.Normalized(ay);
// Calculate angles
ax = CalculateRelativeAngle(baseside, x);
ay = CalculateRelativeAngle(baseside, y);
// Compare results
if(ax < ay) return 1;

View file

@ -213,7 +213,14 @@ namespace CodeImp.DoomBuilder.Geometry
// Return vector from angle
return FromAngle(angle) * length;
}
// This calculates the angle
public static float GetAngle(Vector2D a, Vector2D b)
{
// Calculate and return the angle
return -(float)Math.Atan2(-(a.y - b.y), (a.x - b.x)) + (float)Math.PI * 0.5f;
}
#endregion
#region ================== Methods

View file

@ -40,8 +40,8 @@ namespace CodeImp.DoomBuilder.Rendering
{
#region ================== Constants
private const float PROJ_NEAR_PLANE = 0.5f;
private const float PROJ_FAR_PLANE = 1000f;
private const float PROJ_NEAR_PLANE = 1f;
private const float PROJ_FAR_PLANE = 2000f;
#endregion