149 lines
4.9 KiB
TypeScript
149 lines
4.9 KiB
TypeScript
export const ASSET_FAMILIES = [
|
|
'color',
|
|
'diffuse',
|
|
'roughness',
|
|
'normal',
|
|
'metalness',
|
|
'height',
|
|
'opacity',
|
|
'orm',
|
|
'ao',
|
|
] as const
|
|
|
|
type AssetFamily = typeof ASSET_FAMILIES[number]
|
|
|
|
const ASSET_FAMILY_BY_KEY = new Map(ASSET_FAMILIES.map((family) => [family.toLowerCase(), family]))
|
|
const FORBIDDEN_ASSET_FAMILY_ALIASES: ReadonlyMap<string, AssetFamily> = new Map([
|
|
['basecolor', 'color'],
|
|
['base_color', 'color'],
|
|
['normalopengl', 'normal'],
|
|
['normal_opengl', 'normal'],
|
|
['metallic', 'metalness'],
|
|
['occlusionroughnessmetallic', 'roughness'],
|
|
['occlusion_roughness_metallic', 'roughness'],
|
|
])
|
|
|
|
const EXPORTED_SUFFIX_ALIASES: Array<{ suffix: string; family: AssetFamily }> = [
|
|
{ suffix: 'occlusionroughnessmetallic', family: 'orm' },
|
|
{ suffix: 'occlusion_roughness_metallic', family: 'orm' },
|
|
{ suffix: 'normal_opengl', family: 'normal' },
|
|
{ suffix: 'normalopengl', family: 'normal' },
|
|
{ suffix: 'base_color', family: 'color' },
|
|
{ suffix: 'basecolor', family: 'color' },
|
|
{ suffix: 'mixed_ao', family: 'ao' },
|
|
{ suffix: 'metallic', family: 'metalness' },
|
|
{ suffix: 'roughness', family: 'roughness' },
|
|
{ suffix: 'normal', family: 'normal' },
|
|
{ suffix: 'height', family: 'height' },
|
|
{ suffix: 'opacity', family: 'opacity' },
|
|
{ suffix: 'diffuse', family: 'diffuse' },
|
|
{ suffix: 'color', family: 'color' },
|
|
]
|
|
|
|
export function getAssetFamily(value: string): AssetFamily | undefined {
|
|
return ASSET_FAMILY_BY_KEY.get(value.toLowerCase())
|
|
}
|
|
|
|
function getForbiddenAssetFamilyAlias(value: string): AssetFamily | undefined {
|
|
return FORBIDDEN_ASSET_FAMILY_ALIASES.get(value.toLowerCase())
|
|
}
|
|
|
|
function getFileStem(filename: string) {
|
|
return filename.replace(/\.[^.]+$/, '')
|
|
}
|
|
|
|
function getFileExtension(filename: string) {
|
|
return filename.split('.').pop()?.toLowerCase() || ''
|
|
}
|
|
|
|
function normalizeTargetName(target: string) {
|
|
return target
|
|
.trim()
|
|
.replace(/[\s-]+/g, '_')
|
|
.replace(/_+/g, '_')
|
|
.replace(/^_+|_+$/g, '')
|
|
}
|
|
|
|
function buildTextureFilename(family: AssetFamily, target: string, extension: string) {
|
|
const normalizedTarget = normalizeTargetName(target)
|
|
return `${family}${normalizedTarget ? `_${normalizedTarget}` : ''}.${extension}`
|
|
}
|
|
|
|
function getExportedTextureAlias(stem: string) {
|
|
const lowerStem = stem.toLowerCase()
|
|
|
|
for (const alias of EXPORTED_SUFFIX_ALIASES) {
|
|
const lowerSuffix = alias.suffix.toLowerCase()
|
|
if (lowerStem === lowerSuffix) {
|
|
return { family: alias.family, target: '' }
|
|
}
|
|
|
|
if (lowerStem.endsWith(`_${lowerSuffix}`)) {
|
|
return {
|
|
family: alias.family,
|
|
target: stem.slice(0, -lowerSuffix.length - 1),
|
|
}
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
export function normalizeTextureFilename(filename: string) {
|
|
const stem = getFileStem(filename)
|
|
const extension = getFileExtension(filename)
|
|
const [prefix, ...targetParts] = stem.split('_')
|
|
const family = getAssetFamily(prefix)
|
|
|
|
if (family) {
|
|
return buildTextureFilename(family, targetParts.join('_'), extension)
|
|
}
|
|
|
|
const exportedAlias = getExportedTextureAlias(stem)
|
|
if (exportedAlias) {
|
|
return buildTextureFilename(exportedAlias.family, exportedAlias.target, extension)
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
export function getTextureNamingError(filename: string) {
|
|
const stem = getFileStem(filename)
|
|
const [prefix, ...targetParts] = stem.split('_')
|
|
const family = getAssetFamily(prefix)
|
|
const extension = getFileExtension(filename)
|
|
|
|
if (normalizeTextureFilename(filename)) return null
|
|
|
|
if (family && targetParts.every(Boolean)) return null
|
|
|
|
const aliasSuggestion = getForbiddenAssetFamilyAlias(prefix)
|
|
|
|
if (aliasSuggestion && targetParts.every(Boolean)) {
|
|
const target = targetParts.join('_')
|
|
return `Convention invalide : ${filename}. Utilisez ${aliasSuggestion}_${target}.${extension} pour cibler "${target}", ou ${aliasSuggestion}.${extension} pour tout le modele.`
|
|
}
|
|
|
|
const reversedParts = stem.split('_')
|
|
const reversedFamily = reversedParts.length > 1 ? getAssetFamily(reversedParts[reversedParts.length - 1]) : undefined
|
|
const reversedAliasSuggestion = reversedParts.length > 1
|
|
? getForbiddenAssetFamilyAlias(reversedParts[reversedParts.length - 1])
|
|
: undefined
|
|
|
|
if (reversedFamily) {
|
|
const target = reversedParts.slice(0, -1).join('_')
|
|
return `Convention invalide : ${filename}. Utilisez ${reversedFamily}_${target}.${extension} pour cibler "${target}", ou ${reversedFamily}.${extension} pour tout le modele.`
|
|
}
|
|
|
|
if (reversedAliasSuggestion) {
|
|
const target = reversedParts.slice(0, -1).join('_')
|
|
return `Convention invalide : ${filename}. Utilisez ${reversedAliasSuggestion}_${target}.${extension} pour cibler "${target}", ou ${reversedAliasSuggestion}.${extension} pour tout le modele.`
|
|
}
|
|
|
|
return `Asset inconnu : ${filename}. Familles autorisees : ${formatAssetFamilies()}. Utilisez asset.png pour tout le modele ou asset_objet.png pour cibler un objet.`
|
|
}
|
|
|
|
function formatAssetFamilies() {
|
|
return ASSET_FAMILIES.join(', ')
|
|
}
|