ffibuild.Build(
	{
		name = "vtflib",
		addon = vfs.GetAddonFromPath(SCRIPT_PATH),
		linux = [[
			FROM ubuntu:20.04

			ARG DEBIAN_FRONTEND=noninteractive
			ENV TZ=America/New_York

			RUN apt-get update
			RUN apt-get install -y git cmake g++
		
			WORKDIR /src
			RUN git clone https://github.com/CapsAdmin/VTFLib.git --depth 1 .
			RUN cmake . -DUSE_LIBTXC_DXTN=0 && make --jobs 32
		]],
		c_source = [[
		typedef struct tagSVTFImageFormatInfo {} SVTFImageFormatInfo;
		#include "VTFLib.h"
		#include "VTFWrapper.h"
		#include "VMTWrapper.h"
	]],
		gcc_flags = "-I./src",
		process_header = function(header)
			local meta_data = ffibuild.GetMetaData(header)
			return meta_data:BuildMinimalHeader(
				function(name)
					return name:find("^vl")
				end,
				function(name)
					return true
				end,
				true,
				true
			)
		end,
		build_lua = function(header, meta_data)
			local s = [=[
				local ffi = require("ffi")
				local CLIB = assert(ffi.load("vtflib"))
				ffi.cdef([[]=] .. header .. [=[]])
			]=]
			s = s .. "library = " .. meta_data:BuildLuaFunctions("^vl(.+)")
			s = s .. "library.e = " .. meta_data:BuildLuaEnums(nil, nil, nil, "^enum tagVTF")
			s = s .. [[


		local function float(high, low)
			local b = low
			local sign = 1
			if b >= 128 then
				sign = -1
				b = b - 128
			end
			local exponent = bit.rshift(b, 2) - 15
			local mantissa = bit.band(b, 3) / 4

			b = high
			mantissa = mantissa + b / 4 / 256

			if mantissa == 0 and exponent == -15 then
				return 0
			else
				return (mantissa + 1) * math.pow(2, exponent) * sign
			end
		end

		local function half_buffer_to_float_buffer(length, buffer)
			local out = ffi.new("float[?]", length)
			local i2 = 0
			for i = 1, length * 2, 2 do
				i = i -1
				out[i2] = float(buffer[i + 0], buffer[i + 1])
				i2 = i2 + 1
			end
			return ffi.cast("uint8_t *", out)
		end

		local function cleanup(vtf_material, vtf_image)
			library.ImageDestroy()
			library.MaterialDestroy()
			library.DeleteMaterial(vtf_material[0])
			library.DeleteImage(vtf_image[0])
		end

		local function get_error()
			return ffi.string(library.GetLastError())
		end

		function library.LoadImage(data, path_hint)
			local vtf_image = ffi.new("unsigned int[1]")
			if library.CreateImage(vtf_image) == 0 then return false, "failed to create image: " .. get_error() end
			if library.BindImage(vtf_image[0]) == 0 then return false, "failed to bind image: " .. get_error() end

			-- dummy material
			local vtf_material = ffi.new("unsigned int[1]")
			if library.CreateMaterial(vtf_material) == 0 then return false, "failed to create material: " .. get_error() end
			if library.BindMaterial(vtf_material[0]) == 0 then return false, "failed to bind material: " .. get_error() end

			if library.ImageLoadLump(ffi.cast("void *", data), #data, 0) == 0 then
				return nil, "unknown format"
			end

			local width = library.ImageGetWidth()
			local height = library.ImageGetHeight()
			local internal_format = library.ImageGetFormat()
			local conversion_format = internal_format
			local buffer

			do
				local internal_buffer = library.ImageGetData(0, 0, 0, 0)
				local info = library.ImageGetImageFormatInfo(internal_format)

				if info.bIsCompressed == 1 then
					if info.uiAlphaBitsPerPixel > 0 then
						conversion_format = library.e.IMAGE_FORMAT_RGBA8888
					else
						conversion_format = library.e.IMAGE_FORMAT_RGB888
					end
				end

				local size = library.ImageComputeImageSize(width, height, 1, 1, conversion_format)
				buffer = ffi.new("uint8_t[?]", size)

				if library.ImageConvert(internal_buffer, buffer, width, height, internal_format, conversion_format) == 0 then
					cleanup(vtf_material, vtf_image)
					return false, "conversion from " .. tostring(internal_format) .. " to " .. tostring(conversion_format) .. " failed: " .. get_error()
				end
			end

			local format = "rgba"
			local type = "unsigned_byte"

			if conversion_format == library.e.IMAGE_FORMAT_RGBA8888 then
				format = "rgba"
			elseif conversion_format == library.e.IMAGE_FORMAT_RGB888 then
				format = "rgb"
			elseif conversion_format == library.e.IMAGE_FORMAT_BGRA8888 then
				if path_hint and path_hint:find(".+/[^/]-hdr[^/]-%.vtf") then
					format = "bgr"
					type = "float"

					local new = ffi.new("float[?][3]", width * height)
					local i2 = 0
					for i = 1, (width * height) * 4, 4 do
						i = i - 1
						local r = buffer[i + 0]
						local g = buffer[i + 1]
						local b = buffer[i + 2]
						local a = buffer[i + 3]

						r = (r * (a * 16)) / 262144
						g = (g * (a * 16)) / 262144
						b = (b * (a * 16)) / 262144

						new[i2][0] = r
						new[i2][1] = g
						new[i2][2] = b
						i2 = i2 + 1
					end
					buffer = new
				else
					format = "bgra"
				end
			elseif conversion_format == library.e.IMAGE_FORMAT_BGR888 then
				format = "bgr"
			elseif conversion_format == library.e.IMAGE_FORMAT_RGBA32323232F then
				format = "rgba"
				type = "float"
			elseif conversion_format == library.e.IMAGE_FORMAT_RGB323232F then
				format = "rgb"
				type = "float"
			elseif conversion_format == library.e.IMAGE_FORMAT_RGBA16161616F then
				format = "rgba"
				type = "float"
				buffer = half_buffer_to_float_buffer((width * height) * 4, buffer)
			elseif conversion_format == library.e.IMAGE_FORMAT_RGB161616F then
				format = "rgb"
				type = "float"
				buffer = half_buffer_to_float_buffer((width * height) * 4, buffer)
			else
				wlog("unhandled image format: %s", conversion_format)
			end

			cleanup(vtf_material, vtf_image)

			return {
				buffer = buffer,
				width = width,
				height = height,
				format = format,
				type = type,
			}
		end
		]]
			s = s .. "library.clib = CLIB\n"
			s = s .. "return library\n"
			return s
		end,
	}
)