/*
Minetest
-Copyright (C) 2014-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
-Copyright (C) 2015-2017 paramat
+Copyright (C) 2014-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+Copyright (C) 2015-2018 paramat
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
#include "log.h"
#include "util/numeric.h"
#include <algorithm>
+#include <vector>
FlagDesc flagdesc_deco[] = {
return nplaced;
}
+DecorationManager *DecorationManager::clone() const
+{
+ auto mgr = new DecorationManager();
+ ObjDefManager::cloneTo(mgr);
+ return mgr;
+}
+
///////////////////////////////////////////////////////////////////////////////
nmin.Z + sidelen + sidelen * z0 - 1
);
+ bool cover = false;
// Amount of decorations
float nval = (flags & DECO_USE_NOISE) ?
NoisePerlin2D(&np, p2d_center.X, p2d_center.Y, mapseed) :
fill_ratio;
u32 deco_count = 0;
- float deco_count_f = (float)area * nval;
- if (deco_count_f >= 1.f) {
- deco_count = deco_count_f;
- } else if (deco_count_f > 0.f) {
- // For low density decorations calculate a chance for 1 decoration
- if (ps.range(1000) <= deco_count_f * 1000.f)
- deco_count = 1;
+
+ if (nval >= 10.0f) {
+ // Complete coverage. Disable random placement to avoid
+ // redundant multiple placements at one position.
+ cover = true;
+ deco_count = area;
+ } else {
+ float deco_count_f = (float)area * nval;
+ if (deco_count_f >= 1.0f) {
+ deco_count = deco_count_f;
+ } else if (deco_count_f > 0.0f) {
+ // For very low density calculate a chance for 1 decoration
+ if (ps.range(1000) <= deco_count_f * 1000.0f)
+ deco_count = 1;
+ }
}
+ s16 x = p2d_min.X - 1;
+ s16 z = p2d_min.Y;
+
for (u32 i = 0; i < deco_count; i++) {
- s16 x = ps.range(p2d_min.X, p2d_max.X);
- s16 z = ps.range(p2d_min.Y, p2d_max.Y);
+ if (!cover) {
+ x = ps.range(p2d_min.X, p2d_max.X);
+ z = ps.range(p2d_min.Y, p2d_max.Y);
+ } else {
+ x++;
+ if (x == p2d_max.X + 1) {
+ z++;
+ x = p2d_min.X;
+ }
+ }
int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X);
if ((flags & DECO_ALL_FLOORS) ||
// All-surfaces decorations
// Check biome of column
if (mg->biomemap && !biomes.empty()) {
- std::unordered_set<u8>::const_iterator iter =
- biomes.find(mg->biomemap[mapindex]);
+ auto iter = biomes.find(mg->biomemap[mapindex]);
if (iter == biomes.end())
continue;
}
// Get all floors and ceilings in node column
u16 size = (nmax.Y - nmin.Y + 1) / 2;
- s16 floors[size];
- s16 ceilings[size];
- u16 num_floors = 0;
- u16 num_ceilings = 0;
+ std::vector<s16> floors;
+ std::vector<s16> ceilings;
+ floors.reserve(size);
+ ceilings.reserve(size);
- mg->getSurfaces(v2s16(x, z), nmin.Y, nmax.Y,
- floors, ceilings, &num_floors, &num_ceilings);
+ mg->getSurfaces(v2s16(x, z), nmin.Y, nmax.Y, floors, ceilings);
- if ((flags & DECO_ALL_FLOORS) && num_floors > 0) {
+ if (flags & DECO_ALL_FLOORS) {
// Floor decorations
- for (u16 fi = 0; fi < num_floors; fi++) {
- s16 y = floors[fi];
+ for (const s16 y : floors) {
if (y < y_min || y > y_max)
continue;
}
}
- if ((flags & DECO_ALL_CEILINGS) && num_ceilings > 0) {
+ if (flags & DECO_ALL_CEILINGS) {
// Ceiling decorations
- for (u16 ci = 0; ci < num_ceilings; ci++) {
- s16 y = ceilings[ci];
+ for (const s16 y : ceilings) {
if (y < y_min || y > y_max)
continue;
continue;
if (mg->biomemap && !biomes.empty()) {
- std::unordered_set<u8>::const_iterator iter =
- biomes.find(mg->biomemap[mapindex]);
+ auto iter = biomes.find(mg->biomemap[mapindex]);
if (iter == biomes.end())
continue;
}
}
+void Decoration::cloneTo(Decoration *def) const
+{
+ ObjDef::cloneTo(def);
+ def->flags = flags;
+ def->mapseed = mapseed;
+ def->c_place_on = c_place_on;
+ def->sidelen = sidelen;
+ def->y_min = y_min;
+ def->y_max = y_max;
+ def->fill_ratio = fill_ratio;
+ def->np = np;
+ def->c_spawnby = c_spawnby;
+ def->nspawnby = nspawnby;
+ def->place_offset_y = place_offset_y;
+ def->biomes = biomes;
+}
+
+
///////////////////////////////////////////////////////////////////////////////
+ObjDef *DecoSimple::clone() const
+{
+ auto def = new DecoSimple();
+ Decoration::cloneTo(def);
+
+ def->c_decos = c_decos;
+ def->deco_height = deco_height;
+ def->deco_height_max = deco_height_max;
+ def->deco_param2 = deco_param2;
+ def->deco_param2_max = deco_param2_max;
+
+ return def;
+}
+
+
void DecoSimple::resolveNodeNames()
{
Decoration::resolveNodeNames();
if (ceiling) {
// Ceiling decorations
// 'place offset y' is inverted
- vm->m_area.add_y(em, vi, -place_offset_y);
+ VoxelArea::add_y(em, vi, -place_offset_y);
for (int i = 0; i < height; i++) {
- vm->m_area.add_y(em, vi, -1);
+ VoxelArea::add_y(em, vi, -1);
content_t c = vm->m_data[vi].getContent();
if (c != CONTENT_AIR && c != CONTENT_IGNORE && !force_placement)
break;
vm->m_data[vi] = MapNode(c_place, 0, param2);
}
} else { // Heightmap and floor decorations
- vm->m_area.add_y(em, vi, place_offset_y);
+ VoxelArea::add_y(em, vi, place_offset_y);
for (int i = 0; i < height; i++) {
- vm->m_area.add_y(em, vi, 1);
+ VoxelArea::add_y(em, vi, 1);
content_t c = vm->m_data[vi].getContent();
if (c != CONTENT_AIR && c != CONTENT_IGNORE && !force_placement)
break;
///////////////////////////////////////////////////////////////////////////////
+DecoSchematic::~DecoSchematic()
+{
+ if (was_cloned)
+ delete schematic;
+}
+
+
+ObjDef *DecoSchematic::clone() const
+{
+ auto def = new DecoSchematic();
+ Decoration::cloneTo(def);
+ NodeResolver::cloneTo(def);
+
+ def->rotation = rotation;
+ /* FIXME: We do not own this schematic, yet we only have a pointer to it
+ * and not a handle. We are left with no option but to clone it ourselves.
+ * This is a waste of memory and should be replaced with an alternative
+ * approach sometime. */
+ def->schematic = dynamic_cast<Schematic*>(schematic->clone());
+ def->was_cloned = true;
+
+ return def;
+}
+
+
size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
{
// Schematic could have been unloaded but not the decoration
if (p.Y < vm->m_area.MinEdge.Y)
return 0;
- if (flags & DECO_PLACE_CENTER_X)
- p.X -= (schematic->size.X - 1) / 2;
- if (flags & DECO_PLACE_CENTER_Z)
- p.Z -= (schematic->size.Z - 1) / 2;
-
Rotation rot = (rotation == ROTATE_RAND) ?
(Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
+
+ if (flags & DECO_PLACE_CENTER_X) {
+ if (rot == ROTATE_0 || rot == ROTATE_180)
+ p.X -= (schematic->size.X - 1) / 2;
+ else
+ p.Z -= (schematic->size.X - 1) / 2;
+ }
+ if (flags & DECO_PLACE_CENTER_Z) {
+ if (rot == ROTATE_0 || rot == ROTATE_180)
+ p.Z -= (schematic->size.Z - 1) / 2;
+ else
+ p.X -= (schematic->size.Z - 1) / 2;
+ }
+
bool force_placement = (flags & DECO_FORCE_PLACEMENT);
schematic->blitToVManip(vm, p, rot, force_placement);