package.path=package.path..";C:\\Users\\micro\\AppData\\Roaming\\com.nesbox.tic\\TIC-80\\rift\\?.lua"	-- jtruk
package.path=package.path..";C:\\Users\\Ronan\\AppData\\Roaming\\com.nesbox.tic\\TIC-80\\rift\\?.lua"	-- Mantratronic
package.path=package.path..";C:\\Users\\matt\\AppData\\Roaming\\com.nesbox.tic\\TIC-80\\rift\\?.lua"	-- jynx
package.path=package.path..";C:\\Users\\Philipp\\AppData\\Roaming\\com.nesbox.tic\\TIC-80\\rift\\?.lua"	-- decca

--MODEL_TO_IMPORT=require("./data/model/green-man-walking-2")

MODEL_TO_IMPORT={}

R={}
require("./sys/sys")(R)
require("./ui/gui")(R)
require("./sys/math")(R)

POINTS={}
TRIS={}
TPOINTS={}
ANIM_CYCLES={}
BONES={}

GUI=nil
BG_TABS=nil
BTN_ZOOM=nil
PANEL_VERTS=nil
PANEL_TRIS=nil
PANEL_ANIM=nil
PANEL_TOOL=nil
TEXT_VERT_COUNT=nil
TEXT_BONE_COUNT=nil
TEXT_TRI_COUNT=nil
TEXT_TPOINTS_COUNT=nil
ZOOM_POWER=0
ANIM_CYCLE_NAME=nil
ANIM_FRAME_NAME=nil
MOVE_BONE_STEP_TEXT=nil

GRID_OFSX=0
GRID_OFSY=0
ANIM_CYCLE_INDEX=0
ANIM_FRAME_INDEX=0
IPOINT_HELD=nil
DOT_STYLE=0
TRI_STYLE=0
MOVE_BONE_STEP=nil	-- nil -> pivot -> handle
BONE_SELECTED_ID=nil
SEL_BONE_POINT_HANDLE_ID=nil

ANIM_TYPE="skeleton"	-- "skeleton" or "point"

function BOOT()
    GUI=R.Gui:new('gui',0,0)

	local b=R.Button.new('grid',0,0,128,128)
    GUI:addWidget(b)

	BTN_ZOOM=R.Button.new('grid-zoom',129,129,7,7)
    GUI:addWidget(BTN_ZOOM)

	local b=R.Button.new('grid-scr-y-',129,0,7,7)
    GUI:addWidget(b)
	local b=R.Button.new('grid-scr-y+',129,129-8,7,7)
    GUI:addWidget(b)

	local b=R.Button.new('grid-scr-x-',0,129,7,7)
    GUI:addWidget(b)
	local b=R.Button.new('grid-scr-x+',129-8,129,7,7)
    GUI:addWidget(b)

	BG_TABS=R.ButtonGroup.new('sections',138,0)

	local tabW=20
	local tabS=1
	local tabXD=tabW+tabS
	local tabY=10
	local b=R.Button.new('tab-verts',0,tabY,tabW,8,"Verts")
    BG_TABS:addButton(b)

	if ANIM_TYPE=="skeleton" then
		local b=R.Button.new('tab-skeleton',tabXD,tabY,tabW,8,"Skton")
		BG_TABS:addButton(b)
	end

	local b=R.Button.new('tab-tris',tabXD*2,tabY,tabW,8,"Tris")
    BG_TABS:addButton(b)

    local b=R.Button.new('tab-anim',tabXD*3,tabY,tabW,8,"Anim")
    BG_TABS:addButton(b)

    local b=R.Button.new('tab-tool',tabXD*4,tabY,tabW,8,"Tool")
    BG_TABS:addButton(b)
	GUI:addWidget(BG_TABS)

	TEXT_TPOINTS_COUNT=R.GuiText.new('tpoints-count',0,129,129,8,"")
    GUI:addWidget(TEXT_TPOINTS_COUNT)

	local panelX=138
	local panelY=30
	PANEL_VERTS=R.Panel.new('panel-verts',panelX,panelY)
	GUI:addWidget(PANEL_VERTS)

	TEXT_VERT_COUNT=R.GuiText.new('vert-count',0,0,80,8,"")
    PANEL_VERTS:addWidget(TEXT_VERT_COUNT)

	PANEL_SKELETON=R.Panel.new('panel-skeleton',panelX,panelY)
	GUI:addWidget(PANEL_SKELETON)

	TEXT_BONE_COUNT=R.GuiText.new('bone-count',0,0,80,8,"")
    PANEL_SKELETON:addWidget(TEXT_BONE_COUNT)

	PANEL_TRIS=R.Panel.new('panel-tris',panelX,panelY)
	GUI:addWidget(PANEL_TRIS)

	TEXT_TRI_COUNT=R.GuiText.new('tri-count',0,0,80,8,"")
    PANEL_TRIS:addWidget(TEXT_TRI_COUNT)

	PANEL_ANIM=R.Panel.new('panel-anim',panelX,panelY)
	GUI:addWidget(PANEL_ANIM)

	local w=R.GuiText.new('anim-type-label',0,0,104,8,"Anim Type: "..ANIM_TYPE)
    PANEL_ANIM:addWidget(w)
	
	local w=R.GuiText.new('anim-cycle-label',0,20,104,8,"Animation")
    PANEL_ANIM:addWidget(w)

	local b=R.Button.new('anim-cycle-',0,30,20,8,"<")
    PANEL_ANIM:addWidget(b)

	ANIM_CYCLE_NAME=R.GuiText.new('anim-cycle',22,30,40,8,"")
    PANEL_ANIM:addWidget(ANIM_CYCLE_NAME)

	local b=R.Button.new('anim-cycle+',62,30,20,8,">")
    PANEL_ANIM:addWidget(b)

	local b=R.Button.new('anim-cycle-add',84,30,20,8,"+")
    PANEL_ANIM:addWidget(b)

	local w=R.GuiText.new('anim-cycle-label',0,50,104,8,"Frames")
    PANEL_ANIM:addWidget(w)

	local b=R.Button.new('anim-frame-',0,60,20,8,"<")
    PANEL_ANIM:addWidget(b)

	ANIM_FRAME_NAME=R.GuiText.new('anim-frame',22,60,40,8,"")
    PANEL_ANIM:addWidget(ANIM_FRAME_NAME)

	local b=R.Button.new('anim-frame+',62,60,20,8,">")
    PANEL_ANIM:addWidget(b)

	local b=R.Button.new('anim-frame-add',84,60,40,8,"+")
    PANEL_ANIM:addWidget(b)

	local b=R.Button.new('move-bone',0,80,40,8,"Move Bone")
    PANEL_ANIM:addWidget(b)

	GUI_MOVE_BONE_STEP_TEXT=R.GuiText.new('move-bone-step',70,80,0,8,"")
    PANEL_ANIM:addWidget(GUI_MOVE_BONE_STEP_TEXT)

	PANEL_TOOL=R.Panel.new('panel-tool',panelX,panelY)
	GUI:addWidget(PANEL_TOOL)

	local b=R.Button.new('change-dot-style',5,0,40,8,"Dot style")
    PANEL_TOOL:addWidget(b)

	local b=R.Button.new('change-tri-style',58,0,40,8,"Tri style")
    PANEL_TOOL:addWidget(b)

	local b=R.Button.new('import',5,60,40,8,"Import")
    PANEL_TOOL:addWidget(b)

	local b=R.Button.new('export',58,60,40,8,"Export")
    PANEL_TOOL:addWidget(b)

	local b=R.Button.new('clear',25,80,40,8,"Clear")
    PANEL_TOOL:addWidget(b)

	GUI:setEventCb(function(m,hits)
		if #hits>0 then
			local hit=hits[1]
			local id=hit.id
			if id == 'grid' then
				clickGrid(m,hits[1].x,hits[1].y)
			elseif id == 'tab-verts' then
				BG_TABS:select('tab-verts')
			elseif id == 'tab-skeleton' then
				BG_TABS:select('tab-skeleton')
			elseif id == 'tab-tris' then
				BG_TABS:select('tab-tris')
			elseif id == 'tab-anim' then
				BG_TABS:select('tab-anim')
			elseif id == 'tab-tool' then
				BG_TABS:select('tab-tool')
			elseif id == 'grid-scr-x-' then
--				GRID_OFSX=R.clamp(GRID_OFSX-1,0,127)
			elseif id == 'grid-scr-x+' then
--				GRID_OFSX=R.clamp(GRID_OFSX+1,0,127)
			elseif id == 'grid-scr-y-' then
--				GRID_OFSY=GRID_OFSY-1
			elseif id == 'grid-scr-y+' then
--				GRID_OFSY=GRID_OFSY+1
			elseif id == 'grid-zoom' then
				if m.lbp then
--					ZOOM_POWER=(ZOOM_POWER+1)%4
				end
			elseif id == 'change-dot-style' and m.lbp then
				DOT_STYLE=(DOT_STYLE+1)%3
			elseif id == 'change-tri-style' and m.lbp then
				TRI_STYLE=(TRI_STYLE+1)%2
			elseif id == 'anim-cycle-add' and m.lbp then
				animCycleAdd(string.format("anim-%d",#ANIM_CYCLES+1))
			elseif id == 'anim-cycle-' and #ANIM_CYCLES > 0 and m.lbp then
				ANIM_CYCLE_INDEX=(ANIM_CYCLE_INDEX-1)%#ANIM_CYCLES
			elseif id == 'anim-cycle+' and #ANIM_CYCLES > 0 and m.lbp then
				ANIM_CYCLE_INDEX=(ANIM_CYCLE_INDEX+1)%#ANIM_CYCLES
			elseif id == 'anim-frame-add' and m.lbp then
				animFrameAdd()
			elseif id == 'anim-frame-' and #ANIM_CYCLES > 0 and m.lbp then
				local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]		
				ANIM_FRAME_INDEX=(ANIM_FRAME_INDEX-1)%#animCycle.frames
			elseif id == 'anim-frame+' and #ANIM_CYCLES > 0 and m.lbp then
				local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]
				ANIM_FRAME_INDEX=(ANIM_FRAME_INDEX+1)%#animCycle.frames
			elseif id == 'move-bone' and m.lbp then
				MOVE_BONE_STEP="pivot"
			elseif id == 'import' and m.lbp then
				modelImport(MODEL_TO_IMPORT)
			elseif id == 'export' and m.lbp then
				modelExport()
			elseif id == 'clear' and m.lbp then
				modelClear()
			end
		end

		updatePanelsFromTabs()
    end)

	BG_TABS:select('tab-verts')
	updatePanelsFromTabs()
end

TIC=R.ticWrap(function()
    cls()
    R.tryBreak()

	TEXT_VERT_COUNT:setLabel(string.format("Verts: %d",countPoints()))
	TEXT_BONE_COUNT:setLabel(string.format("Bones: %d",countBones()))
	TEXT_TRI_COUNT:setLabel(string.format("Tris: %d",countTris()))
	TEXT_TPOINTS_COUNT:setLabel(string.format("TriSel: %d",#TPOINTS))
	BTN_ZOOM:setLabel(string.format("x%d",2^ZOOM_POWER))

	if #ANIM_CYCLES == 0 then
		ANIM_CYCLE_NAME:setLabel("(none)")
		ANIM_FRAME_NAME:setLabel("(none)")
	else
		local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]
		ANIM_CYCLE_NAME:setLabel(animCycle.name)
		ANIM_FRAME_NAME:setLabel(string.format("%d/%d",ANIM_FRAME_INDEX+1,#animCycle.frames))
	end

	GUI_MOVE_BONE_STEP_TEXT:setLabel(MOVE_BONE_STEP and MOVE_BONE_STEP or "(none)")

    GUI:update()
	GUI:draw()
 
	local statusText="Status: OK"
	for i=1,#GUI.hits do
		local hit=GUI.hits[i]
		if hit.id=='grid' then
			drawHighlight(hit.x,hit.y)
			statusText=string.format("%3d,%3d",hit.x,hit.y)
			if IPOINT_HELD ~= nil then
				statusText=statusText..string.format(" (P %d)",IPOINT_HELD)
			end
		end
	end

	print(statusText,140,0,12)

	if PANEL_VERTS.isActive then
		drawPoints(POINTS, true)
	elseif PANEL_SKELETON.isActive then
		drawBones(POINTS)
		drawPoints(POINTS, true)
	elseif PANEL_TRIS.isActive or PANEL_TOOL.isActive then
		drawTris(POINTS,6,true)
		drawPoints(POINTS, true)
	elseif PANEL_ANIM.isActive then
		local m=R.getMouse()
		if ANIM_TYPE=="point" then
			if #ANIM_CYCLES>0 then
				local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]
				local iFrame=ANIM_FRAME_INDEX
				local iFramePre=(ANIM_FRAME_INDEX-1)%#animCycle.frames
				local iFramePost=(ANIM_FRAME_INDEX+1)%#animCycle.frames
				local hasFrameGuide=m.rb
				if hasFrameGuide then
					local frame=animCycle.frames[iFramePre+1]
					drawTris(frame.v,2,true)
					drawPoints(frame.v, false)
					
					local frame=animCycle.frames[iFramePost+1]
					drawTris(frame.v,9,true)
					drawPoints(frame.v, false)
				end
			else
				local frame=animCycle.frames[iFrame+1]
				drawTris(frame.v,6,not hasFrameGuide)
				drawPoints(frame.v, false)
			end
		else
			if #ANIM_CYCLES>0 then
				local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]
				local iFrame=ANIM_FRAME_INDEX
				local iFramePre=(ANIM_FRAME_INDEX-1)%#animCycle.frames
				local iFramePost=(ANIM_FRAME_INDEX+1)%#animCycle.frames
				local frame=animCycle.frames[iFrame+1]

				drawTris(frame.v,6,not hasFrameGuide)
				drawBones(frame.v, false)

				if MOVE_BONE_STEP=="pivot" then
					circ(m.x,m.y,3,6)
				elseif MOVE_BONE_STEP=="handle" then
					circ(m.x,m.y,3,7)
				end
			end
		end
	end
end)

function updatePanelsFromTabs()
	local selectedTab=BG_TABS:getSelected()
	isVerts=selectedTab=='tab-verts'
	isSkeleton=selectedTab=='tab-skeleton'
	isTris=selectedTab=='tab-tris'
	isAnim=selectedTab=='tab-anim'
	isTool=selectedTab=='tab-tool'
	PANEL_VERTS:setActive(isVerts)
	PANEL_SKELETON:setActive(isSkeleton)
	PANEL_TRIS:setActive(isTris)
	PANEL_ANIM:setActive(isAnim)
	PANEL_TOOL:setActive(isTool)
	-- #TODO: Should only happen when we switch tab
	if not isSkeleton and not isTris then	-- reset the point accumulator
		TPOINTS={}
	end
end

function clickGrid(m,x,y)
	if PANEL_VERTS.isActive then
		if m.lbp then
			if not tryPickupPoint(POINTS,x,y) then
				tryAddPoint(x,y)
			end
		elseif m.lb then
			tryPlacePoint(POINTS,x,y)
		elseif m.rbp then
--			tryRemovePoint(x,y)
		end
	elseif PANEL_SKELETON.isActive then
		if m.lbp then
			tryAddBone(x,y)
		elseif m.rbp then
			tryAttachPointToBone(POINTS,x,y)
		end
	elseif PANEL_TRIS.isActive then
		if m.lbp then
			tryAddTri(x,y)
		end
	elseif PANEL_ANIM.isActive then
		if ANIM_TYPE=="point" then
			if #ANIM_CYCLES>0 then
				local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]
				local frame=animCycle.frames[ANIM_FRAME_INDEX+1]
				if m.lbp then
					tryPickupPoint(frame.v,x,y)
				elseif m.lb then
					tryPlacePoint(frame.v,x,y)
				end
			end
		else
			if #ANIM_CYCLES>0 then
				local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]
				local frame=animCycle.frames[ANIM_FRAME_INDEX+1]

				if m.lbp then
					if MOVE_BONE_STEP=="pivot" then
						BONE_PIVOT_SET={x=m.x,y=m.y}
						MOVE_BONE_STEP="handle"
					elseif MOVE_BONE_STEP=="handle" then
						BONE_HANDLE_SET={x=m.x,y=m.y}
						moveBone()
						MOVE_BONE_STEP=nil
					end
				end

					--[[
				if m.lbp then
					startBoneAction(x,y)
				elseif m.lb then
					if key(64) then
						tryMoveBone(frame.b,x,y)
					else
						tryRotateBone(frame.b,x,y)
					end
				end
				--]]
			end
		end
	end
end

function countPoints()
	local c=0
	for i=1,#POINTS do
	 if POINTS[i].a then
			c=c+1
		end
	end
	return c
end

function countBones()
	local c=0
	for i=1,#BONES do
	 if BONES[i].a then
			c=c+1
		end
	end
	return c
end

function countTris()
	local c=0
	for i=1,#TRIS do
	 if TRIS[i].a then
			c=c+1
		end
	end
	return c
end

function drawHighlight(x,y)
	local np,nd=nil,nil
	if PANEL_VERTS.isActive or PANEL_SKELETON.isActive or PANEL_TRIS.isActive then
		np,nd=getNearestPoint(POINTS,x,y,true)
	elseif PANEL_ANIM.isActive then
		if #ANIM_CYCLES>0 then
			local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]
			local frame=animCycle.frames[ANIM_FRAME_INDEX+1]
			np,nd=getNearestPoint(frame.v,x,y,false)
		end
	end
	if np~=nil and nd<10 then
		rectb(np.x-1,np.y-1,3,3,2)
	end
end

function drawPoints(points,useAlive)
	local zoom=2^ZOOM_POWER
	clip(0,0,128,128)
	for i=1,#points do
		local p=points[i]
		if not useAlive or p.a then
			local x=(p.x-GRID_OFSX)*zoom
			local y=(p.y-GRID_OFSY)*zoom
			if DOT_STYLE == 0 then
				pix(x,y,12)
			elseif DOT_STYLE == 1 then
				pix(x,y,1+(i%5))
			elseif DOT_STYLE == 2 then
			end
		end
	end
	clip()
end

function drawBones(points)
	clip(0,0,128,128)
	for iB=1,#BONES do
		local b=BONES[iB]
		-- ...
		if b.a then
			local col=(iB==BONE_SELECTED_ID) and 9 or 3
			for iV=1,#b.v do
				local v=points[b.v[iV]]
				rectb(v.x-1,v.y-1,3,3,col)
			end

			if SEL_BONE_POINT_HANDLE_ID then
				local bp=points[SEL_BONE_POINT_HANDLE_ID]
				rect(bp.x-1,bp.y-1,3,3,10)
			end

			local p1=points[b.p1]
			local p2=points[b.p2]
			local col=(iB==BONE_SELECTED_ID) and 9 or 3
			line(p1.x,p1.y,p2.x,p2.y,col)
		end
	end
	clip()
end

function drawTris(points,col,isFilled)
	local zoom=2^ZOOM_POWER
	clip(0,0,128,128)
	local fnTri=isFilled and tri or trib
	for i=1,#TRIS do
		local t=TRIS[i]
		if t.a then
			local p1=points[t.p[1]]
			local p2=points[t.p[2]]
			local p3=points[t.p[3]]
			local p1x,p1y=p1.x*zoom,p1.y*zoom
			local p2x,p2y=p2.x*zoom,p2.y*zoom
			local p3x,p3y=p3.x*zoom,p3.y*zoom
			if TRI_STYLE == 1 then
				col=1+(col+i)%10
			end
			fnTri(p1x,p1y,p2x,p2y,p3x,p3y,col)
		end
	end
	clip()
end


function tryAddPoint(x,y)
	local np,nd=getNearestPoint(POINTS,x,y,true)
	if np==nil or nd>0	then
		POINTS[#POINTS+1]={
			x=x,y=y,a=true -- alive
		}
	end
end

function tryRemovePoint(x,y)
	local np,nd=getNearestPoint(POINTS,x,y,true)
	if np and nd<5	then
		np.a=false
	end
end

function tryAddBone(x,y)
	local np,nd,ni=getNearestPoint(POINTS,x,y,true)
	if np==nil or nd>10 then
		return
	end

	-- check points are different
	for i=1,#TPOINTS do
		if TPOINTS[i]==ni then
			return
		end
	end

	TPOINTS[#TPOINTS+1]=ni

	if #TPOINTS==2 then
		-- If this is already a bone then select it
		local boneId=tryGetBone(POINTS,TPOINTS[1],TPOINTS[2])
		local selectPointId=TPOINTS[2]
		if boneId==nil then	-- add it
			boneId=#BONES+1
			BONES[boneId]={
				p1=TPOINTS[1],
				p2=TPOINTS[2],
				a=true,
				v={},
			}
		end
		-- Select it
		selectBone(boneId,TPOINTS[2])

		TPOINTS={}
	end
end

function selectBone(boneId,pointHandleId)
	BONE_SELECTED_ID=boneId
	SEL_BONE_POINT_HANDLE_ID=pointHandleId
end

-- Returns nil or id
function tryGetBone(points,p1,p2)
	for i=1,#BONES do
		local b=BONES[i]
		if b.a and (b.p1==p1 and b.p2==p2) or (b.p1==p2 and b.p2==p1) then
			return i
		end
	end
	return nil
end

function tryAddTri(x,y)
	local np,nd,ni=getNearestPoint(POINTS,x,y,true)
	if np==nil or nd>10 then
		return
	end

	-- check points are different
	for i=1,#TPOINTS do
		if TPOINTS[i]==ni then
			return
		end
	end

	TPOINTS[#TPOINTS+1]=ni

	if #TPOINTS==3 then
		TRIS[#TRIS+1]={
			p=TPOINTS,
			a=true,
		}
		TPOINTS={}
	end
end

-- returns nil,nil,nil or point,dist,i
function getNearestPoint(points,x,y,useAlive)
	local np=nil
	local nd=nil
	local ni=nil
	for i=1,#points do
	 local p=points[i]
		if not useAlive or p.a then
			local d=(p.x-x)^2+(p.y-y)^2
			if np==nil or d<nd then
				np,nd,ni=p,d,i
			end
		end
	end
	return np,nd,ni
end

function animCycleAdd(name)
-- Copy points from base...
	local v={}
	for i=1,#POINTS do
		local p=POINTS[i]
		v[#v+1]={x=p.x,y=p.y}
	end

	ANIM_CYCLES[#ANIM_CYCLES+1]={name=name,frames={{v=v}}}
	ANIM_CYCLE_INDEX=#ANIM_CYCLES-1
end

function animFrameAdd()
	local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]
	local lastFrame=animCycle.frames[#animCycle.frames]
	local v={}
	for i=1,#lastFrame.v do
		local p=lastFrame.v[i]
		v[#v+1]={x=p.x,y=p.y}
	end

	animCycle.frames[#animCycle.frames+1]={v=v}
	ANIM_FRAME_INDEX=#animCycle.frames-1
end

-- returns false if we didn't pick up
function tryPickupPoint(verts,x,y)
	local np,nd,ni=getNearestPoint(verts,x,y,false)
	IPOINT_HELD = (np~=nil and nd<10) and ni or nil
	return IPOINT_HELD~=nil
end

function tryPlacePoint(verts,x,y)
	if not IPOINT_HELD then
		return
	end

	local v=verts[IPOINT_HELD]
	v.x=x
	v.y=y
end


function tryAttachPointToBone(POINTS,x,y)
	if not BONE_SELECTED_ID then
		return
	end

	local np,nd,ni=getNearestPoint(POINTS,x,y,true)
	if np==nil or nd>10 then
		return
	end

	-- Check if this vertex is attached to any bones and remove if so
	-- NB This may remove it from our selected bone - that's fine, it gets re-added below
	for ib=1,#BONES do
		local b=BONES[ib]
		for i=1,#b.v do
			if b.v[i]==ni then
				table.remove(b.v,i)
				break
			end
		end
	end

	local bone=BONES[BONE_SELECTED_ID]
	if bone==nil then
		return -- hack
	end

	bone.v[#bone.v+1]=ni
end

-- #TODO: Propagate this around the code
function getCurrentFrame()
	local animCycle=ANIM_CYCLES[ANIM_CYCLE_INDEX+1]
	local iFrame=ANIM_FRAME_INDEX
	return animCycle.frames[iFrame+1]
end

function moveBone()
	local frame=getCurrentFrame()
	local bone=BONES[BONE_SELECTED_ID]
	local basePivotPointId=nil
	local baseHandlePointId=nil
	
	if bone.p1==SEL_BONE_POINT_HANDLE_ID then
		basePivotPointId=bone.p1
		baseHandlePointId=bone.p2
	else
		basePivotPointId=bone.p2
		baseHandlePointId=bone.p1
	end

	local basePivotPoint=POINTS[basePivotPointId]
	local baseHandlePoint=POINTS[baseHandlePointId]

	-- get bone length and angle in base
	local dx=basePivotPoint.x-baseHandlePoint.x
	local dy=basePivotPoint.y-baseHandlePoint.y
	local d=(dx^2+dy^2)^.5
	local oldA=math.atan2(dx,dy)

	local newDx=BONE_HANDLE_SET.x-BONE_PIVOT_SET.x
	local newDy=BONE_HANDLE_SET.y-BONE_PIVOT_SET.y
	local newA=math.atan2(newDx,newDy)

	local newFramePivot=frame.v[basePivotPointId]
	local newFrameHandle=frame.v[baseHandlePointId]
	newFramePivot.x=BONE_PIVOT_SET.x
	newFramePivot.y=BONE_PIVOT_SET.y
	newFrameHandle.x=BONE_PIVOT_SET.x+math.sin(newA)*d
	newFrameHandle.y=BONE_PIVOT_SET.y+math.cos(newA)*d

	local diffA=newA-oldA
	for i=1,#bone.v do
		-- Find the angles from the pivot point to each child point
		local p=POINTS[bone.v[i]]
		local vDx,vDy=baseHandlePoint.x-p.x,baseHandlePoint.y-p.y
		local vD=(vDx^2+vDy^2)^.5
		local vA=math.atan2(vDx,vDy)
		local fNewA=vA+diffA

		local newX=newFrameHandle.x+math.sin(fNewA)*vD
		local newY=newFrameHandle.y+math.cos(fNewA)*vD
--		local newX,newY=newFramePivot.x+math.sin(fNewA)*vD,newFramePivot.y+math.cos(fNewA)*vD

		frame.v[bone.v[i]].x=newX//1
		frame.v[bone.v[i]].y=newY//1
	end

	BONE_PIVOT_SET=nil
	BONE_HANDLE_SET=nil
end

function startBoneAction(x,y)
	PICKUP_X=x
	PICKUP_Y=y
end

--[[
function tryMoveBone(bones,x,y)
	if not BONE_SELECTED_ID or not SEL_BONE_POINT_HANDLE_ID then
		return
	end


	local mDx,mDy=x-PICKUP_X,y-PICKUP_Y
	local frameSelectedPoint=frame.v[SEL_BONE_POINT_HANDLE_ID]
	local framePivotPoint=frame.v[pivotPointId]
	frameSelectedPoint.x=(frameSelectedPoint.x-framePivotPoint.x)+mDx
	frameSelectedPoint.y=(frameSelectedPoint.y-framePivotPoint.y)+mDy
	framePivotPoint.x=x
	framePivotPoint.y=y

end

function tryRotateBone(bones,x,y)
	if not BONE_SELECTED_ID or not SEL_BONE_POINT_HANDLE_ID then
		return
	end

	local frame=getCurrentFrame()

	local bone=BONES[BONE_SELECTED_ID]
	local selectedPoint=POINTS[SEL_BONE_POINT_HANDLE_ID]
	-- Get the other point, as the pivot...
	local pivotPointId=bone.p1==SEL_BONE_POINT_HANDLE_ID and bone.p2 or bone.p1
	local pivotPoint=POINTS[pivotPointId]

	local mDx,mDy=x-pivotPoint.x,y-pivotPoint.y
	local mD=(mDx^2+mDy^2)^.5
	local mA=math.atan2(mDx,mDy)

	local boneDx,boneDy=selectedPoint.x-pivotPoint.x,selectedPoint.y-pivotPoint.y
	local boneD=(boneDx^2+boneDy^2)^.5
	local boneA=math.atan2(boneDx,boneDy)

	local boneNewX,boneNewY=pivotPoint.x+math.sin(mA)*boneD,pivotPoint.y+math.cos(mA)*boneD
	frame.v[SEL_BONE_POINT_HANDLE_ID].x=boneNewX//1
	frame.v[SEL_BONE_POINT_HANDLE_ID].y=boneNewY//1
	local diffA=boneA-mA

end
--]]

function modelClear()
	POINTS={}
	BONES={}
	TRIS={}
	TPOINTS={}
	ANIM_CYCLES={}
	ANIM_CYCLE_INDEX=0
	ANIM_FRAME_INDEX=0
end

function modelImport(d)
	modelClear()

	for i=1,#d.vertices,3 do
		POINTS[#POINTS+1]={
			x=d.vertices[i],
			y=d.vertices[i+1],
			a=true
		}
	end

	for i=1,#d.triangles,3 do
		TRIS[#TRIS+1]={
			p={
				d.triangles[i],
				d.triangles[i+1],
				d.triangles[i+2],
			},
			a=true,
		}
	end

	if d.bones then
		for i=1,#d.bones do
			local bone=d.bones[i]
			bone.a=true
			BONES[#BONES+1]=bone
		end
	end

	if d.vanim then
		for name,frames in pairs(d.vanim) do
			local makeFrames={}
			for iF,vertices in ipairs(frames) do
				local v={}
				for iV=1,#vertices,3 do
					v[#v+1]={
						x=vertices[iV],
						y=vertices[iV+1],
					}
				end
				makeFrames[#makeFrames+1]={v=v}
			end

			ANIM_CYCLES[#ANIM_CYCLES+1]={name=name,frames=makeFrames}
		end
	end
end

function modelExport()
	local str="-- Generated by TIC 2D Plot\n"

	str=str.."return {\n"
	str=str.."	flags=0,\n"
	str=str.."	divide_by=100,\n"
	str=str.."	scale=1,\n"
	str=str.."	vertices={"
	for i=1,#POINTS do
		local p=POINTS[i]
		if p.a then
			str=str..string.format("%d,%d,0,",p.x,p.y)
		end
	end
	str=str.."},\n"

	str=str.."	triangles={"
	for i=1,#TRIS do
		local t=TRIS[i]
		if t.a then
			str=str..string.format("%d,%d,%d,",t.p[1],t.p[2],t.p[3])
		end
	end
	str=str.."},\n"

	if #BONES>0 then
		str=str.."	bones={"
		for i=1,#BONES do
			local b=BONES[i]
			local vs=""
			for iV=1,#b.v do
				vs=vs..b.v[iV]..","
			end
			str=str..string.format("{p1=%d,p2=%d,v={%s}},",b.p1,b.p2,vs)
		end
		str=str.."},\n"
	end

	if #ANIM_CYCLES>0 then
		str=str.."	vanim={"
		for iC=1,#ANIM_CYCLES do
			local c=ANIM_CYCLES[iC]
			str=str..string.format('["%s"]={',c.name).."\n"
			for iF=1,#c.frames do
				local f=c.frames[iF]
				str=str.."{\n"
				for iV=1,#f.v do
					str=str..string.format("%d,%d,0,",f.v[iV].x,f.v[iV].y)
				end
				str=str.."},\n"
			end
			str=str.."},\n"
		end
		str=str.."},\n"
	end

	str=str.."}"
	trace(str)
	exit()
end

-- <TILES>
-- 001:eccccccccc888888caaaaaaaca888888cacccccccacc0ccccacc0ccccacc0ccc
-- 002:ccccceee8888cceeaaaa0cee888a0ceeccca0ccc0cca0c0c0cca0c0c0cca0c0c
-- 003:eccccccccc888888caaaaaaaca888888cacccccccacccccccacc0ccccacc0ccc
-- 004:ccccceee8888cceeaaaa0cee888a0ceeccca0cccccca0c0c0cca0c0c0cca0c0c
-- 017:cacccccccaaaaaaacaaacaaacaaaaccccaaaaaaac8888888cc000cccecccccec
-- 018:ccca00ccaaaa0ccecaaa0ceeaaaa0ceeaaaa0cee8888ccee000cceeecccceeee
-- 019:cacccccccaaaaaaacaaacaaacaaaaccccaaaaaaac8888888cc000cccecccccec
-- 020:ccca00ccaaaa0ccecaaa0ceeaaaa0ceeaaaa0cee8888ccee000cceeecccceeee
-- </TILES>

-- <WAVES>
-- 000:00000000ffffffff00000000ffffffff
-- 001:0123456789abcdeffedcba9876543210
-- 002:0123456789abcdef0123456789abcdef
-- </WAVES>

-- <SFX>
-- 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000
-- </SFX>

-- <TRACKS>
-- 000:100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-- </TRACKS>

-- <PALETTE>
-- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
-- </PALETTE>

