Files
LNXSDK/leenkx/Sources/leenkx/trait/internal/UniformsManager.hx
2026-08-07 02:04:01 -07:00

404 lines
11 KiB
Haxe

package leenkx.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<Object, Map<MaterialData, Map<String, Null<kha.FastFloat>>>>();
static var vectorsRegistered = false;
static var vectorsMap = new Map<Object, Map<MaterialData, Map<String, Vec4>>>();
static var texturesRegistered = false;
static var texturesMap = new Map<Object, Map<MaterialData, Map<String, kha.Image>>>();
static var sceneRemoveInitialized = false;
public var uniformExists = false;
public function new() {
super();
notifyOnAdd(init);
notifyOnRemove(removeObject);
if (!sceneRemoveInitialized) {
sceneRemoveInitialized = true;
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 leenkx 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_lnx_parameter) { // Check if leenkx 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.floatValue;
setFloatValue(material, object, link, value);
register(Float);
case "vec3":
var vec = new Vec4();
vec.x = constant.vec3Value.get(0);
vec.y = constant.vec3Value.get(1);
vec.z = constant.vec3Value.get(2);
setVec3Value(material, object, constant.link, vec);
register(Vector);
}
}
}
for (texture in context.texture_units) {
if (texture.is_lnx_parameter) { // Check if leenkx 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<kha.FastFloat>) {
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);
}
if (entry.get(link) != value) {
entry.set(link, value);
#if (rp_renderer == "Deferred")
if (Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
}
// 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);
}
if (entry.get(link) != value) {
entry.set(link, value);
#if (rp_renderer == "Deferred")
if (Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
}
// 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);
}
if (entry.get(link) != value) {
entry.set(link, value);
#if (rp_renderer == "Deferred")
if (Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
}
// Method to get object specific material parameter float value
public static function floatLink(object: Object, mat: MaterialData, link: String): Null<kha.FastFloat> {
if (object == null || mat == null) return null;
// First check if float exists per object
var res = getObjectFloatLink(object, mat, link);
if (res == null) {
// If not defined per object, use default scene root
res = getObjectFloatLink(Scene.active.root, mat, link);
}
return res;
}
// Get float link
static function getObjectFloatLink(object: Object, mat: MaterialData, link: String): Null<kha.FastFloat> {
var material = floatsMap.get(object);
if (material == null) return null;
var entry = material.get(mat);
if (entry == null) return null;
return entry.get(link);
}
// Method to get object specific material parameter vector value
public static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
if (object == null || mat == null) return null;
// First check if vector exists per object
var res = getObjectVec3Link(object, mat, link);
if (res == null) {
// If not defined per object, use default scene root
res = getObjectVec3Link(Scene.active.root, mat, link);
}
return res;
}
// Get vector link
static function getObjectVec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
var material = vectorsMap.get(object);
if (material == null) return null;
var entry = material.get(mat);
if (entry == null) return null;
return entry.get(link);
}
// Method to get object specific material parameter texture value
public static function textureLink(object: Object, mat: MaterialData, link: String): kha.Image {
if (object == null || mat == null) return null;
// First check if texture exists per object
var res = getObjectTextureLink(object, mat, link);
if (res == null) {
// If not defined per object, use default scene root
res = getObjectTextureLink(Scene.active.root, mat, link);
}
return res;
}
// Get texture link
static function getObjectTextureLink(object: Object, mat: MaterialData, link: String): kha.Image {
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<Object, Map<MaterialData, Map<String, Null<kha.FastFloat>>>>{
return floatsMap;
}
// Returns complete map of vec3 value material paramets
public static function getVectorsMap():Map<Object, Map<MaterialData, Map<String, Vec4>>>{
return vectorsMap;
}
// Returns complete map of texture value material paramets
public static function getTexturesMap():Map<Object, Map<MaterialData, Map<String, kha.Image>>>{
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);
}
}
public static function removeFloatValue(object: Object, mat:MaterialData, link: String) {
var material = floatsMap.get(object);
if (material == null) return;
var entry = material.get(mat);
if (entry == null) return;
var existed = entry.exists(link);
entry.remove(link);
if (!entry.keys().hasNext()) material.remove(mat);
if (!material.keys().hasNext()) floatsMap.remove(object);
#if (rp_renderer == "Deferred")
if (existed && Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
public static function removeVectorValue(object: Object, mat:MaterialData, link: String) {
var material = vectorsMap.get(object);
if (material == null) return;
var entry = material.get(mat);
if (entry == null) return;
var existed = entry.exists(link);
entry.remove(link);
if (!entry.keys().hasNext()) material.remove(mat);
if (!material.keys().hasNext()) vectorsMap.remove(object);
#if (rp_renderer == "Deferred")
if (existed && Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
public static function removeTextureValue(object: Object, mat:MaterialData, link: String) {
var material = texturesMap.get(object);
if (material == null) return;
var entry = material.get(mat);
if (entry == null) return;
var existed = entry.exists(link);
entry.remove(link);
if (!entry.keys().hasNext()) material.remove(mat);
if (!material.keys().hasNext()) texturesMap.remove(object);
#if (rp_renderer == "Deferred")
if (existed && Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
}
enum abstract UniformType(Int) from Int to Int {
var Float = 0;
var Vector = 1;
var Texture = 2;
}