Fixed a bug that allowed to place vertices and things outside the map format grid boundaries

This commit is contained in:
boris_i 2010-08-13 18:32:21 +00:00
parent e7d011068e
commit aa34d0605e
13 changed files with 264 additions and 33 deletions

View file

@ -15,6 +15,14 @@ start3dmode = 32000;
// Flat used as sky
skyflatname = "F_SKY1";
// Map boundaries. Map objects can only be placed within these boundaries
// WARNING: changing this may mess your map up, so only change it when you
// know what you are doing
leftboundary = -32768;
rightboundary = 32767;
topboundary = 32767;
bottomboundary = -32768;
// Maximum length of texture name length in characters (0 for unlimited)
// WARNING: changing this may destroy your WAD file. Only change it when

View file

@ -73,6 +73,10 @@ namespace CodeImp.DoomBuilder.Config
private string decorategames;
private string skyflatname;
private int maxtexturenamelength;
private int leftboundary;
private int rightboundary;
private int topboundary;
private int bottomboundary;
private bool doomlightlevels;
// Skills
@ -159,6 +163,10 @@ namespace CodeImp.DoomBuilder.Config
public string DecorateGames { get { return decorategames; } }
public string SkyFlatName { get { return skyflatname; } }
public int MaxTextureNamelength { get { return maxtexturenamelength; } }
public int LeftBoundary { get { return leftboundary; } }
public int RightBoundary { get { return rightboundary; } }
public int TopBoundary { get { return topboundary; } }
public int BottomBoundary { get { return bottomboundary; } }
public bool DoomLightLevels { get { return doomlightlevels; } }
// Skills
@ -267,6 +275,10 @@ namespace CodeImp.DoomBuilder.Config
decorategames = cfg.ReadSetting("decorategames", "");
skyflatname = cfg.ReadSetting("skyflatname", "F_SKY1");
maxtexturenamelength = cfg.ReadSetting("maxtexturenamelength", 8);
leftboundary = cfg.ReadSetting("leftboundary", -32768);
rightboundary = cfg.ReadSetting("rightboundary", 32767);
topboundary = cfg.ReadSetting("topboundary", 32767);
bottomboundary = cfg.ReadSetting("bottomboundary", -32768);
doomlightlevels = cfg.ReadSetting("doomlightlevels", true);
for(int i = 0; i < Linedef.NUM_ARGS; i++) makedoorargs[i] = cfg.ReadSetting("makedoorarg" + i.ToString(CultureInfo.InvariantCulture), 0);

View file

@ -236,8 +236,16 @@ namespace CodeImp.DoomBuilder.Editing
// This snaps to the nearest grid coordinate
public static Vector2D SnappedToGrid(Vector2D v, float gridsize, float gridsizeinv)
{
return new Vector2D((float)Math.Round(v.x * gridsizeinv) * gridsize,
(float)Math.Round(v.y * gridsizeinv) * gridsize);
Vector2D sv = new Vector2D((float)Math.Round(v.x * gridsizeinv) * gridsize,
(float)Math.Round(v.y * gridsizeinv) * gridsize);
if (sv.x < General.Map.Config.LeftBoundary) sv.x = General.Map.Config.LeftBoundary;
else if (sv.x > General.Map.Config.RightBoundary) sv.x = General.Map.Config.RightBoundary;
if (sv.y > General.Map.Config.TopBoundary) sv.y = General.Map.Config.TopBoundary;
else if (sv.y < General.Map.Config.BottomBoundary) sv.y = General.Map.Config.BottomBoundary;
return sv;
}
#endregion

View file

@ -157,29 +157,33 @@ namespace CodeImp.DoomBuilder.Rendering
}
// This draws a dotted grid line horizontally
public void DrawGridLineH(int y, ref PixelColor c)
public void DrawGridLineH(int y, int x1, int x2, ref PixelColor c)
{
int numpixels = visiblewidth >> 1;
int offset = y & 0x01;
int ywidth = y * width;
x1 = General.Clamp(x1 >> 1, 0, numpixels - 1);
x2 = General.Clamp(x2 >> 1, 0, numpixels - 1);
if((y >= 0) && (y < height))
if ((y >= 0) && (y < height))
{
// Draw all pixels on this line
for(int i = 0; i < numpixels; i++) pixels[ywidth + ((i << 1) | offset)] = c;
for (int i = x1; i < x2; i++) pixels[ywidth + ((i << 1) | offset)] = c;
}
}
// This draws a dotted grid line vertically
public void DrawGridLineV(int x, ref PixelColor c)
public void DrawGridLineV(int x, int y1, int y2, ref PixelColor c)
{
int numpixels = visibleheight >> 1;
int offset = x & 0x01;
y1 = General.Clamp(y1 >> 1, 0, numpixels - 1);
y2 = General.Clamp(y2 >> 1, 0, numpixels - 1);
if((x >= 0) && (x < width))
{
// Draw all pixels on this line
for(int i = 0; i < numpixels; i++) pixels[((i << 1) | offset) * width + x] = c;
for (int i = y1; i < y2; i++) pixels[((i << 1) | offset) * width + x] = c;
}
}

View file

@ -831,9 +831,13 @@ namespace CodeImp.DoomBuilder.Rendering
private void RenderGrid(float size, PixelColor c, Plotter gridplotter)
{
Vector2D ltpos, rbpos;
Vector2D tlb, rbb;
Vector2D pos = new Vector2D();
float sizeinv = 1f / size;
float ystart, yend;
float xstart, xend;
float from, to;
// Only render grid when not screen-filling
if((size * scale) > 6f)
{
@ -844,21 +848,48 @@ namespace CodeImp.DoomBuilder.Rendering
// Clip to nearest grid
ltpos = GridSetup.SnappedToGrid(ltpos, size, sizeinv);
rbpos = GridSetup.SnappedToGrid(rbpos, size, sizeinv);
// Translate top left boundary and right bottom boundary of map
// to screen coords
tlb = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary).GetTransformed(translatex, translatey, scale, -scale);
rbb = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary).GetTransformed(translatex, translatey, scale, -scale);
// Draw all horizontal grid lines
for(float y = ltpos.y + size; y > rbpos.y - size; y -= size)
ystart = rbpos.y > General.Map.Config.BottomBoundary ? rbpos.y : General.Map.Config.BottomBoundary;
yend = ltpos.y < General.Map.Config.TopBoundary ? ltpos.y : General.Map.Config.TopBoundary;
for (float y = ystart; y < yend + size; y += size)
{
if (y > General.Map.Config.TopBoundary) y = General.Map.Config.TopBoundary;
else if (y < General.Map.Config.BottomBoundary) y = General.Map.Config.BottomBoundary;
from = tlb.x < 0 ? 0 : tlb.x;
to = rbb.x > windowsize.Width ? windowsize.Width : rbb.x;
pos.y = y;
pos = pos.GetTransformed(translatex, translatey, scale, -scale);
gridplotter.DrawGridLineH((int)pos.y, ref c);
// Note: I'm not using Math.Ceiling in this case, because that doesn't work right.
gridplotter.DrawGridLineH((int)pos.y, (int)Math.Round(from + 0.49999f), (int)Math.Round(to + 0.49999f), ref c);
}
// Draw all vertical grid lines
for(float x = ltpos.x - size; x < rbpos.x + size; x += size)
xstart = ltpos.x > General.Map.Config.LeftBoundary ? ltpos.x : General.Map.Config.LeftBoundary;
xend = rbpos.x < General.Map.Config.RightBoundary ? rbpos.x : General.Map.Config.RightBoundary;
for (float x = xstart; x < xend + size; x += size)
{
if (x > General.Map.Config.RightBoundary) x = General.Map.Config.RightBoundary;
else if (x < General.Map.Config.LeftBoundary) x = General.Map.Config.LeftBoundary;
from = tlb.y < 0 ? 0 : tlb.y;
to = rbb.y > windowsize.Height ? windowsize.Height : rbb.y;
pos.x = x;
pos = pos.GetTransformed(translatex, translatey, scale, -scale);
gridplotter.DrawGridLineV((int)pos.x, ref c);
// Note: I'm not using Math.Ceiling in this case, because that doesn't work right.
gridplotter.DrawGridLineV((int)pos.x, (int)Math.Round(from + 0.49999f), (int)Math.Round(to + 0.49999f), ref c);
}
}
}

View file

@ -165,10 +165,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
Vector2D oldpos = dragitem.Position;
Vector2D anchorpos = dragitemposition + offset;
int i = 0;
Vector2D tl, br;
// don't move if the offset contains invalid data
if (!offset.IsFinite()) return false;
// Find the outmost vertices
tl = br = oldpositions[0];
for (int i = 0; i < oldpositions.Count; i++)
{
if (oldpositions[i].x < tl.x) tl.x = (int)oldpositions[i].x;
if (oldpositions[i].x > br.x) br.x = (int)oldpositions[i].x;
if (oldpositions[i].y > tl.y) tl.y = (int)oldpositions[i].y;
if (oldpositions[i].y < br.y) br.y = (int)oldpositions[i].y;
}
// Snap to nearest?
if(snapnearest)
@ -245,9 +255,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
offset += dragitem.Position - anchorpos;
}
// Make sure the offset is inside the map boundaries
if (offset.x + tl.x < General.Map.Config.LeftBoundary) offset.x = General.Map.Config.LeftBoundary - tl.x;
if (offset.x + br.x > General.Map.Config.RightBoundary) offset.x = General.Map.Config.RightBoundary - br.x;
if (offset.y + tl.y > General.Map.Config.TopBoundary) offset.y = General.Map.Config.TopBoundary - tl.y;
if (offset.y + br.y < General.Map.Config.BottomBoundary) offset.y = General.Map.Config.BottomBoundary - br.y;
// Drag item moved?
if(!snapgrid || (dragitem.Position != oldpos))
{
int i = 0;
// Move selected geometry
foreach(Vertex v in selectedverts)
{

View file

@ -157,11 +157,21 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
Vector2D oldpos = dragitem.Position;
Thing nearest;
int i = 0;
Vector2D tl, br;
// don't move if the offset contains invalid data
if (!offset.IsFinite()) return false;
// Find the outmost things
tl = br = oldpositions[0];
for (int i = 0; i < oldpositions.Count; i++)
{
if (oldpositions[i].x < tl.x) tl.x = (int)oldpositions[i].x;
if (oldpositions[i].x > br.x) br.x = (int)oldpositions[i].x;
if (oldpositions[i].y > tl.y) tl.y = (int)oldpositions[i].y;
if (oldpositions[i].y < br.y) br.y = (int)oldpositions[i].y;
}
// Snap to nearest?
if(snapnearest)
{
@ -193,9 +203,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
offset += (Vector2D)dragitem.Position - (dragitemposition + offset);
}
// Make sure the offset is inside the map boundaries
if (offset.x + tl.x < General.Map.Config.LeftBoundary) offset.x = General.Map.Config.LeftBoundary - tl.x;
if (offset.x + br.x > General.Map.Config.RightBoundary) offset.x = General.Map.Config.RightBoundary - br.x;
if (offset.y + tl.y > General.Map.Config.TopBoundary) offset.y = General.Map.Config.TopBoundary - tl.y;
if (offset.y + br.y < General.Map.Config.BottomBoundary) offset.y = General.Map.Config.BottomBoundary - br.y;
// Drag item moved?
if(!snapgrid || ((Vector2D)dragitem.Position != oldpos))
{
int i = 0;
// Move selected geometry
foreach(Thing t in selectedthings)
{

View file

@ -208,6 +208,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, IRenderer2D renderer, List<DrawnVertex> points)
{
DrawnVertex p = new DrawnVertex();
Vector2D vm = mousemappos;
float vrange = BuilderPlug.Me.StitchRange / renderer.Scale;
// Snap to nearest?
@ -289,11 +290,55 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
// if the mouse cursor is outside the map bondaries check if the line between the last set point and the
// mouse cursor intersect any of the boundary lines. If it does, set the position to this intersection
if (points.Count > 0 &&
(mousemappos.x < General.Map.Config.LeftBoundary || mousemappos.x > General.Map.Config.RightBoundary ||
mousemappos.y > General.Map.Config.TopBoundary || mousemappos.y < General.Map.Config.BottomBoundary))
{
Line2D dline = new Line2D(mousemappos, points[points.Count - 1].pos);
bool foundintersection = false;
float u = 0.0f;
List<Line2D> blines = new List<Line2D>();
// lines for left, top, right and bottom bondaries
blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary));
blines.Add(new Line2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.TopBoundary));
blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary, General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary));
blines.Add(new Line2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary, General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary));
// check for intersections with boundaries
for (int i = 0; i < blines.Count; i++)
{
if (!foundintersection)
{
// only check for intersection if the last set point is not on the
// line we are checking against
if (blines[i].GetSideOfLine(points[points.Count - 1].pos) != 0.0f)
{
foundintersection = blines[i].GetIntersection(dline, out u);
}
}
}
// if there was no intersection set the position to the last set point
if (!foundintersection)
vm = points[points.Count - 1].pos;
else
vm = dline.GetCoordinatesAt(u);
}
// Snap to grid?
if(snaptogrid)
{
// Aligned to grid
p.pos = General.Map.Grid.SnappedToGrid(mousemappos);
p.pos = General.Map.Grid.SnappedToGrid(vm);
// special handling
if (p.pos.x > General.Map.Config.RightBoundary) p.pos.x = General.Map.Config.RightBoundary;
if (p.pos.y < General.Map.Config.BottomBoundary) p.pos.y = General.Map.Config.BottomBoundary;
p.stitch = snaptonearest;
p.stitchline = snaptonearest;
return p;
@ -301,7 +346,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
else
{
// Normal position
p.pos = mousemappos;
p.pos = vm;
p.stitch = snaptonearest;
p.stitchline = snaptonearest;
return p;
@ -315,14 +360,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
// This draws a point at a specific location
public void DrawPointAt(DrawnVertex p)
public bool DrawPointAt(DrawnVertex p)
{
DrawPointAt(p.pos, p.stitch, p.stitchline);
return DrawPointAt(p.pos, p.stitch, p.stitchline);
}
// This draws a point at a specific location
public void DrawPointAt(Vector2D pos, bool stitch, bool stitchline)
public bool DrawPointAt(Vector2D pos, bool stitch, bool stitchline)
{
if (pos.x < General.Map.Config.LeftBoundary || pos.x > General.Map.Config.RightBoundary ||
pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary)
return false;
DrawnVertex newpoint = new DrawnVertex();
newpoint.pos = pos;
newpoint.stitch = stitch;
@ -345,6 +394,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
FinishDraw();
}
}
return true;
}
#endregion
@ -498,7 +549,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(General.Interface.MouseInDisplay)
{
DrawnVertex newpoint = GetCurrentPosition();
DrawPointAt(newpoint);
if(!DrawPointAt(newpoint)) General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries.");
}
}

View file

@ -957,6 +957,56 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Anything to do?
if((selectedthings.Count > 0) || (selectedvertices.Count > 0))
{
Vector2D tl = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary);
Vector2D br = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.RightBoundary);
foreach (Vertex v in selectedvertices)
{
if (v.Position.x < tl.x) tl.x = (int)v.Position.x;
if (v.Position.x > br.x) br.x = (int)v.Position.x;
if (v.Position.y > tl.y) tl.y = (int)v.Position.y;
if (v.Position.y < br.y) br.y = (int)v.Position.y;
}
foreach (Thing t in selectedthings)
{
if (t.Position.x < tl.x) tl.x = (int)t.Position.x;
if (t.Position.x > br.x) br.x = (int)t.Position.x;
if (t.Position.y > tl.y) tl.y = (int)t.Position.y;
if (t.Position.y < br.y) br.y = (int)t.Position.y;
}
// Check if the selection is outside the map boundaries
if (tl.x < General.Map.Config.LeftBoundary || br.x > General.Map.Config.RightBoundary ||
tl.y > General.Map.Config.TopBoundary || br.y < General.Map.Config.BottomBoundary)
{
General.Interface.DisplayStatus(StatusType.Warning, "Error: selection out of map boundaries.");
// If we're in the process of switching to another mode, reset to selection
// to its old position
if (modealreadyswitching == true)
{
// Reset geometry in original position
int index = 0;
foreach (Vertex v in selectedvertices)
v.Move(vertexpos[index++]);
index = 0;
foreach (Thing t in selectedthings)
{
t.Rotate(thingangle[index]);
t.Move(thingpos[index++]);
}
// Resume normal undo/redo recording
General.Map.UndoRedo.IgnorePropChanges = false;
General.Map.Map.Update(true, true);
}
return;
}
Cursor.Current = Cursors.AppStarting;
if(!pasting)

View file

@ -369,8 +369,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, renderer, new List<DrawnVertex>());
drawmode.DrawPointAt(v);
General.Editing.ChangeMode(drawmode);
if (drawmode.DrawPointAt(v))
General.Editing.ChangeMode(drawmode);
else
General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries.");
}
base.OnEditBegin();

View file

@ -591,8 +591,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, renderer, new List<DrawnVertex>());
drawmode.DrawPointAt(v);
General.Editing.ChangeMode(drawmode);
if(drawmode.DrawPointAt(v))
General.Editing.ChangeMode(drawmode);
else
General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries.");
}
base.OnEditBegin();

View file

@ -347,10 +347,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Insert a new item and select it for dragging
General.Map.UndoRedo.CreateUndo("Insert thing");
Thing t = InsertThing(mousemappos);
General.Map.Map.ClearSelectedThings();
t.Selected = true;
Highlight(t);
General.Interface.RedrawDisplay();
if (t == null)
{
General.Map.UndoRedo.WithdrawUndo();
}
else
{
General.Map.Map.ClearSelectedThings();
t.Selected = true;
Highlight(t);
General.Interface.RedrawDisplay();
}
}
}
@ -537,6 +545,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Insert new thing
General.Map.UndoRedo.CreateUndo("Insert thing");
Thing t = InsertThing(mousemappos);
if (t == null)
{
General.Map.UndoRedo.WithdrawUndo();
return;
}
// Edit the thing?
if(BuilderPlug.Me.EditNewThing)
@ -562,6 +576,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
// This creates a new thing
private Thing InsertThing(Vector2D pos)
{
if (pos.x < General.Map.Config.LeftBoundary || pos.x > General.Map.Config.RightBoundary ||
pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary)
{
General.Interface.DisplayStatus(StatusType.Warning, "Failed to insert thing: outside of map boundaries.");
return null;
}
// Create things at mouse position
Thing t = General.Map.Map.CreateThing();
General.Settings.ApplyDefaultThingSettings(t);

View file

@ -322,8 +322,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Start drawing mode
DrawGeometryMode drawmode = new DrawGeometryMode();
DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, renderer, new List<DrawnVertex>());
drawmode.DrawPointAt(v);
General.Editing.ChangeMode(drawmode);
if (drawmode.DrawPointAt(v))
General.Editing.ChangeMode(drawmode);
else
General.Interface.DisplayStatus(StatusType.Warning, "Failed to draw point: outside of map boundaries.");
}
}