LCOV - code coverage report
Current view: top level - src - mg_decoration.cpp (source / functions) Hit Total Coverage
Test: report Lines: 1 133 0.8 %
Date: 2015-07-11 18:23:49 Functions: 2 16 12.5 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2014 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "mg_decoration.h"
      21             : #include "mg_schematic.h"
      22             : #include "mapgen.h"
      23             : #include "noise.h"
      24             : #include "map.h"
      25             : #include "log.h"
      26             : #include "util/numeric.h"
      27             : 
      28             : FlagDesc flagdesc_deco[] = {
      29             :         {"place_center_x", DECO_PLACE_CENTER_X},
      30             :         {"place_center_y", DECO_PLACE_CENTER_Y},
      31             :         {"place_center_z", DECO_PLACE_CENTER_Z},
      32             :         {"force_placement", DECO_FORCE_PLACEMENT},
      33             :         {NULL,             0}
      34             : };
      35             : 
      36             : 
      37             : ///////////////////////////////////////////////////////////////////////////////
      38             : 
      39             : 
      40           0 : DecorationManager::DecorationManager(IGameDef *gamedef) :
      41           0 :         ObjDefManager(gamedef, OBJDEF_DECORATION)
      42             : {
      43           0 : }
      44             : 
      45             : 
      46           0 : size_t DecorationManager::placeAllDecos(Mapgen *mg, u32 blockseed,
      47             :         v3s16 nmin, v3s16 nmax)
      48             : {
      49           0 :         size_t nplaced = 0;
      50             : 
      51           0 :         for (size_t i = 0; i != m_objects.size(); i++) {
      52           0 :                 Decoration *deco = (Decoration *)m_objects[i];
      53           0 :                 if (!deco)
      54           0 :                         continue;
      55             : 
      56           0 :                 nplaced += deco->placeDeco(mg, blockseed, nmin, nmax);
      57           0 :                 blockseed++;
      58             :         }
      59             : 
      60           0 :         return nplaced;
      61             : }
      62             : 
      63             : 
      64             : ///////////////////////////////////////////////////////////////////////////////
      65             : 
      66             : 
      67           0 : Decoration::Decoration()
      68             : {
      69           0 :         mapseed    = 0;
      70           0 :         fill_ratio = 0;
      71           0 :         sidelen    = 1;
      72           0 :         flags      = 0;
      73           0 : }
      74             : 
      75             : 
      76           0 : Decoration::~Decoration()
      77             : {
      78           0 : }
      79             : 
      80             : 
      81           0 : void Decoration::resolveNodeNames()
      82             : {
      83           0 :         getIdsFromNrBacklog(&c_place_on);
      84           0 : }
      85             : 
      86             : 
      87           0 : size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
      88             : {
      89           0 :         PseudoRandom ps(blockseed + 53);
      90           0 :         int carea_size = nmax.X - nmin.X + 1;
      91             : 
      92             :         // Divide area into parts
      93           0 :         if (carea_size % sidelen) {
      94             :                 errorstream << "Decoration::placeDeco: chunk size is not divisible by "
      95           0 :                         "sidelen; setting sidelen to " << carea_size << std::endl;
      96           0 :                 sidelen = carea_size;
      97             :         }
      98             : 
      99           0 :         s16 divlen = carea_size / sidelen;
     100           0 :         int area = sidelen * sidelen;
     101             : 
     102           0 :         for (s16 z0 = 0; z0 < divlen; z0++)
     103           0 :         for (s16 x0 = 0; x0 < divlen; x0++) {
     104             :                 v2s16 p2d_center( // Center position of part of division
     105           0 :                         nmin.X + sidelen / 2 + sidelen * x0,
     106           0 :                         nmin.Z + sidelen / 2 + sidelen * z0
     107           0 :                 );
     108             :                 v2s16 p2d_min( // Minimum edge of part of division
     109           0 :                         nmin.X + sidelen * x0,
     110           0 :                         nmin.Z + sidelen * z0
     111           0 :                 );
     112             :                 v2s16 p2d_max( // Maximum edge of part of division
     113           0 :                         nmin.X + sidelen + sidelen * x0 - 1,
     114           0 :                         nmin.Z + sidelen + sidelen * z0 - 1
     115           0 :                 );
     116             : 
     117             :                 // Amount of decorations
     118           0 :                 float nval = (flags & DECO_USE_NOISE) ?
     119           0 :                         NoisePerlin2D(&np, p2d_center.X, p2d_center.Y, mapseed) :
     120           0 :                         fill_ratio;
     121           0 :                 u32 deco_count = area * MYMAX(nval, 0.f);
     122             : 
     123           0 :                 for (u32 i = 0; i < deco_count; i++) {
     124           0 :                         s16 x = ps.range(p2d_min.X, p2d_max.X);
     125           0 :                         s16 z = ps.range(p2d_min.Y, p2d_max.Y);
     126             : 
     127           0 :                         int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X);
     128             : 
     129           0 :                         s16 y = mg->heightmap ?
     130           0 :                                         mg->heightmap[mapindex] :
     131           0 :                                         mg->findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y);
     132             : 
     133           0 :                         if (y < nmin.Y || y > nmax.Y ||
     134           0 :                                 y < y_min  || y > y_max)
     135           0 :                                 continue;
     136             : 
     137           0 :                         if (y + getHeight() >= mg->vm->m_area.MaxEdge.Y) {
     138           0 :                                 continue;
     139             : #if 0
     140             :                                 printf("Decoration at (%d %d %d) cut off\n", x, y, z);
     141             :                                 //add to queue
     142             :                                 JMutexAutoLock cutofflock(cutoff_mutex);
     143             :                                 cutoffs.push_back(CutoffData(x, y, z, height));
     144             : #endif
     145             :                         }
     146             : 
     147           0 :                         if (mg->biomemap) {
     148           0 :                                 std::set<u8>::iterator iter;
     149             : 
     150           0 :                                 if (!biomes.empty()) {
     151           0 :                                         iter = biomes.find(mg->biomemap[mapindex]);
     152           0 :                                         if (iter == biomes.end())
     153           0 :                                                 continue;
     154             :                                 }
     155             :                         }
     156             : 
     157           0 :                         v3s16 pos(x, y, z);
     158           0 :                         if (generate(mg->vm, &ps, pos))
     159           0 :                                 mg->gennotify.addEvent(GENNOTIFY_DECORATION, pos, index);
     160             :                 }
     161             :         }
     162             : 
     163           0 :         return 0;
     164             : }
     165             : 
     166             : 
     167             : #if 0
     168             : void Decoration::placeCutoffs(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
     169             : {
     170             :         PseudoRandom pr(blockseed + 53);
     171             :         std::vector<CutoffData> handled_cutoffs;
     172             : 
     173             :         // Copy over the cutoffs we're interested in so we don't needlessly hold a lock
     174             :         {
     175             :                 JMutexAutoLock cutofflock(cutoff_mutex);
     176             :                 for (std::list<CutoffData>::iterator i = cutoffs.begin();
     177             :                         i != cutoffs.end(); ++i) {
     178             :                         CutoffData cutoff = *i;
     179             :                         v3s16 p    = cutoff.p;
     180             :                         s16 height = cutoff.height;
     181             :                         if (p.X < nmin.X || p.X > nmax.X ||
     182             :                                 p.Z < nmin.Z || p.Z > nmax.Z)
     183             :                                 continue;
     184             :                         if (p.Y + height < nmin.Y || p.Y > nmax.Y)
     185             :                                 continue;
     186             : 
     187             :                         handled_cutoffs.push_back(cutoff);
     188             :                 }
     189             :         }
     190             : 
     191             :         // Generate the cutoffs
     192             :         for (size_t i = 0; i != handled_cutoffs.size(); i++) {
     193             :                 v3s16 p    = handled_cutoffs[i].p;
     194             :                 s16 height = handled_cutoffs[i].height;
     195             : 
     196             :                 if (p.Y + height > nmax.Y) {
     197             :                         //printf("Decoration at (%d %d %d) cut off again!\n", p.X, p.Y, p.Z);
     198             :                         cuttoffs.push_back(v3s16(p.X, p.Y, p.Z));
     199             :                 }
     200             : 
     201             :                 generate(mg, &pr, nmax.Y, nmin.Y - p.Y, v3s16(p.X, nmin.Y, p.Z));
     202             :         }
     203             : 
     204             :         // Remove cutoffs that were handled from the cutoff list
     205             :         {
     206             :                 JMutexAutoLock cutofflock(cutoff_mutex);
     207             :                 for (std::list<CutoffData>::iterator i = cutoffs.begin();
     208             :                         i != cutoffs.end(); ++i) {
     209             : 
     210             :                         for (size_t j = 0; j != handled_cutoffs.size(); j++) {
     211             :                                 CutoffData coff = *i;
     212             :                                 if (coff.p == handled_cutoffs[j].p)
     213             :                                         i = cutoffs.erase(i);
     214             :                         }
     215             :                 }
     216             :         }
     217             : }
     218             : #endif
     219             : 
     220             : 
     221             : ///////////////////////////////////////////////////////////////////////////////
     222             : 
     223             : 
     224           0 : void DecoSimple::resolveNodeNames()
     225             : {
     226           0 :         Decoration::resolveNodeNames();
     227           0 :         getIdsFromNrBacklog(&c_decos);
     228           0 :         getIdsFromNrBacklog(&c_spawnby);
     229           0 : }
     230             : 
     231             : 
     232           0 : bool DecoSimple::canPlaceDecoration(MMVManip *vm, v3s16 p)
     233             : {
     234             :         // Don't bother if there aren't any decorations to place
     235           0 :         if (c_decos.size() == 0)
     236           0 :                 return false;
     237             : 
     238           0 :         u32 vi = vm->m_area.index(p);
     239             : 
     240             :         // Check if the decoration can be placed on this node
     241           0 :         if (!CONTAINS(c_place_on, vm->m_data[vi].getContent()))
     242           0 :                 return false;
     243             : 
     244             :         // Don't continue if there are no spawnby constraints
     245           0 :         if (nspawnby == -1)
     246           0 :                 return true;
     247             : 
     248           0 :         int nneighs = 0;
     249             :         v3s16 dirs[8] = {
     250             :                 v3s16( 0, 0,  1),
     251             :                 v3s16( 0, 0, -1),
     252             :                 v3s16( 1, 0,  0),
     253             :                 v3s16(-1, 0,  0),
     254             :                 v3s16( 1, 0,  1),
     255             :                 v3s16(-1, 0,  1),
     256             :                 v3s16(-1, 0, -1),
     257             :                 v3s16( 1, 0, -1)
     258           0 :         };
     259             : 
     260             :         // Check a Moore neighborhood if there are enough spawnby nodes
     261           0 :         for (size_t i = 0; i != ARRLEN(dirs); i++) {
     262           0 :                 u32 index = vm->m_area.index(p + dirs[i]);
     263           0 :                 if (!vm->m_area.contains(index))
     264           0 :                         continue;
     265             : 
     266           0 :                 if (CONTAINS(c_spawnby, vm->m_data[index].getContent()))
     267           0 :                         nneighs++;
     268             :         }
     269             : 
     270           0 :         if (nneighs < nspawnby)
     271           0 :                 return false;
     272             : 
     273           0 :         return true;
     274             : }
     275             : 
     276             : 
     277           0 : size_t DecoSimple::generate(MMVManip *vm, PseudoRandom *pr, v3s16 p)
     278             : {
     279           0 :         if (!canPlaceDecoration(vm, p))
     280           0 :                 return 0;
     281             : 
     282           0 :         content_t c_place = c_decos[pr->range(0, c_decos.size() - 1)];
     283             : 
     284           0 :         s16 height = (deco_height_max > 0) ?
     285           0 :                 pr->range(deco_height, deco_height_max) : deco_height;
     286             : 
     287           0 :         v3s16 em = vm->m_area.getExtent();
     288           0 :         u32 vi = vm->m_area.index(p);
     289           0 :         for (int i = 0; i < height; i++) {
     290           0 :                 vm->m_area.add_y(em, vi, 1);
     291             : 
     292           0 :                 content_t c = vm->m_data[vi].getContent();
     293           0 :                 if (c != CONTENT_AIR && c != CONTENT_IGNORE)
     294           0 :                         break;
     295             : 
     296           0 :                 vm->m_data[vi] = MapNode(c_place);
     297             :         }
     298             : 
     299           0 :         return 1;
     300             : }
     301             : 
     302             : 
     303           0 : int DecoSimple::getHeight()
     304             : {
     305           0 :         return (deco_height_max > 0) ? deco_height_max : deco_height;
     306             : }
     307             : 
     308             : 
     309             : ///////////////////////////////////////////////////////////////////////////////
     310             : 
     311             : 
     312           0 : DecoSchematic::DecoSchematic()
     313             : {
     314           0 :         schematic = NULL;
     315           0 : }
     316             : 
     317             : 
     318           0 : size_t DecoSchematic::generate(MMVManip *vm, PseudoRandom *pr, v3s16 p)
     319             : {
     320             :         // Schematic could have been unloaded but not the decoration
     321             :         // In this case generate() does nothing (but doesn't *fail*)
     322           0 :         if (schematic == NULL)
     323           0 :                 return 0;
     324             : 
     325           0 :         u32 vi = vm->m_area.index(p);
     326           0 :         content_t c = vm->m_data[vi].getContent();
     327           0 :         if (!CONTAINS(c_place_on, c))
     328           0 :                 return 0;
     329             : 
     330           0 :         if (flags & DECO_PLACE_CENTER_X)
     331           0 :                 p.X -= (schematic->size.X - 1) / 2;
     332           0 :         if (flags & DECO_PLACE_CENTER_Y)
     333           0 :                 p.Y -= (schematic->size.Y - 1) / 2;
     334           0 :         if (flags & DECO_PLACE_CENTER_Z)
     335           0 :                 p.Z -= (schematic->size.Z - 1) / 2;
     336             : 
     337           0 :         Rotation rot = (rotation == ROTATE_RAND) ?
     338           0 :                 (Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
     339             : 
     340           0 :         bool force_placement = (flags & DECO_FORCE_PLACEMENT);
     341             : 
     342           0 :         schematic->blitToVManip(p, vm, rot, force_placement);
     343             : 
     344           0 :         return 1;
     345             : }
     346             : 
     347             : 
     348           0 : int DecoSchematic::getHeight()
     349             : {
     350           0 :         return schematic->size.Y;
     351           3 : }

Generated by: LCOV version 1.11