From a6db0b24b4aaa82460cbc288853ede85bff4857d Mon Sep 17 00:00:00 2001 From: Bob Omb Date: Sun, 22 Nov 2015 14:24:49 -0800 Subject: [PATCH] validation --- README.md | 1 + init.lua | 174 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 124 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 34d4b36..1bcb15d 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ Using a graphics editor that doesn't do anti-aliasing and preserves exact red ch - added some more raster modes, raster symbology nicer and fills in below steep areas - performance improvements where empty mapchunks are not processed - experimental code for using imagemagick / graphicsmagick command line interface to reduce dependencies (commented out) +- some improvements to form validation, in-game raster selection doesn't require a restart #### 0.0.5 - improved raster modes symbology and added "aspect" diff --git a/init.lua b/init.lua index f99090d..a021d29 100644 --- a/init.lua +++ b/init.lua @@ -46,7 +46,7 @@ realterrain.settings.dembits = 8 --@todo remove this setting when magick autodet realterrain.settings.filebiome = 'demo/biomes.tif' realterrain.settings.biomebits = 8 --@todo remove this setting when magick autodetects bitdepth -realterrain.settings.filedist = '' +realterrain.settings.fileinput = '' realterrain.settings.dist_lim = 30 --default biome (no biome) @@ -318,49 +318,76 @@ end -- SELECT the mechanism for loading the image which is later uesed by get_pixel() --@todo throw warning if image sizes do not match the dem size - -local width, height, dem, lclu, distimage - -if py then +realterrain.dem = {} +realterrain.cover = {} +realterrain.input = {} +function realterrain.init() + --[[ py.execute("import Image") py.execute("dem = Image.open('"..RASTERS..realterrain.settings.filedem.."')") - py.execute("lclu = Image.open('"..RASTERS..realterrain.settings.filebiome.."')") + py.execute("cover = Image.open('"..RASTERS..realterrain.settings.filebiome.."')") local pybits = py.eval("dem.mode") py.execute("w, l = dem.size") - width = tonumber(tostring(py.eval("w"))) - length = tonumber(tostring(py.eval("l"))) + realterrain.dem.width = tonumber(tostring(py.eval("w"))) + realterrain.dem.length = tonumber(tostring(py.eval("l"))) print("[PYTHON] mode: "..pybits..", width: "..width..", length: "..length) -else + --]] local imageload if magick then imageload = magick.load_image elseif imlib2 then imageload = imlib2.image.load end --@todo fail if there is no DEM? - dem = imageload(RASTERS..realterrain.settings.filedem) + realterrain.dem.image = imageload(RASTERS..realterrain.settings.filedem) --local dem = magick.load_image(RASTERS..realterrain.settings.filedem) - if dem then - width = dem:get_width() - length = dem:get_height() + if realterrain.dem.image then + realterrain.dem.width = realterrain.dem.image:get_width() + realterrain.dem.length = realterrain.dem.image:get_height() --local depth = dem:get_depth()-- @todo need to find correct syntax for this --print("depth: "..depth) --print("width: "..width..", height: "..length) else error(RASTERS..realterrain.settings.filedem.." does not appear to be an image file. your image may need to be renamed, or you may need to manually edit the realterrain.settings file in the world folder") end - lclu = imageload(RASTERS..realterrain.settings.filebiome) - --print(dump(realterrain.get_unique_values(lclu))) - distimage = imageload(RASTERS..realterrain.settings.filedist) --@todo should only load if mode == distance + realterrain.cover.image = imageload(RASTERS..realterrain.settings.filebiome) + --print(dump(realterrain.get_unique_values(cover))) + realterrain.input.image = imageload(RASTERS..realterrain.settings.fileinput) --@todo should only load if mode == distance end --- Set mapgen parameters + + + realterrain.surface_cache = {} --used to prevent reading of DEM for skyblocks +-- Set mapgen parameters minetest.register_on_mapgen_init(function(mgparams) minetest.set_mapgen_params({mgname="singlenode", flags="nolight"}) end) +--[[ +realterrain.genlock = false +minetest.register_globalstep(function(dtime) + if not realterrain.genlock then + realterrain.genlock = true + local c_grass = minetest.get_content_id("default:dirt_with_grass") + local vm = minetest.get_voxel_manip() + local emin, emax = vm:read_from_map({x=0,y=minelev,z=-length},{x=width,y=maxelev,z=0}) + print("emin: "..emin.x..","..emin.y..","..emin.z..", emax: "..emax.x..","..emax.y..","..emax.z) + vm = nil + for z=emin.z, emax.z, 80 do + for y=emin.y, emax.y, 80 do + for x=emin.x, emax.x, 80 do + realterrain.generate({x=x,y=y,z=z}, {x=x+79,y=y+79,z=z+79}) + end + end + end + --realterrain.genlock = false + end +end)--]] -- On generated function minetest.register_on_generated(function(minp, maxp, seed) + realterrain.generate(minp, maxp) +end) +function realterrain.generate(minp, maxp) local t0 = os.clock() local x1 = maxp.x local y1 = maxp.y @@ -679,7 +706,7 @@ minetest.register_on_generated(function(minp, maxp, seed) elseif distance < 42 then color = "slope9" elseif distance >= 42 then color = "slope10" end --print("distance: "..distance) - data[vi] = cids[color] get_chunk_pixels(xmin, zmax) + data[vi] = cids[color] end local height = realterrain.fill_below(x,z,heightmap) if height > 0 then @@ -716,25 +743,23 @@ minetest.register_on_generated(function(minp, maxp, seed) local chugent = math.ceil((os.clock() - t0) * 1000) print ("[GEN] "..chugent.." ms mapchunk ("..cx0..", "..cy0..", "..cz0..")") -end) - +end --the raw get pixel method that uses the selected method and accounts for bit depth function realterrain.get_raw_pixel(x,z, raster) -- "image" is a string for python and an image object for magick / imlib2 local v - if py then --images for py need to be greyscale + --[[py then --images for py need to be greyscale v = py.eval(raster..".getpixel(("..x..","..z.."))") --no bit depth conversion required v = tonumber(tostring(v)) --print(e) - else - if raster == "dem" then raster = dem - elseif raster == "lclu" then raster = lclu - elseif raster == "distance" then raster = distimage - end - if magick then - v = math.floor(raster:get_pixel(x, z) * (2^tonumber(realterrain.settings.dembits))) --@todo change when magick autodetects bit depth - elseif imlib2 then - v = raster:get_pixel(x, z).red - end + --]] + if raster == "dem" then raster = realterrain.dem.image + elseif raster == "cover" then raster = realterrain.cover.image + elseif raster == "input" then raster = realterrain.input.image + end + if magick then + v = math.floor(raster:get_pixel(x, z) * (2^tonumber(realterrain.settings.dembits))) --@todo change when magick autodetects bit depth + elseif imlib2 then + v = raster:get_pixel(x, z).red end return v end @@ -748,7 +773,7 @@ function realterrain.get_pixel(x,z, elev_only) col = math.floor(col / tonumber(realterrain.settings.xscale)) --off the dem return false - if ((col < 0) or (col > width) or (row < 0) or (row > length)) then return false end + if ((col < 0) or (col > realterrain.dem.width) or (row < 0) or (row > realterrain.dem.length)) then return false end e = realterrain.get_raw_pixel(col,row, "dem") or 0 --print("raw e: "..e) @@ -758,7 +783,7 @@ function realterrain.get_pixel(x,z, elev_only) if elev_only then return e else - b = realterrain.get_raw_pixel(col,row, "lclu") or 0 + b = realterrain.get_raw_pixel(col,row, "cover") or 0 end @@ -766,7 +791,7 @@ function realterrain.get_pixel(x,z, elev_only) return e, b end --experimental function to enumerate 80x80 crop of raster at once using IM or GM -function realterrain.get_chunk_pixels(xmin, zmax) +--[[function realterrain.get_chunk_pixels(xmin, zmax) local pixels = {} --local firstline = true -- only IM has a firstline --local multiplier = false --only needed with IM 16-bit depth, not with 8-bit and not with GM! @@ -781,10 +806,10 @@ function realterrain.get_chunk_pixels(xmin, zmax) for line in io.popen(cmd):lines() do --print(line) --with IM first line contains the bit depth, parse that first - --[[if firstline then + --if firstline then --extract the multiplier for IM 16-bit depth - firstline = false - end--]] + --firstline = false + end --parse the output pixels local firstcomma = string.find(line, ",") @@ -804,7 +829,7 @@ function realterrain.get_chunk_pixels(xmin, zmax) pixels[z][x] = {elev=e} end return pixels -end +end--]] --this funcion gets the hieght needed to fill below a node for surface-only modes function realterrain.fill_below(x,z,heightmap) @@ -826,7 +851,29 @@ function realterrain.fill_below(x,z,heightmap) --print(height) return height end - +--[[function realterrain.get_elev_range() + print("calculating min and max elevation...") + local minelev, maxelev + + for z=0, -length, -1 do + for x=0, width-1, 1 do + local elev = realterrain.get_pixel(x,z, true) + if not minelev then + minelev = elev + maxelev = elev + else + if elev < minelev then + minelev = elev + end + if elev > maxelev then + maxelev = elev + end + end + end + end + print("min elev: "..minelev..", maxelev: "..maxelev) + return minelev, maxelev +end--]] function realterrain.get_slope(n, rad) --print(dump(n)) local x_cellsize, z_cellsize = 1, 1 @@ -897,7 +944,7 @@ function realterrain.get_distance(x,y,z) row = math.floor(row / tonumber(realterrain.settings.zscale)) col = math.floor(col / tonumber(realterrain.settings.xscale)) - value = realterrain.get_raw_pixel(col,row, "dem") + value = realterrain.get_raw_pixel(col,row, "input") if value > 0 then table.insert(results, {x=i-x, z=j-z}) end @@ -933,14 +980,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if string.sub(formname, 1, 12) == "realterrain:" then local wait = os.clock() while os.clock() - wait < 0.05 do end --popups don't work without this - --print("fields submitted: "..dump(fields)) + print("fields submitted: "..dump(fields)) local pname = player:get_player_name() - -- always save any form fields - for k,v in next, fields do - realterrain.settings[k] = v --we will preserve field entries exactly as entered - end - realterrain.save_settings() + --the popup form never has settings so process that first if formname == "realterrain:popup" then if fields.exit == "Back" then realterrain.show_rc_form(pname) @@ -948,6 +991,33 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end + --check to make sure that a DEM file is selected, this is essential + if fields.filedem == "" then + realterrain.show_popup(pname,"You MUST have an Elevation (DEM) file!") + return + end + --check to make sure that if "distance mode was selected then an 'input' file is selected + if fields.output == "distance" and realterrain.settings.fileinput == "" then + realterrain.show_popup(pname, "For distance mode you must have an input file selected") + return + end + + --check to see if the source rasters were changed, if so re-initialize + local old_dem, old_cover, old_input + old_dem = realterrain.settings.filedem + old_cover = realterrain.settings.filecover + old_input = realterrain.settings.fileinput + -- otherwise save form fields + for k,v in next, fields do + realterrain.settings[k] = v --we will preserve field entries exactly as entered + end + realterrain.save_settings() + if old_dem ~= realterrain.settings.filedem + or old_cover ~= realterrain.settings.filecover + or old_input ~= realterrain.settings.fileinput then + realterrain.init() + end + --the main form if formname == "realterrain:rc_form" then --actual form submissions @@ -960,7 +1030,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) os.remove(WORLDPATH.."/map.sqlite") return true elseif fields.exit == "Apply" then - minetest.chat_send_player(pname, "You changed the mapgen settings!") + minetest.chat_send_player(pname, "You changed the mapgen settings!") return true elseif fields.exit == "Biomes" then realterrain.show_biome_form(pname) @@ -1063,9 +1133,9 @@ function realterrain.show_rc_form(pname) "label[6,5.5;Raster Mode]".. "dropdown[6,6;4,1;output;normal,surface,slope,aspect,curvature,distance;".. modes[realterrain.settings.output].."]".. - "label[6,7;Distance File]".. - "dropdown[6,7.5;4,1;filedist;"..f_images..";".. - realterrain.get_idx(images, realterrain.get_setting("filedist")) .."]" + "label[6,7;Input File]".. + "dropdown[6,7.5;4,1;fileinput;"..f_images..";".. + realterrain.get_idx(images, realterrain.get_setting("fileinput")) .."]" --Action buttons local f_footer = "label[6,9;After applying, exit world and delete map.sqlite]".. @@ -1151,4 +1221,6 @@ function realterrain.show_popup(pname, message) "label[1,3;"..realterrain.esc(message).."]" ) return true -end \ No newline at end of file +end +realterrain.init() +--minelev, maxelev = realterrain.get_elev_range() \ No newline at end of file