diff --git a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp
index 6ddaf136ae96eadd0bf219dfb2d614a606d0cb0f..c677f600e0a0304f26835c685d9ab10545433ad5 100644
--- a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp
+++ b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp
@@ -47,6 +47,8 @@ namespace vkcv::asset {
 enum PrimitiveMode { POINTS=0, LINES, LINELOOP, LINESTRIP, TRIANGLES, TRIANGLESTRIP, TRIANGLEFAN };
 /* With these enums, 0 is reserved to signal uninitialized or invalid data. */
 enum PrimitiveType { POSITION=1, NORMAL, TEXCOORD_0 };
+/* The indices in the index buffer can be of different bit width. */
+enum IndexType { UINT32=0, UINT16=1, UINT8=2 };
 
 typedef struct {
 	// TODO not yet needed for the first (unlit) triangle
@@ -64,26 +66,18 @@ typedef struct {
 
 /* This struct represents one (possibly the only) part of a mesh. There is
  * always one vertexBuffer and zero or one indexBuffer (indexed rendering is
- * common but not always used). If there is no indexBuffer, this is indicated
- * by indexBuffer.data being NULL.
- * Each vertex buffer can have one or more vertex attributes.
- * Note that the indexBuffer and vertexBuffer might be pointing to the same
- * block of memory.
- * 
- * TODO For now, the caller of loadMesh() has to free this memory when they are
- * done, but since this is not generally good practice in C++, this behaviour
- * will likely be changed later. */
+ * common but not always used). If there is no index buffer, this is indicated
+ * by indexBuffer.data being empty. Each vertex buffer can have one or more
+ * vertex attributes. */
 typedef struct {
 	enum PrimitiveMode mode;	// draw as points, lines or triangle?
 	size_t numIndices, numVertices;
 	struct {
-		void *data;		// binary data of the index buffer
-		size_t byteLength;	// length of the index buffer
-		uint32_t byteOffset;	// offset into the buffer in bytes
+		enum IndexType type;	// data type of the indices
+		std::vector<uint8_t> data; // binary data of the index buffer
 	} indexBuffer;
 	struct {
-		void *data;		// the binary data of the buffer
-		size_t byteLength;	// the length of the entire buffer in bytes
+		std::vector<uint8_t> data; // binary data of the vertex buffer
 		std::vector<VertexAttribute> attributes;
 	} vertexBuffer;
 	struct { float x, y, z; } min;	// bounding box lower left
diff --git a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp
index 9e55ff0104c162e40d4584c387f28a8413d62648..3bdc45449d66d8a41e64ac2b5b9f14ed18636651 100644
--- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp
+++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp
@@ -146,58 +146,60 @@ namespace vkcv::asset {
         const fx::gltf::Accessor &indexAccessor = object.accessors[objectPrimitive.indices];
         const fx::gltf::BufferView &indexBufferView = object.bufferViews[indexAccessor.bufferView];
         const fx::gltf::Buffer &indexBuffer = object.buffers[indexBufferView.buffer];
-        void *indexBufferData = calloc(1, indexBuffer.byteLength);
-	if (memcpy(indexBufferData, indexBuffer.data.data(), indexBuffer.byteLength) == NULL) {
-		fprintf(stderr, "ERROR copying buffer data.\n");
-		return 0;
+	std::vector<uint8_t> indexBufferData;
+	indexBufferData.resize(indexBufferView.byteLength);
+	{
+		const size_t off = indexBufferView.byteOffset;
+		const void *const ptr = ((char*)indexBuffer.data.data()) + off;
+		if (!memcpy(indexBufferData.data(), ptr, indexBufferView.byteLength)) {
+			std::cerr << "ERROR copying index buffer data.\n";
+			return 0;
+		}
 	}
 
         // vertexBuffer
         fx::gltf::BufferView& vertexBufferView = object.bufferViews[posAccessor.bufferView];
         fx::gltf::Buffer& vertexBuffer = object.buffers[vertexBufferView.buffer];
-        void *vertexBufferData;
-
-        // check whether only one buffer is used
-        if (indexBufferView.buffer == vertexBufferView.buffer){
-            std::cout << "It's just one Buffer, let's be efficient!" << std::endl;
-            vertexBufferData = indexBufferData;
-        } else {
-            std::cout << "No luck, different Buffers :(" << std::endl;
-	    vertexBufferData = calloc(1, vertexBuffer.byteLength);
-	    if (memcpy(vertexBufferData, vertexBuffer.data.data(), vertexBuffer.byteLength) == NULL) {
-		    fprintf(stderr, "ERROR copying buffer data.\n");
-		    return 0;
-	    }
-        }
+	std::vector<uint8_t> vertexBufferData;
+	vertexBufferData.resize(vertexBufferView.byteLength);
+	{
+		const size_t off = vertexBufferView.byteOffset;
+		const void *const ptr = ((char*)vertexBuffer.data.data()) + off;
+		if (!memcpy(vertexBufferData.data(), ptr, vertexBufferView.byteLength)) {
+			fprintf(stderr, "ERROR copying vertex buffer data.\n");
+			return 0;
+		}
+	}
 
-        // fill vertex groups vector
-	const size_t numVertexGroups = 1;	// TODO get value from fx-gltf
+	IndexType indexType;
+	switch(indexAccessor.componentType) {
+	case fx::gltf::Accessor::ComponentType::UnsignedByte:
+		indexType = UINT8; break;
+	case fx::gltf::Accessor::ComponentType::UnsignedShort:
+		indexType = UINT16; break;
+	case fx::gltf::Accessor::ComponentType::UnsignedInt:
+		indexType = UINT32; break;
+	default:
+		std::cerr << "ERROR: Index type not supported: " <<
+			static_cast<uint16_t>(indexAccessor.componentType) <<
+			std::endl;
+		return 0;
+	}
+
+	const size_t numVertexGroups = objectMesh.primitives.size();
 	vertexGroups.resize(numVertexGroups);
-        vertexGroups.back() = {
-                static_cast<PrimitiveMode>(objectPrimitive.mode), // mode
-                object.accessors[objectPrimitive.indices].count, // num indices
-                posAccessor.count, // num vertices
-                { //index buffer
-                        indexBufferData,
-                        indexBufferView.byteLength,
-                        indexBufferView.byteOffset
-                },
-                { //vertex buffer
-                        vertexBufferData,
-                        vertexBufferView.byteLength,
-                        vertexAttributes
-                },
+	vertexGroups[0] = {
+		static_cast<PrimitiveMode>(objectPrimitive.mode),// mode
+		object.accessors[objectPrimitive.indices].count, // numIndices
+		posAccessor.count,				 // numVertices
+		{ indexType, indexBufferData },
+		{ vertexBufferData, vertexAttributes },
                 {posAccessor.min[0], posAccessor.min[1], posAccessor.min[2]}, // bounding box min
                 {posAccessor.max[0], posAccessor.max[1], posAccessor.max[2]}, // bounding box max
                 static_cast<uint8_t>(objectPrimitive.material) // material index
         };
 
-        // fill mesh struct
-        mesh = {
-                object.meshes[0].name,
-                vertexGroups,
-                materials
-        };
+        mesh = { object.meshes[0].name, vertexGroups, materials };
 
 		// Finally return 1 to signal that all is fine
 		return 1;
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index 769fe9f36a7ebcdbb8027f5548e826ef6c4a8ea1..3a1b5d1af8b3d5e354594086385360854052a105 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -30,11 +30,10 @@ int main(int argc, const char** argv) {
 		const auto &vg = mesh.vertexGroups[i];
 		printf("primitive mode: %d (%s)\n", vg.mode,
 				primitive_modes[vg.mode]);
-		printf("index buffer: %lu bytes for %lu indices (offset into "
-				"%p is %u)\n", vg.indexBuffer.byteLength,
-				vg.numIndices, vg.indexBuffer.data,
-				vg.indexBuffer.byteOffset);
-		buf = (char*)vg.indexBuffer.data + vg.indexBuffer.byteOffset;
+		printf("index buffer: %lu bytes for %lu indices (%p)\n",
+				vg.indexBuffer.data.size(), vg.numIndices,
+				vg.indexBuffer.data.data());
+		buf = (char*)vg.indexBuffer.data.data();
 		uint16_t *indices = (uint16_t*)buf;
 		printf("\tindices: ");
 		for (size_t j = 0; j < vg.numIndices; j++) {
@@ -43,9 +42,9 @@ int main(int argc, const char** argv) {
 		printf("\n");
 		printf("vertex buffer: %lu bytes for %lu vertices with %lu "
 				"attributes (starting at %p)\n",
-				vg.vertexBuffer.byteLength, vg.numVertices,
+				vg.vertexBuffer.data.size(), vg.numVertices,
 				vg.vertexBuffer.attributes.size(),
-				vg.vertexBuffer.data);
+				vg.vertexBuffer.data.data());
 	}
 	
 	return 0;