-- (c) Copyright 2006 Cameron Knight. All Rights Reserved. 
-- This converts data from Blizzard's WMOs into a format usable by Cartographer-InstanceMaps
--
-- You must have md5translate.trs in the current directory as well as all the root WMO files for the dungeons.

local function packint(num, bits, unsigned)
	if not bits then
		bits = 32
	end
	local s = ""
	if not unsigned and num < 0 then
		num = num + 2^bits
	end
	for i = 1, bits/8 do
		local n = math.floor(num / 256^(i-1)) % 256
		s = s .. string.char(n)
	end
	return s
end

local function unpackint(str, bits, unsigned)
if not bits then
	bits = 32
end
	local num = 0
	for i = 1, bits/8 do
		num = num + string.byte(str, i) * 256^(i-1)
	end
	if not unsigned and num >= 2^(bits-1) then
		num = num - 2^(bits-1)
	end
	return num
end

local inf = 1/0
local function packfloat(num, double)
	local negative = false
	if num == 0 then
		if 1/num < 0 then
			return string.char(0, 0, 0, 128)
		end
		return string.char(0, 0, 0, 0)
	else
		negative = num < 0
	end
	if negative then
		num = -num
	end
	local mantissa, exponent = math.frexp(num)
	while mantissa < 1 do
		mantissa, exponent = mantissa*2, exponent - 1
	end
	mantissa = mantissa - 1
	local bits = { negative and 1 or 0 }
	exponent = exponent + (double and 1023 or 127)
	for i = 2, double and 12 or 9 do
		table.insert(bits, math.floor(exponent / 2^((double and 12 or 9)-i))%2)
	end
	for i = double and 13 or 10, double and 64 or 32 do
		mantissa = mantissa * 2
		local a = mantissa > 1
		if a then
			mantissa = mantissa - 1
			table.insert(bits, 1)
		else
			table.insert(bits, 0)
		end
	end
	local s = ""
	for i = 0, #bits-1, 8 do
		local n = 0
		for j = 1, 8 do
			n = n*2 + bits[i+j]
		end
		s = string.char(n) .. s
	end
	return s
end

local function unpackfloat(str, double)
	local bits = {}
	for j = 1, double and 8 or 4 do
		local a = string.byte(str, double and 9-j or 5-j)
		for i = 0, 7 do
			table.insert(bits, math.floor(a/2^(7-i))%2)
		end
	end
	local negative = bits[1] == 1 and -1 or 1
	local exponent = 0
	for i = 2, double and 12 or 9 do
		exponent = exponent*2 + bits[i]
	end
	exponent = exponent - (double and 1023 or 127)
	local mantissa = 1
	for i = double and 13 or 10, double and 64 or 32 do
		mantissa = mantissa + bits[i]*(0.5^(double and i-12 or i-9))
	end
	return negative * 2^exponent * mantissa
end

local function unpackstruct(str, struct)
	local t = {}
	local current = 1
	for i,v in ipairs(struct) do
		if not v.float and not v.double then
			local bits = v.bits
			local fin = current + (bits/8)
			t[v.name] = unpackint(string.sub(str, current, fin - 1), bits, v.unsigned)
			current = fin
		else
			local double = v.double
			local fin = current + (double and 8 or 4)
			t[v.name] = unpackfloat(string.sub(str, current, fin - 1), double)
			current = fin
		end
	end
	return t
end

local function struct_sizeof(struct)
	local num = 0
	for i,v in ipairs(struct) do
		if v.float then
			num = num + 4
		elseif v.double then
			num = num + 8
		else
			num = num + v.bits/8
		end
	end
	return num
end

local function tobits(num)
	local t = {}
	for i = 0, 31 do
		table.insert(t, math.floor(num*0.5^i) % 2)
	end
	return table.concat(t)
end

local SMOHeader = {
	{name = 'nTextures', bits=32, unsigned = true },
	{name = 'nGroups', bits=32, unsigned = true},
	{name = 'nPortals', bits=32, unsigned = true},
	{name = 'nLights', bits=32, unsigned = true},
	{name = 'nDoodadNames', bits=32, unsigned = true},
	{name = 'nDoodadDefs', bits=32, unsigned = true},
	{name = 'nDoodadSets', bits=32, unsigned = true},
	{name = 'ambColor', bits=32, unsigned = true},
	{name = 'wmoID', bits=32, unsigned = true},
	{name = 'bbcorner1_1', float = true},
	{name = 'bbcorner1_2', float = true},
	{name = 'bbcorner1_3', float = true},
	{name = 'bbcorner2_1', float = true},
	{name = 'bbcorner2_2', float = true},
	{name = 'bbcorner2_3', float = true},
	{name = 'unk', bits=32, unsigned = true},
}

local MOGP = {
	{name = 'gName', bits=32, unsigned = true},
	{name = 'gNameDesc', bits=32, unsigned = true},
	{name = 'flags', bits=32, unsigned = true},
	{name = 'bbcorner1_1', float=true},
	{name = 'bbcorner1_2', float=true},
	{name = 'bbcorner1_3', float=true},
	{name = 'bbcorner2_1', float=true},
	{name = 'bbcorner2_2', float=true},
	{name = 'bbcorner2_3', float=true},
	{name = 'moprIndex', bits=16, unsigned=true},
	{name = 'nItems', bits=16, unsigned=true},
	{name = 'nBatchesA', bits=16, unsigned=true},
	{name = 'nBatchesB', bits=16, unsigned=true},
	{name = 'nBatchesC', bits=32, unsigned=true},
	{name = 'fog1', bits=8, unsigned=true},
	{name = 'fog2', bits=8, unsigned=true},
	{name = 'fog3', bits=8, unsigned=true},
	{name = 'fog4', bits=8, unsigned=true},
	{name = 'unk', bits=32, unsigned=true},
	{name = 'groupID', bits=32, unsigned=true},
	{name = 'unk2', bits=32, unsigned=true},
	{name = 'unk3', bits=32, unsigned=true},
}

local MOGI = {
	{name = 'flags', bits=32, unsigned = true},
	{name = 'bbcorner1_1', float=true},
	{name = 'bbcorner1_2', float=true},
	{name = 'bbcorner1_3', float=true},
	{name = 'bbcorner2_1', float=true},
	{name = 'bbcorner2_2', float=true},
	{name = 'bbcorner2_3', float=true},
	{name = 'nameOffset', bits=32}
}

local MLIQ = {
	{name = 'xverts', bits=32, unsigned = true},
	{name = 'yverts', bits=32, unsigned = true},
	{name = 'xtiles', bits=32, unsigned = true},
	{name = 'ytiles', bits=32, unsigned = true},
	{name = 'coord_1', float=true},
	{name = 'coord_2', float=true},
	{name = 'coord_3', float=true},
	{name = 'matID', bits=16, unsigned = true}
}

local maps = {
	{
		name = "Ahn'Qiraj",
		data = "Ahn_Qiraj",
	},
	{
		name = "Blackfathom Deeps",
		data = "Blackfathom_instance"
	},
	{
		name = "Blackwing Lair",
		data = "Blackrock_upper_guild"
	},
	{
		name = "Blackrock Depths",
		data = "Blackrock_lower_instance"
	},
	{
		name = "Dire Maul",
		data = "KL_Diremaul_Instance"
	},
	{
		name = "Gnomeregan",
		data = "KZ_Gnomeragon_Instance"
	},
	{
		name = "Maraudon",
		data = "KL_Maraudon_instance01"
	},
	{
		name = "Molten Core",
		data = "Blackrock_lower_guild"
	},
	{
		name = "Naxxramas",
		data = "Stratholme_raid"
	},
	{
		name = "Onyxia's Lair",
		data = "KL_OnyxiasLair_B"
	},
	{
		name = "Ragefire Chasm",
		data = "LavaDungeon"
	},
	{
		name = "Razorfen Downs",
		data = "RazorfenDowns_instance"
	},
	{
		name = "Razorfen Kraul",
		data = "RazorfenKraul_instance"
	},
	{
		name = "Shadowfang Keep",
		data = "LD_ShadowFangInterior",
	},
	{
		name = "Stratholme",
		data = "Stratholme",
	},
	{
		name = "The Temple of Atal'Hakkar",
		data = "AZ_SunkenTemple_Instance"
	},
	{
		name = "The Deadmines",
		data = "AZ_Deadmines_B"
	},
	{
		name = "The Stockade",
		data = "StormwindJail"
	},
	{
		name = "Uldaman",
		data = "KZ_Uldaman_B"
	},
	{
		name = "Upper Blackrock Spire",
		data = "Blackrock_upper_instance"
	},
	{
		name = "Wailing Caverns",
		data = "wailingcaverns_instance"
	},
}

print("MapData = {")
for i,v in ipairs(maps) do
	local name = v.name
	local map = v.data
	local x_p = v.x
	local y_p = v.y
	local scale = v.scale
	local f = io.open(map .. ".wmo", "rb")
	if not f then
		error("Cannot find map file: " .. map .. ".wmo")
	end
	local text = f:read("*all")
	f:close()

	local pos = text:find("DHOM")
	local header = unpackstruct(text:sub(pos+8, pos+8+struct_sizeof(SMOHeader)-1), SMOHeader)

	local points = {}

	local pos = text:find("IGOM")
	for i = 1, header.nGroups do
		local mogi = unpackstruct(text:sub(pos+8+struct_sizeof(MOGI)*(i-1), pos+8+struct_sizeof(MOGI)*i-1), MOGI)
		points[i-1] = { mogi.bbcorner1_1, mogi.bbcorner1_2 }
	end

	local f = io.open("md5translate.trs", "r")
	local text = f:read("*all")
	f:close()
	print(("\t[%q] = {"):format(name))
	for i = 0, header.nGroups-1 do
		for x = 0, 99 do
			local good = true
			for y = 0, 99 do
				local tex = text:match("\\" .. map .. "_" .. ("%03d"):format(i) .. "_" .. ("%02d"):format(x) .. "_" .. ("%02d"):format(y) .. "%.blp\t(%x*)%.blp")
				if not tex then
					if y == 0 then
						good = false
					end
					break
				end
				if tex ~= "c7182036289831c2dce4a7200377e6f4" then
					print(("\t\t{%q, %f, %f},"):format(tex, points[i][1]*2+x*256, points[i][2]*2+y*256))
				end
			end
			if not good then
				break
			end
		end
	end
	print("\t},")
end
print("}")