local function huh(a, b)
	return a.x * b.y - a.y * b.x
end

local function render_edge(mode, anchors, normals, s, len_s, ns, q, r, half_width)
	if mode == "none" then
		list.insert(anchors, q)
		list.insert(anchors, q)
		list.insert(normals, ns)
		list.insert(normals, -ns)
		s = (r - q)
		len_s = s:GetLength()
		ns = s:GetNormal(half_width / len_s)
		list.insert(anchors, q)
		list.insert(anchors, q)
		list.insert(normals, -ns)
		list.insert(normals, ns)
	elseif mode == "miter" then
		local t = r - q
		local len_t = t:GetLength()
		local nt = t:GetNormal(half_width / len_t)
		list.insert(anchors, q)
		list.insert(anchors, q)
		local det = huh(s, t)

		if math.abs(det) / (len_s * len_t) < 0.05 and (s * t):GetLength() > 0 then
			list.insert(normals, ns)
			list.insert(normals, -ns)
		else
			local lambda = huh(nt - ns, t) / det

			if not math.isvalid(lambda) then lambda = 0 end -- not really sure why this is needed
			local d = ns + s * lambda
			list.insert(normals, d)
			list.insert(normals, -d)
		end

		s = t
		ns = nt
		len_s = len_t
	elseif mode == "bevel" then
		local t = r - q
		local len_t = t:GetLength()
		local det = huh(s, t)

		if math.abs(det) / (len_s * len_t) < 0.05 and (s * t):GetLength() > 0 then
			local n = t:GetNormal(half_width / len_t)
			list.insert(anchors, q)
			list.insert(anchors, q)
			list.insert(normals, n)
			list.insert(normals, -n)
			s = t
			len_s = len_t
			return s, len_s, ns
		end

		local nt = t:GetNormal(half_width / len_t)
		local lambda = huh(nt - ns, t) / det

		if not math.isvalid(lambda) then lambda = 0 end -- not really sure why this is needed
		local d = ns + s * lambda
		list.insert(anchors, q)
		list.insert(anchors, q)
		list.insert(anchors, q)
		list.insert(anchors, q)

		if det > 0 then
			list.insert(normals, d)
			list.insert(normals, -ns)
			list.insert(normals, d)
			list.insert(normals, -nt)
		else
			list.insert(normals, ns)
			list.insert(normals, -d)
			list.insert(normals, nt)
			list.insert(normals, -d)
		end

		s = t
		len_s = len_t
		ns = nt
	end

	return s, len_s, ns
end

local function render(mode, coords, count, size_hint, half_width, pixel_size, draw_overdraw, draw_mode)
	local overdraw_vertex_count = 0
	local overdraw_vertex_start = 0
	local anchors = table.new(size_hint, 1)
	local normals = table.new(size_hint, 1)

	if draw_overdraw then half_width = half_width - pixel_size * 0.3 end

	local is_looping = (coords[1] == coords[count - 1]) and (coords[2] == coords[count])
	local s

	if not is_looping then
		s = Vec2(coords[3] - coords[1], coords[4] - coords[2])
	else
		s = Vec2(coords[1] - coords[count - 3], coords[1] - coords[count - 2])
	end

	local len_s = s:GetLength()
	local ns = s:GetNormal(half_width / len_s)
	local q
	local r = Vec2(coords[1], coords[2])

	for i = 0, count - 4, 2 do
		q = r
		r = Vec2(coords[i + 3], coords[i + 4])
		s, len_s, ns = render_edge(mode, anchors, normals, s, len_s, ns, q, r, half_width)
	end

	q = r
	r = is_looping and Vec2(coords[3], coords[4]) or r + s
	s, len_s, ns = render_edge(mode, anchors, normals, s, len_s, ns, q, r, half_width)
	local vertex_count = #normals
	local extra_vertices = 0

	if draw_overdraw then
		--calc_overdraw_vertex_count(is_looping)
		if mode == "none" then
			overdraw_vertex_count = 4 * vertex_count - 2
		else
			overdraw_vertex_count = 2 * vertex_count + (is_looping and 0 or 2)
		end

		if draw_mode == "triangle_strip" then extra_vertices = 2 end
	end

	local vertices = {}

	for i = 1, vertex_count do
		vertices[i] = anchors[i] + normals[i]
	end

	if draw_overdraw then
		local overdraw = vertices --- + vertex_count + extra_vertices
		overdraw_vertex_start = vertex_count + extra_vertices

		if mode == "none" then
			for i = 2, vertex_count + 3 - 1, 4 do
				local s = vertices[i + 1] - vertices[i + 3 + 1]
				local t = vertices[i + 1] - vertices[i + 1 + 1]
				s:Normalize(pixel_size)
				t:Normalize(pixel_size)
				local k = 4 * (-2)
				k = k + overdraw_vertex_start
				k = k + 1
				i = i + 1
				overdraw[k] = vertices[i]
				overdraw[k + 1] = vertices[i] + s + t
				overdraw[k + 2] = vertices[i + 1] + s - t
				overdraw[k + 3] = vertices[i + 1]
				overdraw[k + 4] = vertices[i + 1]
				overdraw[k + 5] = vertices[i + 1] + s - t
				overdraw[k + 6] = vertices[i + 2] - s - t
				overdraw[k + 7] = vertices[i + 2]
				overdraw[k + 8] = vertices[i + 2]
				overdraw[k + 9] = vertices[i + 2] - s - t
				overdraw[k + 10] = vertices[i + 3] - s + t
				overdraw[k + 11] = vertices[i + 3]
				overdraw[k + 12] = vertices[i + 3]
				overdraw[k + 13] = vertices[i + 3] - s + t
				overdraw[k + 14] = vertices[i] + s + t
				overdraw[k + 15] = vertices[i]
			end
		else
			for i = 0, vertex_count - 1 - 1, 2 do
				overdraw[overdraw_vertex_start + i + 1] = vertices[i + 1]
				overdraw[overdraw_vertex_start + i + 1 + 1] = vertices[i + 1] + normals[i + 1] * (pixel_size / normals[i + 1]:GetLength())
			end

			for i = 0, vertex_count - 1 - 1, 2 do
				local k = vertex_count - i - 1
				overdraw[overdraw_vertex_start + vertex_count + i + 1] = vertices[k]
				overdraw[overdraw_vertex_start + vertex_count + i + 1 + 1] = vertices[k + 1] + normals[k + 1] * (pixel_size / normals[i + 1]:GetLength())
			end

			if not is_looping then
				local spacer = (overdraw[overdraw_vertex_start + 1 + 1] - overdraw[overdraw_vertex_start + 3 + 1])
				spacer:Normalize(pixel_size)
				overdraw[overdraw_vertex_start + 1 + 1] = overdraw[overdraw_vertex_start + 1 + 1] + spacer
				spacer = (
						overdraw[overdraw_vertex_start + vertex_count - 1] - overdraw[overdraw_vertex_start + vertex_count - 3]
					)
				spacer:Normalize(pixel_size)
				overdraw[overdraw_vertex_start + vertex_count - 1 + 1] = overdraw[overdraw_vertex_start + vertex_count - 1 + 1] + spacer
				overdraw[overdraw_vertex_start + vertex_count + 1 + 1] = overdraw[overdraw_vertex_start + vertex_count + 1 + 1] + spacer
				overdraw[overdraw_vertex_start + overdraw_vertex_count - 2 + 1] = overdraw[overdraw_vertex_start + 0 + 1]
				overdraw[overdraw_vertex_start + overdraw_vertex_count - 1 + 1] = overdraw[overdraw_vertex_start + 1 + 1]
			end
		end
	end

	if extra_vertices ~= 0 then
		vertices[vertex_count + 0 + 1] = vertices[vertex_count - 1 + 1]
		vertices[vertex_count + 1 + 1] = vertices[overdraw_vertex_start + 1]
	end

	return vertices, overdraw_vertex_start + overdraw_vertex_count
end

local function draw_line(mode, coords, width, pixel_size, draw_overdraw)
	width = width * 0.5
	local draw_mode

	if mode == "none" then
		draw_mode = "triangles"
	else
		draw_mode = "triangle_strip"
	end

	local count = #coords

	if mode == "miter" then
		return render(mode, coords, count, count, width, pixel_size, draw_overdraw, draw_mode),
		nil,
		draw_mode
	elseif mode == "bevel" then
		return render(mode, coords, count, 2 * count - 4, width, pixel_size, draw_overdraw, draw_mode),
		nil,
		draw_mode
	elseif mode == "none" then
		local vertices, overdraw_count = render(mode, coords, count, 2 * count - 4, width, pixel_size, draw_overdraw, draw_mode)

		for i = 0, #vertices - 4 - 1 do
			vertices[i + 1] = vertices[i + 2 + 1]
		end

		list.remove(vertices, #vertices)
		local total_vertex_count = #vertices

		if draw_overdraw then total_vertex_count = overdraw_count end

		local num_indices = (total_vertex_count / 4) * 6
		local indices = {}

		for i = 0, (num_indices / 6) - 1 do
			indices[(i * 6 + 0) + 1] = i * 4 + 0
			indices[(i * 6 + 1) + 1] = i * 4 + 1
			indices[(i * 6 + 2) + 1] = i * 4 + 2
			indices[(i * 6 + 3) + 1] = i * 4 + 0
			indices[(i * 6 + 4) + 1] = i * 4 + 2
			indices[(i * 6 + 5) + 1] = i * 4 + 3
		end

		return vertices, indices, draw_mode
	end
end

local function to_render2d_mesh(points)
	local temp = {}

	for i, v in ipairs(points) do
		temp[i] = {pos = v, color = Color(1, 1, 1, 0.5)}
	end

	return temp
end

local dynamic = false
local mesh

function goluwa.PreDrawGUI()
	local coords = {200, 50, 400, 50, 500, 300, 100, 300, 200, 50}
	local vertices, indices, mode = draw_line("none", coords, 50, 1)
	mesh = mesh or
		dynamic and
		render2d.CreateMesh(100)
		or
		render2d.CreateMesh(to_render2d_mesh(vertices))
	mesh:SetMode(mode)

	if dynamic then
		for i, v in ipairs(vertices) do
			mesh.Vertices.Pointer[i].pos[0] = v.x
			mesh.Vertices.Pointer[i].pos[1] = v.y
			mesh.Vertices.Pointer[i].color[0] = 1
			mesh.Vertices.Pointer[i].color[1] = 1
			mesh.Vertices.Pointer[i].color[2] = 1
			mesh.Vertices.Pointer[i].color[3] = 1
		end

		if indices then mesh:SetIndices(Array("uint16_t", #indices, indices)) end

		mesh:UpdateBuffer()
	end

	render2d.SetColor(1, 1, 1, 1)
	render2d.SetTexture()
	render2d.PushMatrix(350, 350, 1, 1)
	mesh:Draw()
	render2d.PopMatrix()
end