private static DepthSlice PackDepthSlice(ref RawDepthData rawDepthData, int dataStart, int dataEnd) { DepthSlice depthSlice = new DepthSlice(); depthSlice.xOffset = rawDepthData.startX + dataStart; depthSlice.zOffset = int.MaxValue; for (int i = dataStart; i < dataEnd; i++) { Debug.Assert(rawDepthData.depthFront[i] <= rawDepthData.depthBack[i]); Debug.Assert(rawDepthData.depthBack[i] != int.MinValue); if (rawDepthData.depthFront[i] < depthSlice.zOffset) { depthSlice.zOffset = rawDepthData.depthFront[i]; } } depthSlice.depths = new FrontBack[dataEnd - dataStart]; for (int i = 0; i < depthSlice.depths.Length; i++) { depthSlice.depths[i].front = (byte)System.Math.Min(byte.MaxValue, rawDepthData.depthFront[i + dataStart] - depthSlice.zOffset); depthSlice.depths[i].back = (byte)System.Math.Min(byte.MaxValue, rawDepthData.depthBack[i + dataStart] - depthSlice.zOffset); } return(depthSlice); }
static private DepthSlice MakeBaseDepthSlice(Heightmap heightmap) { RawDepthData rawDepthData = GetRawDepthData(heightmap, 0, heightmap.StartX - 1, heightmap.Width + 2); // <- Guarantuee missing ranges on each end (for extrapolation) if (rawDepthData.IsBlank) { return(DepthSlice.CreateBlank(heightmap.StartX, heightmap.StartZ)); } // Fill in missing data and do extrapolation: rawDepthData.RepairMissingRanges(); int dataStart = rawDepthData.missingDataRanges[0].index + rawDepthData.missingDataRanges[0].count; int dataEnd = rawDepthData.missingDataRanges[rawDepthData.missingDataRanges.Count - 1].index; // Bring extrapolations into the legitimate data range: if (rawDepthData.depthFront[dataStart - 1] == rawDepthData.depthBack[dataStart - 1]) { dataStart--; } if (rawDepthData.depthFront[dataEnd] == rawDepthData.depthBack[dataEnd]) { dataEnd++; } return(PackDepthSlice(ref rawDepthData, dataStart, dataEnd)); }
public static DepthBounds CreateForFlat(AnimationSet animationSet) { Debug.Assert(animationSet.Heightmap == null); // <- should be going through other path DepthSlice ds = new DepthSlice(); ds.xOffset = animationSet.physicsStartX; ds.zOffset = animationSet.physicsStartZ; int width = animationSet.physicsEndX - animationSet.physicsStartX; ds.depths = new FrontBack[width]; if (animationSet.flatDirection != 0) { for (int i = 0; i < width; i++) { int depth = i; if (animationSet.flatDirection == Oblique.Left) { depth = width - 1 - i; } byte d = (byte)System.Math.Min(byte.MaxValue, depth); ds.depths[i].front = d; ds.depths[i].back = d; } } return(new DepthBounds { slices = new[] { ds } }); // <- single slice }
static DepthSlice MakeNonBaseDepthSlice(Heightmap heightmap, int yOffset, DepthSlice previousSlice) { Debug.Assert(yOffset != 0); Debug.Assert(previousSlice != null); RawDepthData rawDepthData = GetRawDepthData(heightmap, yOffset, previousSlice.xOffset, previousSlice.Width); if (rawDepthData.IsBlank) { return(DepthSlice.CreateBlank(previousSlice.xOffset, previousSlice.zOffset)); } DepthSlice depthSlice = PackDepthSlice(ref rawDepthData, 0, previousSlice.Width); // Pull up missing data from previous layers: foreach (var missingRange in rawDepthData.missingDataRanges) { for (int j = 0; j < missingRange.count; j++) { int i = j + missingRange.index; var belowBounds = previousSlice.depths[i]; if (belowBounds.front == belowBounds.back && missingRange.count == 1) // <- Indicates the lower layer is an extrapolation (keep it that way) { depthSlice.depths[i] = belowBounds; } else // Lower bounds is a surface, encode an "above" bounds { depthSlice.depths[i] = new FrontBack { back = belowBounds.back, front = (byte)System.Math.Min(byte.MaxValue, (int)belowBounds.back + 1) } }; } } return(depthSlice); } #endregion }
/// <summary>Deserialize.</summary> public DepthBounds(AnimationDeserializeContext context) { int heightCount = context.br.ReadInt32(); heights = (heightCount == 0) ? null : context.br.ReadBytes(heightCount); slices = new DepthSlice[heightCount + 1]; for (int i = 0; i < slices.Length; i++) { slices[i] = new DepthSlice() { xOffset = context.br.ReadInt32(), zOffset = context.br.ReadInt32(), depths = new FrontBack[context.br.ReadInt32()], }; for (int j = 0; j < slices[i].depths.Length; j++) { slices[i].depths[j].front = context.br.ReadByte(); slices[i].depths[j].back = context.br.ReadByte(); } } }
public static DepthBounds CreateForHeightmap(Heightmap heightmap) { if (heightmap.heightmapData.Data == null) // <- Empty heightmap makes me sad { return(new DepthBounds()); } if (!heightmap.IsObjectHeightmap) // <- Don't generate depth bounds for levels { return(new DepthBounds()); } // Determine what heights are used in the heightmap, and only generate depth slices for those heights bool[] usedHeights = new bool[256]; for (int i = 0; i < heightmap.heightmapData.Data.Length; i++) { usedHeights[heightmap.heightmapData.Data[i]] = true; } List <byte> heights = new List <byte>(); List <DepthSlice> slices = new List <DepthSlice>(); DepthSlice previousSlice = null; int previousHeight = 0; for (int y = 1; y < usedHeights.Length; y++) { if (!usedHeights[y]) { continue; } Debug.Assert(y - 1 <= byte.MaxValue); if (previousSlice == null) { // First slice always starts at height = 0, and its starting height is implicit (not stored in heights): Debug.Assert(slices.Count == 0); slices.Add(previousSlice = MakeBaseDepthSlice(heightmap)); } else { slices.Add(previousSlice = MakeNonBaseDepthSlice(heightmap, y - 1, previousSlice)); // <- note that the slice is wrapped around height at y-1 heights.Add((byte)previousHeight); } previousHeight = y; } if (slices.Count == 0) { return(new DepthBounds()); // <- no physics } else { Debug.Assert(heights.Count == slices.Count - 1); return(new DepthBounds { heights = heights.Count == 0 ? null : heights.ToArray(), slices = slices.ToArray(), }); } }