diff --git a/examples/quick3d/simple/CopperCube.qml b/examples/quick3d/simple/CopperCube.qml
new file mode 100644
index 0000000000000000000000000000000000000000..bd0474a43d8a1f6b2f3fab6659f8dc08b8767e8b
--- /dev/null
+++ b/examples/quick3d/simple/CopperCube.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.12
+import QtDemon 1.0
+
+DemonModel {
+    source: "#Cube"
+    property alias metalColor: copperMaterial.metal_color
+    materials: [ CopperMaterial {
+            id: copperMaterial
+        }
+    ]
+}
diff --git a/examples/quick3d/simple/CopperMaterial.qml b/examples/quick3d/simple/CopperMaterial.qml
new file mode 100644
index 0000000000000000000000000000000000000000..ade4b408e4e01a4126b917f48e4626e3587b72ee
--- /dev/null
+++ b/examples/quick3d/simple/CopperMaterial.qml
@@ -0,0 +1,42 @@
+import QtQuick 2.12
+import QtDemon 1.0
+
+DemonCustomMaterial {
+    // These properties names need to match the ones in the shader code!
+    property bool uEnvironmentMappingEnabled: false
+    property bool uShadowMappingEnabled: false
+    property real roughness: 0.0
+    property vector3d metal_color: Qt.vector3d(0.805, 0.395, 0.305)
+
+    shaderInfo: DemonCustomMaterialShaderInfo {
+        version: "330"
+        type: "GLSL"
+        shaderKey: DemonCustomMaterialShaderInfo.Glossy
+        layers: 1
+    }
+
+    textures: [ DemonCustomMaterialTexture {
+            id: uEnvironmentTexture
+            enabled: uEnvironmentMappingEnabled
+            type: DemonCustomMaterialTexture.Environment
+            name: "uEnvironmentTexture"
+            image: DemonImage {
+                id: envImage
+                source: "maps/spherical_checker.png"
+            }
+    }, DemonCustomMaterialTexture {
+            id: uBakedShadowTexture
+            enabled: uShadowMappingEnabled
+            type: DemonCustomMaterialTexture.LightmapShadow
+            name: "uBakedShadowTexture"
+            image: DemonImage {
+                id: shadowImage
+                source: "maps/shadow.png"
+            }
+    } ]
+
+    shaders: DemonCustomMaterialShader {
+        stage: DemonCustomMaterialShader.Fragment
+        shader: "copper.frag"
+    }
+}
diff --git a/examples/quick3d/simple/FrostedThinGlassMaterial.qml b/examples/quick3d/simple/FrostedThinGlassMaterial.qml
new file mode 100644
index 0000000000000000000000000000000000000000..927c5b06fa46fb1ace31fce66a2f7879fba2c9c4
--- /dev/null
+++ b/examples/quick3d/simple/FrostedThinGlassMaterial.qml
@@ -0,0 +1,163 @@
+import QtQuick 2.12
+import QtDemon 1.0
+
+DemonCustomMaterial {
+
+    //    <Property formalName="Glass Bump map" name="glass_bump" description="Additional bump map for surface" type="Texture" clamp="repeat" category="Material"/>
+    //    <Property formalName="Gradient1D Map" description="Gradient texture of the material" hidden="True" name="randomGradient1D" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="gradient" default="./maps/materials/randomGradient1D.jpg"/>
+    //    <Property formalName="Gradient2D Map" description="Gradient texture of the material" hidden="True" name="randomGradient2D" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="gradient" default="./maps/materials/randomGradient2D.jpg"/>
+    //    <Property formalName="Gradient3D Map" description="Gradient texture of the material" hidden="True" name="randomGradient3D" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="gradient" default="./maps/materials/randomGradient3D.jpg"/>
+    //    <Property formalName="Gradient4D Map" description="Gradient texture of the material" hidden="True" name="randomGradient4D" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="gradient" default="./maps/materials/randomGradient4D.jpg"/>
+
+    // These properties names need to match the ones in the shader code!
+    property real roughness: 1.0
+    property real blur_size: 8.0
+    property real refract_depth: 5
+    property bool uEnvironmentMappingEnabled: true
+    property bool uShadowMappingEnabled: false
+    property real glass_bfactor: 0.0
+    property bool glass_binside: false
+    property real uFresnelPower: 1.0
+    property real reflectivity_amount: 0.1
+    property real glass_ior: 1.1
+    property real intLightFall: 2.0
+    property real intLightRot: 0.0
+    property real intLightBrt: 0.0
+    property real bumpScale: 0.5
+    property int bumpBands: 1
+    property vector3d bumpCoords: Qt.vector3d(1.0, 1.0, 1.0)
+    property vector2d intLightPos: Qt.vector2d(0.5, 0.0)
+    property vector3d glass_color: Qt.vector3d(0.9, 0.9, 0.9)
+    property vector3d intLightCol: Qt.vector3d(0.9, 0.9, 0.9)
+    hasTransparency: true
+
+    shaderInfo: DemonCustomMaterialShaderInfo {
+        version: "330"
+        type: "GLSL"
+        shaderKey: DemonCustomMaterialShaderInfo.Refraction | DemonCustomMaterialShaderInfo.Glossy
+        layers: 1
+    }
+
+    textures: [ DemonCustomMaterialTexture {
+            id: uEnvironmentTexture
+            type: DemonCustomMaterialTexture.Environment
+            name: "uEnvironmentTexture"
+            enabled: uEnvironmentMappingEnabled
+            image: DemonImage {
+                id: envImage
+                source: "maps/spherical_checker.png"
+            }
+        }, DemonCustomMaterialTexture {
+            id: uBakedShadowTexture
+            type: DemonCustomMaterialTexture.LightmapShadow
+            name: "uBakedShadowTexture"
+            enabled: uShadowMappingEnabled
+            image: DemonImage {
+                id: shadowImage
+                source: "maps/shadow.png"
+            }
+        }, DemonCustomMaterialTexture {
+            id: randomGradient1D
+            type: DemonCustomMaterialTexture.Gradient
+            name: "randomGradient1D"
+            // hidden = true
+            image: DemonImage {
+                tilingmodehorz: DemonImage.Repeat
+                tilingmodevert: DemonImage.Repeat
+                source: "maps/randomGradient1D.png"
+            }
+        }, DemonCustomMaterialTexture {
+            id: randomGradient2D
+            type: DemonCustomMaterialTexture.Gradient
+            name: "randomGradient2D"
+            // hidden = true
+            image: DemonImage {
+                tilingmodehorz: DemonImage.Repeat
+                tilingmodevert: DemonImage.Repeat
+                source: "maps/randomGradient2D.png"
+            }
+        }, DemonCustomMaterialTexture {
+            id: randomGradient3D
+            type: DemonCustomMaterialTexture.Gradient
+            name: "randomGradient3D"
+            // hidden = true
+            image: DemonImage {
+                tilingmodehorz: DemonImage.Repeat
+                tilingmodevert: DemonImage.Repeat
+                source: "maps/randomGradient3D.png"
+            }
+        }, DemonCustomMaterialTexture {
+            id: randomGradient4D
+            type: DemonCustomMaterialTexture.Gradient
+            name: "randomGradient4D"
+            // hidden = true
+            image: DemonImage {
+                tilingmodehorz: DemonImage.Repeat
+                tilingmodevert: DemonImage.Repeat
+                source: "maps/randomGradient4D.png"
+            }
+        } ]
+
+    shaders: [ DemonCustomMaterialShader {
+            stage: DemonCustomMaterialShader.Fragment
+            shader: "frostedThinGlass.frag"
+        }, DemonCustomMaterialShader {
+            stage: DemonCustomMaterialShader.Fragment
+            shader: "frostedThinGlassPreBlur.frag"
+        }, DemonCustomMaterialShader {
+            stage: DemonCustomMaterialShader.Fragment
+            shader: "frostedThinGlassBlurX.frag"
+        }, DemonCustomMaterialShader {
+            stage: DemonCustomMaterialShader.Fragment
+            shader: "frostedThinGlassBlurY.frag"
+        }
+    ]
+
+    passes: [ DemonCustomMaterialPass {
+            // NOOP
+            // output => dummy_buffer
+            commands: [ DemonCustomMaterialBufferBlit {
+                    destination: "frame_buffer"
+                }
+            ]
+        }, DemonCustomMaterialPass {
+            // PREBLUR
+            // output => temp_buffer
+            commands: [ DemonCustomMaterialBufferInput {
+                    bufferName: "frame_buffer"
+                    param: "OriginBuffer"
+                }
+            ]
+        }, DemonCustomMaterialPass {
+            // BLURX
+            // output => temp_blurX
+            commands: [ DemonCustomMaterialBufferInput {
+                    bufferName: "temp_buffer"
+                    param: "BlurBuffer"
+                }
+            ]
+        }, DemonCustomMaterialPass {
+            // BLURY
+            // output => temp_blurY
+            commands: [ DemonCustomMaterialBufferInput {
+                    bufferName: "temp_blurX"
+                    param: "BlurBuffer"
+                }, DemonCustomMaterialBufferInput {
+                    bufferName: "temp_buffer"
+                    param: "OriginBuffer"
+                }
+            ]
+        }, DemonCustomMaterialPass {
+            // MAIN
+            // output => dummy_buffer
+            commands: [DemonCustomMaterialBufferInput {
+                    bufferName: "temp_blurY"
+                    param: "refractiveTexture"
+                }, DemonCustomMaterialBlending {
+                    srcBlending: DemonCustomMaterialBlending.SrcAlpha
+                    destBlending: DemonCustomMaterialBlending.OneMinusSrcAlpha
+                }
+            ]
+        }
+    ]
+}
diff --git a/examples/quick3d/simple/PorcelainMaterial.qml b/examples/quick3d/simple/PorcelainMaterial.qml
new file mode 100644
index 0000000000000000000000000000000000000000..40a87e1f9d2f8473aafc8115e68fafbb647f0466
--- /dev/null
+++ b/examples/quick3d/simple/PorcelainMaterial.qml
@@ -0,0 +1,46 @@
+import QtQuick 2.12
+import QtDemon 1.0
+
+DemonCustomMaterial {
+    // These properties names need to match the ones in the shader code!
+    property bool uEnvironmentMappingEnabled: true
+    property bool uShadowMappingEnabled: false
+    property real material_ior: 1.5
+    property real glossy_weight: 1.0
+    property real roughness: 0.15
+    property vector3d porcelain_color: Qt.vector3d(0.92, 0.92, 0.92)
+
+    shaderInfo: DemonCustomMaterialShaderInfo {
+        version: "330"
+        type: "GLSL"
+        shaderKey: DemonCustomMaterialShaderInfo.Glossy
+        layers: 1
+    }
+
+    textures: [ DemonCustomMaterialTexture {
+            id: uEnvironmentTexture
+            type: DemonCustomMaterialTexture.Environment
+            name: "uEnvironmentTexture"
+            enabled: uEnvironmentMappingEnabled
+            image: DemonImage {
+                id: envImage
+                tilingmodehorz: DemonImage.Repeat
+                tilingmodevert: DemonImage.Repeat
+                source: "maps/spherical_checker.png"
+            }
+    }, DemonCustomMaterialTexture {
+            id: uBakedShadowTexture
+            type: DemonCustomMaterialTexture.LightmapShadow
+            enabled: uShadowMappingEnabled
+            name: "uBakedShadowTexture"
+            image: DemonImage {
+                id: shadowImage
+                source: "maps/shadow.png"
+            }
+    } ]
+
+    shaders: DemonCustomMaterialShader {
+        stage: DemonCustomMaterialShader.Fragment
+        shader: "porcelain.frag"
+    }
+}
diff --git a/examples/quick3d/simple/SimpleGlassMaterial.qml b/examples/quick3d/simple/SimpleGlassMaterial.qml
new file mode 100644
index 0000000000000000000000000000000000000000..69b6638c34e3aa261c61b16d50636a6242cf8ac1
--- /dev/null
+++ b/examples/quick3d/simple/SimpleGlassMaterial.qml
@@ -0,0 +1,57 @@
+import QtQuick 2.12
+import QtDemon 1.0
+
+DemonCustomMaterial {
+    // These properties names need to match the ones in the shader code!
+    property bool uEnvironmentMappingEnabled: false
+    property bool uShadowMappingEnabled: false
+    property real uFresnelPower: 1.0
+    property real uMinOpacity: 0.5
+    property real reflectivity_amount: 1.0
+    property real glass_ior: 1.1
+    property vector3d glass_color: Qt.vector3d(0.9, 0.9, 0.9)
+    hasTransparency: true
+//    property alias environmentTexture: envImage.source
+//    property alias shadowTexture: shadowImage.source
+
+    shaderInfo: DemonCustomMaterialShaderInfo {
+        version: "330"
+        type: "GLSL"
+        shaderKey: DemonCustomMaterialShaderInfo.Transparent | DemonCustomMaterialShaderInfo.Glossy
+        layers: 1
+    }
+
+    textures: [ DemonCustomMaterialTexture {
+            id: uEnvironmentTexture
+            type: DemonCustomMaterialTexture.Environment
+            name: "uEnvironmentTexture"
+            enabled: uEnvironmentMappingEnabled
+            image: DemonImage {
+                id: envImage
+                source: "maps/spherical_checker.png"
+            }
+    }, DemonCustomMaterialTexture {
+            id: uBakedShadowTexture
+            type: DemonCustomMaterialTexture.LightmapShadow
+            name: "uBakedShadowTexture"
+            enabled: uShadowMappingEnabled
+            image: DemonImage {
+                id: shadowImage
+                source: "maps/shadow.png"
+            }
+    } ]
+
+    shaders: DemonCustomMaterialShader {
+        stage: DemonCustomMaterialShader.Fragment
+        shader: "simpleGlass.frag"
+    }
+
+    passes: [ DemonCustomMaterialPass {
+            commands: [ DemonCustomMaterialBlending {
+                    srcBlending: DemonCustomMaterialBlending.SrcAlpha
+                    destBlending: DemonCustomMaterialBlending.OneMinusSrcAlpha
+                }, DemonCustomMaterialRenderState {
+                    renderState: DemonCustomMaterialRenderState.CullFace
+                }]
+        }]
+}
diff --git a/examples/quick3d/simple/copper.frag b/examples/quick3d/simple/copper.frag
new file mode 100644
index 0000000000000000000000000000000000000000..f3b7525f5eb969b0d7b8289d8cd0bcc94c1d4b45
--- /dev/null
+++ b/examples/quick3d/simple/copper.frag
@@ -0,0 +1,147 @@
+// add enum defines
+#define scatter_reflect 0
+#define scatter_transmit 1
+#define scatter_reflect_transmit 2
+
+#define QDEMON_ENABLE_UV0 1
+#define QDEMON_ENABLE_WORLD_POSITION 1
+#define QDEMON_ENABLE_TEXTAN 1
+#define QDEMON_ENABLE_BINORMAL 0
+
+#include "vertexFragmentBase.glsllib"
+
+// set shader output
+out vec4 fragColor;
+
+// add structure defines
+struct layer_result
+{
+  vec4 base;
+  vec4 layer;
+  mat3 tanFrame;
+};
+
+
+// temporary declarations
+ vec4 tmpShadowTerm;
+
+layer_result layers[1];
+
+#include "SSAOCustomMaterial.glsllib"
+#include "sampleLight.glsllib"
+#include "sampleProbe.glsllib"
+#include "sampleArea.glsllib"
+#include "square.glsllib"
+#include "calculateRoughness.glsllib"
+#include "evalBakedShadowMap.glsllib"
+#include "evalEnvironmentMap.glsllib"
+#include "luminance.glsllib"
+#include "microfacetBSDF.glsllib"
+#include "physGlossyBSDF.glsllib"
+#include "simpleGlossyBSDF.glsllib"
+#include "fresnelLayer.glsllib"
+
+bool evalTwoSided()
+{
+  return( false );
+}
+
+vec3 computeFrontMaterialEmissive()
+{
+  return( vec3( 0, 0, 0 ) );
+}
+
+void computeFrontLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += tmpShadowTerm * vec4( 0.0f, 0.0f, 0.0f, 1.0f );
+  layers[0].layer += tmpShadowTerm * microfacetBSDF( layers[0].tanFrame, lightDir, viewDir, lightSpecular, materialIOR, roughness, roughness, scatter_reflect );
+#endif
+}
+
+void computeFrontAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += tmpShadowTerm * vec4( 0.0f, 0.0f, 0.0f, 1.0f );
+  layers[0].layer += tmpShadowTerm * lightSpecular * sampleAreaGlossy( layers[0].tanFrame, varWorldPos, lightIdx, viewDir, roughness, roughness );
+#endif
+}
+
+void computeFrontLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QDEMON_ENABLE_LIGHT_PROBE
+  layers[0].base += tmpShadowTerm * vec4( 0.0f, 0.0f, 0.0f, 1.0f );
+  layers[0].layer += tmpShadowTerm * microfacetSampledBSDF( layers[0].tanFrame, viewDir, roughness, roughness, scatter_reflect );
+#else
+  layers[0].base += tmpShadowTerm * vec4( 0.0f, 0.0f, 0.0f, 1.0f );
+  layers[0].layer += tmpShadowTerm * sampleGlossyAniso( layers[0].tanFrame, viewDir, roughness, roughness );
+#endif
+}
+
+vec3 computeBackMaterialEmissive()
+{
+  return( vec3(0, 0, 0) );
+}
+
+void computeBackLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QDEMON_ENABLE_LIGHT_PROBE
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#else
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+float computeIOR()
+{
+  return( false ? 1.0f : luminance( vec3( 1, 1, 1 ) ) );
+}
+
+float evalCutout()
+{
+  return( 1.000000 );
+}
+
+vec3 computeNormal()
+{
+  return( normal );
+}
+
+void computeTemporaries()
+{
+     tmpShadowTerm = evalBakedShadowMap( texCoord0 );
+}
+
+vec4 computeLayerWeights( in float alpha )
+{
+  vec4 color;
+  color = fresnelLayer( normal, vec3( 25.65, 25.65, 25.65 ), 1.000000, vec4( metal_color, 1.0).rgb, layers[0].layer, layers[0].base, alpha );
+  return color;
+}
+
+
+void initializeLayerVariables(void)
+{
+  // clear layers
+  layers[0].base = vec4(0.0, 0.0, 0.0, 1.0);
+  layers[0].layer = vec4(0.0, 0.0, 0.0, 1.0);
+  layers[0].tanFrame = orthoNormalize( mat3( tangent, cross(normal, tangent), normal ) );
+}
diff --git a/examples/quick3d/simple/frostedThinGlass.frag b/examples/quick3d/simple/frostedThinGlass.frag
new file mode 100644
index 0000000000000000000000000000000000000000..30781ffbe91e71c000d0a30634894173def4cfd8
--- /dev/null
+++ b/examples/quick3d/simple/frostedThinGlass.frag
@@ -0,0 +1,292 @@
+// add enum defines
+#define mono_alpha 0
+#define mono_average 1
+#define mono_luminance 2
+#define mono_maximum 3
+#define wrap_clamp 0
+#define wrap_repeat 1
+#define wrap_mirrored_repeat 2
+#define texture_coordinate_uvw 0
+#define texture_coordinate_world 1
+#define texture_coordinate_object 2
+#define scatter_reflect 0
+#define scatter_transmit 1
+#define scatter_reflect_transmit 2
+
+#define QDEMON_ENABLE_UV0 1
+#define QDEMON_ENABLE_WORLD_POSITION 1
+#define QDEMON_ENABLE_TEXTAN 1
+#define QDEMON_ENABLE_BINORMAL 0
+
+#include "vertexFragmentBase.glsllib"
+
+// set shader output
+out vec4 fragColor;
+
+// add structure defines
+struct layer_result
+{
+  vec4 base;
+  vec4 layer;
+  mat3 tanFrame;
+};
+
+// add structure defines
+struct texture_coordinate_info
+{
+  vec3 position;
+  vec3 tangent_u;
+  vec3 tangent_v;
+};
+
+struct texture_return
+{
+  vec3 tint;
+  float mono;
+};
+
+// temporary declarations
+texture_coordinate_info tmp0;
+texture_coordinate_info tmp1;
+vec3 ftmp0;
+vec3 ftmp1;
+vec3 ftmp2;
+vec4 tmpShadowTerm;
+
+layer_result layers[1];
+
+#include "SSAOCustomMaterial.glsllib"
+#include "sampleLight.glsllib"
+#include "sampleProbe.glsllib"
+#include "sampleArea.glsllib"
+#include "square.glsllib"
+#include "cube.glsllib"
+#include "random255.glsllib"
+#include "perlinNoise.glsllib"
+#include "perlinNoiseBumpTexture.glsllib"
+#include "luminance.glsllib"
+#include "monoChannel.glsllib"
+#include "fileBumpTexture.glsllib"
+#include "transformCoordinate.glsllib"
+#include "rotationTranslationScale.glsllib"
+#include "coordinateSource.glsllib"
+#include "calculateRoughness.glsllib"
+#include "evalBakedShadowMap.glsllib"
+#include "evalEnvironmentMap.glsllib"
+#include "microfacetBSDF.glsllib"
+#include "physGlossyBSDF.glsllib"
+#include "simpleGlossyBSDF.glsllib"
+#include "abbeNumberIOR.glsllib"
+#include "average.glsllib"
+#include "perlinNoiseTexture.glsllib"
+#include "fresnelLayer.glsllib"
+#include "refraction.glsllib"
+
+uniform sampler2D refractiveTexture;
+
+bool evalTwoSided()
+{
+  return( false );
+}
+
+vec3 computeFrontMaterialEmissive()
+{
+  return( vec3( 0, 0, 0 ) );
+}
+
+void computeFrontLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += tmpShadowTerm * microfacetBSDF( layers[0].tanFrame, lightDir, viewDir, lightSpecular, materialIOR, roughness, roughness, scatter_reflect_transmit );
+
+#endif
+}
+
+void computeFrontAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += tmpShadowTerm * lightSpecular * sampleAreaGlossy( layers[0].tanFrame, varWorldPos, lightIdx, viewDir, roughness, roughness );
+
+#endif
+}
+
+void computeFrontLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QDEMON_ENABLE_LIGHT_PROBE
+  layers[0].base += tmpShadowTerm * microfacetSampledBSDF( layers[0].tanFrame, viewDir, roughness, roughness, scatter_reflect_transmit );
+
+#else
+  layers[0].base += tmpShadowTerm * sampleGlossyAniso( layers[0].tanFrame, viewDir, roughness, roughness );
+
+#endif
+}
+
+vec3 computeBackMaterialEmissive()
+{
+  return( vec3(0, 0, 0) );
+}
+
+void computeBackLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QDEMON_ENABLE_LIGHT_PROBE
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#else
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+float computeIOR()
+{
+  return( false ? 1.0f : luminance( vec3( abbeNumberIOR(glass_ior, 0.000000 ) ) ) );
+}
+
+float evalCutout()
+{
+  return( 1.000000 );
+}
+
+vec3 computeNormal()
+{
+  if ( glass_bfactor > 0.0 )
+  {
+    ftmp2 = fileBumpTexture(glass_bump, glass_bfactor, mono_average, tmp0, vec2( 0.000000, 1.000000 ), vec2( 0.000000, 1.000000 ), wrap_repeat, wrap_repeat, normal );
+    if (!glass_binside) { normal = ftmp2; }
+  }
+
+  return( perlinNoiseBumpTexture( tmp1, bumpScale, 1.000000, false, false, 0.000000, bumpBands, false, vec3( 0.000000, 0.000000, 0.000000 ), 0.5, 0.0, 1.000000, normal ) );
+}
+
+void computeTemporaries()
+{
+    //tmp0 = transformCoordinate( rotationTranslationScale( vec3( 0.000000, 0.000000, 0.000000 ), vec3( 0.000000, 0.000000, 0.000000 ), refractCoords ), coordinateSource(texture_coordinate_world, 0 ) );
+    //ftmp1 = perlinNoiseBumpTexture( tmp0, refractScale, 1.000000, false, false, 0.000000, 1, false, vec3( 0.000000, 0.000000, 0.000000 ), 1.0, 0.5, 1.000000, viewDir );
+    tmp0 = transformCoordinate( rotationTranslationScale( vec3( 0.000000, 0.000000, 0.000000 ), vec3( 0.000000, 0.000000, 0.000000 ), bumpCoords ), textureCoordinateInfo( texCoord0, tangent, binormal ) );
+    tmp1 = transformCoordinate( rotationTranslationScale( vec3( 0.000000, 0.000000, 0.000000 ), vec3( 0.000000, 0.000000, 0.000000 ), bumpCoords ), coordinateSource(texture_coordinate_world, 0 ) );
+    ftmp1 = viewDir;
+    ftmp0 = vec3( reflectivity_amount );
+    tmpShadowTerm = evalBakedShadowMap( texCoord0 );
+}
+
+vec4 computeLayerWeights( in float alpha )
+{
+  vec4 color;
+  color = layers[0].base * vec4( ftmp0, 1.0);
+  return color;
+}
+
+
+void initializeLayerVariables(void)
+{
+  // clear layers
+  layers[0].base = vec4(0.0, 0.0, 0.0, 1.0);
+  layers[0].layer = vec4(0.0, 0.0, 0.0, 1.0);
+  layers[0].tanFrame = orthoNormalize( tangentFrame( normal, varWorldPos ) );
+}
+
+vec3 getRefractUV( in vec2 baseUV, in vec3 normal, in float materialIOR, in float refractDepth )
+{
+    // Real honest-to-goodness refraction!
+    vec3 refractedDir = refract( -viewDir, normal, 1.0 / materialIOR );
+    float thickness = refractDepth / clamp( dot(viewDir, normal), 0.0001, 1.0 );
+
+    // This will do an "AA" version of that loss due to critical angle and TIR
+        // fakes the same effect than using the glsl refract.
+    float weight = smoothstep( 0.0, 1.0, abs(dot(viewDir, normal)) * 100.0 );
+
+    // Trace out the refracted ray and the straight view ray
+    refractedDir *= thickness;
+    vec3 rawDir = -viewDir * thickness;
+
+    vec3 displace = refractedDir - rawDir;
+    vec3 newUV = vec3(baseUV + displace.xy, weight);
+    return newUV;
+}
+
+vec4 doFakeInnerLight( in vec3 normal, in vec3 absorb_color )
+{
+    vec3 lightColor = intLightCol * intLightBrt;
+
+    float cosRot = cos(intLightRot * 0.01745329251);
+    float sinRot = sin(intLightRot * 0.01745329251);
+    vec2 uvDir = vec2(sinRot, cosRot);
+
+    vec2 dvec = texCoord0.xy - intLightPos;
+    float dist = dot( dvec, uvDir );
+    float fallRate = log2( max( abs(intLightFall), 1.01 ) );
+    vec3 fallCol = exp2( -abs(dist) * fallRate / absorb_color );
+
+    vec3 projDir = (tangent * uvDir.x + binormal * uvDir.y) * dist * intLightFall - surfNormal * refract_depth;
+    projDir = normalize(projDir);
+
+    vec4 retVal = vec4(lightColor * fallCol, 1.0);
+    retVal *= abs(dot( projDir, -ftmp2 ));
+    retVal.a = pow( retVal.a, uFresnelPower );
+    retVal.a *= clamp( intLightBrt * exp2(-dist * fallRate), 0.0, 1.0 );
+
+    return retVal;
+}
+
+vec4 computeGlass(in vec3 normal, in float materialIOR, in float alpha, in vec4 color)
+{
+  vec4 rgba = color;
+  float ratio = simpleFresnel( normal, materialIOR, uFresnelPower );
+  vec3 absorb_color = ( log( glass_color ) * -1.000000 );
+  // prevent log(0) -> inf number issue
+  if ( isinf(absorb_color.r) ) absorb_color.r = 1.0;
+  if ( isinf(absorb_color.g) ) absorb_color.g = 1.0;
+  if ( isinf(absorb_color.b) ) absorb_color.b = 1.0;
+  rgba.rgb *= (vec3(1.0) - absorb_color);
+
+  vec2 texSize = vec2( textureSize( refractiveTexture, 0 ) );
+  vec3 newUV = vec3((gl_FragCoord.xy * 0.5) / texSize, 0.0);
+  vec4 value = texture( refractiveTexture, newUV.xy );
+
+  newUV = getRefractUV( newUV.xy, normal, materialIOR, 0.01 * refract_depth );
+  vec4 refractValue = texture( refractiveTexture, newUV.xy );
+
+  vec3 refractColor = refractValue.a * refractValue.rgb + (1.0 - refractValue.a) * value.rgb;
+  refractColor = refractColor * (vec3(1.0) - absorb_color);
+  vec4 internalColor = doFakeInnerLight( normal, glass_color );
+  refractColor += internalColor.rgb * internalColor.a;
+
+  rgba = vec4(mix(refractColor, rgba.rgb, ratio), 1.0);
+  return rgba;
+}
+
+        </FragmentShader>
+    </Shader>
+    <Shader name="NOOP">
+<VertexShader>
+</VertexShader>
+<FragmentShader>
+#define QDEMON_ENABLE_UV0 1
+#define QDEMON_ENABLE_WORLD_POSITION 1
+#define QDEMON_ENABLE_TEXTAN 1
+
+vec3 texCoord0;
+
+void main()
+{
+
+    // This is a bit silly, but the thing is that a buffer blit takes place on this
+    // pass, and if you do a buffer blit on a pass that outputs to lower-resolution,
+    // it only blits a smaller portion of the backbuffer that occupies that number of
+    // pixels.  So we need a dummy no-op pass that is full-res in order to blit everything.
diff --git a/examples/quick3d/simple/frostedThinGlassBlurX.frag b/examples/quick3d/simple/frostedThinGlassBlurX.frag
new file mode 100644
index 0000000000000000000000000000000000000000..97918501af74e58892a453e207e21f1699504da8
--- /dev/null
+++ b/examples/quick3d/simple/frostedThinGlassBlurX.frag
@@ -0,0 +1,34 @@
+#define QDEMON_ENABLE_UV0 1
+#define QDEMON_ENABLE_WORLD_POSITION 1
+#define QDEMON_ENABLE_TEXTAN 1
+
+vec3 texCoord0;
+
+uniform sampler2D BlurBuffer;
+
+void main()
+{
+    vec2 texSize = vec2( textureSize( BlurBuffer, 0 ) );
+    texSize = vec2(1.0) / texSize;
+    texCoord0.z = 0.0;
+    texCoord0.xy = vec2(gl_FragCoord.xy * texSize);
+
+    float sigma = clamp(blur_size * 0.5, 0.5, 100.0);
+    int smpCount = int(ceil( sigma ));
+    vec4 value = texture(BlurBuffer, texCoord0.xy);
+    float wtsum = 1.0;
+    for (int i = 1; i &lt;= smpCount; ++i)
+    {
+        // Base 2 Gaussian blur
+        float wt = float(i) / (sigma * 0.5);
+        wt = exp2( -wt*wt );
+        vec2 texOfs = vec2(i, 0) * texSize;
+        value += wt * texture(BlurBuffer, texCoord0.xy+texOfs);
+        value += wt * texture(BlurBuffer, texCoord0.xy-texOfs);
+        wtsum += wt * 2.0;
+    }
+
+    gl_FragColor = value / wtsum;
+    gl_FragColor.a = 1.0;
+
+    // No close paren because the generator adds it for us.
diff --git a/examples/quick3d/simple/frostedThinGlassBlurY.frag b/examples/quick3d/simple/frostedThinGlassBlurY.frag
new file mode 100644
index 0000000000000000000000000000000000000000..5a9c5f8366577e1b2444b95974289da8771b2003
--- /dev/null
+++ b/examples/quick3d/simple/frostedThinGlassBlurY.frag
@@ -0,0 +1,41 @@
+#define QDEMON_ENABLE_UV0 1
+#define QDEMON_ENABLE_WORLD_POSITION 1
+#define QDEMON_ENABLE_TEXTAN 1
+
+vec3 texCoord0;
+
+uniform sampler2D BlurBuffer;
+uniform sampler2D OriginBuffer;
+
+void main()
+{
+    vec2 texSize = vec2( textureSize( BlurBuffer, 0 ) );
+    texSize = vec2(1.0) / texSize;
+    texCoord0.z = 0.0;
+    texCoord0.xy = vec2(gl_FragCoord.xy * texSize);
+
+    float sigma = clamp(blur_size * 0.5, 0.5, 100.0);
+    int smpCount = int(ceil( sigma ));
+    vec4 value = texture(BlurBuffer, texCoord0.xy);
+
+    float wtsum = 1.0;
+    for (int i = 1; i &lt;= smpCount; ++i)
+    {
+        // Base 2 Gaussian blur
+        float wt = float(i) / (sigma * 0.5);
+        wt = exp2( -wt*wt );
+        vec2 texOfs = vec2(0, i) * texSize;
+        vec4 posValue = texture(BlurBuffer, texCoord0.xy+texOfs);
+        vec4 negValue = texture(BlurBuffer, texCoord0.xy-texOfs);
+        posValue = posValue.a * posValue + (1.0 - posValue.a) * texture(OriginBuffer, texCoord0.xy+texOfs);
+        negValue = negValue.a * negValue + (1.0 - negValue.a) * texture(OriginBuffer, texCoord0.xy-texOfs);
+
+        value += wt * posValue;
+        value += wt * negValue;
+        wtsum += wt * 2.0;
+    }
+
+    gl_FragColor = (value / wtsum);
+    gl_FragColor.a = 1.0;
+
+    // No close paren because the generator adds it for us.
diff --git a/examples/quick3d/simple/frostedThinGlassPreBlur.frag b/examples/quick3d/simple/frostedThinGlassPreBlur.frag
new file mode 100644
index 0000000000000000000000000000000000000000..ac656bb56ee88a064db5960dbec0c79910554b5c
--- /dev/null
+++ b/examples/quick3d/simple/frostedThinGlassPreBlur.frag
@@ -0,0 +1,32 @@
+#define QDEMON_ENABLE_UV0 1
+#define QDEMON_ENABLE_WORLD_POSITION 1
+#define QDEMON_ENABLE_TEXTAN 1
+
+vec3 texCoord0;
+
+uniform sampler2D OriginBuffer;
+
+void main()
+{
+    vec2 texSize = vec2( textureSize( OriginBuffer, 0 ) );
+    texSize = vec2(1.0) / texSize;
+    texCoord0.z = 0.0;
+    texCoord0.xy = vec2(gl_FragCoord.xy * 2.0 * texSize);
+
+    float wtSum = 0.0;
+    vec4 totSum = vec4(0.0);
+    for (int ix = -1; ix &lt;= 1; ++ix)
+    {
+       for (int iy = -1; iy &lt;= 1; ++iy)
+       {
+        float wt = float(ix*ix + iy*iy) * 4.0;
+        wt = exp2( -wt );
+        vec2 texOfs = vec2(ix, iy) * texSize;
+        totSum += wt * texture( OriginBuffer, texCoord0.xy + texOfs );
+        wtSum += wt;
+       }
+    }
+
+    totSum /= wtSum;
+    gl_FragColor = totSum;
+    // No close paren because the generator adds it for us.
diff --git a/examples/quick3d/simple/main.qml b/examples/quick3d/simple/main.qml
index aa9526bcccb19081639b5d2b61140d8e17afdf19..da5bc0113ed2d9b59beb4c3a30945dff44c6b9af 100644
--- a/examples/quick3d/simple/main.qml
+++ b/examples/quick3d/simple/main.qml
@@ -15,17 +15,23 @@ Window {
         camera: camera
 
         // Light always points the same direction as camera
-        DemonLight {
-            id: directionalLight
-            lightType: DemonLight.Directional
-            rotation: Qt.vector3d(0, 0, 0)
-            SequentialAnimation on rotation {
-                loops: Animation.Infinite
-                PropertyAnimation { duration: 5000; to: Qt.vector3d(0, 360, 0); from: Qt.vector3d(0, 0, 0) }
+//        DemonLight {
+//            id: directionalLight
+//            lightType: DemonLight.Directional
+//            rotation: Qt.vector3d(0, 0, 0)
+//            SequentialAnimation on rotation {
+//                loops: Animation.Infinite
+//                PropertyAnimation { duration: 5000; to: Qt.vector3d(0, 360, 0); from: Qt.vector3d(0, 0, 0) }
+//            }
+//        }
+
+        environment: DemonSceneEnvironment {
+            probeBrightness: 1000
+            lightProbe: DemonImage {
+                source: ":/maps/OpenfootageNET_garage-1024.hdr"
             }
         }
 
-
         DemonNode {
             id: cameraSpinner
             position: Qt.vector3d(0, 0, 0);
@@ -99,5 +105,22 @@ Window {
             x: -300
         }
 
+        CopperCube {
+            id: copperCube
+            SequentialAnimation on metalColor {
+                loops: Animation.Infinite
+                PropertyAnimation { duration: 2000; to: Qt.vector3d(0.805, 0.0, 0.305) }
+                PropertyAnimation { duration: 2000; to: Qt.vector3d(0.805, 1.0, 0.305) }
+            }
+        }
+
+        DemonModel {
+            position: Qt.vector3d(300, 0, 0)
+            source: "#Cube"
+            materials: [ SimpleGlassMaterial {
+                    id: texturedCubeMaterial
+                }
+            ]
+        }
     }
 }
diff --git a/examples/quick3d/simple/maps/OpenfootageNET_garage-1024.hdr b/examples/quick3d/simple/maps/OpenfootageNET_garage-1024.hdr
new file mode 100644
index 0000000000000000000000000000000000000000..01e9e38ac2eb48679de45be85aca47f658da44d6
Binary files /dev/null and b/examples/quick3d/simple/maps/OpenfootageNET_garage-1024.hdr differ
diff --git a/examples/quick3d/simple/maps/shadow.png b/examples/quick3d/simple/maps/shadow.png
new file mode 100644
index 0000000000000000000000000000000000000000..599b1cccae8fef146df32ed5a8f0897e3b6a2dba
Binary files /dev/null and b/examples/quick3d/simple/maps/shadow.png differ
diff --git a/examples/quick3d/simple/maps/spherical_checker.png b/examples/quick3d/simple/maps/spherical_checker.png
new file mode 100644
index 0000000000000000000000000000000000000000..e42394dd0e197df98d57042a71dea8949e7c5e66
Binary files /dev/null and b/examples/quick3d/simple/maps/spherical_checker.png differ
diff --git a/examples/quick3d/simple/materials.qrc b/examples/quick3d/simple/materials.qrc
new file mode 100644
index 0000000000000000000000000000000000000000..54e013406e250dd44f2c73754a00b5465500c0a0
--- /dev/null
+++ b/examples/quick3d/simple/materials.qrc
@@ -0,0 +1,7 @@
+<RCC>
+    <qresource prefix="/">
+        <file>maps/shadow.png</file>
+        <file>maps/spherical_checker.png</file>
+        <file>maps/OpenfootageNET_garage-1024.hdr</file>
+    </qresource>
+</RCC>
diff --git a/examples/quick3d/simple/porcelain.frag b/examples/quick3d/simple/porcelain.frag
new file mode 100644
index 0000000000000000000000000000000000000000..81357a99113d1acee2eadf71cff61da9f835704c
--- /dev/null
+++ b/examples/quick3d/simple/porcelain.frag
@@ -0,0 +1,149 @@
+// add enum defines
+#define scatter_reflect 0
+#define scatter_transmit 1
+#define scatter_reflect_transmit 2
+
+#define QDEMON_ENABLE_UV0 1
+#define QDEMON_ENABLE_WORLD_POSITION 1
+#define QDEMON_ENABLE_TEXTAN 1
+#define QDEMON_ENABLE_BINORMAL 0
+
+#include "vertexFragmentBase.glsllib"
+
+// set shader output
+out vec4 fragColor;
+
+// add structure defines
+struct layer_result
+{
+  vec4 base;
+  vec4 layer;
+  mat3 tanFrame;
+};
+
+
+// temporary declarations
+vec4 tmpShadowTerm;
+
+layer_result layers[1];
+
+#include "SSAOCustomMaterial.glsllib"
+#include "sampleLight.glsllib"
+#include "sampleProbe.glsllib"
+#include "sampleArea.glsllib"
+#include "square.glsllib"
+#include "calculateRoughness.glsllib"
+#include "evalBakedShadowMap.glsllib"
+#include "evalEnvironmentMap.glsllib"
+#include "luminance.glsllib"
+#include "microfacetBSDF.glsllib"
+#include "physGlossyBSDF.glsllib"
+#include "simpleGlossyBSDF.glsllib"
+#include "diffuseReflectionBSDF.glsllib"
+#include "fresnelLayer.glsllib"
+
+bool evalTwoSided()
+{
+  return( false );
+}
+
+vec3 computeFrontMaterialEmissive()
+{
+  return( vec3( 0, 0, 0 ) );
+}
+
+void computeFrontLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += tmpShadowTerm * diffuseReflectionBSDF( normal, lightDir, viewDir, lightDiffuse, 0.000000 );
+  layers[0].layer += tmpShadowTerm * microfacetBSDF( layers[0].tanFrame, lightDir, viewDir, lightSpecular, materialIOR, roughness, roughness, scatter_reflect );
+#endif
+}
+
+void computeFrontAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += tmpShadowTerm * lightDiffuse * sampleAreaDiffuse( layers[0].tanFrame, varWorldPos, lightIdx );
+  layers[0].layer += tmpShadowTerm * lightSpecular * sampleAreaGlossy( layers[0].tanFrame, varWorldPos, lightIdx, viewDir, roughness, roughness );
+#endif
+}
+
+void computeFrontLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QDEMON_ENABLE_LIGHT_PROBE
+  layers[0].base += tmpShadowTerm * diffuseReflectionBSDFEnvironment( normal, 0.000000 ) * aoFactor;
+  layers[0].layer += tmpShadowTerm * microfacetSampledBSDF( layers[0].tanFrame, viewDir, roughness, roughness, scatter_reflect );
+
+#else
+  layers[0].base += tmpShadowTerm * sampleDiffuse( layers[0].tanFrame ) * aoFactor;
+  layers[0].layer += tmpShadowTerm * sampleGlossyAniso( layers[0].tanFrame, viewDir, roughness, roughness );
+#endif
+}
+
+vec3 computeBackMaterialEmissive()
+{
+  return( vec3(0, 0, 0) );
+}
+
+void computeBackLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QDEMON_ENABLE_LIGHT_PROBE
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#else
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+float computeIOR()
+{
+  return( false ? 1.0f : luminance( vec3( 1, 1, 1 ) ) );
+}
+
+float evalCutout()
+{
+  return( 1.000000 );
+}
+
+vec3 computeNormal()
+{
+  return( normal );
+}
+
+void computeTemporaries()
+{
+     tmpShadowTerm = evalBakedShadowMap( texCoord0 );
+}
+
+vec4 computeLayerWeights( in float alpha )
+{
+  vec4 color;
+  color = fresnelLayer( normal, vec3( material_ior ), glossy_weight, vec4( vec3( 1, 1, 1 ), 1.0).rgb, layers[0].layer, layers[0].base * vec4( porcelain_color, 1.0), alpha );
+  return color;
+}
+
+
+void initializeLayerVariables(void)
+{
+  // clear layers
+  layers[0].base = vec4(0.0, 0.0, 0.0, 1.0);
+  layers[0].layer = vec4(0.0, 0.0, 0.0, 1.0);
+  layers[0].tanFrame = orthoNormalize( mat3( tangent, cross(normal, tangent), normal ) );
+}
diff --git a/examples/quick3d/simple/qml.qrc b/examples/quick3d/simple/qml.qrc
index f7b651bd9a133b13669d0745875a04a91bcc8bd5..e1838058e26698956998cda1cc243db89bbab4f8 100644
--- a/examples/quick3d/simple/qml.qrc
+++ b/examples/quick3d/simple/qml.qrc
@@ -6,5 +6,17 @@
         <file>WeirdShape.qml</file>
         <file>texture.png</file>
         <file>TexturedCube.qml</file>
+        <file>CopperCube.qml</file>
+        <file>CopperMaterial.qml</file>
+        <file>copper.frag</file>
+        <file>SimpleGlassMaterial.qml</file>
+        <file>PorcelainMaterial.qml</file>
+        <file>porcelain.frag</file>
+        <file>simpleGlass.frag</file>
+        <file>frostedThinGlass.frag</file>
+        <file>FrostedThinGlassMaterial.qml</file>
+        <file>frostedThinGlassPreBlur.frag</file>
+        <file>frostedThinGlassBlurX.frag</file>
+        <file>frostedThinGlassBlurY.frag</file>
     </qresource>
 </RCC>
diff --git a/examples/quick3d/simple/simple.pro b/examples/quick3d/simple/simple.pro
index 23378a076d133442a1a8eb5722130064074d5f97..ee48a6d33249cbc1f982091fb3ec5945c2e7c34d 100644
--- a/examples/quick3d/simple/simple.pro
+++ b/examples/quick3d/simple/simple.pro
@@ -8,4 +8,5 @@ SOURCES += \
     main.cpp
 
 RESOURCES += \
-    qml.qrc
+    qml.qrc \
+    materials.qrc
diff --git a/examples/quick3d/simple/simpleGlass.frag b/examples/quick3d/simple/simpleGlass.frag
new file mode 100644
index 0000000000000000000000000000000000000000..1406c2451150ce580dd57b16bb16a54f4b76b396
--- /dev/null
+++ b/examples/quick3d/simple/simpleGlass.frag
@@ -0,0 +1,161 @@
+// add enum defines
+#define scatter_reflect 0
+#define scatter_transmit 1
+#define scatter_reflect_transmit 2
+
+#define QDEMON_ENABLE_UV0 1
+#define QDEMON_ENABLE_WORLD_POSITION 1
+#define QDEMON_ENABLE_TEXTAN 1
+#define QDEMON_ENABLE_BINORMAL 0
+
+#include "vertexFragmentBase.glsllib"
+
+// set shader output
+out vec4 fragColor;
+
+// add structure defines
+struct layer_result
+{
+  vec4 base;
+  vec4 layer;
+  mat3 tanFrame;
+};
+
+
+// temporary declarations
+vec3 ftmp0;
+ vec4 tmpShadowTerm;
+
+layer_result layers[1];
+
+#include "SSAOCustomMaterial.glsllib"
+#include "sampleLight.glsllib"
+#include "sampleProbe.glsllib"
+#include "sampleArea.glsllib"
+#include "square.glsllib"
+#include "calculateRoughness.glsllib"
+#include "evalBakedShadowMap.glsllib"
+#include "evalEnvironmentMap.glsllib"
+#include "luminance.glsllib"
+#include "microfacetBSDF.glsllib"
+#include "physGlossyBSDF.glsllib"
+#include "simpleGlossyBSDF.glsllib"
+#include "abbeNumberIOR.glsllib"
+#include "fresnelLayer.glsllib"
+#include "refraction.glsllib"
+
+bool evalTwoSided()
+{
+  return( true );
+}
+
+vec3 computeFrontMaterialEmissive()
+{
+  return( vec3( 0, 0, 0 ) );
+}
+
+void computeFrontLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += tmpShadowTerm * microfacetBSDF( layers[0].tanFrame, lightDir, viewDir, lightSpecular, materialIOR, 0.000000, 0.000000, scatter_reflect_transmit );
+#endif
+}
+
+void computeFrontAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += tmpShadowTerm * lightSpecular * sampleAreaGlossy( layers[0].tanFrame, varWorldPos, lightIdx, viewDir, 0.000000, 0.000000 );
+#endif
+}
+
+void computeFrontLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QDEMON_ENABLE_LIGHT_PROBE
+  layers[0].base += tmpShadowTerm * microfacetSampledBSDF( layers[0].tanFrame, viewDir, 0.000000, 0.000000, scatter_reflect_transmit );
+#else
+  layers[0].base += tmpShadowTerm * sampleGlossyAniso( layers[0].tanFrame, viewDir, 0.000000, 0.000000 );
+#endif
+}
+
+vec3 computeBackMaterialEmissive()
+{
+  return( vec3(0, 0, 0) );
+}
+
+void computeBackLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QDEMON_ENABLE_CG_LIGHTING
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QDEMON_ENABLE_LIGHT_PROBE
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#else
+  layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+  layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+float computeIOR()
+{
+  return( true ? 1.0f : luminance( vec3( abbeNumberIOR(glass_ior, 0.000000 ) ) ) );
+}
+
+float evalCutout()
+{
+  return( 1.000000 );
+}
+
+vec3 computeNormal()
+{
+  return( normal );
+}
+
+void computeTemporaries()
+{
+     ftmp0 = vec3( reflectivity_amount );
+     tmpShadowTerm = evalBakedShadowMap( texCoord0 );
+}
+
+vec4 computeLayerWeights( in float alpha )
+{
+  vec4 color;
+  color = layers[0].base * vec4( ftmp0, 1.0);
+  return color;
+}
+
+
+void initializeLayerVariables(void)
+{
+  // clear layers
+  layers[0].base = vec4(0.0, 0.0, 0.0, 1.0);
+  layers[0].layer = vec4(0.0, 0.0, 0.0, 1.0);
+  layers[0].tanFrame = orthoNormalize( tangentFrame( normal, varWorldPos ) );
+}
+
+vec4 computeGlass(in vec3 normal, in float materialIOR, in float alpha, in vec4 color)
+{
+  vec4 rgba = color;
+  float ratio = simpleFresnel( normal, materialIOR, uFresnelPower );
+  vec3 absorb_color = ( log( glass_color )/-1.000000 );
+  // prevent log(0) -> inf number issue
+  if ( isinf(absorb_color.r) ) absorb_color.r = 1.0;
+  if ( isinf(absorb_color.g) ) absorb_color.g = 1.0;
+  if ( isinf(absorb_color.b) ) absorb_color.b = 1.0;
+  rgba.rgb = mix(vec3(1.0) - absorb_color, rgba.rgb * (vec3(1.0) - absorb_color), ratio);
+  rgba.a = mix(uMinOpacity, alpha, ratio);
+  return rgba;
+}
diff --git a/src/imports/demon/plugin.cpp b/src/imports/demon/plugin.cpp
index 426abd5ff8458fdb935de7994c8371b75bea32f9..f904ad8c53793932b12eaa54c2d8cda25f2c049f 100644
--- a/src/imports/demon/plugin.cpp
+++ b/src/imports/demon/plugin.cpp
@@ -86,6 +86,15 @@ public:
 
         qmlRegisterType<QDemonCamera>(uri, 1, 0, "DemonCamera");
         qmlRegisterType<QDemonCustomMaterial>(uri, 1, 0, "DemonCustomMaterial");
+        qmlRegisterType<QDemonCustomMaterialShader>(uri, 1, 0, "DemonCustomMaterialShader");
+        qmlRegisterType<QDemonCustomMaterialShaderInfo>(uri, 1, 0, "DemonCustomMaterialShaderInfo");
+        qmlRegisterType<QDemonCustomMaterialTexture>(uri, 1, 0, "DemonCustomMaterialTexture");
+        qmlRegisterType<QDemonCustomMaterialRenderPass>(uri, 1, 0, "DemonCustomMaterialPass");
+        qmlRegisterType<QDemonCustomMaterialRenderCommand>(uri, 1, 0, "DemonCustomMaterialCommand");
+        qmlRegisterType<QDemonCustomMaterialBufferInput>(uri, 1, 0, "DemonCustomMaterialBufferInput");
+        qmlRegisterType<QDemonCustomMaterialBufferBlit>(uri, 1, 0, "DemonCustomMaterialBufferBlit");
+        qmlRegisterType<QDemonCustomMaterialBlending>(uri, 1, 0, "DemonCustomMaterialBlending");
+        qmlRegisterType<QDemonCustomMaterialRenderState>(uri, 1, 0, "DemonCustomMaterialRenderState");
         qmlRegisterType<QDemonDefaultMaterial>(uri, 1, 0, "DemonDefaultMaterial");
         qmlRegisterType<QDemonEffect>(uri, 1, 0, "DemonEffect");
         qmlRegisterType<QDemonImage>(uri, 1, 0, "DemonImage");
diff --git a/src/quick3d/qdemoncustommaterial.cpp b/src/quick3d/qdemoncustommaterial.cpp
index 6550e7581976a6154266cb65e0d0687205c98199..2e4e9c097cd7e3c6b5f1ea237028f6109d139840 100644
--- a/src/quick3d/qdemoncustommaterial.cpp
+++ b/src/quick3d/qdemoncustommaterial.cpp
@@ -1,5 +1,9 @@
 #include "qdemoncustommaterial.h"
 #include <QtDemonRuntimeRender/qdemonrendercustommaterial.h>
+#include <QtDemonRuntimeRender/qdemonrendercontextcore.h>
+
+#include "qdemonobject_p.h"
+#include "qdemonview3d.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -32,6 +36,46 @@ QString QDemonCustomMaterial::source() const
     return m_source;
 }
 
+QDemonCustomMaterialShaderInfo *QDemonCustomMaterial::shaderInfo() const
+{
+    return m_shaderInfo;
+}
+
+QQmlListProperty<QDemonCustomMaterialShader> QDemonCustomMaterial::shaders()
+{
+    return QQmlListProperty<QDemonCustomMaterialShader>(this,
+                                                        nullptr,
+                                                        QDemonCustomMaterial::qmlAppendShader,
+                                                        QDemonCustomMaterial::qmlShaderCount,
+                                                        QDemonCustomMaterial::qmlShaderAt,
+                                                        nullptr);
+}
+
+QQmlListProperty<QDemonCustomMaterialTexture> QDemonCustomMaterial::textures()
+{
+    return QQmlListProperty<QDemonCustomMaterialTexture>(this,
+                                                         nullptr,
+                                                         QDemonCustomMaterial::qmlAppendTexture,
+                                                         QDemonCustomMaterial::qmlTextureCount,
+                                                         QDemonCustomMaterial::qmlTextureAt,
+                                                         nullptr);
+}
+
+QQmlListProperty<QDemonCustomMaterialRenderPass> QDemonCustomMaterial::passes()
+{
+    return QQmlListProperty<QDemonCustomMaterialRenderPass>(this,
+                                                            nullptr,
+                                                            QDemonCustomMaterial::qmlAppendPass,
+                                                            QDemonCustomMaterial::qmlPassCount,
+                                                            QDemonCustomMaterial::qmlPassAt,
+                                                            nullptr);
+}
+
+bool QDemonCustomMaterial::alwaysDirty() const
+{
+    return m_alwaysDirty;
+}
+
 void QDemonCustomMaterial::setHasTransparency(bool hasTransparency)
 {
     if (m_hasTransparency == hasTransparency)
@@ -68,11 +112,375 @@ void QDemonCustomMaterial::setSource(QString source)
     emit sourceChanged(m_source);
 }
 
+void QDemonCustomMaterial::setShaderInfo(QDemonCustomMaterialShaderInfo *shaderInfo)
+{
+    m_shaderInfo = shaderInfo;
+}
+
+void QDemonCustomMaterial::setAlwaysDirty(bool alwaysDirty)
+{
+    if (m_alwaysDirty == alwaysDirty)
+        return;
+
+    m_alwaysDirty = alwaysDirty;
+    emit alwaysDirtyChanged(m_alwaysDirty);
+}
+
 QDemonRenderGraphObject *QDemonCustomMaterial::updateSpatialNode(QDemonRenderGraphObject *node)
 {
-    // TODO: Create and update customer material (special)
+    static const auto updateShaderPrefix = [](QByteArray &shaderPrefix, const QByteArray &name) {
+        const char *filter = "linear";
+        const char *clamp = "clamp";
+        // Output macro so we can change the set of variables used for this
+        // independent of the
+        // meta data system.
+        shaderPrefix.append("SNAPPER_SAMPLER2D(");
+        shaderPrefix.append(name);
+        shaderPrefix.append(", ");
+        shaderPrefix.append(name);
+        shaderPrefix.append(", ");
+        shaderPrefix.append(filter);
+        shaderPrefix.append(", ");
+        shaderPrefix.append(clamp);
+        shaderPrefix.append(", ");
+        shaderPrefix.append("false )\n");
+    };
+
+    static const auto appendShaderUniform = [](const QString &type, const QByteArray &name, QByteArray *shaderPrefix, const QString &value = QString()) {
+        shaderPrefix->append(QStringLiteral("uniform %1 %2 %3;\n").arg(type).arg(QString::fromLatin1(name)).arg(value.isEmpty() ? QString() : QString("= %1").arg(value)).toLatin1());
+    };
+
+    static const auto resolveShader = [](const QByteArray &shader) -> QByteArray {
+        int offset = -1;
+        if (shader.startsWith("qrc"))
+            offset = 3;
+        else if (shader.startsWith("file:/"))
+            offset = 0;
+        else if (shader.startsWith(":/"))
+            offset = 0;
+
+        QString path;
+        if (offset == -1) {
+            QUrl u(QString::fromUtf8(shader));
+            if (u.isLocalFile())
+                path = u.toLocalFile();
+        }
 
-    return node;
+        if (offset == -1 && path.isEmpty())
+            path = QString::fromLatin1(":/") + QString::fromUtf8(shader);
+        else
+            path = QString::fromUtf8(shader.constData() + offset);
+
+        QFile f(path);
+        if (f.open(QIODevice::ReadOnly | QIODevice::Text))
+            return f.readAll();
+
+        return shader;
+    };
+
+
+    // Sanity check(s)
+    if (!m_shaderInfo->isValid()) {
+        qWarning("ShaderInfo is not valid!");
+        return node;
+    }
+
+    if (node)
+        QDemonMaterial::updateSpatialNode(node);
+
+    QDemonRenderCustomMaterial *customMaterial = static_cast<QDemonRenderCustomMaterial *>(node);
+    if (!customMaterial) {
+        customMaterial = new QDemonRenderCustomMaterial;
+        customMaterial->m_layerCount = m_shaderInfo->layers;
+        customMaterial->m_shaderKeyValues = static_cast<QDemonRenderCustomMaterial::MaterialShaderKeyFlags>(m_shaderInfo->shaderKey);
+        customMaterial->className = metaObject()->className();
+        customMaterial->m_alwaysDirty = m_alwaysDirty;
+        customMaterial->m_hasTransparency = m_hasTransparency;
+        customMaterial->m_hasRefraction = m_hasRefraction;
+        customMaterial->m_hasVolumetricDF = m_hasVolumetricDF;
+
+        // Shader info
+        auto &shaderInfo = customMaterial->shaderInfo;
+        shaderInfo.type = m_shaderInfo->type;
+        shaderInfo.version = m_shaderInfo->version;
+        shaderInfo.shaderPrefix = m_shaderInfo->shaderPrefix;
+
+        QMetaMethod propertyDirtyMethod;
+        const int idx = metaObject()->indexOfSlot("onPropertyDirty()");
+        if (idx != -1)
+            propertyDirtyMethod = metaObject()->method(idx);
+
+        // Properties
+        const int propCount = metaObject()->propertyCount();
+        const int propOffset = metaObject()->propertyOffset();
+        for (int i = propOffset; i != propCount; ++i) {
+            const auto property = metaObject()->property(i);
+            if (Q_UNLIKELY(!property.isValid()))
+                continue;
+
+            // Track the property changes
+            if (property.hasNotifySignal() && propertyDirtyMethod.isValid())
+                connect(this, property.notifySignal(), this, propertyDirtyMethod);
+
+            const QVariant value = property.read(this);
+            if (Q_UNLIKELY(!value.isValid()))
+                continue;
+
+            QDemonRenderCustomMaterial::Property demonProp;
+            demonProp.name = property.name();
+            demonProp.value = value;
+            demonProp.pid = i;
+            QString type;
+            // TODO: Only types for copper are vec3, bool and float
+            if (value.type() == QVariant::Double) {
+                type = QStringLiteral("float");
+                demonProp.shaderDataType = QDemonRenderShaderDataType::Float;
+            } else if (value.type() == QVariant::Bool) {
+                type = QStringLiteral("bool");
+                demonProp.shaderDataType = QDemonRenderShaderDataType::Boolean;
+            } else if (value.type() == QVariant::Vector2D) {
+                type = QStringLiteral("vec2");
+                demonProp.shaderDataType = QDemonRenderShaderDataType::Vec2;
+            } else if (value.type() == QVariant::Vector3D) {
+                type = QStringLiteral("vec3");
+                demonProp.shaderDataType = QDemonRenderShaderDataType::Vec3;
+            } else if (value.type() == QVariant::Vector4D) {
+                type = QStringLiteral("vec4");
+                demonProp.shaderDataType = QDemonRenderShaderDataType::Vec4;
+            } else if (value.type() == QVariant::Int) {
+                type = QStringLiteral("int");
+                demonProp.shaderDataType = QDemonRenderShaderDataType::Integer;
+            } else {
+                Q_ASSERT(0);
+            }
+
+            appendShaderUniform(type, demonProp.name, &shaderInfo.shaderPrefix);
+            customMaterial->properties.push_back(demonProp);
+        }
+
+        // Textures
+        for (const auto &texture : qAsConst(m_textures)) {
+            QDemonRenderCustomMaterial::TextureProperty textureData;
+            const QByteArray &name = texture->name;
+            if (name.isEmpty()) // Warnings here will just drown in the shader error messages
+                continue;
+            QDemonImage *image = texture->image(); //
+            connect(texture, &QDemonCustomMaterialTexture::textureDirty, this, &QDemonCustomMaterial::onTextureDirty);
+            textureData.name = name;
+            if (texture->enabled)
+                textureData.texImage = image->getRenderImage();
+            textureData.usageType = QDemonRenderTextureTypeValue(texture->type);
+            textureData.shaderDataType = QDemonRenderShaderDataType::Texture2D;
+            textureData.clampType = image->horizontalTiling() == QDemonImage::Repeat ? QDemonRenderTextureCoordOp::Repeat
+                                                                                     : (image->horizontalTiling() == QDemonImage::ClampToEdge) ? QDemonRenderTextureCoordOp::ClampToEdge
+                                                                                                                                               : QDemonRenderTextureCoordOp::MirroredRepeat;
+            updateShaderPrefix(shaderInfo.shaderPrefix, textureData.name);
+            customMaterial->textureProperties.push_back(textureData);
+        }
+
+        // Shaders
+        QByteArray shaderCode = shaderInfo.shaderPrefix;
+        QByteArray shared, vertex, geometry, fragment;
+        for (const auto &shader : qAsConst(m_shaders)) {
+            const QByteArray code = resolveShader(shader->shader);
+            switch (shader->stage) {
+            case QDemonCustomMaterialShader::Stage::Shared:
+                if (!code.isEmpty())
+                    shared.append(code);
+                break;
+            case QDemonCustomMaterialShader::Stage::Geometry:
+                if (!code.isEmpty()) {
+                    geometry.append(QByteArrayLiteral("\n#ifdef USER_GEOMETRY_SHADER\n"));
+                    geometry.append(code);
+                    geometry.append(QByteArrayLiteral("\n#endif\n"));
+                    // TODO: Set m_HasGeomShader to true
+                }
+                break;
+            case QDemonCustomMaterialShader::Stage::Vertex:
+                vertex.append(QByteArrayLiteral("\n#ifdef VERTEX_SHADER\n"));
+                if (code.isEmpty())
+                    vertex.append(QByteArrayLiteral("void vert(){}"));
+                else
+                    vertex.append(code);
+                vertex.append(QByteArrayLiteral("\n#endif\n"));
+                break;
+            case QDemonCustomMaterialShader::Stage::Fragment:
+                fragment.append(QByteArrayLiteral("\n#ifdef FRAGMENT_SHADER\n"));
+                if (code.isEmpty())
+                    fragment.append(QByteArrayLiteral("void frag(){}"));
+                else
+                    fragment.append(code);
+                fragment.append(QByteArrayLiteral("\n#endif\n"));
+                break;
+            }
+        }
+
+        if (!shared.isEmpty())
+            shaderCode.append(shared);
+        if (!vertex.isEmpty())
+            shaderCode.append(vertex);
+        if (!geometry.isEmpty())
+            shaderCode.append(geometry);
+        if (!fragment.isEmpty())
+            shaderCode.append(fragment);
+
+        if (!m_shaders.isEmpty()) {
+            // Find the parent view
+            QObject *p = this;
+            QDemonView3D *view = nullptr;
+            while (p != nullptr && view == nullptr) {
+                p = p->parent();
+                if ((view = qobject_cast<QDemonView3D *>(p)))
+                    break;
+            }
+
+            Q_ASSERT(view);
+
+            customMaterial->commands.push_back(new dynamic::QDemonBindShader(metaObject()->className()));
+            customMaterial->commands.push_back(new dynamic::QDemonApplyInstanceValue());
+
+            QDemonRenderContextInterface::QDemonRenderContextInterfacePtr renderContext = QDemonRenderContextInterface::getRenderContextInterface(quintptr(view->window()));
+            renderContext->customMaterialSystem()->setMaterialClassShader(QString::fromLatin1(customMaterial->className), shaderInfo.type, shaderInfo.version, shaderCode, false, false);
+        }
+
+        for (const auto &pass : qAsConst(m_passes)) {
+            QDemonRenderCustomMaterial::Pass demonPass;
+            for (const auto &command : pass->m_commands)
+                customMaterial->commands.push_back(command->getCommand());
+            customMaterial->passes.push_back(demonPass);
+        }
+
+        customMaterial->commands.push_back(new dynamic::QDemonRender(false));
+    }
+
+    if (m_dirtyAttributes & Dirty::PropertyDirty) {
+        for (const auto &prop : qAsConst(customMaterial->properties)) {
+            auto p = metaObject()->property(prop.pid);
+            if (Q_LIKELY(p.isValid()))
+                prop.value = p.read(this);
+        }
+    }
+
+    if (m_dirtyAttributes & Dirty::TextureDirty) {
+        // TODO:
+        for (const auto &texture : qAsConst(m_textures));
+    }
+
+    return customMaterial;
+}
+
+void QDemonCustomMaterial::onPropertyDirty()
+{
+    markDirty(Dirty::PropertyDirty);
+    update();
+}
+
+void QDemonCustomMaterial::onTextureDirty(QDemonCustomMaterialTexture *texture)
+{
+    Q_UNUSED(texture)
+    markDirty(Dirty::TextureDirty);
+    update();
+}
+
+void QDemonCustomMaterial::qmlAppendShader(QQmlListProperty<QDemonCustomMaterialShader> *list, QDemonCustomMaterialShader *shader)
+{
+    if (!shader)
+        return;
+
+    QDemonCustomMaterial *that = qobject_cast<QDemonCustomMaterial *>(list->object);
+    that->m_shaders.push_back(shader);
+}
+
+QDemonCustomMaterialShader *QDemonCustomMaterial::qmlShaderAt(QQmlListProperty<QDemonCustomMaterialShader> *list, int index)
+{
+    QDemonCustomMaterial *that = qobject_cast<QDemonCustomMaterial *>(list->object);
+    return that->m_shaders.at(index);
+}
+
+int QDemonCustomMaterial::qmlShaderCount(QQmlListProperty<QDemonCustomMaterialShader> *list)
+{
+    QDemonCustomMaterial *that = qobject_cast<QDemonCustomMaterial *>(list->object);
+    return that->m_shaders.size();
+}
+
+void QDemonCustomMaterial::qmlAppendTexture(QQmlListProperty<QDemonCustomMaterialTexture> *textures, QDemonCustomMaterialTexture *texture)
+{
+    if (!texture)
+        return;
+
+    QDemonCustomMaterial *that = qobject_cast<QDemonCustomMaterial *>(textures->object);
+    if (texture->type == QDemonCustomMaterialTexture::TextureType::Displace)
+        that->setDisplacementMap(texture->image());
+    else if (texture->type == QDemonCustomMaterialTexture::TextureType::Emissive2)
+        that->setEmissiveMap2(texture->image());
+    else
+        that->setDynamicTextureMap(texture->image());
+    that->m_textures.push_back(texture);
+    that->markDirty(Dirty::TextureDirty);
+}
+
+QDemonCustomMaterialTexture *QDemonCustomMaterial::qmlTextureAt(QQmlListProperty<QDemonCustomMaterialTexture> *list, int index)
+{
+    QDemonCustomMaterial *that = qobject_cast<QDemonCustomMaterial *>(list->object);
+    return that->m_textures.at(index);
+}
+
+int QDemonCustomMaterial::qmlTextureCount(QQmlListProperty<QDemonCustomMaterialTexture> *list)
+{
+    QDemonCustomMaterial *that = qobject_cast<QDemonCustomMaterial *>(list->object);
+    return that->m_textures.size();
+}
+
+void QDemonCustomMaterial::qmlAppendPass(QQmlListProperty<QDemonCustomMaterialRenderPass> *list, QDemonCustomMaterialRenderPass *pass)
+{
+    if (!pass)
+        return;
+
+    QDemonCustomMaterial *that = qobject_cast<QDemonCustomMaterial *>(list->object);
+    that->m_passes.push_back(pass);
+}
+
+QDemonCustomMaterialRenderPass *QDemonCustomMaterial::qmlPassAt(QQmlListProperty<QDemonCustomMaterialRenderPass> *list, int index)
+{
+    QDemonCustomMaterial *that = qobject_cast<QDemonCustomMaterial *>(list->object);
+    return that->m_passes.at(index);
+}
+
+int QDemonCustomMaterial::qmlPassCount(QQmlListProperty<QDemonCustomMaterialRenderPass> *list)
+{
+    QDemonCustomMaterial *that = qobject_cast<QDemonCustomMaterial *>(list->object);
+    return that->m_textures.count();
+}
+
+void QDemonCustomMaterialRenderPass::qmlAppendCommand(QQmlListProperty<QDemonCustomMaterialRenderCommand> *list, QDemonCustomMaterialRenderCommand *command)
+{
+    if (!command)
+        return;
+
+    QDemonCustomMaterialRenderPass *that = qobject_cast<QDemonCustomMaterialRenderPass *>(list->object);
+    that->m_commands.push_back(command);
+}
+
+QDemonCustomMaterialRenderCommand *QDemonCustomMaterialRenderPass::qmlCommandAt(QQmlListProperty<QDemonCustomMaterialRenderCommand> *list, int index)
+{
+    QDemonCustomMaterialRenderPass *that = qobject_cast<QDemonCustomMaterialRenderPass *>(list->object);
+    return that->m_commands.at(index);
+}
+
+int QDemonCustomMaterialRenderPass::qmlCommandCount(QQmlListProperty<QDemonCustomMaterialRenderCommand> *list)
+{
+    QDemonCustomMaterialRenderPass *that = qobject_cast<QDemonCustomMaterialRenderPass *>(list->object);
+    return that->m_commands.count();
+}
+
+QQmlListProperty<QDemonCustomMaterialRenderCommand> QDemonCustomMaterialRenderPass::commands()
+{
+    return QQmlListProperty<QDemonCustomMaterialRenderCommand>(this,
+                                                               nullptr,
+                                                               QDemonCustomMaterialRenderPass::qmlAppendCommand,
+                                                               QDemonCustomMaterialRenderPass::qmlCommandCount,
+                                                               QDemonCustomMaterialRenderPass::qmlCommandAt,
+                                                               nullptr);
 }
 
 QT_END_NAMESPACE
diff --git a/src/quick3d/qdemoncustommaterial.h b/src/quick3d/qdemoncustommaterial.h
index ad409927cb26dbfc6a60251d1bed35070ec0c4b1..63f3f6aeb1ced759ee84f5be393e452f206e1d24 100644
--- a/src/quick3d/qdemoncustommaterial.h
+++ b/src/quick3d/qdemoncustommaterial.h
@@ -2,16 +2,300 @@
 #define QDEMONCUSTOMMATERIAL_H
 
 #include <QtQuick3d/qdemonmaterial.h>
+#include <QtCore/qvector.h>
+
+#include <QtDemonRender/qdemonrenderbasetypes.h>
+
+#include <QtDemonRuntimeRender/qdemonrenderdynamicobjectsystemcommands.h>
 
 QT_BEGIN_NAMESPACE
 
+
+class Q_QUICK3D_EXPORT QDemonCustomMaterialTexture : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QDemonImage * image READ image WRITE setImage)
+    Q_PROPERTY(QByteArray name MEMBER name)
+    Q_PROPERTY(TextureType type MEMBER type)
+    Q_PROPERTY(bool enabled MEMBER enabled)
+
+public:
+    enum class TextureType
+    {
+        Unknown = 0,
+        Diffuse,
+        Specular,
+        Environment,
+        Bump,
+        Normal,
+        Displace,
+        Emissive,
+        Emissive2,
+        Anisotropy,
+        Translucent,
+        LightmapIndirect,
+        LightmapRadiosity,
+        LightmapShadow
+    };
+    Q_ENUM(TextureType)
+
+    QDemonCustomMaterialTexture() = default;
+    virtual ~QDemonCustomMaterialTexture() = default;
+    QDemonImage *m_image;
+    QByteArray name;
+    TextureType type;
+    bool enabled = true;
+    QDemonImage *image() const
+    {
+        return m_image;
+    }
+
+public Q_SLOTS:
+    void setImage(QDemonImage * image)
+    {
+        if (m_image == image)
+            return;
+
+        m_image = image;
+        Q_EMIT textureDirty(this);
+    }
+
+Q_SIGNALS:
+    void textureDirty(QDemonCustomMaterialTexture * texture);
+};
+
+class Q_QUICK3D_EXPORT QDemonCustomMaterialRenderCommand : public QObject
+{
+    Q_OBJECT
+public:
+    QDemonCustomMaterialRenderCommand() = default;
+    ~QDemonCustomMaterialRenderCommand() override = default;
+    virtual dynamic::QDemonCommand *getCommand() { Q_ASSERT(0); return nullptr; }
+};
+
+class Q_QUICK3D_EXPORT QDemonCustomMaterialBufferInput : public QDemonCustomMaterialRenderCommand
+{
+    Q_OBJECT
+    Q_PROPERTY(QByteArray bufferName MEMBER bufferName)
+    Q_PROPERTY(QByteArray param MEMBER param)
+public:
+    QDemonCustomMaterialBufferInput() = default;
+    ~QDemonCustomMaterialBufferInput() override = default;
+    dynamic::QDemonApplyBufferValue command { QByteArray(), QByteArray() };
+    QByteArray &bufferName = command.m_bufferName;
+    QByteArray &param = command.m_paramName;
+    dynamic::QDemonCommand *getCommand() override { return &command; }
+};
+
+class Q_QUICK3D_EXPORT QDemonCustomMaterialBufferBlit : public QDemonCustomMaterialRenderCommand
+{
+    Q_OBJECT
+    Q_PROPERTY(QByteArray source MEMBER source)
+    Q_PROPERTY(QByteArray destination MEMBER destination)
+public:
+    QDemonCustomMaterialBufferBlit() = default;
+    ~QDemonCustomMaterialBufferBlit() override = default;
+    dynamic::QDemonApplyBlitFramebuffer command { QByteArray(), QByteArray() };
+    QByteArray &source = command.m_sourceBufferName;
+    QByteArray &destination = command.m_destBufferName;
+    dynamic::QDemonCommand *getCommand() override { return &command; }
+};
+
+class Q_QUICK3D_EXPORT QDemonCustomMaterialBlending : public QDemonCustomMaterialRenderCommand
+{
+    Q_OBJECT
+    Q_PROPERTY(SrcBlending srcBlending READ srcBlending WRITE setSrcBlending)
+    Q_PROPERTY(DestBlending destBlending READ destBlending WRITE setDestBlending)
+
+public:
+    enum class SrcBlending
+    {
+        Unknown = 0,
+        Zero,
+        One,
+        SrcColor,
+        OneMinusSrcColor,
+        DstColor,
+        OneMinusDstColor,
+        SrcAlpha,
+        OneMinusSrcAlpha,
+        DstAlpha,
+        OneMinusDstAlpha,
+        ConstantColor,
+        OneMinusConstantColor,
+        ConstantAlpha,
+        OneMinusConstantAlpha,
+        SrcAlphaSaturate
+    };
+    Q_ENUM(SrcBlending)
+
+    enum class DestBlending
+    {
+        Unknown = 0,
+        Zero,
+        One,
+        SrcColor,
+        OneMinusSrcColor,
+        DstColor,
+        OneMinusDstColor,
+        SrcAlpha,
+        OneMinusSrcAlpha,
+        DstAlpha,
+        OneMinusDstAlpha,
+        ConstantColor,
+        OneMinusConstantColor,
+        ConstantAlpha,
+        OneMinusConstantAlpha
+    };
+    Q_ENUM(DestBlending)
+
+    QDemonCustomMaterialBlending() = default;
+    ~QDemonCustomMaterialBlending() override = default;
+    dynamic::QDemonApplyBlending command { QDemonRenderSrcBlendFunc::Unknown, QDemonRenderDstBlendFunc::Unknown };
+    DestBlending destBlending() const
+    {
+        return DestBlending(command.m_dstBlendFunc);
+    }
+    SrcBlending srcBlending() const
+    {
+        return SrcBlending(command.m_srcBlendFunc);
+    }
+
+    dynamic::QDemonCommand *getCommand() override { return &command; }
+
+public Q_SLOTS:
+    void setDestBlending(DestBlending destBlending)
+    {
+        command.m_dstBlendFunc = QDemonRenderDstBlendFunc(destBlending);
+    }
+    void setSrcBlending(SrcBlending srcBlending)
+    {
+        command.m_srcBlendFunc= QDemonRenderSrcBlendFunc(srcBlending);
+    }
+};
+
+class Q_QUICK3D_EXPORT QDemonCustomMaterialRenderState : public QDemonCustomMaterialRenderCommand
+{
+    Q_OBJECT
+    Q_PROPERTY(RenderState renderState READ renderState WRITE setRenderState)
+    Q_PROPERTY(bool enabled MEMBER enabled)
+
+public:
+    enum class RenderState
+    {
+        Unknown = 0,
+        Blend,
+        CullFace,
+        DepthTest,
+        StencilTest,
+        ScissorTest,
+        DepthWrite,
+        Multisample
+    };
+    Q_ENUM(RenderState)
+
+    QDemonCustomMaterialRenderState() = default;
+    ~QDemonCustomMaterialRenderState() override = default;
+    dynamic::QDemonApplyRenderState command { QDemonRenderState::Unknown, false };
+    bool &enabled = command.m_enabled;
+    RenderState renderState() const
+    {
+        return RenderState(command.m_renderState);
+    }
+
+    dynamic::QDemonCommand *getCommand() override { return &command; }
+public Q_SLOTS:
+    void setRenderState(RenderState renderState)
+    {
+        command.m_renderState = QDemonRenderState(renderState);
+    }
+};
+
+class Q_QUICK3D_EXPORT QDemonCustomMaterialRenderPass : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QQmlListProperty<QDemonCustomMaterialRenderCommand> commands READ commands)
+public:
+    QDemonCustomMaterialRenderPass() = default;
+    ~QDemonCustomMaterialRenderPass() override = default;
+
+    static void qmlAppendCommand(QQmlListProperty<QDemonCustomMaterialRenderCommand> *list, QDemonCustomMaterialRenderCommand *command);
+    static QDemonCustomMaterialRenderCommand *qmlCommandAt(QQmlListProperty<QDemonCustomMaterialRenderCommand> *list, int index);
+    static int qmlCommandCount(QQmlListProperty<QDemonCustomMaterialRenderCommand> *list);
+
+    QQmlListProperty<QDemonCustomMaterialRenderCommand> commands();
+    QVector<QDemonCustomMaterialRenderCommand *> m_commands;
+};
+
+class Q_QUICK3D_EXPORT QDemonCustomMaterialShaderInfo : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QByteArray version MEMBER version)
+    Q_PROPERTY(QByteArray type MEMBER type)
+    Q_PROPERTY(qint32 shaderKey MEMBER shaderKey)
+    Q_PROPERTY(qint32 layers MEMBER layers)
+public:
+    QDemonCustomMaterialShaderInfo() = default;
+    ~QDemonCustomMaterialShaderInfo() override = default;
+    QByteArray version;
+    QByteArray type; // I.e., GLSL
+    QByteArray shaderPrefix = QByteArrayLiteral("#include \"customMaterial.glsllib\"\n");
+
+    enum class MaterialShaderKeyValues
+    {
+        Diffuse = 1 << 0,
+        Specular = 1 << 1,
+        Glossy = 1 << 2,
+        Cutout = 1 << 3,
+        Refraction = 1 << 4,
+        Transparent = 1 << 5,
+        Displace = 1 << 6,
+        Volumetric = 1 << 7,
+        Transmissive = 1 << 8,
+    };
+    Q_ENUM(MaterialShaderKeyValues)
+    Q_DECLARE_FLAGS(MaterialShaderKeyFlags, MaterialShaderKeyValues)
+
+    qint32 shaderKey {0};
+    qint32 layers {0};
+    bool isValid() const { return !(version.isEmpty() && type.isEmpty() && shaderPrefix.isEmpty()); }
+};
+
+class Q_QUICK3D_EXPORT QDemonCustomMaterialShader : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QByteArray shader MEMBER shader)
+    Q_PROPERTY(Stage stage MEMBER stage)
+public:
+    QDemonCustomMaterialShader() = default;
+    virtual ~QDemonCustomMaterialShader() = default;
+    enum class Stage : quint8
+    {
+        Shared,
+        Vertex,
+        Fragment,
+        Geometry
+    };
+    Q_ENUM(Stage)
+
+    QByteArray shader;
+    Stage stage;
+};
+
 class Q_QUICK3D_EXPORT QDemonCustomMaterial : public QDemonMaterial
 {
     Q_OBJECT
-    Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
+    Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged) // NOT NEEDED
     Q_PROPERTY(bool hasTransparency READ hasTransparency WRITE setHasTransparency NOTIFY hasTransparencyChanged)
     Q_PROPERTY(bool hasRefraction READ hasRefraction WRITE setHasRefraction NOTIFY hasRefractionChanged)
     Q_PROPERTY(bool hasVolumetricDF READ hasVolumetricDF WRITE setHasVolumetricDF NOTIFY hasVolumetricDFChanged)
+    Q_PROPERTY(bool alwaysDirty READ alwaysDirty WRITE setAlwaysDirty NOTIFY alwaysDirtyChanged)
+
+    Q_PROPERTY(QDemonCustomMaterialShaderInfo *shaderInfo READ shaderInfo WRITE setShaderInfo)
+    Q_PROPERTY(QQmlListProperty<QDemonCustomMaterialShader> shaders READ shaders)
+    Q_PROPERTY(QQmlListProperty<QDemonCustomMaterialTexture> textures READ textures)
+    Q_PROPERTY(QQmlListProperty<QDemonCustomMaterialRenderPass> passes READ passes)
+
 
 public:
     QDemonCustomMaterial();
@@ -25,12 +309,23 @@ public:
 
     QString source() const;
 
+    QDemonCustomMaterialShaderInfo *shaderInfo() const;
+
+    QQmlListProperty<QDemonCustomMaterialShader> shaders();
+    QQmlListProperty<QDemonCustomMaterialTexture> textures();
+    QQmlListProperty<QDemonCustomMaterialRenderPass> passes();
+
+    bool alwaysDirty() const;
+
 public Q_SLOTS:
     void setHasTransparency(bool hasTransparency);
     void setHasRefraction(bool hasRefraction);
     void setHasVolumetricDF(bool hasVolumetricDF);
 
     void setSource(QString source);
+    void setShaderInfo(QDemonCustomMaterialShaderInfo *shaderInfo);
+
+    void setAlwaysDirty(bool alwaysDirty);
 
 Q_SIGNALS:
     void hasTransparencyChanged(bool hasTransparency);
@@ -39,14 +334,54 @@ Q_SIGNALS:
 
     void sourceChanged(QString source);
 
+    void alwaysDirtyChanged(bool alwaysDirty);
+
 protected:
     QDemonRenderGraphObject *updateSpatialNode(QDemonRenderGraphObject *node) override;
 
+private Q_SLOTS:
+    void onPropertyDirty();
+    void onTextureDirty(QDemonCustomMaterialTexture *texture);
+
 private:
+    enum Dirty {
+        TextureDirty = 0x1,
+        PropertyDirty = 0x2
+    };
+
+    // Shader
+    static void qmlAppendShader(QQmlListProperty<QDemonCustomMaterialShader> *list, QDemonCustomMaterialShader *shader);
+    static QDemonCustomMaterialShader *qmlShaderAt(QQmlListProperty<QDemonCustomMaterialShader> *list, int index);
+    static int qmlShaderCount(QQmlListProperty<QDemonCustomMaterialShader> *list);
+
+    // Texture
+    static void qmlAppendTexture(QQmlListProperty<QDemonCustomMaterialTexture> *textures, QDemonCustomMaterialTexture *texture);
+    static QDemonCustomMaterialTexture *qmlTextureAt(QQmlListProperty<QDemonCustomMaterialTexture> *list, int index);
+    static int qmlTextureCount(QQmlListProperty<QDemonCustomMaterialTexture> *list);
+
+    // Passes
+    static void qmlAppendPass(QQmlListProperty<QDemonCustomMaterialRenderPass> *list, QDemonCustomMaterialRenderPass *pass);
+    static QDemonCustomMaterialRenderPass *qmlPassAt(QQmlListProperty<QDemonCustomMaterialRenderPass> *list, int index);
+    static int qmlPassCount(QQmlListProperty<QDemonCustomMaterialRenderPass> *list);
+
+    void markDirty(QDemonCustomMaterial::Dirty type)
+    {
+        if (!(m_dirtyAttributes & quint32(type))) {
+            m_dirtyAttributes |= quint32(type);
+            update();
+        }
+    }
+
+    quint32 m_dirtyAttributes = 0xffffffff;
     bool m_hasTransparency;
     bool m_hasRefraction;
     bool m_hasVolumetricDF;
     QString m_source;
+    QDemonCustomMaterialShaderInfo *m_shaderInfo;
+    QVector<QDemonCustomMaterialShader *> m_shaders;
+    QVector<QDemonCustomMaterialTexture *> m_textures;
+    QVector<QDemonCustomMaterialRenderPass *> m_passes;
+    bool m_alwaysDirty = false;
 };
 
 QT_END_NAMESPACE
diff --git a/src/quick3d/qdemonmaterial.cpp b/src/quick3d/qdemonmaterial.cpp
index 17f7cc48935bfb709896de95794d113ee0175843..65d7125685c562550e443506a186a94084f77cb5 100644
--- a/src/quick3d/qdemonmaterial.cpp
+++ b/src/quick3d/qdemonmaterial.cpp
@@ -253,6 +253,29 @@ void QDemonMaterial::itemChange(QDemonObject::ItemChange change, const QDemonObj
         updateSceneRenderer(value.sceneRenderer);
 }
 
+void QDemonMaterial::setDynamicTextureMap(QDemonImage *textureMap)
+{
+    if (!textureMap)
+        return;
+
+    auto it = m_dynamicTextureMaps.begin();
+    const auto end = m_dynamicTextureMaps.end();
+    for (; it != end; ++it) {
+        if (*it == textureMap)
+            break;
+    }
+
+    if (it != end)
+        return;
+
+    updateProperyListener(textureMap, nullptr, sceneRenderer(), m_connections, [this](QDemonObject *n) {
+        setDynamicTextureMap(qobject_cast<QDemonImage *>(n));
+    });
+
+    m_dynamicTextureMaps.push_back(textureMap);
+    update();
+}
+
 void QDemonMaterial::updateSceneRenderer(QDemonSceneManager *window)
 {
     if (window) {
@@ -274,6 +297,8 @@ void QDemonMaterial::updateSceneRenderer(QDemonSceneManager *window)
         if (m_displacementMap) {
            QDemonObjectPrivate::get(m_displacementMap)->refSceneRenderer(window);
         }
+        for (auto it : m_dynamicTextureMaps)
+            QDemonObjectPrivate::get(it)->refSceneRenderer(window);
     } else {
         if (m_lightmapIndirect) {
            QDemonObjectPrivate::get(m_lightmapIndirect)->derefSceneRenderer();
@@ -293,6 +318,8 @@ void QDemonMaterial::updateSceneRenderer(QDemonSceneManager *window)
         if (m_displacementMap) {
            QDemonObjectPrivate::get(m_displacementMap)->derefSceneRenderer();
         }
+        for (auto it : m_dynamicTextureMaps)
+            QDemonObjectPrivate::get(it)->derefSceneRenderer();
     }
 }
 
diff --git a/src/quick3d/qdemonmaterial.h b/src/quick3d/qdemonmaterial.h
index f9ce35a07464189ab229b86b1692827e49aa2891..b3d63c2051f4e21699f0ba0273489590bbc57509 100644
--- a/src/quick3d/qdemonmaterial.h
+++ b/src/quick3d/qdemonmaterial.h
@@ -4,6 +4,8 @@
 #include <QtQuick3d/qdemonobject.h>
 #include <QtQuick3d/qdemonimage.h>
 
+#include <QtCore/qvector.h>
+
 QT_BEGIN_NAMESPACE
 
 class QDemonSceneManager;
@@ -61,6 +63,8 @@ Q_SIGNALS:
 protected:
     QDemonRenderGraphObject *updateSpatialNode(QDemonRenderGraphObject *node) override;
     void itemChange(ItemChange, const ItemChangeData &) override;
+
+    void setDynamicTextureMap(QDemonImage *textureMap);
 private:
     void updateSceneRenderer(QDemonSceneManager *sceneRenderer);
     QDemonImage *m_lightmapIndirect = nullptr;
@@ -74,6 +78,7 @@ private:
     float m_displacementAmount = 0.0f;
 
     QHash<QObject*, QMetaObject::Connection> m_connections;
+    QVector<QDemonImage *> m_dynamicTextureMaps;
 };
 
 QT_END_NAMESPACE
diff --git a/src/quick3d/qdemonobject_p.h b/src/quick3d/qdemonobject_p.h
index a9750201bd0b749fcb88828899dfb7e51254b79b..dcca865746e9744b5b24d657ed4da0fdf1feba39 100644
--- a/src/quick3d/qdemonobject_p.h
+++ b/src/quick3d/qdemonobject_p.h
@@ -176,8 +176,8 @@ public:
 
     QDemonSceneManager *sceneManager;
     int windowRefCount;
-//    inline QDemonRenderContextInterface *sceneGraphContext() const;
-//    inline QDemonRenderContext *sceneGraphRenderContext() const;
+//    QDemonRenderContextInterface *sceneGraphContext() const;
+//    QDemonRenderContext *sceneGraphRenderContext() const;
 
     QDemonObject *parentItem;
 
diff --git a/src/quick3d/qdemonscenerenderer.cpp b/src/quick3d/qdemonscenerenderer.cpp
index f6dcdd45b14c250459aa4f3d3ff92acbbea9bc03..8b48a7fc3a9906d431870eb4c9da7ce79c9f9f36 100644
--- a/src/quick3d/qdemonscenerenderer.cpp
+++ b/src/quick3d/qdemonscenerenderer.cpp
@@ -240,7 +240,7 @@ QDemonSceneRenderer::QDemonSceneRenderer(QWindow *window)
     if (m_renderContext.isNull())
         m_renderContext = QDemonRenderContext::createGl(m_openGLContext->format());
     if (m_sgContext.isNull())
-        m_sgContext = new QDemonRenderContextInterface(m_renderContext, QString::fromLatin1("./"));
+        m_sgContext = QDemonRenderContextInterface::getRenderContextInterface(m_renderContext, QString::fromLatin1("./"), quintptr(window));
     m_openGLContext->doneCurrent();
     oldContext->makeCurrent(window);
 }
diff --git a/src/quick3d/qdemonscenerenderer.h b/src/quick3d/qdemonscenerenderer.h
index 1eea51d93c0850b9f2fca992e10facd9b8a64ee4..ec0f687bf4faf13caaf2a7c3db0b652fb8d3e544 100644
--- a/src/quick3d/qdemonscenerenderer.h
+++ b/src/quick3d/qdemonscenerenderer.h
@@ -44,7 +44,7 @@ private:
     void removeNodeFromLayer(QDemonRenderNode *node);
     QDemonSceneManager *m_sceneManager = nullptr;
     QDemonRenderLayer *m_layer = nullptr;
-    QDemonRef<QDemonRenderContextInterface> m_sgContext;
+    QDemonRenderContextInterface::QDemonRenderContextInterfacePtr m_sgContext;
     QDemonRef<QDemonRenderContext> m_renderContext;
     QSize m_surfaceSize;
     void *data = nullptr;
diff --git a/src/render/qdemonrenderbasetypes.h b/src/render/qdemonrenderbasetypes.h
index 6208bb70dc52dbad3fd2a07d0857ac35f0ad7b59..3a18778308ce7e49f131f91b380f23d9e126a444 100644
--- a/src/render/qdemonrenderbasetypes.h
+++ b/src/render/qdemonrenderbasetypes.h
@@ -1690,6 +1690,17 @@ typedef QDemonRenderGenericVec2<qint32> qint32_2;
 typedef QDemonRenderGenericVec3<qint32> qint32_3;
 typedef QDemonRenderGenericVec4<qint32> qint32_4;
 
+Q_DECLARE_METATYPE(bool_2)
+Q_DECLARE_METATYPE(bool_3)
+Q_DECLARE_METATYPE(bool_4)
+Q_DECLARE_METATYPE(quint32_2)
+Q_DECLARE_METATYPE(quint32_3)
+Q_DECLARE_METATYPE(quint32_4)
+Q_DECLARE_METATYPE(qint32_2)
+Q_DECLARE_METATYPE(qint32_3)
+Q_DECLARE_METATYPE(qint32_4)
+
+
 enum class QDemonRenderShaderDataType : quint32
 {
     Unknown = 0,
diff --git a/src/runtimerender/graphobjects/graphobjects.pri b/src/runtimerender/graphobjects/graphobjects.pri
index 9c13f094556324b1575649b3b9d18ad75fcce8a6..1e1c5e8afe711ff6ea77e93714f39995d3179a3a 100644
--- a/src/runtimerender/graphobjects/graphobjects.pri
+++ b/src/runtimerender/graphobjects/graphobjects.pri
@@ -2,7 +2,6 @@ HEADERS += \
     $$PWD/qdemonrendercamera.h \
     $$PWD/qdemonrendercustommaterial.h \
     $$PWD/qdemonrenderdefaultmaterial.h \
-    $$PWD/qdemonrenderdynamicobject.h \
     $$PWD/qdemonrendereffect.h \
     $$PWD/qdemonrendergraphobject.h \
     $$PWD/qdemonrenderimage.h \
@@ -19,7 +18,6 @@ HEADERS += \
 SOURCES += \
     $$PWD/qdemonrendercamera.cpp \
     $$PWD/qdemonrenderdefaultmaterial.cpp \
-    $$PWD/qdemonrenderdynamicobject.cpp \
     $$PWD/qdemonrendereffect.cpp \
     $$PWD/qdemonrenderimage.cpp \
     $$PWD/qdemonrenderlayer.cpp \
diff --git a/src/runtimerender/graphobjects/qdemonrendercustommaterial.h b/src/runtimerender/graphobjects/qdemonrendercustommaterial.h
index 7314b5554e4add4039754d720b25b9922abdf969..8185490cb9744cbb9efeb69aded2cbe1e7cc1101 100644
--- a/src/runtimerender/graphobjects/qdemonrendercustommaterial.h
+++ b/src/runtimerender/graphobjects/qdemonrendercustommaterial.h
@@ -30,21 +30,115 @@
 #ifndef QDEMON_RENDER_CUSTOM_MATERIAL_H
 #define QDEMON_RENDER_CUSTOM_MATERIAL_H
 
-#include <QtDemonRuntimeRender/qdemonrenderdynamicobject.h>
 #include <QtDemonRuntimeRender/qdemonrenderimage.h>
 #include <QtDemonRuntimeRender/qdemonrenderlightmaps.h>
 
+#include <QtCore/qurl.h>
+#include <QtCore/qvector.h>
+#include <QtDemonRuntimeRender/qdemonrenderdynamicobjectsystemcommands.h>
+
 QT_BEGIN_NAMESPACE
 
-struct Q_DEMONRUNTIMERENDER_EXPORT QDemonRenderCustomMaterial : public QDemonRenderDynamicGraphObject
+struct Q_DEMONRUNTIMERENDER_EXPORT QDemonRenderCustomMaterial : public QDemonRenderGraphObject
 {
-private:
-    // These objects are only created via the dynamic object system.
-    QDemonRenderCustomMaterial(const QDemonRenderCustomMaterial &);
-    QDemonRenderCustomMaterial &operator=(const QDemonRenderCustomMaterial &);
-    QDemonRenderCustomMaterial();
+    QDemonRenderCustomMaterial() : QDemonRenderGraphObject(Type::CustomMaterial) {}
+
+    struct TextureProperty
+    {
+        QDemonRenderImage *texImage = nullptr;
+        QByteArray name;
+        QDemonRenderShaderDataType shaderDataType;
+        // TODO: Note needed?
+        QDemonRenderTextureMagnifyingOp magFilterType = QDemonRenderTextureMagnifyingOp::Linear;
+        QDemonRenderTextureMinifyingOp minFilterType = QDemonRenderTextureMinifyingOp::Linear;
+        QDemonRenderTextureCoordOp clampType = QDemonRenderTextureCoordOp::ClampToEdge;
+        QDemonRenderTextureTypeValue usageType;
+    };
+
+    QVector<TextureProperty> textureProperties;
+
+    struct Property
+    {
+        QByteArray name;
+        mutable QVariant value;
+        QDemonRenderShaderDataType shaderDataType;
+        int pid = -1;
+    };
+
+    QVector<Property> properties;
+
+    struct ShaderInfo
+    {
+        QByteArray version;
+        QByteArray type; // I.e., GLSL
+        QByteArray shaderPrefix;
+    };
+
+    ShaderInfo shaderInfo;
+
+    struct Shader
+    {
+        enum class Stage : quint8
+        {
+            Shared,
+            Vertex,
+            Fragment
+        };
+
+        QString code;
+        Stage stage;
+    };
+
+    QVector<Shader> shaders;
+
+    struct Pass
+    {
+        struct BufferInput
+        {
+            QString bufferName;
+            QString shaderParam;
+            // dynamic::QDemonApplyBufferValue(bufferName, shaderParam)
+        };
+
+        struct BufferBlit
+        {
+            QString source;
+            QString dest;
+            // dynamic::QDemonApplyBlitFramebuffer(source, dest)
+        };
+
+        struct Blending
+        {
+            QDemonRenderSrcBlendFunc source = QDemonRenderSrcBlendFunc::One;
+            QDemonRenderDstBlendFunc dest = QDemonRenderDstBlendFunc::One;
+            // hasBlending = true; when used
+            // dynamic::QDemonApplyBlending(source, dest)
+        };
+
+        struct RenderState
+        {
+            QDemonRenderState renderState = QDemonRenderState::Unknown;
+            bool enabled;
+            // dynamic::QDemonApplyRenderState(renderState, enabled)
+        };
+
+        QString shaderName;
+        QString input;
+        QString output;
+        QDemonRenderTextureFormat::Format outputFormat;
+        bool needsClear;
+
+        Pass()
+            : input(QLatin1String("[source]"))
+            , output(QLatin1String("[dest]"))
+            , outputFormat(QDemonRenderTextureFormat::RGBA8)
+            , needsClear(false)
+        {}
+    };
+
+    QVector<Pass> passes;
+    QVector<dynamic::QDemonCommand *> commands;
 
-public:
     // IMPORTANT: These flags matches the key produced by a MDL export file
     enum class MaterialShaderKeyValues
     {
@@ -60,41 +154,29 @@ public:
     };
     Q_DECLARE_FLAGS(MaterialShaderKeyFlags, MaterialShaderKeyValues)
 
-    const char *imagePath = nullptr;
+    using Flag = QDemonRenderNode::Flag;
+    Q_DECLARE_FLAGS(Flags, Flag)
+
+    const char *className = nullptr;
 
     // lightmap section
     QDemonRenderLightmaps m_lightmaps;
     // material section
-    bool m_hasTransparency;
-    bool m_hasRefraction;
-    bool m_hasVolumetricDF;
-    QDemonRenderImage *m_iblProbe;
-    QDemonRenderImage *m_emissiveMap2;
-    QDemonRenderImage *m_displacementMap;
-    float m_displaceAmount; ///< depends on the object size
+    bool m_hasTransparency = false;
+    bool m_hasRefraction = false;
+    bool m_hasVolumetricDF = false;
+    QDemonRenderImage *m_iblProbe = nullptr;
+    QDemonRenderImage *m_emissiveMap2 = nullptr;
+    QDemonRenderImage *m_displacementMap = nullptr;
+    float m_displaceAmount = 0.0f; ///< depends on the object size
 
-    QDemonRenderGraphObject *m_nextSibling;
+    QDemonRenderGraphObject *m_nextSibling = nullptr;
 
     MaterialShaderKeyFlags m_shaderKeyValues; ///< input from MDL files
-    quint32 m_layerCount; ///< input from MDL files
+    quint32 m_layerCount = 0; ///< input from MDL files
 
-    void initialize(quint32 inKey, quint32 inLayerCount)
-    {
-        m_lightmaps.m_lightmapIndirect = nullptr;
-        m_lightmaps.m_lightmapRadiosity = nullptr;
-        m_lightmaps.m_lightmapShadow = nullptr;
-        m_hasTransparency = false;
-        m_hasRefraction = false;
-        m_hasVolumetricDF = false;
-        m_nextSibling = nullptr;
-        m_dirtyFlagWithInFrame = flags.testFlag(Flag::Dirty);
-        m_iblProbe = nullptr;
-        m_emissiveMap2 = nullptr;
-        m_displacementMap = nullptr;
-        m_displaceAmount = 0.0;
-        m_shaderKeyValues = static_cast<MaterialShaderKeyFlags>(inKey);
-        m_layerCount = inLayerCount;
-    }
+    Flags flags;
+    bool m_alwaysDirty = false;
 
     bool isDielectric() const { return m_shaderKeyValues & MaterialShaderKeyValues::diffuse; }
     bool isSpecularEnabled() const { return m_shaderKeyValues & MaterialShaderKeyValues::specular; }
@@ -105,7 +187,7 @@ public:
 
     // Dirty
     bool m_dirtyFlagWithInFrame;
-    bool isDirty() const { return flags.testFlag(Flag::Dirty) || m_dirtyFlagWithInFrame; }
+    bool isDirty() const { return flags.testFlag(Flag::Dirty) || m_dirtyFlagWithInFrame || m_alwaysDirty; }
     void updateDirtyForFrame()
     {
         m_dirtyFlagWithInFrame = flags.testFlag(Flag::Dirty);
diff --git a/src/runtimerender/graphobjects/qdemonrenderdynamicobject.cpp b/src/runtimerender/graphobjects/qdemonrenderdynamicobject.cpp
deleted file mode 100644
index 27ed46ccb5da89a1a9c30210fed9feadcb339a3d..0000000000000000000000000000000000000000
--- a/src/runtimerender/graphobjects/qdemonrenderdynamicobject.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2008-2012 NVIDIA Corporation.
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt 3D Studio.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) any later version
-** approved by the KDE Free Qt Foundation. The licenses are as published by
-** the Free Software Foundation and appearing in the file LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qdemonrenderdynamicobject.h"
-
-#include <QtDemonRuntimeRender/qdemonrenderdynamicobjectsystem.h>
-
-#include <QtCore/qdir.h>
-
-QT_BEGIN_NAMESPACE
-
-QDemonRenderDynamicGraphObject::QDemonRenderDynamicGraphObject(Type inType, const QString &inObjName, quint32 inDSByteSize, quint32 thisObjSize)
-    : QDemonRenderGraphObject(inType), className(inObjName), dataSectionByteSize(inDSByteSize), thisObjectSize(thisObjSize)
-{
-}
-
-template<typename TDataType>
-void QDemonRenderDynamicGraphObject::setPropertyValueT(const dynamic::QDemonPropertyDefinition &inDefinition, const TDataType &inValue)
-{
-    if (sizeof(inValue) != inDefinition.byteSize) {
-        Q_ASSERT(false);
-        return;
-    }
-    ::memcpy(getDataSectionBegin() + inDefinition.offset, &inValue, sizeof(inValue));
-}
-
-void QDemonRenderDynamicGraphObject::setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, bool inValue)
-{
-    setPropertyValueT(inDefinition, inValue);
-}
-
-void QDemonRenderDynamicGraphObject::setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, float inValue)
-{
-    setPropertyValueT(inDefinition, inValue);
-}
-void QDemonRenderDynamicGraphObject::setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, float inValue, quint32 inOffset)
-{
-    if (sizeof(float) > (inDefinition.byteSize - inOffset)) {
-        Q_ASSERT(false);
-        return;
-    }
-    ::memcpy(getDataSectionBegin() + inDefinition.offset + inOffset, &inValue, sizeof(inValue));
-}
-void QDemonRenderDynamicGraphObject::setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, const QVector2D &inValue)
-{
-    setPropertyValueT(inDefinition, inValue);
-}
-void QDemonRenderDynamicGraphObject::setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, const QVector3D &inValue)
-{
-    setPropertyValueT(inDefinition, inValue);
-}
-void QDemonRenderDynamicGraphObject::setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, const QVector4D &inValue)
-{
-    setPropertyValueT(inDefinition, inValue);
-}
-void QDemonRenderDynamicGraphObject::setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, qint32 inValue)
-{
-    setPropertyValueT(inDefinition, inValue);
-}
-void QDemonRenderDynamicGraphObject::setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, const QString &inValue)
-{
-    Q_ASSERT(inDefinition.dataType == QDemonRenderShaderDataType::Texture2D);
-    setPropertyValueT(inDefinition, inValue);
-}
-template<typename TStrType>
-void QDemonRenderDynamicGraphObject::setStrPropertyValueT(dynamic::QDemonPropertyDefinition &inDefinition,
-                                                          const char *inValue,
-                                                          const char *inProjectDir,
-                                                          TStrType &ioWorkspace)
-{
-    if (inValue == nullptr)
-        inValue = "";
-    if (inDefinition.dataType == QDemonRenderShaderDataType::Integer) {
-        // TODO: Can the enum values be anything but 8bit chars?
-        QDemonDataView<QString> theEnumValues = inDefinition.enumValueNames;
-        for (int idx = 0, end = theEnumValues.size(); idx < end; ++idx) {
-            if (theEnumValues[idx].compare(QString::fromLocal8Bit(inValue)) == 0) {
-                setPropertyValueT(inDefinition, idx);
-                break;
-            }
-        }
-    } else if (inDefinition.dataType == QDemonRenderShaderDataType::Texture2D) {
-        if (inProjectDir == nullptr)
-            inProjectDir = "";
-
-        const bool RequiresCombineBaseAndRelative = inValue && (::strncmp(inValue, ".", 1) == 0);
-        if (RequiresCombineBaseAndRelative) {
-            const QString absolute = QDir(QString::fromLocal8Bit(inProjectDir)).filePath(QString::fromLocal8Bit(inValue));
-            ioWorkspace = absolute;
-            setPropertyValueT(inDefinition, ioWorkspace);
-            // We also adjust the image path in the definition
-            // I could not find a better place
-            QByteArray *data = new QByteArray(ioWorkspace.toLatin1());
-            inDefinition.imagePath = data->constData(); //ioWorkspace.toLatin1().constData(); // TODO: Life time
-        } else {
-            setPropertyValueT(inDefinition, inValue);
-        }
-    } else if (inDefinition.dataType == QDemonRenderShaderDataType::Image2D) {
-        setPropertyValueT(inDefinition, inValue);
-    } else if (inDefinition.dataType == QDemonRenderShaderDataType::DataBuffer) {
-        setPropertyValueT(inDefinition, inValue);
-    } else {
-        Q_ASSERT(false);
-    }
-}
-
-void QDemonRenderDynamicGraphObject::setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition,
-                                                      const char *inValue,
-                                                      const char *inProjectDir,
-                                                      QString &ioWorkspace)
-{
-    setStrPropertyValueT(const_cast<dynamic::QDemonPropertyDefinition &>(inDefinition), inValue, inProjectDir, ioWorkspace);
-}
-
-// void QDemonDynamicObject::SetPropertyValue(const dynamic::SPropertyDefinition &inDefinition,
-//                                      const char *inValue, const char *inProjectDir,
-//                                      QString &ioWorkspace)
-//{
-//    SetStrPropertyValueT(const_cast<dynamic::SPropertyDefinition &>(inDefinition), inValue,
-//                         inProjectDir, ioWorkspace);
-//}
-
-QT_END_NAMESPACE
diff --git a/src/runtimerender/graphobjects/qdemonrenderdynamicobject.h b/src/runtimerender/graphobjects/qdemonrenderdynamicobject.h
deleted file mode 100644
index c8fa062f04a7836c57834b2aabb0af3e302c59b7..0000000000000000000000000000000000000000
--- a/src/runtimerender/graphobjects/qdemonrenderdynamicobject.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2008-2012 NVIDIA Corporation.
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt 3D Studio.
-**
-** $QT_BEGIN_LICENSE:GPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 or (at your option) any later version
-** approved by the KDE Free Qt Foundation. The licenses are as published by
-** the Free Software Foundation and appearing in the file LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef QDEMON_RENDER_DYNAMIC_OBJECT_H
-#define QDEMON_RENDER_DYNAMIC_OBJECT_H
-
-#include <QtDemonRuntimeRender/qdemonrendergraphobject.h>
-#include <QtDemonRuntimeRender/qdemonrendernode.h>
-
-#include <QtCore/QString>
-
-QT_BEGIN_NAMESPACE
-
-namespace dynamic {
-struct QDemonPropertyDefinition;
-}
-
-// Dynamic objects are objects that have variable number of properties during runtime.
-struct Q_DEMONRUNTIMERENDER_EXPORT QDemonRenderDynamicGraphObject : public QDemonRenderGraphObject
-{
-    using Flag = QDemonRenderNode::Flag;
-    Q_DECLARE_FLAGS(Flags, Flag)
-
-    QString className;
-    Flags flags;
-    quint32 dataSectionByteSize;
-    quint32 thisObjectSize;
-
-    QDemonRenderDynamicGraphObject(Type inType, const QString &inClassName, quint32 inDSByteSize, quint32 thisObjSize);
-
-    quint8 *getDataSectionBegin()
-    {
-        quint8 *thisObjectStart = reinterpret_cast<quint8 *>(this);
-        quint8 *retval = thisObjectStart + thisObjectSize;
-        Q_ASSERT((reinterpret_cast<size_t>(retval) % 4 == 0));
-        return retval;
-    }
-
-    const quint8 *getDataSectionBegin() const { return const_cast<QDemonRenderDynamicGraphObject *>(this)->getDataSectionBegin(); }
-
-    quint8 *getDataSectionEnd() { return getDataSectionBegin() + dataSectionByteSize; }
-
-    template<typename TDataType>
-    void setPropertyValueT(const dynamic::QDemonPropertyDefinition &inDefinition, const TDataType &inType);
-    template<typename TStrType>
-    void setStrPropertyValueT(dynamic::QDemonPropertyDefinition &inDefinition, const char *inValue, const char *inProjectDir, TStrType &ioWorkspace);
-
-    void setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, bool inValue);
-    void setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, float inValue);
-    void setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, float inValue, quint32 inOffset);
-    void setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, const QVector2D &inValue);
-    void setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, const QVector3D &inValue);
-    void setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, const QVector4D &inValue);
-    void setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, qint32 inValue);
-    void setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, const QString &inValue);
-
-    void setPropertyValue(const dynamic::QDemonPropertyDefinition &inDefinition, const char *inValue, const char *inProjectDir, QString &ioWorkspace);
-};
-
-QT_END_NAMESPACE
-#endif
diff --git a/src/runtimerender/graphobjects/qdemonrendereffect.h b/src/runtimerender/graphobjects/qdemonrendereffect.h
index 8a8f2fee84f17efa1a5dc71da5c797dd31bac28c..69269cddff1bd3d0aedd3b2ca86053167650e4c3 100644
--- a/src/runtimerender/graphobjects/qdemonrendereffect.h
+++ b/src/runtimerender/graphobjects/qdemonrendereffect.h
@@ -32,7 +32,6 @@
 
 #include <QtDemonRuntimeRender/qdemonrendergraphobject.h>
 #include <QtDemonRuntimeRender/qdemonrendernode.h>
-#include <QtDemonRuntimeRender/qdemonrenderdynamicobject.h>
 
 QT_BEGIN_NAMESPACE
 struct QDemonRenderLayer;
@@ -43,22 +42,17 @@ class QDemonEffectSystemInterface;
 // them and they have completely variable properties.
 // see IEffectManager in order to create these effects.
 // The data for the effect immediately follows the effect
-struct Q_DEMONRUNTIMERENDER_EXPORT QDemonRenderEffect : public QDemonRenderDynamicGraphObject
+struct Q_DEMONRUNTIMERENDER_EXPORT QDemonRenderEffect : public QDemonRenderGraphObject
 {
-private:
-    // These objects are only created via the dynamic object system.
-    QDemonRenderEffect(const QDemonRenderEffect &) = delete;
-    QDemonRenderEffect &operator=(const QDemonRenderEffect &) = delete;
-    QDemonRenderEffect() = delete;
+    QDemonRenderEffect() : QDemonRenderGraphObject(Type::Effect) {}
     ~QDemonRenderEffect();
 
-public:
     QDemonRenderLayer *m_layer;
     QDemonRenderEffect *m_nextEffect;
     // Opaque pointer to context type implemented by the effect system.
     // May be null in which case the effect system will generate a new context
     // the first time it needs to render this effect.
-    QDemonRef<QDemonEffectContext> m_context;
+    QDemonEffectContext *m_context = nullptr;
 
     void initialize();
 
@@ -67,6 +61,12 @@ public:
     void setActive(bool inActive, QDemonEffectSystemInterface &inSystem);
 
     void reset(QDemonEffectSystemInterface &inSystem);
+
+    using Flag = QDemonRenderNode::Flag;
+    Q_DECLARE_FLAGS(Flags, Flag)
+
+    Flags flags;
+    const char *className = nullptr;
 };
 
 QT_END_NAMESPACE
diff --git a/src/runtimerender/qdemonrendercontextcore.cpp b/src/runtimerender/qdemonrendercontextcore.cpp
index d4910eb3f4c9a8ab1f0163bd6e04ad4fb934f4cb..ef091fe8b2e2208225412c1a254762fa73ba39b9 100644
--- a/src/runtimerender/qdemonrendercontextcore.cpp
+++ b/src/runtimerender/qdemonrendercontextcore.cpp
@@ -136,6 +136,54 @@ QDemonRenderContextInterface::QDemonRenderContextInterface(const QDemonRef<QDemo
 #endif
 }
 
+Q_GLOBAL_STATIC(QVector<QDemonRenderContextInterface::QDemonRenderContextInterfacePtr>, g_renderContexts)
+
+void QDemonRenderContextInterface::releaseRenderContextInterface(quintptr wid)
+{
+    auto it = g_renderContexts->cbegin();
+    const auto end = g_renderContexts->cend();
+    for (; it != end; ++it) {
+        if (it->m_wid == wid)
+            break;
+    }
+
+    if (it != end)
+        g_renderContexts->remove(int(end - it));
+}
+
+QDemonRenderContextInterface::QDemonRenderContextInterfacePtr QDemonRenderContextInterface::getRenderContextInterface(const QDemonRef<QDemonRenderContext> &ctx, const QString &inApplicationDirectory, quintptr wid)
+{
+    auto it = g_renderContexts->cbegin();
+    const auto end = g_renderContexts->cend();
+    for (; it != end; ++it) {
+        if (it->m_wid == wid)
+            break;
+    }
+
+    if (it != end)
+        return *it;
+
+    QDemonRenderContextInterfacePtr ptr { new QDemonRenderContextInterface(ctx, inApplicationDirectory), wid };
+    g_renderContexts->push_back(ptr);
+
+    return ptr;
+}
+
+QDemonRenderContextInterface::QDemonRenderContextInterfacePtr QDemonRenderContextInterface::getRenderContextInterface(quintptr wid)
+{
+    auto it = g_renderContexts->cbegin();
+    const auto end = g_renderContexts->cend();
+    for (; it != end; ++it) {
+        if (it->m_wid == wid)
+            break;
+    }
+
+    if (it != end)
+        return *it;
+
+    return QDemonRenderContextInterfacePtr();
+}
+
 QDemonRef<QDemonRendererInterface> QDemonRenderContextInterface::renderer() { return m_renderer; }
 
 QDemonRef<QDemonBufferManager> QDemonRenderContextInterface::bufferManager() { return m_bufferManager; }
diff --git a/src/runtimerender/qdemonrendercontextcore.h b/src/runtimerender/qdemonrendercontextcore.h
index fee8f4224862edbc0a8400c360cb5d90d6c08df6..805f24efbe36ab99ff229f1ee688df63786babe4 100644
--- a/src/runtimerender/qdemonrendercontextcore.h
+++ b/src/runtimerender/qdemonrendercontextcore.h
@@ -140,9 +140,28 @@ private:
     QRect presentationViewport(const QRect &inViewerViewport, ScaleModes inScaleToFit, const QSize &inPresDimensions) const;
     void setupRenderTarget();
     void teardownRenderTarget();
+    QDemonRenderContextInterface(const QDemonRef<QDemonRenderContext> &ctx, const QString &inApplicationDirectory);
+
+    static void releaseRenderContextInterface(quintptr wid);
 
 public:
-    QDemonRenderContextInterface(const QDemonRef<QDemonRenderContext> &ctx, const QString &inApplicationDirectory);
+    // TODO: temp workaround for now
+    struct QDemonRenderContextInterfacePtr
+    {
+        QDemonRenderContextInterfacePtr() = default;
+        QDemonRenderContextInterfacePtr(QDemonRenderContextInterface *ptr, quintptr wid) : m_ptr(ptr), m_wid(wid) {}
+        QDemonRenderContextInterface * operator-> () const { return m_ptr.data(); }
+        ~QDemonRenderContextInterfacePtr() { if (!m_ptr.isNull() && m_ptr->ref == 0) QDemonRenderContextInterface::releaseRenderContextInterface(m_wid); }
+        bool isNull() const { return m_ptr.data() == nullptr; }
+    private:
+        friend QDemonRenderContextInterface;
+        QDemonRef<QDemonRenderContextInterface> m_ptr;
+        quintptr m_wid = 0;
+    };
+
+    static QDemonRenderContextInterface::QDemonRenderContextInterfacePtr getRenderContextInterface(const QDemonRef<QDemonRenderContext> &ctx, const QString &inApplicationDirectory, quintptr wid);
+    static QDemonRenderContextInterface::QDemonRenderContextInterfacePtr getRenderContextInterface(quintptr wid);
+
     ~QDemonRenderContextInterface();
     QDemonRef<QDemonRendererInterface> renderer();
     QDemonRef<QDemonRendererImpl> renderWidgetContext();
diff --git a/src/runtimerender/qdemonrendercustommaterialsystem.cpp b/src/runtimerender/qdemonrendercustommaterialsystem.cpp
index 0c075ea525c27686dffe6e40336a32164db276b7..83c1d60433f83f2fd0460659f6d947233edcc6e3 100644
--- a/src/runtimerender/qdemonrendercustommaterialsystem.cpp
+++ b/src/runtimerender/qdemonrendercustommaterialsystem.cpp
@@ -36,7 +36,7 @@
 
 #include <QtDemonRuntimeRender/qdemonrendercustommaterialrendercontext.h>
 #include <QtDemonRuntimeRender/qdemonrendercontextcore.h>
-#include <QtDemonRuntimeRender/qdemonrendercustommaterial.h>
+//#include <QtDemonRuntimeRender/qdemonrendercustommaterial.h>
 #include <QtDemonRuntimeRender/qdemonrenderdynamicobjectsystemcommands.h>
 #include <QtDemonRuntimeRender/qdemonrenderbuffermanager.h>
 #include <QtDemonRuntimeRender/qdemonrenderresourcemanager.h>
@@ -480,23 +480,6 @@ void QDemonCustomMaterialVertexPipeline::doGenerateVertexColor()
     vertex().append("\tvarColor = attr_color;");
 }
 
-struct QDemonMaterialClass
-{
-    QAtomicInt ref;
-    QDemonDynamicObjectClass *m_class;
-    bool m_hasTransparency = false;
-    bool m_hasRefraction = false;
-    bool m_hasDisplacement = false;
-    bool m_alwaysDirty = false;
-    quint32 m_shaderKey = 0;
-    quint32 m_layerCount = 0;
-    QDemonMaterialClass(QDemonDynamicObjectClass &inCls) : m_class(&inCls) {}
-
-    void afterWrite() { m_class = nullptr; }
-
-    void afterRead(QDemonDynamicObjectClass &inCls) { m_class = &inCls; }
-};
-
 struct QDemonShaderMapKey
 {
     TStrStrPair m_name;
@@ -543,13 +526,13 @@ struct QDemonCustomMaterialTextureData
     {
     }
 
-    void set(const dynamic::QDemonPropertyDefinition *inDefinition)
+    void set(const QDemonRenderCustomMaterial::TextureProperty *inDefinition)
     {
         if (texture && inDefinition) {
-            texture->setMagFilter(inDefinition->magFilterOp);
-            texture->setMinFilter(inDefinition->minFilterOp);
-            texture->setTextureWrapS(inDefinition->coordOp);
-            texture->setTextureWrapT(inDefinition->coordOp);
+            texture->setMagFilter(inDefinition->magFilterType);
+            texture->setMinFilter(inDefinition->minFilterType);
+            texture->setTextureWrapS(inDefinition->clampType);
+            texture->setTextureWrapT(inDefinition->clampType);
         } else if (texture) {
             // set some defaults
             texture->setMinFilter(QDemonRenderTextureMinifyingOp::Linear);
@@ -761,12 +744,6 @@ QDemonMaterialSystem::~QDemonMaterialSystem()
         allocatedBuffers[0] = allocatedBuffers.back();
         allocatedBuffers.pop_back();
     }
-
-    for (qint32 idx = 0; idx < allocatedImages.size(); ++idx) {
-        QDemonRenderImage *pImage = allocatedImages[idx].second;
-        ::free(pImage);
-    }
-    allocatedImages.clear();
 }
 
 void QDemonMaterialSystem::releaseBuffer(qint32 inIdx)
@@ -786,51 +763,6 @@ void QDemonMaterialSystem::releaseBuffer(qint32 inIdx)
     }
 }
 
-bool QDemonMaterialSystem::isMaterialRegistered(const QString &inStr)
-{
-    return stringMaterialMap.find(inStr) != stringMaterialMap.end();
-}
-
-bool QDemonMaterialSystem::registerMaterialClass(const QString &inName, const QDemonDataView<dynamic::QDemonPropertyDeclaration> &inProperties)
-{
-    if (isMaterialRegistered(inName))
-        return false;
-    context->dynamicObjectSystem()->doRegister(inName,
-                                                            inProperties,
-                                                            sizeof(QDemonRenderCustomMaterial),
-                                                            QDemonRenderGraphObject::Type::CustomMaterial);
-    QDemonDynamicObjectClass *theClass = context->dynamicObjectSystem()->dynamicObjectClass(inName);
-    if (theClass == nullptr) {
-        Q_ASSERT(false);
-        return false;
-    }
-    QDemonRef<QDemonMaterialClass> theNewClass(new QDemonMaterialClass(*theClass));
-    stringMaterialMap.insert(inName, theNewClass);
-    return true;
-}
-
-QDemonMaterialClass *QDemonMaterialSystem::getMaterialClass(const QString &inStr)
-{
-    auto theIter = stringMaterialMap.constFind(inStr);
-    if (theIter != stringMaterialMap.constEnd())
-        return theIter.value().data();
-    return nullptr;
-}
-
-const QDemonMaterialClass *QDemonMaterialSystem::getMaterialClass(const QString &inStr) const
-{
-    return const_cast<QDemonMaterialSystem *>(this)->getMaterialClass(inStr);
-}
-
-QDemonDataView<dynamic::QDemonPropertyDefinition> QDemonMaterialSystem::getCustomMaterialProperties(const QString &inCustomMaterialName) const
-{
-    QDemonDynamicObjectClass *theMaterialClass = context->dynamicObjectSystem()->dynamicObjectClass(inCustomMaterialName);
-    if (theMaterialClass)
-        return theMaterialClass->getProperties();
-
-    return QDemonDataView<dynamic::QDemonPropertyDefinition>();
-}
-
 qint32 QDemonMaterialSystem::findBuffer(const QString &inName)
 {
     for (qint32 idx = 0, end = allocatedBuffers.size(); idx < end; ++idx)
@@ -839,26 +771,20 @@ qint32 QDemonMaterialSystem::findBuffer(const QString &inName)
     return allocatedBuffers.size();
 }
 
-qint32 QDemonMaterialSystem::findAllocatedImage(const QString &inName)
-{
-    for (qint32 idx = 0, end = allocatedImages.size(); idx < end; ++idx)
-        if (allocatedImages[idx].first == inName)
-            return idx;
-    return -1;
-}
-
-bool QDemonMaterialSystem::textureNeedsMips(const dynamic::QDemonPropertyDefinition *inPropDec, QDemonRenderTexture2D *inTexture)
+bool QDemonMaterialSystem::textureNeedsMips(const QDemonRenderCustomMaterial::TextureProperty *inPropDec, QDemonRenderTexture2D *inTexture)
 {
     if (inPropDec && inTexture) {
-        return bool((inPropDec->minFilterOp == QDemonRenderTextureMinifyingOp::LinearMipmapLinear)
+        return bool((inPropDec->minFilterType == QDemonRenderTextureMinifyingOp::LinearMipmapLinear)
                     && (inTexture->numMipmaps() == 0));
     }
 
     return false;
 }
 
-void QDemonMaterialSystem::setTexture(const QDemonRef<QDemonRenderShaderProgram> &inShader, const QString &inPropName,
-                                      const QDemonRef<QDemonRenderTexture2D> &inTexture, const dynamic::QDemonPropertyDefinition *inPropDec,
+void QDemonMaterialSystem::setTexture(const QDemonRef<QDemonRenderShaderProgram> &inShader,
+                                      const QString &inPropName,
+                                      const QDemonRef<QDemonRenderTexture2D> &inTexture,
+                                      const QDemonRenderCustomMaterial::TextureProperty *inPropDec,
                                       bool needMips)
 {
     QDemonRef<QDemonCustomMaterialTextureData> theTextureEntry;
@@ -878,110 +804,18 @@ void QDemonMaterialSystem::setTexture(const QDemonRef<QDemonRenderShaderProgram>
     theTextureEntry->set(inPropDec);
 }
 
-void QDemonMaterialSystem::setPropertyEnumNames(const QString &inName, const QString &inPropName, const QDemonDataView<QString> &inNames)
-{
-    context->dynamicObjectSystem()->setPropertyEnumNames(inName, inPropName, inNames);
-}
-
-void QDemonMaterialSystem::setPropertyTextureSettings(const QString &inName, const QString &inPropName, const QString &inPropPath, QDemonRenderTextureTypeValue inTexType, QDemonRenderTextureCoordOp inCoordOp, QDemonRenderTextureMagnifyingOp inMagFilterOp, QDemonRenderTextureMinifyingOp inMinFilterOp)
-{
-    QDemonMaterialClass *theClass = getMaterialClass(inName);
-    if (theClass && inTexType == QDemonRenderTextureTypeValue::Displace) {
-        theClass->m_hasDisplacement = true;
-    }
-    context->dynamicObjectSystem()
-            ->setPropertyTextureSettings(inName, inPropName, inPropPath, inTexType, inCoordOp, inMagFilterOp, inMinFilterOp);
-}
-
 // TODO: Use an enum for the shader type?
+// Remove and call the setShaderData func directly?
 void QDemonMaterialSystem::setMaterialClassShader(QString inName, const QByteArray &inShaderType, const QByteArray &inShaderVersion,
                                                   const QByteArray &inShaderData, bool inHasGeomShader, bool inIsComputeShader)
 {
     context->dynamicObjectSystem()->setShaderData(inName, inShaderData, inShaderType, inShaderVersion, inHasGeomShader, inIsComputeShader);
 }
 
-QDemonRenderCustomMaterial *QDemonMaterialSystem::createCustomMaterial(const QString &inName)
-{
-    QDemonRenderCustomMaterial *theMaterial = static_cast<QDemonRenderCustomMaterial *>(
-                context->dynamicObjectSystem()->createInstance(inName));
-    QDemonMaterialClass *theClass = getMaterialClass(inName);
-
-    if (theMaterial) {
-        quint32 key = 0, count = 0;
-        if (theClass) {
-            key = theClass->m_shaderKey;
-            count = theClass->m_layerCount;
-        }
-        theMaterial->initialize(key, count);
-    }
-
-    return theMaterial;
-}
-
-void QDemonMaterialSystem::setCustomMaterialTransparency(const QString &inName, bool inHasTransparency)
-{
-    QDemonMaterialClass *theClass = getMaterialClass(inName);
-
-    if (theClass == nullptr) {
-        Q_ASSERT(false);
-        return;
-    }
-
-    theClass->m_hasTransparency = inHasTransparency;
-}
-
-void QDemonMaterialSystem::setCustomMaterialRefraction(const QString &inName, bool inHasRefraction)
-{
-    QDemonMaterialClass *theClass = getMaterialClass(inName);
-
-    if (theClass == nullptr) {
-        Q_ASSERT(false);
-        return;
-    }
-
-    theClass->m_hasRefraction = inHasRefraction;
-}
-
-void QDemonMaterialSystem::setCustomMaterialAlwaysDirty(const QString &inName, bool inIsAlwaysDirty)
-{
-    QDemonMaterialClass *theClass = getMaterialClass(inName);
-
-    if (theClass == nullptr) {
-        Q_ASSERT(false);
-        return;
-    }
-
-    theClass->m_alwaysDirty = inIsAlwaysDirty;
-}
-
-void QDemonMaterialSystem::setCustomMaterialShaderKey(const QString &inName, quint32 inShaderKey)
-{
-    QDemonMaterialClass *theClass = getMaterialClass(inName);
-
-    if (theClass == nullptr) {
-        Q_ASSERT(false);
-        return;
-    }
-
-    theClass->m_shaderKey = inShaderKey;
-}
-
-void QDemonMaterialSystem::setCustomMaterialLayerCount(const QString &inName, quint32 inLayerCount)
-{
-    QDemonMaterialClass *theClass = getMaterialClass(inName);
-
-    if (theClass == nullptr) {
-        Q_ASSERT(false);
-        return;
-    }
-
-    theClass->m_layerCount = inLayerCount;
-}
-
-void QDemonMaterialSystem::setCustomMaterialCommands(QString inName, QDemonDataView<dynamic::QDemonCommand *> inCommands)
-{
-    context->dynamicObjectSystem()->setRenderCommands(inName, inCommands);
-}
+//void QDemonMaterialSystem::setCustomMaterialCommands(QString inName, QDemonDataView<dynamic::QDemonCommand *> inCommands)
+//{
+//    context->dynamicObjectSystem()->setRenderCommands(inName, inCommands);
+//}
 
 QDemonRef<QDemonRenderShaderProgram> QDemonMaterialSystem::getShader(QDemonCustomMaterialRenderContext &inRenderContext, const QDemonRenderCustomMaterial &inMaterial, const dynamic::QDemonBindShader &inCommand, const TShaderFeatureSet &inFeatureSet, const dynamic::QDemonDynamicShaderProgramFlags &inFlags)
 {
@@ -1054,108 +888,117 @@ QDemonMaterialOrComputeShader QDemonMaterialSystem::bindShader(QDemonCustomMater
     return QDemonMaterialOrComputeShader();
 }
 
-void QDemonMaterialSystem::doApplyInstanceValue(QDemonRenderCustomMaterial &inMaterial, quint8 *inDataPtr, const QString &inPropertyName, QDemonRenderShaderDataType inPropertyType, const QDemonRef<QDemonRenderShaderProgram> &inShader, const dynamic::QDemonPropertyDefinition &inDefinition)
+void QDemonMaterialSystem::doApplyInstanceValue(QDemonRenderCustomMaterial &inMaterial,
+                                                const QString &inPropertyName,
+                                                const QVariant &propertyValue,
+                                                QDemonRenderShaderDataType inPropertyType,
+                                                const QDemonRef<QDemonRenderShaderProgram> &inShader)
 {
     QDemonRef<QDemonRenderShaderConstantBase> theConstant = inShader->shaderConstant(inPropertyName.toLocal8Bit());
     if (theConstant) {
         if (theConstant->getShaderConstantType() == inPropertyType) {
             if (inPropertyType == QDemonRenderShaderDataType::Texture2D) {
                 //                    StaticAssert<sizeof(QString) == sizeof(QDemonRenderTexture2DPtr)>::valid_expression();
-                const char *theStrPtr = inMaterial.imagePath;
-                const char *theStrPtrTst = reinterpret_cast<const char *>(inDataPtr); // TODO:
-                QDemonRef<QDemonBufferManager> theBufferManager(context->bufferManager());
-                QDemonRef<QDemonRenderTexture2D> theTexture;
-
-                if (theStrPtr) {
-                    QDemonRenderImageTextureData theTextureData = theBufferManager->loadRenderImage(QString::fromLocal8Bit(theStrPtr));
-                    if (theTextureData.m_texture) {
-                        theTexture = theTextureData.m_texture;
-                        setTexture(inShader,
-                                   inPropertyName,
-                                   theTexture,
-                                   &inDefinition,
-                                   textureNeedsMips(&inDefinition, theTexture.data()));
+                QDemonRenderCustomMaterial::TextureProperty *textureProperty = reinterpret_cast<QDemonRenderCustomMaterial::TextureProperty *>(propertyValue.value<void *>());
+                QDemonRenderImage *image = textureProperty->texImage;
+                if (image) {
+                    const QString imageSource = image->m_imagePath;
+                    QDemonRef<QDemonBufferManager> theBufferManager(context->bufferManager());
+                    QDemonRef<QDemonRenderTexture2D> theTexture;
+
+                    if (!imageSource.isEmpty()) {
+                        QDemonRenderImageTextureData theTextureData = theBufferManager->loadRenderImage(imageSource);
+                        if (theTextureData.m_texture) {
+                            theTexture = theTextureData.m_texture;
+                            dynamic::QDemonPropertyDefinition def;
+                            setTexture(inShader,
+                                       inPropertyName,
+                                       theTexture,
+                                       textureProperty, // TODO: Should not be null!
+                                       textureNeedsMips(textureProperty /* TODO: Should not be null! */, theTexture.data()));
+                        }
                     }
                 }
             } else {
+                // TODO:
                 switch (inPropertyType) {
                 case QDemonRenderShaderDataType::Integer:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<qint32 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.toInt());
                     break;
                 case QDemonRenderShaderDataType::IntegerVec2:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<qint32_2 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<qint32_2>());
                     break;
                 case QDemonRenderShaderDataType::IntegerVec3:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<qint32_3 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<qint32_3>());
                     break;
                 case QDemonRenderShaderDataType::IntegerVec4:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<qint32_4 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<qint32_4>());
                     break;
                 case QDemonRenderShaderDataType::Boolean:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<bool *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<bool>());
                     break;
                 case QDemonRenderShaderDataType::BooleanVec2:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<bool_2 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<bool_2>());
                     break;
                 case QDemonRenderShaderDataType::BooleanVec3:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<bool_3 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<bool_3>());
                     break;
                 case QDemonRenderShaderDataType::BooleanVec4:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<bool_4 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<bool_4>());
                     break;
                 case QDemonRenderShaderDataType::Float:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<float *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<float>());
                     break;
                 case QDemonRenderShaderDataType::Vec2:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QVector2D *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<QVector2D>());
                     break;
                 case QDemonRenderShaderDataType::Vec3:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QVector3D *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<QVector3D>());
                     break;
                 case QDemonRenderShaderDataType::Vec4:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QVector4D *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<QVector4D>());
                     break;
                 case QDemonRenderShaderDataType::UnsignedInteger:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<quint32 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<quint32>());
                     break;
                 case QDemonRenderShaderDataType::UnsignedIntegerVec2:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<quint32_2 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<quint32_2>());
                     break;
                 case QDemonRenderShaderDataType::UnsignedIntegerVec3:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<quint32_3 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<quint32_3>());
                     break;
                 case QDemonRenderShaderDataType::UnsignedIntegerVec4:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<quint32_4 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<quint32_4>());
                     break;
                 case QDemonRenderShaderDataType::Matrix3x3:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QMatrix3x3 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<QMatrix3x3>());
                     break;
                 case QDemonRenderShaderDataType::Matrix4x4:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QMatrix4x4 *>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), propertyValue.value<QMatrix4x4>());
                     break;
                 case QDemonRenderShaderDataType::Texture2D:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QDemonRenderTexture2D **>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QDemonRenderTexture2D **>(propertyValue.value<void *>())));
                     break;
                 case QDemonRenderShaderDataType::Texture2DHandle:
                     inShader->setPropertyValue(theConstant.data(),
-                                               *(reinterpret_cast<QDemonRenderTexture2D ***>(inDataPtr)));
+                                               *(reinterpret_cast<QDemonRenderTexture2D ***>(propertyValue.value<void *>())));
                     break;
                 case QDemonRenderShaderDataType::Texture2DArray:
                     inShader->setPropertyValue(theConstant.data(),
-                                               *(reinterpret_cast<QDemonRenderTexture2DArray **>(inDataPtr)));
+                                               *(reinterpret_cast<QDemonRenderTexture2DArray **>(propertyValue.value<void *>())));
                     break;
                 case QDemonRenderShaderDataType::TextureCube:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QDemonRenderTextureCube **>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QDemonRenderTextureCube **>(propertyValue.value<void *>())));
                     break;
                 case QDemonRenderShaderDataType::TextureCubeHandle:
                     inShader->setPropertyValue(theConstant.data(),
-                                               *(reinterpret_cast<QDemonRenderTextureCube ***>(inDataPtr)));
+                                               *(reinterpret_cast<QDemonRenderTextureCube ***>(propertyValue.value<void *>())));
                     break;
                 case QDemonRenderShaderDataType::Image2D:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QDemonRenderImage2D **>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QDemonRenderImage2D **>(propertyValue.value<void *>())));
                     break;
                 case QDemonRenderShaderDataType::DataBuffer:
-                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QDemonRenderDataBuffer **>(inDataPtr)));
+                    inShader->setPropertyValue(theConstant.data(), *(reinterpret_cast<QDemonRenderDataBuffer **>(propertyValue.value<void *>())));
                     break;
                 default:
                     Q_UNREACHABLE();
@@ -1171,33 +1014,24 @@ void QDemonMaterialSystem::doApplyInstanceValue(QDemonRenderCustomMaterial &inMa
     }
 }
 
-void QDemonMaterialSystem::applyInstanceValue(QDemonRenderCustomMaterial &inMaterial, QDemonMaterialClass &inClass, const QDemonRef<QDemonRenderShaderProgram> &inShader, const dynamic::QDemonApplyInstanceValue &inCommand)
+void QDemonMaterialSystem::applyInstanceValue(QDemonRenderCustomMaterial &inMaterial,
+                                              const QDemonRef<QDemonRenderShaderProgram> &inShader,
+                                              const dynamic::QDemonApplyInstanceValue &inCommand)
 {
     // sanity check
     if (!inCommand.m_propertyName.isNull()) {
-        bool canGetData = inCommand.m_valueOffset + dynamic::getSizeofShaderDataType(inCommand.m_valueType)
-                <= inMaterial.dataSectionByteSize;
-        if (canGetData == false) {
-            Q_ASSERT(false);
-            return;
-        }
-        quint8 *dataPtr = inMaterial.getDataSectionBegin() + inCommand.m_valueOffset;
-        const dynamic::QDemonPropertyDefinition *theDefinition = inClass.m_class->findPropertyByName(inCommand.m_propertyName);
-        if (theDefinition)
-            doApplyInstanceValue(inMaterial, dataPtr, inCommand.m_propertyName, inCommand.m_valueType, inShader, *theDefinition);
+        const auto &properties = inMaterial.properties;
+        const auto foundIt = std::find_if(properties.cbegin(), properties.cend(), [&inCommand](const QDemonRenderCustomMaterial::Property &prop) { return (prop.name == inCommand.m_propertyName); });
+        if (foundIt != properties.cend())
+            doApplyInstanceValue(inMaterial, foundIt->name, foundIt->value, foundIt->shaderDataType, inShader);
     } else {
-        QDemonDataView<dynamic::QDemonPropertyDefinition> theDefs = inClass.m_class->getProperties();
-        for (quint32 idx = 0, end = theDefs.size(); idx < end; ++idx) {
-            const dynamic::QDemonPropertyDefinition &theDefinition(theDefs[idx]);
-            QDemonRef<QDemonRenderShaderConstantBase> theConstant = inShader->shaderConstant(theDefinition.name);
-
-            // This is fine, the property wasn't found and we continue, no problem.
-            if (!theConstant)
-                continue;
-            quint8 *dataPtr = inMaterial.getDataSectionBegin() + theDefinition.offset;
-            inMaterial.imagePath = theDefinition.imagePath;
-            doApplyInstanceValue(inMaterial, dataPtr, theDefinition.name, theDefinition.dataType, inShader, theDefinition);
-        }
+        const auto &properties = inMaterial.properties;
+        for (const auto &prop : properties)
+            doApplyInstanceValue(inMaterial, prop.name, prop.value, prop.shaderDataType, inShader);
+
+        const auto textProps = inMaterial.textureProperties;
+        for (const auto &prop : textProps)
+            doApplyInstanceValue(inMaterial, prop.name, QVariant::fromValue((void *)&prop), prop.shaderDataType, inShader);
     }
 }
 
@@ -1218,6 +1052,38 @@ void QDemonMaterialSystem::applyBlending(const dynamic::QDemonApplyBlending &inC
     theContext->setBlendEquation(blendEqu);
 }
 
+void QDemonMaterialSystem::applyRenderStateValue(const dynamic::QDemonApplyRenderState &inCommand)
+{
+    QDemonRef<QDemonRenderContext> theContext(context->renderContext());
+
+    switch (inCommand.m_renderState) {
+    case QDemonRenderState::Blend:
+        theContext->setBlendingEnabled(inCommand.m_enabled);
+        break;
+    case QDemonRenderState::CullFace:
+        theContext->setCullingEnabled(inCommand.m_enabled);
+        break;
+    case QDemonRenderState::DepthTest:
+        theContext->setDepthTestEnabled(inCommand.m_enabled);
+        break;
+    case QDemonRenderState::StencilTest:
+        theContext->setStencilTestEnabled(inCommand.m_enabled);
+        break;
+    case QDemonRenderState::ScissorTest:
+        theContext->setScissorTestEnabled(inCommand.m_enabled);
+        break;
+    case QDemonRenderState::DepthWrite:
+        theContext->setDepthWriteEnabled(inCommand.m_enabled);
+        break;
+    case QDemonRenderState::Multisample:
+        theContext->setMultisampleEnabled(inCommand.m_enabled);
+        break;
+    case QDemonRenderState::Unknown:
+        break;
+    }
+
+}
+
 const QDemonRef<QDemonRenderTexture2D> QDemonMaterialSystem::applyBufferValue(const QDemonRenderCustomMaterial &inMaterial, const QDemonRef<QDemonRenderShaderProgram> &inShader, const dynamic::QDemonApplyBufferValue &inCommand, const QDemonRef<QDemonRenderTexture2D> inSourceTexture)
 {
     QDemonRef<QDemonRenderTexture2D> theTexture = nullptr;
@@ -1236,15 +1102,14 @@ const QDemonRef<QDemonRenderTexture2D> QDemonMaterialSystem::applyBufferValue(co
         theTexture = inSourceTexture;
 
     if (!inCommand.m_paramName.isNull()) {
-        QDemonRef<QDemonRenderShaderConstantBase> theConstant = inShader->shaderConstant(
-                    inCommand.m_paramName.toLocal8Bit().constData());
+        QDemonRef<QDemonRenderShaderConstantBase> theConstant = inShader->shaderConstant(inCommand.m_paramName.constData());
 
         if (theConstant) {
             if (theConstant->getShaderConstantType() != QDemonRenderShaderDataType::Texture2D) {
                 qCCritical(INVALID_OPERATION,
                            "CustomMaterial %s: Binding buffer to parameter %s that is not a texture",
-                           qPrintable(inMaterial.className),
-                           qPrintable(inCommand.m_paramName));
+                           inMaterial.className,
+                           inCommand.m_paramName.constData());
                 Q_ASSERT(false);
             } else {
                 setTexture(inShader, inCommand.m_paramName, theTexture);
@@ -1564,7 +1429,10 @@ void QDemonMaterialSystem::renderPass(QDemonCustomMaterialRenderContext &inRende
     theContext->draw(theDrawMode, count, offset);
 }
 
-void QDemonMaterialSystem::doRenderCustomMaterial(QDemonCustomMaterialRenderContext &inRenderContext, const QDemonRenderCustomMaterial &inMaterial, QDemonMaterialClass &inClass, const QDemonRef<QDemonRenderFrameBuffer> &inTarget, const TShaderFeatureSet &inFeatureSet)
+void QDemonMaterialSystem::doRenderCustomMaterial(QDemonCustomMaterialRenderContext &inRenderContext,
+                                                  const QDemonRenderCustomMaterial &inMaterial,
+                                                  const QDemonRef<QDemonRenderFrameBuffer> &inTarget,
+                                                  const TShaderFeatureSet &inFeatureSet)
 {
     QDemonRef<QDemonRenderContext> theContext = context->renderContext();
     QDemonRef<QDemonCustomMaterialShader> theCurrentShader(nullptr);
@@ -1587,7 +1455,7 @@ void QDemonMaterialSystem::doRenderCustomMaterial(QDemonCustomMaterialRenderCont
     QVector2D theDestSize;
     bool theRenderTargetNeedsClear = false;
 
-    QDemonDataView<dynamic::QDemonCommand *> theCommands(inClass.m_class->getRenderCommands());
+    QDemonDataView<dynamic::QDemonCommand *> theCommands = toDataView(inMaterial.commands.cbegin(), inMaterial.commands.size());
     for (qint32 commandIdx = 0, commandEnd = theCommands.size(); commandIdx < commandEnd; ++commandIdx) {
         const dynamic::QDemonCommand &theCommand(*theCommands[commandIdx]);
 
@@ -1646,7 +1514,9 @@ void QDemonMaterialSystem::doRenderCustomMaterial(QDemonCustomMaterialRenderCont
             blitFramebuffer(inRenderContext, static_cast<const dynamic::QDemonApplyBlitFramebuffer &>(theCommand), inTarget);
             break;
         case dynamic::CommandType::ApplyRenderState:
-            break; // TODO: "simple_glass.material
+            // TODO: The applyRenderStateValue() function is a very naive implementation
+            applyRenderStateValue(static_cast<const dynamic::QDemonApplyRenderState &>(theCommand));
+            break;
         default:
             Q_ASSERT(false);
             break;
@@ -1667,17 +1537,12 @@ void QDemonMaterialSystem::doRenderCustomMaterial(QDemonCustomMaterialRenderCont
 
 QString QDemonMaterialSystem::getShaderName(const QDemonRenderCustomMaterial &inMaterial)
 {
-    QDemonMaterialClass *theClass = getMaterialClass(inMaterial.className);
-    if (!theClass)
-        return QString();
-
-    QDemonDataView<dynamic::QDemonCommand *> theCommands = theClass->m_class->getRenderCommands();
-    TShaderAndFlags thePrepassShader;
-    for (qint32 idx = 0, end = theCommands.size(); idx < end && thePrepassShader.first == nullptr; ++idx) {
-        const dynamic::QDemonCommand &theCommand = *theCommands[idx];
-        if (theCommand.m_type == dynamic::CommandType::BindShader) {
-            const dynamic::QDemonBindShader &theBindCommand = static_cast<const dynamic::QDemonBindShader &>(theCommand);
-            return theBindCommand.m_shaderPath;
+    auto it = inMaterial.commands.cbegin();
+    const auto end = inMaterial.commands.cend();
+    for (; it != end; ++it) {
+        if ((*it)->m_type == dynamic::CommandType::BindShader) {
+            dynamic::QDemonBindShader *bindCommand = static_cast<dynamic::QDemonBindShader *>(*it);
+            return bindCommand->m_shaderPath;
         }
     }
 
@@ -1687,89 +1552,28 @@ QString QDemonMaterialSystem::getShaderName(const QDemonRenderCustomMaterial &in
 
 void QDemonMaterialSystem::applyShaderPropertyValues(const QDemonRenderCustomMaterial &inMaterial, const QDemonRef<QDemonRenderShaderProgram> &inProgram)
 {
-    QDemonMaterialClass *theClass = getMaterialClass(inMaterial.className);
-    if (!theClass)
-        return;
-
     dynamic::QDemonApplyInstanceValue applier;
-    applyInstanceValue(const_cast<QDemonRenderCustomMaterial &>(inMaterial), *theClass, inProgram, applier);
-}
-
-void QDemonMaterialSystem::prepareTextureForRender(QDemonMaterialClass &inClass, QDemonRenderCustomMaterial &inMaterial)
-{
-    QDemonDataView<dynamic::QDemonPropertyDefinition> thePropDefs = inClass.m_class->getProperties();
-    for (qint32 idx = 0, end = thePropDefs.size(); idx < end; ++idx) {
-        if (thePropDefs[idx].dataType == QDemonRenderShaderDataType::Texture2D) {
-            if (thePropDefs[idx].texUsageType == QDemonRenderTextureTypeValue::Displace) {
-                QDemonRenderImage *pImage = nullptr;
-
-                // we only do this to not miss if "None" is selected
-                QString theStrPtr = *reinterpret_cast<QString *>(inMaterial.getDataSectionBegin() + thePropDefs[idx].offset);
-
-                if (!theStrPtr.isNull()) {
-
-                    const qint32 index = findAllocatedImage(thePropDefs[idx].imagePath);
-                    if (index == -1) {
-                        pImage = new QDemonRenderImage();
-                        allocatedImages.push_back(QPair<QString, QDemonRenderImage *>(thePropDefs[idx].imagePath, pImage));
-                    } else
-                        pImage = allocatedImages[index].second;
-
-                    if (inMaterial.m_displacementMap != pImage) {
-                        inMaterial.m_displacementMap = pImage;
-                        inMaterial.m_displacementMap->m_imagePath = thePropDefs[idx].imagePath;
-                        inMaterial.m_displacementMap->m_imageShaderName = thePropDefs[idx].name; // this is our name in the shader
-                        inMaterial.m_displacementMap->m_verticalTilingMode = thePropDefs[idx].coordOp;
-                        inMaterial.m_displacementMap->m_horizontalTilingMode = thePropDefs[idx].coordOp;
-                    }
-                } else {
-                    inMaterial.m_displacementMap = nullptr;
-                }
-            } else if (thePropDefs[idx].texUsageType == QDemonRenderTextureTypeValue::Emissive2) {
-                QDemonRenderImage *pImage = nullptr;
-
-                // we only do this to not miss if "None" is selected
-                QString theStrPtr = *reinterpret_cast<QString *>(inMaterial.getDataSectionBegin() + thePropDefs[idx].offset);
-
-                if (!theStrPtr.isNull()) {
-                    const qint32 index = findAllocatedImage(thePropDefs[idx].imagePath);
-                    if (index == -1) {
-                        pImage = new QDemonRenderImage();
-                        allocatedImages.push_back(QPair<QString, QDemonRenderImage *>(thePropDefs[idx].imagePath, pImage));
-                    } else
-                        pImage = allocatedImages[index].second;
-
-                    if (inMaterial.m_emissiveMap2 != pImage) {
-                        inMaterial.m_emissiveMap2 = pImage;
-                        inMaterial.m_emissiveMap2->m_imagePath = thePropDefs[idx].imagePath;
-                        inMaterial.m_emissiveMap2->m_imageShaderName = thePropDefs[idx].name; // this is our name in the shader
-                        inMaterial.m_emissiveMap2->m_verticalTilingMode = thePropDefs[idx].coordOp;
-                        inMaterial.m_emissiveMap2->m_horizontalTilingMode = thePropDefs[idx].coordOp;
-                    }
-                } else {
-                    inMaterial.m_emissiveMap2 = nullptr;
-                }
-            }
-        }
-    }
+    applyInstanceValue(const_cast<QDemonRenderCustomMaterial &>(inMaterial), inProgram, applier);
 }
 
-void QDemonMaterialSystem::prepareDisplacementForRender(QDemonMaterialClass &inClass, QDemonRenderCustomMaterial &inMaterial)
+void QDemonMaterialSystem::prepareDisplacementForRender(QDemonRenderCustomMaterial &inMaterial)
 {
+    // TODO: Shouldn't be needed anymore, as there's only one place where the values are updated
     if (inMaterial.m_displacementMap == nullptr)
         return;
 
     // our displacement mappin in MDL has fixed naming
-    QDemonDataView<dynamic::QDemonPropertyDefinition> thePropDefs = inClass.m_class->getProperties();
-    for (qint32 idx = 0, end = thePropDefs.size(); idx < end; ++idx) {
-        if (thePropDefs[idx].dataType == QDemonRenderShaderDataType::Float && (thePropDefs[idx].name == "displaceAmount")) {
-            float theValue = *reinterpret_cast<const float *>(inMaterial.getDataSectionBegin() + thePropDefs[idx].offset);
-            inMaterial.m_displaceAmount = theValue;
-        } else if (thePropDefs[idx].dataType == QDemonRenderShaderDataType::Vec3 && (thePropDefs[idx].name == "displace_tiling")) {
-            QVector3D theValue = *reinterpret_cast<const QVector3D *>(inMaterial.getDataSectionBegin()
-                                                                      + thePropDefs[idx].offset);
+    const auto &props = inMaterial.properties;
+    for (const auto &prop : props) {
+        if (prop.shaderDataType == QDemonRenderShaderDataType::Float && prop.name == QByteArrayLiteral("displaceAmount")) {
+            bool ok = false;
+            const float theValue = prop.value.toFloat(&ok); //*reinterpret_cast<const float *>(inMaterial.getDataSectionBegin() + thePropDefs[idx].offset);
+            if (ok)
+                inMaterial.m_displaceAmount = theValue;
+        } else if (prop.shaderDataType == QDemonRenderShaderDataType::Vec3 && prop.name == QByteArrayLiteral("displace_tiling")) {
+            const QVector3D theValue = prop.value.value<QVector3D>(); // = *reinterpret_cast<const QVector3D *>(inMaterial.getDataSectionBegin() + thePropDefs[idx].offset);
             if (theValue.x() != inMaterial.m_displacementMap->m_scale.x()
-                    || theValue.y() != inMaterial.m_displacementMap->m_scale.y()) {
+                || theValue.y() != inMaterial.m_displacementMap->m_scale.y()) {
                 inMaterial.m_displacementMap->m_scale = QVector2D(theValue.x(), theValue.y());
                 inMaterial.m_displacementMap->m_flags.setFlag(QDemonRenderImage::Flag::TransformDirty);
             }
@@ -1777,12 +1581,10 @@ void QDemonMaterialSystem::prepareDisplacementForRender(QDemonMaterialClass &inC
     }
 }
 
-void QDemonMaterialSystem::prepareMaterialForRender(QDemonMaterialClass &inClass, QDemonRenderCustomMaterial &inMaterial)
+void QDemonMaterialSystem::prepareMaterialForRender(QDemonRenderCustomMaterial &inMaterial)
 {
-    prepareTextureForRender(inClass, inMaterial);
-
-    if (inClass.m_hasDisplacement)
-        prepareDisplacementForRender(inClass, inMaterial);
+    if (inMaterial.m_displacementMap) // inClass->m_hasDisplacement
+        prepareDisplacementForRender(inMaterial);
 }
 
 // Returns true if the material is dirty and thus will produce a different render result
@@ -1791,19 +1593,8 @@ void QDemonMaterialSystem::prepareMaterialForRender(QDemonMaterialClass &inClass
 // object is completely transparent
 bool QDemonMaterialSystem::prepareForRender(const QDemonRenderModel &, const QDemonRenderSubset &, QDemonRenderCustomMaterial &inMaterial, bool clearMaterialDirtyFlags)
 {
-    QDemonMaterialClass *theMaterialClass = getMaterialClass(inMaterial.className);
-    if (theMaterialClass == nullptr) {
-        Q_ASSERT(false);
-        return false;
-    }
-
-    prepareMaterialForRender(*theMaterialClass, inMaterial);
-
-    inMaterial.m_hasTransparency = theMaterialClass->m_hasTransparency;
-    inMaterial.m_hasRefraction = theMaterialClass->m_hasRefraction;
-    inMaterial.m_hasVolumetricDF = false;
-
-    bool wasDirty = inMaterial.isDirty() || theMaterialClass->m_alwaysDirty;
+    prepareMaterialForRender(inMaterial);
+    const bool wasDirty = inMaterial.isDirty(); // TODO: Always dirty flag?
     if (clearMaterialDirtyFlags)
         inMaterial.updateDirtyForFrame();
 
@@ -1813,8 +1604,6 @@ bool QDemonMaterialSystem::prepareForRender(const QDemonRenderModel &, const QDe
 // TODO - handle UIC specific features such as vertex offsets for prog-aa and opacity.
 void QDemonMaterialSystem::renderSubset(QDemonCustomMaterialRenderContext &inRenderContext, const TShaderFeatureSet &inFeatureSet)
 {
-    QDemonMaterialClass *theClass = getMaterialClass(inRenderContext.material.className);
-
     // Ensure that our overall render context comes back no matter what the client does.
     QDemonRenderContextScopedProperty<QDemonRenderBlendFunctionArgument> __blendFunction(*context->renderContext(),
                                                                                          &QDemonRenderContext::blendFunction,
@@ -1829,13 +1618,12 @@ void QDemonMaterialSystem::renderSubset(QDemonCustomMaterialRenderContext &inRen
                                                             &QDemonRenderContext::isBlendingEnabled,
                                                             &QDemonRenderContext::setBlendingEnabled);
 
-    doRenderCustomMaterial(inRenderContext, inRenderContext.material, *theClass, context->renderContext()->renderTarget(), inFeatureSet);
+    doRenderCustomMaterial(inRenderContext, inRenderContext.material, context->renderContext()->renderTarget(), inFeatureSet);
 }
 
 bool QDemonMaterialSystem::renderDepthPrepass(const QMatrix4x4 &inMVP, const QDemonRenderCustomMaterial &inMaterial, const QDemonRenderSubset &inSubset)
 {
-    QDemonMaterialClass *theClass = getMaterialClass(inMaterial.className);
-    QDemonDataView<dynamic::QDemonCommand *> theCommands = theClass->m_class->getRenderCommands();
+    QDemonDataView<dynamic::QDemonCommand *> theCommands = toDataView(inMaterial.commands.cbegin(), inMaterial.commands.size());
     TShaderAndFlags thePrepassShader;
     for (qint32 idx = 0, end = theCommands.size(); idx < end && thePrepassShader.first == nullptr; ++idx) {
         const dynamic::QDemonCommand &theCommand = *theCommands[idx];
@@ -1859,12 +1647,6 @@ bool QDemonMaterialSystem::renderDepthPrepass(const QMatrix4x4 &inMVP, const QDe
     return true;
 }
 
-void QDemonMaterialSystem::onMaterialActivationChange(const QDemonRenderCustomMaterial &inMaterial, bool inActive)
-{
-    Q_UNUSED(inMaterial)
-    Q_UNUSED(inActive)
-}
-
 void QDemonMaterialSystem::endFrame()
 {
     if (lastFrameTime.elapsed() != 0)
diff --git a/src/runtimerender/qdemonrendercustommaterialsystem.h b/src/runtimerender/qdemonrendercustommaterialsystem.h
index 4bc1ded7cdf95bafb5a03baa8098b84ea249e63f..8c122935326deb78e46333b68787c07e0b0a7d28 100644
--- a/src/runtimerender/qdemonrendercustommaterialsystem.h
+++ b/src/runtimerender/qdemonrendercustommaterialsystem.h
@@ -37,6 +37,8 @@
 
 #include <QtCore/qhash.h>
 
+#include <QtDemonRuntimeRender/qdemonrendercustommaterial.h> // Make it possible to forward declare the nested TextureProperty
+
 QT_BEGIN_NAMESPACE
 
 namespace dynamic {
@@ -61,6 +63,7 @@ struct QDemonAllocateBuffer;
 struct QDemonApplyBufferValue;
 struct QDemonBindBuffer;
 struct QDemonApplyBlitFramebuffer;
+struct QDemonApplyRenderState;
 }
 
 // How to handle blend modes?
@@ -75,24 +78,19 @@ public:
 private:
     typedef QHash<QDemonShaderMapKey, QDemonRef<QDemonCustomMaterialShader>> ShaderMap;
     typedef QPair<QString, QDemonRenderImage *> AllocatedImageEntry;
-    typedef QHash<QString, QDemonRef<QDemonMaterialClass>> StringMaterialMap;
     typedef QPair<QString, QString> TStrStrPair;
     typedef QPair<QString, QDemonRef<QDemonCustomMaterialTextureData>> CustomMaterialTextureEntry;
 
     QDemonRenderContextInterface *context = nullptr;
-    StringMaterialMap stringMaterialMap;
     ShaderMap shaderMap;
     QVector<CustomMaterialTextureEntry> textureEntries;
     QVector<QDemonCustomMaterialBuffer> allocatedBuffers;
-    QVector<AllocatedImageEntry> allocatedImages;
     bool useFastBlits = true;
     QString shaderNameBuilder;
     QElapsedTimer lastFrameTime;
     float msSinceLastFrame = 0;
 
     void releaseBuffer(qint32 inIdx);
-    QDemonMaterialClass *getMaterialClass(const QString &inStr);
-    const QDemonMaterialClass *getMaterialClass(const QString &inStr) const;
 
     QDemonRef<QDemonRenderShaderProgram> getShader(QDemonCustomMaterialRenderContext &inRenderContext,
                                                    const QDemonRenderCustomMaterial &inMaterial,
@@ -105,20 +103,20 @@ private:
                                              const dynamic::QDemonBindShader &inCommand,
                                              const TShaderFeatureSet &inFeatureSet);
 
-    void doApplyInstanceValue(QDemonRenderCustomMaterial & /* inMaterial */,
-                              quint8 *inDataPtr,
-                              const QString &inPropertyName,
+    void doApplyInstanceValue(QDemonRenderCustomMaterial &inMaterial,
+                              const QString &propertyName,
+                              const QVariant &propertyValue,
                               QDemonRenderShaderDataType inPropertyType,
-                              const QDemonRef<QDemonRenderShaderProgram> &inShader,
-                              const dynamic::QDemonPropertyDefinition &inDefinition);
+                              const QDemonRef<QDemonRenderShaderProgram> &inShader);
 
     void applyInstanceValue(QDemonRenderCustomMaterial &inMaterial,
-                            QDemonMaterialClass &inClass,
                             const QDemonRef<QDemonRenderShaderProgram> &inShader,
                             const dynamic::QDemonApplyInstanceValue &inCommand);
 
     void applyBlending(const dynamic::QDemonApplyBlending &inCommand);
 
+    void applyRenderStateValue(const dynamic::QDemonApplyRenderState &inCommand);
+
     // we currently only bind a source texture
     const QDemonRef<QDemonRenderTexture2D> applyBufferValue(const QDemonRenderCustomMaterial &inMaterial,
                                                             const QDemonRef<QDemonRenderShaderProgram> &inShader,
@@ -146,44 +144,31 @@ private:
                     quint32 inOffset);
     void doRenderCustomMaterial(QDemonCustomMaterialRenderContext &inRenderContext,
                                 const QDemonRenderCustomMaterial &inMaterial,
-                                QDemonMaterialClass &inClass,
                                 const QDemonRef<QDemonRenderFrameBuffer> &inTarget,
                                 const TShaderFeatureSet &inFeatureSet);
-    void prepareTextureForRender(QDemonMaterialClass &inClass, QDemonRenderCustomMaterial &inMaterial);
-    void prepareDisplacementForRender(QDemonMaterialClass &inClass, QDemonRenderCustomMaterial &inMaterial);
-    void prepareMaterialForRender(QDemonMaterialClass &inClass, QDemonRenderCustomMaterial &inMaterial);
+    void prepareDisplacementForRender(QDemonRenderCustomMaterial &inMaterial);
+    void prepareMaterialForRender(QDemonRenderCustomMaterial &inMaterial);
 
     qint32 findBuffer(const QString &inName);
-    qint32 findAllocatedImage(const QString &inName);
-    bool textureNeedsMips(const dynamic::QDemonPropertyDefinition *inPropDec, QDemonRenderTexture2D *inTexture);
+    bool textureNeedsMips(const QDemonRenderCustomMaterial::TextureProperty *inPropDec, QDemonRenderTexture2D *inTexture);
     void setTexture(const QDemonRef<QDemonRenderShaderProgram> &inShader,
                     const QString &inPropName,
                     const QDemonRef<QDemonRenderTexture2D> &inTexture,
-                    const dynamic::QDemonPropertyDefinition *inPropDec = nullptr,
+                    const QDemonRenderCustomMaterial::TextureProperty *inPropDec = nullptr,
                     bool needMips = false);
 
 public:
     QDemonMaterialSystem(QDemonRenderContextInterface *ct);
 
     ~QDemonMaterialSystem();
-    bool isMaterialRegistered(const QString &inStr);
-
-    bool registerMaterialClass(const QString &inName, const QDemonDataView<dynamic::QDemonPropertyDeclaration> &inProperties);
-
-    QDemonDataView<dynamic::QDemonPropertyDefinition> getCustomMaterialProperties(const QString &inCustomMaterialName) const;
 
-    void setCustomMaterialRefraction(const QString &inName, bool inHasRefraction);
-    void setCustomMaterialTransparency(const QString &inName, bool inHasTransparency);
-    void setCustomMaterialAlwaysDirty(const QString &inName, bool inIsAlwaysDirty);
-    void setCustomMaterialShaderKey(const QString &inName, quint32 inShaderKey);
-    void setCustomMaterialLayerCount(const QString &inName, quint32 inLayerCount);
     // The custom material commands are the actual commands that run for a given material
     // effect.  The tell the system exactly
     // explicitly things like bind this shader, bind this render target, apply this property,
     // run this shader
     // See UICRenderEffectCommands.h for the list of commands.
     // These commands are copied into the effect.
-    void setCustomMaterialCommands(QString inName, QDemonDataView<dynamic::QDemonCommand *> inCommands);
+//    void setCustomMaterialCommands(QString inName, QDemonDataView<dynamic::QDemonCommand *> inCommands);
 
     void setMaterialClassShader(QString inName,
                                 const QByteArray &inShaderType,
@@ -192,18 +177,6 @@ public:
                                 bool inHasGeomShader,
                                 bool inIsComputeShader);
 
-    QDemonRenderCustomMaterial *createCustomMaterial(const QString &inName);
-
-    void setPropertyEnumNames(const QString &inName, const QString &inPropName, const QDemonDataView<QString> &inNames);
-
-    void setPropertyTextureSettings(const QString &inEffectName,
-                                    const QString &inPropName,
-                                    const QString &inPropPath,
-                                    QDemonRenderTextureTypeValue inTexType,
-                                    QDemonRenderTextureCoordOp inCoordOp,
-                                    QDemonRenderTextureMagnifyingOp inMagFilterOp,
-                                    QDemonRenderTextureMinifyingOp inMinFilterOp);
-
     void setRenderContextInterface(QDemonRenderContextInterface *inContext);
 
     // Returns true if the material is dirty and thus will produce a different render result
@@ -215,7 +188,6 @@ public:
 
     bool renderDepthPrepass(const QMatrix4x4 &inMVP, const QDemonRenderCustomMaterial &inMaterial, const QDemonRenderSubset &inSubset);
     void renderSubset(QDemonCustomMaterialRenderContext &inRenderContext, const TShaderFeatureSet &inFeatureSet);
-    void onMaterialActivationChange(const QDemonRenderCustomMaterial &inMaterial, bool inActive);
 
     // get shader name
     QString getShaderName(const QDemonRenderCustomMaterial &inMaterial);
diff --git a/src/runtimerender/qdemonrenderdynamicobjectsystem.cpp b/src/runtimerender/qdemonrenderdynamicobjectsystem.cpp
index 9a7fbde646589c147cf17ba6e9175414e85017a0..ecdc554930892b97156aa4fb69933a0621db5f58 100644
--- a/src/runtimerender/qdemonrenderdynamicobjectsystem.cpp
+++ b/src/runtimerender/qdemonrenderdynamicobjectsystem.cpp
@@ -30,7 +30,6 @@
 #include "qdemonrenderdynamicobjectsystem.h"
 
 #include <QtDemonRuntimeRender/qdemonrendercontextcore.h>
-#include <QtDemonRuntimeRender/qdemonrenderdynamicobject.h>
 #include <QtDemonRuntimeRender/qdemonrendershadercache.h>
 #include <QtDemonRuntimeRender/qdemonrenderinputstreamfactory.h>
 #include <QtDemonRuntimeRender/qdemonrenderer.h>
@@ -178,197 +177,6 @@ void QDemonCommand::copyConstructCommand(quint8 *inDataBuffer, const QDemonComma
 }
 }
 
-namespace {
-
-quint32 align(quint32 inValue)
-{
-    if (inValue % 4)
-        return inValue + (4 - (inValue % 4));
-    return inValue;
-}
-
-quint32 align8(quint32 inValue)
-{
-    if (inValue % 8)
-        return inValue + (8 - (inValue % 8));
-    return inValue;
-}
-
-inline const char *getShaderDatatypeName(QDemonRenderShaderDataType inValue)
-{
-    switch (inValue) {
-    case QDemonRenderShaderDataType::Unknown:
-        return "";
-    case QDemonRenderShaderDataType::Integer:
-        return "qint32";
-    case QDemonRenderShaderDataType::IntegerVec2:
-        return "qint32_2";
-    case QDemonRenderShaderDataType::IntegerVec3:
-        return "qint32_3";
-    case QDemonRenderShaderDataType::IntegerVec4:
-        return "qint32_4";
-    case QDemonRenderShaderDataType::Boolean:
-        return "bool";
-    case QDemonRenderShaderDataType::BooleanVec2:
-        return "bool_2";
-    case QDemonRenderShaderDataType::BooleanVec3:
-        return "bool_3";
-    case QDemonRenderShaderDataType::BooleanVec4:
-        return "bool_4";
-    case QDemonRenderShaderDataType::Float:
-        return "float";
-    case QDemonRenderShaderDataType::Vec2:
-        return "QVector2D";
-    case QDemonRenderShaderDataType::Vec3:
-        return "QVector3D";
-    case QDemonRenderShaderDataType::Vec4:
-        return "QVector4D";
-    case QDemonRenderShaderDataType::UnsignedInteger:
-        return "quint32";
-    case QDemonRenderShaderDataType::UnsignedIntegerVec2:
-        return "quint32_2";
-    case QDemonRenderShaderDataType::UnsignedIntegerVec3:
-        return "quint32_3";
-    case QDemonRenderShaderDataType::UnsignedIntegerVec4:
-        return "quint32_4";
-    case QDemonRenderShaderDataType::Matrix3x3:
-        return "QMatrix3x3";
-    case QDemonRenderShaderDataType::Matrix4x4:
-        return "QMatrix4x4";
-    case QDemonRenderShaderDataType::Texture2D:
-        return "QDemonRenderTexture2DPtr";
-    case QDemonRenderShaderDataType::Texture2DHandle:
-        return "QDemonRenderTexture2DHandle";
-    case QDemonRenderShaderDataType::Texture2DArray:
-        return "QDemonRenderTexture2DArrayPtr";
-    case QDemonRenderShaderDataType::TextureCube:
-        return "QDemonRenderTextureCubePtr";
-    case QDemonRenderShaderDataType::TextureCubeHandle:
-        return "QDemonRenderTextureCubeHandle";
-    case QDemonRenderShaderDataType::Image2D:
-        return "QDemonRenderImage2DPtr";
-    case QDemonRenderShaderDataType::DataBuffer:
-        return "QDemonRenderDataBufferPtr";
-    }
-    Q_ASSERT(false);
-    return "";
-}
-}
-
-QDemonDynamicObjectClass::QDemonDynamicObjectClass(QString id,
-                                                   QDemonDataView<dynamic::QDemonPropertyDefinition> definitions,
-                                                   quint32 propertySectionByteSize,
-                                                   quint32 baseObjectSize,
-                                                   QDemonRenderGraphObject::Type objectType,
-                                                   quint8 *propDefaultData,
-                                                   bool inRequiresDepthTexture,
-                                                   QDemonRenderTextureFormat inOutputFormat)
-    : m_id(id)
-    , m_propertyDefinitions(definitions)
-    , m_propertySectionByteSize(propertySectionByteSize)
-    , m_baseObjectSize(baseObjectSize)
-    , m_graphObjectType(objectType)
-    , m_propertyDefaultData(propDefaultData)
-    , m_requiresDepthTexture(inRequiresDepthTexture)
-    , m_requiresCompilation(false)
-    , m_outputFormat(inOutputFormat)
-{
-}
-
-QDemonDynamicObjectClass::~QDemonDynamicObjectClass()
-{
-    if (m_propertyDefinitions.size()) {
-        for (quint32 idx = 0, end = m_propertyDefinitions.size(); idx < end; ++idx) {
-            if (m_propertyDefinitions[idx].enumValueNames.size()) // ### You can't free a QString like this!
-                ::free((void *)m_propertyDefinitions[idx].enumValueNames.begin());
-        }
-    }
-    releaseCommands();
-}
-
-void QDemonDynamicObjectClass::releaseCommands()
-{
-    if (m_renderCommands.size()) {
-        ::free(const_cast<dynamic::QDemonCommand *>(*m_renderCommands.begin()));
-        m_renderCommands = QDemonDataView<dynamic::QDemonCommand *>();
-    }
-}
-
-QString QDemonDynamicObjectClass::getId() const
-{
-    return m_id;
-}
-
-QDemonDataView<dynamic::QDemonPropertyDefinition> QDemonDynamicObjectClass::getProperties() const
-{
-    return m_propertyDefinitions;
-}
-
-quint32 QDemonDynamicObjectClass::getPropertySectionByteSize() const
-{
-    return m_propertySectionByteSize;
-}
-
-const quint8 *QDemonDynamicObjectClass::getDefaultValueBuffer() const
-{
-    return m_propertyDefaultData;
-}
-
-quint32 QDemonDynamicObjectClass::getBaseObjectSize() const
-{
-    return m_baseObjectSize;
-}
-
-QDemonRenderGraphObject::Type QDemonDynamicObjectClass::graphObjectType() const
-{
-    return m_graphObjectType;
-}
-
-const dynamic::QDemonPropertyDefinition *QDemonDynamicObjectClass::findDefinition(QString &str) const
-{
-    for (quint32 idx = 0, end = m_propertyDefinitions.size(); idx < end; ++idx) {
-        const dynamic::QDemonPropertyDefinition &def(m_propertyDefinitions[idx]);
-        if (def.name == str)
-            return &def;
-    }
-    return nullptr;
-}
-
-const dynamic::QDemonPropertyDefinition *QDemonDynamicObjectClass::findPropertyByName(QString inName) const
-{
-    return findDefinition(inName);
-}
-
-QDemonDataView<dynamic::QDemonCommand *> QDemonDynamicObjectClass::getRenderCommands() const
-{
-    return m_renderCommands;
-}
-
-bool QDemonDynamicObjectClass::requiresDepthTexture() const
-{
-    return m_requiresDepthTexture;
-}
-
-void QDemonDynamicObjectClass::setRequiresDepthTexture(bool inVal)
-{
-    m_requiresDepthTexture = inVal;
-}
-
-bool QDemonDynamicObjectClass::requiresCompilation() const
-{
-    return m_requiresCompilation;
-}
-
-void QDemonDynamicObjectClass::setRequiresCompilation(bool inVal)
-{
-    m_requiresCompilation = inVal;
-}
-
-QDemonRenderTextureFormat QDemonDynamicObjectClass::getOutputTextureFormat() const
-{
-    return m_outputFormat;
-}
-
 QString QDemonDynamicObjectSystem::getShaderCodeLibraryDirectory()
 {
     return QStringLiteral("res/effectlib");
@@ -385,226 +193,59 @@ QDemonDynamicObjectSystem::QDemonDynamicObjectSystem(QDemonRenderContextInterfac
 
 QDemonDynamicObjectSystem::~QDemonDynamicObjectSystem() {}
 
-bool QDemonDynamicObjectSystem::isRegistered(QString inStr)
-{
-    return m_classes.find(inStr) != m_classes.end();
-}
-
-bool QDemonDynamicObjectSystem::doRegister(QString inName,
-                                           QDemonDataView<dynamic::QDemonPropertyDeclaration> inProperties,
-                                           quint32 inBaseObjectSize,
-                                           QDemonRenderGraphObject::Type inGraphObjectType)
-{
-    if (isRegistered(inName)) {
-        Q_ASSERT(false);
-        return false;
-    }
-    QVector<dynamic::QDemonPropertyDefinition> definitions;
-    quint32 theCurrentOffset = 0;
-    for (quint32 idx = 0, end = inProperties.size(); idx < end; ++idx) {
-        const dynamic::QDemonPropertyDeclaration &thePropDec = inProperties[idx];
-        quint32 propSize = dynamic::getSizeofShaderDataType(thePropDec.dataType);
-        definitions.push_back(dynamic::QDemonPropertyDefinition(thePropDec.name, thePropDec.dataType, theCurrentOffset, propSize));
-        theCurrentOffset += propSize;
-        theCurrentOffset = align(theCurrentOffset);
-    }
-    quint32 dataSectionSize = theCurrentOffset;
-    quint32 clsSize = align(sizeof(QDemonDynamicObjectClass));
-    quint32 defSize = align(sizeof(dynamic::QDemonPropertyDefinition) * inProperties.size());
-    quint32 defaultSize = dataSectionSize;
-    quint32 allocSize = clsSize + defSize + defaultSize;
-    quint8 *allocData = reinterpret_cast<quint8 *>(::malloc(allocSize));
-    quint8 *defData = allocData + clsSize;
-    quint8 *defaultData = defData + defSize;
-    dynamic::QDemonPropertyDefinition *defPtr = reinterpret_cast<dynamic::QDemonPropertyDefinition *>(defData);
-    if (defSize)
-        ::memcpy(defPtr, definitions.data(), defSize);
-    if (defaultSize)
-        memset(defaultData, 0, defaultSize);
-    QDemonRef<QDemonDynamicObjectClass> theClass(
-            new (allocData)
-                    QDemonDynamicObjectClass(inName, toDataView(defPtr, inProperties.size()), dataSectionSize, inBaseObjectSize, inGraphObjectType, defaultData));
-    m_classes.insert(inName, theClass);
-    return true;
-}
-
-bool QDemonDynamicObjectSystem::unregister(QString inName)
-{
-    if (!isRegistered(inName)) {
-        Q_ASSERT(false);
-        return false;
-    }
-    TStringClassMap::iterator iter = m_classes.find(inName);
-    if (iter != m_classes.end())
-        m_classes.erase(iter);
-    return true;
-}
-
-QDemonRef<QDemonDynamicObjectClass> QDemonDynamicObjectSystem::findClass(QString inName)
-{
-    TStringClassMap::iterator iter = m_classes.find(inName);
-    if (iter != m_classes.end())
-        return iter.value();
-    return nullptr;
-}
-
-QPair<const dynamic::QDemonPropertyDefinition *, QDemonRef<QDemonDynamicObjectClass>> QDemonDynamicObjectSystem::findProperty(QString inName, QString inPropName)
-{
-    QDemonRef<QDemonDynamicObjectClass> cls = findClass(inName);
-    if (cls) {
-        const dynamic::QDemonPropertyDefinition *def = cls->findDefinition(inPropName);
-        if (def)
-            return QPair<const dynamic::QDemonPropertyDefinition *, QDemonRef<QDemonDynamicObjectClass>>(def, cls);
-    }
-    return QPair<const dynamic::QDemonPropertyDefinition *, QDemonRef<QDemonDynamicObjectClass>>(nullptr, nullptr);
-}
-
-void QDemonDynamicObjectSystem::setPropertyDefaultValue(const QString &inName, const QString &inPropName, const QDemonByteView &inDefaultData)
-{
-    QPair<const dynamic::QDemonPropertyDefinition *, QDemonRef<QDemonDynamicObjectClass>> def = findProperty(inName, inPropName);
-    if (def.first && inDefaultData.size() >= qint32(def.first->byteSize)) {
-        ::memcpy(def.second->m_propertyDefaultData + def.first->offset, inDefaultData.begin(), def.first->byteSize);
-    } else {
-        Q_ASSERT(false);
-    }
-}
-
-void QDemonDynamicObjectSystem::setPropertyEnumNames(const QString &inName, const QString &inPropName, const QDemonDataView<QString> &inNames)
-{
-
-    QPair<const dynamic::QDemonPropertyDefinition *, QDemonRef<QDemonDynamicObjectClass>> def = findProperty(inName, inPropName);
-    dynamic::QDemonPropertyDefinition *theDefinitionPtr = const_cast<dynamic::QDemonPropertyDefinition *>(def.first);
-    if (theDefinitionPtr == nullptr) {
-        Q_ASSERT(false);
-        return;
-    }
-    if (theDefinitionPtr->enumValueNames.size()) {
-        ::free((void *)theDefinitionPtr->enumValueNames.begin());
-        theDefinitionPtr->enumValueNames = QDemonDataView<QString>();
-    }
-    theDefinitionPtr->isEnumProperty = true;
-    if (inNames.size()) {
-        // TODO:
-        QString *theNameValues = new QString[inName.size()];
-        ::memcpy(theNameValues, inNames.begin(), inNames.size() * sizeof(QString));
-        theDefinitionPtr->enumValueNames = QDemonDataView<QString>(theNameValues, inNames.size());
-    }
-}
-
-QDemonDataView<QString> QDemonDynamicObjectSystem::getPropertyEnumNames(const QString &inName, const QString &inPropName) const
-{
-    QPair<const dynamic::QDemonPropertyDefinition *, QDemonRef<QDemonDynamicObjectClass>>
-            def = const_cast<QDemonDynamicObjectSystem &>(*this).findProperty(inName, inPropName);
-    if (def.first)
-        return def.first->enumValueNames;
-    return QDemonDataView<QString>();
-}
-
-QDemonDataView<dynamic::QDemonPropertyDefinition> QDemonDynamicObjectSystem::getProperties(const QString &inName) const
-{
-    QMutexLocker locker(&m_propertyLoadMutex);
-    QDemonRef<QDemonDynamicObjectClass> cls = const_cast<QDemonDynamicObjectSystem &>(*this).findClass(inName);
-    if (cls)
-        return cls->m_propertyDefinitions;
-    return QDemonDataView<dynamic::QDemonPropertyDefinition>();
-}
-
-void QDemonDynamicObjectSystem::setPropertyTextureSettings(const QString &inName,
-                                                           const QString &inPropName,
-                                                           const QString &inPropPath,
-                                                           QDemonRenderTextureTypeValue inTexType,
-                                                           QDemonRenderTextureCoordOp inCoordOp,
-                                                           QDemonRenderTextureMagnifyingOp inMagFilterOp,
-                                                           QDemonRenderTextureMinifyingOp inMinFilterOp)
-{
-    QPair<const dynamic::QDemonPropertyDefinition *, QDemonRef<QDemonDynamicObjectClass>> def = findProperty(inName, inPropName);
-    dynamic::QDemonPropertyDefinition *theDefinitionPtr = const_cast<dynamic::QDemonPropertyDefinition *>(def.first);
-    if (theDefinitionPtr == nullptr) {
-        Q_ASSERT(false);
-        return;
-    }
-    QByteArray *data = new QByteArray(inPropPath.toLatin1());
-    theDefinitionPtr->imagePath = data->constData(); // inPropPath.toLatin1().constData(); // TODO: Lifetime
-    theDefinitionPtr->texUsageType = inTexType;
-    theDefinitionPtr->coordOp = inCoordOp;
-    theDefinitionPtr->magFilterOp = inMagFilterOp;
-    theDefinitionPtr->minFilterOp = inMinFilterOp;
-}
-
-QDemonDynamicObjectClass *QDemonDynamicObjectSystem::dynamicObjectClass(const QString &inName)
-{
-    // TODO: Should probably shared pointer
-    return findClass(inName).data();
-}
-
 void QDemonDynamicObjectSystem::setRenderCommands(const QString &inClassName, const QDemonDataView<dynamic::QDemonCommand *> &inCommands)
 {
-    QDemonRef<QDemonDynamicObjectClass> theClass = const_cast<QDemonDynamicObjectSystem &>(*this).findClass(inClassName);
-    if (theClass == nullptr) {
-        Q_ASSERT(false);
-        return;
-    }
-    theClass->releaseCommands();
-    quint32 commandAllocationSize = 0;
-    for (quint32 idx = 0, end = inCommands.size(); idx < end; ++idx) {
-        quint32 commandSize = align(dynamic::QDemonCommand::getSizeofCommand(*inCommands[idx]));
-        commandAllocationSize += commandSize;
-    }
-    quint32 commandPtrSize = inCommands.size() * sizeof(dynamic::QDemonCommand *);
-    quint32 totalAllocationSize = align8(commandAllocationSize) + commandPtrSize;
-    quint8 *theCommandDataBegin = (quint8 *)::malloc(totalAllocationSize);
-    quint8 *theCurrentCommandData(theCommandDataBegin);
-    dynamic::QDemonCommand **theCommandPtrBegin = reinterpret_cast<dynamic::QDemonCommand **>(
-            theCommandDataBegin + align8(commandAllocationSize));
-    dynamic::QDemonCommand **theCurrentCommandPtr = theCommandPtrBegin;
-    memset(theCommandDataBegin, 0, totalAllocationSize);
-
-    theClass->m_requiresDepthTexture = false;
-    for (quint32 idx = 0, end = inCommands.size(); idx < end; ++idx) {
-        dynamic::QDemonCommand &theCommand(*inCommands[idx]);
-        quint32 theCommandSize = dynamic::QDemonCommand::getSizeofCommand(theCommand);
-        dynamic::QDemonCommand::copyConstructCommand(theCurrentCommandData, theCommand);
-        if (theCommand.m_type == dynamic::CommandType::ApplyDepthValue)
-            theClass->m_requiresDepthTexture = true;
-        if (theCommand.m_type == dynamic::CommandType::BindTarget) {
-            dynamic::QDemonBindTarget *bt = reinterpret_cast<dynamic::QDemonBindTarget *>(&theCommand);
-            theClass->m_outputFormat = bt->m_outputFormat;
-        }
-
-        *theCurrentCommandPtr = reinterpret_cast<dynamic::QDemonCommand *>(theCurrentCommandData);
-        ++theCurrentCommandPtr;
-        theCurrentCommandData += align(theCommandSize);
-    }
-    Q_ASSERT(theCurrentCommandData - theCommandDataBegin == (int)commandAllocationSize);
-    Q_ASSERT((quint8 *)theCurrentCommandPtr - theCommandDataBegin == (int)totalAllocationSize);
-    theClass->m_renderCommands = QDemonDataView<dynamic::QDemonCommand *>(theCommandPtrBegin, inCommands.size());
+    Q_UNUSED(inClassName)
+    Q_UNUSED(inCommands)
+//    QDemonRef<QDemonDynamicObjectClass> theClass = nullptr;// = const_cast<QDemonDynamicObjectSystem &>(*this).findClass(inClassName);
+//    if (theClass == nullptr) {
+//        Q_ASSERT(false);
+//        return;
+//    }
+//    theClass->releaseCommands();
+//    quint32 commandAllocationSize = 0;
+//    for (quint32 idx = 0, end = inCommands.size(); idx < end; ++idx) {
+//        quint32 commandSize = align(dynamic::QDemonCommand::getSizeofCommand(*inCommands[idx]));
+//        commandAllocationSize += commandSize;
+//    }
+//    quint32 commandPtrSize = inCommands.size() * sizeof(dynamic::QDemonCommand *);
+//    quint32 totalAllocationSize = align8(commandAllocationSize) + commandPtrSize;
+//    quint8 *theCommandDataBegin = (quint8 *)::malloc(totalAllocationSize);
+//    quint8 *theCurrentCommandData(theCommandDataBegin);
+//    dynamic::QDemonCommand **theCommandPtrBegin = reinterpret_cast<dynamic::QDemonCommand **>(
+//            theCommandDataBegin + align8(commandAllocationSize));
+//    dynamic::QDemonCommand **theCurrentCommandPtr = theCommandPtrBegin;
+//    memset(theCommandDataBegin, 0, totalAllocationSize);
+
+//    theClass->m_requiresDepthTexture = false;
+//    for (quint32 idx = 0, end = inCommands.size(); idx < end; ++idx) {
+//        dynamic::QDemonCommand &theCommand(*inCommands[idx]);
+//        quint32 theCommandSize = dynamic::QDemonCommand::getSizeofCommand(theCommand);
+//        dynamic::QDemonCommand::copyConstructCommand(theCurrentCommandData, theCommand);
+//        if (theCommand.m_type == dynamic::CommandType::ApplyDepthValue)
+//            theClass->m_requiresDepthTexture = true;
+//        if (theCommand.m_type == dynamic::CommandType::BindTarget) {
+//            dynamic::QDemonBindTarget *bt = reinterpret_cast<dynamic::QDemonBindTarget *>(&theCommand);
+//            theClass->m_outputFormat = bt->m_outputFormat;
+//        }
+
+//        *theCurrentCommandPtr = reinterpret_cast<dynamic::QDemonCommand *>(theCurrentCommandData);
+//        ++theCurrentCommandPtr;
+//        theCurrentCommandData += align(theCommandSize);
+//    }
+//    Q_ASSERT(theCurrentCommandData - theCommandDataBegin == (int)commandAllocationSize);
+//    Q_ASSERT((quint8 *)theCurrentCommandPtr - theCommandDataBegin == (int)totalAllocationSize);
+//    theClass->m_renderCommands = QDemonDataView<dynamic::QDemonCommand *>(theCommandPtrBegin, inCommands.size());
 }
 
 QDemonDataView<dynamic::QDemonCommand *> QDemonDynamicObjectSystem::getRenderCommands(const QString &inClassName) const
 {
-    QDemonRef<QDemonDynamicObjectClass> cls = const_cast<QDemonDynamicObjectSystem &>(*this).findClass(inClassName);
-    if (cls)
-        return cls->m_renderCommands;
+//    QDemonRef<QDemonDynamicObjectClass> cls = nullptr; //const_cast<QDemonDynamicObjectSystem &>(*this).findClass(inClassName);
+//    if (cls)
+//        return cls->m_renderCommands;
     return QDemonDataView<dynamic::QDemonCommand *>();
 }
 
-QDemonRenderDynamicGraphObject *QDemonDynamicObjectSystem::createInstance(const QString &inClassName)
-{
-    QDemonRef<QDemonDynamicObjectClass> theClass = findClass(inClassName);
-    if (!theClass) {
-        Q_ASSERT(false);
-        return nullptr;
-    }
-    quint32 totalObjectSize = theClass->m_baseObjectSize + theClass->m_propertySectionByteSize;
-    QDemonRenderDynamicGraphObject *retval = reinterpret_cast<QDemonRenderDynamicGraphObject *>(::malloc(totalObjectSize));
-    new (retval) QDemonRenderDynamicGraphObject(theClass->m_graphObjectType,
-                                                inClassName,
-                                                theClass->m_propertySectionByteSize,
-                                                theClass->m_baseObjectSize);
-    ::memcpy(retval->getDataSectionBegin(), theClass->m_propertyDefaultData, theClass->m_propertySectionByteSize);
-    return retval;
-}
-
 void QDemonDynamicObjectSystem::setShaderData(const QString &inPath,
                                               const QByteArray &inData,
                                               const QByteArray &inShaderType,
diff --git a/src/runtimerender/qdemonrenderdynamicobjectsystem.h b/src/runtimerender/qdemonrenderdynamicobjectsystem.h
index 2b27dfb7bbf03b47103c1a1bd91ffbd64a5a706d..3f39f14854f3897e85596c22c7e1ccc91c480b94 100644
--- a/src/runtimerender/qdemonrenderdynamicobjectsystem.h
+++ b/src/runtimerender/qdemonrenderdynamicobjectsystem.h
@@ -170,61 +170,18 @@ struct QDemonDynamicObjectShaderInfo
     }
 };
 
-struct QDemonDynamicObjectClass
-{
-    QAtomicInt ref;
-    QString m_id;
-    QDemonDataView<dynamic::QDemonPropertyDefinition> m_propertyDefinitions;
-    quint32 m_propertySectionByteSize;
-    quint32 m_baseObjectSize;
-    QDemonRenderGraphObject::Type m_graphObjectType;
-    quint8 *m_propertyDefaultData;
-    QDemonDataView<dynamic::QDemonCommand *> m_renderCommands;
-    bool m_requiresDepthTexture;
-    bool m_requiresCompilation;
-    QDemonRenderTextureFormat m_outputFormat;
-
-    QDemonDynamicObjectClass(QString id,
-                             QDemonDataView<dynamic::QDemonPropertyDefinition> definitions,
-                             quint32 propertySectionByteSize,
-                             quint32 baseObjectSize,
-                             QDemonRenderGraphObject::Type objectType,
-                             quint8 *propDefaultData,
-                             bool inRequiresDepthTexture = false,
-                             QDemonRenderTextureFormat inOutputFormat = QDemonRenderTextureFormat::RGBA8);
-
-    ~QDemonDynamicObjectClass();
-
-    void releaseCommands();
-
-    QString getId() const;
-    QDemonDataView<dynamic::QDemonPropertyDefinition> getProperties() const;
-    quint32 getPropertySectionByteSize() const;
-    const quint8 *getDefaultValueBuffer() const;
-    quint32 getBaseObjectSize() const;
-    QDemonRenderGraphObject::Type graphObjectType() const;
-    const dynamic::QDemonPropertyDefinition *findDefinition(QString &str) const;
-    const dynamic::QDemonPropertyDefinition *findPropertyByName(QString inName) const;
-    QDemonDataView<dynamic::QDemonCommand *> getRenderCommands() const;
-    bool requiresDepthTexture() const;
-    void setRequiresDepthTexture(bool inVal);
-    bool requiresCompilation() const;
-    void setRequiresCompilation(bool inVal);
-    QDemonRenderTextureFormat getOutputTextureFormat() const;
-};
-
 typedef QPair<QDemonRef<QDemonRenderShaderProgram>, dynamic::QDemonDynamicShaderProgramFlags> TShaderAndFlags;
 
 struct QDemonDynamicObjectSystem
 {
-    typedef QHash<QString, QDemonRef<QDemonDynamicObjectClass>> TStringClassMap;
+//    typedef QHash<QString, QDemonRef<QDemonDynamicObjectClass>> TStringClassMap;
     typedef QHash<QString, QByteArray> TPathDataMap;
     typedef QHash<QString, QDemonDynamicObjectShaderInfo> TShaderInfoMap;
     typedef QSet<QString> TPathSet;
     typedef QHash<dynamic::QDemonDynamicShaderMapKey, TShaderAndFlags> TShaderMap;
 
     QDemonRenderContextInterface *m_context;
-    TStringClassMap m_classes;
+//    TStringClassMap m_classes;
     TPathDataMap m_expandedFiles;
     TShaderMap m_shaderMap;
     TShaderInfoMap m_shaderInfoMap;
@@ -242,44 +199,10 @@ struct QDemonDynamicObjectSystem
 
     ~QDemonDynamicObjectSystem();
 
-    bool isRegistered(QString inStr);
-
-    bool doRegister(QString inName,
-                    QDemonDataView<dynamic::QDemonPropertyDeclaration> inProperties,
-                    quint32 inBaseObjectSize,
-                    QDemonRenderGraphObject::Type inGraphObjectType);
-
-    bool unregister(QString inName);
-
-    QDemonRef<QDemonDynamicObjectClass> findClass(QString inName);
-
-    QPair<const dynamic::QDemonPropertyDefinition *, QDemonRef<QDemonDynamicObjectClass>> findProperty(QString inName, QString inPropName);
-
-    void setPropertyDefaultValue(const QString &inName, const QString &inPropName, const QDemonByteView &inDefaultData);
-
-    void setPropertyEnumNames(const QString &inName, const QString &inPropName, const QDemonDataView<QString> &inNames);
-
-    QDemonDataView<QString> getPropertyEnumNames(const QString &inName, const QString &inPropName) const;
-
-    // Called during loading which is pretty heavily multithreaded.
-    QDemonDataView<dynamic::QDemonPropertyDefinition> getProperties(const QString &inName) const;
-
-    void setPropertyTextureSettings(const QString &inName,
-                                    const QString &inPropName,
-                                    const QString &inPropPath,
-                                    QDemonRenderTextureTypeValue inTexType,
-                                    QDemonRenderTextureCoordOp inCoordOp,
-                                    QDemonRenderTextureMagnifyingOp inMagFilterOp,
-                                    QDemonRenderTextureMinifyingOp inMinFilterOp);
-
-    QDemonDynamicObjectClass *dynamicObjectClass(const QString &inName);
-
     void setRenderCommands(const QString &inClassName, const QDemonDataView<dynamic::QDemonCommand *> &inCommands);
 
     QDemonDataView<dynamic::QDemonCommand *> getRenderCommands(const QString &inClassName) const;
 
-    QDemonRenderDynamicGraphObject *createInstance(const QString &inClassName);
-
     void setShaderData(const QString &inPath,
                        const QByteArray &inData,
                        const QByteArray &inShaderType,
diff --git a/src/runtimerender/qdemonrenderdynamicobjectsystemcommands.h b/src/runtimerender/qdemonrenderdynamicobjectsystemcommands.h
index c0af800f9cabbff03f51a4ecb98a27cf264c937e..89c2d997ed931441157fd4e3f8a51192fb3a3c23 100644
--- a/src/runtimerender/qdemonrenderdynamicobjectsystemcommands.h
+++ b/src/runtimerender/qdemonrenderdynamicobjectsystemcommands.h
@@ -291,12 +291,12 @@ struct QDemonApplyBufferValue : public QDemonCommand
 {
     // If no buffer name is given then the special buffer [source]
     // is assumed.
-    QString m_bufferName;
+    QByteArray m_bufferName;
     // If no param name is given, the buffer is bound to the
     // input texture parameter (texture0).
-    QString m_paramName;
+    QByteArray m_paramName;
 
-    QDemonApplyBufferValue(QString bufferName, QString shaderParam)
+    QDemonApplyBufferValue(const QByteArray &bufferName, const QByteArray &shaderParam)
         : QDemonCommand(CommandType::ApplyBufferValue), m_bufferName(bufferName), m_paramName(shaderParam)
     {
     }
@@ -407,12 +407,12 @@ struct QDemonApplyBlitFramebuffer : public QDemonCommand
 {
     // If no buffer name is given then the special buffer [source]
     // is assumed. Which is the default render target
-    QString m_sourceBufferName;
+    QByteArray m_sourceBufferName;
     // If no buffer name is given then the special buffer [dest]
     // is assumed. Which is the default render target
-    QString m_destBufferName;
+    QByteArray m_destBufferName;
 
-    QDemonApplyBlitFramebuffer(QString inSourceBufferName, QString inDestBufferName)
+    QDemonApplyBlitFramebuffer(const QByteArray &inSourceBufferName, const QByteArray &inDestBufferName)
         : QDemonCommand(CommandType::ApplyBlitFramebuffer), m_sourceBufferName(inSourceBufferName), m_destBufferName(inDestBufferName)
     {
     }
diff --git a/src/runtimerender/qdemonrendereffectsystem.cpp b/src/runtimerender/qdemonrendereffectsystem.cpp
index 57cbb87f3a7483b381386fae85e95accfed9e6a9..c4c48bb6b8f64963f3ec4dfbdc844fe49b73ee4d 100644
--- a/src/runtimerender/qdemonrendereffectsystem.cpp
+++ b/src/runtimerender/qdemonrendereffectsystem.cpp
@@ -443,8 +443,8 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
     QDemonEffectContext &getEffectContext(QDemonRenderEffect &inEffect)
     {
         if (inEffect.m_context == nullptr) {
-            inEffect.m_context = QDemonRef<QDemonEffectContext>(new QDemonEffectContext(inEffect.className, m_context, m_resourceManager));
-            m_contexts.push_back(inEffect.m_context);
+//            inEffect.m_context = QDemonRef<QDemonEffectContext>(new QDemonEffectContext(inEffect.className, m_context, m_resourceManager));
+//            m_contexts.push_back(inEffect.m_context);
         }
         return *inEffect.m_context;
     }
@@ -471,129 +471,132 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
     }
 
     // Registers an effect that runs via a single GLSL file.
-    bool registerGLSLEffect(QString inName, const char *inPathToEffect, QDemonDataView<QDemonPropertyDeclaration> inProperties) override
-    {
-        if (isEffectRegistered(inName))
-            return false;
-
-        m_context->dynamicObjectSystem()->doRegister(inName, inProperties, sizeof(QDemonRenderEffect), QDemonRenderGraphObject::Type::Effect);
-        QDemonDynamicObjectClass &theClass = *m_context->dynamicObjectSystem()->dynamicObjectClass(inName);
-
-        QDemonRef<QDemonEffectClass> theEffect(new QDemonEffectClass(theClass));
-        m_effectClasses.insert(inName, theEffect);
-
-        // Setup the commands required to run this effect
-        //        StaticAssert<(sizeof(SBindShader) % 4 == 0)>::valid_expression();
-        //        StaticAssert<(sizeof(SApplyInstanceValue) % 4 == 0)>::valid_expression();
-        //        StaticAssert<(sizeof(SRender) % 4 == 0)>::valid_expression();
-
-        quint32 commandAllocationSize = sizeof(QDemonBindTarget);
-        commandAllocationSize += sizeof(QDemonBindShader);
-        commandAllocationSize += sizeof(QDemonApplyInstanceValue) * inProperties.size();
-        commandAllocationSize += sizeof(QDemonRender);
-
-        quint32 commandCount = 3 + inProperties.size();
-        quint32 commandPtrAllocationSize = commandCount * sizeof(QDemonCommand *);
-        quint32 allocationSize = align8(commandAllocationSize) + commandPtrAllocationSize;
-        quint8 *startBuffer = (quint8 *)::malloc(allocationSize);
-        quint8 *dataBuffer = startBuffer;
-        // Setup the command buffer such that the ptrs to the commands and the commands themselves
-        // are
-        // all in the same block of memory.  This enables quicker iteration (trivially quicker, most
-        // likely)
-        // but it also enables simpler memory management (single free).
-        // Furthermore, for a single glsl file the effect properties map precisely into the
-        // glsl file itself.
-        QDemonCommand **theFirstCommandPtr = (reinterpret_cast<QDemonCommand **>(dataBuffer + align8(commandAllocationSize)));
-        QDemonCommand **theCommandPtr = theFirstCommandPtr;
-        memset(dataBuffer, 0, commandAllocationSize);
-
-        new (dataBuffer) QDemonBindTarget();
-        *theCommandPtr = (QDemonCommand *)dataBuffer;
-        ++theCommandPtr;
-        dataBuffer += sizeof(QDemonBindTarget);
-
-        new (dataBuffer) QDemonBindShader(QString::fromLocal8Bit(inPathToEffect));
-        *theCommandPtr = (QDemonCommand *)dataBuffer;
-        ++theCommandPtr;
-        dataBuffer += sizeof(QDemonBindShader);
-
-        for (quint32 idx = 0, end = inProperties.size(); idx < end; ++idx) {
-            const QDemonPropertyDefinition &theDefinition(theEffect->dynamicClass->getProperties()[idx]);
-            new (dataBuffer) QDemonApplyInstanceValue(theDefinition.name, theDefinition.dataType, theDefinition.offset);
-            *theCommandPtr = (QDemonCommand *)dataBuffer;
-            ++theCommandPtr;
-            dataBuffer += sizeof(QDemonApplyInstanceValue);
-        }
-        new (dataBuffer) QDemonRender(false);
-        *theCommandPtr = (QDemonCommand *)dataBuffer;
-        ++theCommandPtr;
-        dataBuffer += sizeof(QDemonRender);
-        // Ensure we end up *exactly* where we expected to.
-        Q_ASSERT(dataBuffer == startBuffer + commandAllocationSize);
-        Q_ASSERT(theCommandPtr - theFirstCommandPtr == (int)inProperties.size() + 3);
-        m_context->dynamicObjectSystem()->setRenderCommands(inName, QDemonDataView<QDemonCommand *>(theFirstCommandPtr, commandCount));
-        ::free(startBuffer);
-        return true;
+    bool registerGLSLEffect(QString /*inName*/, const char */*inPathToEffect*/, QDemonDataView<QDemonPropertyDeclaration> /*inProperties*/) override
+    {
+//        if (isEffectRegistered(inName))
+//            return false;
+
+////        m_context->dynamicObjectSystem()->doRegister(inName, inProperties, sizeof(QDemonRenderEffect), QDemonRenderGraphObject::Type::Effect);
+////        QDemonDynamicObjectClass &theClass = *m_context->dynamicObjectSystem()->dynamicObjectClass(inName);
+
+//        QDemonRef<QDemonEffectClass> theEffect(new QDemonEffectClass(theClass));
+//        m_effectClasses.insert(inName, theEffect);
+
+//        // Setup the commands required to run this effect
+//        //        StaticAssert<(sizeof(SBindShader) % 4 == 0)>::valid_expression();
+//        //        StaticAssert<(sizeof(SApplyInstanceValue) % 4 == 0)>::valid_expression();
+//        //        StaticAssert<(sizeof(SRender) % 4 == 0)>::valid_expression();
+
+//        quint32 commandAllocationSize = sizeof(QDemonBindTarget);
+//        commandAllocationSize += sizeof(QDemonBindShader);
+//        commandAllocationSize += sizeof(QDemonApplyInstanceValue) * inProperties.size();
+//        commandAllocationSize += sizeof(QDemonRender);
+
+//        quint32 commandCount = 3 + inProperties.size();
+//        quint32 commandPtrAllocationSize = commandCount * sizeof(QDemonCommand *);
+//        quint32 allocationSize = align8(commandAllocationSize) + commandPtrAllocationSize;
+//        quint8 *startBuffer = (quint8 *)::malloc(allocationSize);
+//        quint8 *dataBuffer = startBuffer;
+//        // Setup the command buffer such that the ptrs to the commands and the commands themselves
+//        // are
+//        // all in the same block of memory.  This enables quicker iteration (trivially quicker, most
+//        // likely)
+//        // but it also enables simpler memory management (single free).
+//        // Furthermore, for a single glsl file the effect properties map precisely into the
+//        // glsl file itself.
+//        QDemonCommand **theFirstCommandPtr = (reinterpret_cast<QDemonCommand **>(dataBuffer + align8(commandAllocationSize)));
+//        QDemonCommand **theCommandPtr = theFirstCommandPtr;
+//        memset(dataBuffer, 0, commandAllocationSize);
+
+//        new (dataBuffer) QDemonBindTarget();
+//        *theCommandPtr = (QDemonCommand *)dataBuffer;
+//        ++theCommandPtr;
+//        dataBuffer += sizeof(QDemonBindTarget);
+
+//        new (dataBuffer) QDemonBindShader(QString::fromLocal8Bit(inPathToEffect));
+//        *theCommandPtr = (QDemonCommand *)dataBuffer;
+//        ++theCommandPtr;
+//        dataBuffer += sizeof(QDemonBindShader);
+
+//        for (quint32 idx = 0, end = inProperties.size(); idx < end; ++idx) {
+//            const QDemonPropertyDefinition &theDefinition(theEffect->dynamicClass->getProperties()[idx]);
+//            new (dataBuffer) QDemonApplyInstanceValue(theDefinition.name, theDefinition.dataType, theDefinition.offset);
+//            *theCommandPtr = (QDemonCommand *)dataBuffer;
+//            ++theCommandPtr;
+//            dataBuffer += sizeof(QDemonApplyInstanceValue);
+//        }
+//        new (dataBuffer) QDemonRender(false);
+//        *theCommandPtr = (QDemonCommand *)dataBuffer;
+//        ++theCommandPtr;
+//        dataBuffer += sizeof(QDemonRender);
+//        // Ensure we end up *exactly* where we expected to.
+//        Q_ASSERT(dataBuffer == startBuffer + commandAllocationSize);
+//        Q_ASSERT(theCommandPtr - theFirstCommandPtr == (int)inProperties.size() + 3);
+//        m_context->dynamicObjectSystem()->setRenderCommands(inName, QDemonDataView<QDemonCommand *>(theFirstCommandPtr, commandCount));
+//        ::free(startBuffer);
+//        return true;
+        return false;
     }
 
     void setEffectPropertyDefaultValue(QString inName, QString inPropName, QDemonByteView inDefaultData) override
     {
-        m_context->dynamicObjectSystem()->setPropertyDefaultValue(inName, inPropName, inDefaultData);
+//        m_context->dynamicObjectSystem()->setPropertyDefaultValue(inName, inPropName, inDefaultData);
     }
 
     void setEffectPropertyEnumNames(QString inName, QString inPropName, QDemonDataView<QString> inNames) override
     {
-        m_context->dynamicObjectSystem()->setPropertyEnumNames(inName, inPropName, inNames);
+//        m_context->dynamicObjectSystem()->setPropertyEnumNames(inName, inPropName, inNames);
     }
 
     bool registerEffect(QString inName, QDemonDataView<QDemonPropertyDeclaration> inProperties) override
     {
-        if (isEffectRegistered(inName))
-            return false;
-        m_context->dynamicObjectSystem()->doRegister(inName, inProperties, sizeof(QDemonRenderEffect), QDemonRenderGraphObject::Type::Effect);
-        auto theClass = m_context->dynamicObjectSystem()->dynamicObjectClass(inName);
-        QDemonRef<QDemonEffectClass> theEffect(new QDemonEffectClass(*theClass));
-        m_effectClasses.insert(inName, theEffect);
-        return true;
+//        if (isEffectRegistered(inName))
+//            return false;
+//        m_context->dynamicObjectSystem()->doRegister(inName, inProperties, sizeof(QDemonRenderEffect), QDemonRenderGraphObject::Type::Effect);
+//        auto theClass = m_context->dynamicObjectSystem()->dynamicObjectClass(inName);
+//        QDemonRef<QDemonEffectClass> theEffect(new QDemonEffectClass(*theClass));
+//        m_effectClasses.insert(inName, theEffect);
+//        return true;
+        return false;
     }
 
     bool unregisterEffect(QString inName) override
     {
-        if (!isEffectRegistered(inName))
-            return false;
+//        if (!isEffectRegistered(inName))
+//            return false;
 
-        m_context->dynamicObjectSystem()->unregister(inName);
+//        m_context->dynamicObjectSystem()->unregister(inName);
 
-        TEffectClassMap::iterator iter = m_effectClasses.find(inName);
-        if (iter != m_effectClasses.end())
-            m_effectClasses.erase(iter);
+//        TEffectClassMap::iterator iter = m_effectClasses.find(inName);
+//        if (iter != m_effectClasses.end())
+//            m_effectClasses.erase(iter);
 
-        for (quint32 idx = 0, end = m_contexts.size(); idx < end; ++idx) {
-            if (m_contexts[idx]->m_className == inName)
-                releaseEffectContext(m_contexts[idx].data());
-        }
-        return true;
+//        for (quint32 idx = 0, end = m_contexts.size(); idx < end; ++idx) {
+//            if (m_contexts[idx]->m_className == inName)
+//                releaseEffectContext(m_contexts[idx].data());
+//        }
+//        return true;
+        return false;
     }
 
     QDemonDataView<QString> getEffectPropertyEnumNames(QString inName, QString inPropName) const override
     {
-        const auto theClass = getEffectClass(inName);
-        if (theClass == nullptr) {
-            Q_ASSERT(false);
-            QDemonDataView<QString>();
-        }
-        const QDemonPropertyDefinition *theDefinitionPtr = theClass->dynamicClass->findPropertyByName(inPropName);
-        if (theDefinitionPtr)
-            return theDefinitionPtr->enumValueNames;
+//        const auto theClass = getEffectClass(inName);
+//        if (theClass == nullptr) {
+//            Q_ASSERT(false);
+//            QDemonDataView<QString>();
+//        }
+//        const QDemonPropertyDefinition *theDefinitionPtr = theClass->dynamicClass->findPropertyByName(inPropName);
+//        if (theDefinitionPtr)
+//            return theDefinitionPtr->enumValueNames;
         return QDemonDataView<QString>();
     }
 
     QDemonDataView<QDemonPropertyDefinition> getEffectProperties(QString inEffectName) const override
     {
-        const auto theClass = getEffectClass(inEffectName);
-        if (theClass)
-            return theClass->dynamicClass->getProperties();
+//        const auto theClass = getEffectClass(inEffectName);
+//        if (theClass)
+//            return theClass->dynamicClass->getProperties();
         return QDemonDataView<QDemonPropertyDefinition>();
     }
 
@@ -605,58 +608,60 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
                                           QDemonRenderTextureMagnifyingOp inMagFilterOp,
                                           QDemonRenderTextureMinifyingOp inMinFilterOp) override
     {
-        m_context->dynamicObjectSystem()
-                ->setPropertyTextureSettings(inName, inPropName, inPropPath, inTexType, inCoordOp, inMagFilterOp, inMinFilterOp);
+//        m_context->dynamicObjectSystem()
+//                ->setPropertyTextureSettings(inName, inPropName, inPropPath, inTexType, inCoordOp, inMagFilterOp, inMinFilterOp);
     }
 
     void setEffectRequiresDepthTexture(QString inEffectName, bool inValue) override
     {
-        auto theClass = getEffectClass(inEffectName);
-        if (theClass == nullptr) {
-            Q_ASSERT(false);
-            return;
-        }
-        theClass->dynamicClass->setRequiresDepthTexture(inValue);
+//        auto theClass = getEffectClass(inEffectName);
+//        if (theClass == nullptr) {
+//            Q_ASSERT(false);
+//            return;
+//        }
+//        theClass->dynamicClass->setRequiresDepthTexture(inValue);
     }
 
     bool doesEffectRequireDepthTexture(QString inEffectName) const override
     {
-        const auto theClass = getEffectClass(inEffectName);
-        if (theClass == nullptr) {
-            Q_ASSERT(false);
-            return false;
-        }
-        return theClass->dynamicClass->requiresDepthTexture();
+        //        const auto theClass = getEffectClass(inEffectName);
+        //        if (theClass == nullptr) {
+        //            Q_ASSERT(false);
+        //            return false;
+        //        }
+        //        return theClass->dynamicClass->requiresDepthTexture();
+        return false;
     }
 
     void setEffectRequiresCompilation(QString inEffectName, bool inValue) override
     {
-        auto theClass = getEffectClass(inEffectName);
-        if (theClass == nullptr) {
-            Q_ASSERT(false);
-            return;
-        }
-        theClass->dynamicClass->setRequiresCompilation(inValue);
+//        auto theClass = getEffectClass(inEffectName);
+//        if (theClass == nullptr) {
+//            Q_ASSERT(false);
+//            return;
+//        }
+//        theClass->dynamicClass->setRequiresCompilation(inValue);
     }
 
     bool doesEffectRequireCompilation(QString inEffectName) const override
     {
-        const auto theClass = getEffectClass(inEffectName);
-        if (theClass == nullptr) {
-            Q_ASSERT(false);
-            return false;
-        }
-        return theClass->dynamicClass->requiresCompilation();
+        //        const auto theClass = getEffectClass(inEffectName);
+        //        if (theClass == nullptr) {
+        //            Q_ASSERT(false);
+        //            return false;
+        //        }
+        //        return theClass->dynamicClass->requiresCompilation();
+        return false;
     }
 
     void setEffectCommands(QString inEffectName, QDemonDataView<dynamic::QDemonCommand *> inCommands) override
     {
-        m_context->dynamicObjectSystem()->setRenderCommands(inEffectName, inCommands);
+//        m_context->dynamicObjectSystem()->setRenderCommands(inEffectName, inCommands);
     }
 
     QDemonDataView<dynamic::QDemonCommand *> getEffectCommands(QString inEffectName) const override
     {
-        return m_context->dynamicObjectSystem()->getRenderCommands(inEffectName);
+        return QDemonDataView<dynamic::QDemonCommand *>();/*m_context->dynamicObjectSystem()->getRenderCommands(inEffectName);*/
     }
 
     QDemonRenderEffect *createEffectInstance(QString inEffectName) override
@@ -666,10 +671,11 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
             return nullptr;
         //        StaticAssert<(sizeof(SEffect) % 4 == 0)>::valid_expression();
 
-        QDemonRenderEffect *theEffect = static_cast<QDemonRenderEffect *>(
-                m_context->dynamicObjectSystem()->createInstance(inEffectName));
-        theEffect->initialize();
-        return theEffect;
+//        QDemonRenderEffect *theEffect = static_cast<QDemonRenderEffect *>(
+//                m_context->dynamicObjectSystem()->createInstance(inEffectName));
+//        theEffect->initialize();
+//        return theEffect;
+        return nullptr;
     }
 
     void allocateBuffer(QDemonRenderEffect &inEffect,
@@ -852,7 +858,7 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
         if (theBuffer == nullptr) {
             qCCritical(INVALID_OPERATION,
                        "Effect %s: Failed to find buffer %s for bind",
-                       inEffect.className.toLatin1().constData(),
+                       inEffect.className,
                        inCommand.m_bufferName.toLatin1().constData());
             QString errorMsg = QObject::tr("Failed to compile \"%1\" effect.\nConsider"
                                            " removing it from the presentation.")
@@ -873,39 +879,40 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
         return theBuffer;
     }
 
-    QDemonRef<QDemonEffectShader> bindShader(QString &inEffectId, const QDemonBindShader &inCommand)
-    {
-        auto theClass = getEffectClass(inEffectId);
-        if (!theClass) {
-            Q_ASSERT(false);
-            return nullptr;
-        }
-
-        bool forceCompilation = theClass->dynamicClass->requiresCompilation();
-
-        auto key = TStrStrPair(inCommand.m_shaderPath, inCommand.m_shaderDefine);
-        auto theInsertResult = m_shaderMap.find(key);
-        const bool found = (theInsertResult != m_shaderMap.end());
-        if (!found)
-            theInsertResult = m_shaderMap.insert(key, QDemonRef<QDemonEffectShader>());
-
-        if (found || forceCompilation) {
-            auto theProgram = m_context->dynamicObjectSystem()
-                                      ->getShaderProgram(inCommand.m_shaderPath,
-                                                         inCommand.m_shaderDefine,
-                                                         TShaderFeatureSet(),
-                                                         QDemonDynamicShaderProgramFlags(),
-                                                         forceCompilation)
-                                      .first;
-            if (theProgram)
-                theInsertResult.value() = QDemonRef<QDemonEffectShader>(new QDemonEffectShader(theProgram));
-        }
-        if (theInsertResult.value()) {
-            auto theContext(m_context->renderContext());
-            theContext->setActiveShader(theInsertResult.value()->m_shader);
-        }
-
-        return theInsertResult.value();
+    QDemonRef<QDemonEffectShader> bindShader(const QString &inEffectId, const QDemonBindShader &inCommand)
+    {
+//        auto theClass = getEffectClass(inEffectId);
+//        if (!theClass) {
+//            Q_ASSERT(false);
+//            return nullptr;
+//        }
+
+//        bool forceCompilation = theClass->dynamicClass->requiresCompilation();
+
+//        auto key = TStrStrPair(inCommand.m_shaderPath, inCommand.m_shaderDefine);
+//        auto theInsertResult = m_shaderMap.find(key);
+//        const bool found = (theInsertResult != m_shaderMap.end());
+//        if (!found)
+//            theInsertResult = m_shaderMap.insert(key, QDemonRef<QDemonEffectShader>());
+
+//        if (found || forceCompilation) {
+//            auto theProgram = m_context->dynamicObjectSystem()
+//                                      ->getShaderProgram(inCommand.m_shaderPath,
+//                                                         inCommand.m_shaderDefine,
+//                                                         TShaderFeatureSet(),
+//                                                         QDemonDynamicShaderProgramFlags(),
+//                                                         forceCompilation)
+//                                      .first;
+//            if (theProgram)
+//                theInsertResult.value() = QDemonRef<QDemonEffectShader>(new QDemonEffectShader(theProgram));
+//        }
+//        if (theInsertResult.value()) {
+//            auto theContext(m_context->renderContext());
+//            theContext->setActiveShader(theInsertResult.value()->m_shader);
+//        }
+
+//        return theInsertResult.value();
+        return nullptr;
     }
 
     void doApplyInstanceValue(QDemonRenderEffect *inEffect,
@@ -1054,29 +1061,29 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
                             const QDemonApplyInstanceValue &inCommand)
     {
         // sanity check
-        if (!inCommand.m_propertyName.isEmpty()) {
-            bool canGetData = inCommand.m_valueOffset + getSizeofShaderDataType(inCommand.m_valueType) <= inEffect->dataSectionByteSize;
-            if (canGetData == false) {
-                Q_ASSERT(false);
-                return;
-            }
-            quint8 *dataPtr = inEffect->getDataSectionBegin() + inCommand.m_valueOffset;
-            const QDemonPropertyDefinition *theDefinition = inClass->dynamicClass->findPropertyByName(inCommand.m_propertyName);
-            if (theDefinition)
-                doApplyInstanceValue(inEffect, dataPtr, inCommand.m_propertyName, inCommand.m_valueType, inShader, *theDefinition);
-        } else {
-            QDemonDataView<QDemonPropertyDefinition> theDefs = inClass->dynamicClass->getProperties();
-            for (quint32 idx = 0, end = theDefs.size(); idx < end; ++idx) {
-                const QDemonPropertyDefinition &theDefinition(theDefs[idx]);
-                auto theConstant = inShader->shaderConstant(theDefinition.name);
-
-                // This is fine, the property wasn't found and we continue, no problem.
-                if (!theConstant)
-                    continue;
-                quint8 *dataPtr = inEffect->getDataSectionBegin() + theDefinition.offset;
-                doApplyInstanceValue(inEffect, dataPtr, theDefinition.name, theDefinition.dataType, inShader, theDefinition);
-            }
-        }
+//        if (!inCommand.m_propertyName.isEmpty()) {
+//            bool canGetData = inCommand.m_valueOffset + getSizeofShaderDataType(inCommand.m_valueType) <= inEffect->dataSectionByteSize;
+//            if (canGetData == false) {
+//                Q_ASSERT(false);
+//                return;
+//            }
+//            quint8 *dataPtr = inEffect->getDataSectionBegin() + inCommand.m_valueOffset;
+//            const QDemonPropertyDefinition *theDefinition = inClass->dynamicClass->findPropertyByName(inCommand.m_propertyName);
+//            if (theDefinition)
+//                doApplyInstanceValue(inEffect, dataPtr, inCommand.m_propertyName, inCommand.m_valueType, inShader, *theDefinition);
+//        } else {
+//            QDemonDataView<QDemonPropertyDefinition> theDefs = inClass->dynamicClass->getProperties();
+//            for (quint32 idx = 0, end = theDefs.size(); idx < end; ++idx) {
+//                const QDemonPropertyDefinition &theDefinition(theDefs[idx]);
+//                auto theConstant = inShader->shaderConstant(theDefinition.name);
+
+//                // This is fine, the property wasn't found and we continue, no problem.
+//                if (!theConstant)
+//                    continue;
+//                quint8 *dataPtr = inEffect->getDataSectionBegin() + theDefinition.offset;
+//                doApplyInstanceValue(inEffect, dataPtr, theDefinition.name, theDefinition.dataType, inShader, theDefinition);
+//            }
+//        }
     }
 
     void applyValue(QDemonRenderEffect *inEffect,
@@ -1084,12 +1091,12 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
                     const QDemonRef<QDemonRenderShaderProgram> &inShader,
                     const QDemonApplyValue &inCommand)
     {
-        if (!inCommand.m_propertyName.isEmpty()) {
-            quint8 *dataPtr = inCommand.m_value.mData;
-            const QDemonPropertyDefinition *theDefinition = inClass->dynamicClass->findPropertyByName(inCommand.m_propertyName);
-            if (theDefinition)
-                doApplyInstanceValue(inEffect, dataPtr, inCommand.m_propertyName, inCommand.m_valueType, inShader, *theDefinition);
-        }
+//        if (!inCommand.m_propertyName.isEmpty()) {
+//            quint8 *dataPtr = inCommand.m_value.mData;
+//            const QDemonPropertyDefinition *theDefinition = inClass->dynamicClass->findPropertyByName(inCommand.m_propertyName);
+//            if (theDefinition)
+//                doApplyInstanceValue(inEffect, dataPtr, inCommand.m_propertyName, inCommand.m_valueType, inShader, *theDefinition);
+//        }
     }
 
     bool applyBlending(const QDemonApplyBlending &inCommand)
@@ -1164,7 +1171,7 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
         }
 
         if (!inCommand.m_paramName.isEmpty()) {
-            auto theConstant = inShader->shaderConstant(inCommand.m_paramName.toLatin1());
+            auto theConstant = inShader->shaderConstant(inCommand.m_paramName);
 
             if (theConstant) {
                 if (theConstant->getShaderConstantType() != QDemonRenderShaderDataType::Texture2D) {
@@ -1419,204 +1426,206 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
                         const QDemonRef<QDemonRenderTexture2D> &inDepthStencilTexture,
                         const QVector2D &inCameraClipRange)
     {
-        // Run through the effect commands and render the effect.
-        // QDemonRenderTexture2D* theCurrentTexture(&inSourceTexture);
-        auto theContext = m_context->renderContext();
-
-        // Context variables that are updated during the course of a pass.
-        QDemonEffectTextureData theCurrentSourceTexture(inSourceTexture, false);
-        QDemonRef<QDemonRenderTexture2D> theCurrentDepthStencilTexture;
-        QDemonRef<QDemonRenderFrameBuffer> theCurrentRenderTarget(inTarget);
-        QDemonRef<QDemonEffectShader> theCurrentShader;
-        QRect theOriginalViewport(theContext->viewport());
-        bool wasScissorEnabled = theContext->isScissorTestEnabled();
-        bool wasBlendingEnabled = theContext->isBlendingEnabled();
-        // save current blending setup
-        QDemonRenderBlendFunctionArgument theBlendFunc = theContext->blendFunction();
-        QDemonRenderBlendEquationArgument theBlendEqu = theContext->blendEquation();
-        bool intermediateBlendingEnabled = false;
-        QDemonTextureDetails theDetails(inSourceTexture->textureDetails());
-        quint32 theFinalWidth = (quint32)(theDetails.width);
-        quint32 theFinalHeight = (quint32)(theDetails.height);
-        QVector2D theDestSize;
-        {
-            // Ensure no matter the command run goes we replace the rendering system to some
-            // semblance of the approprate
-            // setting.
-            QDemonRenderContextScopedProperty<QDemonRef<QDemonRenderFrameBuffer>> __framebuffer(*theContext,
-                                                                                                &QDemonRenderContext::renderTarget,
-                                                                                                &QDemonRenderContext::setRenderTarget);
-            QDemonRenderContextScopedProperty<QRect> __viewport(*theContext,
-                                                                &QDemonRenderContext::viewport,
-                                                                &QDemonRenderContext::setViewport);
-            QDemonRenderContextScopedProperty<bool> __scissorEnabled(*theContext,
-                                                                     &QDemonRenderContext::isScissorTestEnabled,
-                                                                     &QDemonRenderContext::setScissorTestEnabled);
-            QDemonRenderContextScopedProperty<bool> __stencilTest(*theContext,
-                                                                  &QDemonRenderContext::isStencilTestEnabled,
-                                                                  &QDemonRenderContext::setStencilTestEnabled);
-            QDemonRenderContextScopedProperty<QDemonRenderBoolOp> __depthFunction(*theContext,
-                                                                                        &QDemonRenderContext::depthFunction,
-                                                                                        &QDemonRenderContext::setDepthFunction);
-            QDemonOption<QDemonDepthStencil> theCurrentDepthStencil;
-
-            theContext->setScissorTestEnabled(false);
-            theContext->setBlendingEnabled(false);
-            theContext->setCullingEnabled(false);
-            theContext->setDepthTestEnabled(false);
-            theContext->setDepthWriteEnabled(false);
-
-            QMatrix4x4 theMVP;
-            QDemonDataView<dynamic::QDemonCommand *> theCommands = inClass->dynamicClass->getRenderCommands();
-            for (quint32 commandIdx = 0, commandEnd = theCommands.size(); commandIdx < commandEnd; ++commandIdx) {
-                const QDemonCommand &theCommand(*theCommands[commandIdx]);
-                switch (theCommand.m_type) {
-                case CommandType::AllocateBuffer:
-                    allocateBuffer(*inEffect,
-                                   static_cast<const QDemonAllocateBuffer &>(theCommand),
-                                   theFinalWidth,
-                                   theFinalHeight,
-                                   theDetails.format);
-                    break;
-
-                case CommandType::AllocateImage:
-                    allocateImage(*inEffect, static_cast<const QDemonAllocateImage &>(theCommand), theFinalWidth, theFinalHeight);
-                    break;
-
-                case CommandType::AllocateDataBuffer:
-                    allocateDataBuffer(*inEffect, static_cast<const QDemonAllocateDataBuffer &>(theCommand));
-                    break;
-
-                case CommandType::BindBuffer:
-                    theCurrentRenderTarget = bindBuffer(*inEffect, static_cast<const QDemonBindBuffer &>(theCommand), theMVP, theDestSize);
-                    break;
-
-                case CommandType::BindTarget: {
-                    m_context->renderContext()->setRenderTarget(inTarget);
-                    theCurrentRenderTarget = inTarget;
-                    theMVP = inMVP;
-                    theContext->setViewport(theOriginalViewport);
-                    theDestSize = QVector2D((float)theFinalWidth, (float)theFinalHeight);
-                    // This isn't necessary if we are rendering to an offscreen buffer and not
-                    // compositing
-                    // with other objects.
-                    if (inEnableBlendWhenRenderToTarget) {
-                        theContext->setBlendingEnabled(wasBlendingEnabled);
-                        theContext->setScissorTestEnabled(wasScissorEnabled);
-                        // The blending setup was done before we apply the effect
-                        theContext->setBlendFunction(theBlendFunc);
-                        theContext->setBlendEquation(theBlendEqu);
-                    }
-                } break;
-                case CommandType::BindShader:
-                    theCurrentShader = bindShader(inEffect->className, static_cast<const QDemonBindShader &>(theCommand));
-                    break;
-                case CommandType::ApplyInstanceValue:
-                    if (theCurrentShader)
-                        applyInstanceValue(inEffect,
-                                           inClass,
-                                           theCurrentShader->m_shader,
-                                           static_cast<const QDemonApplyInstanceValue &>(theCommand));
-                    break;
-                case CommandType::ApplyValue:
-                    if (theCurrentShader)
-                        applyValue(inEffect, inClass, theCurrentShader->m_shader, static_cast<const QDemonApplyValue &>(theCommand));
-                    break;
-                case CommandType::ApplyBlending:
-                    intermediateBlendingEnabled = applyBlending(static_cast<const QDemonApplyBlending &>(theCommand));
-                    break;
-                case CommandType::ApplyBufferValue:
-                    if (theCurrentShader)
-                        theCurrentSourceTexture = applyBufferValue(inEffect,
-                                                                   theCurrentShader->m_shader,
-                                                                   static_cast<const QDemonApplyBufferValue &>(theCommand),
-                                                                   inSourceTexture,
-                                                                   theCurrentSourceTexture);
-                    break;
-                case CommandType::ApplyDepthValue:
-                    if (theCurrentShader)
-                        applyDepthValue(inEffect, theCurrentShader->m_shader, static_cast<const QDemonApplyDepthValue &>(theCommand), inDepthTexture);
-                    if (!inDepthTexture) {
-                        qCCritical(INVALID_OPERATION,
-                                   "Depth value command detected but no "
-                                   "depth buffer provided for effect %s",
-                                   qPrintable(inEffect->className));
-                        Q_ASSERT(false);
-                    }
-                    break;
-                case CommandType::ApplyImageValue:
-                    if (theCurrentShader)
-                        applyImageValue(inEffect, theCurrentShader->m_shader, static_cast<const QDemonApplyImageValue &>(theCommand));
-                    break;
-                case CommandType::ApplyDataBufferValue:
-                    if (theCurrentShader)
-                        applyDataBufferValue(inEffect,
-                                             theCurrentShader->m_shader,
-                                             static_cast<const QDemonApplyDataBufferValue &>(theCommand));
-                    break;
-                case CommandType::DepthStencil: {
-                    const QDemonDepthStencil &theDepthStencil = static_cast<const QDemonDepthStencil &>(theCommand);
-                    theCurrentDepthStencilTexture = findTexture(inEffect, theDepthStencil.m_bufferName);
-                    if (theCurrentDepthStencilTexture)
-                        theCurrentDepthStencil = theDepthStencil;
-                } break;
-                case CommandType::Render:
-                    if (theCurrentShader && theCurrentSourceTexture.texture) {
-                        renderPass(*theCurrentShader,
-                                   theMVP,
-                                   theCurrentSourceTexture,
-                                   theCurrentRenderTarget,
-                                   theDestSize,
-                                   inCameraClipRange,
-                                   theCurrentDepthStencilTexture,
-                                   theCurrentDepthStencil,
-                                   static_cast<const QDemonRender &>(theCommand).m_drawIndirect);
-                    }
-                    // Reset the source texture regardless
-                    theCurrentSourceTexture = QDemonEffectTextureData(inSourceTexture, false);
-                    theCurrentDepthStencilTexture = nullptr;
-                    theCurrentDepthStencil = QDemonOption<QDemonDepthStencil>();
-                    // reset intermediate blending state
-                    if (intermediateBlendingEnabled) {
-                        theContext->setBlendingEnabled(false);
-                        intermediateBlendingEnabled = false;
-                    }
-                    break;
-                case CommandType::ApplyRenderState:
-                    applyRenderStateValue(theCurrentRenderTarget.data(),
-                                          inDepthStencilTexture,
-                                          static_cast<const QDemonApplyRenderState &>(theCommand));
-                    break;
-                default:
-                    Q_ASSERT(false);
-                    break;
-                }
-            }
-
-            setEffectRequiresCompilation(inEffect->className, false);
-
-            // reset to default stencil state
-            if (inDepthStencilTexture)
-                theContext->setDepthStencilState(m_defaultStencilState);
-
-            // Release any per-frame buffers
-            if (inEffect->m_context) {
-                QDemonEffectContext &theContext(*inEffect->m_context);
-                // Query for size on every loop intentional
-                for (qint32 idx = 0; idx < theContext.m_allocatedBuffers.size(); ++idx) {
-                    if (theContext.m_allocatedBuffers[idx].flags.isSceneLifetime() == false) {
-                        theContext.releaseBuffer(idx);
-                        --idx;
-                    }
-                }
-                for (qint32 idx = 0; idx < theContext.m_allocatedImages.size(); ++idx) {
-                    if (theContext.m_allocatedImages[idx].flags.isSceneLifetime() == false) {
-                        theContext.releaseImage(idx);
-                        --idx;
-                    }
-                }
-            }
-        }
+        Q_ASSERT(0);
+
+//        // Run through the effect commands and render the effect.
+//        // QDemonRenderTexture2D* theCurrentTexture(&inSourceTexture);
+//        auto theContext = m_context->renderContext();
+
+//        // Context variables that are updated during the course of a pass.
+//        QDemonEffectTextureData theCurrentSourceTexture(inSourceTexture, false);
+//        QDemonRef<QDemonRenderTexture2D> theCurrentDepthStencilTexture;
+//        QDemonRef<QDemonRenderFrameBuffer> theCurrentRenderTarget(inTarget);
+//        QDemonRef<QDemonEffectShader> theCurrentShader;
+//        QRect theOriginalViewport(theContext->viewport());
+//        bool wasScissorEnabled = theContext->isScissorTestEnabled();
+//        bool wasBlendingEnabled = theContext->isBlendingEnabled();
+//        // save current blending setup
+//        QDemonRenderBlendFunctionArgument theBlendFunc = theContext->blendFunction();
+//        QDemonRenderBlendEquationArgument theBlendEqu = theContext->blendEquation();
+//        bool intermediateBlendingEnabled = false;
+//        QDemonTextureDetails theDetails(inSourceTexture->textureDetails());
+//        quint32 theFinalWidth = (quint32)(theDetails.width);
+//        quint32 theFinalHeight = (quint32)(theDetails.height);
+//        QVector2D theDestSize;
+//        {
+//            // Ensure no matter the command run goes we replace the rendering system to some
+//            // semblance of the approprate
+//            // setting.
+//            QDemonRenderContextScopedProperty<QDemonRef<QDemonRenderFrameBuffer>> __framebuffer(*theContext,
+//                                                                                                &QDemonRenderContext::renderTarget,
+//                                                                                                &QDemonRenderContext::setRenderTarget);
+//            QDemonRenderContextScopedProperty<QRect> __viewport(*theContext,
+//                                                                &QDemonRenderContext::viewport,
+//                                                                &QDemonRenderContext::setViewport);
+//            QDemonRenderContextScopedProperty<bool> __scissorEnabled(*theContext,
+//                                                                     &QDemonRenderContext::isScissorTestEnabled,
+//                                                                     &QDemonRenderContext::setScissorTestEnabled);
+//            QDemonRenderContextScopedProperty<bool> __stencilTest(*theContext,
+//                                                                  &QDemonRenderContext::isStencilTestEnabled,
+//                                                                  &QDemonRenderContext::setStencilTestEnabled);
+//            QDemonRenderContextScopedProperty<QDemonRenderBoolOp> __depthFunction(*theContext,
+//                                                                                        &QDemonRenderContext::depthFunction,
+//                                                                                        &QDemonRenderContext::setDepthFunction);
+//            QDemonOption<QDemonDepthStencil> theCurrentDepthStencil;
+
+//            theContext->setScissorTestEnabled(false);
+//            theContext->setBlendingEnabled(false);
+//            theContext->setCullingEnabled(false);
+//            theContext->setDepthTestEnabled(false);
+//            theContext->setDepthWriteEnabled(false);
+
+//            QMatrix4x4 theMVP;
+//            QDemonDataView<dynamic::QDemonCommand *> theCommands = inClass->dynamicClass->getRenderCommands();
+//            for (quint32 commandIdx = 0, commandEnd = theCommands.size(); commandIdx < commandEnd; ++commandIdx) {
+//                const QDemonCommand &theCommand(*theCommands[commandIdx]);
+//                switch (theCommand.m_type) {
+//                case CommandType::AllocateBuffer:
+//                    allocateBuffer(*inEffect,
+//                                   static_cast<const QDemonAllocateBuffer &>(theCommand),
+//                                   theFinalWidth,
+//                                   theFinalHeight,
+//                                   theDetails.format);
+//                    break;
+
+//                case CommandType::AllocateImage:
+//                    allocateImage(*inEffect, static_cast<const QDemonAllocateImage &>(theCommand), theFinalWidth, theFinalHeight);
+//                    break;
+
+//                case CommandType::AllocateDataBuffer:
+//                    allocateDataBuffer(*inEffect, static_cast<const QDemonAllocateDataBuffer &>(theCommand));
+//                    break;
+
+//                case CommandType::BindBuffer:
+//                    theCurrentRenderTarget = bindBuffer(*inEffect, static_cast<const QDemonBindBuffer &>(theCommand), theMVP, theDestSize);
+//                    break;
+
+//                case CommandType::BindTarget: {
+//                    m_context->renderContext()->setRenderTarget(inTarget);
+//                    theCurrentRenderTarget = inTarget;
+//                    theMVP = inMVP;
+//                    theContext->setViewport(theOriginalViewport);
+//                    theDestSize = QVector2D((float)theFinalWidth, (float)theFinalHeight);
+//                    // This isn't necessary if we are rendering to an offscreen buffer and not
+//                    // compositing
+//                    // with other objects.
+//                    if (inEnableBlendWhenRenderToTarget) {
+//                        theContext->setBlendingEnabled(wasBlendingEnabled);
+//                        theContext->setScissorTestEnabled(wasScissorEnabled);
+//                        // The blending setup was done before we apply the effect
+//                        theContext->setBlendFunction(theBlendFunc);
+//                        theContext->setBlendEquation(theBlendEqu);
+//                    }
+//                } break;
+//                case CommandType::BindShader:
+//                    theCurrentShader = bindShader(inEffect->className, static_cast<const QDemonBindShader &>(theCommand));
+//                    break;
+//                case CommandType::ApplyInstanceValue:
+//                    if (theCurrentShader)
+//                        applyInstanceValue(inEffect,
+//                                           inClass,
+//                                           theCurrentShader->m_shader,
+//                                           static_cast<const QDemonApplyInstanceValue &>(theCommand));
+//                    break;
+//                case CommandType::ApplyValue:
+//                    if (theCurrentShader)
+//                        applyValue(inEffect, inClass, theCurrentShader->m_shader, static_cast<const QDemonApplyValue &>(theCommand));
+//                    break;
+//                case CommandType::ApplyBlending:
+//                    intermediateBlendingEnabled = applyBlending(static_cast<const QDemonApplyBlending &>(theCommand));
+//                    break;
+//                case CommandType::ApplyBufferValue:
+//                    if (theCurrentShader)
+//                        theCurrentSourceTexture = applyBufferValue(inEffect,
+//                                                                   theCurrentShader->m_shader,
+//                                                                   static_cast<const QDemonApplyBufferValue &>(theCommand),
+//                                                                   inSourceTexture,
+//                                                                   theCurrentSourceTexture);
+//                    break;
+//                case CommandType::ApplyDepthValue:
+//                    if (theCurrentShader)
+//                        applyDepthValue(inEffect, theCurrentShader->m_shader, static_cast<const QDemonApplyDepthValue &>(theCommand), inDepthTexture);
+//                    if (!inDepthTexture) {
+//                        qCCritical(INVALID_OPERATION,
+//                                   "Depth value command detected but no "
+//                                   "depth buffer provided for effect %s",
+//                                   qPrintable(inEffect->className));
+//                        Q_ASSERT(false);
+//                    }
+//                    break;
+//                case CommandType::ApplyImageValue:
+//                    if (theCurrentShader)
+//                        applyImageValue(inEffect, theCurrentShader->m_shader, static_cast<const QDemonApplyImageValue &>(theCommand));
+//                    break;
+//                case CommandType::ApplyDataBufferValue:
+//                    if (theCurrentShader)
+//                        applyDataBufferValue(inEffect,
+//                                             theCurrentShader->m_shader,
+//                                             static_cast<const QDemonApplyDataBufferValue &>(theCommand));
+//                    break;
+//                case CommandType::DepthStencil: {
+//                    const QDemonDepthStencil &theDepthStencil = static_cast<const QDemonDepthStencil &>(theCommand);
+//                    theCurrentDepthStencilTexture = findTexture(inEffect, theDepthStencil.m_bufferName);
+//                    if (theCurrentDepthStencilTexture)
+//                        theCurrentDepthStencil = theDepthStencil;
+//                } break;
+//                case CommandType::Render:
+//                    if (theCurrentShader && theCurrentSourceTexture.texture) {
+//                        renderPass(*theCurrentShader,
+//                                   theMVP,
+//                                   theCurrentSourceTexture,
+//                                   theCurrentRenderTarget,
+//                                   theDestSize,
+//                                   inCameraClipRange,
+//                                   theCurrentDepthStencilTexture,
+//                                   theCurrentDepthStencil,
+//                                   static_cast<const QDemonRender &>(theCommand).m_drawIndirect);
+//                    }
+//                    // Reset the source texture regardless
+//                    theCurrentSourceTexture = QDemonEffectTextureData(inSourceTexture, false);
+//                    theCurrentDepthStencilTexture = nullptr;
+//                    theCurrentDepthStencil = QDemonOption<QDemonDepthStencil>();
+//                    // reset intermediate blending state
+//                    if (intermediateBlendingEnabled) {
+//                        theContext->setBlendingEnabled(false);
+//                        intermediateBlendingEnabled = false;
+//                    }
+//                    break;
+//                case CommandType::ApplyRenderState:
+//                    applyRenderStateValue(theCurrentRenderTarget.data(),
+//                                          inDepthStencilTexture,
+//                                          static_cast<const QDemonApplyRenderState &>(theCommand));
+//                    break;
+//                default:
+//                    Q_ASSERT(false);
+//                    break;
+//                }
+//            }
+
+//            setEffectRequiresCompilation(inEffect->className, false);
+
+//            // reset to default stencil state
+//            if (inDepthStencilTexture)
+//                theContext->setDepthStencilState(m_defaultStencilState);
+
+//            // Release any per-frame buffers
+//            if (inEffect->m_context) {
+//                QDemonEffectContext &theContext(*inEffect->m_context);
+//                // Query for size on every loop intentional
+//                for (qint32 idx = 0; idx < theContext.m_allocatedBuffers.size(); ++idx) {
+//                    if (theContext.m_allocatedBuffers[idx].flags.isSceneLifetime() == false) {
+//                        theContext.releaseBuffer(idx);
+//                        --idx;
+//                    }
+//                }
+//                for (qint32 idx = 0; idx < theContext.m_allocatedImages.size(); ++idx) {
+//                    if (theContext.m_allocatedImages[idx].flags.isSceneLifetime() == false) {
+//                        theContext.releaseImage(idx);
+//                        --idx;
+//                    }
+//                }
+//            }
+//        }
     }
 
     QDemonRef<QDemonRenderTexture2D> renderEffect(QDemonEffectRenderArgument inRenderArgument) override
@@ -1641,8 +1650,9 @@ struct QDemonEffectSystem : public QDemonEffectSystemInterface
         // UdoL Some Effects may need to run before HDR tonemap. This means we need to keep the
         // input format
         QDemonRenderTextureFormat theOutputFormat = QDemonRenderTextureFormat::RGBA8;
-        if (theClass->dynamicClass->getOutputTextureFormat() == QDemonRenderTextureFormat::Unknown)
-            theOutputFormat = theDetails.format;
+        // TODO:
+//        if (theClass->dynamicClass->getOutputTextureFormat() == QDemonRenderTextureFormat::Unknown)
+//            theOutputFormat = theDetails.format;
         auto theTargetTexture = theManager->allocateTexture2D(theFinalWidth, theFinalHeight, theOutputFormat);
         theBuffer->attach(QDemonRenderFrameBufferAttachment::Color0, theTargetTexture);
         theContext->setRenderTarget(theBuffer);