use of com.bergerkiller.bukkit.common.bases.IntVector2 in project BKCommonLib by bergerhealer.
the class MCSDBubbleFormat method writeTo.
public void writeTo(OutputStream stream) throws IOException {
try (BitOutputStream bitStream = new BitOutputStream(StreamUtil.createDeflaterOutputStreamWithCompressionLevel(stream, Deflater.BEST_COMPRESSION))) {
// Input colors will be used to correct errors in the color model
// These are never written to and serve as a backup while writing
this.input_colors = new MapColorSpaceData();
this.input_colors.readFrom(this);
// Load in all bubble boundary information
Logging.LOGGER_MAPDISPLAY.info("Loading bubble boundaries...");
for (int z = 0; z < 256; z++) {
boolean[] strands = this.strands[z];
final int index_end = ((z + 1) << 16);
for (int index = (z << 16); index < index_end; index++) {
int x = (index & 0xFF);
int y = ((index >> 8) & 0xFF);
byte color = get(index);
strands[index & (strands.length - 1)] = (x < 255 && color != get(index + 1)) || (y < 255 && color != get(index + 256));
}
}
// Find connected blobs of color (restore colors after all bubbles are found)
Logging.LOGGER_MAPDISPLAY.info("Generating bubble spatial information...");
for (int z = 0; z < 256; z++) {
boolean[] strands = this.strands[z];
int index_offset = (z << 16);
for (int index = 0; index < (1 << 16); index++) {
if (strands[index]) {
continue;
}
byte color = this.get(index_offset + index);
if (color == 0) {
continue;
}
this.set(index_offset + index, (byte) 0);
Bubble bubble = new Bubble();
bubble.x = (index & 0xFF);
bubble.y = ((index >> 8) & 0xFF);
bubble.z_min = z;
bubble.z_max = z;
bubble.color = color;
bubble.pixels.add(new IntVector2(bubble.x, bubble.y));
spread(bubble);
this.bubbles.add(bubble);
}
}
this.readFrom(this.input_colors);
// Merge the blobs with same colors sharing points
Logging.LOGGER_MAPDISPLAY.info("Connecting bubbles in the z-axis...");
for (int bubbleidx = 0; bubbleidx < this.bubbles.size(); bubbleidx++) {
Bubble bubble = this.bubbles.get(bubbleidx);
Iterator<Bubble> iter = this.bubbles.iterator();
while (iter.hasNext()) {
Bubble otherBubble = iter.next();
// Mergable?
if (bubble == otherBubble || bubble.color != otherBubble.color) {
continue;
}
// Sharing a Z-border?
if (bubble.z_min != (otherBubble.z_max + 1) && bubble.z_max != (otherBubble.z_min - 1)) {
continue;
}
// Sharing any pixel at all?
boolean sharesPixels = false;
for (IntVector2 p : otherBubble.pixels) {
if (bubble.pixels.contains(p)) {
sharesPixels = true;
break;
}
}
if (!sharesPixels) {
continue;
}
// Remove all pixels of the other cell and update z-bounds to merge the two
bubble.pixels.retainAll(otherBubble.pixels);
if (otherBubble.z_min < bubble.z_min) {
bubble.z_min = otherBubble.z_min;
}
if (otherBubble.z_max > bubble.z_max) {
bubble.z_max = otherBubble.z_max;
}
iter.remove();
}
}
// Calculate bubble x/y
Logging.LOGGER_MAPDISPLAY.info("Calculating bubble positions...");
for (Bubble bubble : this.bubbles) {
// Adjust x/y to be in the middle of all pixels found
int avg_x = 0;
int avg_y = 0;
for (IntVector2 pixel : bubble.pixels) {
avg_x += pixel.x;
avg_y += pixel.z;
}
avg_x /= bubble.pixels.size();
avg_y /= bubble.pixels.size();
IntVector2 closest = null;
int minDistSq = Integer.MAX_VALUE;
for (IntVector2 pixel : bubble.pixels) {
int dx = (pixel.x - avg_x);
int dy = (pixel.z - avg_y);
int distSq = (dx * dx) + (dy * dy);
if (distSq < minDistSq) {
minDistSq = distSq;
closest = pixel;
}
}
bubble.x = closest.x;
bubble.y = closest.z;
}
// Write out all color RGB values
for (int i = 0; i < 256; i++) {
Color color = this.getColor((byte) i);
bitStream.write(color.getRed());
bitStream.write(color.getGreen());
bitStream.write(color.getBlue());
bitStream.write(color.getAlpha());
}
// Write out all bubble information
for (Bubble bubble : bubbles) {
bitStream.write(bubble.color & 0xFF);
bitStream.write(bubble.x);
bitStream.write(bubble.y);
bitStream.write(bubble.z_min);
bitStream.write(bubble.z_max - bubble.z_min);
}
bitStream.write(0);
// Initialize the colors based on the known cell colors
Logging.LOGGER_MAPDISPLAY.info("Initializing color information for " + bubbles.size() + " bubbles...");
this.initColors();
// Write cell information
Logging.LOGGER_MAPDISPLAY.info("Writing bubble boundary information...");
IntStream.range(0, 256).mapToObj(z -> generateSlice(z)).parallel().forEachOrdered(codec -> {
try {
codec.writePackets(bitStream);
} catch (IOException ex) {
// Oh well.
ex.printStackTrace();
}
});
// Write missing color information using bit encoding
Logging.LOGGER_MAPDISPLAY.info("Correcting missing color information...");
List<BitPacket> colorCodes = new ArrayList<BitPacket>();
for (int i = 0; i < (1 << 24); i++) {
if (this.get(i) == 0) {
int x = (i & 0xFF);
int y = (i >> 8) & 0xFF;
BitPacket code = new BitPacket();
byte color = this.input_colors.get(i);
if (x > 0 && this.get(i - 1) == color) {
code.write(0, 1);
} else {
code.write(1, 1);
if (y > 0 && this.get(i - 256) == color) {
code.write(0, 2);
} else if (x < 255 && this.get(i + 1) == color) {
code.write(1, 2);
} else if (y < 255 && this.get(i + 256) == color) {
code.write(2, 2);
} else {
code.write(3, 2);
code.write(color & 0xFF, 8);
}
}
colorCodes.add(code);
this.set(i, color);
}
}
for (BitPacket code : colorCodes) {
bitStream.writeBits(code.data, code.bits);
}
}
}
use of com.bergerkiller.bukkit.common.bases.IntVector2 in project BKCommonLib by bergerhealer.
the class MCSDBubbleFormat method generateSlice.
private MCSDWebbingCodec generateSlice(int z) {
// Split all found coordinates in edge points, intersections and lines
// First optimize the order of rendering from the edge points
// Then try to optimize the order of the remaining intersections
// Then finally, try to optimize the order in which lines are drawn
boolean[] cells = this.strands[z];
List<IntVector2> edges = new ArrayList<IntVector2>();
List<IntVector2> intersects = new ArrayList<IntVector2>();
List<IntVector2> lines = new ArrayList<IntVector2>();
{
boolean[] data3x3 = new boolean[9];
int index = 0;
for (int y = 0; y < 256; y++) {
for (int x = 0; x < 256; x++) {
if (!cells[index++]) {
continue;
}
IntVector2 coord = new IntVector2(x, y);
int n = 0;
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
int mx = coord.x + dx;
int my = coord.z + dy;
if (mx < 0 || my < 0 || mx >= 256 || my >= 256) {
data3x3[n++] = false;
} else {
data3x3[n++] = cells[mx | (my << 8)];
}
}
}
if (MCSDWebbingCodec.EDGE_PATTERN.matches(data3x3)) {
edges.add(coord);
} else if (MCSDWebbingCodec.LINE_PATTERN.matches(data3x3)) {
lines.add(coord);
} else {
intersects.add(coord);
}
}
}
}
Logging.LOGGER_MAPDISPLAY.info("Processing z=" + z + ", " + edges.size() + " edges, " + intersects.size() + " intersects, " + lines.size() + " lines");
MCSDWebbingCodec codec = new MCSDWebbingCodec();
codec.reset(cells, true);
codec.processBest(edges, max_iterations);
codec.processBest(intersects, max_iterations);
codec.processBest(lines, max_iterations);
return codec;
}
use of com.bergerkiller.bukkit.common.bases.IntVector2 in project BKCommonLib by bergerhealer.
the class MapDisplayMarkers method computeTileAtPosition.
private MapDisplayMarkerTile computeTileAtPosition(double x, double y) {
int tileX = MathUtil.floor(x) >> 7;
int tileY = MathUtil.floor(y) >> 7;
return markersByTile.computeIfAbsent(new IntVector2(tileX, tileY), MapDisplayMarkerTile::new);
}
Aggregations