Add biome color computation

Rather than using fixed values for all biomes, generate grass and foliage
colors based on (height-dependent) temperature and rainfall parameters.

This changes a lot of colors; in general, the new colors should be closer
to the actual Minecraft rendering. It also fixes a few colors that were
completely off (like in the badlands biomes) and adds the MC 1.13 biomes
(which were rendered in black).

Some of the newer biomes (warm/cold/... oceans) don't have proper
parameters yet, and we do not derive the water color from the biome yet.

Fixes #1.
This commit is contained in:
Matthias Schiffer 2018-11-08 17:12:40 +01:00
parent 4ffa28dd63
commit 0bdf249307
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
7 changed files with 382 additions and 219 deletions

View file

@ -10,7 +10,6 @@ add_executable(MinedMap
NBT/Tag.cpp
Resource/Biome.cpp
Resource/BlockType.cpp
World/Block.cpp
World/Chunk.cpp
World/ChunkData.cpp
World/Level.cpp

View file

@ -51,7 +51,7 @@ namespace MinedMap {
static const size_t DIM = World::Region::SIZE*World::Chunk::SIZE;
static void addChunk(World::Block::Color image[DIM*DIM], uint8_t lightmap[2*DIM*DIM], size_t X, size_t Z, const World::ChunkData *data) {
static void addChunk(Resource::Color image[DIM*DIM], uint8_t lightmap[2*DIM*DIM], size_t X, size_t Z, const World::ChunkData *data) {
World::Chunk chunk(data);
World::Chunk::Blocks layer = chunk.getTopLayer();
@ -137,7 +137,7 @@ static void doRegion(const std::string &input, const std::string &output, const
std::printf("Generating %s from %s...\n", output.c_str(), input.c_str());
try {
std::unique_ptr<World::Block::Color[]> image(new World::Block::Color[DIM*DIM]);
std::unique_ptr<Resource::Color[]> image(new Resource::Color[DIM*DIM]);
std::memset(image.get(), 0, 4*DIM*DIM);
std::unique_ptr<uint8_t[]> lightmap(new uint8_t[2*DIM*DIM]);

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2015, 2018, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -26,179 +26,344 @@
#include "Biome.hpp"
#include "BlockType.hpp"
#include "../Util.hpp"
namespace MinedMap {
namespace Resource {
const Biome BIOMES[256] = {
/* 0 */ {0.25, 1, 0.25},
/* 1 */ {0.3, 1, 0.3},
/* 2 */ {1, 1, 0.25},
/* 3 */ {0.3, 0.9, 0.3},
/* 4 */ {0.15, 0.75, 0.15},
/* 5 */ {0.5, 0.75, 0.5},
/* 6 */ {0.75, 1, 0.25},
/* 7 */ {0.25, 1, 0.25},
/* 8 */ {1, 0.1, 0.1},
/* 9 */ {1.5, 1.5, 0.75},
/* 10 */ {0.25, 1, 0.25},
/* 11 */ {0.25, 1, 0.25},
/* 12 */ {0.3, 1, 0.3},
/* 13 */ {0.3, 0.9, 0.3},
/* 14 */ {0.75, 0.1, 0.75},
/* 15 */ {0.75, 0.1, 0.75},
/* 16 */ {1, 1, 0.25},
/* 17 */ {1, 1, 0.25},
/* 18 */ {0.15, 0.75, 0.15},
/* 19 */ {0.5, 0.75, 0.5},
/* 20 */ {0.3, 0.9, 0.3},
/* 21 */ {0.1, 1.25, 0.1},
/* 22 */ {0.1, 1.25, 0.1},
/* 23 */ {0.1, 1.25, 0.1},
/* 24 */ {0.25, 1, 0.25},
/* 25 */ {1, 1, 0.25},
/* 26 */ {1, 1, 0.25},
/* 27 */ {0.15, 0.75, 0.15},
/* 28 */ {0.15, 0.75, 0.15},
/* 29 */ {0.15, 0.75, 0.15},
/* 30 */ {0.5, 0.75, 0.5},
/* 31 */ {0.5, 0.75, 0.5},
/* 32 */ {0.5, 0.75, 0.5},
/* 33 */ {0.5, 0.75, 0.5},
/* 34 */ {0.3, 0.9, 0.3},
/* 35 */ {0.6, 1, 0.25},
/* 36 */ {0.6, 1, 0.25},
/* 37 */ {0.25, 1, 1.25},
/* 38 */ {0.25, 1, 1.25},
/* 39 */ {0.25, 1, 1.25},
/* 40 */ {},
/* 41 */ {},
/* 42 */ {},
/* 43 */ {},
/* 44 */ {},
/* 45 */ {},
/* 46 */ {},
/* 47 */ {},
/* 48 */ {},
/* 49 */ {},
/* 50 */ {},
/* 51 */ {},
/* 52 */ {},
/* 53 */ {},
/* 54 */ {},
/* 55 */ {},
/* 56 */ {},
/* 57 */ {},
/* 58 */ {},
/* 59 */ {},
/* 60 */ {},
/* 61 */ {},
/* 62 */ {},
/* 63 */ {},
/* 64 */ {},
/* 65 */ {},
/* 66 */ {},
/* 67 */ {},
/* 68 */ {},
/* 69 */ {},
/* 70 */ {},
/* 71 */ {},
/* 72 */ {},
/* 73 */ {},
/* 74 */ {},
/* 75 */ {},
/* 76 */ {},
/* 77 */ {},
/* 78 */ {},
/* 79 */ {},
/* 80 */ {},
/* 81 */ {},
/* 82 */ {},
/* 83 */ {},
/* 84 */ {},
/* 85 */ {},
/* 86 */ {},
/* 87 */ {},
/* 88 */ {},
/* 89 */ {},
/* 90 */ {},
/* 91 */ {},
/* 92 */ {},
/* 93 */ {},
/* 94 */ {},
/* 95 */ {},
/* 96 */ {},
/* 97 */ {},
/* 98 */ {},
/* 99 */ {},
/* 100 */ {},
/* 101 */ {},
/* 102 */ {},
/* 103 */ {},
/* 104 */ {},
/* 105 */ {},
/* 106 */ {},
/* 107 */ {},
/* 108 */ {},
/* 109 */ {},
/* 110 */ {},
/* 111 */ {},
/* 112 */ {},
/* 113 */ {},
/* 114 */ {},
/* 115 */ {},
/* 116 */ {},
/* 117 */ {},
/* 118 */ {},
/* 119 */ {},
/* 120 */ {},
/* 121 */ {},
/* 122 */ {},
/* 123 */ {},
/* 124 */ {},
/* 125 */ {},
/* 126 */ {},
/* 127 */ {},
/* 128 */ {0.3, 1, 0.3},
/* 129 */ {0.3, 1, 0.3},
/* 130 */ {1, 1, 0.25},
/* 131 */ {0.3, 0.9, 0.3},
/* 132 */ {0.15, 0.75, 0.15},
/* 133 */ {0.5, 0.75, 0.5},
/* 134 */ {0.75, 1, 0.25},
/* 135 */ {},
/* 136 */ {},
/* 137 */ {},
/* 138 */ {},
/* 139 */ {},
/* 140 */ {0.3, 1, 0.3},
/* 141 */ {},
/* 142 */ {},
/* 143 */ {},
/* 144 */ {},
/* 145 */ {},
/* 146 */ {},
/* 147 */ {},
/* 148 */ {},
/* 149 */ {0.1, 1.25, 0.1},
/* 150 */ {},
/* 151 */ {0.1, 1.25, 0.1},
/* 152 */ {},
/* 153 */ {},
/* 154 */ {},
/* 155 */ {0.15, 0.75, 0.15},
/* 156 */ {0.15, 0.75, 0.15},
/* 157 */ {0.15, 0.75, 0.15},
/* 158 */ {0.5, 0.75, 0.5},
/* 159 */ {},
/* 160 */ {0.5, 0.75, 0.5},
/* 161 */ {0.5, 0.75, 0.5},
/* 162 */ {0.3, 0.9, 0.3},
/* 163 */ {0.6, 1, 0.25},
/* 164 */ {0.6, 1, 0.25},
/* 165 */ {0.25, 1, 1.25},
/* 166 */ {0.25, 1, 1.25},
/* 167 */ {0.25, 1, 1.25},
static Biome::FloatColor operator+(const Biome::FloatColor &a, const Biome::FloatColor &b){
return Biome::FloatColor {
a.r+b.r,
a.g+b.g,
a.b+b.b,
};
}
static Biome::FloatColor & operator*=(Biome::FloatColor &a, const Biome::FloatColor &b) {
a.r *= b.r;
a.g *= b.g;
a.b *= b.b;
return a;
}
static Biome::FloatColor operator*(float s, const Biome::FloatColor &c) {
return Biome::FloatColor {
s*c.r,
s*c.g,
s*c.b,
};
}
static Biome::FloatColor colorFromParams(float temp, float rain, bool grass) {
const Biome::FloatColor grassColors[3] = {
{0.502f, 0.706f, 0.592f}, // lower right
{0.247f, 0.012f, -0.259f}, // lower left - lower right
{-0.471f, 0.086f, -0.133f}, // upper left - lower left
};
const Biome::FloatColor foliageColors[3] = {
{0.376f, 0.631f, 0.482f}, // lower right
{0.306f, 0.012f, -0.317f}, // lower left - lower right
{-0.580f, 0.106f, -0.165f}, // upper left - lower left
};
const Biome::FloatColor *colors = grass ? grassColors : foliageColors;
return colors[0] + temp*colors[1] + rain*colors[2];
}
Biome::FloatColor Biome::getGrassColor(float temp, float rain) const {
return colorFromParams(temp, rain, true);
}
Biome::FloatColor Biome::getFoliageColor(float temp, float rain) const {
return colorFromParams(temp, rain, false);
}
Biome::FloatColor Biome::getWaterColor(float, float) const {
return {0.161f, 0.365f, 0.996f};
}
Color Biome::getBlockColor(const BlockType *type, unsigned height) const {
Biome::FloatColor c = {
float(type->color.r),
float(type->color.g),
float(type->color.b),
};
float t = clamp(temp - std::max(0.0f, (height-64)/600.0f), 0, 1);
float r = clamp(rain, 0, 1) * t;
if (type->grass)
c *= getGrassColor(t, r);
if (type->foliage)
c *= getFoliageColor(t, r);
if (type->blue)
c *= getWaterColor(t, r);
float h = 0.5f + height * 0.005f;
return Color {
uint8_t(clamp(c.r * h, 0, 255)),
uint8_t(clamp(c.g * h, 0, 255)),
uint8_t(clamp(c.b * h, 0, 255)),
0xff,
};
}
class SwampBiome : public Biome {
protected:
virtual FloatColor getGrassColor(float, float) const {
return {0.417f, 0.439f, 0.224f};
}
virtual FloatColor getFoliageColor(float temp, float rain) const {
return getGrassColor(temp, rain);
}
virtual FloatColor getWaterColor(float, float) const {
return {0.141f, 0.365f, 0.680f};
}
public:
SwampBiome(float temp0, float rain0) : Biome(temp0, rain0) {}
};
class DarkForestBiome : public Biome {
private:
const FloatColor darkGreen = {0.157f, 0.204f, 0.039f};
protected:
virtual FloatColor getGrassColor(float temp, float rain) const {
return 0.5 * (darkGreen + colorFromParams(temp, rain, true));
}
virtual FloatColor getFoliageColor(float temp, float rain) const {
return 0.5 * (darkGreen + colorFromParams(temp, rain, false));
}
public:
DarkForestBiome(float temp0, float rain0) : Biome(temp0, rain0) {}
};
class BadlandsBiome : public Biome {
protected:
virtual FloatColor getGrassColor(float, float) const {
return {0.565f, 0.506f, 0.302f};
}
virtual FloatColor getFoliageColor(float, float) const {
return {0.620f, 0.506f, 0.302f};
}
public:
BadlandsBiome(float temp0, float rain0) : Biome(temp0, rain0) {}
};
/* Values from https://github.com/erich666/Mineways/blob/master/Win/biomes.cpp */
static const Biome BiomeDefault(0.5f, 0.5f);
static const Biome BiomePlains(0.8f, 0.4f);
static const Biome BiomeDesert(2.0f, 0.0f);
static const Biome BiomeMountains(0.2f, 0.3f);
static const Biome BiomeForest(0.7f, 0.8f);
static const Biome BiomeTaiga(0.25f, 0.8f);
static const SwampBiome BiomeSwamp(0.8f, 0.9f);
static const Biome BiomeFrozen(0.0f, 0.5f);
static const Biome BiomeMushroomFields(0.9f, 1.0f);
static const Biome BiomeJungle(0.95f, 0.9f);
static const Biome BiomeJungleEdge(0.95f, 0.8f);
static const Biome BiomeSnowyBeach(0.05f, 0.3f);
static const Biome BiomeBirchForest(0.6f, 0.6f);
static const DarkForestBiome BiomeDarkForest(0.7f, 0.8f);
static const Biome BiomeSnowyTaiga(-0.5f, 0.4f);
static const Biome BiomeGiantTreeTaiga(0.3f, 0.8f);
static const Biome BiomeSavanna(1.2f, 0.0f);
static const Biome BiomeSavannaPlateau(1.0f, 0.0f);
static const Biome BiomeShatteredSavanna(1.1f, 0.0f);
static const BadlandsBiome BiomeBadlands(2.0f, 0.0f);
extern const Biome *const BIOME_DEFAULT = &BiomeDefault;
/*
* TODO: Add proper temp/rain values for oceans 44-50
*
* It does not matter much at the moment, as we do not compute
* the water color anyways
*/
const Biome *const BIOMES[256] = {
/* 0 */ &BiomeDefault, /* Ocean */
/* 1 */ &BiomePlains,
/* 2 */ &BiomeDesert,
/* 3 */ &BiomeMountains,
/* 4 */ &BiomeForest,
/* 5 */ &BiomeTaiga,
/* 6 */ &BiomeSwamp,
/* 7 */ &BiomeDefault, /* River */
/* 8 */ &BiomeDesert, /* Nether */
/* 9 */ &BiomeDefault, /* The End */
/* 10 */ &BiomeFrozen, /* Frozen Ocean */
/* 11 */ &BiomeFrozen, /* Frozen River */
/* 12 */ &BiomeFrozen, /* Snowy Tundra */
/* 13 */ &BiomeFrozen, /* Snowy Mountains */
/* 14 */ &BiomeMushroomFields,
/* 15 */ &BiomeMushroomFields, /* Mushroom Field Shore */
/* 16 */ &BiomePlains, /* Beach */
/* 17 */ &BiomeDesert, /* Desert Hills */
/* 18 */ &BiomeForest, /* Wooded Hiils */
/* 19 */ &BiomeTaiga, /* Taiga Hills */
/* 20 */ &BiomeMountains, /* Moutain Edge */
/* 21 */ &BiomeJungle,
/* 22 */ &BiomeJungle, /* Jungle Hills */
/* 23 */ &BiomeJungleEdge,
/* 24 */ &BiomeDefault, /* Deep Ocean */
/* 25 */ &BiomeMountains, /* Stone Shore */
/* 26 */ &BiomeSnowyBeach,
/* 27 */ &BiomeBirchForest,
/* 28 */ &BiomeBirchForest, /* Birch Forest Hills */
/* 29 */ &BiomeDarkForest,
/* 30 */ &BiomeSnowyTaiga,
/* 31 */ &BiomeSnowyTaiga, /* Snowy Taiga Hills */
/* 32 */ &BiomeGiantTreeTaiga,
/* 33 */ &BiomeGiantTreeTaiga, /* Giant Tree Taiga Hills */
/* 34 */ &BiomeMountains, /* Wooded Mountains */
/* 35 */ &BiomeSavanna,
/* 36 */ &BiomeSavanna, /* Savanna Plateau */
/* 37 */ &BiomeBadlands,
/* 38 */ &BiomeBadlands, /* Wooded Badlands Plateau */
/* 39 */ &BiomeBadlands, /* Badlands Plateau */
/* 40 */ &BiomeDefault, /* Small End Islands */
/* 41 */ &BiomeDefault, /* End Midlands */
/* 42 */ &BiomeDefault, /* End Highlands */
/* 43 */ &BiomeDefault, /* End Barrens */
/* 44 */ &BiomeDefault, /* Warm Ocean */
/* 45 */ &BiomeDefault, /* Lukewarm Ocean */
/* 46 */ &BiomeDefault, /* Cold Ocean */
/* 47 */ &BiomeDefault, /* Deep Warm Ocean */
/* 48 */ &BiomeDefault, /* Deep Lukewarm Ocean */
/* 49 */ &BiomeDefault, /* Deep Cold Ocean */
/* 50 */ &BiomeFrozen, /* Deep Frozen Ocean */
/* 51 */ nullptr,
/* 52 */ nullptr,
/* 53 */ nullptr,
/* 54 */ nullptr,
/* 55 */ nullptr,
/* 56 */ nullptr,
/* 57 */ nullptr,
/* 58 */ nullptr,
/* 59 */ nullptr,
/* 60 */ nullptr,
/* 61 */ nullptr,
/* 62 */ nullptr,
/* 63 */ nullptr,
/* 64 */ nullptr,
/* 65 */ nullptr,
/* 66 */ nullptr,
/* 67 */ nullptr,
/* 68 */ nullptr,
/* 69 */ nullptr,
/* 70 */ nullptr,
/* 71 */ nullptr,
/* 72 */ nullptr,
/* 73 */ nullptr,
/* 74 */ nullptr,
/* 75 */ nullptr,
/* 76 */ nullptr,
/* 77 */ nullptr,
/* 78 */ nullptr,
/* 79 */ nullptr,
/* 80 */ nullptr,
/* 81 */ nullptr,
/* 82 */ nullptr,
/* 83 */ nullptr,
/* 84 */ nullptr,
/* 85 */ nullptr,
/* 86 */ nullptr,
/* 87 */ nullptr,
/* 88 */ nullptr,
/* 89 */ nullptr,
/* 90 */ nullptr,
/* 91 */ nullptr,
/* 92 */ nullptr,
/* 93 */ nullptr,
/* 94 */ nullptr,
/* 95 */ nullptr,
/* 96 */ nullptr,
/* 97 */ nullptr,
/* 98 */ nullptr,
/* 99 */ nullptr,
/* 100 */ nullptr,
/* 101 */ nullptr,
/* 102 */ nullptr,
/* 103 */ nullptr,
/* 104 */ nullptr,
/* 105 */ nullptr,
/* 106 */ nullptr,
/* 107 */ nullptr,
/* 108 */ nullptr,
/* 109 */ nullptr,
/* 110 */ nullptr,
/* 111 */ nullptr,
/* 112 */ nullptr,
/* 113 */ nullptr,
/* 114 */ nullptr,
/* 115 */ nullptr,
/* 116 */ nullptr,
/* 117 */ nullptr,
/* 118 */ nullptr,
/* 119 */ nullptr,
/* 120 */ nullptr,
/* 121 */ nullptr,
/* 122 */ nullptr,
/* 123 */ nullptr,
/* 124 */ nullptr,
/* 125 */ nullptr,
/* 126 */ nullptr,
/* 127 */ &BiomeDefault, /* The Void */
/* 128 */ nullptr,
/* 129 */ &BiomeDefault, /* Sunflower Plains */
/* 130 */ &BiomeDesert, /* Desert Lakes */
/* 131 */ &BiomeMountains, /* Gravelly Mountains */
/* 132 */ &BiomeForest, /* Flower Forest */
/* 133 */ &BiomeTaiga, /* Taiga Mountains */
/* 134 */ &BiomeSwamp, /* Swamp Hills */
/* 135 */ nullptr,
/* 136 */ nullptr,
/* 137 */ nullptr,
/* 138 */ nullptr,
/* 139 */ nullptr,
/* 140 */ &BiomeFrozen, /* Ice Spikes */
/* 141 */ nullptr,
/* 142 */ nullptr,
/* 143 */ nullptr,
/* 144 */ nullptr,
/* 145 */ nullptr,
/* 146 */ nullptr,
/* 147 */ nullptr,
/* 148 */ nullptr,
/* 149 */ &BiomeJungle, /* Modified Jungle */
/* 150 */ nullptr,
/* 151 */ &BiomeJungleEdge, /* Modified Jungle Edge */
/* 152 */ nullptr,
/* 153 */ nullptr,
/* 154 */ nullptr,
/* 155 */ &BiomeBirchForest, /* Tall Birch Forest */
/* 156 */ &BiomeBirchForest, /* Tall Birch Hills */
/* 157 */ &BiomeDarkForest, /* Dark Forest Hills */
/* 158 */ &BiomeSnowyTaiga, /* Snowy Taiga Mountains */
/* 159 */ nullptr,
/* 160 */ &BiomeTaiga, /* Giant Spruce Taiga */
/* 161 */ &BiomeTaiga, /* Giant Spruce Taiga Hills */
/* 162 */ &BiomeMountains, /* Gravelly Mountains+ */
/* 163 */ &BiomeShatteredSavanna,
/* 164 */ &BiomeSavannaPlateau, /* Shattered Savanna Plateau */
/* 165 */ &BiomeBadlands, /* Eroded Badlands */
/* 166 */ &BiomeBadlands, /* Modified Wooded Badlands Plateau */
/* 167 */ &BiomeBadlands, /* Modified Badlands Plateau */
};
}

View file

@ -26,14 +26,36 @@
#pragma once
#include "Color.hpp"
namespace MinedMap {
namespace Resource {
struct Biome {
float r, g, b;
class BlockType;
class Biome {
public:
struct FloatColor {
float r, g, b;
};
private:
float temp, rain;
protected:
virtual FloatColor getGrassColor(float temp, float rain) const;
virtual FloatColor getFoliageColor(float temp, float rain) const;
virtual FloatColor getWaterColor(float temp, float rain) const;
public:
Biome(float temp0, float rain0) : temp(temp0), rain(rain0) {}
Color getBlockColor(const BlockType *type, unsigned height) const;
};
extern const Biome BIOMES[256];
extern const Biome *const BIOME_DEFAULT;
extern const Biome *const BIOMES[256];
}
}

View file

@ -1,5 +1,5 @@
/*
Copyright (c) 2015, Matthias Schiffer <mschiffer@universe-factory.net>
Copyright (c) 2018, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -24,47 +24,17 @@
*/
#include "Block.hpp"
#include "../Resource/Biome.hpp"
#pragma once
#include <cstdint>
namespace MinedMap {
namespace World {
namespace Resource {
Block::Color Block::getColor() const {
if (!type || !type->opaque)
return Color {};
float r = type->color.r;
float g = type->color.g;
float b = type->color.b;
float heightCoef = height/255.0f + 0.5f;
r *= heightCoef;
g *= heightCoef;
b *= heightCoef;
if (type->grass || type->foliage) {
const Resource::Biome &biomeDef = Resource::BIOMES[biome];
r *= biomeDef.r;
g *= biomeDef.g;
b *= biomeDef.b;
}
if (type->blue) {
r *= 0.265;
g *= 0.382;
b *= 1.379;
}
if (r > 255) r = 255;
if (g > 255) g = 255;
if (b > 255) b = 255;
return Color {uint8_t(r), uint8_t(g), uint8_t(b), 0xff};
}
struct Color {
uint8_t r, g, b, a;
};
}
}

View file

@ -26,6 +26,7 @@
#pragma once
#include <algorithm>
#include <stdexcept>
#include <utility>
@ -39,4 +40,8 @@ template <typename T> static inline T assertValue(T&& val) {
return std::forward<T>(val);
}
static inline float clamp(float v, float min, float max) {
return std::max(std::min(v, max), min);
}
}

View file

@ -27,6 +27,7 @@
#pragma once
#include "../NBT/CompoundTag.hpp"
#include "../Resource/Biome.hpp"
#include "../Resource/BlockType.hpp"
@ -34,17 +35,18 @@ namespace MinedMap {
namespace World {
struct Block {
struct Color {
uint8_t r, g, b, a;
};
const Resource::BlockType *type;
unsigned height;
uint8_t blockLight;
uint8_t biome;
Color getColor() const;
Resource::Color getColor() const {
if (!type || !type->opaque)
return Resource::Color {};
return (Resource::BIOMES[biome] ?: Resource::BIOME_DEFAULT)->getBlockColor(type, height);
}
operator bool() const {
return type;