mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-31 04:40:55 +00:00
triangulation fixes, put the TriangulatorMode back in and some visibility range checking in visual mode
This commit is contained in:
parent
053f87f21e
commit
471a9e3d51
10 changed files with 944 additions and 34 deletions
|
@ -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" />
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
543
Source/BuilderModes/Testing/TriangulatorMode.cs
Normal file
543
Source/BuilderModes/Testing/TriangulatorMode.cs
Normal 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
|
||||
}
|
|
@ -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
|
||||
|
|
269
Source/BuilderModes/VisualMode/Clipper.cs
Normal file
269
Source/BuilderModes/VisualMode/Clipper.cs
Normal 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
|
||||
}
|
||||
}
|
|
@ -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...");
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue