]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_noise.cpp
noise: Throw exception on noise allocation failure
[dragonfireclient.git] / src / script / lua_api / l_noise.cpp
1 /*
2 Minetest
3 Copyright (C) 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 "lua_api/l_noise.h"
21 #include "lua_api/l_internal.h"
22 #include "common/c_converter.h"
23 #include "common/c_content.h"
24 #include "log.h"
25
26 // garbage collector
27 int LuaPerlinNoise::gc_object(lua_State *L)
28 {
29         LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
30         delete o;
31         return 0;
32 }
33
34 int LuaPerlinNoise::l_get2d(lua_State *L)
35 {
36         NO_MAP_LOCK_REQUIRED;
37         LuaPerlinNoise *o = checkobject(L, 1);
38         v2f pos2d = read_v2f(L,2);
39         lua_Number val = noise2d_perlin(pos2d.X/o->scale, pos2d.Y/o->scale, o->seed, o->octaves, o->persistence);
40         lua_pushnumber(L, val);
41         return 1;
42 }
43 int LuaPerlinNoise::l_get3d(lua_State *L)
44 {
45         NO_MAP_LOCK_REQUIRED;
46         LuaPerlinNoise *o = checkobject(L, 1);
47         v3f pos3d = read_v3f(L,2);
48         lua_Number val = noise3d_perlin(pos3d.X/o->scale, pos3d.Y/o->scale, pos3d.Z/o->scale, o->seed, o->octaves, o->persistence);
49         lua_pushnumber(L, val);
50         return 1;
51 }
52
53
54 LuaPerlinNoise::LuaPerlinNoise(int a_seed, int a_octaves, float a_persistence,
55                 float a_scale):
56         seed(a_seed),
57         octaves(a_octaves),
58         persistence(a_persistence),
59         scale(a_scale)
60 {
61 }
62
63 LuaPerlinNoise::~LuaPerlinNoise()
64 {
65 }
66
67 // LuaPerlinNoise(seed, octaves, persistence, scale)
68 // Creates an LuaPerlinNoise and leaves it on top of stack
69 int LuaPerlinNoise::create_object(lua_State *L)
70 {
71         NO_MAP_LOCK_REQUIRED;
72         int seed = luaL_checkint(L, 1);
73         int octaves = luaL_checkint(L, 2);
74         float persistence = luaL_checknumber(L, 3);
75         float scale = luaL_checknumber(L, 4);
76         LuaPerlinNoise *o = new LuaPerlinNoise(seed, octaves, persistence, scale);
77         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
78         luaL_getmetatable(L, className);
79         lua_setmetatable(L, -2);
80         return 1;
81 }
82
83 LuaPerlinNoise* LuaPerlinNoise::checkobject(lua_State *L, int narg)
84 {
85         NO_MAP_LOCK_REQUIRED;
86         luaL_checktype(L, narg, LUA_TUSERDATA);
87         void *ud = luaL_checkudata(L, narg, className);
88         if(!ud) luaL_typerror(L, narg, className);
89         return *(LuaPerlinNoise**)ud;  // unbox pointer
90 }
91
92 void LuaPerlinNoise::Register(lua_State *L)
93 {
94         lua_newtable(L);
95         int methodtable = lua_gettop(L);
96         luaL_newmetatable(L, className);
97         int metatable = lua_gettop(L);
98
99         lua_pushliteral(L, "__metatable");
100         lua_pushvalue(L, methodtable);
101         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
102
103         lua_pushliteral(L, "__index");
104         lua_pushvalue(L, methodtable);
105         lua_settable(L, metatable);
106
107         lua_pushliteral(L, "__gc");
108         lua_pushcfunction(L, gc_object);
109         lua_settable(L, metatable);
110
111         lua_pop(L, 1);  // drop metatable
112
113         luaL_openlib(L, 0, methods, 0);  // fill methodtable
114         lua_pop(L, 1);  // drop methodtable
115
116         // Can be created from Lua (PerlinNoise(seed, octaves, persistence)
117         lua_register(L, className, create_object);
118 }
119
120 const char LuaPerlinNoise::className[] = "PerlinNoise";
121 const luaL_reg LuaPerlinNoise::methods[] = {
122         luamethod(LuaPerlinNoise, get2d),
123         luamethod(LuaPerlinNoise, get3d),
124         {0,0}
125 };
126
127 /*
128   PerlinNoiseMap
129  */
130
131
132 int LuaPerlinNoiseMap::gc_object(lua_State *L)
133 {
134         LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
135         delete o;
136         return 0;
137 }
138
139 int LuaPerlinNoiseMap::l_get2dMap(lua_State *L)
140 {
141         NO_MAP_LOCK_REQUIRED;
142         int i = 0;
143
144         LuaPerlinNoiseMap *o = checkobject(L, 1);
145         v2f p = read_v2f(L, 2);
146
147         Noise *n = o->noise;
148         n->perlinMap2D(p.X, p.Y);
149
150         lua_newtable(L);
151         for (int y = 0; y != n->sy; y++) {
152                 lua_newtable(L);
153                 for (int x = 0; x != n->sx; x++) {
154                         float noiseval = n->np->offset + n->np->scale * n->result[i++];
155                         lua_pushnumber(L, noiseval);
156                         lua_rawseti(L, -2, x + 1);
157                 }
158                 lua_rawseti(L, -2, y + 1);
159         }
160         return 1;
161 }
162
163 int LuaPerlinNoiseMap::l_get2dMap_flat(lua_State *L)
164 {
165         NO_MAP_LOCK_REQUIRED;
166
167         LuaPerlinNoiseMap *o = checkobject(L, 1);
168         v2f p = read_v2f(L, 2);
169
170         Noise *n = o->noise;
171         n->perlinMap2D(p.X, p.Y);
172
173         int maplen = n->sx * n->sy;
174
175         lua_newtable(L);
176         for (int i = 0; i != maplen; i++) {
177                 float noiseval = n->np->offset + n->np->scale * n->result[i];
178                 lua_pushnumber(L, noiseval);
179                 lua_rawseti(L, -2, i + 1);
180         }
181         return 1;
182 }
183
184 int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
185 {
186         NO_MAP_LOCK_REQUIRED;
187         int i = 0;
188
189         LuaPerlinNoiseMap *o = checkobject(L, 1);
190         v3f p = read_v3f(L, 2);
191
192         Noise *n = o->noise;
193         n->perlinMap3D(p.X, p.Y, p.Z, n->np->eased);
194
195         lua_newtable(L);
196         for (int z = 0; z != n->sz; z++) {
197                 lua_newtable(L);
198                 for (int y = 0; y != n->sy; y++) {
199                         lua_newtable(L);
200                         for (int x = 0; x != n->sx; x++) {
201                                 lua_pushnumber(L, n->np->offset + n->np->scale * n->result[i++]);
202                                 lua_rawseti(L, -2, x + 1);
203                         }
204                         lua_rawseti(L, -2, y + 1);
205                 }
206                 lua_rawseti(L, -2, z + 1);
207         }
208         return 1;
209 }
210
211 int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L)
212 {
213         NO_MAP_LOCK_REQUIRED;
214
215         LuaPerlinNoiseMap *o = checkobject(L, 1);
216         v3f p = read_v3f(L, 2);
217
218         Noise *n = o->noise;
219         n->perlinMap3D(p.X, p.Y, p.Z, n->np->eased);
220
221
222         int maplen = n->sx * n->sy * n->sz;
223
224         lua_newtable(L);
225         for (int i = 0; i != maplen; i++) {
226                 float noiseval = n->np->offset + n->np->scale * n->result[i];
227                 lua_pushnumber(L, noiseval);
228                 lua_rawseti(L, -2, i + 1);
229         }
230         return 1;
231 }
232
233 LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size) {
234         try {
235                 noise = new Noise(np, seed, size.X, size.Y, size.Z);
236         } catch (InvalidNoiseParamsException &e) {
237                 throw LuaError(e.what());
238         }
239 }
240
241 LuaPerlinNoiseMap::~LuaPerlinNoiseMap()
242 {
243         delete noise->np;
244         delete noise;
245 }
246
247 // LuaPerlinNoiseMap(np, size)
248 // Creates an LuaPerlinNoiseMap and leaves it on top of stack
249 int LuaPerlinNoiseMap::create_object(lua_State *L)
250 {
251         NoiseParams *np = read_noiseparams(L, 1);
252         if (!np)
253                 return 0;
254         v3s16 size = read_v3s16(L, 2);
255
256         LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(np, 0, size);
257         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
258         luaL_getmetatable(L, className);
259         lua_setmetatable(L, -2);
260         return 1;
261 }
262
263 LuaPerlinNoiseMap* LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
264 {
265         luaL_checktype(L, narg, LUA_TUSERDATA);
266
267         void *ud = luaL_checkudata(L, narg, className);
268         if (!ud)
269                 luaL_typerror(L, narg, className);
270
271         return *(LuaPerlinNoiseMap **)ud;  // unbox pointer
272 }
273
274 void LuaPerlinNoiseMap::Register(lua_State *L)
275 {
276         lua_newtable(L);
277         int methodtable = lua_gettop(L);
278         luaL_newmetatable(L, className);
279         int metatable = lua_gettop(L);
280
281         lua_pushliteral(L, "__metatable");
282         lua_pushvalue(L, methodtable);
283         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
284
285         lua_pushliteral(L, "__index");
286         lua_pushvalue(L, methodtable);
287         lua_settable(L, metatable);
288
289         lua_pushliteral(L, "__gc");
290         lua_pushcfunction(L, gc_object);
291         lua_settable(L, metatable);
292
293         lua_pop(L, 1);  // drop metatable
294
295         luaL_openlib(L, 0, methods, 0);  // fill methodtable
296         lua_pop(L, 1);  // drop methodtable
297
298         // Can be created from Lua (PerlinNoiseMap(np, size)
299         lua_register(L, className, create_object);
300 }
301
302 const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
303 const luaL_reg LuaPerlinNoiseMap::methods[] = {
304         luamethod(LuaPerlinNoiseMap, get2dMap),
305         luamethod(LuaPerlinNoiseMap, get2dMap_flat),
306         luamethod(LuaPerlinNoiseMap, get3dMap),
307         luamethod(LuaPerlinNoiseMap, get3dMap_flat),
308         {0,0}
309 };
310
311 /*
312         LuaPseudoRandom
313 */
314
315 // garbage collector
316 int LuaPseudoRandom::gc_object(lua_State *L)
317 {
318         LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
319         delete o;
320         return 0;
321 }
322
323 // next(self, min=0, max=32767) -> get next value
324 int LuaPseudoRandom::l_next(lua_State *L)
325 {
326         NO_MAP_LOCK_REQUIRED;
327         LuaPseudoRandom *o = checkobject(L, 1);
328         int min = 0;
329         int max = 32767;
330         lua_settop(L, 3); // Fill 2 and 3 with nil if they don't exist
331         if(!lua_isnil(L, 2))
332                 min = luaL_checkinteger(L, 2);
333         if(!lua_isnil(L, 3))
334                 max = luaL_checkinteger(L, 3);
335         if(max < min){
336                 errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
337                 throw LuaError("PseudoRandom.next(): max < min");
338         }
339         if(max - min != 32767 && max - min > 32767/5)
340                 throw LuaError("PseudoRandom.next() max-min is not 32767"
341                                 " and is > 32768/5. This is disallowed due to"
342                                 " the bad random distribution the"
343                                 " implementation would otherwise make.");
344         PseudoRandom &pseudo = o->m_pseudo;
345         int val = pseudo.next();
346         val = (val % (max-min+1)) + min;
347         lua_pushinteger(L, val);
348         return 1;
349 }
350
351
352 LuaPseudoRandom::LuaPseudoRandom(int seed):
353         m_pseudo(seed)
354 {
355 }
356
357 LuaPseudoRandom::~LuaPseudoRandom()
358 {
359 }
360
361 const PseudoRandom& LuaPseudoRandom::getItem() const
362 {
363         return m_pseudo;
364 }
365 PseudoRandom& LuaPseudoRandom::getItem()
366 {
367         return m_pseudo;
368 }
369
370 // LuaPseudoRandom(seed)
371 // Creates an LuaPseudoRandom and leaves it on top of stack
372 int LuaPseudoRandom::create_object(lua_State *L)
373 {
374         int seed = luaL_checknumber(L, 1);
375         LuaPseudoRandom *o = new LuaPseudoRandom(seed);
376         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
377         luaL_getmetatable(L, className);
378         lua_setmetatable(L, -2);
379         return 1;
380 }
381
382 LuaPseudoRandom* LuaPseudoRandom::checkobject(lua_State *L, int narg)
383 {
384         luaL_checktype(L, narg, LUA_TUSERDATA);
385         void *ud = luaL_checkudata(L, narg, className);
386         if(!ud) luaL_typerror(L, narg, className);
387         return *(LuaPseudoRandom**)ud;  // unbox pointer
388 }
389
390 void LuaPseudoRandom::Register(lua_State *L)
391 {
392         lua_newtable(L);
393         int methodtable = lua_gettop(L);
394         luaL_newmetatable(L, className);
395         int metatable = lua_gettop(L);
396
397         lua_pushliteral(L, "__metatable");
398         lua_pushvalue(L, methodtable);
399         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
400
401         lua_pushliteral(L, "__index");
402         lua_pushvalue(L, methodtable);
403         lua_settable(L, metatable);
404
405         lua_pushliteral(L, "__gc");
406         lua_pushcfunction(L, gc_object);
407         lua_settable(L, metatable);
408
409         lua_pop(L, 1);  // drop metatable
410
411         luaL_openlib(L, 0, methods, 0);  // fill methodtable
412         lua_pop(L, 1);  // drop methodtable
413
414         // Can be created from Lua (LuaPseudoRandom(seed))
415         lua_register(L, className, create_object);
416 }
417
418 const char LuaPseudoRandom::className[] = "PseudoRandom";
419 const luaL_reg LuaPseudoRandom::methods[] = {
420         luamethod(LuaPseudoRandom, next),
421         {0,0}
422 };