diff --git a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp
index 1ab280c03ffb0a675d72f97270c869e258af2ca7..6df014563a8991e464e02eb10f210c079913d3cb 100644
--- a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp
+++ b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp
@@ -96,9 +96,10 @@ typedef struct {
 	std::vector<VertexGroup> vertexGroups;
 	std::vector<Material> materials;
 	// FIXME Dirty hack to get one(!) texture for our cube demo
+	// hardcoded to always have RGBA channel layout
 	struct {
 		int w, h, ch;	// width, height and channels of image
-		void *img;	// raw data, free after use (deal with it)
+		uint8_t *img;	// raw bytes, free after use (deal with it)
 	} texture_hack;
 } Mesh;
 
diff --git a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp
index c0ce049646389994bdee68c84c5c6e686755a1e2..bedd86ca593b87326f273b36011d797f4270e944 100644
--- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp
+++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp
@@ -3,6 +3,9 @@
 #include <string.h>	// memcpy(3)
 #include <stdlib.h>	// calloc(3)
 #include <fx/gltf.h>
+#define STB_IMAGE_IMPLEMENTATION
+#define STBI_ONLY_JPEG
+#include <stb_image.h>
 
 namespace vkcv::asset {
 
@@ -170,24 +173,30 @@ int loadMesh(const std::string &path, Mesh &mesh) {
 	
 	std::vector<Material> materials;
 
+	mesh = {
+		object.meshes[0].name,
+		vertexGroups,
+		materials,
+		0, 0, 0, NULL
+	};
+
 	// FIXME HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK
 	// fail quietly if there is no texture
 	if (object.textures.size()) {
 		const std::string mime_type("image/jpeg");
 		const fx::gltf::Texture &tex = object.textures[0];
 		const fx::gltf::Image &img = object.images[tex.source];
+#ifdef DEBUG
 		printf("texture name=%s sampler=%u source=%u\n",
 				tex.name.c_str(), tex.sampler, tex.source);
-		printf("image   name=%s uri=%s mime=%s\n",
-				img.name.c_str(), img.uri.c_str(),
-				img.mimeType.c_str());
-		// URI is in img.uri
-
-		// TODO decode using stbimage lib and store in mesh.texture
+		printf("image   name=%s uri=%s mime=%s\n", img.name.c_str(),
+				img.uri.c_str(), img.mimeType.c_str());
+#endif
+		mesh.texture_hack.img = stbi_load(img.uri.c_str(),
+				&mesh.texture_hack.w, &mesh.texture_hack.h,
+				&mesh.texture_hack.ch, 4);
 	}
 	// FIXME HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK
-
-	mesh = { object.meshes[0].name, vertexGroups, materials };
 	return 1;
 }