-- Converts a number to a zero-padded binary string.
function tobin(number, bits)
    local binary = ""
    repeat
        local remainder = number % 2
        binary = tostring(remainder) .. binary
        number = math.floor(number / 2)
    until number == 0

    local paddedBinary = binary
    if #binary < bits then
        paddedBinary = string.rep("0", bits - #binary) .. binary
    end

    return paddedBinary
end

-- Calls map_callback(x, y, z) on every voxel from 'vsp', then returns a new
-- sprite of the same size, where the voxel is placed at the returned (x, y, z).
function remap_voxel_positions(vsp, map_callback)
    local xsize, ysize, zsize = vsp_get_size(vsp);
    local new_vsp = vsp_new(xsize, ysize, zsize)

    for z = 0, (zsize - 1) do
        for y = 0, (ysize - 1) do
            for x = 0, (xsize - 1) do
                local voxel = vsp_get_voxel(vsp, x, y, z);
                local dx, dy, dz = map_callback(x, y, z);

                vsp_set_voxel(new_vsp, dx, dy, dz, voxel);
            end
        end
    end

    return new_vsp
end