local math = math
local additiveColorMaterial = {materialType = 11, lighting = false}
local HELPER_SPRITES = {}

function video.initHelpers()
	local f = video.getSpriteStateNames("helper.dat")
	if f then
		for index, anim in pairs(f) do
			HELPER_SPRITES[anim] = video.createSpriteState(anim, "helper.dat")
		end
	end
end

local old_renderFullscreenPP = video.renderFullscreenPP
--fixes a canvas size bug
function video.rendreFullscreenPP(...)
	local w,h = canvas.w, canvas.h
	canvas.setToWindow()
	old_renderFullscreenPP(...)
	canvas.setSize(w,h)
end

function video.renderAveragedAdditiveSpriteState(sprite, x, y, scale, angle, r, g, b, flipped)
	if not video.disableAdditive then
		video.setUseMaterialFor2d(true)
		video.setMaterial(additiveColorMaterial)
		local avg = math.max(1,(r+g+b)/255)
		video.renderSpriteState(sprite, x, y, scale, angle, 255,  r/avg, g/avg, b/avg, flipped)		
		video.setUseMaterialFor2d(false)
	end
end

function video.renderAdditiveSpriteState(sprite, x, y, scale, angle, r, g, b, flipped)
	if not video.disableAdditive then
		video.setUseMaterialFor2d(true)
		video.setMaterial(additiveColorMaterial)
		video.renderSpriteState(sprite, x, y, scale, angle, 255,  r, g, b, flipped)		
		video.setUseMaterialFor2d(false)
	end
end

function video.renderLineWithOutline(x, y, x2, y2, alpha, r, g, b, outAlpha, outR, outG, outB)
	video.renderLine(x+1,y+1,x2+1,y2+1, outAlpha, outR, outG, outB)
	video.renderLine(x-1,y-1,x2-1,y2-1, outAlpha, outR, outG, outB)
	video.renderLine(x+1,y-1,x2+1,y2-1, outAlpha, outR, outG, outB)
	video.renderLine(x-1,y+1,x2-1,y2+1, outAlpha, outR, outG, outB)
	video.renderLine(x,y,x2,y2, alpha, r, g, b)
end

function video.renderLineArrow(x,y, x2, y2, arc, size, alpha, r, g, b)
	video.renderLine(x,y, x2, y2, alpha, r, g, b)
	local ang = math.angleBetweenPoints(x,y,x2,y2)
	video.renderLine(x2, y2, x2 + math.cos(ang+math.pi+arc*0.5)*size, y2 + math.sin(ang+math.pi+arc*0.5)*size , alpha, r, g, b)
	video.renderLine(x2, y2, x2 + math.cos(ang+math.pi-arc*0.5)*size, y2 + math.sin(ang+math.pi-arc*0.5)*size , alpha, r, g, b)
end


function video.renderLinePlus(x, y, size, alpha, r, g, b)
	video.renderLine(x-size,y,x+size,y, alpha, r, g, b)
	video.renderLine(x,y-size,x,y+size, alpha, r, g, b)
end

function video.renderRectangleOutline(x, y, x2, y2, alpha, r, g, b)
	video.renderLine(x,y,x2,y, alpha, r, g, b)
	video.renderLine(x,y2,x2,y2, alpha, r, g, b)
	video.renderLine(x,y,x,y2, alpha, r, g, b)
	video.renderLine(x2,y,x2,y2, alpha, r, g, b)
end

function video.renderTextWithOutline(text, x, y, alignment, font, alpha, r, g, b, outAlpha, outR, outG, outB)
	video.renderTextSprites(text, x-1, y, alignment, font, outAlpha, outR, outG, outB)		
	video.renderTextSprites(text, x+2, y, alignment, font, outAlpha, outR, outG, outB)		
	video.renderTextSprites(text, x, y-1, alignment, font, outAlpha, outR, outG, outB)		
	video.renderTextSprites(text, x, y+1, alignment, font, outAlpha, outR, outG, outB)		
	video.renderTextSprites(text, x, y, alignment, font, alpha, r, g, b)		
end

function video.renderReflectiveSpriteState(sprite, x, y, scale, alpha, red, green, blue, threshold)
	PP_SHADERS.reflective.toShader.intensity = alpha
	PP_SHADERS.reflective.toShader.colorMask[1] = math.min(1, red)
	PP_SHADERS.reflective.toShader.colorMask[2] = math.min(1, green)
	PP_SHADERS.reflective.toShader.colorMask[3] = math.min(1, blue)
	PP_SHADERS.reflective.toShader.resolution[1] = canvas.w
	PP_SHADERS.reflective.toShader.resolution[2] = canvas.h
	PP_SHADERS.reflective.toShader.threshold = threshold
	video.renderSpriteStatePP(getPPMaterial(PP_SHADERS.reflective), sprite, x, y, scale, PP_SHADERS.reflective.toShader)	
end

function video.renderBeamSprite(sprite, x1, y1, x2, y2, width, alpha, r, g, b)
	local realAngle = math.angleBetweenPoints(x1, y1, x2, y2)
	local sx1, sy1 = x1 + math.cos(realAngle-math.pi*0.5)*width, y1 + math.sin(realAngle-math.pi*0.5)*width
	local sx2, sy2 = x1 + math.cos(realAngle+math.pi*0.5)*width, y1 + math.sin(realAngle+math.pi*0.5)*width
	local tx1, ty1 = x2 + math.cos(realAngle-math.pi*0.5)*width, y2 + math.sin(realAngle-math.pi*0.5)*width
	local tx2, ty2 = x2 + math.cos(realAngle+math.pi*0.5)*width, y2 + math.sin(realAngle+math.pi*0.5)*width
	video.renderSpriteStateFreeShape(sprite, sx1, sy1, tx1, ty1, sx2, sy2, tx2, ty2, alpha, r, g, b)
end

function video.renderLightSpriteState(sprite, x, y, scale, alpha, red, green, blue)
	PP_SHADERS.light.toShader.intensity = math.min(1, alpha)
	PP_SHADERS.light.toShader.colorMask[1] = math.min(1, red)
	PP_SHADERS.light.toShader.colorMask[2] = math.min(1, green)
	PP_SHADERS.light.toShader.colorMask[3] = math.min(1, blue)
	video.renderSpriteStatePP(getPPMaterial(PP_SHADERS.light), sprite, x, y, scale, PP_SHADERS.light.toShader)	
end


function video.renderHudSpriteState(sprite, x, y, scale, angle, alpha, r, g, b)
	if _config.pixelShaders then
		video.renderSpriteState(sprite, x , y , scale, angle , alpha/2, r, g, b)
		video.renderLightSpriteState(sprite, x, y, scale , alpha/255/3*2, r/255, g/255, b/255)
	else
		video.renderSpriteState(sprite, x , y , scale, angle , alpha, r, g, b)
	end
end

function video.renderPlus(x,y, size, thickness, alpha, r, g, b)
	video.renderRectangle(x-size/2, y-size/2*thickness, size,  size*thickness, alpha, r, g, b)
	video.renderRectangle(x-size/2*thickness, y-size/2, size*thickness, size/2-size*thickness/2, alpha, r, g, b)
	video.renderRectangle(x-size/2*thickness, y+ size*thickness/2, size*thickness, size/2-size*thickness/2, alpha, r, g, b)
end

function video.renderFrameSprite(fs, x, y, w, h, a, r, g, b, widthborder, heightborder)
	local wi,hi = widthborder or fs.width, heightborder or fs.height
	video.renderSpriteStateFreeShape(fs.topLeft, x, y, math.min(x+wi, x+w/2), y, x, math.min(y+hi, y+h/2), math.min(x+wi, x+w/2), math.min(y+hi, y+h/2), a, r, g, b)
	video.renderSpriteStateFreeShape(fs.top, math.min(x+wi, x+w/2), y, math.max(x+w-wi, x+w/2), y, math.min(x+wi, x+w/2), math.min(y+hi, y+h/2), math.max(x+w-wi, x+w/2), math.min(y+hi, y+h/2), a, r, g, b)
	video.renderSpriteStateFreeShape(fs.topRight, math.max(x+w-wi, x+w/2), y, x+w, y, math.max(x+w-wi, x+w/2), math.min(y+hi, y+h/2), x+w, math.min(y+hi, y+h/2), a, r, g, b)
	video.renderSpriteStateFreeShape(fs.left, x, math.min(y+hi, y+h/2), math.min(x+wi, x+w/2), math.min(y+hi, y+h/2), x, math.max(y+h-hi, y+h/2), math.min(x+wi, x+w/2), math.max(y+h-hi, y+h/2), a, r, g, b)
	if fs.main then
		video.renderSpriteStateFreeShape(fs.main, math.min(x+wi, x+w/2), math.min(y+hi, y+h/2), math.max(x+w-wi, x+w/2), math.min(y+hi, y+h/2), math.min(x+wi, x+w/2), math.max(y+h-hi, y+h/2), math.max(x+w-wi, x+w/2), math.max(y+h-hi, y+h/2), a, r, g, b)
	end
	video.renderSpriteStateFreeShape(fs.right, math.max(x+w-wi, x+w/2), math.min(y+hi, y+h/2), x+w, math.min(y+hi, y+h/2), math.max(x+w-wi, x+w/2), math.max(y+h-hi, y+h/2), x+w, math.max(y+h-hi, y+h/2), a, r, g, b)
	video.renderSpriteStateFreeShape(fs.bottomLeft, x, math.max(y+h-hi, y+h/2), math.min(x+wi, x+w/2),math.max(y+h-hi, y+h/2), x, y+h, math.min(x+wi, x+w/2), y+h, a, r, g, b)
	video.renderSpriteStateFreeShape(fs.bottom, math.min(x+wi, x+w/2), math.max(y+h-hi, y+h/2), math.max(x+w-wi, x+w/2), math.max(y+h-hi, y+h/2), math.min(x+wi, x+w/2), y+h, math.max(x+w-wi, x+w/2), y+h, a, r, g, b)
	video.renderSpriteStateFreeShape(fs.bottomRight, math.max(x+w-wi, x+w/2), math.max(y+h-hi, y+h/2), x+w, math.max(y+h-hi, y+h/2), math.max(x+w-wi, x+w/2), y+h, x+w, y+h, a, r, g, b)
end

function video.renderGradientUp(left, top, right, bottom, alpha, r, g, b)
	video.renderSpriteStateFreeShape(HELPER_SPRITES.gradient, left, bottom, right, bottom, left, top, right, top, alpha, r, g, b)
end

function video.renderGradientLeft(left, top, right, bottom, alpha, r, g, b)
	video.renderSpriteStateFreeShape(HELPER_SPRITES.gradient, right, top, right, bottom, left, top, left, bottom, alpha, r, g, b)
end

function video.renderGradientRight(left, top, right, bottom, alpha, r, g, b)
	video.renderSpriteStateFreeShape(HELPER_SPRITES.gradient, left, bottom, left, top, right, bottom, right, top, alpha, r, g, b)
end

function video.renderGradientDown(left, top, right, bottom, alpha, r, g, b)
	video.renderSpriteStateFreeShape(HELPER_SPRITES.gradient, left, top, right, top, left, bottom, right, bottom, alpha, r, g, b)
end

function video.renderGradientBox(left, top, right, bottom, gradientStart, gradientLength, alpha, r, g, b)
	video.renderGradientUp(left,bottom - bottom*gradientLength-gradientStart*bottom, right, bottom-gradientStart*bottom, alpha, r, g, b)
	video.renderGradientDown(left,gradientStart*bottom, right, bottom*gradientLength +gradientStart*bottom, alpha, r, g, b)
	video.renderGradientRight(gradientStart*right,top, right*gradientLength+gradientStart*right, bottom, alpha, r, g, b)
	video.renderGradientLeft(right-gradientLength*right-gradientStart*right,top, right-gradientStart*right, bottom, alpha, r, g, b)
end

function video.renderProgressBar(val, step, x, y, scale, angle, alpha, r, g, b)
	for i=1,math.ceil(val) do
		local stepAlpha = math.min(1,math.max(0,val - (i-1)))
		video.renderSpriteState(HELPER_SPRITES.hudLine, x + math.cos(angle)*(i-1)*step, y+ math.sin(angle)*(i-1)*step, scale, angle-math.pi*0.5, alpha*stepAlpha, r*stepAlpha, g*stepAlpha, b*stepAlpha)
	end
end


function video.renderCenteredProgressBar(val, gapSize, step, x, y, scale, angle, alpha, r, g, b)
	for i=1,math.ceil(val) do
		local stepAlpha = math.min(1,math.max(0,val - (i-1)))
		video.renderSpriteState(HELPER_SPRITES.hudLine, x + gapSize/2 + i*step, y, scale, angle-math.pi*0.5, alpha*stepAlpha, r*stepAlpha, g*stepAlpha, b*stepAlpha)
		video.renderSpriteState(HELPER_SPRITES.hudLine, x - gapSize/2 - i*step, y, scale, angle-math.pi*0.5, alpha*stepAlpha, r*stepAlpha, g*stepAlpha, b*stepAlpha)
	end
end

function video.renderHealthBar(prg, x,y, width, height, scale, a, r, g, b)
	video.renderSpriteRectangle(x -width*0.5*scale, y-height*0.5*scale, width*prg*scale, height*scale, a, r, g, b)
end

function video.renderCircle(x, y, radius, alpha, r, g, b)
	video.renderSpriteState(HELPER_SPRITES.fontCircle, x, y, radius/50, 0, alpha, r, g, b)
end

function video.renderSpriteRectangle(x, y, w, h, alpha, r, g, b)
	video.renderSpriteStateFreeShape(HELPER_SPRITES.rectangle, x, y, x +w, y, x, y+h, x+w, y+h, alpha, r, g, b)
end


function video.renderCircleProgressBar(val, maxSlices, radius, x, y, scale, angle, alpha, r, g, b)
	for i=0, math.min(math.ceil(val), maxSlices) do
		local a = math.pi*2/maxSlices*i + angle - math.pi*0.5
		local nx,ny = x + math.cos(a)*radius, y + math.sin(a)*radius
		local stepAlpha = math.min(1,math.max(0,val - (i-1)))
		video.renderSpriteState(HELPER_SPRITES.hudLine, nx , ny, scale, a, alpha*stepAlpha,r*stepAlpha,g*stepAlpha,b*stepAlpha)
	end
end

function video.renderCircleNotches(maxSlices, radius, x, y, angle, alpha, r, g, b, width, length)
	for i=0, maxSlices do
		local a = math.pi*2/maxSlices*i + angle
		local nx,ny = x + math.cos(a)*radius, y + math.sin(a)*radius
		video.renderSpriteLine(nx, ny, nx + math.cos(a)*length, ny + math.sin(a)*length, alpha, r, g, b, nil, nil, width)
	end
end

function video.renderCircleProcess(val, maxSlices, radius, x, y, scale, angle, alpha, r, g, b)
	for i=0, maxSlices do
		local a = math.pi*2/maxSlices*i + angle - math.pi*0.5
		local nx,ny = x + math.cos(a)*radius, y + math.sin(a)*radius
		local diff = -math.angleDifference(a, math.pi*2/maxSlices*val*maxSlices + angle - math.pi*0.5)
		local stepAlpha = math.max(0,1- math.max(0,diff/math.pi))
		video.renderSpriteState(HELPER_SPRITES.hudLine, nx , ny, scale, a, alpha*stepAlpha,r*stepAlpha,g*stepAlpha,b*stepAlpha)
	end
end

function video.renderSpriteCircleLine(x,y, radius, w,h, steps, angle, alpha, r, g, b, width, animate)
	for i=0,steps-1 do
		local a1 = -math.pi*2/steps*i + angle
		local a2 = -math.pi*2/steps*(i+1) + angle
		local an = animate and math.max(0,(steps*animate-i)/steps) or 1
		video.renderSpriteLine(x+math.cos(a1)*radius*w,y+math.sin(a1)*radius*h,x+math.cos(a2)*radius*w,y+math.sin(a2)*radius*h, an*alpha, r, g, b, nil, nil, width, 1)
	end
end

function video.renderArcLineSprite(x,y, radius, arc, steps, angle, alpha, r, g, b, lineSprite, additive, width)
	local lineSprite = lineSprite or HELPER_SPRITES.line
	for i=0,steps-1 do
		local a1 = -arc/steps*i + angle + arc*0.5
		local a2 = -arc/steps*(i+1) + angle + arc*0.5
		
		local an1 = math.abs(math.angleDifference(angle, a1))/(arc*0.5)
		local an2 = math.abs(math.angleDifference(angle, a2))/(arc*0.5)
		local an = math.min(1,math.max(0,1-math.max(an1, an2)))
		
		video.renderSpriteStateFreeShape(lineSprite,
			x+math.cos(a1)*(radius+width*0.5),
			y+math.sin(a1)*(radius+width*0.5),
			x+math.cos(a2)*(radius+width*0.5),
			y+math.sin(a2)*(radius+width*0.5),
			x+math.cos(a1)*(radius-width*0.5),
			y+math.sin(a1)*(radius-width*0.5),
			x+math.cos(a2)*(radius-width*0.5),
			y+math.sin(a2)*(radius-width*0.5),
			alpha*an, r, g, b)
	end
end

function video.renderCircleArcSprite(sprite, x,y, radius, arc, steps, angle, alpha, r, g, b, width)
	for i=0,steps-1 do
		local a1 = -arc/steps*i + angle + arc*0.5
		local a2 = -arc/steps*(i+1) + angle + arc*0.5
		
		local an1 = math.abs(math.angleDifference(angle, a1))/(arc*0.5)
		local an2 = math.abs(math.angleDifference(angle, a2))/(arc*0.5)
		local an = math.min(1,math.max(0,1-math.max(an1, an2)))
		
		video.renderSpriteStateFreeShape(sprite,
			x+math.cos(a1)*(radius+width*0.5),
			y+math.sin(a1)*(radius+width*0.5),
			x+math.cos(a2)*(radius+width*0.5),
			y+math.sin(a2)*(radius+width*0.5),
			x+math.cos(a1)*(radius-width*0.5),
			y+math.sin(a1)*(radius-width*0.5),
			x+math.cos(a2)*(radius-width*0.5),
			y+math.sin(a2)*(radius-width*0.5),
			alpha*an, r, g, b)
	end
end

function video.renderCircleSprite(sprite, x,y, radius, steps, angle, alpha, r, g, b, width)
	for i=0,steps-1 do
		local a1 = -math.pi*2/steps*i + angle
		local a2 = -math.pi*2/steps*(i+1) + angle
		video.renderSpriteStateFreeShape(sprite,
			x+math.cos(a1)*(radius+width*0.5),
			y+math.sin(a1)*(radius+width*0.5),
			x+math.cos(a2)*(radius+width*0.5),
			y+math.sin(a2)*(radius+width*0.5),
			x+math.cos(a1)*(radius-width*0.5),
			y+math.sin(a1)*(radius-width*0.5),
			x+math.cos(a2)*(radius-width*0.5),
			y+math.sin(a2)*(radius-width*0.5),
			alpha, r, g, b)
	end
end

function video.renderSpriteRectangleOutline(x, y, x2, y2, alpha, r, g, b, lineSprite, additive, width)
	video.renderSpriteLine(x,y,x2,y, alpha, r, g, b, lineSprite, additive, width)
	video.renderSpriteLine(x,y2,x2,y2, alpha, r, g, b, lineSprite, additive, width)
	video.renderSpriteLine(x,y,x,y2, alpha, r, g, b, lineSprite, additive, width)
	video.renderSpriteLine(x2,y,x2,y2, alpha, r, g, b, lineSprite, additive, width)
end

function video.renderAngledSpriteLine(x1,y1,ang1, x2,y2, ang2, alpha, r, g, b, lineSprite, additive, width, animate)
	local lineSprite = lineSprite or HELPER_SPRITES.line
	local width = (width or 3)*0.5
	local animate = animate or 1
	if animate < 0 then
		animate = math.abs(animate)
		x1,y1,x2,y2 = math.reverseCoordinates(x1,y1,x2,y2)
	end
	local x2 = x1 + (x2-x1)*math.min(1,(animate or 1))
	local y2 = y1 + (y2-y1)*math.min(1,(animate or 1))
	if additive then
		video.setUseMaterialFor2d(true)
		video.setMaterial(additiveColorMaterial)
		video.renderSpriteStateFreeShape(lineSprite, x1+math.cos(ang1-math.pi*0.5)*width-math.cos(ang1)*width, y1+math.sin(ang1-math.pi*0.5)*width-math.sin(ang1)*width, x2+math.cos(ang2-math.pi*0.5)*width+math.cos(ang2)*width, y2+math.sin(ang2-math.pi*0.5)*width+math.sin(ang2)*width, x1+math.cos(ang1+math.pi*0.5)*width-math.cos(ang1)*width, y1+math.sin(ang1+math.pi*0.5)*width-math.sin(ang1)*width, x2+math.cos(ang2+math.pi*0.5)*width+math.cos(ang2)*width, y2+math.sin(ang2+math.pi*0.5)*width+math.sin(ang2)*width, alpha, r, g, b)
		video.setUseMaterialFor2d(false)
	else
		video.renderSpriteStateFreeShape(lineSprite, x1+math.cos(ang1-math.pi*0.5)*width, y1+math.sin(ang1-math.pi*0.5)*width, x2+math.cos(ang2-math.pi*0.5)*width, y2+math.sin(ang2-math.pi*0.5)*width, x1+math.cos(ang1+math.pi*0.5)*width, y1+math.sin(ang1+math.pi*0.5)*width, x2+math.cos(ang2+math.pi*0.5)*width, y2+math.sin(ang2+math.pi*0.5)*width, alpha, r, g, b)
	end
end

function video.renderSpriteLine(x1,y1,x2,y2,alpha, r, g, b, lineSprite, additive, width, animate)
	local lineSprite = lineSprite or HELPER_SPRITES.line
	local width = (width or 3)*0.5
	local animate = animate or 1
	if animate < 0 then
		animate = math.abs(animate)
		x1,y1,x2,y2 = math.reverseCoordinates(x1,y1,x2,y2)
	end
	local x2 = x1 + (x2-x1)*math.min(1,(animate or 1))
	local y2 = y1 + (y2-y1)*math.min(1,(animate or 1))
	local ang = math.angleBetweenPoints(x1,y1,x2,y2)
	if additive then
		video.setUseMaterialFor2d(true)
		video.setMaterial(additiveColorMaterial)
		video.renderSpriteStateFreeShape(lineSprite, x1+math.cos(ang-math.pi*0.5)*width-math.cos(ang)*width, y1+math.sin(ang-math.pi*0.5)*width-math.sin(ang)*width, x2+math.cos(ang-math.pi*0.5)*width+math.cos(ang)*width, y2+math.sin(ang-math.pi*0.5)*width+math.sin(ang)*width, x1+math.cos(ang+math.pi*0.5)*width-math.cos(ang)*width, y1+math.sin(ang+math.pi*0.5)*width-math.sin(ang)*width, x2+math.cos(ang+math.pi*0.5)*width+math.cos(ang)*width, y2+math.sin(ang+math.pi*0.5)*width+math.sin(ang)*width, alpha, r, g, b)
		video.setUseMaterialFor2d(false)
	else
		video.renderSpriteStateFreeShape(lineSprite, x1+math.cos(ang-math.pi*0.5)*width, y1+math.sin(ang-math.pi*0.5)*width, x2+math.cos(ang-math.pi*0.5)*width, y2+math.sin(ang-math.pi*0.5)*width, x1+math.cos(ang+math.pi*0.5)*width, y1+math.sin(ang+math.pi*0.5)*width, x2+math.cos(ang+math.pi*0.5)*width, y2+math.sin(ang+math.pi*0.5)*width, alpha, r, g, b)
	end
end


function video.renderSpriteLineArrow(x,y, x2, y2, arc, size, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x,y, x2, y2, alpha, r, g, b, lineSprite, additive, width, animate)
	local ang = math.angleBetweenPoints(x,y,x2,y2)
	video.renderSpriteLine(x2, y2, x2 + math.cos(ang+math.pi+arc*0.5)*size, y2 + math.sin(ang+math.pi+arc*0.5)*size , alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x2, y2, x2 + math.cos(ang+math.pi-arc*0.5)*size, y2 + math.sin(ang+math.pi-arc*0.5)*size , alpha, r, g, b, lineSprite, additive, width, animate)
end


function video.renderSpriteLineWithOutline(x1,y1,x2,y2,alpha, r, g, b, outAlpha, outR, outG, outB, lineSprite, additive, width, animate)
	video.renderSpriteLine(x1,y1,x2,y2,outAlpha, outR, outG, outB, lineSprite, additive, width*2, animate)
	video.renderSpriteLine(x1,y1,x2,y2,alpha, r, g, b, lineSprite, additive, width, animate)
end

local zBase = 2

function video.renderConnectionLines(s1, e1, s2, e2, x, y, w, h, slices, alpha, r, g, b, lineSprite, additive, width, animate)
	for i=1, slices do
		local prg = i/(slices+1)
		local pprg1 = prg
		if s1.z then
			local bias1 = (zBase + s1.z)/(zBase + e1.z)
			pprg1 = math.pow(prg, bias1)
		end
		local pprg2 = prg
		if s2.z then
			local bias2 = (zBase + s2.z)/(zBase + e2.z)
			pprg2 = math.pow(prg, bias2)
		end
		
		local an = (animate or 1)*(slices/3+1)-i/3
		if an <= 0 then
			break
		else
		video.renderSpriteLine(x + s1.x * pprg1*w + e1.x * (1-pprg1)*w, y + s1.y * pprg1*h + e1.y * (1-pprg1)*h,
						 x + s2.x * pprg2*w + e2.x * (1-pprg2)*w, y + s2.y * pprg2*h + e2.y * (1-pprg2)*h,
						 alpha, r, g, b, lineSprite, additive, width, math.min(1,an))
		end
	end
end	

function video.renderLineGrid(tl, tr, bl, br, x, y, w, h, wslices, hslices, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderConnectionLines(tl, tr, bl, br, x, y, w, h, wslices, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderConnectionLines(tl, bl, tr, br, x, y, w, h, hslices, alpha, r, g, b, lineSprite, additive, width, animate)
end

function video.renderLineBox(tl, tr, bl, br, x, y, w, h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + tl.x*w, y + tl.y*h, x + tr.x*w, y + tr.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + tr.x*w, y + tr.y*h, x + br.x*w, y + br.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + br.x*w, y + br.y*h, x + bl.x*w, y + bl.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + bl.x*w, y + bl.y*h, x + tl.x*w, y + tl.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
end
		
		
function video.renderPerspectiveGridCube(cube, x, y, w, h, slices, alpha, r, g, b, lineSprite, additive, width, animate)
	local animate = math.min(1,animate or 1)
	video.renderSpriteLine(x + cube.t.x*w, y + cube.t.y*h, x + cube.tr.x*w, y + cube.tr.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + cube.t.x*w, y + cube.t.y*h, x + cube.tl.x*w, y + cube.tl.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + cube.tr.x*w, y + cube.tr.y*h, x + cube.c.x*w, y + cube.c.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + cube.tl.x*w, y + cube.tl.y*h, x + cube.c.x*w, y + cube.c.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + cube.br.x*w, y + cube.br.y*h, x + cube.tr.x*w, y + cube.tr.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + cube.bl.x*w, y + cube.bl.y*h, x + cube.tl.x*w, y + cube.tl.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + cube.br.x*w, y + cube.br.y*h, x + cube.b.x*w, y + cube.b.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + cube.bl.x*w, y + cube.bl.y*h, x + cube.b.x*w, y + cube.b.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderSpriteLine(x + cube.b.x*w, y + cube.b.y*h, x + cube.c.x*w, y + cube.c.y*h, alpha, r, g, b, lineSprite, additive, width, animate)
	
	video.renderConnectionLines(cube.tr, cube.t, cube.c, cube.tl, x, y, w, h, slices, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderConnectionLines(cube.tl, cube.t, cube.c, cube.tr, x, y, w, h, slices, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderConnectionLines(cube.c, cube.tr, cube.b, cube.br, x, y, w, h, slices, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderConnectionLines(cube.c, cube.tl, cube.b, cube.bl, x, y, w, h, slices, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderConnectionLines(cube.c, cube.b, cube.tl, cube.bl, x, y, w, h, slices, alpha, r, g, b, lineSprite, additive, width, animate)
	video.renderConnectionLines(cube.c, cube.b, cube.tr, cube.br, x, y, w, h, slices, alpha, r, g, b, lineSprite, additive, width, animate)
end

video.colorStyles = {}

local colorStyles = video.colorStyles
colorStyles.intro = {
	getColor = function(linePrg)
		local a = linePrg*255
		local redding = 1-0.1*math.max(0,math.min(1,linePrg*2-1))
		local r = (linePrg*linePrg*0.5 + 0.5*math.easeOut(linePrg)*0.5)*255
		local g = (linePrg*0.5 + 0.5*redding*linePrg)*255
		local b = 0.5*redding*math.easeOut(linePrg)*255
		return a,r,g,b
	end
	}

colorStyles.dashboard = {
	getColor = function(linePrg)
		local a = linePrg*255
		local r = (linePrg*linePrg*0.5 + math.easeOut(linePrg)*0.5)*255*0.35
		local g = (linePrg)*255
		local b = math.easeOut(linePrg)*255*0.3
		return a,r,g,b
	end
	}

colorStyles.master = {
	getColor = function(linePrg)
		local a = linePrg*255
		local r = (linePrg*linePrg*0.5 + math.easeOut(linePrg)*0.5)*255*0.35
		local g = (linePrg)*255
		local b = math.easeOut(linePrg)*255*0.3
		return a,r,g,b
	end
	}


local defaultFonts = {sizes = {"small", "medium", "big"}, heights = {23, 40, 83}}
function video.renderFormattedText(lines, x,y, progress, lineFactor, fonts, enableContinue, time, colorStyle)
	local lineWaitIndex = 1
	local defaultAlignment = 0
	local defaultSize = 0
	local fonts = fonts or defaultFonts
	local newY = y
	for index, line in ipairs(lines) do
		local lineProgress = 1
		if progress then
			lineProgress = math.clamp(1 * (progress-lineFactor*(lineWaitIndex)), 0, 1)
		end
		
		local alpha, r, g, b = colorStyles[colorStyle or "intro"].getColor(lineProgress)
		
		if alpha > 0 then
			local newX = x
			if (line.alignment or defaultAlignment) == 0 then
				newX = newX - lines.width/2
			elseif (line.alignment or defaultAlignment) == 1 then
				newX = newX
			elseif (line.alignment or defaultAlignment) == 2 then
				newX = newX + lines.width/2
			end
			video.renderTextSprites(line.text, newX, newY, line.alignment or defaultAlignment, "../"..fonts.sizes[(line.size or defaultSize) +1] , alpha, r, g, b)
		end
		lineWaitIndex = lineWaitIndex+string.len(line.text)/20+0.35
		
		if (line.size or defaultSize) == 0 then
			newY = newY + fonts.heights[1]
		elseif (line.size or defaultSize) == 1 then
			newY = newY +  fonts.heights[2]
		elseif (line.size or defaultSize) == 2 then
			newY = newY +  fonts.heights[3]
		end
		
		if enableContinue and index == #lines then
			newY = newY + fonts.heights[1]/2
			local continueAlpha = 255
			if progress then
				continueAlpha = math.clamp((128+127*math.easeOut(math.abs(math.sin((time or 2)*math.pi/2)))) * math.min(1,(progress-lineFactor*(lineWaitIndex+1))), 0, 255)
			end
			local redding = 1-0.1*math.max(0,math.min(1,alpha/255*2-1))
			if continueAlpha > 0 then
				video.renderTextSprites(localize.get("press_to_continue"), x, newY, 1,  "../"..fonts.sizes[1], continueAlpha, (continueAlpha/255)*(continueAlpha/255)*255*0.5 + 0.5*math.easeOut(continueAlpha/255)*255*0.5, continueAlpha*0.5 + 0.5*redding*continueAlpha, 0.5*redding*math.easeOut(continueAlpha/255)*255)
			end
		end
	end
end

local function findParam(text, start)
	local par = nil
	local leng = 0
	local paramFound = false
	for i=start,string.len(text) do
		if string.sub(text, i,i) == ">" then
			return par, leng
		else
			if string.sub(text, i,i) == "=" then
				paramFound = true
			else
				if paramFound and string.sub(text, i,i) ~= "=" then
					par = (par or "").. string.sub(text, i,i)
				end
			end
			leng = leng +1
		end
	end
	return nil, leng
end
local function findNextCode(text, start)
	local leng = 0
	for i=start,string.len(text) do
		if string.sub(text, i,i) == "<" then
			return leng
		else			
			leng = leng +1
		end
	end
	return leng
end

function video.renderShadowedSpriteState(sprite, x , y, scale, angle, alpha,r,g,b, flipped)
	video.renderSpriteState(sprite, x+1 , y+1, scale, angle, alpha,0,0,0, flipped)
	video.renderSpriteState(sprite, x , y, scale, angle, alpha,r,g,b, flipped)
end


function video.renderShadowedTextSprites(text, x, y, align, customFont, alpha, r, g, b, prg, scale)
	video.renderTextSprites(text, x+1, y+1, align, customFont, alpha, 0, 0, 0, prg, scale)
	video.renderTextSprites(text, x, y, align, customFont, alpha, r, g, b, prg, scale)
end

function video.renderTextSprites(text, x, y, align, customFont, alpha, r, g, b, prg, scale)
	if not FONTS[customFont] then
		video.renderText(text, x, y, align, customFont, alpha or 255, r or 255, g or 255, b or 255)
		return
	end
	
	local text = text or ""
	local scale = scale or 1
	
	local w,h = video.getTextSpritesSize(text, customFont, scale)
	local font = customFont	
	local x = x - w*align/2
	local len = math.min((prg or 1)*string.len(text), string.len(text))
	local dr,dg,db = r,g,b
	local drawing = 1
	local inverse = false
	local button = false
	local thumb = false
	local trendered = false
	local scanning = false
	local first = false
	local arrow = nil
	local stick = false
	local extraScale = nil
	for i=1,len do
		local char = string.char(string.byte(text, drawing))
		if char == "<" then
			scanning = true
			drawing = drawing +1
			first = true
		elseif char == ">" then
			scanning = false
			drawing = drawing +1
		else
			if scanning then
				local cmd = string.char(string.byte(text, drawing))
				drawing = drawing +1
				if first then
					if cmd == "c" then
						local col, extra = findParam(text, drawing)
						if col then
							dr,dg,db = COLORS[col].r,COLORS[col].g,COLORS[col].b
						else
							dr,dg,db = r,g,b
						end
						drawing = drawing + extra
					elseif cmd == "S" then
						local angle, extra = findParam(text, drawing)
						if angle then
							arrow = tonumber(angle)
							stick = true
							drawing = drawing + extra-1
							scanning = false
						else
							stick = true
							scanning = false
						end
					elseif cmd == "R" then
						thumb = false
						inverse = false
						button = false
						stick = false
						font = customFont
						extraScale = nil
					elseif cmd == "I" then
						inverse = true
					elseif cmd == "B" then
						button = true
					elseif cmd == "T" then
						thumb = true
						trendered = false
					elseif cmd == "A" then
						local angle, extra = findParam(text, drawing)
						arrow = tonumber(angle)
						drawing = drawing + extra-1
						scanning = false
					end
				end
				first = false
			end
			if not scanning then
				if FONTS[font][string.byte(text, drawing)] then			
					local letter = FONTS[font][string.byte(text, drawing)]
					if letter.sprite then
						local rr, rg, rb = dr,dg,db
						if thumb then
							if not trendered then
								local totw = 0
								local len = findNextCode(text, drawing)
								for l=drawing, drawing+len-1 do
									local let = FONTS[customFont][string.byte(text, l)]
									totw = totw + let.w*scale
								end
								video.renderSpriteStateFreeShape(HELPER_SPRITES.fontRectangle, x -totw*0.1, y - letter.h*scale*0.2, x + totw*1.1, y- letter.h*scale*0.2, x -totw*0.1, y+letter.h*scale *1.1, x + totw*1.1, y+letter.h*scale *1.1, alpha, dr*0.5,dg*0.5,db*0.5)
								trendered = true
							end
							rr, rg, rb = math.min(255,dr*1.5),math.min(255,dg*1.5),math.min(255,db*1.5)
						elseif button then
							video.renderSpriteState(HELPER_SPRITES.fontCircle, x + letter.w/2*scale, y + letter.h/2.3*scale, (math.max(letter.w,letter.h))/90*scale, 0, alpha, dr*0.5,dg*0.5,db*0.5)
							rr, rg, rb = math.min(255,dr*1.5),math.min(255,dg*1.5),math.min(255,db*1.5)
						elseif stick then
							letter = FONTS[font][48]
							
							local ofx, ofy = 0,0
							if arrow then
								ofx, ofy = math.cos(arrow*math.pi*0.5 + math.pi)*letter.w/5*scale, math.sin(arrow*math.pi*0.5 + math.pi)*letter.w/5*scale
							else
								scale = scale*1.1
							end
							x = x + letter.w/4*scale
							video.renderSpriteState(HELPER_SPRITES.fontCircleGradient, x + letter.w/2*scale + ofx, y + letter.h/2*scale, (letter.w+letter.h)/180*scale, 0, alpha, dr*0.75,dg*0.75,db*0.75)
							video.renderSpriteState(HELPER_SPRITES.fontCircleGradient, x + letter.w/2*scale + ofx, y + letter.h/2*scale, (letter.w+letter.h)/225*scale, math.pi, alpha, dr*0.65,dg*0.65,db*0.65)
							for i=0,3 do
								video.renderSpriteState(HELPER_SPRITES.fontCircleGradient, x + letter.w/2*scale + math.cos(i*math.pi/2)*letter.w/3*scale+ ofx, y + letter.h/2*scale + math.sin(i*math.pi/2)*letter.w/3*scale, (letter.w+letter.h)/2100*scale, math.pi*0.5, alpha, dr*0.65,dg*0.65,db*0.65)
							end
							
							rr, rg, rb = math.min(255,dr*1.5),math.min(255,dg*1.5),math.min(255,db*1.5)
						elseif inverse then
							video.renderRectangle(x, y, letter.w*scale, letter.h*scale, alpha, dr,dg,db)
							rr, rg, rb = dr*0.5,dg*0.5,db*0.5
						end
						if arrow then
							if stick then
								local ofx, ofy = math.cos(arrow*math.pi*0.5 + math.pi)*letter.w/5*scale, math.sin(arrow*math.pi*0.5 + math.pi)*letter.w/5*scale
								video.renderSpriteState(HELPER_SPRITES.fontArrow, x+ofx + letter.w/2*scale + math.cos(arrow*math.pi/2)*letter.w/1.2*scale, y + letter.h/2*scale + math.sin(arrow*math.pi/2)*letter.w/1.2*scale, (letter.w+letter.h)/500*scale, arrow*math.pi/2, alpha, math.min(255,rr*1.5),math.min(255,rg*1.5),math.min(255,rb*1.5))
								extraScale = 0.6
								stick = false
								x = x + ofx + letter.w/2*scale*extraScale - letter.w/4*scale*extraScale
							else
								local ofx, ofy = 0,0
								video.renderSpriteState(HELPER_SPRITES.fontArrow, x + letter.w/2*scale , y + letter.h/2*scale , (letter.w+letter.h)/250*scale, arrow*math.pi/2, alpha, math.min(255,rr*1.5),math.min(255,rg*1.5),math.min(255,rb*1.5))
							end
							arrow = nil
						elseif stick then
							extraScale = 0.8
							stick = false
							x = x + (letter.w*scale*0.5 - letter.w*scale*extraScale*0.5)
						else
							if extraScale then								
								video.renderSpriteState(letter.sprite, x + (letter.w*0.5*scale - extraScale*letter.w*scale*0.5), y+ (letter.h*0.5*scale - extraScale*letter.h*scale*0.5), scale*extraScale, 0, alpha, rr, rg, rb)
								x = x + letter.w*scale*extraScale
							else
								video.renderSpriteState(letter.sprite, x, y, scale, 0, alpha, rr, rg, rb)
							end
							x = x + letter.w*scale
						end
					else
						x = x + letter.w*scale
					end
					
				end
				drawing = drawing +1
			end
		end
		if drawing > len then
			break
		end
	end
end

function video.getTextSpritesSize(text, customFont, scale)
	if not FONTS[customFont] then
		return video.getTextSize(text, customFont)
	end
	local text = text or ""
	local w,h = 0,0
	local scale = scale or 1
	local drawing = 1
	for i=1, string.len(text) do
		local char = string.char(string.byte(text, drawing))
		if char == "<" then
			scanning = true
			drawing = drawing +1
		elseif char == ">" then
			scanning = false
			drawing = drawing +1
		else
			if not scanning then
				if string.byte(text, drawing) and FONTS[customFont][string.byte(text, drawing)] then
					w = w + FONTS[customFont][string.byte(text, drawing)].w
					h = math.max(h,FONTS[customFont][string.byte(text, drawing)].h)
				end
				drawing = drawing +1
			else
				local cmd = string.char(string.byte(text, drawing))				
				if cmd == "S" then
					w = w + FONTS[customFont][string.byte(text, drawing)].w
				end
				drawing = drawing +1
			end
		end
	end	
	return w*scale,h*scale
end

function video.renderControllerIcon(controller, x, y, scale, a, r, g, b)
	video.renderSpriteState(controller:getIconSprite(), x, y, scale, 0, a, r, g, b)
	local id = controller:getDeviceId()
	if id then
		video.renderTextSprites(id, x- 75*scale, y+fonts.alignY("medium"), 2, "medium", a, r,g,b)
	end
end

function video.renderAdvancedText(lines, x,y, progress, colorStyle, a, r, g, b)
	local lineWaitIndex = 1
	local defaultAlignment = 0
	local defaultSize = 0
	local newY = y
	local font = "small"
	
	for index, line in ipairs(lines) do
		local lineProgress = 1
		if progress then
			lineProgress = math.clamp(1 * (progress-(lineWaitIndex)), 0, 1)
		end
		local alpha, r, g, b = a or 255, r or 255, g or 255, b or 255
		if colorStyle then
			alpha, r, g, b = colorStyles[colorStyle or "intro"].getColor(lineProgress)
		end
		
		if alpha > 0 then
			local newX = x
			if (line.alignment or defaultAlignment) == 0 then
				newX = newX - lines.width/2
			elseif (line.alignment or defaultAlignment) == 1 then
				newX = newX - line.width/2
			elseif (line.alignment or defaultAlignment) == 2 then
				newX = newX + lines.width/2 - line.width
			end

			local moveX = 0
			for i,segment in ipairs(line.segments) do
				font = fonts.sizes[segment.size]
				video.renderTextSprites(segment.text, newX+moveX, newY + line.height - segment.height, 0, font , alpha, r, g, b, lineProgress)
				lineWaitIndex = lineWaitIndex+video.getTextSpritesSize(text, font)/20+0.35
				moveX = moveX + segment.width
			end
		end
		
		newY = newY + line.height
	end
end

function video.getSpriteCorners(sprite, x, y, widthScale, heightScale, scale, angle, flipped)
	local scx, scy = video.getSpriteStateSize(sprite)
	local orcX, orcY = video.getSpriteStateHotspot(sprite)
	
	local rightSize = scx-orcX
	local bottomSize = scy-orcY
	local leftSize = scx-rightSize
	local topSize = scy-bottomSize

	leftSize  = leftSize * widthScale * scale
	topSize   = topSize * heightScale * scale
	rightSize = rightSize * widthScale * scale
	bottomSize= bottomSize * heightScale * scale
	--local left = 

	local leftX, leftY = math.cos(angle+math.pi)*leftSize, math.sin(angle+math.pi)*leftSize
	local topX, topY = math.cos(angle-math.pi*0.5)*topSize, math.sin(angle-math.pi*0.5)*topSize
	local rightX, rightY = math.cos(angle)*rightSize, math.sin(angle)*rightSize
	local bottomX, bottomY = math.cos(angle+math.pi*0.5)*bottomSize, math.sin(angle+math.pi*0.5)*bottomSize

	local x1 = x + leftX + topX
	local y1 = y + leftY + topY
	local x2 = x + rightX + topX
	local y2 = y + rightY + topY
	local x3 = x + leftX + bottomX
	local y3 = y + leftY + bottomY
	local x4 = x + rightX + bottomX
	local y4 = y + rightY + bottomY
	
	if flipped then
		return x2, y2, x1, y1, x4, y4, x3, y3
	else
		return x1, y1, x2, y2, x3, y3, x4, y4
	end
end


function video.renderScaledSpriteState(sprite, x, y, widthScale, heightScale, scale, angle, alpha, r, g, b, flipped)
	local x1,y1,x2,y2,x3,y3,x4,y4 = video.getSpriteCorners(sprite, x, y, widthScale, heightScale, scale, angle, flipped)
	video.renderSpriteStateFreeShape(sprite, x1,y1,x2,y2,x3,y3,x4,y4, alpha, r, g, b)
end


function video.renderAngledSpriteLineShaped(x1,y1,ang1, x2,y2, ang2, alpha, r, g, b, lineSprite, width, width2)
	local lineSprite = lineSprite or SPRITES.line
	local width = (width or 3)*0.5
	local width2 = (width2 or 3)*0.5
	video.renderSpriteStateFreeShape(lineSprite, x1+math.cos(ang1-math.pi*0.5)*width, y1+math.sin(ang1-math.pi*0.5)*width, x2+math.cos(ang2-math.pi*0.5)*width2, y2+math.sin(ang2-math.pi*0.5)*width2, x1+math.cos(ang1+math.pi*0.5)*width, y1+math.sin(ang1+math.pi*0.5)*width, x2+math.cos(ang2+math.pi*0.5)*width2, y2+math.sin(ang2+math.pi*0.5)*width2, alpha, r, g, b)
end