private List <List <RelevantRoom> > groupBuildRoomSequences(Vector2 cursorPos, int groupIndex) { // Decide what bar is at the given index Vector2 probePos = groupIndex == DepthProbes.Count ? cursorPos : DepthProbes[groupIndex].Position; bool shouldCheckRoomsToMove = groupIndex == DepthProbes.Count && _roomsToMove != null; // Iterate over all rooms under the cursor and add them to the room sequences IEnumerable <Room> sortedRoomList = _editor.Level.GetVerticallyAscendingRoomList(room => { Vector2 roomLocal = probePos - room.SectorPos; bool CollidesWithProbe = roomLocal.X >= 1 && roomLocal.Y >= 1 && roomLocal.X < room.NumXSectors - 1 && roomLocal.Y < room.NumZSectors - 1; return(shouldCheckRoomsToMove ? _roomsToMove.Contains(room) : CollidesWithProbe); }); var roomSequences = new List <List <RelevantRoom> >(); foreach (Room room in sortedRoomList) { Vector2 roomLocal = probePos - room.SectorPos; bool CollidesWithProbe = roomLocal.X >= 1 && roomLocal.Y >= 1 && roomLocal.X < room.NumXSectors - 1 && roomLocal.Y < room.NumZSectors - 1; Block block = CollidesWithProbe ? room.Blocks[(int)roomLocal.X, (int)roomLocal.Y] : null; RelevantRoom relevantRoom = new RelevantRoom { Room = room, Block = block, MinDepth = room.Position.Y + room.GetLowestCorner(), MaxDepth = room.Position.Y + room.GetHighestCorner() }; // Search for a fit in the sequence for rooms it the current room is connected to on this sector if (block != null && block.FloorPortal != null) { var portal = block.FloorPortal; var roomAbove = portal.AdjoiningRoom; foreach (var roomSequence in roomSequences) { if (roomSequence.Last().Room == roomAbove) { roomSequence.Add(relevantRoom); goto AddedRoomSucessfully; } } } roomSequences.Add(new List <RelevantRoom>()); roomSequences.Last().Add(relevantRoom); AddedRoomSucessfully: ; } // Also try moving rooms into the same sequence that are connected directly, just not on the square that is selected for (int i = 1; i < roomSequences.Count; ++i) // triangular iteration { var roomSequenceAbove = roomSequences[i]; foreach (var portal in roomSequenceAbove[0].Room.Portals) { var connectedRoom = portal.AdjoiningRoom; for (int j = 0; j < i; ++j) { var roomSequenceBelow = roomSequences[j]; if (roomSequences[j].Last().Room != connectedRoom) { continue; } float distanceBetweenSequences = roomSequenceAbove[0].MinDepth - roomSequenceBelow.Last().MaxDepth; if (!(distanceBetweenSequences >= 0.0)) { continue; } roomSequences[j].AddRange(roomSequences[i]); roomSequences.RemoveAt(i); --i; goto NextRoom; } } NextRoom: ; } // Try to merge independent sequences if they are sufficently far apart for (int i = 0; i < roomSequences.Count; ++i) { var roomSequenceAbove = roomSequences[i]; for (int j = 0; j < roomSequences.Count; ++j) { var roomSequenceBelow = roomSequences[j]; float distanceBetweenSequences = roomSequenceAbove[0].MinDepth - roomSequenceBelow.Last().MaxDepth; if (distanceBetweenSequences >= _minDepthDifferenceBetweenIndependentlyMergedSequences) { roomSequenceBelow.AddRange(roomSequenceAbove); roomSequences.RemoveAt(i); --i; goto NextRoom; } } NextRoom: ; } return(roomSequences); }
public void Draw(PaintEventArgs e, Size parentControlSize, Vector2 cursorPos, Func <Room, Brush, ConditionallyOwned <Brush> > getRoomBrush) { RectangleF barArea = getBarArea(parentControlSize); float selectedLimit0PosY = ToVisualY(barArea, _selectedLimit0); float selectedLimit1PosY = ToVisualY(barArea, _selectedLimit1); // Draw box e.Graphics.FillRectangle(_backgroundBrush, barArea); // Draw height lines if (barArea.IntersectsWith(e.ClipRectangle)) { e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; for (int depth = (int)MinDepth; depth <= (int)MaxDepth; ++depth) { float posY = ToVisualY(barArea, depth); e.Graphics.DrawLine(_heightLinesPen, barArea.Left, posY, barArea.Right, posY); } e.Graphics.SmoothingMode = SmoothingMode.Default; } // Draw height strings for (int i = 0; i <= _heightStringCount; ++i) { float depth = MaxDepth - (MaxDepth - MinDepth) / _heightStringCount * i; float posY = ToVisualY(barArea, depth); // Hide height string when close to selection limits float distanceToSelectionLimit0 = Math.Abs(posY - selectedLimit0PosY); float distanceToSelectionLimit1 = Math.Abs(posY - selectedLimit1PosY); float distance = Math.Min(distanceToSelectionLimit0, distanceToSelectionLimit1) - _heightStringFont.Height * 0.85f; if (distance > _heightStringFadeDistance) { DrawHeightString(e, barArea, _outlinePen, (float)Math.Round(depth)); if (i > 0 && i < _heightStringCount) { e.Graphics.DrawLine(_heightLinesBigPen, barArea.Left, posY, barArea.Right, posY); } } else if (distance > 0.0f) { using (var alphaOutlinePen = (Pen)_outlinePen.Clone()) { alphaOutlinePen.Color = Color.FromArgb((int)(alphaOutlinePen.Color.A * (distance / _heightStringFadeDistance)), alphaOutlinePen.Color.R, alphaOutlinePen.Color.G, alphaOutlinePen.Color.B); DrawHeightString(e, barArea, alphaOutlinePen, (float)Math.Round(depth)); } if (i > 0 && i < _heightStringCount) { using (var alphaPen = (Pen)_heightLinesBigPen.Clone()) { alphaPen.Color = Color.FromArgb((int)(alphaPen.Color.A * (distance / _heightStringFadeDistance)), alphaPen.Color.R, alphaPen.Color.G, alphaPen.Color.B); e.Graphics.DrawLine(alphaPen, barArea.Left, posY, barArea.Right, posY); } } } } // Draw common selection range DrawHeightString(e, barArea, _selectionPen, _selectedLimit0, true); DrawHeightString(e, barArea, _selectionPen, _selectedLimit1, true); RectangleF selectionRect = new RectangleF(new PointF(barArea.Left, Math.Min(selectedLimit1PosY, selectedLimit0PosY)), new SizeF(_barWidth, Math.Abs(selectedLimit0PosY - selectedLimit1PosY))); e.Graphics.FillRectangle(_selectionBrush, selectionRect); // Draw probe selection ranges if (!barArea.Contains(e.ClipRectangle)) { for (int groupIndex = 0; groupIndex < DepthProbes.Count; ++groupIndex) { RectangleF groupArea = groupGetArea(barArea, groupIndex); selectionRect = new RectangleF(new PointF(groupArea.Left, Math.Min(selectedLimit1PosY, selectedLimit0PosY)), new SizeF(groupArea.Width, Math.Abs(selectedLimit0PosY - selectedLimit1PosY))); using (var b = new SolidBrush(Color.FromArgb(60, DepthProbes[groupIndex].Color.R, DepthProbes[groupIndex].Color.G, DepthProbes[groupIndex].Color.B))) e.Graphics.FillRectangle(b, selectionRect); } } // Draw depth bar content if (barArea.IntersectsWith(e.ClipRectangle)) { // Draw group for (int groupIndex = 0; groupIndex < GroupCount; ++groupIndex) { RectangleF groupArea = groupGetArea(barArea, groupIndex); if (!groupArea.IntersectsWith(e.ClipRectangle)) { continue; } // Draw sequences List <List <RelevantRoom> > roomSequences = groupBuildRoomSequences(cursorPos, groupIndex); float sequenceWidth = groupArea.Width / roomSequences.Count; for (int roomSequenceIndex = 0; roomSequenceIndex < roomSequences.Count; ++roomSequenceIndex) { var roomSequence = roomSequences[roomSequenceIndex]; float posX0 = groupArea.X + sequenceWidth * roomSequenceIndex; float posX1 = groupArea.X + sequenceWidth * (roomSequenceIndex + 1); for (int i = 0; i < roomSequence.Count; ++i) { RelevantRoom room = roomSequence[i]; float posY0 = ToVisualY(groupArea, room.MaxDepth); float posY1 = ToVisualY(groupArea, room.MinDepth); // HACK: if a rooms is full of walls (but why a designer should do this???) then // MaxDepth or MinDepth can be int.MinValue or int.MaxValue and posY0 or posY1 get f****d... // However I'm solving the issue elsewhere, this hack is here as a really last chance for // the 0.0000000001% of the cases that could be wrong if (Math.Abs(posY0) >= short.MaxValue || Math.Abs(posY1) >= short.MaxValue) { continue; } // Draw fill color for room Brush colorBrush = _roomsNormalBrush; RectangleF roomRect = new RectangleF(posX0, posY0, posX1 - posX0, posY1 - posY0); if (room.Block != null && room.Block.Type != BlockType.Floor) { colorBrush = _roomsWallBrush; } using (var colorBrush2 = getRoomBrush(room.Room, colorBrush)) e.Graphics.FillRectangle(colorBrush2, roomRect); if (!CheckRoom(room.MinDepth, room.MaxDepth)) { e.Graphics.FillRectangle(_roomsOutsideOverdraw, roomRect); } if (room.Room.Locked) { e.Graphics.FillRectangle(_roomsLockedBrush, roomRect); } // Find portals on the selected sector Pen belowPen = _roomBoundsPen; if (room.Block != null && room.Block.FloorPortal != null) { Room portalRoom = room.Block.FloorPortal.AdjoiningRoom; if (i - 1 >= 0 && roomSequence[i - 1].Room == portalRoom) { belowPen = _portalPen; } } Pen abovePen = _roomBoundsPen; if (room.Block != null && room.Block.CeilingPortal != null) { Room portalRoom = room.Block.CeilingPortal.AdjoiningRoom; if (i + 1 < roomSequence.Count && roomSequence[i + 1].Room == portalRoom) { abovePen = _portalPen; } } //Draw room borders e.Graphics.DrawLine(belowPen, posX0, posY1, posX1, posY1); e.Graphics.DrawLine(abovePen, posX0, posY0, posX1, posY0); e.Graphics.DrawLine(_sequenceSeperatorPen, posX0, posY0, posX0, posY1); e.Graphics.DrawLine(_sequenceSeperatorPen, posX1, posY0, posX1, posY1); } } } } // Draw outline around the groups for (int groupIndex = 0; groupIndex < GroupCount; ++groupIndex) { RectangleF groupArea = groupGetArea(barArea, groupIndex); e.Graphics.DrawRectangle(_outlinePen, groupArea); } }