local wea_c = worldeditadditions_core local Vector3 = wea_c.Vector3 --- Applies the given brush at the given x/z position to the given heightmap. -- Important: Where a Vector3 is mentioned in the parameter list, it reall MUST -- be a Vector3 instance. -- Also important: Remember that the position there is RELATIVE TO THE HEIGHTMAP'S origin (0, 0) and is on the X and Z axes! -- @param brush table The ZERO-indexed brush to apply. Values should be normalised to be between 0 and 1. -- @param brush_size Vector3 The size of the brush on the x/y axes. -- @pram height number The multiplier to apply to each brush pixel value just before applying it. Negative values are allowed - this will cause a subtraction operation instead of an addition. -- @param position Vector3 The position RELATIVE TO THE HEIGHTMAP on the x/z coordinates to centre the brush application on. -- @param heightmap table The heightmap to apply the brush to. See worldeditadditions.make_heightmap for how to obtain one of these. -- @param heightmap_size Vector3 The size of the aforementioned heightmap. See worldeditadditions.make_heightmap for more information. -- @returns true,number,number|false,string If the operation was not successful, then false followed by an error message as a string is returned. If it was successful however, 3 values are returned: true, then the number of nodes added, then the number of nodes removed. local function apply_heightmap(brush, brush_size, height, position, heightmap, heightmap_size) -- Convert brush_size to match the scheme used in the heightmap brush_size = brush_size:clone() brush_size.z = brush_size.y brush_size.y = 0 local brush_radius = (brush_size/2):ceil() - 1 local pos_start = (position - brush_radius) :clamp(Vector3.new(0, 0, 0), heightmap_size) local pos_end = (pos_start + brush_size) :clamp(Vector3.new(0, 0, 0), heightmap_size) local added = 0 local removed = 0 -- TODO: Make the strength of the brush depend on the height of the nodes in the heightmap? -- Iterate over the heightmap and apply the brush -- Note that we do not iterate over the brush, because we don't know if the -- brush actually fits inside the region.... O.o for z = pos_end.z - 1, pos_start.z, -1 do for x = pos_end.x - 1, pos_start.x, -1 do local hi = z*heightmap_size.x + x local pos_brush = Vector3.new(x, 0, z) - pos_start local bi = pos_brush.z*brush_size.x + pos_brush.x local adjustment = math.floor(brush[bi]*height) if adjustment > 0 then added = added + adjustment elseif adjustment < 0 then removed = removed + math.abs(adjustment) end heightmap[hi] = heightmap[hi] + adjustment end end return true, added, removed end return apply_heightmap