-- Common symbology definitions. Used by MFDS, HUD, EWS for RWR screen symbology.

dofile(LockOn_Options.common_script_path.."elements_defs.lua")
dofile(LockOn_Options.script_path.."materials.lua")

local use_mipfilter		= true
local show_masks		= false

-- made by four lines
line_box_indices		= {0, 1, 1, 2, 2, 3, 3, 0}

-- overwrite this value with actual clipping level
DEFAULT_LEVEL			= 9
-- fill this table with font parameters
stringdefs				= {}
-- overwrite these values with actual material names
default_material		= ""
stroke_font				= ""
--
z_disabled				= false


function setPlaceholderCommonProperties(placeholder, name, pos, parent, controllers)
	placeholder.name			= name
	pos							= pos or {0, 0}
	placeholder.init_pos		= {pos[1], pos[2], 0}
	placeholder.collimated		= collimated or false

	if parent ~= nil then
		placeholder.parent_element	= parent
	end	

	if controllers ~= nil then
		placeholder.controllers		= controllers
	end
end

function addPlaceholder(name, pos, parent, controllers)
	local placeholder			= CreateElement "ceSimple"
	setPlaceholderCommonProperties(placeholder, name, pos, parent, controllers)

	Add(placeholder)
	return placeholder
end

function addRotPlaceholder(name, pos, rot, parent, controllers)
	local placeholder			= CreateElement "ceSimple"
	setPlaceholderCommonProperties(placeholder, name, pos, parent, controllers)

	if rot ~= nil then
		placeholder.init_rot	= {rot}
	end

	Add(placeholder)
	return placeholder
end

function setAsInvisibleMask(obj)
	obj.isvisible	= show_masks
	obj.material	= "MASK_MATERIAL_PURPLE"
end

function setClipLevel(obj, level)
	level					= level or 0
	obj.h_clip_relation		= h_clip_relations.COMPARE
	obj.level				= DEFAULT_LEVEL + level
end

-- Local functions

-- NOTE
-- 'pos' is passed as a two-component table - x and y coordinates
function setSymbolCommonProperties(symbol, name, pos, parent, controllers, material)
	symbol.name					= name
	symbol.isdraw				= true
	symbol.material				= material or default_material
	symbol.additive_alpha		= additive_alpha or false
	symbol.collimated			= collimated or false
	symbol.use_mipfilter		= use_mipfilter

	if parent ~= nil then
		symbol.parent_element = parent
	end

	if controllers ~= nil then
		if type(controllers) == "table" then
			symbol.controllers = controllers
		end
	end

	pos							= pos or {0, 0}
	symbol.init_pos				= {pos[1], pos[2], 0}
	
	if z_disabled == true then
		symbol.z_enabled = false
	end

	setClipLevel(symbol)
end

local function setSymbolAlignment(symbol, align)
	if align ~= nil then
		symbol.alignment = align
	else
		symbol.alignment = "CenterCenter"
	end
end

local function setStrokeSymbolProperties(symbol)

	if override_materials == true then
		-- Is used for outlined font generated by DMC
		symbol.thickness			= override_thickness
		symbol.fuzziness			= override_fuzziness
	else
		symbol.thickness			= stroke_thickness
		symbol.fuzziness			= stroke_fuzziness
	end

	symbol.draw_as_wire			= dbg_drawStrokesAsWire
	--symbol.use_specular_pass	= false -- ommitted for now as is set for the entire indicator
end

local function buildStrokeLineVerts(length, dashed, stroke, gap)
	local verts	= {}
	local inds	= {}

	if dashed == true and stroke ~= nil and gap ~= nil then
		local segLength			= stroke + gap
		local numOfWholePairs	= math.floor(length / segLength)
		local reminder			= length - numOfWholePairs * segLength

		local function addSeg(num)
			local shift1 = num * 2
			verts[shift1 + 1] = {0, num * segLength}
			verts[shift1 + 2] = {0, num * segLength + stroke}

			inds[shift1 + 1] = shift1
			inds[shift1 + 2] = shift1 + 1
		end

		for segNum = 0, numOfWholePairs - 1 do
			addSeg(segNum)
		end

		if reminder > 0 then
			if reminder >= stroke then
				addSeg(numOfWholePairs)
			else
				local shift1 = numOfWholePairs * 2
				verts[shift1 + 1] = {0, numOfWholePairs * segLength}
				verts[shift1 + 2] = {0, numOfWholePairs * segLength + reminder}

				inds[shift1 + 1] = shift1
				inds[shift1 + 2] = shift1 + 1
			end
		end
	else
		verts	= {{0, 0}, {0, length}}
		inds	= {0, 1}
	end

	return verts, inds
end


-- Shared functions

function buildBoxVerts(width, height, align)
	align = align or "CenterCenter"

	local w		= width
	local h		= height
	local w05	= w * 0.5
	local h05	= h * 0.5

	local verts = {}

	if align == "CenterCenter" then
		verts =	{ {-w05, -h05}, {-w05,  h05}, { w05,  h05}, { w05, -h05} }
	elseif align == "LeftCenter" then
		verts =	{ { 0, -h05}, { 0,  h05}, { w,  h05}, { w, -h05} }
	elseif align == "RightCenter" then
		verts =	{ {-w, -h05}, {-w,  h05}, { 0,  h05}, { 0, -h05} }
	elseif align == "CenterBottom" then
		verts =	{ {-w05, 0}, {-w05, h}, { w05, h}, { w05, 0} }
	elseif align == "CenterTop" then
		verts =	{ {-w05, -h}, {-w05,  0}, { w05,  0}, { w05, -h} }
	elseif align == "LeftBottom" then
		verts =	{ { 0, 0}, { 0, h}, { w, h}, { w, 0} }
	elseif align == "LeftTop" then
		verts =	{ { 0, -h}, { 0,  0}, { w,  0}, { w, -h} }
	elseif align == "RightTop" then
		verts =	{ {-w, -h}, {-w,  0}, { 0,  0}, { 0, -h} }
	elseif align == "RightBottom" then
		verts =	{ {-w, 0}, {-w, h}, { 0, h}, { 0, 0} }
	end

	return verts
end

-- Triangle like an arrow to UP
function buildTriangleVerts(width, height, align)
	align = align or "CenterCenter"

	local w		= width
	local h		= height
	local w05	= w * 0.5
	local h05	= h * 0.5

	local verts = {}

	if align == "CenterCenter" then
		verts =	{ {-w05,	-h05}, { 0,	 h05}, { w05,	-h05} }
	elseif align == "LeftCenter" then
		verts =	{ { 0,	-h05}, { w05,	 h05}, { w,	-h05} }
	elseif align == "RightCenter" then
		verts =	{ {-w,	-h05}, {-w05,	 h05}, { 0,	-h05} }
	elseif align == "CenterBottom" then
		verts =	{ {-w05,	0}, { 0,	h}, { w05,	0} }
	elseif align == "CenterTop" then
		verts =	{ {-w05,	-h}, { 0,	 0}, { w05,	-h} }
	elseif align == "LeftBottom" then
		verts =	{ { 0,	0}, { w05,	h}, { w,	0} }
	elseif align == "LeftTop" then
		verts =	{ { 0,	-h}, { w05,	 0}, { w,	-h} }
	elseif align == "RightTop" then
		verts =	{ {-w,	-h}, {-w05,	 0}, { 0,	-h} }
	elseif align == "RightBottom" then
		verts =	{ {-w,	0}, {-w05,	h}, { 0,	0} }
	end

	return verts
end
default_triangle_indices = {0, 1, 2}


-- Stroke text with glyphs described in a .svg file
function addStrokeText(name, value, stringdef, align, pos, parent, controllers, formats, font)
	local txt = CreateElement "ceStringSLine"
	setSymbolCommonProperties(txt, name, pos, parent, controllers, font or stroke_font)
	setSymbolAlignment(txt, align)

	-- custom size is noted in documents as in percents from the original one
	if type(stringdef) == "table" then
		txt.stringdefs = stringdef
	else
		txt.stringdefs = stringdefs[stringdef]
	end

	if value ~= nil then
		txt.value = value
	end

	txt.formats		= formats

	Add(txt)
	return txt
end

-- Stroke symbol with points described in a .svg file
function addStrokeSymbol(name, set, align, pos, parent, controllers, scale, material)
	local symbol		= CreateElement "ceSMultiLine"
	setSymbolCommonProperties(symbol, name, pos, parent, controllers, material)
	setSymbolAlignment(symbol, align)
	setStrokeSymbolProperties(symbol)
	symbol.points_set	= set
	symbol.scale		= scale or 1
	Add(symbol)
	return symbol
end

-- Stroke line
-- rot (CCW in degrees from up)
-- pos (position of beginning of the line)
function addStrokeLine(name, length, pos, rot, parent, controllers, dashed, stroke, gap, material)
	local line		= CreateElement "ceSMultiLine"
	setSymbolCommonProperties(line, name, pos, parent, controllers, material)
	setStrokeSymbolProperties(line)

	if rot ~= nil then
		line.init_rot	= {rot}
	end

	local verts, inds = buildStrokeLineVerts(length, dashed, stroke, gap)
	line.vertices	= verts
	line.indices	= inds

	Add(line)
	return line
end

-- Stroke line of variable length
function addVarLenStrokeLine(name, length, pos, rot, parent, controllers, maxLength, dashed, stroke, gap, material)
	local line		= CreateElement "ceSVarLenLine"
	setSymbolCommonProperties(line, name, pos, parent, controllers, material)
	setStrokeSymbolProperties(line)

	if rot ~= nil then
		line.init_rot	= {rot}
	end

	if length ~= nil then
		line.length		= length
	end

	if maxLength == nil then
		maxLength		= 2000	-- DI
	end

	local verts, inds = buildStrokeLineVerts(maxLength, dashed or false, stroke, gap)
	line.vertices		= verts
	line.indices		= inds

	Add(line)
	return line
end

-- Box made of stroke lines
function addStrokeBox(name, sideX, sideY, align, pos, parent, controllers, material)
	local box		= CreateElement "ceSMultiLine"
	setSymbolCommonProperties(box, name, pos, parent, controllers, material)
	setSymbolAlignment(box, align)
	setStrokeSymbolProperties(box)

	local halfSideX	= sideX / 2
	local halfSideY	= sideY / 2
	box.vertices	= {{-halfSideX, -halfSideY}, {-halfSideX, halfSideY}, {halfSideX, halfSideY}, {halfSideX, -halfSideY}}
	box.indices		= line_box_indices

	Add(box)
	return box
end

-- Segmented box made of stroke lines. Use case - HUD segmented TD box /from F-18
--function addStrokeBoxSegmented(name, sideX, sideY, segmentX, segmentY, align, pos, parent, controllers, material)
--end

-- Dashed box made of stroke lines. Align - CenterCenter
function addStrokeBoxDashed(name, sideX, sideY, stroke, gap, pos, parent, controllers, material)
	local root = addPlaceholder(name, pos, parent, controllers)

	addStrokeLine(name.."_left", sideY, {-sideX / 2, -sideY / 2}, 0, root.name, nil, true, stroke, gap, material)
	addStrokeLine(name.."_right", sideY, {sideX / 2, -sideY / 2}, 0, root.name, nil, true, stroke, gap, material)
	addStrokeLine(name.."_top", sideX, {-sideX / 2, sideY / 2}, -90, root.name, nil, true, stroke, gap, material)
	addStrokeLine(name.."_bottom", sideX, {-sideX / 2, -sideY / 2}, -90, root.name, nil, true, stroke, gap, material)
end

-- Equilateral triangle. Center point is at the top end.
-- The element is rotated about its center point by 'rot' angle, and then 'pos_shift' is applied.
--function addStrokeEquilateralTriangle(name, height, angle, pos, rot, pos_shift, parent, controllers, material)
--end

-- Stroke circle
function addStrokeCircle(name, radius, pos, parent, controllers, arc, segment, gap, dashed, material)
	local segmentsN = 64

	local circle			= CreateElement "ceSCircle"
	setSymbolCommonProperties(circle, name, pos, parent, controllers, material)
	setStrokeSymbolProperties(circle)
	circle.radius			= {radius, radius}
	circle.arc				= arc or {0, math.pi * 2}
	circle.segment			= segment or math.pi * 4 / segmentsN
	circle.gap				= gap or math.pi * 4 / segmentsN
	circle.segment_detail	= 4

	if dashed ~= nil then
		circle.dashed		= dashed
	else
		circle.dashed		= false
	end

	Add(circle)
	return circle
end

-- Non-textured mesh, which is drawn by either triangles or by zero-width lines ('primitives' parameter)
function addMesh(name, vertices, indices, pos, primitives, parent, controllers, material)
	local mesh				= CreateElement "ceMeshPoly"
	setSymbolCommonProperties(mesh, name, pos, parent, controllers, material)
	mesh.vertices			= vertices or {}
	mesh.indices			= indices or {}
	mesh.primitivetype		= primitives
	Add(mesh)
	return mesh
end

function addBox(name, width, height, align, pos, parent, controllers, material)
	local box = addMesh(name, buildBoxVerts(width, height, align), default_box_indices, pos, "triangles", parent, controllers, material)
	return box
end

function addMaskedBox(name, width, height, align, pos, rot, parent, controllers, material)
	local box = addBox(name, width, height, align, pos, parent, controllers, material)
	local mask = openMaskArea(0, name.." _opening_mask", box.vertices, box.indices, pos, parent, controllers, nil)

	if rot ~= nil then
		box.init_rot	= {rot}
		mask.init_rot	= {rot}
	end

	return box, mask
end

function addTriangle(name, width, height, align, pos, rot, parent, controllers, material)
	local triangle		= addMesh(name, buildTriangleVerts(width, height, align), default_triangle_indices, pos, "triangles", parent, controllers, material)

	if rot ~= nil then
		triangle.init_rot	= {rot}
	end

	return triangle
end

function addMaskedTriangle(name, width, height, align, pos, rot, parent, controllers, material)
	local triangle	= addTriangle(name, width, height, align, pos, rot, parent, controllers, material)
	local mask		= openMaskArea(0, name.." _opening_mask", triangle.vertices, triangle.indices, pos, parent, controllers, nil)

	if rot ~= nil then
		mask.init_rot	= {rot}
	end

	return triangle, mask
end

function addCircle(name, radius_outer, radius_inner, arc, sides, pos, parent, controllers, material)
	local circle			= CreateElement "ceMeshPoly"
	setSymbolCommonProperties(circle, name, pos, parent, controllers, material)
	set_circle(circle, radius_outer, radius_inner, arc, sides)
	circle.primitivetype	= "triangles"
	Add(circle)
	return circle
end

-- rot (CCW in degrees from up)
-- pos (position of beginning of the line)
function addFatLine(name, length, width, pos, rot, parent, controllers, material)
	local line		= addBox(name, width, length, "CenterBottom", pos, parent, controllers, material)

	if rot ~= nil then
		line.init_rot	= {rot}
	end

	return line
end

function addMaskedFatLine(name, length, width, pos, rot, parent, controllers, material)
	local line	= addFatLine(name, length, width, pos, rot, parent, controllers, material)
	local mask	= openMaskArea(0, name.." _opening_mask", line.vertices, line.indices, pos, parent, controllers, nil)

	if rot ~= nil then
		mask.init_rot	= {rot}
	end

	return line, mask
end

-- rot (CCW in degrees from up)
-- pos (position of beginning of the line)
function addFatDashedLine(name, length, stroke, gap, width, pos, rot, parent, controllers, material)
	local segLength			= stroke + gap
	local numOfWholePairs	= math.floor(length / segLength)
	local reminder			= length - numOfWholePairs * segLength

	rot = rot or 0

	local rot_rad			= math.rad(rot)
	local dx				= -segLength * math.sin(rot_rad)
	local dy				=  segLength * math.cos(rot_rad)

	local function addSegment(num, len)
		local pos0 = { pos[1] + dx * num, pos[2] + dy * num}
		addFatLine(name.." _seg "..num, len, width, pos0, rot, parent, controllers, material)
	end

	for segNum = 0, numOfWholePairs - 1 do
		addSegment(segNum, stroke)
	end

	if reminder > 0 then
		if reminder >= stroke then
			addSegment(numOfWholePairs, stroke)
		else
			addSegment(numOfWholePairs, reminder)
		end
	end
end


-- A symbology clipping region. May be used to limit the area where an element is visible/hidden.
--  In aircraft manuals also called 'occultation area/mask'.
local function createMask(name, vertices, indices, pos, parent, controllers, material)
	local mask				= addMesh(name, vertices, indices, pos, "triangles", parent, controllers)
	setAsInvisibleMask(mask) -- changes material
	mask.additive_alpha		= false
	mask.change_opacity		= false

	if material ~= nil then
		mask.material		= material
	end

	return mask
end

-- See above. Creates the region, and sets its occultation level.
-- Will increase the currently used level value, and will affect symbology
--  according to 'h_clip_relation' field value of each element rendered after it.
function openMaskArea(level, name, vertices, indices, pos, parent, controllers, material)
	local mask				= createMask(name, vertices, indices, pos, parent, controllers, material)
	mask.h_clip_relation	= h_clip_relations.INCREASE_IF_LEVEL
	mask.level				= DEFAULT_LEVEL + level
	return mask
end

-- Same as above, but removes the previously created clipping region.
function closeMaskArea(level, name, vertices, indices, pos, parent, controllers, material)
	local mask				= createMask(name, vertices, indices, pos, parent, controllers, material)
	mask.h_clip_relation	= h_clip_relations.DECREASE_IF_LEVEL
	mask.level				= DEFAULT_LEVEL + level
	return mask
end

-- Debug reference grid. Fits for both HUD and MDI/AMPCD
function dbg_add_MDG_RefGrid(step, halfWidth, collimated, noTFOV)
	local lines_count = math.ceil(halfWidth / step)
	if noTFOV == true then
		drawIndicatorRefGrid(lines_count, step, 2 * halfWidth, collimated)
	else
		drawIndicatorRefGrid(lines_count, step, 2 * halfWidth, collimated, halfWidth)
	end
end

-- Debug indicator display center (optical center in the case of HUD)
function dbg_addIndicatorCenter()

	do return end -- comment if you want the debug cross to be displayed

	-- new way - cross
	local crossSz		= 40
	local side			= crossSz * 0.5
	local vertices		= {{-side, 0}, {side, 0}, {0, side}, {0, -side}}
	local indices		= {0, 1, 2, 3}
	addMesh("indicator_center", vertices, indices, {0, 0}, "lines", nil, nil, "DBG_RED")

	do return end

	-- old way - circle
	local dbgCenter			= CreateElement "ceMeshPoly"
	dbgCenter.name			= "indicator_center"
	dbgCenter.primitivetype	= "triangles"
	set_circle(dbgCenter, 6, 3)
	dbgCenter.material		= "DBG_RED"
	dbgCenter.collimated	= collimated or false
	Add(dbgCenter)
end

function set_box(obj, left, right, up, down)
	local verts =
	{
		{left,	down},
		{left,	up},
		{right,	up},
		{right,	down}
	}

	local inds	= {	0, 1, 2,
					0, 2, 3 }

	obj.vertices	= verts
	obj.indices		= inds
end

function set_box_w_h(obj, width, height)
	set_box(obj, -width/2, width/2, height/2, -height/2)
end

-- arc is decreased counterclockwise by controllers in the range of 360 - 0 degrees
function addStrokeVarArc(name, radius, rot, pos, parent, controllerMask, controllerMain, level)
	local maskSide = radius

	-- right half of the circle (arc)
	local openingMaskRight = openMaskArea(level, name.."_openingMaskRight", {}, {}, pos, parent, controllerMask)
	set_box(openingMaskRight, 0, maskSide + 5, maskSide + 5, -(maskSide + 5))

	rot = rot or 0

	openingMaskRight.init_rot = {rot - 180}
	--openingMaskRight.isvisible = true -- dbg

	addStrokeArc(name.."_right", radius, 180, rot, pos, parent, nil, 1)

	local closingMaskRight = closeMaskArea(level + 1, name.."_closingMaskRight",
		openingMaskRight.vertices, openingMaskRight.indices, openingMaskRight.init_pos, parent, controllerMask)
	closingMaskRight.init_rot = {rot - 180}
	--closingMaskRight.isvisible = true -- dbg

	-- left half of the circle (arc)
	local openingMaskLeft = openMaskArea(level, name.."_openingMaskLeft", {}, {}, pos, parent, controllerMask)
	set_box(openingMaskLeft, -(maskSide + 5), 0, maskSide + 5, -(maskSide + 5))
	openingMaskLeft.init_rot = {rot}

	addStrokeArc(name.."_left", radius, 180, rot + 180, pos, parent, controllerMain, 0)

	local closingMaskLeft = closeMaskArea(level + 1, name.."_closingMaskLeft",
		openingMaskLeft.vertices, openingMaskLeft.indices, openingMaskLeft.init_pos, parent, controllerMask)
	openingMaskLeft.init_rot = {rot}
end

function addStrokeArcIndicator(name, radius, rot, pos, parent, controller, level)
	local maskSide = radius

	-- Right half of the circle (arc)
	controller[1][#controller[1] + 1] = 0
	local openingMaskRight = openMaskArea(level, name.."_openingMaskRight", {}, {}, pos, parent, controller)
	set_box(openingMaskRight, -(maskSide + 5), 0, maskSide + 5, -(maskSide + 5)) ---(obj, left, right, up, down)

	addStrokeArc(name.."_Right", radius, 180, rot, pos, parent, nil, 0)
	

	local closingMaskRight = closeMaskArea(level + 1, name.."_closingMaskRight",
		openingMaskRight.vertices, openingMaskRight.indices, openingMaskRight.init_pos, parent, controller)
	openingMaskRight.init_rot = {rot}

	-- Left half of the circle (arc)
	controller[1][#controller[1]] = 1
	local openingMaskLeft = openMaskArea(level, name.."_openingMaskLeft", {}, {}, pos, parent, controller)
	set_box(openingMaskLeft, 0, maskSide + 5, maskSide + 5, -(maskSide + 5)) ---(obj, left, right, up, down)

	addStrokeArc(name.."_left", radius, 180, rot + 180, pos, parent, nil, 0)

	local closingMaskLeft = closeMaskArea(level + 1, name.."_closingMaskLeft",
		openingMaskLeft.vertices, openingMaskLeft.indices, openingMaskLeft.init_pos, parent, controller)
	openingMaskLeft.init_rot = {rot}
end

-- arc is decreased counterclockwise by controllers in the range of 360 - 0 degrees. Other space filled by dashed arc
function addStrokeVarArcFilledDashArc(name, radius, rot, pos, parent, controller, segment, gap, level)
	local maskSide = radius

	-- Right half of the circle (arc)
	controller[1][#controller[1] + 1] = 0
	local openingMaskRight = openMaskArea(level, name.."_openingMaskRight", {}, {}, pos, parent, controller)
	set_box(openingMaskRight, -(maskSide + 5), 0, maskSide + 5, -(maskSide + 5)) ---(obj, left, right, up, down)

	addStrokeArc(name.."_Right", radius, 180, rot, pos, parent, nil, 0)
	local dashed_part = addStrokeCircle(name.."_Right_dashed_part", radius, pos, parent, nil, {0, math.pi}, segment, gap, true)
	dashed_part.init_rot = {-90}
	setClipLevel(dashed_part, 1)

	local closingMaskRight = closeMaskArea(level + 1, name.."_closingMaskRight",
		openingMaskRight.vertices, openingMaskRight.indices, openingMaskRight.init_pos, parent, controller)
	openingMaskRight.init_rot = {rot}

	-- Left half of the circle (arc)
	controller[1][#controller[1]] = 1
	local openingMaskLeft = openMaskArea(level, name.."_openingMaskLeft", {}, {}, pos, parent, controller)
	set_box(openingMaskLeft, 0, maskSide + 5, maskSide + 5, -(maskSide + 5)) ---(obj, left, right, up, down)

	addStrokeArc(name.."_left", radius, 180, rot + 180, pos, parent, nil, 0)
	local dashed_part = addStrokeCircle(name.."_left_dashed_part", radius, pos, parent, nil, {0, math.pi}, segment, gap, true)
	dashed_part.init_rot = {90}
	setClipLevel(dashed_part, 1)

	local closingMaskLeft = closeMaskArea(level + 1, name.."_closingMaskLeft",
		openingMaskLeft.vertices, openingMaskLeft.indices, openingMaskLeft.init_pos, parent, controller)
	openingMaskLeft.init_rot = {rot}
end

function addStrokeArc(name, radius, arc, rot, pos, parent, controllers, level)
	local obj = CreateElement "ceSMultiLine"

	local MaxSegments = 64

	local arc = arc or 360
	if arc > 360 then
		arc = 360
	end

	local count = math.ceil(arc / 360 * MaxSegments)
	local delta = math.rad(arc/count)

	setSymbolCommonProperties(obj, name, pos, parent, controllers)

	if rot ~= nil then
		obj.init_rot	= {rot}
	end

	setStrokeSymbolProperties(obj)

	local verts		= {}
	local inds		= {}

	for i = 1, count + 1 do
		verts[i] = {radius * math.sin(delta * (i - 1)), radius * math.cos(delta * (i - 1))}
	end

	for i = 1, count do
		inds[2*(i-1) + 1] = i - 1
		inds[2*(i-1) + 2] = i
	end

	obj.vertices		= verts
	obj.indices			= inds

	setClipLevel(obj, level or 0)

	Add(obj)
	return obj
end

function addTexturedMesh(name, material, vertices, tex_params, pos, rot, parent, controllers)
	if material == nil then
		do return end
	end

	local texturedMesh			= CreateElement "ceTexPoly"
	setSymbolCommonProperties(texturedMesh, name, pos, parent, controllers, material)

	texturedMesh.indices		= default_box_indices
	texturedMesh.vertices		= vertices
	texturedMesh.tex_params		= tex_params

	if rot ~= nil then
		texturedMesh.init_rot	= {rot}
	end

	Add(texturedMesh)
	return texturedMesh
end

function addDbgBackground(name, width, height, pos, material)

	local quad		= {	{0		, 0},
						{width	, 0},
						{width	,-height},
						{0		,-height}}
	local quad_tex	= {	{0,0},
						{1,0},
						{1,1},
						{0,1}}

	local dbg_background_tex			= CreateElement "ceTexPoly"
	dbg_background_tex.name				= name
	dbg_background_tex.vertices			= quad
	dbg_background_tex.indices			= default_box_indices
	dbg_background_tex.material			= material
	dbg_background_tex.tex_coords		= quad_tex
	dbg_background_tex.init_pos			= pos
	dbg_background_tex.collimated		= collimated or false
	Add(dbg_background_tex)

	return dbg_background_tex
end

-- X over a display element - text, symbol, etc
function add_X_Over(name, width, height, pos, parent, controllers)
	local rootName = name.."_Root"
	local angle = math.floor(math.deg(math.atan(height / width)))
	local hypotenuse = math.floor(math.sqrt(height ^ 2 + width ^ 2))

	addPlaceholder(rootName, pos, parent, controllers)
	addStrokeLine(name.."_BottomLine", hypotenuse, {-width / 2, -height / 2}, -90 + angle, rootName)
	addStrokeLine(name.."_TopLine", hypotenuse, {-width / 2, height / 2}, -90 - angle, rootName)
end

function addClippedBox(name, width, height, align, pos, parent, controllers, material)
	local openingMask = openMaskArea(0, name.."_Mask", buildBoxVerts(width, height, align), default_box_indices, pos, parent)
	local clippedObject = addBox(name, width, height, align, pos, parent, controllers, material)
	setClipLevel(clippedObject, 1)
	closeMaskArea(1, name.."_Mask_Close", openingMask.vertices, openingMask.indices, openingMask.init_pos, parent)
end