diff --git a/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js b/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js
index 6988009f4fd55b0b0c2c811c04910a6102898bda..e0ae1e2a26905578bbe7432c43505b811f006f45 100644
--- a/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js
+++ b/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js
@@ -54,8 +54,27 @@ function initGL(canvas, textureLoader) {
         // Initialize vertex and color buffers
         initBuffers();
 
-        // Load the texture
-        textureLoader.loadTexture("qtlogo.png");
+        // Load the Qt logo as texture
+        var qtLogoImage = TextureImageFactory.newTexImage();
+        qtLogoImage.imageLoaded.connect(function() {
+            cubeTexture = gl.createTexture();
+            cubeTexture.name = "CubeTexture";
+            gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+            gl.texImage2D(gl.TEXTURE_2D,    // target
+                          0,                // level
+                          gl.RGBA,          // internalformat
+                          gl.RGBA,          // format
+                          gl.UNSIGNED_BYTE, // type
+                          qtLogoImage);    // pixels
+
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+            gl.generateMipmap(gl.TEXTURE_2D);
+        });
+        qtLogoImage.imageLoadingFailed.connect(function() {
+            console.log("Texture load FAILED, "+qtLogoImage.errorString);
+        });
+        qtLogoImage.src = "qrc:/qml/framebuffer/qtlogo.png";
 
         //! [1]
         // Create the framebuffer object
@@ -102,25 +121,6 @@ function initGL(canvas, textureLoader) {
     }
 }
 
-function textureLoaded(textureImage) {
-    if (textureImage.imageState == TextureImage.LOADING_FINISHED && cubeTexture  == 0) {
-        log("    processing "+textureImage.source);
-        cubeTexture = gl.createTexture();
-        cubeTexture.name = "CubeTexture";
-        gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
-        gl.texImage2D(gl.TEXTURE_2D,    // target
-                      0,                // level
-                      gl.RGBA,          // internalformat
-                      gl.RGBA,          // format
-                      gl.UNSIGNED_BYTE, // type
-                      textureImage);    // pixels
-
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-        gl.generateMipmap(gl.TEXTURE_2D);
-    }
-}
-
 function degToRad(degrees) {
     return degrees * Math.PI / 180;
 }
diff --git a/examples/canvas3d/framebuffer/qml/framebuffer/main.qml b/examples/canvas3d/framebuffer/qml/framebuffer/main.qml
index f5d19ed15357e3113a1878e0c2084959dc6225f0..af143dec188891d5da1dbf20a716470571caa0bc 100644
--- a/examples/canvas3d/framebuffer/qml/framebuffer/main.qml
+++ b/examples/canvas3d/framebuffer/qml/framebuffer/main.qml
@@ -50,7 +50,6 @@ Item {
     Canvas3D {
         id: canvas3d
         anchors.fill: parent
-        imageLoader: textureImageLoader
         property double xRotSlider: 0
         property double yRotSlider: 0
         property double zRotSlider: 0
@@ -61,7 +60,7 @@ Item {
 
         // Emitted when one time initializations should happen
         onInitGL: {
-            GLCode.initGL(canvas3d, textureImageLoader);
+            GLCode.initGL(canvas3d);
         }
 
         // Emitted each time Canvas3D is ready for a new frame
@@ -212,27 +211,4 @@ Item {
             onValueChanged: canvas3d.zRotSlider = value;
         }
     }
-
-    TextureImageLoader {
-        id: textureImageLoader
-
-        function loadTexture(file) {
-            if (canvas3d.logAllCalls)
-                console.log("TextureImageLoader.loadTexture(qrc:/qml/framebuffer/"+file+")")
-            return textureImageLoader.loadImage("qrc:/qml/framebuffer/"+file);
-        }
-
-        onImageLoaded: {
-            if (canvas3d.logAllCalls)
-                console.log("Texture loaded, size "+image.width+"x"+image.height);
-            GLCode.textureLoaded(image);
-        }
-
-        onImageLoadingFailed: {
-            if (GLCode.textureLoadError !== undefined) {
-                GLCode.textureLoadError(image);
-            }
-            console.log("Texture load FAILED, "+image.errorString);
-        }
-    }
 }
diff --git a/examples/canvas3d/interaction/qml/interaction/interaction.js b/examples/canvas3d/interaction/qml/interaction/interaction.js
index 84bd11de79565df8f38467bdb521bbb99b212200..19a7772fdd602a8ccf2b8d9530f052e067110533 100644
--- a/examples/canvas3d/interaction/qml/interaction/interaction.js
+++ b/examples/canvas3d/interaction/qml/interaction/interaction.js
@@ -40,7 +40,7 @@ function Model() {
 
 var theModel = new Model();
 
-function initGL(canvas, textureLoader) {
+function initGL(canvas) {
     canvas3d = canvas
     log("*******************************************************************************************")
     log("initGL ENTER...")
@@ -95,7 +95,27 @@ function initGL(canvas, textureLoader) {
 
         // Load the barrel texture
         gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
-        textureLoader.loadImage("qrc:/qml/interaction/barrel.jpg");
+        // Load the Qt logo as texture
+        var barrelImage = TextureImageFactory.newTexImage();
+        barrelImage.imageLoaded.connect(function() {
+            barrelTexture = gl.createTexture();
+            barrelTexture.name = "barrelTexture"
+            gl.bindTexture(gl.TEXTURE_2D, barrelTexture);
+            gl.texImage2D(gl.TEXTURE_2D,    // target
+                          0,                // level
+                          gl.RGBA,          // internalformat
+                          gl.RGBA,          // format
+                          gl.UNSIGNED_BYTE, // type
+                          barrelImage);     // pixels
+
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+            gl.generateMipmap(gl.TEXTURE_2D);
+        });
+        barrelImage.imageLoadingFailed.connect(function() {
+            console.log("Texture load FAILED, "+barrelImage.errorString);
+        });
+        barrelImage.src = "qrc:/qml/interaction/barrel.jpg";
 
         // Load the model
         log("    Create XMLHttpRequest")
@@ -241,32 +261,6 @@ function handleLoadedModel(jsonObj) {
     log("*******************************************************************************************");
 }
 
-function textureLoaded(textureImage) {
-    log("*******************************************************************************************");
-    log("textureLoaded ENTER...")
-
-    if (textureImage.imageState == TextureImage.LOADING_FINISHED && barrelTexture  == 0) {
-        log("    processing "+textureImage.source);
-        barrelTexture = gl.createTexture();
-        barrelTexture.name = "barrelTexture"
-        gl.bindTexture(gl.TEXTURE_2D, barrelTexture);
-        gl.texImage2D(gl.TEXTURE_2D,    // target
-                      0,                // level
-                      gl.RGBA,          // internalformat
-                      gl.RGBA,          // format
-                      gl.UNSIGNED_BYTE, // type
-                      textureImage);    // pixels
-
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-        gl.generateMipmap(gl.TEXTURE_2D);
-    }
-
-    gl.bindTexture(gl.TEXTURE_2D, null);
-    log("...textureLoaded EXIT");
-    log("*******************************************************************************************");
-}
-
 function degToRad(degrees) {
     return degrees * Math.PI / 180;
 }
diff --git a/examples/canvas3d/interaction/qml/interaction/main.qml b/examples/canvas3d/interaction/qml/interaction/main.qml
index 298f6e149ca7b0ae753e3926480feb51331f3354..8947fac96719fa6c1575c875fc16ff281deda825 100644
--- a/examples/canvas3d/interaction/qml/interaction/main.qml
+++ b/examples/canvas3d/interaction/qml/interaction/main.qml
@@ -52,7 +52,6 @@ Item {
     Canvas3D {
         id: canvas3d
         anchors.fill: parent
-        imageLoader: textureImageLoader
         focus: true
         //! [3]
         property double xRotSlider: 0
@@ -62,7 +61,7 @@ Item {
 
         // Emitted when one time initializations should happen
         onInitGL: {
-            GLCode.initGL(canvas3d, textureImageLoader);
+            GLCode.initGL(canvas3d);
         }
 
         // Emitted each time Canvas3D is ready for a new frame
@@ -139,21 +138,4 @@ Item {
             onValueChanged: canvas3d.zRotSlider = value;
         }
     }
-
-    TextureImageLoader {
-        id: textureImageLoader
-
-        onImageLoaded: {
-            if (canvas3d.logAllCalls)
-                console.log("Texture loaded, size "+image.width+"x"+image.height);
-            GLCode.textureLoaded(image);
-        }
-
-        onImageLoadingFailed: {
-            if (GLCode.textureLoadError !== undefined) {
-                GLCode.textureLoadError(image);
-            }
-            console.log("Texture load FAILED, "+image.errorString);
-        }
-    }
 }
diff --git a/examples/canvas3d/jsonmodels/doc/src/jsonmodels.qdoc b/examples/canvas3d/jsonmodels/doc/src/jsonmodels.qdoc
index 0e19a7d2dca46e4859192103319460a3001c2c0a..2c3532abcb286df99542b3dee3f28d435babe1c2 100644
--- a/examples/canvas3d/jsonmodels/doc/src/jsonmodels.qdoc
+++ b/examples/canvas3d/jsonmodels/doc/src/jsonmodels.qdoc
@@ -85,16 +85,13 @@
 
     \section1 Loading the Textures
 
-    First we ask the TextureImageLoader to load the texture images one by one:
+    First we create the TextureImage objects for each of the images we are going to load and register
+    handlers for the \c imageLoaded and \c imageLoadingFailed signals. In the \c imageLoaded signal
+    handlers we create the OpenGL textures:
 
     \snippet jsonmodels/jsonmodels.js 5
     \dots
 
-    Then, after being successfully loaded, we create the textures:
-
-    \snippet jsonmodels/jsonmodels.js 6
-    \dots
-
     \section1 Input Handling
 
     First we add a MouseArea to fill the Canvas3D:
diff --git a/examples/canvas3d/jsonmodels/jsonmodels.js b/examples/canvas3d/jsonmodels/jsonmodels.js
index 254ae50696c18e8e0c33363ed2760c3de272e561..bca47ddd91e2c3cc322ea3502eb0856b63441d3e 100644
--- a/examples/canvas3d/jsonmodels/jsonmodels.js
+++ b/examples/canvas3d/jsonmodels/jsonmodels.js
@@ -75,7 +75,7 @@ var modelThree = new Model();
 var modelFour = new Model();
 var modelFive = new Model();
 
-function initGL(canvas, textureLoader) {
+function initGL(canvas) {
     canvas3d = canvas
     log("initGL...")
     try {
@@ -115,7 +115,7 @@ function initGL(canvas, textureLoader) {
 
         // Load textures
         gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
-        loadTextures(textureLoader);
+        loadTextures();
 
         // Load JSON models
         loadJSONModels();
@@ -567,84 +567,6 @@ function fillModel(modelData, model) {
 }
 //! [4]
 
-//! [6]
-function textureLoaded(textureImage) {
-    log("textureLoaded...")
-    if (textureImage.imageState === TextureImage.LOADING_FINISHED) {
-        log("    processing "+textureImage.source);
-        if (modelOneTexture == 0 && textureImage.source == "qrc:///gold.jpg") {
-            log("    creating model one texture");
-            modelOneTexture = gl.createTexture();
-            gl.bindTexture(gl.TEXTURE_2D, modelOneTexture);
-            gl.texImage2D(gl.TEXTURE_2D,    // target
-                          0,                // level
-                          gl.RGBA,          // internalformat
-                          gl.RGBA,          // format
-                          gl.UNSIGNED_BYTE, // type
-                          textureImage);    // pixels
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-            gl.generateMipmap(gl.TEXTURE_2D);
-        } else if (modelTwoTexture == 0 && textureImage.source == "qrc:///woodbox.jpg") {
-            log("    creating model two texture");
-            modelTwoTexture = gl.createTexture();
-            gl.bindTexture(gl.TEXTURE_2D, modelTwoTexture);
-            gl.texImage2D(gl.TEXTURE_2D,    // target
-                          0,                // level
-                          gl.RGBA,          // internalformat
-                          gl.RGBA,          // format
-                          gl.UNSIGNED_BYTE, // type
-                          textureImage);    // pixels
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-            gl.generateMipmap(gl.TEXTURE_2D);
-            //! [6]
-        } else if (modelThreeTexture == 0 && textureImage.source == "qrc:///bush.png") {
-            log("    creating model three texture");
-            modelThreeTexture = gl.createTexture();
-            gl.bindTexture(gl.TEXTURE_2D, modelThreeTexture);
-            gl.texImage2D(gl.TEXTURE_2D,    // target
-                          0,                // level
-                          gl.RGBA,          // internalformat
-                          gl.RGBA,          // format
-                          gl.UNSIGNED_BYTE, // type
-                          textureImage);    // pixels
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-            gl.generateMipmap(gl.TEXTURE_2D);
-        } else if (modelFourTexture == 0 && textureImage.source == "qrc:///pallet.jpg") {
-            log("    creating model four texture");
-            modelFourTexture = gl.createTexture();
-            gl.bindTexture(gl.TEXTURE_2D, modelFourTexture);
-            gl.texImage2D(gl.TEXTURE_2D,    // target
-                          0,                // level
-                          gl.RGBA,          // internalformat
-                          gl.RGBA,          // format
-                          gl.UNSIGNED_BYTE, // type
-                          textureImage);    // pixels
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-            gl.generateMipmap(gl.TEXTURE_2D);
-        } else if (modelFiveTexture == 0 && textureImage.source == "qrc:///rock.jpg") {
-            log("    creating model five texture");
-            modelFiveTexture = gl.createTexture();
-            gl.bindTexture(gl.TEXTURE_2D, modelFiveTexture);
-            gl.texImage2D(gl.TEXTURE_2D,    // target
-                          0,                // level
-                          gl.RGBA,          // internalformat
-                          gl.RGBA,          // format
-                          gl.UNSIGNED_BYTE, // type
-                          textureImage);    // pixels
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-            gl.generateMipmap(gl.TEXTURE_2D);
-        }
-    }
-
-    gl.bindTexture(gl.TEXTURE_2D, null);
-    log("...textureLoaded");
-}
-
 function degToRad(degrees) {
     return degrees * Math.PI / 180;
 }
@@ -743,27 +665,117 @@ function initBuffers() {
 }
 
 //! [5]
-function loadTextures(textureLoader) {
+function loadTextures() {
     // Load the first texture
-    textureLoader.loadTexture("gold.jpg");
-    log("   loadTexture sent for texture one")
+    var goldImage = TextureImageFactory.newTexImage();
+    goldImage.imageLoaded.connect(function() {
+        log("    creating model one texture");
+        modelOneTexture = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_2D, modelOneTexture);
+        gl.texImage2D(gl.TEXTURE_2D,    // target
+                      0,                // level
+                      gl.RGBA,          // internalformat
+                      gl.RGBA,          // format
+                      gl.UNSIGNED_BYTE, // type
+                      goldImage);       // pixels
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+        gl.generateMipmap(gl.TEXTURE_2D);
+    });
+    goldImage.imageLoadingFailed.connect(function() {
+        console.log("Texture load FAILED, "+goldImage.errorString);
+    });
+    goldImage.src = "qrc:///gold.jpg";
+    log("   texture one source set")
 
     // Load the second texture
-    textureLoader.loadTexture("woodbox.jpg");
-    log("   loadTexture sent for texture two")
+    var woodBoxImage = TextureImageFactory.newTexImage();
+    woodBoxImage.imageLoaded.connect(function() {
+        log("    creating model two texture");
+        modelTwoTexture = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_2D, modelTwoTexture);
+        gl.texImage2D(gl.TEXTURE_2D,    // target
+                      0,                // level
+                      gl.RGBA,          // internalformat
+                      gl.RGBA,          // format
+                      gl.UNSIGNED_BYTE, // type
+                      woodBoxImage);    // pixels
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+        gl.generateMipmap(gl.TEXTURE_2D);
+    });
+    woodBoxImage.imageLoadingFailed.connect(function() {
+        console.log("Texture load FAILED, "+woodBoxImage.errorString);
+    });
+    woodBoxImage.src = "qrc:///woodbox.jpg";
+    log("   texture two source set")
     //! [5]
 
     // Load the third texture
-    textureLoader.loadTexture("bush.png");
-    log("   loadTexture sent for texture three")
+    var bushImage = TextureImageFactory.newTexImage();
+    bushImage.imageLoaded.connect(function() {
+        log("    creating model three texture");
+        modelThreeTexture = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_2D, modelThreeTexture);
+        gl.texImage2D(gl.TEXTURE_2D,    // target
+                      0,                // level
+                      gl.RGBA,          // internalformat
+                      gl.RGBA,          // format
+                      gl.UNSIGNED_BYTE, // type
+                      bushImage);    // pixels
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+        gl.generateMipmap(gl.TEXTURE_2D);
+    });
+    bushImage.imageLoadingFailed.connect(function() {
+        console.log("Texture load FAILED, "+bushImage.errorString);
+    });
+    bushImage.src = "qrc:///bush.png";
+    log("   texture three source set")
 
     // Load the fourth texture
-    textureLoader.loadTexture("pallet.jpg");
-    log("   loadTexture sent for texture four")
+    var palletImage = TextureImageFactory.newTexImage();
+    palletImage.imageLoaded.connect(function() {
+        log("    creating model four texture");
+        modelFourTexture = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_2D, modelFourTexture);
+        gl.texImage2D(gl.TEXTURE_2D,    // target
+                      0,                // level
+                      gl.RGBA,          // internalformat
+                      gl.RGBA,          // format
+                      gl.UNSIGNED_BYTE, // type
+                      palletImage);     // pixels
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+        gl.generateMipmap(gl.TEXTURE_2D);
+    });
+    palletImage.imageLoadingFailed.connect(function() {
+        console.log("Texture load FAILED, "+palletImage.errorString);
+    });
+    palletImage.src = "qrc:///pallet.jpg";
+    log("   texture four source set")
 
     // Load the fifth texture
-    textureLoader.loadTexture("rock.jpg");
-    log("   loadTexture sent for texture five")
+    var rockImage = TextureImageFactory.newTexImage();
+    rockImage.imageLoaded.connect(function() {
+        log("    creating model five texture");
+        modelFiveTexture = gl.createTexture();
+        gl.bindTexture(gl.TEXTURE_2D, modelFiveTexture);
+        gl.texImage2D(gl.TEXTURE_2D,    // target
+                      0,                // level
+                      gl.RGBA,          // internalformat
+                      gl.RGBA,          // format
+                      gl.UNSIGNED_BYTE, // type
+                      rockImage);       // pixels
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+        gl.generateMipmap(gl.TEXTURE_2D);
+    });
+    rockImage.imageLoadingFailed.connect(function() {
+        console.log("Texture load FAILED, "+rockImage.errorString);
+    });
+    rockImage.src = "qrc:///rock.jpg";
+    log("   texture five source set")
 }
 
 //! [2]
diff --git a/examples/canvas3d/jsonmodels/jsonmodels.qml b/examples/canvas3d/jsonmodels/jsonmodels.qml
index 055635e1d9c0d376e9ca7c579e73d58957b8a943..cdba0dbfa4526264399c7de41aea5e3090e8867e 100644
--- a/examples/canvas3d/jsonmodels/jsonmodels.qml
+++ b/examples/canvas3d/jsonmodels/jsonmodels.qml
@@ -26,7 +26,6 @@ Window {
                 id: canvas3d
                 Layout.fillHeight: true
                 Layout.fillWidth: true
-                imageLoader: textureImageLoader
                 //! [1]
                 property double xRot: 0.0
                 property double yRot: 45.0
@@ -41,7 +40,7 @@ Window {
                 property bool drawWireframe: false
 
                 onInitGL: {
-                    GLCode.initGL(canvas3d, textureImageLoader);
+                    GLCode.initGL(canvas3d);
                 }
 
                 onRenderGL: {
@@ -314,22 +313,4 @@ Window {
             easing.type: Easing.InOutSine
         }
     }
-
-    TextureImageLoader {
-        id: textureImageLoader
-
-        function loadTexture(file) {
-            return textureImageLoader.loadImage("qrc:///"+file);
-        }
-
-        onImageLoaded: {
-            GLCode.textureLoaded(image);
-        }
-
-        onImageLoadingFailed: {
-            if (GLCode.textureLoadError !== undefined) {
-                GLCode.textureLoadError(image);
-            }
-        }
-    }
 }
diff --git a/examples/canvas3d/jsonmodels/jsonmodelsbasic.qml b/examples/canvas3d/jsonmodels/jsonmodelsbasic.qml
index 0d0d0168281b8aa7fa925bc727c4f3dfff595869..db96281ac18ad96b1b84946dca9f26ee5f126f06 100644
--- a/examples/canvas3d/jsonmodels/jsonmodelsbasic.qml
+++ b/examples/canvas3d/jsonmodels/jsonmodelsbasic.qml
@@ -23,7 +23,6 @@ Window {
                 id: canvas3d
                 Layout.fillHeight: true
                 Layout.fillWidth: true
-                imageLoader: textureImageLoader
                 property double xRot: 0.0
                 property double yRot: 45.0
                 property double distance: 2.0
@@ -36,7 +35,7 @@ Window {
                 property bool drawWireframe: false
 
                 onInitGL: {
-                    GLCode.initGL(canvas3d, textureImageLoader);
+                    GLCode.initGL(canvas3d);
                 }
 
                 onRenderGL: {
@@ -258,22 +257,4 @@ Window {
             easing.type: Easing.InOutSine
         }
     }
-
-    TextureImageLoader {
-        id: textureImageLoader
-
-        function loadTexture(file) {
-            return textureImageLoader.loadImage("qrc:///"+file);
-        }
-
-        onImageLoaded: {
-            GLCode.textureLoaded(image);
-        }
-
-        onImageLoadingFailed: {
-            if (GLCode.textureLoadError !== undefined) {
-                GLCode.textureLoadError(image);
-            }
-        }
-    }
 }
diff --git a/examples/canvas3d/plasmaeffects/doc/src/plasmaeffects.qdoc b/examples/canvas3d/plasmaeffects/doc/src/plasmaeffects.qdoc
index 8124dde66ff7f2db2b4f8e63a054ecdc8b6584b4..44d92eff1171ff117fbc44aeaf0a8c298ab04aa3 100644
--- a/examples/canvas3d/plasmaeffects/doc/src/plasmaeffects.qdoc
+++ b/examples/canvas3d/plasmaeffects/doc/src/plasmaeffects.qdoc
@@ -42,6 +42,10 @@
     \brief Apply oldsk00l plasma effects into a canvas
 
     The Plasma Effects Example concentrates on showing how to use different shaders in Canvas3D.
+    These shaders are of "old school graphics demo" variety that achieve their effects with raw
+    computations based on combining output of trigonometrical functions in various ways. But they
+    demonstrate how you can hand over high intensity calculations to the Graphics Processing Unit
+    (GPU) when using QtCanvas3D.
 
     For a more thorough look into the QML side see the \l {Textured Cube Example} and
     for a more thorough look into the JavaScript side see the \l {Lit and Textured Cube Example}.
diff --git a/examples/canvas3d/plasmaeffects/qml/plasmaeffects/main.qml b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/main.qml
index 08ee4a08fd0f327d8f042a920e4402a3ddac6788..8ff15894c058d792b609c20eed4d7c3be709deee 100644
--- a/examples/canvas3d/plasmaeffects/qml/plasmaeffects/main.qml
+++ b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/main.qml
@@ -48,7 +48,6 @@ Item {
     Canvas3D {
         id: canvas3d
         anchors.fill:parent
-        imageLoader: textureImageLoader
         focus: true
         property double xRotAnim: 0
         property double yRotAnim: 0
@@ -57,7 +56,7 @@ Item {
 
         // Emitted when one time initializations should happen
         onInitGL: {
-            GLCode.initGL(canvas3d, textureImageLoader);
+            GLCode.initGL(canvas3d);
         }
 
         // Emitted each time Canvas3D is ready for a new frame
@@ -144,21 +143,4 @@ Item {
             }
         }
     }
-
-    TextureImageLoader {
-        id: textureImageLoader
-
-        onImageLoaded: {
-            if (canvas3d.logAllCalls)
-                console.log("Texture loaded, size "+image.width+"x"+image.height);
-            GLCode.textureLoaded(image);
-        }
-
-        onImageLoadingFailed: {
-            if (GLCode.textureLoadError !== undefined) {
-                GLCode.textureLoadError(image);
-            }
-            console.log("Texture load FAILED, "+image.errorString);
-        }
-    }
 }
diff --git a/examples/canvas3d/plasmaeffects/qml/plasmaeffects/plasmaeffects.js b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/plasmaeffects.js
index 86e783666899ce4b1f69e38c40ab34041253ace6..eb40d9726505289a6ef786af7cfe6f77973c66d4 100644
--- a/examples/canvas3d/plasmaeffects/qml/plasmaeffects/plasmaeffects.js
+++ b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/plasmaeffects.js
@@ -41,7 +41,7 @@ function log(message) {
         console.log(message)
 }
 
-function initGL(canvas, textureLoader) {
+function initGL(canvas) {
     canvas3d = canvas;
     log("*******************************************************************************************");
     log("initGL ENTER...");
@@ -74,7 +74,25 @@ function initGL(canvas, textureLoader) {
         initShaders();
 
         // Load the texture
-        textureLoader.loadImage("qrc:/qml/plasmaeffects/qtlogo_gray.png");
+        var qtLogoImage = TextureImageFactory.newTexImage();
+        qtLogoImage.imageLoaded.connect(function() {
+            cubeTexture = gl.createTexture();
+            gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+            gl.texImage2D(gl.TEXTURE_2D,    // target
+                          0,                // level
+                          gl.RGBA,          // internalformat
+                          gl.RGBA,          // format
+                          gl.UNSIGNED_BYTE, // type
+                          qtLogoImage);     // pixels
+
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+            gl.generateMipmap(gl.TEXTURE_2D);
+        });
+        qtLogoImage.imageLoadingFailed.connect(function() {
+            console.log("Texture load FAILED, "+qtLogoImage.errorString);
+        });
+        qtLogoImage.src = "qrc:/qml/plasmaeffects/qtlogo_gray.png";
 
         log("...initGL EXIT");
     } catch(e) {
@@ -85,29 +103,6 @@ function initGL(canvas, textureLoader) {
     log("*******************************************************************************************");
 }
 
-function textureLoaded(textureImage) {
-    log("textureLoaded ENTER...")
-
-    if (textureImage.imageState == TextureImage.LOADING_FINISHED && cubeTexture  == 0) {
-        if (canvas3d.logAllCalls)
-            console.log("    processing "+textureImage.source);
-        cubeTexture = gl.createTexture();
-        gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
-        gl.texImage2D(gl.TEXTURE_2D,    // target
-                      0,                // level
-                      gl.RGBA,          // internalformat
-                      gl.RGBA,          // format
-                      gl.UNSIGNED_BYTE, // type
-                      textureImage);    // pixels
-
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-        gl.generateMipmap(gl.TEXTURE_2D);
-    }
-
-    log("...textureLoaded EXIT");
-}
-
 function degToRad(degrees) {
     return degrees * Math.PI / 180;
 }
diff --git a/examples/canvas3d/textureandlight/doc/src/textureandlight.qdoc b/examples/canvas3d/textureandlight/doc/src/textureandlight.qdoc
index 495242a4f9e863b244becd0fd5033e6844cb03e7..2d3e0ac85863bf6eaff6b510f2b568d129fb7337 100644
--- a/examples/canvas3d/textureandlight/doc/src/textureandlight.qdoc
+++ b/examples/canvas3d/textureandlight/doc/src/textureandlight.qdoc
@@ -93,9 +93,9 @@
     As can be seen, first we create the buffer, then bind it and finally insert the data into it.
     We won't take a look at the other buffers, as they are all handled in a similar fashion.
 
-    After that, as the final step in \c{initGL}, we'll request a texture from TextureImageLoader
-    passed to \c initGL as a parameter. Once the texture image is successfully loaded, we create
-    the actual texture in \c textureLoaded function called by the TextureImageLoader:
+    After that, as the final step in \c{initGL}, we'll create a texture image from
+    TextureImageFactory. And we register handlers for \c imageLoaded and \c imageLoadingFailed
+    signals. Once the texture image is successfully loaded, we create the actual texture:
 
     \snippet textureandlight/qml/textureandlight/textureandlight.js 8
 
diff --git a/examples/canvas3d/textureandlight/qml/textureandlight/main.qml b/examples/canvas3d/textureandlight/qml/textureandlight/main.qml
index b55d12469d32560c46d556ff10fdb2c1db2f498a..b38cfe3ceda9f163502960544a480afb0c4fb81e 100644
--- a/examples/canvas3d/textureandlight/qml/textureandlight/main.qml
+++ b/examples/canvas3d/textureandlight/qml/textureandlight/main.qml
@@ -48,7 +48,6 @@ Item {
     Canvas3D {
         id: canvas3d
         anchors.fill:parent
-        imageLoader: textureImageLoader
         focus: true
         property double xRotAnim: 0
         property double yRotAnim: 0
@@ -57,7 +56,7 @@ Item {
 
         // Emitted when one time initializations should happen
         onInitGL: {
-            GLCode.initGL(canvas3d, textureImageLoader);
+            GLCode.initGL(canvas3d);
         }
 
         // Emitted each time Canvas3D is ready for a new frame
@@ -144,27 +143,4 @@ Item {
             }
         }
     }
-
-    TextureImageLoader {
-        id: textureImageLoader
-
-        function loadTexture(file) {
-            if (canvas3d.logAllCalls)
-                console.log("TextureImageLoader.loadTexture(qrc:/qml/textureandlight/"+file+")")
-            return textureImageLoader.loadImage("qrc:/qml/textureandlight/"+file);
-        }
-
-        onImageLoaded: {
-            if (canvas3d.logAllCalls)
-                console.log("Texture loaded, size "+image.width+"x"+image.height);
-            GLCode.textureLoaded(image);
-        }
-
-        onImageLoadingFailed: {
-            if (GLCode.textureLoadError !== undefined) {
-                GLCode.textureLoadError(image);
-            }
-            console.log("Texture load FAILED, "+image.errorString);
-        }
-    }
 }
diff --git a/examples/canvas3d/textureandlight/qml/textureandlight/textureandlight.js b/examples/canvas3d/textureandlight/qml/textureandlight/textureandlight.js
index 1e52d0c1a18a318e75b21c51cbd150de7e199d40..06a643cae033a1383ab675f9368c69cb719ede7c 100644
--- a/examples/canvas3d/textureandlight/qml/textureandlight/textureandlight.js
+++ b/examples/canvas3d/textureandlight/qml/textureandlight/textureandlight.js
@@ -23,7 +23,7 @@ var width = 0;
 var height = 0;
 var canvas3d;
 
-function initGL(canvas, textureLoader) {
+function initGL(canvas) {
     canvas3d = canvas;
     //! [1]
     // Get the OpenGL context object that represents the API we call
@@ -50,15 +50,11 @@ function initGL(canvas, textureLoader) {
     // Initialize vertex and color buffers
     initBuffers();
 
-    // Load the texture
-    textureLoader.loadTexture("qtlogo.png");
-}
-
-//! [8]
-function textureLoaded(textureImage) {
-    if (textureImage.imageState == TextureImage.LOADING_FINISHED && cubeTexture  == 0) {
-        if (canvas3d.logAllCalls)
-            console.log("    processing "+textureImage.source);
+    // Load the Qt logo as texture
+    var qtLogoImage = TextureImageFactory.newTexImage();
+    //! [8]
+    qtLogoImage.imageLoaded.connect(function() {
+        console.log("Texture loaded, "+qtLogoImage.src);
         // Create the Texture3D object
         cubeTexture = gl.createTexture();
         // Bind it
@@ -69,15 +65,20 @@ function textureLoaded(textureImage) {
                       gl.RGBA,          // internalformat
                       gl.RGBA,          // format
                       gl.UNSIGNED_BYTE, // type
-                      textureImage);    // pixels
+                      qtLogoImage);     // pixels
         // Set texture filtering parameters
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
         // Generate mipmap
         gl.generateMipmap(gl.TEXTURE_2D);
-    }
+    });
+    //! [8]
+    qtLogoImage.imageLoadingFailed.connect(function() {
+        console.log("Texture load FAILED, "+qtLogoImage.errorString);
+    });
+    qtLogoImage.src = "qrc:/qml/textureandlight/qtlogo.png";
 }
-//! [8]
+
 
 function degToRad(degrees) {
     return degrees * Math.PI / 180;
diff --git a/examples/canvas3d/texturedcube/doc/src/texturedcube.qdoc b/examples/canvas3d/texturedcube/doc/src/texturedcube.qdoc
index 7327820870b83bdb600482bf27c7543e8b82c960..9a6d76431f778b4f16f9384404652dc1acc66dd5 100644
--- a/examples/canvas3d/texturedcube/doc/src/texturedcube.qdoc
+++ b/examples/canvas3d/texturedcube/doc/src/texturedcube.qdoc
@@ -58,23 +58,16 @@
 
     \snippet texturedcube/qml/texturedcube/main.qml 1
 
-    As we want to add a texture in the js object, we need to set the \c imageLoader property in
-    the canvas:
-
-    \snippet texturedcube/qml/texturedcube/main.qml 2
-
-    The TextureImageLoader itself is outside the Canvas3D and handles texture load successes and
-    possible errors:
-
-    \snippet texturedcube/qml/texturedcube/main.qml 3
-
     \section1 The JavaScript Object
 
     First we import the js object in the QML:
 
     \snippet texturedcube/qml/texturedcube/main.qml 4
 
-    In the \c initGL function of the js object, we initialize the OpenGL state:
+    In the \c initGL function of the js object, we initialize the OpenGL state. We also create the
+    TextureImage and register handlers for image load success and fail signals. In the case of
+    load success the OpenGL texture is created and the loaded image is used to fill the texture
+    with pixel data:
 
     \snippet texturedcube/qml/texturedcube/texturedcube.js 0
 
diff --git a/examples/canvas3d/texturedcube/qml/texturedcube/main.qml b/examples/canvas3d/texturedcube/qml/texturedcube/main.qml
index f159c88ad27b62fb837d886d7349588e58f84ecf..92081bb5be991e9c9ce8dbd9931cfa3653062cdf 100644
--- a/examples/canvas3d/texturedcube/qml/texturedcube/main.qml
+++ b/examples/canvas3d/texturedcube/qml/texturedcube/main.qml
@@ -52,9 +52,6 @@ Item {
         id: canvas3d
         anchors.fill: parent
         //! [0]
-        //! [2]
-        imageLoader: textureImageLoader
-        //! [2]
         focus: true
         property double xRotAnim: 0
         property double yRotAnim: 0
@@ -63,7 +60,7 @@ Item {
         //! [1]
         // Emitted when one time initializations should happen
         onInitGL: {
-            GLCode.initGL(canvas3d, textureImageLoader);
+            GLCode.initGL(canvas3d);
         }
 
         // Emitted each time Canvas3D is ready for a new frame
@@ -140,23 +137,4 @@ Item {
             }
         }
     }
-
-    //! [3]
-    TextureImageLoader {
-        id: textureImageLoader
-
-        onImageLoaded: {
-            if (canvas3d.logAllCalls)
-                console.log("Texture loaded, size "+image.width+"x"+image.height);
-            GLCode.textureLoaded(image);
-        }
-
-        onImageLoadingFailed: {
-            if (GLCode.textureLoadError !== undefined) {
-                GLCode.textureLoadError(image);
-            }
-            console.log("Texture load FAILED, "+image.errorString);
-        }
-    }
-    //! [3]
 }
diff --git a/examples/canvas3d/texturedcube/qml/texturedcube/texturedcube.js b/examples/canvas3d/texturedcube/qml/texturedcube/texturedcube.js
index 6d93bfb9eeaf16f55759297337999e9b76726e69..fe80ff0171a3777b5f517cae1260878ad48ab444 100644
--- a/examples/canvas3d/texturedcube/qml/texturedcube/texturedcube.js
+++ b/examples/canvas3d/texturedcube/qml/texturedcube/texturedcube.js
@@ -27,7 +27,7 @@ function log(message) {
 }
 
 //! [0]
-function initGL(canvas, textureLoader) {
+function initGL(canvas) {
     canvas3d = canvas
     log("*******************************************************************************************")
     log("initGL ENTER...")
@@ -55,18 +55,8 @@ function initGL(canvas, textureLoader) {
     initBuffers();
 
     // Load the texture
-    textureLoader.loadImage("qrc:/qml/texturedcube/qtlogo_gray.png");
-
-    log("...initGL EXIT");
-    log("*******************************************************************************************");
-}
-//! [0]
-
-function textureLoaded(textureImage) {
-    log("textureLoaded ENTER {")
-
-    if (textureImage.imageState == TextureImage.LOADING_FINISHED && cubeTexture  == 0) {
-        log("    processing "+textureImage.source);
+    var qtLogoImage = TextureImageFactory.newTexImage();
+    qtLogoImage.imageLoaded.connect(function() {
         cubeTexture = gl.createTexture();
         gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
         gl.texImage2D(gl.TEXTURE_2D,    // target
@@ -74,15 +64,21 @@ function textureLoaded(textureImage) {
                       gl.RGBA,          // internalformat
                       gl.RGBA,          // format
                       gl.UNSIGNED_BYTE, // type
-                      textureImage);    // pixels
+                      qtLogoImage);    // pixels
 
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
         gl.generateMipmap(gl.TEXTURE_2D);
-    }
+    });
+    qtLogoImage.imageLoadingFailed.connect(function() {
+        console.log("Texture load FAILED, "+qtLogoImage.errorString);
+    });
+    qtLogoImage.src = "qrc:/qml/texturedcube/qtlogo_gray.png";
 
-    log("}");
+    log("...initGL EXIT");
+    log("*******************************************************************************************");
 }
+//! [0]
 
 function degToRad(degrees) {
     return degrees * Math.PI / 180;
diff --git a/src/abstractobject3d.cpp b/src/abstractobject3d.cpp
index 0f432d253f9f5b8715d4c24b36ce0655eedaf4c7..6f1c87faf3e8e3b25f0ec688845fa176fccc6cee 100644
--- a/src/abstractobject3d.cpp
+++ b/src/abstractobject3d.cpp
@@ -36,20 +36,39 @@
 
 #include "abstractobject3d_p.h"
 
+/*!
+ * \internal
+ */
 CanvasAbstractObject::CanvasAbstractObject(QObject *parent) :
-    QQmlPropertyMap(parent)
+    QObject(parent)
 {
-    insert("name", QVariant::fromValue(QString("0x%1").arg((long long) this, 0, 16)));
+    m_name = QString("0x%1").arg((long long) this, 0, 16);
 }
 
+/*!
+ * \internal
+ */
 CanvasAbstractObject::~CanvasAbstractObject()
 {
 }
 
-QString CanvasAbstractObject::name() const
+/*!
+ * \internal
+ */
+void CanvasAbstractObject::setName(const QString &name)
 {
-    if (!contains("name"))
-        return "";
+    if (m_name == name)
+        return;
 
-    return value("name").toString();
+    m_name = name;
+
+    emit nameChanged(m_name);
+}
+
+/*!
+ * \internal
+ */
+const QString &CanvasAbstractObject::name() const
+{
+    return m_name;
 }
diff --git a/src/abstractobject3d_p.h b/src/abstractobject3d_p.h
index c223b54ad7f3cf08e6d135e8953f592ce091e555..0845adfa6d731f06c6090eadcae336114707f72c 100644
--- a/src/abstractobject3d_p.h
+++ b/src/abstractobject3d_p.h
@@ -48,18 +48,26 @@
 #define ABSTRACTOBJECT3D_P_H
 
 #include <QObject>
-#include <QQmlPropertyMap>
 #include <QThread>
 
-class CanvasAbstractObject : public QQmlPropertyMap
+class CanvasAbstractObject : public QObject
 {
     Q_OBJECT
+    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
 
 public:
     explicit CanvasAbstractObject(QObject *parent = 0);
     virtual ~CanvasAbstractObject();
 
-    QString name() const;
+    void setName(const QString &name);
+    const QString &name() const;
+
+signals:
+    void nameChanged(const QString &name);
+
+private:
+    QString m_name;
 };
 
+
 #endif // ABSTRACTOBJECT3D_P_H
diff --git a/src/activeinfo3d.cpp b/src/activeinfo3d.cpp
index 6df460c2ae54e287335ceb1cedc7d039f4d94cb5..188b00017ff33adb85f59ae257a90bcb432871dc 100644
--- a/src/activeinfo3d.cpp
+++ b/src/activeinfo3d.cpp
@@ -48,49 +48,35 @@
  * \sa Context3D, Canvas3D, {QML Canvas 3D QML Types}
  */
 
-
-
 CanvasActiveInfo::CanvasActiveInfo(int size, CanvasContext::glEnums type,
                                    QString name, QObject *parent) :
-    CanvasAbstractObject(parent),
+    QObject(parent),
     m_size(size),
     m_type(type),
     m_name(name)
 {
 }
 
-/*!
- * \qmlproperty int ActiveInfo3D::size
- * Size of the active attrib or uniform.
- */
 /*!
  * \internal
  */
-int CanvasActiveInfo::infoSize() const
+const QString CanvasActiveInfo::name() const
 {
-    return m_size;
+    return m_name;
 }
 
-/*!
- * \qmlproperty Context3D.glEnums ActiveInfo3D::type
- * Type of the active attrib or uniform.
- */
 /*!
  * \internal
  */
-CanvasContext::glEnums CanvasActiveInfo::infoType() const
+int CanvasActiveInfo::size() const
 {
-    return m_type;
+    return m_size;
 }
 
-/*!
- * \qmlproperty string ActiveInfo3D::name
- * Name of the active attrib or uniform.
- */
 /*!
  * \internal
  */
-QString CanvasActiveInfo::infoName() const
+CanvasContext::glEnums CanvasActiveInfo::type() const
 {
-    return m_name;
+    return m_type;
 }
diff --git a/src/activeinfo3d_p.h b/src/activeinfo3d_p.h
index 13a1ba2a031d20f15fd71beb7deda191c9cc141a..66ddd43e582a1d26a3d3227ae115d19630d1419a 100644
--- a/src/activeinfo3d_p.h
+++ b/src/activeinfo3d_p.h
@@ -47,29 +47,29 @@
 #ifndef CANVASACTIVEINFO_P_H
 #define CANVASACTIVEINFO_P_H
 
-#include "abstractobject3d_p.h"
+#include <QObject>
 #include "context3d_p.h"
 
-class CanvasActiveInfo : public CanvasAbstractObject
+class CanvasActiveInfo : public QObject
 {
     Q_OBJECT
 
-    Q_PROPERTY(int size READ infoSize NOTIFY infoSizeChanged)
-    Q_PROPERTY(CanvasContext::glEnums type READ infoType NOTIFY infoTypeChanged)
-    Q_PROPERTY(QString name READ infoName NOTIFY infoNameChanged)
+    Q_PROPERTY(int size READ size NOTIFY sizeChanged)
+    Q_PROPERTY(CanvasContext::glEnums type READ type NOTIFY typeChanged)
+    Q_PROPERTY(QString name READ name NOTIFY nameChanged)
 
 public:
     explicit CanvasActiveInfo(int size, CanvasContext::glEnums type,
                               QString name, QObject *parent = 0);
 
-    int infoSize() const;
-    CanvasContext::glEnums infoType() const;
-    QString infoName() const;
+    int size() const;
+    CanvasContext::glEnums type() const;
+    const QString name() const;
 
 signals:
-    void infoSizeChanged(int size);
-    void infoTypeChanged(CanvasContext::glEnums type);
-    void infoNameChanged(QString &name);
+    void sizeChanged(int size);
+    void typeChanged(CanvasContext::glEnums type);
+    void nameChanged(const QString name);
 
 private:
     int m_size;
diff --git a/src/canvas3d.cpp b/src/canvas3d.cpp
index 72128ef6483998e62921cab987ec27415ea65543..5b503c5bc6b7cb5e935461b992974f3ac4268454 100644
--- a/src/canvas3d.cpp
+++ b/src/canvas3d.cpp
@@ -41,11 +41,14 @@
 #include "arraybuffer_p.h"
 #include "canvas3dcommon_p.h"
 #include "canvasrendernode_p.h"
+#include "teximage3d_p.h"
 
-#include <QGuiApplication>
+#include <QtGui/QGuiApplication>
 #include <QtGui/QOffscreenSurface>
 #include <QtGui/QOpenGLContext>
 #include <QtGui/QOpenGLFramebufferObject>
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlContext>
 
 static QList<const QQuickWindow *> staticClearList;
 static QHash<Canvas *, QQuickWindow *> canvasWindowList;
@@ -94,7 +97,6 @@ Canvas::Canvas(QQuickItem *parent):
     #endif
     m_samples(0),
     m_devicePixelRatio(1.0f),
-    m_imageLoader(0),
     m_isContextAttribsSet(false),
     m_antialiasFbo(0),
     m_renderFbo(0),
@@ -108,6 +110,7 @@ Canvas::Canvas(QQuickItem *parent):
     // Set contents to false in case we are in qml designer to make component look nice
     m_runningInDesigner = QGuiApplication::applicationDisplayName() == "Qml2Puppet";
     setFlag(ItemHasContents, !m_runningInDesigner);
+
 }
 
 /*!
@@ -375,7 +378,7 @@ CanvasContext *Canvas::getContext(const QString &type, const QVariantMap &option
             m_antialiasFbo = new QOpenGLFramebufferObject(m_initialisedSize, antialiasFboFormat);
         }
 
-        m_context3D = new CanvasContext(m_glContext, m_initialisedSize.width() * m_devicePixelRatio,
+        m_context3D = new CanvasContext(m_glContext, m_offscreenSurface, m_initialisedSize.width() * m_devicePixelRatio,
                                         m_initialisedSize.height() * m_devicePixelRatio);
         m_context3D->setCanvas(this);
         m_context3D->setDevicePixelRatio(m_devicePixelRatio);
@@ -446,33 +449,6 @@ CanvasContext *Canvas::context()
     return m_context3D;
 }
 
-/*!
- * \qmlproperty TextureImageLoader Canvas3D::imageLoader
- * Specifies the texture image loader that can be used to load images and used with the Context3D
- * texture methods.
- * \sa Context3D, TextureImageLoader
- */
-/*!
- * \internal
- */
-CanvasTextureImageLoader *Canvas::imageLoader()
-{
-    if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
-    return m_imageLoader;
-}
-
-void Canvas::setImageLoader(CanvasTextureImageLoader *loader)
-{
-    if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << "(loader: " << loader << ")";
-    if (loader == m_imageLoader)
-        return;
-
-    m_imageLoader = loader;
-    loader->setCanvas(this);
-
-    emit imageLoaderChanged(loader);
-}
-
 /*!
  * \internal
  */
@@ -637,9 +613,10 @@ void Canvas::renderNext()
     if (!isComponentComplete())
         return;
 
-    // Check if there is a image loader ask it to notify any image loads
-    if (m_imageLoader)
-        m_imageLoader->notifyLoadedImages();
+    // Check if any images are loaded and need to be notified while the correct
+    // GL context is current.
+    QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
+    CanvasTextureImageFactory::factory(engine)->notifyLoadedImages();
 
     // Call render in QML JavaScript side
     emit renderGL();
diff --git a/src/canvas3d_p.h b/src/canvas3d_p.h
index ef9c4e3002810ea47e23ef272fd9a44828f1b318..82f00aee28fcafa888d45d4849d2e47e28228099 100644
--- a/src/canvas3d_p.h
+++ b/src/canvas3d_p.h
@@ -49,7 +49,6 @@
 
 #include "canvas3dcommon_p.h"
 #include "context3d_p.h"
-#include "teximage3dloader_p.h"
 
 #include <QQuickItem>
 #include <QQuickWindow>
@@ -65,7 +64,6 @@ class QT_CANVAS3D_EXPORT Canvas : public QQuickItem, QOpenGLFunctions
     Q_PROPERTY(bool logAllCalls READ logAllCalls WRITE setLogAllCalls NOTIFY logAllCallsChanged)
     Q_PROPERTY(bool logAllErrors READ logAllErrors WRITE setLogAllErrors NOTIFY logAllErrorsChanged)
     Q_PROPERTY(float devicePixelRatio READ devicePixelRatio NOTIFY devicePixelRatioChanged)
-    Q_PROPERTY(CanvasTextureImageLoader *imageLoader READ imageLoader WRITE setImageLoader NOTIFY imageLoaderChanged)
 
 public:
     Canvas(QQuickItem *parent = 0);
@@ -81,9 +79,6 @@ public:
 
     GLuint drawFBOHandle();
 
-    CanvasTextureImageLoader *imageLoader();
-    void setImageLoader(CanvasTextureImageLoader *loader);
-
     Q_INVOKABLE CanvasContext *getContext(const QString &name);
     Q_INVOKABLE CanvasContext *getContext(const QString &name, const QVariantMap &options);
     CanvasContext *context();
@@ -97,7 +92,6 @@ signals:
     void needRender();
     void devicePixelRatioChanged(float ratio);
     void animatedChanged(bool animated);
-    void imageLoaderChanged(CanvasTextureImageLoader *loader);
     void logAllCallsChanged(bool logCalls);
     void logAllErrorsChanged(bool logErrors);
     void contextChanged(CanvasContext *context);
@@ -134,7 +128,6 @@ private:
     int m_samples;
     float m_devicePixelRatio;
 
-    CanvasTextureImageLoader *m_imageLoader;
     bool m_runningInDesigner;
     CanvasContextAttributes m_contextAttribs;
     bool m_isContextAttribsSet;
diff --git a/src/context3d.cpp b/src/context3d.cpp
index 4be262bfb681b446bcb37a1c51f3edcb85900b8d..6d351cccae6d8326468ccfe3d6bbe98464695892 100644
--- a/src/context3d.cpp
+++ b/src/context3d.cpp
@@ -76,7 +76,8 @@
  */
 
 // Owned by the SG Render Thread!
-CanvasContext::CanvasContext(QOpenGLContext *context, int width, int height, QObject *parent) :
+CanvasContext::CanvasContext(QOpenGLContext *context, QSurface *surface,
+                             int width, int height, QObject *parent) :
     CanvasAbstractObject(parent),
     QOpenGLFunctions(context),
     m_unpackFlipYEnabled(false),
@@ -88,15 +89,14 @@ CanvasContext::CanvasContext(QOpenGLContext *context, int width, int height, QOb
     m_currentArrayBuffer(0),
     m_currentElementArrayBuffer(0),
     m_currentTexture(0),
-    m_context(0),
+    m_context(context),
+    m_surface(surface),
     m_error(NO_ERROR),
     m_currentFramebuffer(0),
     m_map(EnumToStringMap::newInstance()),
     m_canvas(0),
     m_maxVertexAttribs(0)
 {
-    m_context = context;
-
     int value = 0;
     glGetIntegerv(MAX_VERTEX_ATTRIBS, &value);
     m_maxVertexAttribs = uint(value);
@@ -3159,7 +3159,7 @@ CanvasUniformLocation *CanvasContext::getUniformLocation(CanvasProgram *program,
     }
 
     CanvasUniformLocation *location = new CanvasUniformLocation(index, this);
-    location->insert("name", name);
+    location->setName(name);
     if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__
                                 << "(program:" << program
                                 << ", name:" << name
@@ -4932,9 +4932,7 @@ QVariant CanvasContext::getUniform(CanvasProgram *program, CanvasUniformLocation
         CanvasActiveInfo *info = getActiveUniform(program, locationId);
         int numValues = 4;
 
-        qDebug() << "Context3D::" << __FUNCTION__ << "info->type():" << glEnumToString(info->infoType());
-
-        switch (info->infoType()) {
+        switch (info->type()) {
         case SAMPLER_2D:
             // Intentional flow through
         case SAMPLER_CUBE:
diff --git a/src/context3d_p.h b/src/context3d_p.h
index 20477cfec8313aa4ed215e13a6f3c555b21432d0..344356ed67188a46d814635f56e98d0846911646 100644
--- a/src/context3d_p.h
+++ b/src/context3d_p.h
@@ -939,7 +939,8 @@ public:
     ENUM_AS_PROPERTY(UNPACK_COLORSPACE_CONVERSION_WEBGL)
     ENUM_AS_PROPERTY(BROWSER_DEFAULT_WEBGL)
 
-    CanvasContext(QOpenGLContext *context, int width, int height, QObject *parent = 0);
+    CanvasContext(QOpenGLContext *context, QSurface *surface,
+                  int width, int height, QObject *parent = 0);
     ~CanvasContext();
 
     void setCanvas(Canvas *canvas);
@@ -1168,7 +1169,9 @@ public:
     Q_INVOKABLE void vertexAttrib3fva(uint indx, QVariantList values);
     Q_INVOKABLE void vertexAttrib4fva(uint indx, QVariantList values);
 
-    Q_INVOKABLE int getFramebufferAttachmentParameter(glEnums target, glEnums attachment, glEnums pname);
+    Q_INVOKABLE int getFramebufferAttachmentParameter(glEnums target,
+                                                      glEnums attachment,
+                                                      glEnums pname);
     Q_INVOKABLE int getRenderbufferParameter(glEnums target, glEnums pname);
     Q_INVOKABLE QVariant getTexParameter(glEnums target, glEnums pname);
     Q_INVOKABLE QVariant getUniform(CanvasProgram *program, CanvasUniformLocation *location);
@@ -1215,6 +1218,7 @@ private:
     CanvasBuffer *m_currentElementArrayBuffer;
     CanvasTexture *m_currentTexture;
     QOpenGLContext *m_context;
+    QSurface *m_surface;
     glEnums m_error;
     CanvasFrameBuffer *m_currentFramebuffer;
     CanvasRenderBuffer *m_currentRenderbuffer;
diff --git a/src/qcanvas3d_plugin.cpp b/src/qcanvas3d_plugin.cpp
index 3c1cf1b42d6e03ed54eed73b7a35e6217a9ba83d..703af02cd9458d4ee18113c823c4e67dc00758a3 100644
--- a/src/qcanvas3d_plugin.cpp
+++ b/src/qcanvas3d_plugin.cpp
@@ -45,10 +45,11 @@ void QtCanvas3DPlugin::registerTypes(const char *uri)
                                                       1, 0,
                                                       "Arrays",
                                                       CanvasTypedArrayFactory::type_array_factory_provider);
+    qmlRegisterSingletonType<CanvasTextureImageFactory>(uri,
+                                                        1, 0,
+                                                        "TextureImageFactory",
+                                                        CanvasTextureImageFactory::texture_image_factory_provider);
 
-    qmlRegisterType<CanvasTextureImageLoader>(uri,
-                                              1, 0,
-                                              "TextureImageLoader");
     qmlRegisterType<CanvasTextureImage>(uri,
                                         1, 0,
                                         "TextureImage");
diff --git a/src/qcanvas3d_plugin.h b/src/qcanvas3d_plugin.h
index 72f9d81d2557edf4ab044721dff33391b984b5b8..3cd0e9ea807a8c76bac0389bbc864ef03a0f8e52 100644
--- a/src/qcanvas3d_plugin.h
+++ b/src/qcanvas3d_plugin.h
@@ -62,7 +62,6 @@
 #include "framebuffer3d_p.h"
 #include "renderbuffer3d_p.h"
 #include "shaderprecisionformat_p.h"
-#include "teximage3dloader_p.h"
 #include "activeinfo3d_p.h"
 
 #include <QQmlExtensionPlugin>
@@ -90,14 +89,13 @@ QML_DECLARE_TYPE(CanvasArrayBufferView)
 QML_DECLARE_TYPE(CanvasArrayBuffer)
 QML_DECLARE_TYPE(CanvasTypedArrayFactory)
 QML_DECLARE_TYPE(CanvasTextureImage)
+QML_DECLARE_TYPE(CanvasTextureImageFactory)
 QML_DECLARE_TYPE(CanvasTypedArray)
 QML_DECLARE_TYPE(CanvasContextAttributes)
 QML_DECLARE_TYPE(CanvasFrameBuffer)
 QML_DECLARE_TYPE(CanvasRenderBuffer)
 QML_DECLARE_TYPE(CanvasShaderPrecisionFormat)
-QML_DECLARE_TYPE(CanvasTextureImageLoader)
 QML_DECLARE_TYPE(CanvasActiveInfo)
-
 class QtCanvas3DPlugin : public QQmlExtensionPlugin
 {
     Q_OBJECT
diff --git a/src/src.pro b/src/src.pro
index 1ad338952b2c1da1df9b54659f98e2504109f1fd..52317412a584bdccd1497c760e5fdae0f47f5f3f 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -43,7 +43,6 @@ SOURCES += qcanvas3d_plugin.cpp \
     shader3d.cpp \
     shaderprecisionformat.cpp \
     teximage3d.cpp \
-    teximage3dloader.cpp \
     texture3d.cpp \
     uniformlocation.cpp \
     activeinfo3d.cpp
@@ -78,7 +77,6 @@ HEADERS += qcanvas3d_plugin.h \
     shader3d_p.h \
     shaderprecisionformat_p.h \
     teximage3d_p.h \
-    teximage3dloader_p.h \
     texture3d_p.h \
     uniformlocation_p.h \
     activeinfo3d_p.h
diff --git a/src/teximage3d.cpp b/src/teximage3d.cpp
index 3e9e1b6a7708dba4c1fce482a9e0a2da2d433107..601e3184895f7637e4c56ee36c14936408edcabd 100644
--- a/src/teximage3d.cpp
+++ b/src/teximage3d.cpp
@@ -39,6 +39,108 @@
 
 #include <QJSValueIterator>
 
+static QMap<QQmlEngine *,CanvasTextureImageFactory *>m_qmlEngineToImageFactoryMap;
+
+/*!
+ * \internal
+ */
+CanvasTextureImageFactory::CanvasTextureImageFactory(QQmlEngine *engine, QObject *parent) :
+    QObject(parent)
+{
+    m_qmlEngine = engine;
+}
+
+/*!
+ * \internal
+ */
+CanvasTextureImageFactory::~CanvasTextureImageFactory()
+{
+    m_qmlEngineToImageFactoryMap.remove(m_qmlEngine);
+}
+
+/*!
+ * \qmltype TextureImageFactory
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Create TextureImage elements.
+ *
+ * This static QML type is used for creating TextureImage instances by calling the
+ * TextureImageFactory::newTexImage() function.
+ *
+ * \sa TextureImage
+ */
+
+/*!
+ * \internal
+ */
+QObject *CanvasTextureImageFactory::texture_image_factory_provider(QQmlEngine *engine,
+                                                                   QJSEngine *scriptEngine)
+{
+    Q_UNUSED(scriptEngine)
+    return factory(engine);
+}
+
+/*!
+ * \internal
+ */
+CanvasTextureImageFactory *CanvasTextureImageFactory::factory(QQmlEngine *engine)
+{
+    if (m_qmlEngineToImageFactoryMap.contains(engine))
+        return m_qmlEngineToImageFactoryMap[engine];
+
+    CanvasTextureImageFactory *factory = new CanvasTextureImageFactory(engine);
+    m_qmlEngineToImageFactoryMap[engine] = factory;
+    return factory;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImageFactory::handleImageLoadingStarted(CanvasTextureImage *image)
+{
+    if (m_loadingImagesList.contains(image))
+        return;
+
+    m_loadingImagesList << image;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImageFactory::notifyLoadedImages()
+{
+    if (!m_loadingImagesList.size())
+        return;
+
+    QMutableListIterator<CanvasTextureImage *> it(m_loadingImagesList);
+    while (it.hasNext()) {
+        CanvasTextureImage *image = it.next();
+        if (image->imageState() == CanvasTextureImage::LOADING_FINISHED) {
+            m_loadingImagesList.removeOne(image);
+            image->emitImageLoaded();
+
+        } else if (image->imageState() == CanvasTextureImage::LOADING_ERROR) {
+            m_loadingImagesList.removeOne(image);
+            image->emitImageLoadingError();
+        }
+    }
+}
+
+/*!
+ * \qmlmethod TextureImage TextureImageFactory::newTexImage()
+ * Returns a new empty TextureImage.
+ */
+/*!
+ * \internal
+ */
+CanvasTextureImage *CanvasTextureImageFactory::newTexImage()
+{
+    CanvasTextureImage *newImg = new CanvasTextureImage(this);
+    connect(newImg, &CanvasTextureImage::imageLoadingStarted,
+            this, &CanvasTextureImageFactory::handleImageLoadingStarted);
+    return newImg;
+}
+
 /*!
  * \qmltype TextureImage
  * \since QtCanvas3D 1.0
@@ -46,17 +148,35 @@
  * \brief Contains a texture image.
  *
  * An uncreatable QML type that contains a texture image created by calling
- * TextureImageLoader::loadImage().
+ * TextureImageFactory::newTexImage() and settings the \c src of the image.
  *
- * \sa TextureImageLoader
+ * \sa TextureImageFactory
  */
 
 /*!
  * \internal
  */
-CanvasTextureImage::CanvasTextureImage(QObject *parent) :
+CanvasTextureImage::CanvasTextureImage(CanvasTextureImageFactory *parent) :
     CanvasAbstractObject(parent),
-    m_requestId(0),
+    m_networkAccessManager(0),
+    m_state(INITIALIZED),
+    m_errorString(""),
+    m_pixelCache(0),
+    m_pixelCacheFormat(CanvasContext::NONE),
+    m_pixelCacheFlipY(false),
+    m_parentFactory(parent)
+{
+    m_networkAccessManager = new QNetworkAccessManager(this);
+    QObject::connect(m_networkAccessManager, &QNetworkAccessManager::finished,
+                     this, &CanvasTextureImage::handleReply);
+}
+
+/*!
+ * \internal
+ */
+CanvasTextureImage::CanvasTextureImage(const QImage &source, int width, int height, QObject *parent) :
+    CanvasAbstractObject(parent),
+    m_networkAccessManager(0),
     m_state(INITIALIZED),
     m_errorString(""),
     m_pixelCache(0),
@@ -66,6 +186,9 @@ CanvasTextureImage::CanvasTextureImage(QObject *parent) :
     m_networkAccessManager = new QNetworkAccessManager(this);
     QObject::connect(m_networkAccessManager, &QNetworkAccessManager::finished,
                      this, &CanvasTextureImage::handleReply);
+
+    m_image = source.scaled(width, height);
+    setImageState(LOADING_FINISHED);
 }
 
 /*!
@@ -78,13 +201,21 @@ CanvasTextureImage::~CanvasTextureImage()
 }
 
 /*!
- * \qmlproperty url TextureImage::source()
- * Contains the url to the image.
+ * \internal
+ */
+CanvasTextureImage *CanvasTextureImage::create()
+{
+    return new CanvasTextureImage();
+}
+
+/*!
+ * \qmlproperty url TextureImage::src()
+ * Contains the url source where the image data is loaded from.
  */
 /*!
  * \internal
  */
-const QUrl &CanvasTextureImage::source() const
+const QUrl &CanvasTextureImage::src() const
 {
     return m_source;
 }
@@ -92,13 +223,13 @@ const QUrl &CanvasTextureImage::source() const
 /*!
  * \internal
  */
-void CanvasTextureImage::setSource(const QUrl &url)
+void CanvasTextureImage::setSrc(const QUrl &url)
 {
     if (url == m_source)
         return;
 
     m_source = url;
-    emit sourceChanged(m_source);
+    emit srcChanged(m_source);
 
     load();
 }
@@ -115,6 +246,22 @@ ulong CanvasTextureImage::id()
     return ulong(this);
 }
 
+/*!
+ * \internal
+ */
+void CanvasTextureImage::emitImageLoaded()
+{
+    emit imageLoaded(this);
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImage::emitImageLoadingError()
+{
+    emit imageLoadingFailed(this);
+}
+
 /*!
  * \internal
  */
@@ -132,6 +279,8 @@ void CanvasTextureImage::load()
         return;
 
     setImageState(LOADING);
+    emit imageLoadingStarted(this);
+
     QNetworkRequest request(m_source);
     m_networkAccessManager->get(request);
 }
@@ -154,9 +303,9 @@ QString CanvasTextureImage::errorString() const
 void CanvasTextureImage::handleReply(QNetworkReply *reply)
 {
     if (reply->error() != QNetworkReply::NoError) {
-        setImageState(LOADING_ERROR);
         m_errorString = reply->errorString();
         emit errorStringChanged(m_errorString);
+        setImageState(LOADING_ERROR);
         return;
     }
 
@@ -168,7 +317,7 @@ void CanvasTextureImage::handleReply(QNetworkReply *reply)
 /*!
  * \internal
  */
-QImage & CanvasTextureImage::getImage()
+QImage &CanvasTextureImage::getImage()
 {
     return m_image;
 }
@@ -176,7 +325,7 @@ QImage & CanvasTextureImage::getImage()
 /*!
  * \internal
  */
-QVariant *CanvasTextureImage::anything()
+QVariant *CanvasTextureImage::anything() const
 {
     return m_anyValue;
 }
@@ -201,7 +350,7 @@ void CanvasTextureImage::setAnything(QVariant *value)
 /*!
  * \internal
  */
-CanvasTextureImage::TextureImageState CanvasTextureImage::imageState()
+CanvasTextureImage::TextureImageState CanvasTextureImage::imageState() const
 {
     return m_state;
 }
@@ -224,7 +373,7 @@ void CanvasTextureImage::setImageState(TextureImageState state)
 /*!
  * \internal
  */
-int CanvasTextureImage::width()
+int CanvasTextureImage::width() const
 {
     if (m_state != LOADING_FINISHED)
         return 0;
@@ -239,7 +388,7 @@ int CanvasTextureImage::width()
 /*!
  * \internal
  */
-int CanvasTextureImage::height()
+int CanvasTextureImage::height() const
 {
     if (m_state != LOADING_FINISHED)
         return 0;
@@ -247,21 +396,6 @@ int CanvasTextureImage::height()
     return m_image.height();
 }
 
-/*!
- * \internal
- */
-void CanvasTextureImage::emitImageLoadedSGRT()
-{
-}
-
-/*!
- * \internal
- */
-void CanvasTextureImage::emitImageLoadingErrorSGRT()
-{
-}
-
-
 /*!
  * \internal
  */
@@ -352,6 +486,21 @@ uchar *CanvasTextureImage::convertToFormat(CanvasContext::glEnums format, bool f
     return 0;
 }
 
+/*!
+ * \qmlmethod TextureImage TextureImage::resize(int width, int height)
+ * Returns a copy of the texture image resized to the given \a width and \a height.
+ */
+/*!
+ * \internal
+ */
+CanvasTextureImage *CanvasTextureImage::resize(int width, int height)
+{
+    if (m_state != LOADING_FINISHED)
+        return 0;
+
+    return new CanvasTextureImage(m_image, width, height);
+}
+
 /*!
  * \internal
  */
diff --git a/src/teximage3d_p.h b/src/teximage3d_p.h
index c2824c39e0c9b8554bac069be8657b2e9a6202b6..de93a7b347eb7ed6548eb291ab553e228fabfb43 100644
--- a/src/teximage3d_p.h
+++ b/src/teximage3d_p.h
@@ -50,16 +50,36 @@
 #include "context3d_p.h"
 #include "abstractobject3d_p.h"
 
-#include <QUrl>
-#include <QNetworkAccessManager>
-#include <QImage>
-#include <QNetworkReply>
+#include <QtCore/QUrl>
+#include <QtGui/QImage>
+#include <QtNetwork/QNetworkAccessManager>
+#include <QtNetwork/QNetworkReply>
+
+class CanvasTextureImageFactory : public QObject
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(CanvasTextureImageFactory)
+
+public:
+    static QObject *texture_image_factory_provider(QQmlEngine *engine, QJSEngine *scriptEngine);
+    static CanvasTextureImageFactory *factory(QQmlEngine *engine);
+    explicit CanvasTextureImageFactory(QQmlEngine *engine, QObject *parent = 0);
+    ~CanvasTextureImageFactory();
+
+    void handleImageLoadingStarted(CanvasTextureImage *image);
+    void notifyLoadedImages();
+
+    Q_INVOKABLE CanvasTextureImage* newTexImage();
+private:
+    QQmlEngine *m_qmlEngine;
+    QList<CanvasTextureImage *> m_loadingImagesList;
+};
 
 class CanvasTextureImage : public CanvasAbstractObject
 {
     Q_OBJECT
     Q_DISABLE_COPY(CanvasTextureImage)
-    Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+    Q_PROPERTY(QUrl src READ src WRITE setSrc NOTIFY srcChanged)
     Q_PROPERTY(TextureImageState imageState READ imageState NOTIFY imageStateChanged)
     Q_PROPERTY(int width READ width NOTIFY widthChanged)
     Q_PROPERTY(int height READ height NOTIFY heightChanged)
@@ -75,45 +95,50 @@ public:
         LOADING_ERROR
     };
 
-    explicit CanvasTextureImage(QObject *parent = 0);
+    Q_INVOKABLE explicit CanvasTextureImage(CanvasTextureImageFactory *parent = 0);
     virtual ~CanvasTextureImage();
 
+    Q_INVOKABLE CanvasTextureImage *create();
     Q_INVOKABLE ulong id();
+    Q_INVOKABLE CanvasTextureImage *resize(int width, int height);
 
-    QVariant *anything();
+    QVariant *anything() const;
     void setAnything(QVariant *value);
 
-    const QUrl &source() const;
-    void setSource(const QUrl &src);
-    TextureImageState imageState();
-    int width();
-    int height();
+    const QUrl &src() const;
+    void setSrc(const QUrl &src);
+    TextureImageState imageState() const;
+    int width() const;
+    int height() const;
     QString errorString() const;
 
+    void emitImageLoaded();
+    void emitImageLoadingError();
+
     void load();
     void handleReply(QNetworkReply *reply);
     QImage &getImage();
     uchar *convertToFormat(CanvasContext::glEnums format, bool flipY = false);
 
-    void emitImageLoadedSGRT();
-    void emitImageLoadingErrorSGRT();
-
     friend QDebug operator<< (QDebug d, const CanvasTextureImage *buffer);
 
 private:
     void setImageState(TextureImageState state);
+    explicit CanvasTextureImage(const QImage &source, int width, int height, QObject *parent = 0);
 
 signals:
-    void sourceChanged(QUrl source);
+    void srcChanged(QUrl source);
     void imageStateChanged(TextureImageState state);
     void widthChanged(int width);
     void heightChanged(int height);
     void errorStringChanged(const QString errorString);
     void anythingChanged(QVariant *value);
+    void imageLoadingStarted(CanvasTextureImage *image);
+    void imageLoaded(CanvasTextureImage *image);
+    void imageLoadingFailed(CanvasTextureImage *image);
 
 private:
     QNetworkAccessManager *m_networkAccessManager;
-    int m_requestId;
     QImage m_image;
     QUrl m_source;
     TextureImageState m_state;
@@ -123,6 +148,7 @@ private:
     bool m_pixelCacheFlipY;
     QImage m_glImage;
     QVariant *m_anyValue;
+    CanvasTextureImageFactory *m_parentFactory;
 };
 
 #endif // TEXIMAGE3D_P_H
diff --git a/src/teximage3dloader.cpp b/src/teximage3dloader.cpp
deleted file mode 100644
index 4a5e2d8ddd538bed9e23bbde6c922c08d75acf7b..0000000000000000000000000000000000000000
--- a/src/teximage3dloader.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtCanvas3D module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Digia.  For licensing terms and
-** conditions see http://qt.digia.com/licensing.  For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free 
-** Software Foundation and appearing in the file LICENSE.GPL included in 
-** the packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "teximage3dloader_p.h"
-#include "canvas3d_p.h"
-#include "canvas3dcommon_p.h"
-
-/*!
- * \qmltype TextureImageLoader
- * \since QtCanvas3D 1.0
- * \ingroup qtcanvas3d-qml-types
- * \brief Texture image loader.
- *
- * Texture image loader that allows loading of 2D images to be used as input of Context3D
- * texture upload calls.
- *
- * \sa Context3D, TextureImage, {QML Canvas 3D QML Types}
- */
-
-/*!
- * \qmlproperty TextureImage TextureImageLoader::image
- * A read-only property holding the last loaded or failed texture. Should be called on receiving the
- * imageLoaded or imageLoadingFailed signal.
- */
-
-/*!
- * \qmlsignal void TextureImageLoader::imageLoaded()
- * Emitted when a texture has been successfully loaded.
- */
-
-/*!
- * \qmlsignal void TextureImageLoader::imageLoadingFailed()
- * Emitted when a texture loading has failed.
- */
-
-/*!
- * \internal
- */
-CanvasTextureImageLoader::CanvasTextureImageLoader(QObject *parent) :
-    CanvasAbstractObject(parent),
-    m_logAllCalls(false),
-    m_logAllErrors(true),
-    m_image(0),
-    m_canvas(0)
-{
-}
-
-/*!
- * \internal
- */
-CanvasTextureImageLoader::~CanvasTextureImageLoader()
-{
-}
-
-/*!
- * \internal
- */
-void CanvasTextureImageLoader::setLogAllCalls(bool logCalls)
-{
-    if (m_logAllCalls != logCalls) {
-        m_logAllCalls = logCalls;
-        emit logAllCallsChanged(logCalls);
-    }
-}
-
-/*!
- * \qmlproperty bool TextureImageLoader::logAllCalls
- * Specifies if all TextureImageLoader method calls (including internal ones) are logged to the
- * console.
- * Defaults to \c{false}.
- */
-/*!
- * \internal
- */
-bool CanvasTextureImageLoader::logAllCalls() const
-{
-    return m_logAllCalls;
-}
-
-/*!
- * \internal
- */
-void CanvasTextureImageLoader::setLogAllErrors(bool logErrors)
-{
-    if (m_logAllErrors != logErrors) {
-        m_logAllErrors = logErrors;
-        emit logAllErrorsChanged(logErrors);
-    }
-}
-
-/*!
- * \qmlproperty bool TextureImageLoader::logAllErrors
- * Specifies if all TextureImageLoader errors are logged to the console. Defaults to \c{true}.
- */
-/*!
- * \internal
- */
-bool CanvasTextureImageLoader::logAllErrors() const
-{
-    return m_logAllErrors;
-}
-
-/*!
- * \internal
- */
-void CanvasTextureImageLoader::emitImageLoaded(CanvasTextureImage *textureImage)
-{
-    if (m_logAllCalls) qDebug() << "TexImage3DLoader::" << __FUNCTION__;
-    m_image = textureImage;
-    emit imageLoaded();
-}
-
-/*!
- * \internal
- */
-void CanvasTextureImageLoader::emitImageLoadingError(CanvasTextureImage *textureImage)
-{
-    if (m_logAllCalls) qDebug() << "TexImage3DLoader::" << __FUNCTION__;
-    m_image = textureImage;
-    emit imageLoadingFailed();
-}
-
-/*!
- * \qmlmethod TextureImage TextureImageLoader::loadImage(url url)
- * Loads an image located in \a url and creates a TextureImage of it.
- */
-/*!
- * \internal
- */
-CanvasTextureImage *CanvasTextureImageLoader::loadImage(const QUrl &url)
-{
-    if (m_logAllCalls) qDebug() << "TexImage3DLoader::" << __FUNCTION__ << "(url:" << url << ")";
-
-    if (!m_canvas && m_logAllErrors) qDebug() << "TexImage3DLoader::" << __FUNCTION__ << ": ERROR tried to load image before setting as property of a canvas.";
-
-    CanvasContext *context = m_canvas->context();
-    if (!context) {
-        if (m_logAllErrors) qDebug() << "TexImage3DLoader::" << __FUNCTION__ << ": ERROR tried to load image before GL context was created.";
-        return 0;
-    }
-
-    CanvasTextureImage *img;
-    if (m_urlToImageMap.contains(url) && m_urlToImageMap.values(url).size() != 0) {
-        img = m_urlToImageMap[url];
-    } else {
-        img = new CanvasTextureImage(context);
-        m_urlToImageMap[url] = img;
-        m_loadingImagesList << img;
-        img->setSource(url);
-    }
-
-    return img;
-}
-
-/*!
- * \internal
- */
-void CanvasTextureImageLoader::setCanvas(Canvas *canvas)
-{
-    m_canvas = canvas;
-}
-
-/*!
- * \internal
- */
-void CanvasTextureImageLoader::notifyLoadedImages()
-{
-    if (!m_loadingImagesList.size())
-        return;
-
-    if (m_logAllCalls) qDebug() << "TexImage3DLoader::" << __FUNCTION__ << "(m_loadingImagesList.size():"<<m_loadingImagesList.size()<<")";
-
-    QMutableListIterator<CanvasTextureImage *> it(m_loadingImagesList);
-    while (it.hasNext()) {
-        CanvasTextureImage *loader = it.next();
-        if (loader->imageState() == CanvasTextureImage::LOADING_FINISHED) {
-            m_loadingImagesList.removeOne(loader);
-            emitImageLoaded(loader);
-        } else if (loader->imageState() == CanvasTextureImage::LOADING_ERROR) {
-            m_loadingImagesList.removeOne(loader);
-            emitImageLoadingError(loader);
-        }
-    }
-}
diff --git a/src/teximage3dloader_p.h b/src/teximage3dloader_p.h
deleted file mode 100644
index 6df88702ec346e379614af2a6483c69a233b3901..0000000000000000000000000000000000000000
--- a/src/teximage3dloader_p.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtCanvas3D module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Digia.  For licensing terms and
-** conditions see http://qt.digia.com/licensing.  For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free 
-** Software Foundation and appearing in the file LICENSE.GPL included in 
-** the packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-//  W A R N I N G
-//  -------------
-//
-// This file is not part of the QtCanvas3D API.  It exists purely as an
-// implementation detail.  This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-
-#ifndef TEXIMAGE3DLOADER_P_H
-#define TEXIMAGE3DLOADER_P_H
-
-#include "abstractobject3d_p.h"
-#include "teximage3d_p.h"
-
-class Canvas;
-
-class CanvasTextureImageLoader : public CanvasAbstractObject
-{
-    Q_OBJECT
-    Q_PROPERTY(CanvasTextureImage* image READ image)
-    Q_PROPERTY(bool logAllCalls READ logAllCalls WRITE setLogAllCalls NOTIFY logAllCallsChanged)
-    Q_PROPERTY(bool logAllErrors READ logAllErrors WRITE setLogAllErrors NOTIFY logAllErrorsChanged)
-
-public:
-    explicit CanvasTextureImageLoader(QObject *parent = 0);
-    virtual ~CanvasTextureImageLoader();
-
-    Q_INVOKABLE CanvasTextureImage *loadImage(const QUrl &url);
-
-    void setLogAllCalls(bool logCalls);
-    bool logAllCalls() const;
-    void setLogAllErrors(bool logErrors);
-    bool logAllErrors() const;
-    void setCanvas(Canvas *canvas);
-    void notifyLoadedImages();
-    void emitImageLoaded(CanvasTextureImage *textureImage);
-    void emitImageLoadingError(CanvasTextureImage *textureImage);
-    inline CanvasTextureImage *image() { return m_image; }
-
-signals:
-    void imageLoaded();
-    void imageLoadingFailed();
-    void logAllCallsChanged(bool logCalls);
-    void logAllErrorsChanged(bool logErrors);
-
-private:
-    bool m_logAllCalls;
-    bool m_logAllErrors;
-    QMap<QUrl, CanvasTextureImage *> m_urlToImageMap;
-    QList<CanvasTextureImage *> m_loadingImagesList;
-    CanvasTextureImage *m_image;
-    Canvas *m_canvas;
-};
-
-#endif // TEXIMAGE3DLOADER_P_H
diff --git a/src/typedarrayfactory.cpp b/src/typedarrayfactory.cpp
index 78e7a4d663afc0772c829dabaceb4ca401e085ef..8fd8fcccc3c3342439ad7c4aaf6f577e821d7140 100644
--- a/src/typedarrayfactory.cpp
+++ b/src/typedarrayfactory.cpp
@@ -574,16 +574,3 @@ CanvasUint8ClampedArray *CanvasTypedArrayFactory::newUint8ClampedArray(CanvasArr
     return new CanvasUint8ClampedArray(buffer, byteOffset);
 }
 
-/*!
- * \qmlmethod TextureImage Arrays::newTexImage()
- * Returns a new empty TextureImage.
- */
-/*!
- * \internal
- */
-CanvasTextureImage *CanvasTypedArrayFactory::newTexImage()
-{
-    CanvasTextureImage *newImg = new CanvasTextureImage();
-    if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "():"<<newImg;
-    return newImg;
-}
diff --git a/src/typedarrayfactory_p.h b/src/typedarrayfactory_p.h
index f36bf296b4fbe02ac4b17ea22b616cca5c8d8996..bd9d30d32f715ee3951b0d3a35b851c38baf703c 100644
--- a/src/typedarrayfactory_p.h
+++ b/src/typedarrayfactory_p.h
@@ -130,8 +130,6 @@ public:
     Q_INVOKABLE CanvasUint8ClampedArray* newUint8ClampedArray(QVariantList array);
     Q_INVOKABLE CanvasUint8ClampedArray* newUint8ClampedArray(CanvasArrayBuffer *buffer,
                                                               unsigned long byteOffset);
-
-    Q_INVOKABLE CanvasTextureImage* newTexImage();
 };
 
 #endif // TYPEDARRAYFACTORY_P_H