diff --git a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp index f07ddc7136931f38e4eed0ce49fded84a20fdff2..896a8c9e388d7684b0416bfe0f7e58549859a951 100644 --- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp +++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp @@ -176,17 +176,21 @@ int loadMesh(const std::string &path, Mesh &mesh) { std::vector<Texture> textures; std::vector<Sampler> samplers; + std::vector<int> vertexGroupsIndex; + + for(int i = 0; i < numVertexGroups; i++){ + vertexGroupsIndex.push_back(i); + } + + mesh = { object.meshes[0].name, - vertexGroups, - materials, - textures, - samplers, + vertexGroupsIndex, }; // FIXME HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK // fail quietly if there is no texture - mesh.textures.reserve(1); + textures.reserve(1); if (object.textures.size()) { const std::string mime_type("image/jpeg"); const fx::gltf::Texture &tex = object.textures[0]; @@ -220,7 +224,7 @@ int loadMesh(const std::string &path, Mesh &mesh) { } free(data); - mesh.textures.push_back({ + textures.push_back({ 0, static_cast<uint8_t>(c), static_cast<uint16_t>(w), static_cast<uint16_t>(h), imgdata @@ -230,4 +234,206 @@ int loadMesh(const std::string &path, Mesh &mesh) { return 1; } +int loadScene(const std::string &path, Scene &scene){ + fx::gltf::Document sceneObjects; + + try { + if (path.rfind(".glb", (path.length()-4)) != std::string::npos) { + sceneObjects = fx::gltf::LoadFromBinary(path); + } else { + sceneObjects = fx::gltf::LoadFromText(path); + } + } catch (const std::system_error &err) { + print_what(err, path); + return 0; + } catch (const std::exception &e) { + print_what(e, path); + return 0; + } + size_t pos = path.find_last_of("/"); + auto dir = path.substr(0, pos); + + // file has to contain at least one mesh + if (sceneObjects.meshes.size() == 0) return 0; + + + fx::gltf::Accessor posAccessor; + std::vector<VertexAttribute> vertexAttributes; + std::vector<Material> materials; + std::vector<Texture> textures; + std::vector<Sampler> samplers; + std::vector<Mesh> meshes; + std::vector<VertexGroup> vertexGroups; + std::vector<int> vertexGroupsIndex; + int groupCount = 0; + + Mesh mesh = {}; + + + for(int i = 0; i < sceneObjects.meshes.size(); i++){ + fx::gltf::Mesh const &objectMesh = sceneObjects.meshes[i]; + + for(int j = 0; j < objectMesh.primitives.size(); j++){ + fx::gltf::Primitive const &objectPrimitive = objectMesh.primitives[j]; + vertexAttributes.reserve(objectPrimitive.attributes.size()); + + for (auto const & attrib : objectPrimitive.attributes) { + + fx::gltf::Accessor accessor = sceneObjects.accessors[attrib.second]; + VertexAttribute attribute; + + if (attrib.first == "POSITION") { + attribute.type = PrimitiveType::POSITION; + posAccessor = accessor; + } else if (attrib.first == "NORMAL") { + attribute.type = PrimitiveType::NORMAL; + } else if (attrib.first == "TEXCOORD_0") { + attribute.type = PrimitiveType::TEXCOORD_0; + } else { + return 0; + } + + attribute.offset = sceneObjects.bufferViews[accessor.bufferView].byteOffset; + attribute.length = sceneObjects.bufferViews[accessor.bufferView].byteLength; + attribute.stride = sceneObjects.bufferViews[accessor.bufferView].byteStride; + // TODO use enums instead of only integer representation for types (defined in VertexLayout.hpp) + attribute.componentType = static_cast<uint16_t>(accessor.componentType); + + if (convertTypeToInt(accessor.type) != 10) { + attribute.componentCount = convertTypeToInt(accessor.type); + } else { + return 0; + } + + vertexAttributes.push_back(attribute); + } + + IndexType indexType; + std::vector<uint8_t> indexBufferData = {}; + if (objectPrimitive.indices >= 0){ // if there is no index buffer, -1 is returned from fx-gltf + const fx::gltf::Accessor &indexAccessor = sceneObjects.accessors[objectPrimitive.indices]; + const fx::gltf::BufferView &indexBufferView = sceneObjects.bufferViews[indexAccessor.bufferView]; + const fx::gltf::Buffer &indexBuffer = sceneObjects.buffers[indexBufferView.buffer]; + + 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; + } + } + + 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 fx::gltf::BufferView& vertexBufferView = sceneObjects.bufferViews[posAccessor.bufferView]; + const fx::gltf::Buffer& vertexBuffer = sceneObjects.buffers[vertexBufferView.buffer]; + + // FIXME: This only works when all vertex attributes are in one buffer + std::vector<uint8_t> vertexBufferData; + vertexBufferData.resize(vertexBuffer.byteLength); + { + const size_t off = 0; + const void *const ptr = ((char*)vertexBuffer.data.data()) + off; + if (!memcpy(vertexBufferData.data(), ptr, vertexBuffer.byteLength)) { + std::cerr << "ERROR copying vertex buffer data.\n"; + return 0; + } + } + + const size_t numVertexGroups = objectMesh.primitives.size(); + vertexGroups.reserve(numVertexGroups); + + vertexGroups.push_back({ + static_cast<PrimitiveMode>(objectPrimitive.mode), + sceneObjects.accessors[objectPrimitive.indices].count, + posAccessor.count, + {indexType, indexBufferData}, + {vertexBufferData, vertexAttributes}, + {posAccessor.min[0], posAccessor.min[1], posAccessor.min[2]}, + {posAccessor.max[0], posAccessor.max[1], posAccessor.max[2]}, + static_cast<uint8_t>(objectPrimitive.material) + }); + + groupCount++; + vertexGroupsIndex.push_back(groupCount); + } + + mesh = { + sceneObjects.meshes[i].name, + vertexGroupsIndex, + }; + + meshes.push_back(mesh); + } + + if (sceneObjects.textures.size() > 0){ + textures.reserve(sceneObjects.textures.size()); + + for(int k = 0; k < sceneObjects.textures.size(); k++){ + const fx::gltf::Texture &tex = sceneObjects.textures[k]; + const fx::gltf::Image &img = sceneObjects.images[tex.source]; +#ifndef NDEBUG + 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()); +#endif + std::string img_uri = dir + "/" + img.uri; + int w, h, c; + uint8_t *data = stbi_load(img_uri.c_str(), &w, &h, &c, 4); + c = 4; // FIXME hardcoded to always have RGBA channel layout + if (!data) { + std::cerr << "ERROR loading texture image data.\n"; + return 0; + } + const size_t byteLen = w * h * c; + + std::vector<uint8_t> imgdata; + imgdata.resize(byteLen); + if (!memcpy(imgdata.data(), data, byteLen)) { + std::cerr << "ERROR copying texture image data.\n"; + free(data); + return 0; + } + free(data); + + textures.push_back({ + 0, + static_cast<uint8_t>(c), + static_cast<uint16_t>(w), + static_cast<uint16_t>(h), + imgdata + }); + + } + } + + // TODO fill materials struct and vector + + scene = { + meshes, + vertexGroups, + materials, + textures, + samplers + }; + + return 1; +} + } diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 1225af1cb5bca794e751d1aa341396958ed9a6ca..193b640ab0464503a070a42c06e7da59e7dbdbf0 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -30,10 +30,10 @@ int main(int argc, const char** argv) { { "VK_KHR_swapchain" } ); - vkcv::asset::Mesh mesh; + vkcv::asset::Scene mesh; - const char* path = argc > 1 ? argv[1] : "resources/cube/cube.gltf"; - int result = vkcv::asset::loadMesh(path, mesh); + const char* path = argc > 1 ? argv[1] : "resources/Szene/Szene.gltf"; + int result = vkcv::asset::loadScene(path, mesh); if (result == 1) { std::cout << "Mesh loading successful!" << std::endl;