package armory.trait.internal; import iron.object.DecalObject; import iron.object.MeshObject; import iron.Trait; import kha.Image; import iron.math.Vec4; import iron.data.MaterialData; import iron.Scene; import iron.object.Object; import iron.object.Uniforms; class UniformsManager extends Trait{ static var floatsRegistered = false; static var floatsMap = new Map>>>(); static var vectorsRegistered = false; static var vectorsMap = new Map>>(); static var texturesRegistered = false; static var texturesMap = new Map>>(); static var sceneRemoveInitalized = false; public var uniformExists = false; public function new(){ super(); notifyOnInit(init); notifyOnRemove(removeObject); if(! sceneRemoveInitalized){ Scene.active.notifyOnRemove(removeScene); } } function init() { if(Std.isOfType(object, MeshObject)){ var materials = cast(object, MeshObject).materials; for (material in materials){ var exists = registerShaderUniforms(material); if(exists) { uniformExists = true; } } } #if rp_decals if(Std.isOfType(object, DecalObject)){ var material = cast(object, DecalObject).material; var exists = registerShaderUniforms(material); if(exists) { uniformExists = true; } } #end } static function removeScene() { removeObjectFromAllMaps(Scene.active.root); } function removeObject() { removeObjectFromAllMaps(object); } // Helper method to register float, vec3 and texture getter functions static function register(type: UniformType){ switch (type){ case Float: if(! floatsRegistered){ floatsRegistered = true; Uniforms.externalFloatLinks.push(floatLink); } case Vector: if(! vectorsRegistered){ vectorsRegistered = true; Uniforms.externalVec3Links.push(vec3Link); } case Texture: if(! texturesRegistered){ texturesRegistered = true; Uniforms.externalTextureLinks.push(textureLink); } } } // Register and map shader uniforms if it is an armory shader parameter public static function registerShaderUniforms(material: MaterialData) : Bool { var uniformExist = false; if(! floatsMap.exists(Scene.active.root)) floatsMap.set(Scene.active.root, null); if(! vectorsMap.exists(Scene.active.root)) vectorsMap.set(Scene.active.root, null); if(! texturesMap.exists(Scene.active.root)) texturesMap.set(Scene.active.root, null); for(context in material.shader.raw.contexts){ // For each context in shader for (constant in context.constants){ // For each constant in the context if(constant.is_arm_parameter){ // Check if armory parameter uniformExist = true; var object = Scene.active.root; // Map default uniforms to scene root switch (constant.type){ case "float":{ var link = constant.link; var value = constant.float; setFloatValue(material, object, link, value); register(Float); } case "vec3":{ var vec = new Vec4(); vec.x = constant.vec3.get(0); vec.y = constant.vec3.get(1); vec.z = constant.vec3.get(2); setVec3Value(material, object, constant.link, vec); register(Vector); } } } } for (texture in context.texture_units){ if(texture.is_arm_parameter){ // Check if armory parameter uniformExist = true; var object = Scene.active.root; // Map default texture to scene root if(texture.default_image_file == null){ setTextureValue(material, object, texture.link, null); } else{ iron.data.Data.getImage(texture.default_image_file, function(image: kha.Image) { setTextureValue(material, object, texture.link, image); }); } register(Texture); } } } return uniformExist; } // Method to set map Object -> Material -> Link -> FLoat public static function setFloatValue(material: MaterialData, object: Object, link: String, value: Null){ if(object == null || material == null || link == null) return; var map = floatsMap; var matMap = map.get(object); if (matMap == null) { matMap = new Map(); map.set(object, matMap); } var entry = matMap.get(material); if (entry == null) { entry = new Map(); matMap.set(material, entry); } entry.set(link, value); // parameter name, value } // Method to set map Object -> Material -> Link -> Vec3 public static function setVec3Value(material: MaterialData, object: Object, link: String, value: Vec4){ if(object == null || material == null || link == null) return; var map = vectorsMap; var matMap = map.get(object); if (matMap == null) { matMap = new Map(); map.set(object, matMap); } var entry = matMap.get(material); if (entry == null) { entry = new Map(); matMap.set(material, entry); } entry.set(link, value); // parameter name, value } // Method to set map Object -> Material -> Link -> Texture public static function setTextureValue(material: MaterialData, object: Object, link: String, value: kha.Image){ if(object == null || material == null || link == null) return; var map = texturesMap; var matMap = map.get(object); if (matMap == null) { matMap = new Map(); map.set(object, matMap); } var entry = matMap.get(material); if (entry == null) { entry = new Map(); matMap.set(material, entry); } entry.set(link, value); // parameter name, value } // Mehtod to get object specific material parameter float value static function floatLink(object: Object, mat: MaterialData, link: String): Null { if(object == null || mat == null) return null; if(! floatsMap.exists(object)){ object = Scene.active.root; } var material = floatsMap.get(object); if (material == null) return null; var entry = material.get(mat); if (entry == null) return null; return entry.get(link); } // Mehtod to get object specific material parameter vec3 value static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 { if(object == null || mat == null) return null; if(! vectorsMap.exists(object)){ object = Scene.active.root; } var material = vectorsMap.get(object); if (material == null) return null; var entry = material.get(mat); if (entry == null) return null; return entry.get(link); } // Mehtod to get object specific material parameter texture value static function textureLink(object: Object, mat: MaterialData, link: String): kha.Image { if(object == null || mat == null) return null; if(! texturesMap.exists(object)){ object = Scene.active.root; } var material = texturesMap.get(object); if (material == null) return null; var entry = material.get(mat); if (entry == null) return null; return entry.get(link); } // Returns complete map of float value material paramets public static function getFloatsMap():Map>>>{ return floatsMap; } // Returns complete map of vec3 value material paramets public static function getVectorsMap():Map>>{ return vectorsMap; } // Returns complete map of texture value material paramets public static function getTexturesMap():Map>>{ return texturesMap; } // Remove all object specific material paramenter keys public static function removeObjectFromAllMaps(object: Object) { floatsMap.remove(object); vectorsMap.remove(object); texturesMap.remove(object); } // Remove object specific material paramenter keys public static function removeObjectFromMap(object: Object, type: UniformType) { switch (type){ case Float: floatsMap.remove(object); case Vector: vectorsMap.remove(object); case Texture: texturesMap.remove(object); } } } @:enum abstract UniformType(Int) from Int to Int { var Float = 0; var Vector = 1; var Texture = 2; }