Jump to content

Module:ShapeViewer/Core

From shapez Wiki

Documentation for this module may be created at Module:ShapeViewer/Core/doc

local p = {}

local colors = {
    r = "#ff666a",
    g = "#78ff66",
    b = "#66a7ff",
    y = "#fcf52a",
    m = "#f066f0",
    p = "#dd66ff",
    c = "#87fff5",
    w = "#ffffff",
    u = "#aaaaaa",
}

local function rotate(x, y, rot)
    if rot == 0 then
        return x, y
    end

    if rot == 1 then
        return -y, x
    end

    if rot == 2 then
        return -x, -y
    end

    if rot == 3 then
        return y, -x
    end
end

local function point(x, y, rotation, scale)
    local tx, ty = rotate(x * scale, y * scale, rotation)
    return tostring(tx) .. " " .. tostring(ty) .. " "
end

local paths = {}

function paths.C(rotation, scale)
    return "M 14 14 l"
        .. point(0, -10, rotation, scale)
        .. "a" .. point(10, 10, 0, scale)
        .. "0 0 1 "
        .. point(10, 10, rotation, scale)
        .. "z"
end

function paths.R(rotation, scale)
    return "M 14 14 l"
        .. point(0, -10, rotation, scale)
        .. point(10, 0, rotation, scale)
        .. point(0, 10, rotation, scale)
        .. "z"
end

function paths.S(rotation, scale)
    return "M 14 14 l"
        .. point(0, -6, rotation, scale)
        .. point(10, -4, rotation, scale)
        .. point(-4, 10, rotation, scale)
        .. "z"
end

function paths.W(rotation, scale)
    return "M 14 14 l"
        .. point(0, -6, rotation, scale)
        .. point(10, -4, rotation, scale)
        .. point(0, 10, rotation, scale)
        .. "z"
end

local function isempty(subshape, color)
    local part = subshape .. color

    if subshape ~= "-" and color == "-" then
        error("missing color in part " .. part)
    end

    if subshape == "-" and color ~= "-" then
        error("missing subshape in part " .. part)
    end

    return part == "--"
end

local function generatelayer(code, scale, index)
    if #code ~= 8 then
        error("invalid layer length " .. index)
    end

    if code == "--------" then
        error("empty layer " .. index)
    end

    local parts = {}

    for i = 1, #code, 2 do
        local subshape = string.sub(code, i, i)
        local color = string.sub(code, i + 1, i + 1)

        if not isempty(subshape, color) then
            local generatepath = paths[subshape]
            local fill = colors[color]
    
            if not generatepath then
                error("unknown subshape " .. subshape)
            end
    
            if not fill then
                error("unknown color " .. color)
            end
    
            local d = generatepath((i - 1) / 2, scale)
            local path = ([[<path d="%s" fill="%s" />]]):format(d, fill)
            table.insert(parts, path)
        end
    end

    return table.concat(parts)
end

function p.generate(code, size, shadow)	
    -- Vanilla leaves some blank space, cut it off
    local margin = shadow and 2.5 or 4
    local viewbox = 28 - margin * 2

    local svg = string.format(
        [[
        <svg
            class="shapez-shape"
            width="%d"
            height="%d"
            viewBox="%f %f %f %f"
            stroke="#555">
        ]],
        size,
        size,
        margin,
        margin,
        viewbox,
        viewbox)

    if shadow then
        svg = svg .. [[
        <circle cx="14" cy="14" r="11.5"
            fill="rgba(40, 50, 65, 0.1)"
            stroke="none" />
        ]]
    end

    local currentlayer = 0
    for layer in string.gmatch(code, "[^:]+") do
        currentlayer = currentlayer + 1

        if currentlayer == 5 then
            error("too many layers")
        end

        -- Adjusted for index starting from 1
        local scale = 1.12 - 0.22 * currentlayer
        svg = svg .. generatelayer(layer, scale, currentlayer)
    end

    return svg .. "</svg>"
end

return p