/** Calculate the shortest path through the funnel. * \param funnel The portals of the funnel. The first and last vertices portals must be single points (so for example left[0] == right[0]). * \param unwrap Determines if twists and bends should be straightened out before running the funnel algorithm. * \param splitAtEveryPortal If true, then a vertex will be inserted every time the path crosses a portal * instead of only at the corners of the path. The result will have exactly one vertex per portal if this is enabled. * This may introduce vertices with the same position in the output (esp. in corners where many portals meet). * * If the unwrap option is disabled the funnel will simply be projected onto the XZ plane. * If the unwrap option is enabled then the funnel may be oriented arbitrarily and may have twists and bends. * This makes it possible to support the funnel algorithm in XY space as well as in more complicated cases, such * as on curved worlds. * \shadowimage{funnel_unwrap_illustration.png} * * \shadowimage{funnel_split_at_every_portal.png} * * \see Unwrap */ //Good Game //public static List<Vector3> Calculate (FunnelPortals funnel, bool unwrap, bool splitAtEveryPortal) { public static List <VInt3> Calculate(FunnelPortals funnel, bool unwrap, bool splitAtEveryPortal) { if (funnel.left.Count != funnel.right.Count) { throw new System.ArgumentException("funnel.left.Count != funnel.right.Count"); } // Get arrays at least as large as the number of portals //Good Game /*var leftArr = ArrayPool<Vector2>.Claim(funnel.left.Count); * var rightArr = ArrayPool<Vector2>.Claim(funnel.left.Count);*/ var leftArr = ArrayPool <VInt2> .Claim(funnel.left.Count); var rightArr = ArrayPool <VInt2> .Claim(funnel.left.Count); if (unwrap) { Unwrap(funnel, leftArr, rightArr); } else { // Copy to arrays for (int i = 0; i < funnel.left.Count; i++) { leftArr[i] = ToXZ(funnel.left[i]); rightArr[i] = ToXZ(funnel.right[i]); } } int startIndex = FixFunnel(leftArr, rightArr, funnel.left.Count); var intermediateResult = ListPool <int> .Claim(); if (startIndex == -1) { // If funnel algorithm failed, fall back to a simple line intermediateResult.Add(0); intermediateResult.Add(funnel.left.Count - 1); } else { bool lastCorner; Calculate(leftArr, rightArr, funnel.left.Count, startIndex, intermediateResult, int.MaxValue, out lastCorner); } // Get list for the final result //Good Game //var result = ListPool<Vector3>.Claim(intermediateResult.Count); var result = ListPool <VInt3> .Claim(intermediateResult.Count); //Good Game //Vector2 prev2D = leftArr[0]; VInt2 prev2D = leftArr[0]; var prevIdx = 0; for (int i = 0; i < intermediateResult.Count; i++) { var idx = intermediateResult[i]; if (splitAtEveryPortal) { // Check intersections with every portal segment var next2D = idx >= 0 ? leftArr[idx] : rightArr[-idx]; for (int j = prevIdx + 1; j < System.Math.Abs(idx); j++) { //Good Game //var factor = VectorMath.LineIntersectionFactorXZ(FromXZ(leftArr[j]), FromXZ(rightArr[j]), FromXZ(prev2D), FromXZ(next2D)); var factor = IntMath.LineIntersectionFactorXZ(FromXZ(leftArr[j]), FromXZ(rightArr[j]), FromXZ(prev2D), FromXZ(next2D)); //result.Add(Vector3.Lerp(funnel.left[j], funnel.right[j], factor)); //Good Game result.Add(VInt3.Lerp(funnel.left[j], funnel.right[j], factor)); } prevIdx = Mathf.Abs(idx); prev2D = next2D; } if (idx >= 0) { result.Add(funnel.left[idx]); } else { result.Add(funnel.right[-idx]); } } // Release lists back to the pool ListPool <int> .Release(ref intermediateResult); //Good Game /*ArrayPool<Vector2>.Release(ref leftArr); * ArrayPool<Vector2>.Release(ref rightArr);*/ ArrayPool <VInt2> .Release(ref leftArr); ArrayPool <VInt2> .Release(ref rightArr); return(result); }