All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pepsoft.worldpainter.tools.BiomesTileProvider Maven / Gradle / Ivy

There is a newer version: 2.23.2
Show newest version
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.pepsoft.worldpainter.tools;

import org.pepsoft.util.ColourUtils;
import org.pepsoft.util.swing.TileListener;
import org.pepsoft.util.swing.TileProvider;
import org.pepsoft.worldpainter.BiomeScheme;
import org.pepsoft.worldpainter.ColourScheme;
import org.pepsoft.worldpainter.biomeschemes.BiomeSchemeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Arrays;

import static org.pepsoft.worldpainter.Constants.*;
import static org.pepsoft.worldpainter.biomeschemes.Minecraft1_17Biomes.*;

/**
 *
 * @author pepijn
 */
public class BiomesTileProvider implements TileProvider {
    public BiomesTileProvider(BiomeScheme biomeScheme, ColourScheme colourScheme) {
        this(biomeScheme, colourScheme, 2, false);
    }

    public BiomesTileProvider(BiomeScheme biomeScheme, ColourScheme colourScheme, int zoom, boolean fade) {
        this.biomeScheme = biomeScheme;
        this.colourScheme = colourScheme;
        this.zoom = zoom;
        this.fade = fade;
        patternColour = fade ? 0xff808080 : 0xff000000;
        init();
    }

    public BiomesTileProvider(int biomeAlgorithm, long minecraftSeed, ColourScheme colourScheme, int zoom, boolean fade) {
        this.biomeAlgorithm = biomeAlgorithm;
        this.colourScheme = colourScheme;
        this.minecraftSeed = minecraftSeed;
        this.zoom = zoom;
        this.fade = fade;
        patternColour = fade ? 0xff808080 : 0xff000000;
    }
    
    @Override
    public int getTileSize() {
        return TILE_SIZE;
    }

    @Override
    public boolean isZoomSupported() {
        return true;
    }
    
    @Override
    public int getZoom() {
        return zoom;
    }
    
    @Override
    public void setZoom(int zoom) {
        if (zoom != this.zoom) {
            if (zoom > 0) {
                throw new UnsupportedOperationException("Zooming in not supported");
            }
            this.zoom = zoom;
            bufferRef = new ThreadLocal<>();
        }
    }

    @Override
    public boolean isTilePresent(int x, int y) {
        return enabled;
    }

    @Override
    public boolean paintTile(Image image, int tileX, int tileY, int imageX, int imageY) {
        if (! enabled) {
            return false;
        }
        try {
            BiomeScheme biomeScheme = getBiomeScheme();
            if (biomeScheme == null) {
                return false;
            }
            final int scale = 1 << -zoom;
            int[] buffer = bufferRef.get();
            if (buffer == null) {
                buffer = new int[TILE_SIZE * TILE_SIZE * scale * scale];
                bufferRef.set(buffer);
            }
            biomeScheme.getBiomes(tileX * TILE_SIZE * scale, tileY * TILE_SIZE * scale, TILE_SIZE * scale, TILE_SIZE * scale, buffer);
            BufferedImage tile = renderBufferRef.get();
            int[][] biomeCounts = biomeCountsRef.get();
            if (biomeCounts == null) {
                biomeCounts = new int[][] {new int[256], new int[256], new int[256]};
                biomeCountsRef.set(biomeCounts);
            }
            for (int x = 0; x < TILE_SIZE; x++) {
                for (int y = 0; y < TILE_SIZE; y++) {
                    for (int i = 0; i < 3; i++) {
                        for (int j = 0; j < biomeCounts[i].length; j++) {
                            biomeCounts[i][j] = 0;
                        }
                    }
                    for (int dx = 0; dx < scale; dx++) {
                        for (int dz = 0; dz < scale; dz++) {
                            int biome = buffer[x * scale + dx + (y * scale + dz) * TILE_SIZE * scale];
                            biomeCounts[BIOME_PRIORITIES[biome]][biome]++;
                        }
                    }
                    int mostCommonBiome = -1;
                    for (int i = 2; i >= 0; i--) {
                        int mostCommonBiomeCount = 0;
                        for (int j = 0; j < biomeCounts[i].length; j++) {
                            if (biomeCounts[i][j] > mostCommonBiomeCount) {
                                mostCommonBiome = j;
                                mostCommonBiomeCount = biomeCounts[i][j];
                            }
                        }
                        if (mostCommonBiome != -1) {
                            break;
                        }
                    }
                    if ((biomePatterns[mostCommonBiome] != null) && (biomePatterns[mostCommonBiome][x % 16][y % 16])) {
                        tile.setRGB(x, y, patternColour);
                    } else {
                        tile.setRGB(x, y, biomeColours[mostCommonBiome]);
                    }
                }
            }
            Graphics2D g2 = (Graphics2D) image.getGraphics();
            try {
                g2.drawImage(tile, imageX, imageY, null);
            } finally {
                g2.dispose();
            }
        } catch (Throwable t) {
            logger.error("Exception while generating image for tile at {}, {}", tileX, tileY, t);
        }
        return true;
    }

    @Override
    public int getTilePriority(int x, int y) {
        return 0; // All tiles have equal priority
    }

    @Override
    public Rectangle getExtent() {
        return null;
    }

    @Override
    public void addTileListener(TileListener tileListener) {
        // Do nothing (tiles never change)
    }

    @Override
    public void removeTileListener(TileListener tileListener) {
        // Do nothing (tiles never change)
    }

    private synchronized BiomeScheme getBiomeScheme() {
        if (biomeScheme == null) {
            try {
                biomeScheme = BiomeSchemeManager.getSharedBiomeScheme(biomeAlgorithm);
                if (biomeScheme == null) {
                    switch (biomeAlgorithm) {
                        case BIOME_ALGORITHM_1_7_DEFAULT:
                            biomeScheme = BiomeSchemeManager.getSharedBiomeScheme(BIOME_ALGORITHM_1_2_AND_1_3_DEFAULT);
                            break;
                        case BIOME_ALGORITHM_1_7_LARGE:
                            biomeScheme = BiomeSchemeManager.getSharedBiomeScheme(BIOME_ALGORITHM_1_3_LARGE);
                            break;
                    }
                }
            } catch (Exception e) {
                // TODO: this seems to happen with the Minecraft 1.6 jar
                // Why?
                logger.error("An exception occurred while trying to load or initialize Minecraft jar; continuing without showing biomes", e);
            } catch (Error e) {
                // TODO: this seems to happen with the Minecraft 1.6 jar
                // Why?
                logger.error("An error occurred while trying to load or initialize Minecraft jar; continuing without showing biomes", e);
            }
            if (biomeScheme != null) {
                biomeScheme.setSeed(minecraftSeed);
                init();
            } else {
                enabled = false;
            }
        }
        return biomeScheme;
    }

    private void init() {
        int biomeCount = biomeScheme.getBiomeCount();
        biomeColours = new int[biomeCount];
        biomePatterns = new boolean[biomeCount][][];
        for (int i = 0; i < biomeCount; i++) {
            if (biomeScheme.isBiomePresent(i)) {
                biomeColours[i] = 0xff000000 | (fade ? ColourUtils.mix(0xffffff, biomeScheme.getColour(i, colourScheme)) : biomeScheme.getColour(i, colourScheme));
                biomePatterns[i] = biomeScheme.getPattern(i);
            }
        }
    }

    private final ColourScheme colourScheme;
    private int biomeAlgorithm;
    private long minecraftSeed;
    private final ThreadLocal biomeCountsRef = new ThreadLocal<>();
    private final int patternColour;
    private final boolean fade;
    private BiomeScheme biomeScheme;
    private int zoom;
    private volatile ThreadLocal bufferRef = new ThreadLocal<>();
    private int[] biomeColours;
    private boolean[][][] biomePatterns;
    private volatile boolean enabled = true;

    private static final ThreadLocal renderBufferRef = new ThreadLocal() {
        @Override
        protected BufferedImage initialValue() {
            return new BufferedImage(TILE_SIZE, TILE_SIZE, BufferedImage.TYPE_INT_ARGB);
        }
    };
    private static final Logger logger = LoggerFactory.getLogger(BiomesTileProvider.class);
    private static final int[] BIOME_PRIORITIES = new int[256];
    static {
        // Every biome should have medium priority except the exceptions below
        Arrays.fill(BIOME_PRIORITIES, 1);
        
        // Ocean should have low priority:
        BIOME_PRIORITIES[BIOME_OCEAN] = 0;
        BIOME_PRIORITIES[BIOME_FROZEN_OCEAN] = 0;
        BIOME_PRIORITIES[BIOME_DEEP_OCEAN] = 0;

        // River should have high priority
        BIOME_PRIORITIES[BIOME_RIVER] = 2;
        BIOME_PRIORITIES[BIOME_FROZEN_RIVER] = 2;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy