public Vector2 EstTileAtPosWithScroll(Vector2 pos) { pos *= new Vector2(FSOEnvironment.DPIScaleFactor); var sPos = new Vector3(pos, 0); var p1 = State.Device.Viewport.Unproject(sPos, State.Camera.Projection, State.Camera.View, Matrix.Identity); sPos.Z = 1; var p2 = State.Device.Viewport.Unproject(sPos, State.Camera.Projection, State.Camera.View, Matrix.Identity); var dir = p2 - p1; dir.Normalize(); var ray = new Ray(p1, p2 - p1); ray.Direction.Normalize(); ray.Position -= new Vector3(0, (State.Level - 1) * 2.95f * 3, 0); var baseBox = new BoundingBox(new Vector3(0, -5000, 0), new Vector3(Blueprint.Width * 3, 5000, Blueprint.Height * 3)); if (baseBox.Contains(ray.Position) != ContainmentType.Contains) { //move ray start inside box var i = baseBox.Intersects(ray); if (i != null) { ray.Position += ray.Direction * (i.Value + 0.01f); } } var mx = (int)ray.Position.X / 3; var my = (int)ray.Position.Z / 3; var px = (ray.Direction.X > 0); var py = (ray.Direction.Z > 0); int iteration = 0; while (mx >= 0 && mx < Blueprint.Width && my >= 0 && my < Blueprint.Width) { //test triangle 1. (centre of tile down xz, we lean towards positive x) var plane = new Plane( new Vector3(mx * 3, Blueprint.GetAltPoint(mx, my) * Blueprint.TerrainFactor * 3, my * 3), new Vector3(mx * 3 + 3, Blueprint.GetAltPoint(mx + 1, my) * Blueprint.TerrainFactor * 3, my * 3), new Vector3(mx * 3 + 3, Blueprint.GetAltPoint(mx + 1, my + 1) * Blueprint.TerrainFactor * 3, my * 3 + 3) ); var tBounds = new BoundingBox(new Vector3(mx * 3, -5000, my * 3), new Vector3(mx * 3 + 3, 5000, my * 3 + 3)); var t1 = ray.Intersects(plane); var t2 = BoxRC2(ray, 3); //var t2 = BoxRC(ray, tBounds); if (plane.DotCoordinate(ray.Position) > 0) { t1 = 0; } if (t1 != null && t2 != null && t1.Value < t2.Value) { //hit the ground... var tentative = ray.Position + ray.Direction * (t1.Value + 0.00001f); //did it hit the correct side of the triangle? var mySide = ((tentative.X / 3) % 1) - ((tentative.Z / 3) % 1); if (mySide >= 0) { return(new Vector2(tentative.X / 3, tentative.Z / 3)); } else { //test the other side (positive z) plane = new Plane( new Vector3(mx * 3, Blueprint.GetAltPoint(mx, my) * Blueprint.TerrainFactor * 3, my * 3), new Vector3(mx * 3, Blueprint.GetAltPoint(mx, my + 1) * Blueprint.TerrainFactor * 3, my * 3 + 3), new Vector3(mx * 3 + 3, Blueprint.GetAltPoint(mx + 1, my + 1) * Blueprint.TerrainFactor * 3, my * 3 + 3) ); t1 = ray.Intersects(plane); if (t1 != null && t2 != null && t1.Value < t2.Value) { //hit the other side tentative = ray.Position + ray.Direction * (t1.Value + 0.00001f); return(new Vector2(tentative.X / 3, tentative.Z / 3)); } } } if (t2 == null) { break; } ray.Position += ray.Direction * (t2.Value + 0.00001f); mx = (!px) ? ((int)Math.Ceiling(ray.Position.X / 3) - 1) : (int)(ray.Position.X / 3); my = (!py) ? ((int)Math.Ceiling(ray.Position.Z / 3) - 1) : (int)(ray.Position.Z / 3); if (iteration++ > 1000) { break; } } //fall back to base positioning var bplane = new Plane(new Vector3(0, 0, 0), new Vector3(Blueprint.Width * 3, 0, 0), new Vector3(0, 0, Blueprint.Height * 3)); var cast = ray.Intersects(bplane); if (cast != null) { ray.Position += ray.Direction * (cast.Value + 0.01f); return(new Vector2(ray.Position.X / 3, ray.Position.Z / 3)); } return(new Vector2(0, 0)); }
public Vector2 EstTileAtPosWithScroll(Vector2 pos, sbyte level = -1) { if (level == -1) { level = State.Level; } var ray = State.CameraRayAtScreenPos(pos, level); var baseBox = new BoundingBox(new Vector3(0, -5000, 0), new Vector3(Blueprint.Width * 3, 5000, Blueprint.Height * 3)); if (baseBox.Contains(ray.Position) != ContainmentType.Contains) { //move ray start inside box var i = baseBox.Intersects(ray); if (i != null) { ray.Position += ray.Direction * (i.Value + 0.01f); } } var mx = (int)ray.Position.X / 3; var my = (int)ray.Position.Z / 3; var px = (ray.Direction.X > 0); var py = (ray.Direction.Z > 0); var canProj = Blueprint?.Altitude != null; int iteration = 0; while (mx >= 0 && mx < Blueprint.Width && my >= 0 && my < Blueprint.Width && canProj) { //test triangle 1. (centre of tile down xz, we lean towards positive x) var plane = new Plane( new Vector3(mx * 3, Blueprint.GetAltPoint(mx, my) * Blueprint.TerrainFactor * 3, my * 3), new Vector3(mx * 3 + 3, Blueprint.GetAltPoint(mx + 1, my) * Blueprint.TerrainFactor * 3, my * 3), new Vector3(mx * 3 + 3, Blueprint.GetAltPoint(mx + 1, my + 1) * Blueprint.TerrainFactor * 3, my * 3 + 3) ); var tBounds = new BoundingBox(new Vector3(mx * 3, -5000, my * 3), new Vector3(mx * 3 + 3, 5000, my * 3 + 3)); var t1 = ray.Intersects(plane); var t2 = BoxRC2(ray, 3); //var t2 = BoxRC(ray, tBounds); if (plane.DotCoordinate(ray.Position) > 0) { t1 = 0; } if (t1 != null && t2 != null && t1.Value < t2.Value) { //hit the ground... var tentative = ray.Position + ray.Direction * (t1.Value + 0.00001f); //did it hit the correct side of the triangle? var mySide = ((tentative.X / 3) % 1) - ((tentative.Z / 3) % 1); if (mySide >= 0) { return(new Vector2(tentative.X / 3, tentative.Z / 3)); } else { //test the other side (positive z) plane = new Plane( new Vector3(mx * 3, Blueprint.GetAltPoint(mx, my) * Blueprint.TerrainFactor * 3, my * 3), new Vector3(mx * 3, Blueprint.GetAltPoint(mx, my + 1) * Blueprint.TerrainFactor * 3, my * 3 + 3), new Vector3(mx * 3 + 3, Blueprint.GetAltPoint(mx + 1, my + 1) * Blueprint.TerrainFactor * 3, my * 3 + 3) ); t1 = ray.Intersects(plane); if (t1 != null && t2 != null && t1.Value < t2.Value) { //hit the other side tentative = ray.Position + ray.Direction * (t1.Value + 0.00001f); return(new Vector2(tentative.X / 3, tentative.Z / 3)); } } } if (t2 == null) { break; } ray.Position += ray.Direction * (t2.Value + 0.00001f); mx = (!px) ? ((int)Math.Ceiling(ray.Position.X / 3) - 1) : (int)(ray.Position.X / 3); my = (!py) ? ((int)Math.Ceiling(ray.Position.Z / 3) - 1) : (int)(ray.Position.Z / 3); if (iteration++ > 1000) { break; } } //fall back to base positioning var bplane = new Plane(new Vector3(0, 0, 0), new Vector3(Blueprint.Width * 3, 0, 0), new Vector3(0, 0, Blueprint.Height * 3)); var cast = ray.Intersects(bplane); if (cast != null) { ray.Position += ray.Direction * (cast.Value + 0.01f); return(new Vector2(ray.Position.X / 3, ray.Position.Z / 3)); } return(new Vector2(0, 0)); }