205 lines
7.1 KiB
Java
205 lines
7.1 KiB
Java
/*
|
|
*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2020 TerraForged
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
package com.terraforged.core.world.biome;
|
|
|
|
import me.dags.noise.util.NoiseUtil;
|
|
|
|
import javax.imageio.ImageIO;
|
|
import javax.swing.*;
|
|
import java.awt.*;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
|
|
public class BiomeTypeLoader {
|
|
|
|
private static BiomeTypeLoader instance;
|
|
|
|
private final float[][] edges = new float[BiomeType.RESOLUTION][BiomeType.RESOLUTION];
|
|
private final BiomeType[][] map = new BiomeType[BiomeType.RESOLUTION][BiomeType.RESOLUTION];
|
|
|
|
public BiomeTypeLoader() {
|
|
generateTypeMap();
|
|
generateEdgeMap();
|
|
}
|
|
|
|
public BiomeType[][] getTypeMap() {
|
|
return map;
|
|
}
|
|
|
|
public float[][] getEdgeMap() {
|
|
return edges;
|
|
}
|
|
|
|
private BiomeType getType(int x, int y) {
|
|
return map[y][x];
|
|
}
|
|
|
|
private void generateTypeMap() {
|
|
try {
|
|
BufferedImage image = ImageIO.read(BiomeType.class.getResourceAsStream("/biomes.png"));
|
|
float xf = image.getWidth() / (float) BiomeType.RESOLUTION;
|
|
float yf = image.getHeight() / (float) BiomeType.RESOLUTION;
|
|
for (int y = 0; y < BiomeType.RESOLUTION; y++) {
|
|
for (int x = 0; x < BiomeType.RESOLUTION; x++) {
|
|
if (BiomeType.MAX - y > x) {
|
|
map[BiomeType.MAX - y][x] = BiomeType.ALPINE;
|
|
continue;
|
|
}
|
|
int ix = NoiseUtil.round(x * xf);
|
|
int iy = NoiseUtil.round(y * yf);
|
|
int argb = image.getRGB(ix, iy);
|
|
Color color = fromARGB(argb);
|
|
map[BiomeType.MAX - y][x] = forColor(color);
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
private void generateEdgeMap() {
|
|
int[] distances = new int[BiomeType.values().length];
|
|
for (int y = 0; y < BiomeType.RESOLUTION; y++) {
|
|
for (int x = 0; x < BiomeType.RESOLUTION; x++) {
|
|
if (y > x) continue;
|
|
BiomeType type = getType(x, y);
|
|
if (type == BiomeType.ALPINE) {
|
|
continue;
|
|
}
|
|
int distance2 = getEdge(x, y, type);
|
|
edges[y][x] = distance2;
|
|
distances[type.ordinal()] = Math.max(distances[type.ordinal()], distance2);
|
|
}
|
|
}
|
|
|
|
for (int y = 0; y < BiomeType.RESOLUTION; y++) {
|
|
for (int x = 0; x < BiomeType.RESOLUTION; x++) {
|
|
BiomeType type = getType(x, y);
|
|
int max = distances[type.ordinal()];
|
|
float distance = edges[y][x];
|
|
float value = NoiseUtil.pow(distance / max, 0.33F);
|
|
edges[y][x] = NoiseUtil.clamp(value, 0, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
private int getEdge(int cx, int cy, BiomeType type) {
|
|
int radius = BiomeType.RESOLUTION / 4;
|
|
int distance2 = Integer.MAX_VALUE;
|
|
int x0 = Math.max(0, cx - radius);
|
|
int x1 = Math.min(BiomeType.MAX, cx + radius);
|
|
int y0 = Math.max(0, cy - radius);
|
|
int y1 = Math.min(BiomeType.MAX, cy + radius);
|
|
for (int y = y0; y <= y1; y++) {
|
|
for (int x = x0; x <= x1; x++) {
|
|
BiomeType neighbour = getType(x, y);
|
|
|
|
if (neighbour == BiomeType.ALPINE) {
|
|
continue;
|
|
}
|
|
|
|
if (neighbour != type) {
|
|
int dist2 = dist2(cx, cy, x, y);
|
|
if (dist2 < distance2) {
|
|
distance2 = dist2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return distance2;
|
|
}
|
|
|
|
private static BiomeType forColor(Color color) {
|
|
BiomeType type = null;
|
|
int closest = Integer.MAX_VALUE;
|
|
for (BiomeType t : BiomeType.values()) {
|
|
int distance2 = getDistance2(color, t.getLookup());
|
|
if (distance2 < closest) {
|
|
closest = distance2;
|
|
type = t;
|
|
}
|
|
}
|
|
if (type == null) {
|
|
return BiomeType.GRASSLAND;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
private static int getDistance2(Color a, Color b) {
|
|
int dr = a.getRed() - b.getRed();
|
|
int dg = a.getGreen() - b.getGreen();
|
|
int db = a.getBlue() - b.getBlue();
|
|
return dr * dr + dg * dg + db * db;
|
|
}
|
|
|
|
private static Color fromARGB(int argb) {
|
|
int b = (argb) & 0xFF;
|
|
int g = (argb >> 8) & 0xFF;
|
|
int r = (argb >> 16) & 0xFF;
|
|
return new Color(r, g, b);
|
|
}
|
|
|
|
private static int dist2(int x1, int y1, int x2, int y2) {
|
|
int dx = x1 - x2;
|
|
int dy = y1 - y2;
|
|
return dx * dx + dy * dy;
|
|
}
|
|
|
|
private static BufferedImage generateEdgeMapImage() {
|
|
BufferedImage image = new BufferedImage(BiomeType.RESOLUTION, BiomeType.RESOLUTION, BufferedImage.TYPE_INT_RGB);
|
|
for (int y = 0; y < BiomeType.RESOLUTION; y++) {
|
|
for (int x = 0; x < BiomeType.RESOLUTION; x++) {
|
|
float temperature = x / (float) BiomeType.RESOLUTION;
|
|
float moisture = y / (float) BiomeType.RESOLUTION;
|
|
float value = BiomeType.getEdge(temperature, moisture);
|
|
int color = Color.HSBtoRGB(0, 0, value);
|
|
image.setRGB(x, image.getHeight() - 1 - y, color);
|
|
}
|
|
}
|
|
return image;
|
|
}
|
|
|
|
public static BiomeTypeLoader getInstance() {
|
|
if (instance == null) {
|
|
instance = new BiomeTypeLoader();
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
public static void main(String[] args) throws Throwable {
|
|
BufferedImage img = generateEdgeMapImage();
|
|
ImageIO.write(img, "png", new File("biomes_dist.png"));
|
|
JLabel label = new JLabel(new ImageIcon(img));
|
|
JFrame frame = new JFrame();
|
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
|
frame.add(label);
|
|
frame.pack();
|
|
frame.setLocationRelativeTo(null);
|
|
frame.setVisible(true);
|
|
}
|
|
}
|