private static bool RectToRect(Collider a, Collider b, Point2 offset) { RectInt ar = a.rect + a.Entity.Position + offset; RectInt br = b.rect + b.Entity.Position; return(ar.Overlaps(br)); }
private static RectInt GetNewRoomLocation(List <Data.Room> rooms, List <RectInt> placeholders) { for (int i = 0; i < 10; i++) { int2 randomMapPosition = Util.Map.GetRandomMapPosition(); RectInt roomBounds = new RectInt( new Vector2Int(randomMapPosition.x, randomMapPosition.y), new Vector2Int(Info.Map.SeedRoomSize, Info.Map.SeedRoomSize) ); bool collision = false; if (Util.Map.OnMap(roomBounds) == false) { collision = true; } else { foreach (Data.Room room in rooms) { if (roomBounds.Overlaps(room.Bounds)) { collision = true; } } foreach (RectInt placeholder in placeholders) { if (roomBounds.Overlaps(placeholder)) { collision = true; } } } if (collision == false) { return(roomBounds); } } return(new RectInt(0, 0, 0, 0)); }
public static float CollideArea(this RectInt a, RectInt b) { if (a.Overlaps(b)) { float width = Mathf.Min(a.xMax, b.xMax) - Mathf.Max(a.xMin, b.xMin); float height = Mathf.Min(a.yMax, b.yMax) - Mathf.Max(a.yMin, b.yMin); return(width * height); } return(0); }
public static bool RayRectIntersect(Vector2Int origin, Vector2Int delta, RectInt rect, out Vector2Int preContact, out Vector2Int contactNormal) { // # Bounding Box Check Vector2Int raySize = Vector2Int.Max(Vector2Int.one, new Vector2Int(Mathf.Abs(delta.x), Mathf.Abs(delta.y))); Vector2Int rayDst = origin + delta; Vector2Int rayCorner = Vector2Int.Min(origin, origin + delta); RectInt rayBoundingBox = new RectInt(rayCorner.x, rayCorner.y, raySize.x, raySize.y); if (rayBoundingBox.Overlaps(rect) == false) { contactNormal = Vector2Int.zero; preContact = Vector2Int.zero; return(false); } // Wall Checks Vector2Int?southHit = RayOrthoLineIntersect(origin, delta, rect.position, true, rect.width); Vector2Int?northHit = RayOrthoLineIntersect(origin, delta, rect.max, true, -rect.width); Vector2Int?westHit = RayOrthoLineIntersect(origin, delta, rect.position, false, rect.height); Vector2Int?eastHit = RayOrthoLineIntersect(origin, delta, rect.max, false, -rect.height); Vector2Int?NSCloser = GetCloser(origin, southHit, northHit); Vector2Int?EWCloser = GetCloser(origin, westHit, eastHit); Vector2Int?closest = GetCloser(origin, NSCloser, EWCloser); preContact = closest ?? Vector2Int.zero; if (closest.HasValue) { if (closest == southHit) { contactNormal = Vector2Int.down; } else if (closest == northHit) { contactNormal = Vector2Int.up; } else if (closest == westHit) { contactNormal = Vector2Int.left; } else { contactNormal = Vector2Int.right; } } else { contactNormal = Vector2Int.zero; } return(closest.HasValue); }
public static bool Intersects(this RectInt a, RectInt b, out RectInt area) { area = new RectInt(); if (b.Overlaps(a)) { int x1 = Mathf.Min(a.xMax, b.xMax); int x2 = Mathf.Max(a.xMin, b.xMin); int y1 = Mathf.Min(a.yMax, b.yMax); int y2 = Mathf.Max(a.yMin, b.yMin); area.x = Mathf.Min(x1, x2); area.y = Mathf.Min(y1, y2); area.width = Mathf.Max(0, x1 - x2); area.height = Mathf.Max(0, y1 - y2); return(true); } return(false); }
// TODO: mimic logical & operation from Phil.Core.RectInt public static bool TryGetRectIntersection(RectInt a, RectInt b, out RectInt intersection) { if (!a.Overlaps(b)) { intersection = new RectInt(0, 0, 0, 0); return(false); } else { var aMax = a.TrueMax(); var bMax = b.TrueMax(); int maxLeft = Mathf.Max(a.xMin, b.xMin); int minRight = Mathf.Min(aMax.x, bMax.x); int minTop = Mathf.Min(aMax.y, bMax.y); int maxBot = Mathf.Max(a.yMin, b.yMin); int width = minRight - maxLeft + 1; int height = minTop - maxBot + 1; intersection = new RectInt(maxLeft, maxBot, width, height); return(true); } }
/// <summary> /// Checks if a given area in the container is free /// </summary> /// <param name="area">The area to check</param> /// <returns>If the given area is free</returns> public bool IsAreaFree(RectInt area) { if (area.xMin < 0 || area.xMax < 0) { return(false); } if (area.xMax > Size.x || area.yMax > Size.y) { return(false); } foreach (StoredItem storedItem in items) { var storedItemPlacement = new RectInt(storedItem.Position, storedItem.Item.Size); if (area.Overlaps(storedItemPlacement)) { return(false); } } return(true); }
internal void ExecuteNonDrawMesh(DrawParams drawParams, float pixelsPerPoint, ref Exception immediateException) { switch (type) { case CommandType.ImmediateCull: { RectInt worldRect = RectPointsToPixelsAndFlipYAxis(owner.worldBound, pixelsPerPoint); if (!worldRect.Overlaps(Utility.GetActiveViewport())) { break; } // Element isn't culled, follow through the normal immediate callback procedure goto case CommandType.Immediate; } case CommandType.Immediate: { if (immediateException != null) { break; } s_ImmediateOverheadMarker.Begin(); Matrix4x4 oldProjection = Utility.GetUnityProjectionMatrix(); Camera oldCamera = Camera.current; RenderTexture oldRT = RenderTexture.active; bool hasScissor = drawParams.scissor.Count > 1; // We always expect the "unbound" scissor rectangle to exists if (hasScissor) { Utility.DisableScissor(); // Disable scissor since most IMGUI code assume it's inactive } using (new GUIClip.ParentClipScope(owner.worldTransform, owner.worldClip)) { s_ImmediateOverheadMarker.End(); try { callback(); } catch (Exception e) { immediateException = e; } s_ImmediateOverheadMarker.Begin(); } Camera.SetupCurrent(oldCamera); RenderTexture.active = oldRT; GL.modelview = drawParams.view.Peek().transform; GL.LoadProjectionMatrix(oldProjection); if (hasScissor) { Utility.SetScissorRect(RectPointsToPixelsAndFlipYAxis(drawParams.scissor.Peek(), pixelsPerPoint)); } s_ImmediateOverheadMarker.End(); break; } case CommandType.PushView: var parent = owner.hierarchy.parent; Vector4 clipRect; if (parent != null) { clipRect = RectToClipSpace(parent.worldClip); } else { clipRect = UIRUtility.ToVector4(DrawParams.k_FullNormalizedRect); } var vt = new ViewTransform() { transform = owner.worldTransform, clipRect = clipRect }; drawParams.view.Push(vt); GL.modelview = vt.transform; break; case CommandType.PopView: drawParams.view.Pop(); GL.modelview = drawParams.view.Peek().transform; break; case CommandType.PushScissor: Rect elemRect = CombineScissorRects(owner.worldClip, drawParams.scissor.Peek()); drawParams.scissor.Push(elemRect); Utility.SetScissorRect(RectPointsToPixelsAndFlipYAxis(elemRect, pixelsPerPoint)); break; case CommandType.PopScissor: drawParams.scissor.Pop(); Rect prevRect = drawParams.scissor.Peek(); if (prevRect.x == DrawParams.k_UnlimitedRect.x) { Utility.DisableScissor(); } else { Utility.SetScissorRect(RectPointsToPixelsAndFlipYAxis(prevRect, pixelsPerPoint)); } break; case CommandType.PushRenderTexture: { RectInt viewport = Utility.GetActiveViewport(); RenderTexture rt = RenderTexture.GetTemporary(viewport.width, viewport.height, 24, RenderTextureFormat.ARGBHalf); RenderTexture.active = rt; GL.Clear(true, true, new Color(0, 0, 0, 0), UIRUtility.k_ClearZ); drawParams.renderTexture.Add(RenderTexture.active); break; } case CommandType.PopRenderTexture: { int index = drawParams.renderTexture.Count - 1; Debug.Assert(index > 0); //Check that we have something to pop, We should never pop the last(original)one // Only supported use case for now is to do a blit befor the pop. // This should set the active RenderTexture to index-1 and we should not have this warning. Debug.Assert(drawParams.renderTexture[index - 1] == RenderTexture.active, "Content of previous render texture was probably not blitted"); var rt = drawParams.renderTexture[index]; if (rt != null) { RenderTexture.ReleaseTemporary(rt); } drawParams.renderTexture.RemoveAt(index); } break; case CommandType.BlitToPreviousRT: { // Currently the command only blit to the previous RT, but this could be expanded if we use // indexCount and indexOffset to point to specific indices in the renderTextureBuffer. // The main difficulty is to memorize the current renderTexture depth to get the indices in the RenderChain // as we can edit the stack in the middle and that would requires rewriting previous/ subsequent commands //Also, there is currently no way to have a permanently assigned rt to be used as cache. var source = drawParams.renderTexture[drawParams.renderTexture.Count - 1]; var destination = drawParams.renderTexture[drawParams.renderTexture.Count - 2]; // Note: Graphics.Blit set the arctive RT => RT is not restored and it is expected to be chaged before PopRenderTexture //TODO check blit code for other side effect Debug.Assert(source == RenderTexture.active, "Unexpected render target change: Current renderTarget is not the one on the top of the stack"); //The following lines are equivalent to //Graphics.Blit(source, destination, state.material); //except the vertex are at the specified depth Blit(source, destination, UIRUtility.k_MeshPosZ); } break; //Logic of both command is entirely in UIRenderDevice as it need access to the local variable defaultMat case CommandType.PushDefaultMaterial: break; case CommandType.PopDefaultMaterial: break; } }
/// <summary> /// Gets the first empty space in <paramref name="atlas"/> that has at least the size of <paramref name="pixelScale"/>. /// </summary> /// <param name="atlas">The <see cref="dfAtlas"/> to find the empty space in.</param> /// <param name="pixelScale">The required size of the empty space.</param> /// <returns>The rect of the empty space divided by the atlas texture's size.</returns> public static Rect FindFirstValidEmptySpace(this dfAtlas atlas, IntVector2 pixelScale) { if (atlas == null || atlas.Texture == null || !atlas.Texture.IsReadable()) { return(new Rect(0f, 0f, 0f, 0f)); } Vector2Int point = new Vector2Int(0, 0); int pointIndex = -1; List <RectInt> rects = atlas.GetPixelRegions(); while (true) { bool shouldContinue = false; foreach (RectInt rint in rects) { if (rint.Overlaps(new RectInt(point, pixelScale.ToVector2Int()))) { shouldContinue = true; pointIndex++; if (pointIndex >= rects.Count) { return(new Rect(0f, 0f, 0f, 0f)); } point = rects[pointIndex].max + Vector2Int.one; if (point.x > atlas.Texture.width || point.y > atlas.Texture.height) { atlas.ResizeAtlas(new IntVector2(atlas.Texture.width * 2, atlas.Texture.height * 2)); } break; } bool shouldBreak = false; foreach (RectInt rint2 in rects) { RectInt currentRect = new RectInt(point, pixelScale.ToVector2Int()); if (rint2.x < currentRect.x || rint2.y < currentRect.y) { continue; } else { if (currentRect.Overlaps(rint2)) { shouldContinue = true; shouldBreak = true; pointIndex++; if (pointIndex >= rects.Count) { return(new Rect(0f, 0f, 0f, 0f)); } point = rects[pointIndex].max + Vector2Int.one; if (point.x > atlas.Texture.width || point.y > atlas.Texture.height) { atlas.ResizeAtlas(new IntVector2(atlas.Texture.width * 2, atlas.Texture.height * 2)); } break; } } } if (shouldBreak) { break; } } if (shouldContinue) { continue; } RectInt currentRect2 = new RectInt(point, pixelScale.ToVector2Int()); if (currentRect2.xMax > atlas.Texture.width || currentRect2.yMax > atlas.Texture.height) { atlas.ResizeAtlas(new IntVector2(atlas.Texture.width * 2, atlas.Texture.height * 2)); } break; } RectInt currentRect3 = new RectInt(point, pixelScale.ToVector2Int()); Rect rect = new Rect((float)currentRect3.x / atlas.Texture.width, (float)currentRect3.y / atlas.Texture.height, (float)currentRect3.width / atlas.Texture.width, (float)currentRect3.height / atlas.Texture.height); return(rect); }
public static bool RectIntCast(RectInt origin, Vector2Int delta, RectInt obstruction, out RectInt dst, out Vector2Int contactNormal, out RectInt overlapIntersection, bool debug = false) { if (delta == Vector2Int.zero) { contactNormal = Vector2Int.zero; if (TryGetRectIntersection(origin, obstruction, out overlapIntersection)) { dst = origin; return(true); } else { dst = origin; overlapIntersection = new RectInt(Vector2Int.zero, Vector2Int.zero); return(false); } } float strideWidth = (float)origin.width / 2; float strideHeight = (float)origin.height / 2; int slices = Mathf.Max( Mathf.CeilToInt((float)Mathf.Abs(delta.x) / strideWidth), Mathf.CeilToInt((float)Mathf.Abs(delta.y) / strideHeight) ); Vector2 floatStride = new Vector2(delta.x, delta.y) / slices; // Debug.LogFormat("float stride: {0}", floatStride); RectInt?overlapRect = null; RectInt coarseRect = new RectInt(0, 0, 0, 0); for (int i = 0; i < slices + 1; i++) { Vector2Int position = origin.position + Vector2Int.RoundToInt(i * floatStride); RectInt iterRect = new RectInt(position, origin.size); if (iterRect.Overlaps(obstruction)) { TryGetRectIntersection(iterRect, obstruction, out RectInt ol); overlapRect = ol; coarseRect = iterRect; break; } } if (overlapRect.HasValue == false) { dst = new RectInt(origin.position + delta, origin.size); contactNormal = Vector2Int.zero; overlapIntersection = new RectInt(); return(false); } var overlap = overlapRect.Value; overlapIntersection = overlap; if (debug) { Debug.LogFormat("Coarse rect: {0}", coarseRect); } if (debug) { Debug.LogFormat("Overlap rect: {0}", overlap); } // At this point, one of our rects overlapped // Use our delta, coarse rect, and overlap rect to back-out of overlapping Vector2Int backTrack = Vector2Int.zero; // fine-tune contact normal? right now just returns a cardinal dir or zero. contactNormal = Vector2Int.zero; { Vector2Int backtrackFromHorz = Vector2Int.zero; Vector2Int contactNormalFromHorz = Vector2Int.one; if (delta.x != 0) { float slope = (float)delta.y / delta.x; if (-delta.x > 0) { int rightResolve = 1 + overlap.TrueMax().x - coarseRect.x; backtrackFromHorz.x = rightResolve; backtrackFromHorz.y = Mathf.RoundToInt(rightResolve * slope); if (debug) { Debug.LogFormat("Right resolve: {0}. backtrackFromHorz: {1}", rightResolve, backtrackFromHorz); } contactNormalFromHorz = Vector2Int.right; } else { int leftResolve = -Mathf.Abs(coarseRect.TrueMax().x - overlap.x + 1); backtrackFromHorz.x = leftResolve; backtrackFromHorz.y = Mathf.RoundToInt(leftResolve * slope); if (debug) { Debug.LogFormat("Left resolve: {0}. backtrackFromHorz: {1}", leftResolve, backtrackFromHorz); } contactNormalFromHorz = Vector2Int.left; } } Vector2Int backtrackFromVert = Vector2Int.zero; Vector2Int contactNormalFromVert = Vector2Int.zero; if (delta.y != 0) { // Pure vertical float invSlope = (float)delta.x / delta.y; if (delta.y > 0) { int downResolve = -Mathf.Abs(coarseRect.TrueMax().y - overlap.y + 1); backtrackFromVert.y = downResolve; backtrackFromVert.x = Mathf.RoundToInt(downResolve * invSlope); if (debug) { Debug.LogFormat("Down resolve: {0}. backtrackFromVert: {1}.", downResolve, backtrackFromVert); } contactNormalFromVert = Vector2Int.down; } else { int upResolve = 1 + overlap.TrueMax().y - coarseRect.y; backtrackFromVert.y = upResolve; backtrackFromVert.x = Mathf.RoundToInt(upResolve * invSlope); if (debug) { Debug.LogFormat("Up resolve: {0}. backtrackFromVert: {1}", upResolve, backtrackFromVert); } contactNormalFromVert = Vector2Int.up; } } bool useVert = (Mathf.Abs(delta.y) > Mathf.Abs(delta.x)); backTrack = useVert ? backtrackFromVert : backtrackFromHorz; contactNormal = useVert ? contactNormalFromVert : contactNormalFromHorz; } // Note: we don't handle corner-to-corner collisions here^. if (debug) { Debug.LogFormat("backtrack: {0}", backTrack); } Vector2Int finalRectPos = coarseRect.position + backTrack; dst = new RectInt(finalRectPos, origin.size); if (debug) { Debug.LogFormat("Final rect: {0}", finalRectPos); } return(true); }
internal void ExecuteNonDrawMesh(DrawParams drawParams, float pixelsPerPoint, ref Exception immediateException) { switch (type) { case CommandType.ImmediateCull: { RectInt worldRect = RectPointsToPixelsAndFlipYAxis(owner.worldBound, pixelsPerPoint); if (!worldRect.Overlaps(Utility.GetActiveViewport())) { break; } // Element isn't culled, follow through the normal immediate callback procedure goto case CommandType.Immediate; } case CommandType.Immediate: { if (immediateException != null) { break; } Matrix4x4 oldProjection = Utility.GetUnityProjectionMatrix(); bool hasScissor = drawParams.scissor.Count > 1; // We always expect the "unbound" scissor rectangle to exists if (hasScissor) { Utility.DisableScissor(); // Disable scissor since most IMGUI code assume it's inactive } Utility.ProfileImmediateRendererBegin(); try { using (new GUIClip.ParentClipScope(owner.worldTransform, owner.worldClip)) callback(); } catch (Exception e) { immediateException = e; } GL.modelview = drawParams.view.Peek().transform; GL.LoadProjectionMatrix(oldProjection); Utility.ProfileImmediateRendererEnd(); if (hasScissor) { Utility.SetScissorRect(RectPointsToPixelsAndFlipYAxis(drawParams.scissor.Peek(), pixelsPerPoint)); } break; } case CommandType.PushView: var vt = new ViewTransform() { transform = owner.worldTransform, clipRect = RectToClipSpace(owner.worldClip) }; drawParams.view.Push(vt); GL.modelview = vt.transform; break; case CommandType.PopView: drawParams.view.Pop(); GL.modelview = drawParams.view.Peek().transform; break; case CommandType.PushScissor: Rect elemRect = CombineScissorRects(owner.worldClip, drawParams.scissor.Peek()); drawParams.scissor.Push(elemRect); Utility.SetScissorRect(RectPointsToPixelsAndFlipYAxis(elemRect, pixelsPerPoint)); break; case CommandType.PopScissor: drawParams.scissor.Pop(); Rect prevRect = drawParams.scissor.Peek(); if (prevRect.x == DrawParams.k_UnlimitedRect.x) { Utility.DisableScissor(); } else { Utility.SetScissorRect(RectPointsToPixelsAndFlipYAxis(prevRect, pixelsPerPoint)); } break; } }