split up terrain blending for individual houses

master
Sokomine 2014-11-13 23:15:57 +01:00
parent 66c25310c4
commit 398f846ff2
3 changed files with 53 additions and 63 deletions

View File

@ -404,7 +404,7 @@ mg_villages.village_area_mark_inside_village_area = function( village_area, vill
local pr = PseudoRandom(mg_villages.get_bseed(minp));
for village_nr, village in ipairs( villages ) do
if( village and village.is_single_house and village.to_add_data and village.to_add_data.bpos and #village.to_add_data.bpos>=1) then
mg_villages.village_area_mark_single_house_area( village_area, minp, maxp, village.to_add_data.bpos[1], pr, village_nr );
mg_villages.village_area_mark_single_house_area( village_area, minp, maxp, village.to_add_data.bpos[1], pr, village_nr, village );
end
end
end

View File

@ -3,7 +3,7 @@
-- it will then calculate the minimum point (xbmin, avsurfy, zbmin) where the house should be spawned
-- and mark a mapchunk-sized 'house area' for terrain blending
mg_villages.village_area_mark_single_house_area = function(village_area, minp, maxp, pos, pr, village_nr)
mg_villages.village_area_mark_single_house_area = function(village_area, minp, maxp, pos, pr, village_nr, village)
local YFLATMIN = 2 -- Lowest flat area height
local FFAPROP = 0.5 -- front flat area proportion of dimension
@ -26,28 +26,6 @@ mg_villages.village_area_mark_single_house_area = function(village_area, minp, m
xdim = pos.bsizex + math.floor(FFAPROP * pos.bsizex)
zdim = pos.bsizez
end
local blenrad = math.floor((math.max(xdim, zdim) + 16) / 2) -- radius of blend area
local blendim = 2 * blenrad + 1 -- blend area dimensions
local blencenx = minp.x + pr:next(blenrad+16, sidelen - blenrad - 1 -16) -- blend area centre point
local blencenz = minp.z + pr:next(blenrad+16, sidelen - blenrad - 1 -16)
local minx = blencenx - math.ceil(xdim / 2) -- minimum point of house plus front flat area
local minz = blencenz - math.ceil(zdim / 2)
local xbmin, zbmin -- house minimum point
if pos.brotate == 2 or pos.brotate == 3 then -- N, E
xbmin = minx
zbmin = minz
elseif pos.brotate == 1 then -- W
xbmin = minx + math.floor(FFAPROP * pos.bsizex)
zbmin = minz
else -- pos.brotate = 2, S
xbmin = minx
zbmin = minz + math.floor(FFAPROP * pos.bsizez)
end
-- CHANGE the position of the house so that it sits where the terrain is blended:
-- *** spawn building at (xbmin, avsurfy, zbmin) after landscaping ***
pos.x = xbmin;
pos.z = zbmin;
-- 2D noise perlinmap
local chulens = {x=sidelen, y=sidelen, z=sidelen}
@ -58,13 +36,13 @@ mg_villages.village_area_mark_single_house_area = function(village_area, minp, m
local ni = 1
-- for z = minp.z, maxp.z do
-- for x = minp.x, maxp.x do -- for each column do
for z = math.max( blencenz - blenrad, minp.z), math.min(blencenz + blenrad, maxp.z), 1 do
for x = math.max( blencenx - blenrad, minp.x), math.min(blencenx + blenrad, maxp.x), 1 do -- for each column do
for z = math.max( village.vz - village.vs, minp.z), math.min(village.vz + village.vs, maxp.z), 1 do
for x = math.max( village.vx - village.vs, minp.x), math.min(village.vx + village.vs, maxp.x), 1 do -- for each column do
local xrm = x - minp.x -- relative to mapchunk minp
local zrm = z - minp.z
local xr = x - blencenx -- relative to blend centre
local zr = z - blencenz
local xr = x - village.vx -- relative to blend centre
local zr = z - village.vz
local xre1 = (zdim / 2) * (xr / zr)
local zre1 = zdim / 2
local xre2 = xdim / 2
@ -73,12 +51,12 @@ mg_villages.village_area_mark_single_house_area = function(village_area, minp, m
local rade2 = math.sqrt(xre2 ^ 2 + zre2 ^ 2)
local flatrad = math.min(rade1, rade2) -- radius at edge of rectangular house flat area
local n_absblend = math.abs(nvals_blend[ni])
local blenradn = blenrad - n_absblend * 2 -- vary blend radius
local blenradn = village.vs - n_absblend * 2 -- vary blend radius
local flatradn = flatrad + n_absblend * 2 -- vary shape of house flat area
local nodrad = math.sqrt(xr ^ 2 + zr ^ 2) -- node radius
if x >= xbmin and x <= xbmin + pos.bsizex -- area reserved for house
and z >= zbmin and z <= zbmin + pos.bsizez then
if x >= pos.x and x <= pos.x + pos.bsizex -- area reserved for house
and z >= pos.z and z <= pos.z + pos.bsizez then
village_area[ x ][ z ] = {village_nr, 4}
elseif nodrad <= flatradn or (xr == 0 and zr == 0) then -- irregular flat area around house
village_area[ x ][ z ] = {village_nr, 1}

View File

@ -682,23 +682,13 @@ end
-- the data structure is like that of a village, except that bpos (=buildings to be placed) is already set;
-- Note: one building per mapchunk is more than enough (else it would look too crowded);
mg_villages.houses_in_one_mapchunk = function( minp, mapchunk_size, villages, vnoise )
local village = {};
local pr = PseudoRandom(mg_villages.get_bseed(minp))
local pr = PseudoRandom(mg_villages.get_bseed(minp))
-- only each mg_villages.INVERSE_HOUSE_DENSITY th mapchunk gets a building
if( pr:next(1,mg_villages.INVERSE_HOUSE_DENSITY) > 1 ) then
return {};
end
-- set random coordinates withhin chunk (but far enough away from the shell so that we don't have to bother about cavegen)
village.vx = pr:next(minp.x, minp.x + mapchunk_size - 1)
village.vz = pr:next(minp.z, minp.z + mapchunk_size - 1)
-- village height will be set to a value fitting the terrain later on
village.vh = 10;
-- this will force re-calculation of height
village.vs = 5;
-- store that this is not a village but a lone house
village.is_single_house = 1;
-- pseudorandom orientation
local orient1 = pr:next(0,3);
@ -707,7 +697,7 @@ mg_villages.houses_in_one_mapchunk = function( minp, mapchunk_size, villages, vn
-- TODO: select only types that exist
-- the village type is "single" here - since not all houses which might fit into a village might do for lone standing houses
-- (i.e. church, forge, wagon, ..)
btype, rotation, bsizex, bsizez, mirror = choose_building_rot({}, pr, orient1, 'single');
local btype, rotation, bsizex, bsizez, mirror = choose_building_rot({}, pr, orient1, 'single');
if( not( bsizex )) then
print('FAILURE to generate a building.');
btype, rotation, bsizex, bsizez, mirror = choose_building_rot({}, pr, orient1, 'lumberjack');
@ -716,36 +706,55 @@ mg_villages.houses_in_one_mapchunk = function( minp, mapchunk_size, villages, vn
if( not( bsizex ) or not(mg_villages.BUILDINGS[ btype ].weight)) then
return {};
end
local village = {};
-- store that this is not a village but a lone house
village.is_single_house = 1;
-- village height will be set to a value fitting the terrain later on
village.vh = 10;
-- this will force re-calculation of height
village.vs = 5;
-- find out the real village type of this house (which is necessary for the replacements);
-- the "single" type only indicates that this building may be used for one-house-villages such as this one
for k,v in pairs( mg_villages.BUILDINGS[ btype ].weight ) do
for k, _ in pairs( mg_villages.BUILDINGS[ btype ].weight ) do
if( k and k ~= 'single' ) then
village.village_type = k;
end
end
-- the flattened area shall extend in front of the building (so that there's room for using the front entrance)
local bx = village.vx;
local bz = village.vz;
if( orient1==0 ) then
bz = bz - math.floor(bsizez/2);
elseif( orient1==1 ) then
bx = bx - math.floor(bsizex/2);
bz = bz - bsizez;
elseif( orient1==2 ) then
bz = bz - math.floor(bsizez/2);
bx = bx - bsizex;
elseif( orient1==3 ) then
bx = bx - math.floor(bsizex/2);
end
-- adjust the size of the flattened area to the building's size
village.vs = pr:next( math.max( 2, math.floor(math.min( bsizex, bsizez )*0.3)), math.min( math.ceil( math.max( bsizex, bsizez )), 25));
-- TODO: if village.is_single_house==1, do another check (based on the houses only)
-- taken from paramats terrain blending code for single houses
local FFAPROP = 0.5 -- front flat area proportion of dimension
local xdim, zdim -- dimensions of house plus front flat area
if rotation == 0 or rotation == 2 then
xdim = bsizex
zdim = bsizez + math.floor(FFAPROP * bsizez)
else
xdim = bsizex + math.floor(FFAPROP * bsizex)
zdim = bsizez
end
local blenrad = math.floor((math.max(xdim, zdim) + 16) / 2) -- radius of blend area
local blencenx = pr:next(minp.x + blenrad, minp.x + mapchunk_size - blenrad - 1) -- blend area centre point
local blencenz = pr:next(minp.z + blenrad, minp.z + mapchunk_size - blenrad - 1)
local minx = blencenx - math.ceil(xdim / 2) -- minimum point of house plus front flat area
local minz = blencenz - math.ceil(zdim / 2)
local bx, bz -- house minimum point
if rotation == 2 or rotation == 3 then -- N, E
bx = minx
bz = minz
elseif rotation == 1 then -- W
bx = minx + math.floor(FFAPROP * bsizex)
bz = minz
else -- rotation = 2, S
bx = minx
bz = minz + math.floor(FFAPROP * bsizez)
end
-- now check if this village can be placed here or if it intersects with another village in any critical manner;
-- the village area may intersect (=unproblematic; may even look nice), but the actual building must not be inside another village
for i,v in ipairs(villages) do
for _,v in ipairs(villages) do
-- abort if the new building can't be placed here
if( mg_villages.inside_village_area(bx, bz, v, vnoise)
or mg_villages.inside_village_area(bx+bsizex, bz, v, vnoise)
@ -755,6 +764,9 @@ mg_villages.houses_in_one_mapchunk = function( minp, mapchunk_size, villages, vn
end
end
village.vx = blencenx;
village.vz = blencenz;
village.vs = blenrad;
local village_id = tostring( village.vx )..':'..tostring( village.vz );
-- these values have to be determined once per village; afterwards, they need to be fixed
if( mg_villages.all_villages and mg_villages.all_villages[ village_id ] and mg_villages.all_villages[ village_id ].optimal_height) then