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