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)); }
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 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 }
static RawDepthData GetRawDepthData(Heightmap heightmap, int yOffset, int startX, int width) { RawDepthData output = new RawDepthData(startX, width); // Now walk left-to-right, finding front and back depth bounds, // as well as ranges where the heightmap has no data: int endOfLastDataIndex = 0; for (int i = 0; i < width; i++) { int x = i + startX; if (x >= heightmap.StartX && x < heightmap.EndX) { // Walk back to find front of heightmap for this column, at the given height int front = heightmap.StartZ; // <- front is an inclusive bound while (true) { if (front >= heightmap.EndZ) { goto skipColumn; // no data } if (heightmap[x, front] > yOffset) { break; } front++; } // Walk forward to find the back of the heightmap int back = heightmap.EndZ; // <- back is an exclusive bound while (true) { Debug.Assert(back > front); // <- if this fires, there's a bug in the algorithm (or heightmap misbehaved) if (heightmap[x, back - 1] > yOffset) { break; } back--; } // Note any missing data up to here: Debug.Assert(endOfLastDataIndex <= i); if (endOfLastDataIndex != i) { output.missingDataRanges.Add(new DataRange { index = endOfLastDataIndex, count = (i - endOfLastDataIndex) }); } endOfLastDataIndex = i + 1; // Save the bounds: output.depthFront[i] = front; output.depthBack[i] = back; } skipColumn: ; } if (endOfLastDataIndex != width) { output.missingDataRanges.Add(new DataRange { index = endOfLastDataIndex, count = (width - endOfLastDataIndex) }); } return(output); }