
function calcYDimension(func, sizeX, sizeZ, maxY)
	if maxY == nil then
		if sizeX > sizeZ then
			maxY = sizeX * 4
		else
			maxY = sizeZ * 4
		end
	end
	local max = 0
	local i, j
	for i = 1,sizeX do
		for j = 1,sizeZ do
			local y = func(i, j)
			if y ~= nil and y > max then
				if y > maxY then
					max = maxY
				else
					max = y
				end
			end
		end
	end
	return max + 1
end

function round(n)
	return math.floor(n + 0.499)
end

function checkSteps(startX, endX, startZ, endZ, y, func, step)
	local x = startX
	while x <= endX do
		local z = startZ
		while z <= endZ do
			local funcYVal = func(x, z)
			if funcYVal ~= nil then
				if round(funcYVal) == y then return true end
			end
			z = z + step
		end
		x = x + step
	end
	return false
end

function surfaceGetBlockAt(x, y, z, func, step, startX, startZ, endX, endZ)
	local funcYVal, funcMat = func(x, z)
	if funcYVal == nil then return nil end
	if funcMat == nil then funcMat = 1 end
	if round(funcYVal) == y then return funcMat end
	local stepStartX, stepStartZ = x - 0.5, z - 0.5
	local stepEndX, stepEndZ = x + 0.5, z + 0.5
	if stepStartX < startX then stepStartX = startX end
	if stepStartZ < startZ then stepStartZ = startZ end
	if stepEndX > endX then stepEndX = endX end
	if stepEndZ > endZ then stepEndZ = endZ end
	if checkSteps(stepStartX, stepEndX, stepStartZ, stepEndZ, y, func, step) then
		return funcMat
	end
	return nil
end

function prov(sizeX, sizeZ, getYFunc, numMaterials, fillMode, maxY)
	if numMaterials == nil then numMaterials = 1 end
	local sizeY = calcYDimension(getYFunc, sizeX, sizeZ, maxY)
	local provGetBlockAt = function(x, y, z)
		local mat = surfaceGetBlockAt(x, y, z, getYFunc, 0.125, 0, 0, sizeX - 1, sizeZ - 1)
		return mat
	end
	local provider = {
		["sizeX"] = sizeX,
		["sizeY"] = sizeY,
		["sizeZ"] = sizeZ,
		["numMaterials"] = numMaterials,
		["getBlockAt"] = provGetBlockAt
	}
	return provider
end





