File size: 6,908 Bytes
b6a38d7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
EngineBinAssetsPrints = {}
EngineBinAssetsPrint = CreatePrint { "", output = function(s) table.insert(EngineBinAssetsPrints, s) end }
EngineBinAssetsPrintf = CreatePrint { "", output = function(s) table.insert(EngineBinAssetsPrints, s) end, format = string.format }
EngineBinAssetsError = CreatePrint { "EB_ERROR", output = function(s) table.insert(EngineBinAssetsPrints, s) end }
EngineBinAssetsErrorf = CreatePrint { "EB_ERROR", output = function(s) table.insert(EngineBinAssetsPrints, s) end, format = string.format }
local function MarkTestEntityTextures(texture_list)
local tex_map = {}
local test_assets_path = ConvertToOSPath("svnAssets/Bin/Common/Materials/")
for texture_id, path in pairs(texture_list) do
local texture_name = path:sub(path:find("[^\\]*$"))
tex_map[texture_name] = {
id = texture_id,
path = path,
skip = string.starts_with(path, test_assets_path),
}
end
return tex_map;
end
local function AddTextureHashes(textures_data, cached_hashes)
local cached_hashes = cached_hashes or {}
for texture_id, texture_data in pairs(textures_data) do
local tex_hash = cached_hashes[texture_id]
if not tex_hash then
local err, hash = AsyncFileToString(texture_data.path, nil, nil, "hash")
if err then
EngineBinAssetsError("AsyncFileToString(" .. texture_data.path .. ") failed: " .. err)
return err
else
tex_hash = tostring(hash)
end
end
texture_data.hash = tex_hash
end
end
local function GetTexturesCachedHashes()
local err, hash_list = FileToLuaValue("svnAssets/BuildCache/TextureHashes.lua")
if err then
EngineBinAssetsError("Could not load hash map with material textures!")
end
local cached_hashes = {}
for filename, v in pairs(hash_list or empty_table) do
cached_hashes[filename:sub(filename:find("[^/]*$"))] = tostring(v.hash)
end
return cached_hashes
end
function MarkUniqueTextures(textures_data)
local sorted_texture_ids = table.keys(textures_data)
table.sort(sorted_texture_ids, function (a, b) return #a == #b and a < b or #a < #b end)
local unique_hashes = {}
for _, texture_id in ipairs(sorted_texture_ids) do
local tex_data = textures_data[texture_id]
if not tex_data.skip then
local tex_alias = unique_hashes[tex_data.hash]
if tex_alias then
tex_data.alias = tex_alias
elseif not tex_data.hash then
EngineBinAssetsError("Missing texture hash for(" .. texture_id .. ")")
else
--tex_data.alias = texture_id -- not needed it its the same
unique_hashes[tex_data.hash] = texture_id
end
end
end
local num_tex = table.count(textures_data)
local num_unique = table.count(unique_hashes)
EngineBinAssetsPrintf("Entity textures: %d (%d Unique, %d Duplicates)", num_tex, num_unique, num_tex - num_unique)
return unique_hashes
end
local function RemapMaterialTextures(mat_name, textures_data, used_tex, ent_textures)
local num_sub_mats = GetNumSubMaterials(mat_name)
for subi=1, num_sub_mats do
local props = GetMaterialProperties(mat_name, subi-1)
local new_props = false
for prop, value in sorted_pairs(props) do
if type(value) == "string" then
local tex_name = value:sub(value:find("[^/]*$"))
if tex_name then
local tex_data = textures_data[tex_name]
if tex_data then
if tex_data.alias then
new_props = new_props or {}
new_props[prop] = textures_data[tex_data.alias].id
ent_textures[tex_data.alias] = true
local alias_data = textures_data[tex_data.alias]
alias_data.used_in = alias_data.used_in or {}
table.insert(alias_data.used_in, mat_name)
else
used_tex[tex_name] = tex_data.path
ent_textures[tex_name] = true
tex_data.used_in = tex_data.used_in or {}
table.insert(tex_data.used_in, mat_name)
end
end
elseif value:find("<unknown>", 1, "plain") then
EngineBinAssetsPrintf("once", "Missing texture Textures/%s in material %s", value:match("Textures/(.*)%.<unknown>"), mat_name)
end
end
end
if new_props then
SetMaterialProperties(mat_name, subi-1, new_props)
end
end
end
local function BuildTextureIdx(used_tex)
local tex_idx = {}
local textures = table.keys(used_tex)
table.sort(textures, function (a, b) return #a == #b and a < b or #a < #b end)
for _, tex_name in ipairs(textures) do
tex_idx[#tex_idx+1] = string.format("Textures/%s=%s", tex_name, used_tex[tex_name])
end
local filename = "entities.txt"
local path = "svnAssets/BuildCache/win32/TextureIdx/"
local err = AsyncCreatePath(path)
assert(not err, "Error creating textures idx path: " .. tostring(err))
local err = StringToFileIfDifferent(path .. filename, table.concat(tex_idx, "\r\n"))
assert(not err, "Error writing textures idx: " .. tostring(err))
end
local function ShortenTexturePaths(textures_data)
for _, texture_data in pairs(textures_data) do
texture_data.path = string.match(texture_data.path, "\\([^\\]+Assets.+)$")
end
end
function CollapseMaterialTextures(texture_list, entities, cached_hashes, shorten_paths)
local textures_data = MarkTestEntityTextures(texture_list)
AddTextureHashes(textures_data, cached_hashes)
if shorten_paths then
ShortenTexturePaths(textures_data)
end
MarkUniqueTextures(textures_data)
local materials_seen, entity_textures, used_tex = {}, {}, {}
for entity, _ in sorted_pairs(entities) do
if entity:sub(1,1) ~= "#" then
local ent_textures = {}
local states = GetStates(entity)
for si=1, #states do
local state = GetStateIdx(states[si])
local num_lods = GetStateLODCount(entity, state)
for li=1, num_lods do
local material = GetStateMaterial(entity, state, li - 1)
if not materials_seen[material] then
RemapMaterialTextures(material, textures_data, used_tex, ent_textures)
materials_seen[material] = entity
entity_textures[entity] = ent_textures
else
local other_entity = materials_seen[material]
entity_textures[entity] = entity_textures[other_entity]
end
end
end
end
end
return materials_seen, used_tex, textures_data
end
function CollapseAllTextures()
local all_entities = GetAllEntities()
local texture_list = CollectMtlReferencedTextures()
local cached_hashes = GetTexturesCachedHashes()
local materials_seen, used_tex, textures_data = CollapseMaterialTextures(texture_list, all_entities, cached_hashes, true)
BuildTextureIdx(used_tex)
return materials_seen, used_tex, textures_data
end
function CollapseEntitiesTextures(entities)
local texture_list = {}
for entity, _ in sorted_pairs(entities) do
local states = GetStates(entity)
for si=1, #states do
local state = GetStateIdx(states[si])
local state_textures = GetStateMaterialTextures(entity, state)
table.append(texture_list, state_textures)
end
end
local materials_seen, used_tex, textures_data = CollapseMaterialTextures(texture_list, entities)
return materials_seen, used_tex, textures_data
end |