//mxd private void CreateTiles() { Point lt = TileForPoint(mapbounds.Left - Tile.TILE_SIZE, mapbounds.Top - Tile.TILE_SIZE); Point rb = TileForPoint(mapbounds.Right + Tile.TILE_SIZE, mapbounds.Bottom + Tile.TILE_SIZE); Rectangle tilesrect = new Rectangle(lt.X, lt.Y, rb.X - lt.X, rb.Y - lt.Y); NearestLineBlockmap blockmap = new NearestLineBlockmap(tilesrect); for (int x = tilesrect.X; x <= tilesrect.Right; x += Tile.TILE_SIZE) { for (int y = tilesrect.Y; y <= tilesrect.Bottom; y += Tile.TILE_SIZE) { // If the tile is obviously outside the map, don't create it Vector2D pc = new Vector2D(x + (Tile.TILE_SIZE >> 1), y + (Tile.TILE_SIZE >> 1)); Linedef ld = MapSet.NearestLinedef(blockmap.GetBlockAt(pc).Lines, pc); double distancesq = ld.DistanceToSq(pc, true); if (distancesq > (Tile.TILE_SIZE * Tile.TILE_SIZE)) { double side = ld.SideOfLine(pc); if ((side > 0.0f) && (ld.Back == null)) { continue; } } Point tp = new Point(x, y); tiles.Add(tp, new Tile(tp)); } } }
// This returns the camera sector from linedef private Sector GetCameraSectorFromLinedef(Linedef ld) { if (ld.SideOfLine(General.Map.VisualCamera.Position) < 0) { if (ld.Front != null) { return(ld.Front.Sector); } else { return(null); } } else { if (ld.Back != null) { return(ld.Back.Sector); } else { return(null); } } }
// This highlights a new region private void Highlight(bool buttonspressed) { // Mouse inside? if (mouseinside) { // Highlighting from a new sidedef? Linedef nl = General.Map.Map.NearestLinedef(mousemappos); if (nl != null) { bool front = (nl.SideOfLine(mousemappos) <= 0.0f); //mxd LinedefSide newnearest = new LinedefSide(nl, front); if (newnearest != nearestside) { // Only change when buttons are not pressed if (!buttonspressed || (editside == newnearest)) { // Find new sector nearestside = newnearest; allsides = Tools.FindPotentialSectorAt(nl, front); //mxd if (allsides != null) { alllines = new List <Linedef>(allsides.Count); foreach (LinedefSide sd in allsides) { alllines.Add(sd.Line); } } else { alllines = null; } } else { // Don't highlight this one nearestside = null; allsides = null; alllines = null; } // Redraw overlay DrawGeometry(); DrawOverlay(); //mxd renderer.Present(); } } } else { // No valid region nearestside = null; allsides = null; alllines = null; // Redraw overlay DrawGeometry(); renderer.Present(); } }
// This tests on which side of the line the given coordinates are // returns < 0 for front (right) side, > 0 for back (left) side and 0 if on the line public float SideOfLine(LuaVector2D p) { if (linedef.IsDisposed) { throw new ScriptRuntimeException("Linedef has been disposed, can't SideOfLine."); } return(linedef.SideOfLine(p.vec)); }
// This returns the camera sector from linedef private static Sector GetCameraSectorFromLinedef(Linedef ld) { if (ld.SideOfLine(General.Map.VisualCamera.Position) < 0) { return(ld.Front != null ? ld.Front.Sector : null); } return(ld.Back != null ? ld.Back.Sector : null); }
public Sector GetSectorAt(Vector2D pos) { List <Sector> sectors = new List <Sector>(1); foreach (VisualBlockEntry e in GetBlocks(pos)) { foreach (Sector s in e.Sectors) { if (s.Intersect(pos)) { sectors.Add(s); } } } if (sectors.Count == 0) { return(null); } else if (sectors.Count == 1) { return(sectors[0]); } else { // Having multiple intersections indicates that there are self-referencing sectors in this spot. // In this case we have to check which side of the nearest linedef pos is on, and then use that sector HashSet <Linedef> linedefs = new HashSet <Linedef>(sectors[0].Sidedefs.Count * sectors.Count); foreach (Sector s in sectors) { foreach (Sidedef sd in s.Sidedefs) { linedefs.Add(sd.Line); } } Linedef nearest = MapSet.NearestLinedef(linedefs, pos); double d = nearest.SideOfLine(pos); if (d <= 0.0 && nearest.Front != null) { return(nearest.Front.Sector); } else if (nearest.Back != null) { return(nearest.Back.Sector); } } return(null); }
// Mouse moves public override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(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); } } } }
//mxd private static Linedef FindPotentialLine(Vector2D target, Vector2D center) { // Target position on top of existing vertex? Vertex v = General.Map.Map.NearestVertex(target); if (v == null) { return(null); } Linedef result = null; if (v.Position == target) { float mindistance = float.MaxValue; foreach (Linedef l in v.Linedefs) { if (result == null) { result = l; mindistance = Vector2D.DistanceSq(l.GetCenterPoint(), center); } else { float curdistance = Vector2D.DistanceSq(l.GetCenterPoint(), center); if (curdistance < mindistance) { mindistance = curdistance; result = l; } } } } else { // Result position will split a line? result = General.Map.Map.NearestLinedef(target); if (result.SideOfLine(target) != 0) { return(null); } } return(result); }
//mxd private static bool CanFinishDrawing(Vector2D start, Vector2D end, Vector2D center) { Linedef startline = FindPotentialLine(start, center); if (startline == null) { return(false); } Linedef endline = FindPotentialLine(end, center); if (endline == null) { return(false); } // Can finish drawing if a path between startline and endline exists return(Tools.FindClosestPath(startline, startline.SideOfLine(center) < 0.0f, endline, endline.SideOfLine(center) < 0.0f, true) != null); }
// Mouse moves public override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // Not holding any buttons? if (e.Button == MouseButtons.None) { // Find the nearest items within highlight range Vertex v = General.Map.Map.NearestVertexSquareRange(mousemappos, VERTEX_HIGHLIGHT_RANGE / renderer.Scale); Thing t = General.Map.Map.NearestThingSquareRange(mousemappos, THING_HIGHLIGHT_RANGE / renderer.Scale); Linedef l = General.Map.Map.NearestLinedef(mousemappos); Sector s; // 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) { s = l.Back.Sector; } else { s = null; } } else { // Is there a sidedef here? if (l.Front != null) { s = l.Front.Sector; } else { s = null; } } // Both a vertex and thing in range? if ((v != null) && (t != null)) { // Highlight closest float vd = v.DistanceToSq(mousemappos); float td = t.DistanceToSq(mousemappos); if (vd < td) { Highlight(v); } else { Highlight(t); } } // Vertex in range? else if (v != null) { // Highlight vertex Highlight(v); } // Thing in range? else if (t != null) { // Highlight thing Highlight(t); } else { // Linedef within in range? float ld = l.DistanceTo(mousemappos, true); if (ld < (LINEDEF_HIGHLIGHT_RANGE / renderer.Scale)) { // Highlight line Highlight(l); } // Mouse inside a sector? else if (s != null) { // Highlight sector Highlight(s); } else { // Highlight nothing Highlight(null); } } } }
// Mode engages public override void OnEngage() { base.OnEngage(); // We don't want to record this for undoing while we move the geometry around. // This will be set back to normal when we're done. General.Map.UndoRedo.IgnorePropChanges = true; // Presentation renderer.SetPresentation(Presentation.Standard); // Selection General.Map.Map.ConvertSelection(SelectionType.Sectors); General.Map.Map.SelectionType = SelectionType.Sectors; if (General.Map.Map.SelectedSectorsCount == 0) { // Find the nearest linedef within highlight range Linedef l = General.Map.Map.NearestLinedef(mousemappos); if (l != null) { Sector selectsector = null; // Check on which side of the linedef the mouse is and which sector there is float side = l.SideOfLine(mousemappos); if ((side > 0) && (l.Back != null)) { selectsector = l.Back.Sector; } else if ((side <= 0) && (l.Front != null)) { selectsector = l.Front.Sector; } // Select the sector! if (selectsector != null) { selectsector.Selected = true; foreach (Sidedef sd in selectsector.Sidedefs) { sd.Line.Selected = true; } } } } // Get sector selection selection = General.Map.Map.GetSelectedSectors(true); if (selection.Count == 0) { General.Interface.MessageBeep(MessageBeepType.Default); General.Interface.DisplayStatus(StatusType.Action, "A selected sector is required for this action."); General.Editing.CancelMode(); return; } editsector = General.GetByIndex(selection, 0); // Get the texture texture = GetTexture(editsector); if ((texture == null) || (texture == General.Map.Data.WhiteTexture) || (texture.Width <= 0) || (texture.Height <= 0) || !texture.IsImageLoaded) { General.Interface.MessageBeep(MessageBeepType.Default); General.Interface.DisplayStatus(StatusType.Action, "The selected sector must have a loaded texture to align."); General.Editing.CancelMode(); return; } // Cache the transformation values sectorinfo = new List <SectorInfo>(selection.Count); foreach (Sector s in selection) { SectorInfo si; si.rotation = Angle2D.DegToRad(s.Fields.GetValue(RotationName, 0.0f)); si.scale.x = s.Fields.GetValue(XScaleName, 1.0f); si.scale.y = s.Fields.GetValue(YScaleName, 1.0f); si.offset.x = s.Fields.GetValue(XOffsetName, 0.0f); si.offset.y = -s.Fields.GetValue(YOffsetName, 0.0f); sectorinfo.Add(si); } // We want the texture corner nearest to the center of the sector Vector2D fp; fp.x = (editsector.BBox.Left + editsector.BBox.Right) / 2; fp.y = (editsector.BBox.Top + editsector.BBox.Bottom) / 2; // Transform the point into texture space fp = WorldToTex(fp); // Snap to the nearest left-top corner fp.x = (float)Math.Floor(fp.x / texture.ScaledWidth) * texture.ScaledWidth; fp.y = (float)Math.Ceiling(fp.y / texture.ScaledHeight) * texture.ScaledHeight; // Now move the offset so that the 0,0 point is at this location // We want to work with the 0,0 location because it makes things easier. SectorInfo si0 = sectorinfo[0]; si0.offset -= fp / si0.scale; sectorinfo[0] = si0; UpdateRectangleComponents(); UpdateSectors(); }
// This runs the check public override void Run() { BlockMap <BlockEntry> blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap; int progress = 0; int stepprogress = 0; float maxradius = 0; Dictionary <int, HashSet <int> > processedthingpairs = new Dictionary <int, HashSet <int> >(); //mxd foreach (ThingTypeInfo tti in General.Map.Data.ThingTypes) { if (tti.Radius > maxradius) { maxradius = tti.Radius; } } // Go for all the things foreach (Thing t in General.Map.Map.Things) { ThingTypeInfo info = General.Map.Data.GetThingInfo(t.Type); bool stuck = false; // Check this thing for getting stuck? if ((info.ErrorCheck == ThingTypeInfo.THING_ERROR_INSIDE_STUCK) && (info.Blocking > ThingTypeInfo.THING_BLOCKING_NONE)) { // Make square coordinates from thing float blockingsize = t.Size - ALLOWED_STUCK_DISTANCE; Vector2D lt = new Vector2D(t.Position.x - blockingsize, t.Position.y - blockingsize); Vector2D rb = new Vector2D(t.Position.x + blockingsize, t.Position.y + blockingsize); Vector2D bmlt = new Vector2D(t.Position.x - maxradius, t.Position.y - maxradius); Vector2D bmrb = new Vector2D(t.Position.x + maxradius, t.Position.y + maxradius); // Go for all the lines to see if this thing is stuck List <BlockEntry> blocks = blockmap.GetSquareRange(new RectangleF(bmlt.x, bmlt.y, (bmrb.x - bmlt.x), (bmrb.y - bmlt.y))); Dictionary <Linedef, Linedef> doneblocklines = new Dictionary <Linedef, Linedef>(blocks.Count * 3); foreach (BlockEntry b in blocks) { foreach (Linedef l in b.Lines) { // Only test when sinlge-sided, two-sided + impassable and not already checked if (((l.Back == null) || l.IsFlagSet(General.Map.Config.ImpassableFlag)) && !doneblocklines.ContainsKey(l)) { // Test if line ends are inside the thing if (PointInRect(lt, rb, l.Start.Position) || PointInRect(lt, rb, l.End.Position)) { // Thing stuck in line! stuck = true; SubmitResult(new ResultStuckThingInLine(t, l)); } // Test if the line intersects the square else if (Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, lt.y, rb.x, lt.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, lt.y, rb.x, rb.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, rb.y, lt.x, rb.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, rb.y, lt.x, lt.y)) { // Thing stuck in line! stuck = true; SubmitResult(new ResultStuckThingInLine(t, l)); } // Checked doneblocklines.Add(l, l); } } // Check if thing is stuck in other things if (info.Blocking != ThingTypeInfo.THING_BLOCKING_NONE) { foreach (Thing ot in b.Things) { // Don't compare the thing with itself if (t.Index == ot.Index) { continue; } // mxd. Don't compare already processed stuff if (processedthingpairs.ContainsKey(t.Index) && processedthingpairs[t.Index].Contains(ot.Index)) { continue; } // Only check of items that can block if (General.Map.Data.GetThingInfo(ot.Type).Blocking == ThingTypeInfo.THING_BLOCKING_NONE) { continue; } // need to compare the flags if (FlagsOverlap(t, ot) && ThingsOverlap(t, ot)) { stuck = true; SubmitResult(new ResultStuckThingInThing(t, ot)); } //mxd. Prepare collections if (!processedthingpairs.ContainsKey(t.Index)) { processedthingpairs.Add(t.Index, new HashSet <int>()); } if (!processedthingpairs.ContainsKey(ot.Index)) { processedthingpairs.Add(ot.Index, new HashSet <int>()); } //mxd. Add both ways processedthingpairs[t.Index].Add(ot.Index); processedthingpairs[ot.Index].Add(t.Index); } } } } // Check this thing for being outside the map? if (!stuck && info.ErrorCheck >= ThingTypeInfo.THING_ERROR_INSIDE) { // Get the nearest line to see if the thing is outside the map bool outside; Linedef l = General.Map.Map.NearestLinedef(t.Position); if (l.SideOfLine(t.Position) <= 0) { outside = (l.Front == null); } else { outside = (l.Back == null); } // Outside the map? if (outside) { // Make result SubmitResult(new ResultThingOutside(t)); } } // Handle thread interruption try { Thread.Sleep(0); } catch (ThreadInterruptedException) { return; } // We are making progress! if ((++progress / PROGRESS_STEP) > stepprogress) { stepprogress = (progress / PROGRESS_STEP); AddProgress(1); } } }
// Mouse moves public override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // Not holding any buttons? if (e.Button == MouseButtons.None) { General.Interface.SetCursor(Cursors.Default); // Find the nearest linedef within highlight range Linedef l = General.Map.Map.NearestLinedef(mousemappos); if (l != null) { // 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 if (highlighted != null) { // Highlight nothing 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 if (highlighted != null) { // Highlight nothing Highlight(null); } } } else if (highlighted != null) { // Highlight nothing Highlight(null); } //mxd. Find the nearest linedef within default highlight range l = General.Map.Map.NearestLinedefRange(mousemappos, 20 / renderer.Scale); //mxd. We are not interested in single-sided lines, unless they have zoneboundary flag... if (l != null && ((l.Front == null || l.Back == null) && !l.IsFlagSet(ZoneBoundaryFlag))) { l = null; } //mxd. Set as highlighted bool redrawrequired = false; if (highlightedline != l) { highlightedline = l; redrawrequired = true; } //mxd. Highlighted environment changed? if (oldhighlightedsoundenvironment != highlightedsoundenvironment) { oldhighlightedsoundenvironment = highlightedsoundenvironment; redrawrequired = true; } //mxd. Find the nearest thing within default highlight range if (highlightedline == null && highlightedsoundenvironment != null) { Thing t = MapSet.NearestThingSquareRange(highlightedsoundenvironment.Things, mousemappos, 10 / renderer.Scale); if (highlightedthing != t) { highlightedthing = t; redrawrequired = true; } } else if (highlightedthing != null) { highlightedthing = null; redrawrequired = true; } //mxd if (redrawrequired) { // Show highlight info if (highlightedline != null && !highlightedline.IsDisposed) { General.Interface.ShowLinedefInfo(highlightedline); } else if (highlighted != null && !highlighted.IsDisposed) { General.Interface.ShowSectorInfo(highlighted); } else { General.Interface.HideInfo(); } // Redraw display General.Interface.RedrawDisplay(); } } }
// This makes sure we are updated with the source linedef information public override void Update() { if (l.Front == null || l.Back == null) { return; //mxd } // Find the vertex furthest from the line Vertex foundv = null; float founddist = -1.0f; foreach (Sidedef sd in data.Sector.Sidedefs) { Vertex v = sd.IsFront ? sd.Line.Start : sd.Line.End; float d = l.DistanceToSq(v.Position, false); if (d > founddist) { foundv = v; founddist = d; } } if (foundv == null) { return; //mxd } bool updatesides = false; // Align floor with back of line if ((l.Args[0] == 1) && (l.Front.Sector == data.Sector)) { Vector3D v1 = new Vector3D(l.Start.Position.x, l.Start.Position.y, l.Back.Sector.FloorHeight); Vector3D v2 = new Vector3D(l.End.Position.x, l.End.Position.y, l.Back.Sector.FloorHeight); Vector3D v3 = new Vector3D(foundv.Position.x, foundv.Position.y, data.Sector.FloorHeight); data.Floor.plane = (l.SideOfLine(v3) < 0.0f ? new Plane(v1, v2, v3, true) : new Plane(v2, v1, v3, true)); //mxd. Update only when actually changed if (storedfloor != data.Floor.plane) { storedfloor = data.Floor.plane; updatesides = true; } } // Align floor with front of line else if ((l.Args[0] == 2) && (l.Back.Sector == data.Sector)) { Vector3D v1 = new Vector3D(l.Start.Position.x, l.Start.Position.y, l.Front.Sector.FloorHeight); Vector3D v2 = new Vector3D(l.End.Position.x, l.End.Position.y, l.Front.Sector.FloorHeight); Vector3D v3 = new Vector3D(foundv.Position.x, foundv.Position.y, data.Sector.FloorHeight); data.Floor.plane = (l.SideOfLine(v3) < 0.0f ? new Plane(v1, v2, v3, true) : new Plane(v2, v1, v3, true)); //mxd. Update only when actually changed if (storedfloor != data.Floor.plane) { storedfloor = data.Floor.plane; updatesides = true; } } // Align ceiling with back of line if ((l.Args[1] == 1) && (l.Front.Sector == data.Sector)) { Vector3D v1 = new Vector3D(l.Start.Position.x, l.Start.Position.y, l.Back.Sector.CeilHeight); Vector3D v2 = new Vector3D(l.End.Position.x, l.End.Position.y, l.Back.Sector.CeilHeight); Vector3D v3 = new Vector3D(foundv.Position.x, foundv.Position.y, data.Sector.CeilHeight); data.Ceiling.plane = (l.SideOfLine(v3) > 0.0f ? new Plane(v1, v2, v3, false) : new Plane(v2, v1, v3, false)); //mxd. Update only when actually changed if (storedceiling != data.Ceiling.plane) { storedceiling = data.Ceiling.plane; updatesides = true; } } // Align ceiling with front of line else if ((l.Args[1] == 2) && (l.Back.Sector == data.Sector)) { Vector3D v1 = new Vector3D(l.Start.Position.x, l.Start.Position.y, l.Front.Sector.CeilHeight); Vector3D v2 = new Vector3D(l.End.Position.x, l.End.Position.y, l.Front.Sector.CeilHeight); Vector3D v3 = new Vector3D(foundv.Position.x, foundv.Position.y, data.Sector.CeilHeight); data.Ceiling.plane = (l.SideOfLine(v3) > 0.0f ? new Plane(v1, v2, v3, false) : new Plane(v2, v1, v3, false)); //mxd. Update only when actually changed if (storedceiling != data.Ceiling.plane) { storedceiling = data.Ceiling.plane; updatesides = true; } } //mxd. Update outer sidedef geometry if (updatesides) { UpdateSectorSides(data.Sector); // Update sectors with PlaneCopySlope Effect... List <SectorData> toupdate = new List <SectorData>(); foreach (Sector s in data.UpdateAlso.Keys) { SectorData osd = data.Mode.GetSectorDataEx(s); if (osd == null) { continue; } foreach (SectorEffect e in osd.Effects) { if (e is EffectPlaneCopySlope) { toupdate.Add(osd); break; } } } // Do it in 2 steps, because SectorData.Reset() may change SectorData.UpdateAlso collection... foreach (SectorData sd in toupdate) { // Update PlaneCopySlope Effect... sd.Reset(false); // Update outer sides... UpdateSectorSides(sd.Sector); } } }
// This makes sure we are updated with the source linedef information public override void Update() { ThingData td = data.Mode.GetThingData(thing); Thing t = thing; // Find the tagged line Linedef ld = null; foreach (Linedef l in General.Map.Map.Linedefs) { if (l.Tag == t.Args[0]) { ld = l; break; } } if (ld != null) { if (t.Type == 9500) { // Slope the floor from the linedef to thing t.DetermineSector(data.Mode.BlockMap); if (t.Sector != null) { Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.FloorHeight); if (ld.SideOfLine(t.Position) < 0.0f) { Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Front.Sector.FloorHeight); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Front.Sector.FloorHeight); SectorData sd = data.Mode.GetSectorData(ld.Front.Sector); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(ld.Front.Sector, true); sd.Floor.plane = new Plane(v1, v2, v3, true); } else { Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Back.Sector.FloorHeight); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Back.Sector.FloorHeight); SectorData sd = data.Mode.GetSectorData(ld.Back.Sector); sd.AddUpdateSector(data.Sector, true); if (!sd.Updated) { sd.Update(); } td.AddUpdateSector(ld.Back.Sector, true); sd.Floor.plane = new Plane(v2, v1, v3, true); } } } else if (t.Type == 9501) { // Slope the ceiling from the linedef to thing t.DetermineSector(data.Mode.BlockMap); if (t.Sector != null) { td.AddUpdateSector(t.Sector, true); Vector3D v3 = new Vector3D(t.Position.x, t.Position.y, t.Position.z + t.Sector.CeilHeight); if (ld.SideOfLine(t.Position) < 0.0f) { Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Front.Sector.CeilHeight); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Front.Sector.CeilHeight); SectorData sd = data.Mode.GetSectorData(ld.Front.Sector); sd.AddUpdateSector(data.Sector, true); td.AddUpdateSector(ld.Front.Sector, true); if (!sd.Updated) { sd.Update(); } sd.Ceiling.plane = new Plane(v1, v2, v3, false); } else { Vector3D v1 = new Vector3D(ld.Start.Position.x, ld.Start.Position.y, ld.Back.Sector.CeilHeight); Vector3D v2 = new Vector3D(ld.End.Position.x, ld.End.Position.y, ld.Back.Sector.CeilHeight); SectorData sd = data.Mode.GetSectorData(ld.Back.Sector); sd.AddUpdateSector(data.Sector, true); td.AddUpdateSector(ld.Back.Sector, true); if (!sd.Updated) { sd.Update(); } sd.Ceiling.plane = new Plane(v2, v1, v3, false); } } } } }
// Mode starts public override void OnEngage() { Cursor.Current = Cursors.WaitCursor; base.OnEngage(); General.Interface.DisplayStatus(StatusType.Busy, "Setting up test environment..."); CleanUp(); BuilderPlug.InterfaceForm.AddToInterface(); lastviewstats = BuilderPlug.InterfaceForm.ViewStats; // Export the current map to a temporary WAD file tempfile = BuilderPlug.MakeTempFilename(".wad"); General.Map.ExportToFile(tempfile); // Load the map in VPO_DLL BuilderPlug.VPO.Start(tempfile, General.Map.Options.LevelName); // Determine map boundary mapbounds = Rectangle.Round(MapSet.CreateArea(General.Map.Map.Vertices)); // Create tiles for all points inside the map Point lt = TileForPoint(mapbounds.Left - Tile.TILE_SIZE, mapbounds.Top - Tile.TILE_SIZE); Point rb = TileForPoint(mapbounds.Right + Tile.TILE_SIZE, mapbounds.Bottom + Tile.TILE_SIZE); Rectangle tilesrect = new Rectangle(lt.X, lt.Y, rb.X - lt.X, rb.Y - lt.Y); NearestLineBlockmap blockmap = new NearestLineBlockmap(tilesrect); for (int x = tilesrect.X; x <= tilesrect.Right; x += Tile.TILE_SIZE) { for (int y = tilesrect.Y; y <= tilesrect.Bottom; y += Tile.TILE_SIZE) { // If the tile is obviously outside the map, don't create it Vector2D pc = new Vector2D(x + (Tile.TILE_SIZE >> 1), y + (Tile.TILE_SIZE >> 1)); Linedef ld = MapSet.NearestLinedef(blockmap.GetBlockAt(pc).Lines, pc); float distancesq = ld.DistanceToSq(pc, true); if (distancesq > (Tile.TILE_SIZE * Tile.TILE_SIZE)) { float side = ld.SideOfLine(pc); if ((side > 0.0f) && (ld.Back == null)) { continue; } } Point tp = new Point(x, y); tiles.Add(tp, new Tile(tp)); } } QueuePoints(0); // Make an image to draw on. // The BitmapImage for Doom Builder's resources must be Format32bppArgb and NOT using color correction, // otherwise DB will make a copy of the bitmap when LoadImage() is called! This is normally not a problem, // but we want to keep drawing to the same bitmap. int width = General.NextPowerOf2(General.Interface.Display.ClientSize.Width); int height = General.NextPowerOf2(General.Interface.Display.ClientSize.Height); canvas = new Bitmap(width, height, PixelFormat.Format32bppArgb); image = new DynamicBitmapImage(canvas, "_CANVAS_"); image.UseColorCorrection = false; image.MipMapLevels = 1; image.LoadImage(); image.CreateTexture(); // Make custom presentation CustomPresentation p = new CustomPresentation(); p.AddLayer(new PresentLayer(RendererLayer.Overlay, BlendingMode.Mask, 1f, false)); p.AddLayer(new PresentLayer(RendererLayer.Grid, BlendingMode.Mask)); p.AddLayer(new PresentLayer(RendererLayer.Geometry, BlendingMode.Alpha, 1f, true)); renderer.SetPresentation(p); // Setup processing nextupdate = DateTime.Now + new TimeSpan(0, 0, 0, 0, 100); General.Interface.EnableProcessing(); processingenabled = true; RedrawAllTiles(); Cursor.Current = Cursors.Default; General.Interface.SetCursor(Cursors.Cross); General.Interface.DisplayReady(); }
// Mouse moves public override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // Not holding any buttons? if(e.Button == MouseButtons.None) { General.Interface.SetCursor(Cursors.Default); //mxd. Find the nearest linedef within default highlight range Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, 20 / renderer.Scale); //mxd. We are not interested in single-sided lines (unless they have "blocksound" flag set)... if(nl != null && (nl.Front == null || nl.Back == null) && !nl.IsFlagSet(BlockSoundFlag)) nl = null; //mxd. Set as highlighted bool redrawrequired = (highlightedline != nl); highlightedline = nl; // Find the nearest linedef within highlight range Linedef l = General.Map.Map.NearestLinedef(mousemappos); if(l != null) { // Check on which side of the linedef the mouse is double 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); redrawrequired = true; //mxd } } else if(highlighted != null) { // Highlight nothing Highlight(null); redrawrequired = true; //mxd } } else { // Is there a sidedef here? if(l.Front != null) { // Highlight if not the same if(l.Front.Sector != highlighted) { Highlight(l.Front.Sector); redrawrequired = true; //mxd } } else if(highlighted != null) { // Highlight nothing Highlight(null); redrawrequired = true; //mxd } } } else if(highlighted != null) { // Highlight nothing Highlight(null); redrawrequired = true; //mxd } //mxd if(redrawrequired) { // Show highlight info if(highlightedline != null && !highlightedline.IsDisposed) General.Interface.ShowLinedefInfo(highlightedline); else if(highlighted != null && !highlighted.IsDisposed) General.Interface.ShowSectorInfo(highlighted); else General.Interface.HideInfo(); // Redraw display General.Interface.RedrawDisplay(); } } }
// Mouse moves public override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // Not in any editing mode? if ((mode == ModifyMode.None) && (e.Button == MouseButtons.None)) { // Find the nearest linedef within highlight range Linedef l = General.Map.Map.NearestLinedef(mousemappos); if (l != null) { // 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); } } } } else { // Highlight nothing if (highlighted != null) { Highlight(null); } } } // Adjusting mode? else if (mode == ModifyMode.Adjusting) { // Calculate change in position Point delta = Cursor.Position - new Size(editstartpos); if (General.Interface.ShiftState) { // Adjust selected sectors int index = 0; ICollection <Sector> orderedselection = General.Map.Map.GetSelectedSectors(true); foreach (Sector s in orderedselection) { int basebrightness = sectorbrightness[index]; // Adjust brightness s.Brightness = basebrightness - delta.Y; if (s.Brightness > 255) { s.Brightness = 255; } if (s.Brightness < 0) { s.Brightness = 0; } index++; } } else { // Adjust selected sectors int index = 0; ICollection <Sector> orderedselection = General.Map.Map.GetSelectedSectors(true); foreach (Sector s in orderedselection) { int basebrightness = sectorbrightness[index]; // Adjust brightness s.Brightness = General.Map.Config.BrightnessLevels.GetNearest(basebrightness - delta.Y); index++; } } // Update General.Interface.RefreshInfo(); UpdateSelectedLabels(); UpdateOverlay(); renderer.Present(); } }
// This highlights a new region protected void Highlight(bool buttonspressed) { LinedefSide newnearest; // Mouse inside? if (mouseinside) { // Highlighting from a new sidedef? Linedef nl = General.Map.Map.NearestLinedef(mousemappos); if (nl != null) { float side = nl.SideOfLine(mousemappos); newnearest = new LinedefSide(nl, (side <= 0.0f)); if (newnearest != nearestside) { // Only change when buttons are not pressed if (!buttonspressed || (editside == newnearest)) { // Find new sector General.Interface.SetCursor(Cursors.AppStarting); nearestside = newnearest; allsides = Tools.FindPotentialSectorAt(mousemappos); if (allsides != null) { alllines = new List <Linedef>(allsides.Count); foreach (LinedefSide sd in allsides) { alllines.Add(sd.Line); } } else { alllines = null; } General.Interface.SetCursor(Cursors.Default); } else { // Don't highlight this one nearestside = null; allsides = null; alllines = null; } // Redraw overlay DrawGeometry(); renderer.Present(); } } } else { // No valid region nearestside = null; allsides = null; alllines = null; // Redraw overlay DrawGeometry(); renderer.Present(); } }
// Mode is engaged public override void OnEngage() { base.OnEngage(); // Update projection (mxd) General.Map.CRenderer3D.CreateProjection(); // Update the used textures General.Map.Data.UpdateUsedTextures(); // Fill the blockmap FillBlockMap(); //mxd. Synch camera position to cursor position or center of the screen in 2d-mode if (General.Settings.GZSynchCameras) { // Keep previous camera position if Control is held and camera was previously moved in Visual mode if (!General.Interface.CtrlState || General.Map.VisualCamera.Position.GetLengthSq() == 0) { //If initial position is inside or nearby a sector - adjust camera.z accordingly float posz = General.Map.VisualCamera.Position.z; Sector nearestsector = General.Map.Map.GetSectorByCoordinates(initialcameraposition, blockmap); if (nearestsector == null) { Linedef nearestline = MapSet.NearestLinedef(General.Map.Map.Linedefs, initialcameraposition); if (nearestline != null) { float side = nearestline.SideOfLine(initialcameraposition); Sidedef nearestside = (side < 0.0f ? nearestline.Front : nearestline.Back) ?? (side < 0.0f ? nearestline.Back : nearestline.Front); if (nearestside != null) { nearestsector = nearestside.Sector; } } } if (nearestsector != null) { int sectorheight = nearestsector.CeilHeight - nearestsector.FloorHeight; if (sectorheight < 41) { posz = nearestsector.FloorHeight + Math.Max(16, sectorheight / 2); } else if (General.Map.VisualCamera.Position.z < nearestsector.FloorHeight + 41) { posz = nearestsector.FloorHeight + 41; // same as in doom } else if (General.Map.VisualCamera.Position.z > nearestsector.CeilHeight) { posz = nearestsector.CeilHeight - 4; } } General.Map.VisualCamera.Position = new Vector3D(initialcameraposition.x, initialcameraposition.y, posz); } } else { General.Map.VisualCamera.PositionAtThing(); } // Start special input mode General.Interface.EnableProcessing(); General.Interface.StartExclusiveMouseInput(); }
//mxd protected void AlignTextureToClosestLine(bool alignx, bool aligny) { if (!(mode.HighlightedObject is BaseVisualSector)) { return; } // Do we need to align this? (and also grab texture scale while we are at it) float scaleX, scaleY; bool isFloor = (geometrytype == VisualGeometryType.FLOOR); if (mode.HighlightedTarget is VisualFloor) { Sector target; VisualFloor vf = (VisualFloor)mode.HighlightedTarget; // Use the control sector if the floor belongs to a 3D floor if (vf.ExtraFloor == null) { target = vf.Sector.Sector; } else { target = vf.GetControlSector(); } // Check texture if (target.FloorTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Fields.GetValue("xscalefloor", 1.0f); scaleY = target.Fields.GetValue("yscalefloor", 1.0f); } else { Sector target; VisualCeiling vc = (VisualCeiling)mode.HighlightedTarget; // Use the control sector if the ceiling belongs to a 3D floor if (vc.ExtraFloor == null) { target = vc.Sector.Sector; } else { target = vc.GetControlSector(); } // Check texture if (target.CeilTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Fields.GetValue("xscaleceiling", 1.0f); scaleY = target.Fields.GetValue("yscaleceiling", 1.0f); } //find a linedef to align to Vector2D hitpos = mode.GetHitPosition(); if (!hitpos.IsFinite()) { return; } //align to line of highlighted sector, which is closest to hitpos Sector highlightedSector = ((BaseVisualSector)mode.HighlightedObject).Sector; List <Linedef> lines = new List <Linedef>(); foreach (Sidedef side in highlightedSector.Sidedefs) { lines.Add(side.Line); } Linedef targetLine = MapSet.NearestLinedef(lines, hitpos); if (targetLine == null) { return; } bool isFront = targetLine.SideOfLine(hitpos) > 0; Sector.Sector.Fields.BeforeFieldsChange(); //find an angle to rotate texture float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(targetLine.Angle) + 90 : -Angle2D.RadToDeg(targetLine.Angle) - 90), 1); if (!isFront) { sourceAngle = General.ClampAngle(sourceAngle + 180); } //update angle UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f); // Scale texture if it's a slope and the appropriate option is set if (level.plane.Normal.z != 1.0f && BuilderPlug.Me.ScaleTexturesOnSlopes != 2) { Vector2D basescale = new Vector2D(1.0f, 1.0f); // User wants to use the current scale as a base? if (BuilderPlug.Me.ScaleTexturesOnSlopes == 1) { basescale.x = scaleX; basescale.y = scaleY; } // Create a unit vector of the direction of the target line in 3D space Vector3D targetlinevector = new Line3D(new Vector3D(targetLine.Start.Position, level.plane.GetZ(targetLine.Start.Position)), new Vector3D(targetLine.End.Position, level.plane.GetZ(targetLine.End.Position))).GetDelta().GetNormal(); // Get a perpendicular vector of the target line in 3D space. This is used to get the slope angle relative to the target line Vector3D targetlineperpendicular = Vector3D.CrossProduct(targetlinevector, level.plane.Normal); if (alignx) { scaleX = Math.Abs(basescale.x * (1.0f / (float)Math.Cos(targetlinevector.GetAngleZ()))); } if (aligny) { scaleY = Math.Abs(basescale.y * (1.0f / (float)Math.Cos(targetlineperpendicular.GetAngleZ()))); } } //set scale UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xscalefloor" : "xscaleceiling"), scaleX, 1.0f); UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "yscalefloor" : "yscaleceiling"), scaleY, 1.0f); //update offset float distToStart = Vector2D.Distance(hitpos, targetLine.Start.Position); float distToEnd = Vector2D.Distance(hitpos, targetLine.End.Position); Vector2D offset = (distToStart < distToEnd ? targetLine.Start.Position : targetLine.End.Position).GetRotated(Angle2D.DegToRad(sourceAngle)); if (alignx) { if (Texture != null && Texture.IsImageLoaded) { offset.x %= Texture.Width / scaleX; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f); } if (aligny) { if (Texture != null && Texture.IsImageLoaded) { offset.y %= Texture.Height / scaleY; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f); } //update geometry Sector.UpdateSectorGeometry(false); }
// Mouse moving public override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (selecting) { ClearHighlighted(); RenderMultiSelection(); } else { // ano - a lot of this is from codeimp's buildermodes plugins if (e.Button == MouseButtons.None) { Linedef l = General.Map.Map.NearestLinedefRange( mousemappos, HIGHLIGHT_RANGE / renderer.Scale); Thing t = MapSet.NearestThingSquareRange( General.Map.ThingsFilter.VisibleThings, mousemappos, HIGHLIGHT_THINGS_RANGE / renderer.Scale); Vertex v = General.Map.Map.NearestVertexSquareRange( mousemappos, HIGHLIGHT_VERTICES_RANGE / renderer.Scale); Sector s = null; Linedef ls = l; if (ls == null) { ls = General.Map.Map.NearestLinedef(mousemappos); } if (ls != null) { // Check on which side of the linedef the mouse is float side = ls.SideOfLine(mousemappos); if (side > 0) { // Is there a sidedef here? if (ls.Back != null) { s = ls.Back.Sector; } } else if (ls.Front != null) { s = ls.Front.Sector; } } HighlightType htype = HighlightType.Null; if (v != null) { htype = HighlightType.Vertex; } if (t != null) { if (htype == HighlightType.Null) { htype = HighlightType.Thing; } else if (htype == HighlightType.Vertex && v.DistanceToSq(mousemappos) > t.DistanceToSq(mousemappos)) { // figure out which is closer and highlight that one htype = HighlightType.Thing; } } if (l != null) { switch (htype) { case HighlightType.Vertex: break; case HighlightType.Thing: if (l.SafeDistanceToSq(mousemappos, false) < t.DistanceToSq(mousemappos)) { // figure out which is closer and highlight that one htype = HighlightType.Linedef; } break; default: htype = HighlightType.Linedef; break; } } if (htype == HighlightType.Null && s != null) { htype = HighlightType.Sector; } switch (htype) { case HighlightType.Linedef: HighlightLinedef(l); break; case HighlightType.Sector: HighlightSector(s); break; case HighlightType.Vertex: HighlightVertex(v); break; case HighlightType.Thing: HighlightThing(t); break; case HighlightType.Null: default: // highlight nothing ClearHighlighted(); renderer.Present(); break; } // switch } if (renderer.StartOverlay(true)) { DrawCursor(); renderer.Finish(); renderer.Present(); } } }
//mxd protected void AlignTextureToClosestLine(bool alignx, bool aligny) { if (!(mode.HighlightedObject is BaseVisualSector)) { return; } // Do we need to align this? (and also grab texture scale while we are at it) float scaleX, scaleY; bool isFloor = (geometrytype == VisualGeometryType.FLOOR); if (mode.HighlightedTarget is VisualFloor) { VisualFloor target = (VisualFloor)mode.HighlightedTarget; // Check texture if (target.Sector.Sector.FloorTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Sector.Sector.Fields.GetValue("xscalefloor", 1.0f); scaleY = target.Sector.Sector.Fields.GetValue("yscalefloor", 1.0f); } else { VisualCeiling target = (VisualCeiling)mode.HighlightedTarget; // Check texture if (target.Sector.Sector.CeilTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture)) { return; } scaleX = target.Sector.Sector.Fields.GetValue("xscaleceiling", 1.0f); scaleY = target.Sector.Sector.Fields.GetValue("yscaleceiling", 1.0f); } //find a linedef to align to Vector2D hitpos = mode.GetHitPosition(); if (!hitpos.IsFinite()) { return; } //align to line of highlighted sector, which is closest to hitpos Sector highlightedSector = ((BaseVisualSector)mode.HighlightedObject).Sector; List <Linedef> lines = new List <Linedef>(); foreach (Sidedef side in highlightedSector.Sidedefs) { lines.Add(side.Line); } Linedef targetLine = MapSet.NearestLinedef(lines, hitpos); if (targetLine == null) { return; } bool isFront = targetLine.SideOfLine(hitpos) > 0; Sector.Sector.Fields.BeforeFieldsChange(); //find an angle to rotate texture float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(targetLine.Angle) + 90 : -Angle2D.RadToDeg(targetLine.Angle) - 90), 1); if (!isFront) { sourceAngle = General.ClampAngle(sourceAngle + 180); } //update angle UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f); //set scale UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xscalefloor" : "xscaleceiling"), scaleX, 1.0f); UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "yscalefloor" : "yscaleceiling"), scaleY, 1.0f); //update offset float distToStart = Vector2D.Distance(hitpos, targetLine.Start.Position); float distToEnd = Vector2D.Distance(hitpos, targetLine.End.Position); Vector2D offset = (distToStart < distToEnd ? targetLine.Start.Position : targetLine.End.Position).GetRotated(Angle2D.DegToRad(sourceAngle)); if (alignx) { if (Texture != null && Texture.IsImageLoaded) { offset.x %= Texture.Width / scaleX; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f); } if (aligny) { if (Texture != null && Texture.IsImageLoaded) { offset.y %= Texture.Height / scaleY; } UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f); } //update geometry Sector.UpdateSectorGeometry(false); }
// Mouse moves public override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (selectpressed && !editpressed && !selecting) { // Check if moved enough pixels for multiselect Vector2D delta = mousedownpos - mousepos; if ((Math.Abs(delta.x) > 2) || (Math.Abs(delta.y) > 2)) { // Start multiselecting StartMultiSelection(); } } else if (e.Button == MouseButtons.None) { SlopeVertex oldhighlight = highlightedslope; Sector oldhighlightedsector = highlightedsector; float distance = float.MaxValue; float d; highlightedslope = null; foreach (SlopeVertexGroup svg in BuilderPlug.Me.SlopeVertexGroups) { foreach (SlopeVertex sv in svg.Vertices) { d = Vector2D.Distance(sv.Pos, mousemappos); if (d <= BuilderModes.BuilderPlug.Me.HighlightRange / renderer.Scale && d < distance) { distance = d; highlightedslope = sv; } } } // If no slope vertex is highlighted, check if a sector should be if (highlightedslope == null) { // Find the nearest linedef within highlight range Linedef l = General.Map.Map.NearestLinedef(mousemappos); if (l != null) { // 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 != highlightedsector) { HighlightSector(l.Back.Sector); } } else { // Highlight nothing if (highlightedsector != null) { HighlightSector(null); } } } else { // Is there a sidedef here? if (l.Front != null) { // Highlight if not the same if (l.Front.Sector != highlightedsector) { HighlightSector(l.Front.Sector); } } else { // Highlight nothing if (highlightedsector != null) { HighlightSector(null); } } } } } else { HighlightSector(null); } if (highlightedslope != oldhighlight) { updateOverlaySurfaces(); UpdateOverlay(); General.Interface.RedrawDisplay(); } } else if (dragging && highlightedslope != null) { Vector2D newpos = SnapToNearest(mousemappos); Vector2D offset = highlightedslope.Pos - newpos; foreach (SlopeVertex sl in GetSelectedSlopeVertices()) { sl.Pos -= offset; } highlightedslope.Pos = newpos; General.Map.IsChanged = true; updateOverlaySurfaces(); UpdateOverlay(); General.Interface.RedrawDisplay(); } else if (selecting) { UpdateOverlay(); General.Interface.RedrawDisplay(); } }
// This runs the check public override void Run() { BlockMap <BlockEntry> blockmap = BuilderPlug.Me.ErrorCheckForm.BlockMap; int progress = 0; int stepprogress = 0; // Go for all the things foreach (Thing t in General.Map.Map.Things) { ThingTypeInfo info = General.Map.Data.GetThingInfo(t.Type); bool stucked = false; // Check this thing for getting stucked? if ((info.ErrorCheck == ThingTypeInfo.THING_ERROR_INSIDE_STUCKED) && (info.Blocking > ThingTypeInfo.THING_BLOCKING_NONE)) { // Make square coordinates from thing float blockingsize = t.Size - ALLOWED_STUCK_DISTANCE; Vector2D lt = new Vector2D(t.Position.x - blockingsize, t.Position.y - blockingsize); Vector2D rb = new Vector2D(t.Position.x + blockingsize, t.Position.y + blockingsize); // Go for all the lines to see if this thing is stucked List <BlockEntry> blocks = blockmap.GetSquareRange(new RectangleF(lt.x, lt.y, (rb.x - lt.x), (rb.y - lt.y))); Dictionary <Linedef, Linedef> doneblocklines = new Dictionary <Linedef, Linedef>(blocks.Count * 3); foreach (BlockEntry b in blocks) { foreach (Linedef l in b.Lines) { // Only test when sinlge-sided and not already checked if ((l.Back == null) && !doneblocklines.ContainsKey(l)) { // Test if line ends are inside the thing if (PointInRect(lt, rb, l.Start.Position) || PointInRect(lt, rb, l.End.Position)) { // Thing stucked in line! stucked = true; } // Test if the line intersects the square else if (Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, lt.y, rb.x, lt.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, lt.y, rb.x, rb.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, rb.x, rb.y, lt.x, rb.y) || Line2D.GetIntersection(l.Start.Position, l.End.Position, lt.x, rb.y, lt.x, lt.y)) { // Thing stucked in line! stucked = true; } // Checked doneblocklines.Add(l, l); } } } } // Stucked? if (stucked) { // Make result SubmitResult(new ResultStuckedThing(t)); } else { // Check this thing for being outside the map? if (info.ErrorCheck >= ThingTypeInfo.THING_ERROR_INSIDE) { // Get the nearest line to see if the thing is outside the map bool outside = false; Linedef l = General.Map.Map.NearestLinedef(t.Position); if (l.SideOfLine(t.Position) <= 0) { outside = (l.Front == null); } else { outside = (l.Back == null); } // Outside the map? if (outside) { // Make result SubmitResult(new ResultThingOutside(t)); } } } // Handle thread interruption try { Thread.Sleep(0); } catch (ThreadInterruptedException) { return; } // We are making progress! if ((++progress / PROGRESS_STEP) > stepprogress) { stepprogress = (progress / PROGRESS_STEP); AddProgress(1); } } }
// This makes sure we are updated with the source linedef information public override void Update() { Linedef l = linedef; // Find the vertex furthest from the line Vertex foundv = null; float founddist = -1.0f; foreach (Sidedef sd in data.Sector.Sidedefs) { Vertex v = sd.IsFront ? sd.Line.Start : sd.Line.End; float d = l.DistanceToSq(v.Position, false); if (d > founddist) { foundv = v; founddist = d; } } // Align floor with back of line if ((l.Args[0] == 1) && (l.Front.Sector == data.Sector) && (l.Back != null)) { Vector3D v1 = new Vector3D(l.Start.Position.x, l.Start.Position.y, l.Back.Sector.FloorHeight); Vector3D v2 = new Vector3D(l.End.Position.x, l.End.Position.y, l.Back.Sector.FloorHeight); Vector3D v3 = new Vector3D(foundv.Position.x, foundv.Position.y, data.Sector.FloorHeight); if (l.SideOfLine(v3) < 0.0f) { data.Floor.plane = new Plane(v1, v2, v3, true); } else { data.Floor.plane = new Plane(v2, v1, v3, true); } SectorData sd = data.Mode.GetSectorData(l.Back.Sector); sd.AddUpdateSector(data.Sector, true); } // Align floor with front of line else if ((l.Args[0] == 2) && (l.Back.Sector == data.Sector) && (l.Front != null)) { Vector3D v1 = new Vector3D(l.Start.Position.x, l.Start.Position.y, l.Front.Sector.FloorHeight); Vector3D v2 = new Vector3D(l.End.Position.x, l.End.Position.y, l.Front.Sector.FloorHeight); Vector3D v3 = new Vector3D(foundv.Position.x, foundv.Position.y, data.Sector.FloorHeight); if (l.SideOfLine(v3) < 0.0f) { data.Floor.plane = new Plane(v1, v2, v3, true); } else { data.Floor.plane = new Plane(v2, v1, v3, true); } SectorData sd = data.Mode.GetSectorData(l.Front.Sector); sd.AddUpdateSector(data.Sector, true); } // Align ceiling with back of line if ((l.Args[1] == 1) && (l.Front.Sector == data.Sector) && (l.Back != null)) { Vector3D v1 = new Vector3D(l.Start.Position.x, l.Start.Position.y, l.Back.Sector.CeilHeight); Vector3D v2 = new Vector3D(l.End.Position.x, l.End.Position.y, l.Back.Sector.CeilHeight); Vector3D v3 = new Vector3D(foundv.Position.x, foundv.Position.y, data.Sector.CeilHeight); if (l.SideOfLine(v3) > 0.0f) { data.Ceiling.plane = new Plane(v1, v2, v3, false); } else { data.Ceiling.plane = new Plane(v2, v1, v3, false); } SectorData sd = data.Mode.GetSectorData(l.Back.Sector); sd.AddUpdateSector(data.Sector, true); } // Align ceiling with front of line else if ((l.Args[1] == 2) && (l.Back.Sector == data.Sector) && (l.Front != null)) { Vector3D v1 = new Vector3D(l.Start.Position.x, l.Start.Position.y, l.Front.Sector.CeilHeight); Vector3D v2 = new Vector3D(l.End.Position.x, l.End.Position.y, l.Front.Sector.CeilHeight); Vector3D v3 = new Vector3D(foundv.Position.x, foundv.Position.y, data.Sector.CeilHeight); if (l.SideOfLine(v3) > 0.0f) { data.Ceiling.plane = new Plane(v1, v2, v3, false); } else { data.Ceiling.plane = new Plane(v2, v1, v3, false); } SectorData sd = data.Mode.GetSectorData(l.Front.Sector); sd.AddUpdateSector(data.Sector, true); } }