public PortalView(PortalView parent, Matrix4 viewMatrix, List<List<IntPoint>> path, LineF[] fovLines, LineF[] fovLinesPrevious, LineF portalLine) { PortalLine = portalLine; FovLines = fovLines; FovLinesPrevious = fovLinesPrevious; Children = new List<PortalView>(); Parent = parent; if (Parent != null) { Parent.Children.Add(this); } ViewMatrix = viewMatrix; Paths = path; }
public static PortalView CalculatePortalViews(IList<IPortal> portals, ICamera2 camera, int depth) { Debug.Assert(camera != null); Debug.Assert(depth >= 0); Debug.Assert(portals != null); List<IntPoint> view = ClipperConvert.ToIntPoint(CameraExt.GetWorldVerts(camera)); List<List<IntPoint>> paths = new List<List<IntPoint>>(); paths.Add(view); PortalView portalView = new PortalView(null, CameraExt.GetViewMatrix(camera), view, new LineF[0], new LineF[0]); Vector2 camPos = camera.GetWorldTransform().Position; List<Func<bool>> actionList = new List<Func<bool>>(); foreach (IPortal p in portals) { actionList.Add(() => CalculatePortalViews(p, null, portals, CameraExt.GetViewMatrix(camera), camPos, camPos - camera.GetWorldVelocity().Position / Controller.DrawsPerSecond, portalView, Matrix4.Identity, actionList)); } while (actionList.Count > 0 && depth > 0) { bool result = actionList.First().Invoke(); if (result) { depth--; } actionList.RemoveAt(0); } return portalView; }
private static bool CalculatePortalViews(IPortal portal, IPortal portalEnter, IList<IPortal> portals, Matrix4 viewMatrix, Vector2 viewPos, Vector2 viewPosPrevious, PortalView portalView, Matrix4 portalMatrix, List<Func<bool>> actionList) { const float AREA_EPSILON = 0.0001f; Clipper c = new Clipper(); //The clipper must be set to strictly simple. Otherwise polygons might have duplicate vertices which causes poly2tri to generate incorrect results. c.StrictlySimple = true; if (!_isPortalValid(portalEnter, portal, viewPos)) { return false; } Vector2[] fov = Vector2Ext.Transform(Portal.GetFov(portal, viewPos, 500, 3), portalMatrix); if (MathExt.GetArea(fov) < AREA_EPSILON) { return false; } List<IntPoint> pathFov = ClipperConvert.ToIntPoint(fov); var viewNew = new List<List<IntPoint>>(); c.AddPath(pathFov, PolyType.ptSubject, true); c.AddPaths(portalView.Paths, PolyType.ptClip, true); c.Execute(ClipType.ctIntersection, viewNew); c.Clear(); if (viewNew.Count <= 0) { return false; } c.AddPaths(viewNew, PolyType.ptSubject, true); foreach (IPortal other in portals) { if (other == portal) { continue; } if (!_isPortalValid(portalEnter, other, viewPos)) { continue; } //Skip this portal if it's inside the current portal's FOV. LineF portalLine = new LineF(Portal.GetWorldVerts(portal)); LineF portalOtherLine = new LineF(Portal.GetWorldVerts(other)); if (portalLine.IsInsideFOV(viewPos, portalOtherLine)) { continue; } Vector2[] otherFov = Vector2Ext.Transform(Portal.GetFov(other, viewPos, 500, 3), portalMatrix); if (MathExt.GetArea(otherFov) < AREA_EPSILON) { continue; } otherFov = MathExt.SetWinding(otherFov, true); List<IntPoint> otherPathFov = ClipperConvert.ToIntPoint(otherFov); c.AddPath(otherPathFov, PolyType.ptClip, true); } var viewNewer = new List<List<IntPoint>>(); c.Execute(ClipType.ctDifference, viewNewer, PolyFillType.pftNonZero, PolyFillType.pftNonZero); c.Clear(); if (viewNewer.Count <= 0) { return false; } Vector2 viewPosNew = Vector2Ext.Transform(viewPos, Portal.GetLinkedMatrix(portal, portal.Linked)); Vector2 viewPosPreviousNew = Vector2Ext.Transform(viewPosPrevious, Portal.GetLinkedMatrix(portal, portal.Linked)); Matrix4 portalMatrixNew = Portal.GetLinkedMatrix(portal.Linked, portal) * portalMatrix; Matrix4 viewMatrixNew = portalMatrixNew * viewMatrix; LineF[] lines = Portal.GetFovLines(portal, viewPos, 500); lines[0] = lines[0].Transform(portalMatrix); lines[1] = lines[1].Transform(portalMatrix); LineF[] linesPrevious = Portal.GetFovLines(portal, viewPosPrevious, 500); linesPrevious[0] = linesPrevious[0].Transform(portalMatrix); linesPrevious[1] = linesPrevious[1].Transform(portalMatrix); LineF portalWorldLine = new LineF(Portal.GetWorldVerts(portal)); portalWorldLine = portalWorldLine.Transform(portalMatrix); PortalView portalViewNew = new PortalView(portalView, viewMatrixNew, viewNewer, lines, linesPrevious, portalWorldLine); foreach (IPortal p in portals) { actionList.Add(() => CalculatePortalViews(p, portal, portals, viewMatrix, viewPosNew, viewPosPreviousNew, portalViewNew, portalMatrixNew, actionList) ); } return true; }
public PortalView(PortalView parent, Matrix4 viewMatrix, List<IntPoint> path, LineF[] fovLines, LineF[] fovLinesPrevious) : this(parent, viewMatrix, new List<List<IntPoint>>(), fovLines, fovLinesPrevious, null) { Paths.Add(path); }
/// <summary>Sets scissor region around a portalview.</summary> /// <param name="viewMatrix">Camera view matrix, do not use view matrix for the portalview.</param> private void SetScissor(PortalView view, Matrix4 viewMatrix) { Debug.Assert(view != null); if (view.Paths == null) { ResetScissor(); return; } Matrix4 ScaleMatrix; ScaleMatrix = viewMatrix * Matrix4.CreateTranslation(new Vector3(1, 1, 0)); ScaleMatrix = ScaleMatrix * Matrix4.CreateScale(new Vector3(CanvasSize.Width / (float)2, CanvasSize.Height / (float)2, 0)); Vector2 vMin, vMax; vMin = ClipperConvert.ToVector2(view.Paths[0][0]); vMax = ClipperConvert.ToVector2(view.Paths[0][0]); for (int i = 0; i < view.Paths.Count; i++) { for (int j = 0; j < view.Paths[i].Count; j++) { Vector2 vTransform = Vector2Ext.Transform(ClipperConvert.ToVector2(view.Paths[i][j]), ScaleMatrix); vMax = Vector2.ComponentMax(vMax, vTransform); vMin = Vector2.ComponentMin(vMin, vTransform); } } //The -1 and +3 are margins to prevent rounding errors from making the scissor box too small. GL.Scissor((int)vMin.X - 1, (int)vMin.Y - 1, (int)(vMax.X - vMin.X) + 3, (int)(vMax.Y - vMin.Y) + 3); }