Increased performance when creating new map geometry (for example, when applying changes made by "Draw Line", "Draw Rectangle" etc. actions).

This commit is contained in:
MaxED 2013-12-17 13:18:44 +00:00
parent 9df67e8b22
commit b1b3dda28b
8 changed files with 163 additions and 100 deletions

View file

@ -130,15 +130,14 @@ namespace CodeImp.DoomBuilder.Actions
public static string GetShortcutKeyDesc(int key)
{
KeysConverter conv = new KeysConverter();
int ctrl, button;
string ctrlprefix = "";
// When key is 0, then return an empty string
if(key == 0) return "";
// Split the key in Control and Button
ctrl = key & ((int)Keys.Control | (int)Keys.Shift | (int)Keys.Alt);
button = key & ~((int)Keys.Control | (int)Keys.Shift | (int)Keys.Alt);
int ctrl = key & ((int)Keys.Control | (int)Keys.Shift | (int)Keys.Alt);
int button = key & ~((int)Keys.Control | (int)Keys.Shift | (int)Keys.Alt);
// When the button is a control key, then remove the control itsself
if((button == (int)Keys.ControlKey) ||

View file

@ -1540,9 +1540,10 @@ namespace CodeImp.DoomBuilder
// This outputs log information
public static void WriteLogLine(string line)
{
#if DEBUG
// Output to console
Console.WriteLine(line);
#endif
// Write to log file
try { File.AppendAllText(logfile, line + Environment.NewLine); }
catch(Exception) { }
@ -1551,8 +1552,10 @@ namespace CodeImp.DoomBuilder
// This outputs log information
public static void WriteLog(string text)
{
#if DEBUG
// Output to console
Console.Write(text);
#endif
// Write to log file
try { File.AppendAllText(logfile, text); }

View file

@ -125,7 +125,8 @@ namespace CodeImp.DoomBuilder.Geometry
u_ray = ((v2.x - v1.x) * (v1.y - y3) - (v2.y - v1.y) * (v1.x - x3)) / div;
// Return if intersecting
return (u_ray >= 0.0f) && (u_ray <= 1.0f) && (u_line >= 0.0f) && (u_line <= 1.0f);
if (u_ray <= 0.0f || u_ray >= 1.0f || u_line <= 0.0f || u_line >= 1.0f) return false; //mxd
return true;
}
else
{

View file

@ -910,16 +910,24 @@ namespace CodeImp.DoomBuilder.Geometry
// Check if any other lines intersect this line
List<float> intersections = new List<float>();
Line2D measureline = ld.Line;
foreach(Linedef ld2 in map.Linedefs)
{
// Intersecting?
// We only keep the unit length from the start of the line and
// do the real splitting later, when all intersections are known
float u;
if(ld2.Line.GetIntersection(measureline, out u))
{
if(!float.IsNaN(u) && (u > 0.0f) && (u < 1.0f) && (ld2 != ld))
intersections.Add(u);
Dictionary<Linedef, bool> processed = new Dictionary<Linedef, bool>(); //mxd
//mxd
foreach (Sector s in map.Sectors) {
//line intersects with sector's bounding box?
if((MapSet.GetCSFieldBits(measureline.v1, s.BBox) & MapSet.GetCSFieldBits(measureline.v2, s.BBox)) == 0) {
foreach (Sidedef side in s.Sidedefs) {
if(processed.ContainsKey(side.Line)) continue;
if(side.Line == ld) continue;
float u;
if(side.Line.Line.GetIntersection(measureline, out u)) {
if(float.IsNaN(u) || (u < 0.0f) || (u > 1.0f)) continue;
intersections.Add(u);
}
processed.Add(side.Line, false);
}
}
}
@ -960,7 +968,7 @@ namespace CodeImp.DoomBuilder.Geometry
// Join merge vertices so that overlapping vertices in the draw become one.
map.BeginAddRemove();
MapSet.JoinVertices(mergeverts, mergeverts, false, MapSet.STITCH_DISTANCE);
MapSet.JoinVertices(mergeverts, MapSet.STITCH_DISTANCE); //mxd
map.EndAddRemove();
/***************************************************\
@ -1187,7 +1195,7 @@ namespace CodeImp.DoomBuilder.Geometry
drawingclosed = true;
// Join merge vertices so that overlapping vertices in the draw become one.
MapSet.JoinVertices(mergeverts, mergeverts, false, MapSet.STITCH_DISTANCE);
MapSet.JoinVertices(mergeverts, MapSet.STITCH_DISTANCE); //mxd
}
}
}
@ -1417,7 +1425,8 @@ namespace CodeImp.DoomBuilder.Geometry
for(int i = newlines.Count - 1; i >= 0; i--)
{
// Remove the line if it has no sides
if((newlines[i].Front == null) && (newlines[i].Back == null)) newlines[i].Dispose();
if((newlines[i].Front != null) || (newlines[i].Back != null)) continue;
newlines[i].Dispose();
}
}

View file

@ -52,6 +52,7 @@ namespace CodeImp.DoomBuilder.Map
public Size Size { get { return size; } }
public RectangleF Range { get { return range; } }
public int BlockSize { get { return blocksize; } }
internal BE[,] Map { get { return blockmap; } }
#endregion

View file

@ -17,7 +17,6 @@
#region ================== Namespaces
using System;
using System.Collections;
using System.Collections.Generic;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Windows;
@ -1907,7 +1906,7 @@ namespace CodeImp.DoomBuilder.Map
foreach(Linedef l in lines)
{
// Check the cs field bits
if ((GetCSFieldBits(l.Start, ref area) & GetCSFieldBits(l.End, ref area)) == 0)
if ((GetCSFieldBits(l.Start.Position, area) & GetCSFieldBits(l.End.Position, area)) == 0)
{
// The line could be in the area
newlines.Add(l);
@ -1918,14 +1917,14 @@ namespace CodeImp.DoomBuilder.Map
return newlines;
}
// This returns the cohen-sutherland field bits for a vertex in a rectangle area
private static int GetCSFieldBits(Vertex v, ref RectangleF area)
/// <summary> This returns the cohen-sutherland field bits for a vector in a rectangle area</summary>
public static int GetCSFieldBits(Vector2D v, RectangleF area)
{
int bits = 0;
if(v.Position.y < area.Top) bits |= 0x01;
if(v.Position.y > area.Bottom) bits |= 0x02;
if(v.Position.x < area.Left) bits |= 0x04;
if(v.Position.x > area.Right) bits |= 0x08;
if(v.y < area.Top) bits |= 0x01;
if(v.y > area.Bottom) bits |= 0x02;
if(v.x < area.Left) bits |= 0x04;
if(v.x > area.Right) bits |= 0x08;
return bits;
}
@ -2270,6 +2269,48 @@ namespace CodeImp.DoomBuilder.Map
return joinsdone;
}
/// <summary>This joins nearby vertices in the same collection </summary>
public static int JoinVertices(List<Vertex> set, float joindist) {
float joindist2 = joindist * joindist;
int joinsdone = 0;
bool joined;
Vertex v1, v2;
do {
// No joins yet
joined = false;
// Go for all vertices in the first set
for(int i = 0; i < set.Count - 1; i++) {
for(int c = i + 1; c < set.Count; c++) {
v1 = set[i];
v2 = set[c];
// Check if vertices are close enough
if (v1.DistanceToSq(v2.Position) <= joindist2) {
// Check if not the same vertex
if (v1.Index != v2.Index) {
// Move the second vertex to match the first
v2.Move(v1.Position);
// Join the second into the first
v2.Join(v1);
set.Remove(v2);
// Count the join
joinsdone++;
joined = true;
break;
}
}
}
}
} while(joined);
// Return result
return joinsdone;
}
/// <summary>This corrects lines that have a back sidedef but no front sidedef by flipping them. Returns the number of flips made.</summary>
public static int FlipBackwardLinedefs(ICollection<Linedef> lines)
{
@ -2299,58 +2340,69 @@ namespace CodeImp.DoomBuilder.Map
float splitdist2 = splitdist * splitdist;
bool splitted;
//mxd. Create blockmap
RectangleF area = CreateArea(verts);
BlockMap<BlockEntry> blockmap = new BlockMap<BlockEntry>(area);
blockmap.AddVerticesSet(verts);
blockmap.AddLinedefsSet(lines);
int bmWidth = blockmap.Size.Width;
int bmHeight = blockmap.Size.Height;
BlockEntry[,] bmap = blockmap.Map;
BlockEntry block;
int w, h;
do
{
// No split yet
splitted = false;
// Go for all the lines
foreach(Linedef l in lines)
{
// Go for all the vertices
foreach(Vertex v in verts)
{
// Check if v is close enough to l for splitting
if(l.DistanceToSq(v.Position, true) <= splitdist2)
{
// Line is not already referencing v?
Vector2D deltastart = l.Start.Position - v.Position;
Vector2D deltaend = l.End.Position - v.Position;
if(((Math.Abs(deltastart.x) > 0.001f) ||
(Math.Abs(deltastart.y) > 0.001f)) &&
((Math.Abs(deltaend.x) > 0.001f) ||
(Math.Abs(deltaend.y) > 0.001f)))
{
// Split line l with vertex v
Linedef nl = l.Split(v);
if(nl == null) return false;
// Add the new line to the list
lines.Add(nl);
for(w = 0; w < bmWidth; w++) {
for(h = 0; h < bmHeight; h++) {
block = bmap[w, h];
if(block.Vertices.Count == 0 || block.Lines.Count == 0) continue;
// Both lines must be updated because their new length
// is relevant for next iterations!
l.UpdateCache();
nl.UpdateCache();
// Go for all the lines
foreach(Linedef l in block.Lines) {
// Go for all the vertices
foreach(Vertex v in block.Vertices) {
// Check if v is close enough to l for splitting
if(l.DistanceToSq(v.Position, true) <= splitdist2) {
// Line is not already referencing v?
Vector2D deltastart = l.Start.Position - v.Position;
Vector2D deltaend = l.End.Position - v.Position;
if(((Math.Abs(deltastart.x) > 0.001f) || (Math.Abs(deltastart.y) > 0.001f)) &&
((Math.Abs(deltaend.x) > 0.001f) || (Math.Abs(deltaend.y) > 0.001f))) {
// Split line l with vertex v
Linedef nl = l.Split(v);
if(nl == null) return false;
// Add both lines to changedlines
if(changedlines != null)
{
changedlines.Add(l);
changedlines.Add(nl);
// Add the new line to the list
lines.Add(nl);
// Both lines must be updated because their new length
// is relevant for next iterations!
l.UpdateCache();
nl.UpdateCache();
// Add both lines to changedlines
if(changedlines != null) {
changedlines.Add(l);
changedlines.Add(nl);
}
// Count the split
splitted = true;
break;
}
}
// Count the split
splitted = true;
break;
}
// Will have to restart when splitted
// TODO: If we make (linked) lists from the collections first,
// we don't have to restart when splitted?
if(splitted) break;
}
}
// Will have to restart when splitted
// TODO: If we make (linked) lists from the collections first,
// we don't have to restart when splitted?
if(splitted) break;
}
}
while(splitted);

View file

@ -269,31 +269,30 @@ namespace CodeImp.DoomBuilder.Map
#region ================== Methods
// This checks and returns a flag without creating it
public bool IsFlagSet(string flagname) {
if(flags.ContainsKey(flagname))
return flags[flagname];
else
return false;
public bool IsFlagSet(string flagname)
{
return (flags.ContainsKey(flagname) && flags[flagname]);
}
// This sets a flag
public void SetFlag(string flagname, bool value) {
public void SetFlag(string flagname, bool value)
{
if(!flags.ContainsKey(flagname) || (IsFlagSet(flagname) != value)) {
BeforePropsChange();
flags[flagname] = value;
}
}
// This returns a copy of the flags dictionary
public Dictionary<string, bool> GetFlags() {
public Dictionary<string, bool> GetFlags()
{
return new Dictionary<string, bool>(flags);
}
// This clears all flags
public void ClearFlags() {
public void ClearFlags()
{
BeforePropsChange();
flags.Clear();
}
@ -306,11 +305,13 @@ namespace CodeImp.DoomBuilder.Map
// This removes textures that are not required
public void RemoveUnneededTextures(bool removemiddle, bool force)
{
BeforePropsChange();
bool changed = false; //mxd
// The middle texture can be removed regardless of any sector tag or linedef action
if(!MiddleRequired() && removemiddle)
{
BeforePropsChange(); //mxd
changed = true; //mxd
this.texnamemid = "-";
this.longtexnamemid = MapSet.EmptyLongName;
General.Map.IsChanged = true;
@ -324,6 +325,10 @@ namespace CodeImp.DoomBuilder.Map
{
if(!HighRequired())
{
if(!changed) { //mxd
BeforePropsChange();
changed = true;
}
this.texnamehigh = "-";
this.longtexnamehigh = MapSet.EmptyLongName;
General.Map.IsChanged = true;
@ -331,6 +336,7 @@ namespace CodeImp.DoomBuilder.Map
if(!LowRequired())
{
if(!changed) BeforePropsChange(); //mxd
this.texnamelow = "-";
this.longtexnamelow = MapSet.EmptyLongName;
General.Map.IsChanged = true;
@ -349,10 +355,8 @@ namespace CodeImp.DoomBuilder.Map
// Texture is required when ceiling of other side is lower
return (Other.sector.CeilHeight < this.sector.CeilHeight);
}
else
{
return false;
}
return false;
}
/// <summary>
@ -375,10 +379,8 @@ namespace CodeImp.DoomBuilder.Map
// Texture is required when floor of other side is higher
return (Other.sector.FloorHeight > this.sector.FloorHeight);
}
else
{
return false;
}
return false;
}
/// <summary>
@ -394,10 +396,8 @@ namespace CodeImp.DoomBuilder.Map
int height = top - bottom;
return (height > 0) ? height : 0;
}
else
{
return 0;
}
return 0;
}
/// <summary>
@ -435,10 +435,8 @@ namespace CodeImp.DoomBuilder.Map
int height = top - bottom;
return (height > 0) ? height : 0;
}
else
{
return 0;
}
return 0;
}
// This creates a checksum from the sidedef properties

View file

@ -81,12 +81,12 @@ namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes
if (block == null) continue;
foreach (Vertex blockVert in block.Vertices) {
if(!blockVert.IsDisposed && blockVert.Index != v.Index && blockVert.Position == v.Position) {
foreach(Linedef l in blockVert.Linedefs)
if(!movedLines.Contains(l)) movedLines.Add(l);
v.Join(blockVert);
break;
}
if(blockVert.IsDisposed || blockVert.Index == v.Index || blockVert.Position != v.Position) continue;
foreach(Linedef l in blockVert.Linedefs)
if(!movedLines.Contains(l)) movedLines.Add(l);
v.Join(blockVert);
break;
}
}