2021-07-17 16:06:50 +02:00
|
|
|
/*
|
|
|
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
|
|
|
*
|
|
|
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
|
|
|
* Copyright (c) contributors
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2022-05-28 21:55:41 +02:00
|
|
|
package de.bluecolored.bluemap.core.resources;
|
2021-07-17 16:06:50 +02:00
|
|
|
|
|
|
|
import com.flowpowered.math.GenericMath;
|
2022-05-28 21:55:41 +02:00
|
|
|
import com.google.gson.stream.JsonReader;
|
2022-07-24 12:10:00 +02:00
|
|
|
import de.bluecolored.bluemap.api.debug.DebugDump;
|
2021-07-17 16:06:50 +02:00
|
|
|
import de.bluecolored.bluemap.core.util.math.Color;
|
|
|
|
import de.bluecolored.bluemap.core.world.Biome;
|
2023-11-08 13:27:51 +01:00
|
|
|
import de.bluecolored.bluemap.core.world.block.BlockNeighborhood;
|
2021-07-17 16:06:50 +02:00
|
|
|
|
|
|
|
import java.awt.image.BufferedImage;
|
2022-05-28 21:55:41 +02:00
|
|
|
import java.io.BufferedReader;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.nio.file.Files;
|
|
|
|
import java.nio.file.Path;
|
2021-07-17 16:06:50 +02:00
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
@DebugDump
|
|
|
|
public class BlockColorCalculatorFactory {
|
|
|
|
|
2024-02-05 16:38:33 +01:00
|
|
|
private static final int
|
|
|
|
AVERAGE_MIN_X = - 2,
|
|
|
|
AVERAGE_MAX_X = 2,
|
|
|
|
AVERAGE_MIN_Y = - 1,
|
|
|
|
AVERAGE_MAX_Y = 1,
|
|
|
|
AVERAGE_MIN_Z = - 2,
|
|
|
|
AVERAGE_MAX_Z = 2;
|
|
|
|
|
2021-09-19 22:15:50 +02:00
|
|
|
private final int[] foliageMap = new int[65536];
|
|
|
|
private final int[] grassMap = new int[65536];
|
|
|
|
|
|
|
|
private final Map<String, ColorFunction> blockColorMap;
|
|
|
|
|
|
|
|
public BlockColorCalculatorFactory() {
|
|
|
|
this.blockColorMap = new HashMap<>();
|
|
|
|
}
|
|
|
|
|
2022-05-28 21:55:41 +02:00
|
|
|
public void load(Path configFile) throws IOException {
|
|
|
|
try (BufferedReader reader = Files.newBufferedReader(configFile)) {
|
|
|
|
JsonReader json = new JsonReader(reader);
|
|
|
|
json.setLenient(true);
|
|
|
|
|
|
|
|
json.beginObject();
|
|
|
|
while (json.hasNext()) {
|
|
|
|
|
|
|
|
String key = json.nextName();
|
|
|
|
String value = json.nextString();
|
|
|
|
|
|
|
|
ColorFunction colorFunction;
|
|
|
|
switch (value) {
|
|
|
|
case "@foliage":
|
|
|
|
colorFunction = BlockColorCalculator::getFoliageAverageColor;
|
|
|
|
break;
|
|
|
|
case "@grass":
|
|
|
|
colorFunction = BlockColorCalculator::getGrassAverageColor;
|
|
|
|
break;
|
|
|
|
case "@water":
|
|
|
|
colorFunction = BlockColorCalculator::getWaterAverageColor;
|
|
|
|
break;
|
|
|
|
case "@redstone":
|
|
|
|
colorFunction = BlockColorCalculator::getRedstoneColor;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
final Color color = new Color();
|
2022-10-14 10:00:51 +02:00
|
|
|
color.parse(value).premultiplied();
|
2022-05-28 21:55:41 +02:00
|
|
|
colorFunction = (calculator, block, target) -> target.set(color);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// don't overwrite already present values, higher priority resources are loaded first
|
|
|
|
blockColorMap.putIfAbsent(key, colorFunction);
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
|
2022-05-28 21:55:41 +02:00
|
|
|
json.endObject();
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setFoliageMap(BufferedImage foliageMap) {
|
|
|
|
foliageMap.getRGB(0, 0, 256, 256, this.foliageMap, 0, 256);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setGrassMap(BufferedImage grassMap) {
|
|
|
|
grassMap.getRGB(0, 0, 256, 256, this.grassMap, 0, 256);
|
|
|
|
}
|
|
|
|
|
|
|
|
public BlockColorCalculator createCalculator() {
|
|
|
|
return new BlockColorCalculator();
|
|
|
|
}
|
|
|
|
|
|
|
|
@FunctionalInterface
|
|
|
|
private interface ColorFunction {
|
2022-05-28 21:55:41 +02:00
|
|
|
Color invoke(BlockColorCalculator calculator, BlockNeighborhood<?> block, Color target);
|
2021-09-19 22:15:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public class BlockColorCalculator {
|
|
|
|
|
|
|
|
private final Color tempColor = new Color();
|
|
|
|
|
2022-05-28 21:55:41 +02:00
|
|
|
public Color getBlockColor(BlockNeighborhood<?> block, Color target) {
|
|
|
|
String blockId = block.getBlockState().getFormatted();
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
ColorFunction colorFunction = blockColorMap.get(blockId);
|
|
|
|
if (colorFunction == null) colorFunction = blockColorMap.get("default");
|
|
|
|
if (colorFunction == null) colorFunction = BlockColorCalculator::getFoliageAverageColor;
|
|
|
|
|
|
|
|
return colorFunction.invoke(this, block, target);
|
|
|
|
}
|
|
|
|
|
2022-05-28 21:55:41 +02:00
|
|
|
public Color getRedstoneColor(BlockNeighborhood<?> block, Color target) {
|
2022-10-19 16:25:25 +02:00
|
|
|
int power = block.getBlockState().getRedstonePower();
|
2021-09-19 22:15:50 +02:00
|
|
|
return target.set(
|
|
|
|
(power + 5f) / 20f, 0f, 0f,
|
|
|
|
1f, true
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-05-28 21:55:41 +02:00
|
|
|
public Color getWaterAverageColor(BlockNeighborhood<?> block, Color target) {
|
2021-09-19 22:15:50 +02:00
|
|
|
target.set(0, 0, 0, 0, true);
|
|
|
|
|
2024-02-05 16:38:33 +01:00
|
|
|
int x, y, z;
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
Biome biome;
|
2024-02-05 16:38:33 +01:00
|
|
|
for (y = AVERAGE_MIN_Y; y <= AVERAGE_MAX_Y; y++) {
|
|
|
|
for (x = AVERAGE_MIN_X; x <= AVERAGE_MAX_X; x++) {
|
|
|
|
for (z = AVERAGE_MIN_Z; z <= AVERAGE_MAX_Z; z++) {
|
2021-09-19 22:15:50 +02:00
|
|
|
biome = block.getNeighborBlock(x, y, z).getBiome();
|
|
|
|
target.add(biome.getWaterColor());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return target.flatten();
|
|
|
|
}
|
|
|
|
|
2022-05-28 21:55:41 +02:00
|
|
|
public Color getFoliageAverageColor(BlockNeighborhood<?> block, Color target) {
|
2021-09-19 22:15:50 +02:00
|
|
|
target.set(0, 0, 0, 0, true);
|
|
|
|
|
2024-02-05 16:38:33 +01:00
|
|
|
int x, y, z;
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
Biome biome;
|
2024-02-05 16:38:33 +01:00
|
|
|
for (y = AVERAGE_MIN_Y; y <= AVERAGE_MAX_Y; y++) {
|
|
|
|
for (x = AVERAGE_MIN_X; x <= AVERAGE_MAX_X; x++) {
|
|
|
|
for (z = AVERAGE_MIN_Z; z <= AVERAGE_MAX_Z; z++) {
|
2021-09-19 22:15:50 +02:00
|
|
|
biome = block.getNeighborBlock(x, y, z).getBiome();
|
|
|
|
target.add(getFoliageColor(biome, tempColor));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return target.flatten();
|
|
|
|
}
|
|
|
|
|
|
|
|
public Color getFoliageColor(Biome biome, Color target) {
|
|
|
|
getColorFromMap(biome, foliageMap, 4764952, target);
|
|
|
|
return target.overlay(biome.getOverlayFoliageColor());
|
|
|
|
}
|
|
|
|
|
2022-05-28 21:55:41 +02:00
|
|
|
public Color getGrassAverageColor(BlockNeighborhood<?> block, Color target) {
|
2021-09-19 22:15:50 +02:00
|
|
|
target.set(0, 0, 0, 0, true);
|
|
|
|
|
2024-02-05 16:38:33 +01:00
|
|
|
int x, y, z;
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
Biome biome;
|
2024-02-05 16:38:33 +01:00
|
|
|
for (y = AVERAGE_MIN_Y; y <= AVERAGE_MAX_Y; y++) {
|
|
|
|
for (x = AVERAGE_MIN_X; x <= AVERAGE_MAX_X; x++) {
|
|
|
|
for (z = AVERAGE_MIN_Z; z <= AVERAGE_MAX_Z; z++) {
|
2021-09-19 22:15:50 +02:00
|
|
|
biome = block.getNeighborBlock(x, y, z).getBiome();
|
|
|
|
target.add(getGrassColor(biome, tempColor));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return target.flatten();
|
|
|
|
}
|
|
|
|
|
|
|
|
public Color getGrassColor(Biome biome, Color target) {
|
|
|
|
getColorFromMap(biome, grassMap, 0xff52952f, target);
|
|
|
|
return target.overlay(biome.getOverlayGrassColor());
|
|
|
|
}
|
|
|
|
|
|
|
|
private void getColorFromMap(Biome biome, int[] colorMap, int defaultColor, Color target) {
|
2021-11-20 12:31:18 +01:00
|
|
|
double temperature = GenericMath.clamp(biome.getTemp(), 0.0, 1.0);
|
|
|
|
double humidity = GenericMath.clamp(biome.getHumidity(), 0.0, 1.0);
|
|
|
|
|
|
|
|
humidity *= temperature;
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
int x = (int) ((1.0 - temperature) * 255.0);
|
|
|
|
int y = (int) ((1.0 - humidity) * 255.0);
|
|
|
|
|
|
|
|
int index = y << 8 | x;
|
2022-08-07 20:32:55 +02:00
|
|
|
int color = (index >= colorMap.length ? defaultColor : colorMap[index]) | 0xFF000000;
|
2021-09-19 22:15:50 +02:00
|
|
|
|
|
|
|
target.set(color);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-07-17 16:06:50 +02:00
|
|
|
}
|