Search in sources :

Example 11 with IntVector2

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);
        }
    }
}
Also used : BitOutputStream(com.bergerkiller.bukkit.common.io.BitOutputStream) Color(java.awt.Color) ArrayList(java.util.ArrayList) BitPacket(com.bergerkiller.bukkit.common.io.BitPacket) IOException(java.io.IOException) IntVector2(com.bergerkiller.bukkit.common.bases.IntVector2)

Example 12 with IntVector2

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;
}
Also used : ArrayList(java.util.ArrayList) IntVector2(com.bergerkiller.bukkit.common.bases.IntVector2)

Example 13 with IntVector2

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);
}
Also used : IntVector2(com.bergerkiller.bukkit.common.bases.IntVector2)

Aggregations

IntVector2 (com.bergerkiller.bukkit.common.bases.IntVector2)13 IntVector3 (com.bergerkiller.bukkit.common.bases.IntVector3)6 HashSet (java.util.HashSet)6 Chunk (org.bukkit.Chunk)5 ArrayList (java.util.ArrayList)4 WorldHandle (com.bergerkiller.generated.net.minecraft.world.level.WorldHandle)2 File (java.io.File)2 BitSet (java.util.BitSet)2 Set (java.util.Set)2 BitOutputStream (com.bergerkiller.bukkit.common.io.BitOutputStream)1 BitPacket (com.bergerkiller.bukkit.common.io.BitPacket)1 ItemFrameInfo (com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo)1 OfflineWorld (com.bergerkiller.bukkit.common.offline.OfflineWorld)1 IntHashMap (com.bergerkiller.bukkit.common.wrappers.IntHashMap)1 OutputTypeMap (com.bergerkiller.mountiplex.reflection.util.OutputTypeMap)1 Color (java.awt.Color)1 IOException (java.io.IOException)1 HashMap (java.util.HashMap)1 IdentityHashMap (java.util.IdentityHashMap)1 Map (java.util.Map)1