]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen_math.cpp
Add minetest.get_mapgen_object to API
[dragonfireclient.git] / src / mapgen_math.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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 <cmath>
21 #include "mapgen_math.h"
22 #include "voxel.h"
23 #include "mapblock.h"
24 #include "mapnode.h"
25 #include "map.h"
26 #include "nodedef.h"
27 #include "voxelalgorithms.h"
28 #include "profiler.h"
29 #include "settings.h" // For g_settings
30 #include "main.h" // For g_profiler
31 #include "emerge.h"
32 #include "biome.h"
33
34 // can use ported lib from http://mandelbulber.googlecode.com/svn/trunk/src
35 //#include "mandelbulber/fractal.h"
36 //#include "mandelbulber/fractal.cpp"
37
38 double mandelbox(double x, double y, double z, double d, int nn = 10) {
39         int s = 7;
40         x *= s;
41         y *= s;
42         z *= s;
43         d *= s;
44
45         double posX = x;
46         double posY = y;
47         double posZ = z;
48
49         double dr = 1.0;
50         double r = 0.0;
51
52         double scale = 2;
53
54         double minRadius2 = 0.25;
55         double fixedRadius2 = 1;
56
57         for (int n = 0; n < nn; n++) {
58                 // Reflect
59                 if (x > 1.0)
60                         x = 2.0 - x;
61                 else if (x < -1.0)
62                         x = -2.0 - x;
63                 if (y > 1.0)
64                         y = 2.0 - y;
65                 else if (y < -1.0)
66                         y = -2.0 - y;
67                 if (z > 1.0)
68                         z = 2.0 - z;
69                 else if (z < -1.0)
70                         z = -2.0 - z;
71
72                 // Sphere Inversion
73                 double r2 = x * x + y * y + z * z;
74
75                 if (r2 < minRadius2) {
76                         x = x * fixedRadius2 / minRadius2;
77                         y = y * fixedRadius2 / minRadius2;
78                         z = z * fixedRadius2 / minRadius2;
79                         dr = dr * fixedRadius2 / minRadius2;
80                 } else if (r2 < fixedRadius2) {
81                         x = x * fixedRadius2 / r2;
82                         y = y * fixedRadius2 / r2;
83                         z = z * fixedRadius2 / r2;
84                         fixedRadius2 *= fixedRadius2 / r2;
85                 }
86
87                 x = x * scale + posX;
88                 y = y * scale + posY;
89                 z = z * scale + posZ;
90                 dr *= scale;
91         }
92         r = sqrt(x * x + y * y + z * z);
93         return ((r / fabs(dr)) < d);
94
95 }
96
97 double mengersponge(double x, double y, double z, double d, int MI = 10) {
98
99         double r = x * x + y * y + z * z;
100         double scale = 3;
101         int i = 0;
102
103
104         for (i = 0; i < MI && r < 9; i++) {
105
106
107                 x = fabs(x);
108                 y = fabs(y);
109                 z = fabs(z);
110
111
112                 if (x - y < 0) {
113                         double x1 = y;
114                         y = x;
115                         x = x1;
116                 }
117                 if (x - z < 0) {
118                         double x1 = z;
119                         z = x;
120                         x = x1;
121                 }
122                 if (y - z < 0) {
123                         double y1 = z;
124                         z = y;
125                         y = y1;
126                 }
127
128
129                 x = scale * x - 1 * (scale - 1);
130                 y = scale * y - 1 * (scale - 1);
131                 z = scale * z;
132
133
134                 if (z > 0.5 * 1 * (scale - 1))
135                         z -= 1 * (scale - 1);
136
137
138                 r = x * x + y * y + z * z;
139         }
140         return ((sqrt(r)) * pow(scale, (-i)) < d);
141 }
142
143 double sphere(double x, double y, double z, double d, int ITR = 1) {
144         return v3f(x, y, z).getLength() < d;
145 }
146
147
148 //////////////////////// Mapgen Math parameter read/write
149
150 bool MapgenMathParams::readParams(Settings *settings) {
151         //params = settings->getJson("mg_math");
152         // can be counfigured from here.
153         std::string value = "{}";
154         Json::Reader reader;
155         if (!reader.parse( value, params ) ) {
156                 errorstream  << "Failed to parse json conf var ='" << value << "' : " << reader.getFormattedErrorMessages();
157         }
158
159         if (params["generator"].empty()) params["generator"] = settings->get("mgmath_generator");
160
161         return true;
162 }
163
164
165 void MapgenMathParams::writeParams(Settings *settings) {
166         //settings->setJson("mg_math", params);
167         settings->set("mgmath_generator", params["generator"].asString());
168 }
169
170 ///////////////////////////////////////////////////////////////////////////////
171
172 MapgenMath::MapgenMath(int mapgenid, MapgenMathParams *params_, EmergeManager *emerge) : MapgenV7(mapgenid, params_, emerge) {
173         mg_params = params_;
174         this->lighting = 0;
175         this->ridges   = 0;
176
177         Json::Value & params = mg_params->params;
178         invert = params["invert"].empty() ? 1 : params["invert"].asBool(); //params["invert"].empty()?1:params["invert"].asBool();
179         size = params["size"].empty() ? 0 : params["size"].asDouble(); // = max_r
180         scale = params["scale"].empty() ? 0 : params["scale"].asDouble(); //(double)1 / size;
181         if(!params["center"].empty()) center = v3f(params["center"]["x"].asFloat(), params["center"]["y"].asFloat(), params["center"]["z"].asFloat()); //v3f(5, -size - 5, 5);
182         iterations = params["iterations"].empty() ? 0 : params["iterations"].asInt(); //10;
183         distance = params["distance"].empty() ? 0 : params["distance"].asDouble(); // = 1/size;
184
185         func = &sphere;
186
187         if (params["generator"].empty()) params["generator"] = "mandelbox";
188         if (params["generator"].asString() == "mengersponge") {
189                 if (!size) size = (MAP_GENERATION_LIMIT - 1000) / 2;
190                 if (!iterations) iterations = 10;
191                 if (!distance) distance = 0.0003;
192                 //if (!scale) scale = (double)0.1 / size;
193                 //if (!distance) distance = 0.01; //10/size;//sqrt3 * bd4;
194                 //if (!scale) scale = 0.01; //10/size;//sqrt3 * bd4;
195                 //center=v3f(-size/3,-size/3+(-2*-invert),2);
196                 center = v3f(-size, -size, -size);
197                 func = &mengersponge;
198         } else if (params["generator"].asString() == "mandelbox") {
199                 /*
200                         size = MAP_GENERATION_LIMIT - 1000;
201                         //size = 1000;
202                         distance = 0.01; //100/size; //0.01;
203                         iterations = 10;
204                         center = v3f(1, 1, 1); // *size/6;
205                 */
206
207                 //mandelbox
208                 if (!size) size = 1000;
209                 if (!distance) distance = 0.01;
210                 if(params["invert"].empty()) invert = 0;
211                 //center=v3f(2,-size/4,2);
212                 //size = 10000;
213                 //center=v3f(size/2,-size*0.9,size/2);
214                 if(params["center"].empty())center = v3f(size * 0.3, -size * 0.6, size * 0.5);
215                 func = &mandelbox;
216         } else if (params["generator"].asString() == "sphere") {
217                 if(params["invert"].empty()) invert = 0;
218                 if (!size) size = 100;
219                 if (!distance) distance = size;
220                 func = &sphere;
221                 if (!scale) scale = 1;
222                 //sphere
223                 //size = 1000;scale = 1;center = v3f(2,-size-2,2);
224         }
225
226         if (!iterations) iterations = 10;
227         if (!size) size = 1000;
228         if (!scale) scale = (double)1 / size;
229         if (!distance)  distance = scale;
230         if (params["center"].empty() && !center.getLength()) center = v3f(3, -size + (-5 - (-invert * 10)), 3);
231         //size ||= params["size"].empty()?1000:params["size"].asDouble(); // = max_r
232
233 }
234
235
236 MapgenMath::~MapgenMath() {
237 }
238
239 //////////////////////// Map generator
240
241 void MapgenMath::generateTerrain() {
242
243         MapNode n_air(CONTENT_AIR, LIGHT_SUN), n_water_source(c_water_source, LIGHT_SUN);
244         MapNode n_stone(c_stone, LIGHT_SUN);
245         u32 index = 0;
246         v3s16 em = vm->m_area.getExtent();
247
248 #if 1
249
250         /* debug
251         v3f vec0 = (v3f(node_min.X, node_min.Y, node_min.Z) - center) * scale ;
252         errorstream << " X=" << node_min.X << " Y=" << node_min.Y << " Z=" << node_min.Z
253                     //<< " N="<< mengersponge(vec0.X, vec0.Y, vec0.Z, distance, iterations)
254                     << " N=" << (*func)(vec0.X, vec0.Y, vec0.Z, distance, iterations)
255                     << " Sc=" << scale << " gen=" << params["generator"].asString() << " J=" << Json::FastWriter().write(params) << std::endl;
256         */
257         for (s16 z = node_min.Z; z <= node_max.Z; z++) {
258                 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
259                         Biome *biome = bmgr->biomes[biomemap[index]];
260                         u32 i = vm->m_area.index(x, node_min.Y, z);
261                         for (s16 y = node_min.Y; y <= node_max.Y; y++) {
262                                 v3f vec = (v3f(x, y, z) - center) * scale ;
263                                 double d = (*func)(vec.X, vec.Y, vec.Z, distance, iterations);
264                                 if ((!invert && d > 0) || (invert && d == 0)  ) {
265                                         if (vm->m_data[i].getContent() == CONTENT_IGNORE)
266                                                 vm->m_data[i] = (y > water_level + biome->filler_height) ?
267                                                                 MapNode(biome->c_filler) : n_stone;
268 //                                              vm->m_data[i] = n_stone;
269                                 } else if (y <= water_level) {
270                                         vm->m_data[i] = n_water_source;
271                                 } else {
272                                         vm->m_data[i] = n_air;
273                                 }
274                                 vm->m_area.add_y(em, i, 1);
275                         }
276                 }
277         }
278 #endif
279
280
281 #if 0
282 // mandelbulber, unfinished but works
283         sFractal par;
284         par.doubles.N = 10;
285
286         par.doubles.power = 9.0;
287         par.doubles.foldingSphericalFixed =  1.0;
288         par.doubles.foldingSphericalMin = 0.5;
289         //no par.formula = smoothMandelbox; par.doubles.N = 40; invert = 0;//no
290         par.mandelbox.doubles.sharpness = 3.0;
291         par.mandelbox.doubles.scale = 1;
292         par.mandelbox.doubles.sharpness = 2;
293         par.mandelbox.doubles.foldingLimit = 1.0;
294         par.mandelbox.doubles.foldingValue = 2;
295
296 //ok    par.formula = mandelboxVaryScale4D; par.doubles.N = 50; scale = 5; invert = 1; //ok
297         par.mandelbox.doubles.vary4D.scaleVary =  0.1;
298         par.mandelbox.doubles.vary4D.fold = 1;
299         par.mandelbox.doubles.vary4D.rPower = 1;
300         par.mandelbox.doubles.vary4D.minR = 0.5;
301         par.mandelbox.doubles.vary4D.wadd = 0;
302         par.doubles.constantFactor = 1.0;
303
304         par.formula = menger_sponge; par.doubles.N = 15; invert = 0; size = 30000; center = v3f(-size / 2, -size + (-2 * -invert), 2);  scale = (double)1 / size; //ok
305
306         //double tresh = 1.5;
307         //par.formula = mandelbulb2; par.doubles.N = 10; scale = (double)1/size; invert=1; center = v3f(5,-size-5,0); //ok
308         //par.formula = hypercomplex; par.doubles.N = 20; scale = 0.0001; invert=1; center = v3f(0,-10001,0); //(double)50 / max_r;
309
310         //no par.formula = trig_DE; par.doubles.N = 5;  scale = (double)10; invert=1;
311
312         //no par.formula = trig_optim; scale = (double)10;  par.doubles.N = 4;
313
314         //par.formula = mandelbulb2; scale = (double)1/10000; par.doubles.N = 10; invert = 1; center = v3f(1,-4201,1); //ok
315         // no par.formula = tglad;
316
317         //par.formula = xenodreambuie;  par.juliaMode = 1; par.doubles.julia.x = -1; par.doubles.power = 2.0; center=v3f(-size/2,-size/2-5,5); //ok
318
319         par.mandelbox.doubles.vary4D.scaleVary = 0.1;
320         par.mandelbox.doubles.vary4D.fold = 1;
321         par.mandelbox.doubles.vary4D.minR = 0.5;
322         par.mandelbox.doubles.vary4D.rPower = 1;
323         par.mandelbox.doubles.vary4D.wadd = 0;
324         //no par.formula = mandelboxVaryScale4D;
325         par.doubles.cadd = -1.3;
326         //par.formula = aexion; // ok but center
327         //par.formula = benesi; par.doubles.N = 10; center = v3f(0,0,0); invert = 0; //ok
328
329         // par.formula = bristorbrot; //ok
330
331         v3f vec0(node_min.X, node_min.Y, node_min.Z);
332         vec0 = (vec0 - center) * scale ;
333         errorstream << " X=" << node_min.X << " Y=" << node_min.Y << " Z=" << node_min.Z
334                     << " N=" << Compute<normal>(CVector3(vec0.X, vec0.Y, vec0.Z), par)
335                     //<<" F="<< Compute<fake_AO>(CVector3(node_min.X,node_min.Y,node_min.Z), par)
336                     //<<" L="<<node_min.getLength()<< " -="<<node_min.getLength() - Compute<normal>(CVector3(node_min.X,node_min.Y,node_min.Z), par)
337                     << " Sc=" << scale
338                     << std::endl;
339
340         for (s16 z = node_min.Z; z <= node_max.Z; z++)
341                 for (s16 y = node_min.Y; y <= node_max.Y; y++) {
342                         u32 i = vm->m_area.index(node_min.X, y, z);
343                         for (s16 x = node_min.X; x <= node_max.X; x++) {
344                                 v3f vec(x, y, z);
345                                 vec = (vec - center) * scale ;
346                                 //double d = Compute<fake_AO>(CVector3(x,y,z), par);
347                                 double d = Compute<normal>(CVector3(vec.X, vec.Y, vec.Z), par);
348                                 //if (d>0)
349                                 // errorstream << " d=" << d  <<" v="<< vec.getLength()<< " -="<< vec.getLength() - d <<" yad="
350                                 //<< Compute<normal>(CVector3(x,y,z), par)
351                                 //<< std::endl;
352                                 if ((!invert && d > 0) || (invert && d == 0)/*&& vec.getLength() - d > tresh*/ ) {
353                                         if (vm->m_data[i].getContent() == CONTENT_IGNORE)
354                                                 vm->m_data[i] = n_stone;
355                                 } else {
356                                         vm->m_data[i] = n_air;
357                                 }
358                                 i++;
359                         }
360                 }
361
362
363 #endif
364
365 }
366
367 int MapgenMath::getGroundLevelAtPoint(v2s16 p) {
368         return 0;
369 }