include("shared.lua")

local font = "3D2DText_CV_"

local textscreens = {}
function ENT:Initialize()
	net.Start("3d2dtexts_download")
		net.WriteEntity(self)
	net.SendToServer()
end

function ENT:Draw()
end

function ENT:DrawTranslucent()
end

local product
local function IsInFront(local_ply, pos, shoot_pos, direction)
	product = (pos.x - shoot_pos.x) * direction.x + (pos.y - shoot_pos.y) * direction.y + (pos.z - shoot_pos.z) * direction.z
	return product < 0
end

local cam, surface, render = cam, surface, render
local local_ply, tpos, eye_pos, ind, text
local function DrawTextscreen(local_ply, pos, camangle, index, size)
	cam.Start3D2D(pos, camangle, 0.1)
		render.PushFilterMin(TEXFILTER.ANISOTROPIC)
		for i=1, size do
			ind = index[i]
			text = ind.text
			if text then
				surface.SetFont(ind.font)
				surface.SetTextPos(ind.posx, ind.posy)
				surface.SetTextColor(ind.color)
				surface.DrawText(text)
			end
		end
		render.PopFilterMin()
	cam.End3D2D()
end

local drawscreens = {}

local reg = debug.getregistry()
local IsDormant = reg.Entity.IsDormant
local GetNoDraw = reg.Entity.GetNoDraw
local IsSolid = reg.Entity.IsSolid
local GetPos = reg.Entity.GetPos
local EyePos = reg.Entity.EyePos
local DistToSqr = reg.Vector.DistToSqr
local GetAngles = reg.Entity.GetAngles
local Up = reg.Angle.Up
local GetVehicle = reg.Player.GetVehicle
local IsValid_ent = reg.Entity.IsValid
local GetShootPos = reg.Player.GetShootPos

local function Re_3D2DText(ent)
	local local_ply

	if ent then
		if IsDormant(ent) or GetNoDraw(ent) then return end
		if !ent:GetPersisted() and !IsSolid(ent) then return end

		tpos = GetPos(ent)
		local_ply = local_ply or LocalPlayer()
		eye_pos = EyePos(local_ply)

		if DistToSqr(tpos, eye_pos) <= 1000000 then
			table.insert(drawscreens, ent)
		end
	else
		drawscreens = {}

		for ent in pairs(textscreens) do
			if ent != NULL then
				if IsDormant(ent) or GetNoDraw(ent) then continue end
				if !ent:GetPersisted() and !IsSolid(ent) then continue end

				tpos = GetPos(ent)
				local_ply = local_ply or LocalPlayer()
				eye_pos = EyePos(local_ply)

				if DistToSqr(tpos, eye_pos) <= 1000000 then
					table.insert(drawscreens, ent)
				end
			else
				textscreens[ent] = nil
			end
		end
	end
end

timer.Create("3D2D_TextscreenDraw", 0.5, 0, function()
	Re_3D2DText()
end)

local ang, up, pos, index, size, veh
local function DrawTextscreens()
	for _, ent in ipairs(drawscreens) do
		if ent != NULL then
			local_ply = local_ply or LocalPlayer()

			tpos = GetPos(ent)
			ang = GetAngles(ent)
			up = Up(ang)
			pos = tpos + up
			index = textscreens[ent]
			size = index.tsize
			veh = GetVehicle(local_ply)

			if IsValid_ent(veh) then
				veh = veh:GetThirdPersonMode()
				if veh then
					DrawTextscreen(local_ply, pos, ang, index, size)
					ang:RotateAroundAxis(ang:Right(), 180)
					DrawTextscreen(local_ply, pos, ang, index, size)
				end
			end

			if IsInFront(local_ply, pos, GetShootPos(local_ply), up) then
				DrawTextscreen(local_ply, pos, ang, index, size)
			else
				ang:RotateAroundAxis(ang:Right(), 180)
				DrawTextscreen(local_ply, pos, ang, index, size)
			end
		end
	end
end
hook.Add("PostDrawTranslucentRenderables", "3D2DText_DrawTextscreens", DrawTextscreens)

local fonts_table = {}
local function CreateFont(size)
	if !fonts_table[size] then
		fonts_table[size] = true
		surface.CreateFont(font..size, {font = "coolvetica", size = size * 2.4, antialias = true, shadow = true})
	end
end

net.Receive("3d2dtexts_update", function()
	local ent = net.ReadEntity()
	if IsValid(ent) and ent:GetClass() == "3d2dtext" then
		local ent_tbl = net.ReadTable()
		local drawtable = {}
		for i=1, #ent_tbl do
			local index = ent_tbl[i]
			local text = index.text
			if text and string.Trim(text) != "" then
				table.insert(drawtable, ent_tbl[i])
			end
		end
		local cur_height = 0
		local total_height = 0
		local drawtable_cnt = #drawtable
		for i=1, drawtable_cnt do
			local index = drawtable[i]
			drawtable[i] = {}
			drawtable[i].text = index.text
			drawtable[i].color = index.color
			drawtable[i].font = font..math.Clamp(index.size, 20, 100)
			CreateFont(index.size)
			index = drawtable[i]
			surface.SetFont(index.font)
			local wide, height = surface.GetTextSize(index.text)
			drawtable[i].wide = wide
			drawtable[i].height = height
			total_height = total_height + height
		end
		for i=1, drawtable_cnt do
			drawtable[i].posx = math.ceil(-drawtable[i].wide / 2)
			drawtable[i].posy = -(total_height / 2) + cur_height
			cur_height = cur_height + drawtable[i].height
		end
		drawtable.tsize = drawtable_cnt
		textscreens[ent] = drawtable
	end
end)