The new mapgen, noise functions, et al.

This commit is contained in:
kwolekr 2012-11-25 21:16:48 -05:00 committed by Perttu Ahola
parent 736b386554
commit 11afcbff69
23 changed files with 1892 additions and 1037 deletions

View File

@ -218,6 +218,7 @@ set(common_SRCS
sha1.cpp
base64.cpp
ban.cpp
biome.cpp
clientserver.cpp
staticobject.cpp
util/serialize.cpp

229
src/biome.cpp Normal file
View File

@ -0,0 +1,229 @@
/*
Minetest-c55
Copyright (C) 2010-2011 kwolekr, Ryan Kwolek <kwolekr2@cs.scranton.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "biome.h"
#include "nodedef.h"
#include "map.h" //for ManualMapVoxelManipulator
#include "main.h"
#define BT_NONE 0
#define BT_OCEAN 1
#define BT_LAKE 2
#define BT_SBEACH 3
#define BT_GBEACH 4
#define BT_PLAINS 5
#define BT_HILLS 6
#define BT_EXTREMEHILLS 7
#define BT_MOUNTAINS 8
#define BT_DESERT 9
#define BT_DESERTHILLS 10
#define BT_HELL 11
#define BT_AETHER 12
#define BT_BTMASK 0x3F
#define BTF_SNOW 0x40
#define BTF_FOREST 0x80
#define BGFREQ_1 ( 0.40)
#define BGFREQ_2 (BGFREQ_1 + 0.05)
#define BGFREQ_3 (BGFREQ_2 + 0.08)
#define BGFREQ_4 (BGFREQ_3 + 0.35)
#define BGFREQ_5 (BGFREQ_4 + 0.18)
//BGFREQ_5 is not checked as an upper bound; it ought to sum up to 1.00, but it's okay if it doesn't.
/*float bg1_temps[] = {0.0};
int bg1_biomes[] = {BT_OCEAN};
float bg2_temps[] = {10.0};
int bg2_biomes[] = {BT_GBEACH, BT_SBEACH};
float bg3_temps[] = {30.0, 40.0};
int bg3_biomes[] = {BT_HILLS, BT_EXTREMEHILLS, BT_MOUNTAINS};
float bg4_temps[] = {25.0, 30.0, 35.0, 40.0};
int bg4_biomes[] = {BT_HILLS, BT_EXTREMEHILLS, BT_MOUNTAINS, BT_DESERT, BT_DESERTHILLS};
float bg5_temps[] = {5.0, 40.0};
int bg5_biomes[] = {BT_LAKE, BT_PLAINS, BT_DESERT};*/
BiomeDefManager::BiomeDefManager(IGameDef *gamedef) {
this->m_gamedef = gamedef;
this->ndef = gamedef->ndef();
//addDefaultBiomes(); //can't do this in the ctor, too early
}
BiomeDefManager::~BiomeDefManager() {
for (int i = 0; i != bgroups.size(); i++)
delete bgroups[i];
}
void BiomeDefManager::addBiome() {
}
NoiseParams npmtdef = {0.0, 20.0, v3f(250., 250., 250.), 82341, 5, 0.6};
void BiomeDefManager::addDefaultBiomes() {
std::vector<Biome *> *bgroup;
Biome *b;
//bgroup = new std::vector<Biome *>;
b = new Biome;
b->name = "Default";
b->n_top = MapNode(ndef->getId("mapgen_stone"));
b->n_filler = b->n_top;
b->ntopnodes = 0;
b->height_min = -MAP_GENERATION_LIMIT;
b->height_max = MAP_GENERATION_LIMIT;
b->heat_min = FLT_MIN;
b->heat_max = FLT_MAX;
b->humidity_min = FLT_MIN;
b->humidity_max = FLT_MAX;
b->np = &npmtdef;
biome_default = b;
//bgroup->push_back(b);
//bgroups.push_back(bgroup);
}
Biome *BiomeDefManager::getBiome(float bgfreq, float heat, float humidity) {
std::vector<Biome *> bgroup;
Biome *b;
int i;
int ngroups = bgroup_freqs.size();
if (!ngroups)
return biome_default;
for (i = 0; (i != ngroups - 1) && (bgfreq > bgroup_freqs[i]); i++);
bgroup = *(bgroups[i]);
int nbiomes = bgroup.size();
if (!nbiomes)
return biome_default;
for (i = 0; i != nbiomes - 1; i++) {
b = bgroup[i];
if (heat >= b->heat_min && heat <= b->heat_max &&
humidity >= b->humidity_min && humidity <= b->humidity_max)
return b;
}
return biome_default;
}
//////////////////////////// [ Generic biome ] ////////////////////////////////
int Biome::getSurfaceHeight(float noise_terrain) {
return np->offset + np->scale * noise_terrain;
}
void Biome::genColumn(Mapgen *mg, int x, int z, int y1, int y2) {
//printf("(%d, %d): %f\n", x, z, mg->map_terrain[z * mg->ystride + x]);
//int surfaceh = 4;
int surfaceh = np->offset + np->scale * mg->map_terrain[(z - mg->node_min.Z) * 80 /*THIS IS TEMPORARY mg->ystride*/ + (x - mg->node_min.X)];
//printf("gen column %f\n", );
int y = y1;
int i = mg->vmanip->m_area.index(x, y, z); //z * mg->zstride + x + (y - mg->vmanip->m_area.MinEdge.Y) * mg->ystride;
for (; y <= surfaceh - ntopnodes && y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = n_filler;
for (; y <= surfaceh && y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = n_top;
for (; y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = mg->n_air;
}
///////////////////////////// [ Ocean biome ] /////////////////////////////////
void BiomeOcean::genColumn(Mapgen *mg, int x, int z, int y1, int y2) {
int y, i = 0;
int surfaceh = np->offset + np->scale * mg->map_terrain[z * mg->ystride + x];
i = z * mg->zstride + x;
for (y = y1; y <= surfaceh - ntopnodes && y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = n_filler;
for (; y <= surfaceh && y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = n_top;
for (; y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = mg->n_air;
}
///////////////////////////// [ Nether biome ] /////////////////////////////////
int BiomeHell::getSurfaceHeight(float noise_terrain) {
return np->offset + np->scale * noise_terrain;
}
void BiomeHell::genColumn(Mapgen *mg, int x, int z, int y1, int y2) {
int y, i = 0;
int surfaceh = np->offset + np->scale * mg->map_terrain[z * mg->ystride + x];
i = z * mg->zstride + x;
for (y = y1; y <= surfaceh - ntopnodes && y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = n_filler;
for (; y <= surfaceh && y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = n_top;
for (; y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = mg->n_air;
}
///////////////////////////// [ Aether biome ] ////////////////////////////////
/////////////////////////// [ Superflat biome ] ///////////////////////////////
int BiomeSuperflat::getSurfaceHeight(float noise_terrain) {
return ntopnodes;
}
void BiomeSuperflat::genColumn(Mapgen *mg, int x, int z, int y1, int y2) {
int y, i = 0;
int surfaceh = ntopnodes;
i = z * mg->zstride + x;
for (y = y1; y <= surfaceh - ntopnodes && y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = n_filler;
for (; y <= surfaceh && y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = n_top;
for (; y <= y2; y++, i += mg->ystride)
mg->vmanip->m_data[i] = mg->n_air;
}

79
src/biome.h Normal file
View File

@ -0,0 +1,79 @@
/*
Minetest-c55
Copyright (C) 2010-2011 kwolekr, Ryan Kwolek <kwolekr2@cs.scranton.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef BIOME_HEADER
#define BIOME_HEADER
#include "nodedef.h"
#include "gamedef.h"
#include "mapnode.h"
#include "noise.h"
#include "mapgen.h"
class Biome {
public:
MapNode n_top;
MapNode n_filler;
s16 ntopnodes;
s16 flags;
s16 height_min;
s16 height_max;
float heat_min;
float heat_max;
float humidity_min;
float humidity_max;
const char *name;
NoiseParams *np;
virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2);
virtual int getSurfaceHeight(float noise_terrain);
};
class BiomeOcean : public Biome {
virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2);
};
class BiomeHell : public Biome {
virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2);
virtual int getSurfaceHeight(float noise_terrain);
};
class BiomeSuperflat : public Biome {
virtual void genColumn(Mapgen *mg, int x, int z, int y1, int y2);
virtual int getSurfaceHeight(float noise_terrain);
};
class BiomeDefManager {
public:
std::vector<float> bgroup_freqs;
std::vector<std::vector<Biome *> *> bgroups;
Biome *biome_default;
IGameDef *m_gamedef;
INodeDefManager *ndef;
BiomeDefManager(IGameDef *gamedef);
~BiomeDefManager();
Biome *getBiome(float bgfreq, float heat, float humidity);
void addBiome();
void addDefaultBiomes();
};
#endif

View File

@ -163,7 +163,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("max_block_generate_distance", "7");
settings->setDefault("time_send_interval", "5");
settings->setDefault("time_speed", "72");
settings->setDefault("water_level", "1");
settings->setDefault("default_water_level", "1");
settings->setDefault("server_unload_unused_data_timeout", "29");
settings->setDefault("server_map_save_interval", "5.3");
settings->setDefault("full_block_send_enable_min_time_from_building", "2.0");

View File

@ -1301,6 +1301,7 @@ u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
return id;
}
#if 0
bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
{
assert(obj);
@ -1343,6 +1344,7 @@ bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
return succeeded;
}
#endif
/*
Finds out what new objects have been added to
@ -1563,13 +1565,15 @@ void ServerEnvironment::removeRemovedObjects()
*/
if(obj->m_static_exists && obj->m_removed)
{
MapBlock *block = m_map->emergeBlock(obj->m_static_block);
if(block)
{
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
if (block) {
block->m_static_objects.remove(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
"removeRemovedObjects");
obj->m_static_exists = false;
} else {
infostream << "failed to emerge block from which "
"an object to be removed was loaded from. id="<<id<<std::endl;
}
}
@ -1717,6 +1721,8 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
If force_delete is set, active object is deleted nevertheless. It
shall only be set so in the destructor of the environment.
If block wasn't generated (not in memory or on disk),
*/
void ServerEnvironment::deactivateFarObjects(bool force_delete)
{

View File

@ -241,8 +241,9 @@ public:
MapBlock.
Caller allocates memory, ServerEnvironment frees memory.
Return value: true if succeeded, false if failed.
(note: not used, pending removal from engine)
*/
bool addActiveObjectAsStatic(ServerActiveObject *object);
//bool addActiveObjectAsStatic(ServerActiveObject *object);
/*
Find out what new objects have been added to

View File

@ -120,14 +120,14 @@ HeightPoint ground_height(u64 seed, v2s16 p2d)
if(n)
return n->getValue();
HeightPoint hp;
s16 level = mapgen::find_ground_level_from_noise(seed, p2d, 3);
s16 level = Mapgen::find_ground_level_from_noise(seed, p2d, 3);
hp.gh = (level-4)*BS;
hp.ma = (4)*BS;
/*hp.gh = BS*base_rock_level_2d(seed, p2d);
hp.ma = BS*get_mud_add_amount(seed, p2d);*/
hp.have_sand = mapgen::get_have_beach(seed, p2d);
hp.have_sand = Mapgen::get_have_beach(seed, p2d);
if(hp.gh > BS*WATER_LEVEL)
hp.tree_amount = mapgen::tree_amount_2d(seed, p2d);
hp.tree_amount = Mapgen::tree_amount_2d(seed, p2d);
else
hp.tree_amount = 0;
// No mud has been added if mud amount is less than 1

View File

@ -1994,7 +1994,7 @@ void Map::removeNodeTimer(v3s16 p)
ServerMap
*/
ServerMap::ServerMap(std::string savedir, IGameDef *gamedef):
ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
Map(dout_server, gamedef),
m_seed(0),
m_map_metadata_changed(true),
@ -2004,6 +2004,8 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef):
{
verbosestream<<__FUNCTION_NAME<<std::endl;
m_emerge = emerge;
//m_chunksize = 8; // Takes a few seconds
if (g_settings->get("fixed_map_seed").empty())
@ -2011,12 +2013,15 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef):
m_seed = (((u64)(myrand()%0xffff)<<0)
+ ((u64)(myrand()%0xffff)<<16)
+ ((u64)(myrand()%0xffff)<<32)
+ ((u64)(myrand()%0xffff)<<48));
+ ((u64)(myrand()&0xffff)<<48));
}
else
{
m_seed = g_settings->getU64("fixed_map_seed");
}
emerge->seed = m_seed;
emerge->water_level = g_settings->getS16("default_water_level");
//<set noiseparams here>
/*
Experimental and debug stuff
@ -2136,7 +2141,7 @@ ServerMap::~ServerMap()
#endif
}
void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
void ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
{
bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
if(enable_mapgen_debug_info)
@ -2208,7 +2213,7 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
Refer to the map generator heuristics.
*/
bool ug = mapgen::block_is_underground(data->seed, p);
bool ug = m_emerge->isBlockUnderground(p);
block->setIsUnderground(ug);
}
@ -2243,7 +2248,7 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
// Data is ready now.
}
MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
core::map<v3s16, MapBlock*> &changed_blocks)
{
v3s16 blockpos_min = data->blockpos_min;
@ -2483,6 +2488,7 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
return sector;
}
#if 0
/*
This is a quick-hand function for calling makeBlock().
*/
@ -2518,7 +2524,7 @@ MapBlock * ServerMap::generateBlock(
/*
Create block make data
*/
mapgen::BlockMakeData data;
BlockMakeData data;
initBlockMake(&data, p);
/*
@ -2526,7 +2532,8 @@ MapBlock * ServerMap::generateBlock(
*/
{
TimeTaker t("mapgen::make_block()");
mapgen::make_block(&data);
mapgen->makeChunk(&data);
//mapgen::make_block(&data);
if(enable_mapgen_debug_info == false)
t.stop(true); // Hide output
@ -2595,6 +2602,7 @@ MapBlock * ServerMap::generateBlock(
return block;
}
#endif
MapBlock * ServerMap::createBlock(v3s16 p)
{
@ -2656,14 +2664,15 @@ MapBlock * ServerMap::createBlock(v3s16 p)
}
// Create blank
block = sector->createBlankBlock(block_y);
return block;
}
MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
{
DSTACKF("%s: p=(%d,%d,%d), allow_generate=%d",
DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
__FUNCTION_NAME,
p.X, p.Y, p.Z, allow_generate);
p.X, p.Y, p.Z, create_blank);
{
MapBlock *block = getBlockNoCreateNoEx(p);
@ -2677,7 +2686,13 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
return block;
}
if(allow_generate)
if (create_blank) {
ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
MapBlock *block = sector->createBlankBlock(p.Y);
return block;
}
/*if(allow_generate)
{
core::map<v3s16, MapBlock*> modified_blocks;
MapBlock *block = generateBlock(p, modified_blocks);
@ -2700,7 +2715,7 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
return block;
}
}
}*/
return NULL;
}
@ -2742,7 +2757,7 @@ plan_b:
Determine from map generator noise functions
*/
s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1);
s16 level = m_emerge->getGroundLevelAtPoint(p2d);
return level;
//double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
@ -3062,6 +3077,7 @@ void ServerMap::saveMapMeta()
Settings params;
params.setU64("seed", m_seed);
params.setS16("water_level", m_emerge->water_level);
params.writeLines(os);
@ -3102,6 +3118,9 @@ void ServerMap::loadMapMeta()
}
m_seed = params.getU64("seed");
m_emerge->seed = m_seed;
m_emerge->water_level = params.getS16("water_level");
//m_emerge->np = ;
verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
}

View File

@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapnode.h"
#include "constants.h"
#include "voxel.h"
#include "mapgen.h" //for BlockMakeData and EmergeManager
#include "modifiedstate.h"
#include "util/container.h"
#include "nodetimer.h"
@ -46,9 +47,6 @@ class NodeMetadata;
class IGameDef;
class IRollbackReportSink;
namespace mapgen{
struct BlockMakeData;
};
/*
MapEditEvent
@ -360,7 +358,7 @@ public:
/*
savedir: directory to which map data should be saved
*/
ServerMap(std::string savedir, IGameDef *gamedef);
ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge);
~ServerMap();
s32 mapType() const
@ -379,15 +377,15 @@ public:
/*
Blocks are generated by using these and makeBlock().
*/
void initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos);
MapBlock* finishBlockMake(mapgen::BlockMakeData *data,
void initBlockMake(BlockMakeData *data, v3s16 blockpos);
MapBlock* finishBlockMake(BlockMakeData *data,
core::map<v3s16, MapBlock*> &changed_blocks);
// A non-threaded wrapper to the above
MapBlock * generateBlock(
// A non-threaded wrapper to the above - DEFUNCT
/* MapBlock * generateBlock(
v3s16 p,
core::map<v3s16, MapBlock*> &modified_blocks
);
);*/
/*
Get a block from somewhere.
@ -400,9 +398,10 @@ public:
Forcefully get a block from somewhere.
- Memory
- Load from disk
- Generate
- Create blank filled with CONTENT_IGNORE
*/
MapBlock * emergeBlock(v3s16 p, bool allow_generate=true);
MapBlock * emergeBlock(v3s16 p, bool create_blank=true);
// Helper for placing objects on ground level
s16 findGroundLevel(v2s16 p2d);
@ -479,6 +478,7 @@ public:
u64 getSeed(){ return m_seed; }
EmergeManager *m_emerge;
private:
// Seed used for all kinds of randomness in generation
u64 m_seed;

View File

@ -20,7 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mapgen.h"
#include "voxel.h"
#include "noise.h"
#include "biome.h"
#include "mapblock.h"
#include "mapnode.h"
#include "map.h"
//#include "serverobject.h"
#include "content_sao.h"
@ -28,9 +30,296 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapnode.h" // For content_mapnode_get_new_name
#include "voxelalgorithms.h"
#include "profiler.h"
#include "settings.h" // For g_settings
#include "main.h" // For g_profiler
#include "treegen.h"
NoiseParams nparams_mtdefault =
{0.0, 20.0, v3f(250., 250., 250.), 82341, 5, 0.6}; //terrain
NoiseParams nparams_def_bgroup =
{0.5, 1/(2*1.6), v3f(250., 250., 250.), 5923, 2, 0.60}; //0 to 1
NoiseParams nparams_def_heat =
{25.0, 50.0, v3f(500., 500., 500.), 35293, 1, 0.00}; //-25 to 75
NoiseParams nparams_def_humidity =
{50, 100/(2*1.6), v3f(750., 750., 750.), 12094, 2, 0.60}; //0 to 100
///////////////////////////////////////////////////////////////////////////////
/*
Mapgen::Mapgen(BiomeDefManager *biomedef) {
Mapgen(0, 0, biomedef);
}*/
Mapgen::Mapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed) {
initMapgen(biomedef, mapgenid, seed,
&nparams_mtdefault, &nparams_def_bgroup,
&nparams_def_heat, &nparams_def_humidity);
}
Mapgen::Mapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed,
NoiseParams *np_terrain, NoiseParams *np_bgroup,
NoiseParams *np_heat, NoiseParams *np_humidity) {
initMapgen(biomedef, mapgenid, seed,
np_terrain, np_bgroup, np_heat, np_humidity);
}
void Mapgen::initMapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed,
NoiseParams *np_terrain, NoiseParams *np_bgroup,
NoiseParams *np_heat, NoiseParams *np_humidity) {
this->generating = false;
this->id = mapgenid;
this->seed = (int)seed;
this->biomedef = biomedef;
this->csize = v3s16(5, 5, 5) * MAP_BLOCKSIZE; /////////////////get this from config!
this->water_level = g_settings->getS16("default_water_level"); ////fix this!
this->np_terrain = np_terrain;
this->np_bgroup = np_bgroup;
this->np_heat = np_heat;
this->np_humidity = np_humidity;
noise_terrain = new Noise(np_terrain, seed, csize.X, csize.Y);
noise_bgroup = new Noise(np_bgroup, seed, csize.X, csize.Y);
noise_heat = new Noise(np_heat, seed, csize.X, csize.Y);
noise_humidity = new Noise(np_humidity, seed, csize.X, csize.Y);
this->ndef = biomedef->ndef;
n_air = MapNode(ndef->getId("mapgen_air"));
n_water = MapNode(ndef->getId("mapgen_water_source"));
n_lava = MapNode(ndef->getId("mapgen_lava_source"));
}
Mapgen::~Mapgen() {
delete noise_terrain;
delete noise_bgroup;
delete noise_heat;
delete noise_humidity;
}
void Mapgen::makeChunk(BlockMakeData *data) {
if (data->no_op)
return;
//printf("generating...\n");//////////////
assert(data->vmanip);
assert(data->nodedef);
assert(data->blockpos_requested.X >= data->blockpos_min.X &&
data->blockpos_requested.Y >= data->blockpos_min.Y &&
data->blockpos_requested.Z >= data->blockpos_min.Z);
assert(data->blockpos_requested.X <= data->blockpos_max.X &&
data->blockpos_requested.Y <= data->blockpos_max.Y &&
data->blockpos_requested.Z <= data->blockpos_max.Z);
this->generating = true;
this->data = data;
this->vmanip = data->vmanip;
v3s16 em = vmanip->m_area.getExtent();
this->ystride = em.X;
this->zstride = em.Y * em.X;
node_min = (data->blockpos_min) * MAP_BLOCKSIZE;
node_max = (data->blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
v3s16 full_node_min = (data->blockpos_min - 1) * MAP_BLOCKSIZE;
v3s16 full_node_max = (data->blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1,1,1);
int y1 = node_min.Y;
int y2 = node_max.Y;
int x = node_min.X;
int z = node_min.Z;
//printf("full_node_min.X: %d | full_node_min.Z: %d | MinEdge: %d | MaxEdge: %d\n", node_min.X, node_min.Z, vmanip->m_area.MinEdge.X, vmanip->m_area.MinEdge.Z);
TimeTaker timer("Generating terrain");
map_terrain = noise_terrain->perlinMap2D(x, z);
map_bgroup = noise_bgroup->perlinMap2D(x, z);
map_heat = noise_heat->perlinMap2D(x, z);
map_humidity = noise_humidity->perlinMap2D(x, z);
int i = 0;
for (x = node_min.X; x <= node_max.X; x++) {
for (z = node_min.Z; z <= node_max.Z; z++) {
Biome *biome = biomedef->getBiome(map_bgroup[i], map_heat[i], map_humidity[i]);
biome->genColumn(this, x, z, y1, y2);
i++;
}
}
timer.stop();
//genCave();
//genDungeon();
//add blobs of dirt and gravel underground
//decorateChunk();
//updateLiquid(full_node_min, full_node_max);
updateLighting(node_min, node_max);
this->generating = false;
//printf("generated block (%d, %d) to (%d, %d)\n", node_min.X, node_min.Y, node_max.X, node_max.Y);//////////
}
void Mapgen::updateLiquid(v3s16 node_min, v3s16 node_max) {
bool isliquid, wasliquid;
u32 i;
content_t c;
for (s16 z = node_min.Z; z <= node_max.Z; z++) {
for (s16 x = node_min.X; x <= node_max.X; x++) {
v2s16 p2d(x, z);
wasliquid = true;
v3s16 em = vmanip->m_area.getExtent();
i = vmanip->m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
for (s16 y = node_max.Y; y >= node_min.Y; y--) {
isliquid = ndef->get(vmanip->m_data[i]).isLiquid();
//there was a change between liquid and nonliquid, add to queue
if (isliquid != wasliquid)
data->transforming_liquid.push_back(v3s16(p2d.X, y, p2d.Y));
wasliquid = isliquid;
vmanip->m_area.add_y(em, i, -1);
}
}
}
}
void Mapgen::updateLighting(v3s16 node_min, v3s16 node_max) {
enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
VoxelArea a(node_min - v3s16(1,0,1) * MAP_BLOCKSIZE,
node_max + v3s16(1,0,1) * MAP_BLOCKSIZE);
bool block_is_underground = (water_level > node_max.Y);
bool sunlight = !block_is_underground;
ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
for (int i = 0; i < 2; i++) {
enum LightBank bank = banks[i];
core::map<v3s16, bool> light_sources;
core::map<v3s16, u8> unlight_from;
voxalgo::clearLightAndCollectSources(*vmanip, a, bank, ndef,
light_sources, unlight_from);
voxalgo::propagateSunlight(*vmanip, a, sunlight, light_sources, ndef);
printf("light_sources: %d\t\tunlight_from: %d\n", light_sources.size(), unlight_from.size());
vmanip->unspreadLight(bank, unlight_from, light_sources, ndef);
vmanip->spreadLight(bank, light_sources, ndef);
}
}
/*class EmergeManager {
public:
int seed;
int water_level;
BiomeDefManager *biomedef;
//mapgen objects here
void addBlockToQueue();
//mapgen helper methods
int getGroundLevelAtPoint(u64 mseed, v2s16 p);
bool isBlockUnderground(u64 mseed, v3s16 blockpos);
u32 getBlockSeed(u64 mseed, v3s16 p);
};*/
EmergeManager::EmergeManager(IGameDef *gamedef) {
this->seed = 0;
this->water_level = 0;
this->np_terrain = &nparams_mtdefault;
this->np_bgroup = &nparams_def_bgroup;
this->np_heat = &nparams_def_heat;
this->np_humidity = &nparams_def_humidity;
this->biomedef = new BiomeDefManager(gamedef);
}
EmergeManager::~EmergeManager() {
delete biomedef;
}
void EmergeManager::addBlockToQueue() {
}
Biome *EmergeManager::getBiomeAtPoint(v3s16 p) {
float bgroup = NoisePerlin2D(np_bgroup, p.X, p.Y, seed);
float heat = NoisePerlin2D(np_heat, p.X, p.Y, seed);
float humidity = NoisePerlin2D(np_humidity, p.X, p.Y, seed);
return biomedef->getBiome(bgroup, heat, humidity);
}
//FIXME: This assumes y == 0, that is, always in a non-hell/non-sky biome
int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
float terrain = NoisePerlin2D(np_terrain, p.X, p.Y, seed);
Biome *biome = getBiomeAtPoint(v3s16(p.X, p.Y, 0));
return biome->getSurfaceHeight(terrain);
}
bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
/*
v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
(blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
int ground_level = getGroundLevelAtPoint(p);
return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
*/
//yuck, but then again, should i bother being accurate?
//the height of the nodes in a single block is quite variable
return false; //blockpos.Y * (MAP_BLOCKSIZE + 1) <= water_level;
}
u32 EmergeManager::getBlockSeed(v3s16 p) {
return (u32)(seed & 0xFFFFFFFF) +
p.Z * 38134234 +
p.Y * 42123 +
p.Y * 23;
}
/////////////////////////////////// legacy static functions for farmesh
s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
//just need to return something
s16 level = 5;
return level;
}
bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
double sandnoise = noise2d_perlin(
0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
seed+59420, 3, 0.50);
return (sandnoise > 0.15);
}
double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
double noise = noise2d_perlin(
0.5+(float)p.X/125, 0.5+(float)p.Y/125,
seed+2, 4, 0.66);
double zeroval = -0.39;
if(noise < zeroval)
return 0;
else
return 0.04 * (noise-zeroval) / (1.0-zeroval);
}
#if 0 /// BIG COMMENT
namespace mapgen
{
@ -121,6 +410,7 @@ static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
}
#endif
#if 0
static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
@ -2756,6 +3046,8 @@ void make_block(BlockMakeData *data)
}
}
#endif ///BIG COMMENT
BlockMakeData::BlockMakeData():
no_op(false),
vmanip(NULL),
@ -2768,6 +3060,6 @@ BlockMakeData::~BlockMakeData()
delete vmanip;
}
}; // namespace mapgen
//}; // namespace mapgen

View File

@ -22,12 +22,121 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "util/container.h" // UniqueQueue
#include "gamedef.h"
#include "mapnode.h"
#include "noise.h"
struct BlockMakeData;
class BiomeDefManager;
class Biome;
//struct BlockMakeData;
class MapBlock;
class ManualMapVoxelManipulator;
class INodeDefManager;
struct BlockMakeData {
bool no_op;
ManualMapVoxelManipulator *vmanip;
u64 seed;
v3s16 blockpos_min;
v3s16 blockpos_max;
v3s16 blockpos_requested;
UniqueQueue<v3s16> transforming_liquid;
INodeDefManager *nodedef;
BlockMakeData();
~BlockMakeData();
};
class Mapgen {
public:
BlockMakeData *data;
ManualMapVoxelManipulator *vmanip;
INodeDefManager *ndef;
BiomeDefManager *biomedef;
int ystride;
int zstride;
v3s16 csize;
int seed;
int water_level;
Noise *noise_terrain;
Noise *noise_bgroup;
Noise *noise_heat;
Noise *noise_humidity;
v3s16 node_min;
v3s16 node_max;
float *map_terrain;
float *map_bgroup;
float *map_heat;
float *map_humidity;
bool generating;
int id;
NoiseParams *np_terrain;
NoiseParams *np_bgroup;
NoiseParams *np_heat;
NoiseParams *np_humidity;
//should these be broken off into a "commonly used nodes" class?
MapNode n_air;
MapNode n_water;
MapNode n_lava;
Mapgen(BiomeDefManager *biomedef, int mapgenid=0, u64 seed=0);
Mapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed,
NoiseParams *np_terrain, NoiseParams *np_bgroup,
NoiseParams *np_heat, NoiseParams *np_humidity);
void initMapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed,
NoiseParams *np_terrain, NoiseParams *np_bgroup,
NoiseParams *np_heat, NoiseParams *np_humidity);
~Mapgen();
void makeChunk(BlockMakeData *data);
void updateLiquid(v3s16 node_min, v3s16 node_max);
void updateLighting(v3s16 node_min, v3s16 node_max);
//Legacy functions for Farmesh (pending removal)
static bool get_have_beach(u64 seed, v2s16 p2d);
static double tree_amount_2d(u64 seed, v2s16 p);
static s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision);
};
class EmergeManager {
public:
//settings
u64 seed;
int water_level;
NoiseParams *np_terrain;
NoiseParams *np_bgroup;
NoiseParams *np_heat;
NoiseParams *np_humidity;
//biome manager
BiomeDefManager *biomedef;
//mapgen objects here
EmergeManager(IGameDef *gamedef);
~EmergeManager();
void addBlockToQueue();
//mapgen helper methods
Biome *getBiomeAtPoint(v3s16 p);
int getGroundLevelAtPoint(v2s16 p);
bool isBlockUnderground(v3s16 blockpos);
u32 getBlockSeed(v3s16 p);
};
/*
namespace mapgen
{
// Finds precise ground level at any position
@ -42,9 +151,8 @@ namespace mapgen
// Main map generation routine
void make_block(BlockMakeData *data);
/*
These are used by FarMesh
*/
//These are used by FarMesh
bool get_have_beach(u64 seed, v2s16 p2d);
double tree_amount_2d(u64 seed, v2s16 p);
@ -64,6 +172,6 @@ namespace mapgen
};
}; // namespace mapgen
*/
#endif

View File

@ -21,50 +21,93 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "noise.h"
#include <iostream>
#include "debug.h"
#include "util/numeric.h"
#define NOISE_MAGIC_X 1619
#define NOISE_MAGIC_Y 31337
#define NOISE_MAGIC_Z 52591
#define NOISE_MAGIC_SEED 1013
double cos_lookup[16] = {
float cos_lookup[16] = {
1.0, 0.9238, 0.7071, 0.3826, 0, -0.3826, -0.7071, -0.9238,
1.0, -0.9238, -0.7071, -0.3826, 0, 0.3826, 0.7071, 0.9238
};
double dotProduct(double vx, double vy, double wx, double wy){
///////////////////////////////////////////////////////////////////////////////
//noise poly: p(n) = 60493n^3 + 19990303n + 137612589
float noise2d(int x, int y, int seed) {
int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y
+ NOISE_MAGIC_SEED * seed) & 0x7fffffff;
n = (n >> 13) ^ n;
n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
return 1.f - (float)n / 0x40000000;
}
float noise3d(int x, int y, int z, int seed) {
int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z
+ NOISE_MAGIC_SEED * seed) & 0x7fffffff;
n = (n >> 13) ^ n;
n = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
return 1.f - (float)n / 0x40000000;
}
float dotProduct(float vx, float vy, float wx, float wy) {
return vx * wx + vy * wy;
}
double easeCurve(double t){
return t * t * t * (6. * t * t - 15. * t + 10.);
inline float linearInterpolation(float v0, float v1, float t) {
return v0 + (v1 - v0) * t;
}
double linearInterpolation(double x0, double x1, double t){
return x0+(x1-x0)*t;
}
double biLinearInterpolation(double x0y0, double x1y0, double x0y1, double x1y1, double x, double y){
double tx = easeCurve(x);
double ty = easeCurve(y);
/*double tx = x;
double ty = y;*/
double u = linearInterpolation(x0y0,x1y0,tx);
double v = linearInterpolation(x0y1,x1y1,tx);
float biLinearInterpolation(float v00, float v10,
float v01, float v11,
float x, float y) {
float tx = easeCurve(x);
float ty = easeCurve(y);
float u = linearInterpolation(v00, v10, tx);
float v = linearInterpolation(v01, v11, tx);
return linearInterpolation(u, v, ty);
}
double triLinearInterpolation(
double v000, double v100, double v010, double v110,
double v001, double v101, double v011, double v111,
double x, double y, double z)
float biLinearInterpolationNoEase(float x0y0, float x1y0,
float x0y1, float x1y1,
float x, float y) {
float u = linearInterpolation(x0y0, x1y0, x);
float v = linearInterpolation(x0y1, x1y1, x);
return linearInterpolation(u, v, y);
}
float triLinearInterpolation(
float v000, float v100, float v010, float v110,
float v001, float v101, float v011, float v111,
float x, float y, float z) {
float u = biLinearInterpolationNoEase(v000, v100, v010, v110, x, y);
float v = biLinearInterpolationNoEase(v001, v101, v011, v111, x, y);
return linearInterpolation(u, v, z);
}
#if 0
float triLinearInterpolation(
float v000, float v100, float v010, float v110,
float v001, float v101, float v011, float v111,
float x, float y, float z)
{
/*double tx = easeCurve(x);
double ty = easeCurve(y);
double tz = easeCurve(z);*/
double tx = x;
double ty = y;
double tz = z;
/*float tx = easeCurve(x);
float ty = easeCurve(y);
float tz = easeCurve(z);*/
float tx = x;
float ty = y;
float tz = z;
return(
v000 * (1 - tx) * (1 - ty) * (1 - tz) +
v100 * tx * (1 - ty) * (1 - tz) +
@ -76,34 +119,18 @@ double triLinearInterpolation(
v111 * tx * ty * tz
);
}
#endif
double noise2d(int x, int y, int seed)
{
int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y
+ NOISE_MAGIC_SEED * seed) & 0x7fffffff;
n = (n>>13)^n;
n = (n * (n*n*60493+19990303) + 1376312589) & 0x7fffffff;
return 1.0 - (double)n/1073741824;
}
double noise3d(int x, int y, int z, int seed)
{
int n = (NOISE_MAGIC_X * x + NOISE_MAGIC_Y * y + NOISE_MAGIC_Z * z
+ NOISE_MAGIC_SEED * seed) & 0x7fffffff;
n = (n>>13)^n;
n = (n * (n*n*60493+19990303) + 1376312589) & 0x7fffffff;
return 1.0 - (double)n/1073741824;
}
#if 0
double noise2d_gradient(double x, double y, int seed)
float noise2d_gradient(float x, float y, int seed)
{
// Calculate the integer coordinates
int x0 = (x > 0.0 ? (int)x : (int)x - 1);
int y0 = (y > 0.0 ? (int)y : (int)y - 1);
// Calculate the remaining part of the coordinates
double xl = x - (double)x0;
double yl = y - (double)y0;
float xl = x - (float)x0;
float yl = y - (float)y0;
// Calculate random cosine lookup table indices for the integer corners.
// They are looked up as unit vector gradients from the lookup table.
int n00 = (int)((noise2d(x0, y0, seed)+1)*8);
@ -111,63 +138,66 @@ double noise2d_gradient(double x, double y, int seed)
int n01 = (int)((noise2d(x0, y0+1, seed)+1)*8);
int n11 = (int)((noise2d(x0+1, y0+1, seed)+1)*8);
// Make a dot product for the gradients and the positions, to get the values
double s = dotProduct(cos_lookup[n00], cos_lookup[(n00+12)%16], xl, yl);
double u = dotProduct(-cos_lookup[n10], cos_lookup[(n10+12)%16], 1.-xl, yl);
double v = dotProduct(cos_lookup[n01], -cos_lookup[(n01+12)%16], xl, 1.-yl);
double w = dotProduct(-cos_lookup[n11], -cos_lookup[(n11+12)%16], 1.-xl, 1.-yl);
float s = dotProduct(cos_lookup[n00], cos_lookup[(n00+12)%16], xl, yl);
float u = dotProduct(-cos_lookup[n10], cos_lookup[(n10+12)%16], 1.-xl, yl);
float v = dotProduct(cos_lookup[n01], -cos_lookup[(n01+12)%16], xl, 1.-yl);
float w = dotProduct(-cos_lookup[n11], -cos_lookup[(n11+12)%16], 1.-xl, 1.-yl);
// Interpolate between the values
return biLinearInterpolation(s,u,v,w,xl,yl);
}
#endif
#if 1
double noise2d_gradient(double x, double y, int seed)
float noise2d_gradient(float x, float y, int seed)
{
// Calculate the integer coordinates
int x0 = (x > 0.0 ? (int)x : (int)x - 1);
int y0 = (y > 0.0 ? (int)y : (int)y - 1);
int x0 = myfloor(x);
int y0 = myfloor(y);
// Calculate the remaining part of the coordinates
double xl = x - (double)x0;
double yl = y - (double)y0;
// Get values for corners of cube
double v00 = noise2d(x0, y0, seed);
double v10 = noise2d(x0+1, y0, seed);
double v01 = noise2d(x0, y0+1, seed);
double v11 = noise2d(x0+1, y0+1, seed);
float xl = x - (float)x0;
float yl = y - (float)y0;
// Get values for corners of square
float v00 = noise2d(x0, y0, seed);
float v10 = noise2d(x0+1, y0, seed);
float v01 = noise2d(x0, y0+1, seed);
float v11 = noise2d(x0+1, y0+1, seed);
// Interpolate
return biLinearInterpolation(v00,v10,v01,v11,xl,yl);
}
#endif
double noise3d_gradient(double x, double y, double z, int seed)
float noise3d_gradient(float x, float y, float z, int seed)
{
// Calculate the integer coordinates
int x0 = (x > 0.0 ? (int)x : (int)x - 1);
int y0 = (y > 0.0 ? (int)y : (int)y - 1);
int z0 = (z > 0.0 ? (int)z : (int)z - 1);
int x0 = myfloor(x);
int y0 = myfloor(y);
int z0 = myfloor(z);
// Calculate the remaining part of the coordinates
double xl = x - (double)x0;
double yl = y - (double)y0;
double zl = z - (double)z0;
float xl = x - (float)x0;
float yl = y - (float)y0;
float zl = z - (float)z0;
// Get values for corners of cube
double v000 = noise3d(x0, y0, z0, seed);
double v100 = noise3d(x0+1, y0, z0, seed);
double v010 = noise3d(x0, y0+1, z0, seed);
double v110 = noise3d(x0+1, y0+1, z0, seed);
double v001 = noise3d(x0, y0, z0+1, seed);
double v101 = noise3d(x0+1, y0, z0+1, seed);
double v011 = noise3d(x0, y0+1, z0+1, seed);
double v111 = noise3d(x0+1, y0+1, z0+1, seed);
float v000 = noise3d(x0, y0, z0, seed);
float v100 = noise3d(x0 + 1, y0, z0, seed);
float v010 = noise3d(x0, y0 + 1, z0, seed);
float v110 = noise3d(x0 + 1, y0 + 1, z0, seed);
float v001 = noise3d(x0, y0, z0 + 1, seed);
float v101 = noise3d(x0 + 1, y0, z0 + 1, seed);
float v011 = noise3d(x0, y0 + 1, z0 + 1, seed);
float v111 = noise3d(x0 + 1, y0 + 1, z0 + 1, seed);
// Interpolate
return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl);
return triLinearInterpolation(v000, v100, v010, v110,
v001, v101, v011, v111,
xl, yl, zl);
}
double noise2d_perlin(double x, double y, int seed,
int octaves, double persistence)
float noise2d_perlin(float x, float y, int seed,
int octaves, float persistence)
{
double a = 0;
double f = 1.0;
double g = 1.0;
float a = 0;
float f = 1.0;
float g = 1.0;
for (int i = 0; i < octaves; i++)
{
a += g * noise2d_gradient(x * f, y * f, seed + i);
@ -177,12 +207,13 @@ double noise2d_perlin(double x, double y, int seed,
return a;
}
double noise2d_perlin_abs(double x, double y, int seed,
int octaves, double persistence)
float noise2d_perlin_abs(float x, float y, int seed,
int octaves, float persistence)
{
double a = 0;
double f = 1.0;
double g = 1.0;
float a = 0;
float f = 1.0;
float g = 1.0;
for (int i = 0; i < octaves; i++)
{
a += g * fabs(noise2d_gradient(x * f, y * f, seed + i));
@ -192,12 +223,13 @@ double noise2d_perlin_abs(double x, double y, int seed,
return a;
}
double noise3d_perlin(double x, double y, double z, int seed,
int octaves, double persistence)
float noise3d_perlin(float x, float y, float z, int seed,
int octaves, float persistence)
{
double a = 0;
double f = 1.0;
double g = 1.0;
float a = 0;
float f = 1.0;
float g = 1.0;
for (int i = 0; i < octaves; i++)
{
a += g * noise3d_gradient(x * f, y * f, z * f, seed + i);
@ -207,12 +239,13 @@ double noise3d_perlin(double x, double y, double z, int seed,
return a;
}
double noise3d_perlin_abs(double x, double y, double z, int seed,
int octaves, double persistence)
float noise3d_perlin_abs(float x, float y, float z, int seed,
int octaves, float persistence)
{
double a = 0;
double f = 1.0;
double g = 1.0;
float a = 0;
float f = 1.0;
float g = 1.0;
for (int i = 0; i < octaves; i++)
{
a += g * fabs(noise3d_gradient(x * f, y * f, z * f, seed + i));
@ -222,8 +255,9 @@ double noise3d_perlin_abs(double x, double y, double z, int seed,
return a;
}
// -1->0, 0->1, 1->0
double contour(double v)
float contour(float v)
{
v = fabs(v);
if(v >= 1.0)
@ -231,195 +265,276 @@ double contour(double v)
return (1.0-v);
}
double noise3d_param(const NoiseParams &param, double x, double y, double z)
{
double s = param.pos_scale;
x /= s;
y /= s;
z /= s;
if(param.type == NOISE_CONSTANT_ONE)
{
return 1.0;
///////////////////////// [ New perlin stuff ] ////////////////////////////
Noise::Noise(NoiseParams *np, int seed, int sx, int sy) {
int nlx, nly;
float ofactor;
//maximum possible spread value factor
ofactor = (float)(1 << (np->octaves - 1));
//noise lattice point count
//(int)(sz * spread * ofactor) is # of lattice points crossed due to length
// + 2 for the two initial endpoints
// + 1 for potentially crossing a boundary due to offset
nlx = (int)(sx * ofactor / np->spread.X) + 3;
nly = (int)(sy * ofactor / np->spread.Y) + 3;
this->np = np;
this->seed = seed;
this->sx = sx;
this->sy = sy;
this->sz = 0;
this->noisebuf = new float[nlx * nly];
this->buf = new float[sx * sy];
this->result = new float[sx * sy];
}
else if(param.type == NOISE_PERLIN)
{
return param.noise_scale*noise3d_perlin(x,y,z, param.seed,
param.octaves,
param.persistence);
Noise::Noise(NoiseParams *np, int seed, int sx, int sy, int sz) {
int nlx, nly, nlz;
float ofactor;
ofactor = (float)(1 << (np->octaves - 1));
nlx = (int)(sx * ofactor / np->spread.X) + 3;
nly = (int)(sy * ofactor / np->spread.Y) + 3;
nlz = (int)(sz * ofactor / np->spread.Z) + 3;
this->np = np;
this->seed = seed;
this->sx = sx;
this->sy = sy;
this->sz = sz;
this->noisebuf = new float[nlx * nly * nlz];
this->buf = new float[sx * sy * sz];
this->result = new float[sx * sy * sz];
}
else if(param.type == NOISE_PERLIN_ABS)
{
return param.noise_scale*noise3d_perlin_abs(x,y,z, param.seed,
param.octaves,
param.persistence);
}
else if(param.type == NOISE_PERLIN_CONTOUR)
{
return contour(param.noise_scale*noise3d_perlin(x,y,z,
param.seed, param.octaves,
param.persistence));
}
else if(param.type == NOISE_PERLIN_CONTOUR_FLIP_YZ)
{
return contour(param.noise_scale*noise3d_perlin(x,z,y,
param.seed, param.octaves,
param.persistence));
}
else assert(0);
Noise::~Noise() {
delete[] buf;
delete[] result;
delete[] noisebuf;
}
/*
NoiseBuffer
* NB: This algorithm is not optimal in terms of space complexity. The entire
* integer lattice of noise points could be done as 2 lines instead, and for 3D,
* 2 lines + 2 planes.
* However, this would require the noise calls to be interposed with the
* interpolation loops, which may trash the icache, leading to lower overall
* performance.
* Another optimization that could save half as many noise calls is to carry over
* values from the previous noise lattice as midpoints in the new lattice for the
* next octave.
*/
void Noise::gradientMap2D(float x, float y, float step_x, float step_y, int seed) {
float v00, v01, v10, v11, u, v, orig_u;
int index, i, j, x0, y0, noisex, noisey;
int nlx, nly;
NoiseBuffer::NoiseBuffer():
m_data(NULL)
{
}
x0 = floor(x);
y0 = floor(y);
u = x - (float)x0;
v = y - (float)y0;
orig_u = u;
NoiseBuffer::~NoiseBuffer()
{
clear();
}
//calculate noise point lattice
void NoiseBuffer::clear()
{
if(m_data)
delete[] m_data;
m_data = NULL;
m_size_x = 0;
m_size_y = 0;
m_size_z = 0;
}
nlx = (int)(u + sx * step_x) + 2;
nly = (int)(v + sy * step_y) + 2;
index = 0;
for (j = 0; j != nly; j++)
for (i = 0; i != nlx; i++)
noisebuf[index++] = noise2d(x0 + i, y0 + j, seed);
void NoiseBuffer::create(const NoiseParams &param,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z)
{
clear();
//calculate interpolations
noisey = 0;
for (j = 0; j != sy; j++) {
v00 = noisebuf[noisey * nlx];
v10 = noisebuf[noisey * nlx + 1];
v01 = noisebuf[(noisey + 1) * nlx];
v11 = noisebuf[(noisey + 1) * nlx + 1];
m_start_x = first_x - samplelength_x;
m_start_y = first_y - samplelength_y;
m_start_z = first_z - samplelength_z;
m_samplelength_x = samplelength_x;
m_samplelength_y = samplelength_y;
m_samplelength_z = samplelength_z;
m_size_x = (last_x - m_start_x)/samplelength_x + 2;
m_size_y = (last_y - m_start_y)/samplelength_y + 2;
m_size_z = (last_z - m_start_z)/samplelength_z + 2;
m_data = new double[m_size_x*m_size_y*m_size_z];
for(int x=0; x<m_size_x; x++)
for(int y=0; y<m_size_y; y++)
for(int z=0; z<m_size_z; z++)
{
double xd = (m_start_x + (double)x*m_samplelength_x);
double yd = (m_start_y + (double)y*m_samplelength_y);
double zd = (m_start_z + (double)z*m_samplelength_z);
double a = noise3d_param(param, xd,yd,zd);
intSet(x,y,z, a);
u = orig_u;
noisex = 0;
for (i = 0; i != sx; i++) {
buf[j * sx + i] = biLinearInterpolation(v00, v10, v01, v11, u, v);
u += step_x;
if (u >= 1.0) {
u -= 1.0;
noisex++;
v00 = v10;
v01 = v11;
v10 = noisebuf[noisey * nlx + noisex + 1];
v11 = noisebuf[(noisey + 1) * nlx + noisex + 1];
}
}
void NoiseBuffer::multiply(const NoiseParams &param)
{
assert(m_data != NULL);
for(int x=0; x<m_size_x; x++)
for(int y=0; y<m_size_y; y++)
for(int z=0; z<m_size_z; z++)
{
double xd = (m_start_x + (double)x*m_samplelength_x);
double yd = (m_start_y + (double)y*m_samplelength_y);
double zd = (m_start_z + (double)z*m_samplelength_z);
double a = noise3d_param(param, xd,yd,zd);
intMultiply(x,y,z, a);
v += step_y;
if (v >= 1.0) {
v -= 1.0;
noisey++;
}
}
}
// Deprecated
void NoiseBuffer::create(int seed, int octaves, double persistence,
bool abs,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z)
{
NoiseParams param;
param.type = abs ? NOISE_PERLIN_ABS : NOISE_PERLIN;
param.seed = seed;
param.octaves = octaves;
param.persistence = persistence;
create(param, first_x, first_y, first_z,
last_x, last_y, last_z,
samplelength_x, samplelength_y, samplelength_z);
void Noise::gradientMap3D(float x, float y, float z,
float step_x, float step_y, float step_z,
int seed) {
float v000, v010, v100, v110;
float v001, v011, v101, v111;
float u, v, w, orig_u, orig_w;
int index, i, j, k, x0, y0, z0, noisex, noisey, noisez;
int nlx, nly, nlz;
x0 = floor(x);
y0 = floor(y);
z0 = floor(z);
u = x - (float)x0;
v = y - (float)y0;
w = z - (float)z0;
orig_u = u;
orig_w = w;
//calculate noise point lattice
nlx = (int)(u + sx * step_x) + 2;
nly = (int)(v + sy * step_y) + 2;
nlz = (int)(v + sy * step_z) + 2;
index = 0;
for (k = 0; k != nlz; k++)
for (j = 0; j != nly; j++)
for (i = 0; i != nlx; i++)
noisebuf[index++] = noise3d(x0 + i, y0 + j, z0 + k, seed);
#define index(x, y, z) ((z) * nly * nlx + (y) * nlx + (x))
//calculate interpolations
noisey = 0;
noisez = 0;
for (k = 0; k != sz; k++) {
v000 = noisebuf[index(0, noisey, noisez)];
v100 = noisebuf[index(1, noisey, noisez)];
v010 = noisebuf[index(0, noisey + 1, noisez)];
v110 = noisebuf[index(1, noisey + 1, noisez)];
v001 = noisebuf[index(0, noisey, noisez + 1)];
v101 = noisebuf[index(1, noisey, noisez + 1)];
v011 = noisebuf[index(0, noisey + 1, noisez + 1)];
v111 = noisebuf[index(1, noisey + 1, noisez + 1)];
w = orig_w;
noisey = 0;
for (j = 0; j != sy; j++) {
v000 = noisebuf[index(0, noisey, noisez)];
v100 = noisebuf[index(1, noisey, noisez)];
v010 = noisebuf[index(0, noisey + 1, noisez)];
v110 = noisebuf[index(1, noisey + 1, noisez)];
v001 = noisebuf[index(0, noisey, noisez + 1)];
v101 = noisebuf[index(1, noisey, noisez + 1)];
v011 = noisebuf[index(0, noisey + 1, noisez + 1)];
v111 = noisebuf[index(1, noisey + 1, noisez + 1)];
u = orig_u;
noisex = 0;
for (i = 0; i != sx; i++) {
buf[j * sx + i] = triLinearInterpolation(
v000, v100, v010, v110,
v001, v101, v011, v111,
u, v, w);
u += step_x;
if (u >= 1.0) {
u -= 1.0;
noisex++;
v000 = v100;
v010 = v110;
v100 = noisebuf[index(noisex + 1, noisey, noisez)];
v110 = noisebuf[index(noisex + 1, noisey + 1, noisez)];
v001 = v101;
v011 = v111;
v101 = noisebuf[index(noisex + 1, noisey, noisez + 1)];
v111 = noisebuf[index(noisex + 1, noisey + 1, noisez + 1)];
}
}
void NoiseBuffer::intSet(int x, int y, int z, double d)
{
int i = m_size_x*m_size_y*z + m_size_x*y + x;
assert(i >= 0);
assert(i < m_size_x*m_size_y*m_size_z);
m_data[i] = d;
v += step_y;
if (v >= 1.0) {
v -= 1.0;
noisey++;
}
}
void NoiseBuffer::intMultiply(int x, int y, int z, double d)
{
int i = m_size_x*m_size_y*z + m_size_x*y + x;
assert(i >= 0);
assert(i < m_size_x*m_size_y*m_size_z);
m_data[i] = m_data[i] * d;
w += step_z;
if (w >= 1.0) {
w -= 1.0;
noisez++;
}
}
}
double NoiseBuffer::intGet(int x, int y, int z)
{
int i = m_size_x*m_size_y*z + m_size_x*y + x;
assert(i >= 0);
assert(i < m_size_x*m_size_y*m_size_z);
return m_data[i];
float *Noise::perlinMap2D(float x, float y) {
float a = 0.0, f = 1.0, g = 1.0;
int i, j, index, oct;
x /= np->spread.X;
y /= np->spread.Y;
memset(result, 0, sizeof(float) * sx * sy);
for (oct = 0; oct < np->octaves; oct++) {
gradientMap2D(x * f, y * f,
f / np->spread.X, f / np->spread.Y,
seed + np->seed + oct);
index = 0;
for (j = 0; j != sy; j++) {
for (i = 0; i != sx; i++) {
result[index] += g * buf[index];
index++;
}
}
double NoiseBuffer::get(double x, double y, double z)
{
x -= m_start_x;
y -= m_start_y;
z -= m_start_z;
x /= m_samplelength_x;
y /= m_samplelength_y;
z /= m_samplelength_z;
// Calculate the integer coordinates
int x0 = (x > 0.0 ? (int)x : (int)x - 1);
int y0 = (y > 0.0 ? (int)y : (int)y - 1);
int z0 = (z > 0.0 ? (int)z : (int)z - 1);
// Calculate the remaining part of the coordinates
double xl = x - (double)x0;
double yl = y - (double)y0;
double zl = z - (double)z0;
// Get values for corners of cube
double v000 = intGet(x0, y0, z0);
double v100 = intGet(x0+1, y0, z0);
double v010 = intGet(x0, y0+1, z0);
double v110 = intGet(x0+1, y0+1, z0);
double v001 = intGet(x0, y0, z0+1);
double v101 = intGet(x0+1, y0, z0+1);
double v011 = intGet(x0, y0+1, z0+1);
double v111 = intGet(x0+1, y0+1, z0+1);
// Interpolate
return triLinearInterpolation(v000,v100,v010,v110,v001,v101,v011,v111,xl,yl,zl);
f *= 2.0;
g *= np->persist;
}
/*bool NoiseBuffer::contains(double x, double y, double z)
{
x -= m_start_x;
y -= m_start_y;
z -= m_start_z;
x /= m_samplelength_x;
y /= m_samplelength_y;
z /= m_samplelength_z;
if(x <= 0.0 || x >= m_size_x)
}*/
return result;
}
float *Noise::perlinMap3D(float x, float y, float z) {
float a = 0.0, f = 1.0, g = 1.0;
int i, j, k, index, oct;
x /= np->spread.X;
y /= np->spread.Y;
z /= np->spread.Z;
memset(result, 0, sizeof(float) * sx * sy * sz);
for (oct = 0; oct < np->octaves; oct++) {
gradientMap3D(x * f, y * f, z * f,
f / np->spread.X, f / np->spread.Y, f / np->spread.Z,
seed + np->seed + oct);
index = 0;
for (k = 0; k != sz; k++) {
for (j = 0; j != sy; j++) {
for (i = 0; i != sx; i++) {
result[index] += g * buf[index];
index++;
}
}
}
f *= 2.0;
g *= np->persist;
}
return result;
}

View File

@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define NOISE_HEADER
#include "debug.h"
#include "irr_v3d.h"
class PseudoRandom
{
@ -59,91 +60,69 @@ private:
int m_next;
};
double easeCurve(double t);
// Return value: -1 ... 1
double noise2d(int x, int y, int seed);
double noise3d(int x, int y, int z, int seed);
double noise2d_gradient(double x, double y, int seed);
double noise3d_gradient(double x, double y, double z, int seed);
double noise2d_perlin(double x, double y, int seed,
int octaves, double persistence);
double noise2d_perlin_abs(double x, double y, int seed,
int octaves, double persistence);
double noise3d_perlin(double x, double y, double z, int seed,
int octaves, double persistence);
double noise3d_perlin_abs(double x, double y, double z, int seed,
int octaves, double persistence);
enum NoiseType
{
NOISE_CONSTANT_ONE,
NOISE_PERLIN,
NOISE_PERLIN_ABS,
NOISE_PERLIN_CONTOUR,
NOISE_PERLIN_CONTOUR_FLIP_YZ,
};
struct NoiseParams
{
NoiseType type;
struct NoiseParams {
float offset;
float scale;
v3f spread;
int seed;
int octaves;
double persistence;
double pos_scale;
double noise_scale; // Useful for contour noises
NoiseParams(NoiseType type_=NOISE_PERLIN, int seed_=0,
int octaves_=3, double persistence_=0.5,
double pos_scale_=100.0, double noise_scale_=1.0):
type(type_),
seed(seed_),
octaves(octaves_),
persistence(persistence_),
pos_scale(pos_scale_),
noise_scale(noise_scale_)
{
}
float persist;
};
double noise3d_param(const NoiseParams &param, double x, double y, double z);
class NoiseBuffer
{
class Noise {
public:
NoiseBuffer();
~NoiseBuffer();
NoiseParams *np;
int seed;
int sx;
int sy;
int sz;
float *noisebuf;
float *buf;
float *result;
void clear();
void create(const NoiseParams &param,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z);
void multiply(const NoiseParams &param);
// Deprecated
void create(int seed, int octaves, double persistence,
bool abs,
double first_x, double first_y, double first_z,
double last_x, double last_y, double last_z,
double samplelength_x, double samplelength_y, double samplelength_z);
Noise(NoiseParams *np, int seed, int sx, int sy);
Noise(NoiseParams *np, int seed, int sx, int sy, int sz);
~Noise();
void intSet(int x, int y, int z, double d);
void intMultiply(int x, int y, int z, double d);
double intGet(int x, int y, int z);
double get(double x, double y, double z);
//bool contains(double x, double y, double z);
private:
double *m_data;
double m_start_x, m_start_y, m_start_z;
double m_samplelength_x, m_samplelength_y, m_samplelength_z;
int m_size_x, m_size_y, m_size_z;
void gradientMap2D(
float x, float y,
float step_x, float step_y,
int seed);
void gradientMap3D(
float x, float y, float z,
float step_x, float step_y, float step_z,
int seed);
float *perlinMap2D(float x, float y);
float *perlinMap3D(float x, float y, float z);
};
// Return value: -1 ... 1
float noise2d(int x, int y, int seed);
float noise3d(int x, int y, int z, int seed);
float noise2d_gradient(float x, float y, int seed);
float noise3d_gradient(float x, float y, float z, int seed);
float noise2d_perlin(float x, float y, int seed,
int octaves, float persistence);
float noise2d_perlin_abs(float x, float y, int seed,
int octaves, float persistence);
float noise3d_perlin(float x, float y, float z, int seed,
int octaves, float persistence);
float noise3d_perlin_abs(float x, float y, float z, int seed,
int octaves, float persistence);
inline float easeCurve(float t) {
return t * t * t * (t * (6.f * t - 15.f) + 10.f);
}
#define NoisePerlin2D(np, x, y, s) ((np)->offset + (np)->scale * \
noise2d_perlin((float)(x) * (np)->spread.X, (float)(y) * (np)->spread.Y, \
(s) + (np)->seed, (np)->octaves, (np)->persist))
#endif

View File

@ -3240,8 +3240,8 @@ class LuaPerlinNoise
private:
int seed;
int octaves;
double persistence;
double scale;
float persistence;
float scale;
static const char className[];
static const luaL_reg methods[];
@ -3273,8 +3273,8 @@ private:
}
public:
LuaPerlinNoise(int a_seed, int a_octaves, double a_persistence,
double a_scale):
LuaPerlinNoise(int a_seed, int a_octaves, float a_persistence,
float a_scale):
seed(a_seed),
octaves(a_octaves),
persistence(a_persistence),
@ -3292,8 +3292,8 @@ public:
{
int seed = luaL_checkint(L, 1);
int octaves = luaL_checkint(L, 2);
double persistence = luaL_checknumber(L, 3);
double scale = luaL_checknumber(L, 4);
float persistence = luaL_checknumber(L, 3);
float scale = luaL_checknumber(L, 4);
LuaPerlinNoise *o = new LuaPerlinNoise(seed, octaves, persistence, scale);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
@ -3999,8 +3999,8 @@ private:
int seeddiff = luaL_checkint(L, 2);
int octaves = luaL_checkint(L, 3);
double persistence = luaL_checknumber(L, 4);
double scale = luaL_checknumber(L, 5);
float persistence = luaL_checknumber(L, 4);
float scale = luaL_checknumber(L, 5);
LuaPerlinNoise *n = new LuaPerlinNoise(seeddiff + int(env->getServerMap().getSeed()), octaves, persistence, scale);
*(void **)(lua_newuserdata(L, sizeof(void *))) = n;

View File

@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "itemdef.h"
#include "craftdef.h"
#include "mapgen.h"
#include "biome.h"
#include "content_mapnode.h"
#include "content_nodemeta.h"
#include "content_abm.h"
@ -169,6 +170,10 @@ void * EmergeThread::Thread()
v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
EmergeManager *emerge = m_server->m_emerge;
Mapgen *mapgen = new Mapgen( m_server->m_emerge->biomedef,/*mapgenid*/ 0, map.getSeed()); ////////fix this...!
/*
Get block info from queue, emerge them and send them
to clients.
@ -233,7 +238,7 @@ void * EmergeThread::Thread()
<<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
<<"only_from_disk="<<only_from_disk<<std::endl;
ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
MapBlock *block = NULL;
bool got_block = true;
@ -245,7 +250,7 @@ void * EmergeThread::Thread()
*/
bool started_generate = false;
mapgen::BlockMakeData data;
BlockMakeData data;
{
JMutexAutoLock envlock(m_server->m_env_mutex);
@ -287,7 +292,8 @@ void * EmergeThread::Thread()
SPT_AVG);
TimeTaker t("mapgen::make_block()");
mapgen::make_block(&data);
mapgen->makeChunk(&data);
//mapgen::make_block(&data);
if(enable_mapgen_debug_info == false)
t.stop(true); // Hide output
@ -332,7 +338,7 @@ void * EmergeThread::Thread()
{
TimeTaker timer("on_generated");
scriptapi_environment_on_generated(m_server->m_lua,
minp, maxp, mapgen::get_blockseed(data.seed, minp));
minp, maxp, emerge->getBlockSeed(minp));
/*int t = timer.stop(true);
dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
}
@ -937,6 +943,7 @@ Server::Server(
m_rollback(NULL),
m_rollback_sink_enabled(true),
m_enable_rollback_recording(false),
m_emerge(NULL),
m_lua(NULL),
m_itemdef(createItemDefManager()),
m_nodedef(createNodeDefManager()),
@ -976,6 +983,9 @@ Server::Server(
infostream<<"- config: "<<m_path_config<<std::endl;
infostream<<"- game: "<<m_gamespec.path<<std::endl;
// Create emerge manager
m_emerge = new EmergeManager(this);
// Create rollback manager
std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
m_rollback = createRollbackManager(rollback_path, this);
@ -1082,9 +1092,12 @@ Server::Server(
// Apply item aliases in the node definition manager
m_nodedef->updateAliases(m_itemdef);
// Add default biomes after nodedef had its aliases added
m_emerge->biomedef->addDefaultBiomes();
// Initialize Environment
m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
m_env = new ServerEnvironment(new ServerMap(path_world, this, m_emerge), m_lua,
this, this);
// Give environment reference to scripting api
@ -1184,6 +1197,7 @@ Server::~Server()
i = m_clients.getIterator();
i.atEnd() == false; i++)
{
// Delete client
delete i.getNode()->getValue();
}
@ -1192,6 +1206,7 @@ Server::~Server()
// Delete things in the reverse order of creation
delete m_env;
delete m_rollback;
delete m_emerge;
delete m_event;
delete m_itemdef;
delete m_nodedef;
@ -4832,7 +4847,7 @@ v3f findSpawnPos(ServerMap &map)
#endif
#if 1
s16 water_level = g_settings->getS16("water_level");
s16 water_level = map.m_emerge->water_level; //g_settings->getS16("default_water_level");
// Try to find a good place a few times
for(s32 i=0; i<1000; i++)

View File

@ -739,6 +739,9 @@ private:
bool m_rollback_sink_enabled;
bool m_enable_rollback_recording; // Updated once in a while
// Emerge manager
EmergeManager *m_emerge;
// Scripting
// Envlock and conlock should be locked when using Lua
lua_State *m_lua;

View File

@ -574,10 +574,7 @@ public:
set(name, "false");
}
void setS32(std::string name, s32 value)
{
set(name, itos(value));
}
void setFloat(std::string name, float value)
{
@ -598,6 +595,16 @@ public:
set(name, os.str());
}
void setS16(std::string name, s16 value)
{
set(name, itos(value));
}
void setS32(std::string name, s32 value)
{
set(name, itos(value));
}
void setU64(std::string name, u64 value)
{
std::ostringstream os;

View File

@ -120,6 +120,7 @@ inline s16 rangelim(s16 i, s16 max)
}
#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
#define myfloor(x) ((x) > 0.0 ? (int)(x) : (int)(x) - 1)
inline v3s16 arealim(v3s16 p, s16 d)
{