diff --git a/include/vkcv/VertexLayout.hpp b/include/vkcv/VertexLayout.hpp index 9f609b48472386cd7628ff40b5fa4b90bc91649a..0600b99a24a327605e89b2e8ec304c20dbf7ad2e 100644 --- a/include/vkcv/VertexLayout.hpp +++ b/include/vkcv/VertexLayout.hpp @@ -63,4 +63,4 @@ namespace vkcv{ std::vector<VertexBinding> vertexBindings; }; -} \ No newline at end of file +} diff --git a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp index d687bbf60a03a59eee8c29f9b676f10cc7f2f2b3..4107d57ee97a6efe0475c6d9dbd80d2603e0afe8 100644 --- a/modules/asset_loader/include/vkcv/asset/asset_loader.hpp +++ b/modules/asset_loader/include/vkcv/asset/asset_loader.hpp @@ -1,15 +1,16 @@ #pragma once /** - * @authors Trevor Hollmann + * @authors Trevor Hollmann, Mara Vogt, Susanne DÃķtsch * @file include/vkcv/asset/asset_loader.h * @brief Interface of the asset loader module for the vkcv framework. */ #include <string> #include <vector> +#include <array> #include <cstdint> -/* These macros define limits of the following structs. Implementations can +/** These macros define limits of the following structs. Implementations can * test against these limits when performing sanity checks. The main constraint * expressed is that of the data type: Material indices are identified by a * uint8_t in the VertexGroup struct, so there can't be more than UINT8_MAX @@ -19,17 +20,18 @@ #define MAX_MATERIALS_PER_MESH UINT8_MAX #define MAX_VERTICES_PER_VERTEX_GROUP UINT32_MAX -/* LOADING MESHES +/** LOADING MESHES * The description of meshes is a hierarchy of structures with the Mesh at the * top. * * Each Mesh has an array of one or more vertex groups (called "primitives" in - * glTF parlance) and an array of zero or more Materials. + * glTF parlance). Specifically, it has an array of indices into an array of + * vertex groups defined by the Scene struct. * * Each vertex group describes a part of the meshes vertices by defining how * they should be rendered (as points, lines, triangles), how many indices and * vertices there are, how the content of the vertex buffer is to be - * interpreted and which material from the Meshes materials array should be + * interpreted and which material from the Scenes materials array should be * used for the surface of the vertices. * As a bonus there is also the axis aligned bounding box of the vertices. * @@ -43,37 +45,99 @@ namespace vkcv::asset { -/* This enum matches modes in fx-gltf, the library returns a standard mode +/** This enum matches modes in fx-gltf, the library returns a standard mode * (TRIANGLES) if no mode is given in the file. */ -enum PrimitiveMode { +enum class PrimitiveMode : uint8_t { POINTS=0, LINES, LINELOOP, LINESTRIP, TRIANGLES, TRIANGLESTRIP, TRIANGLEFAN }; -/* The indices in the index buffer can be of different bit width. */ -enum IndexType { UINT32=0, UINT16=1, UINT8=2 }; -/* With these enums, 0 is reserved to signal uninitialized or invalid data. */ +/** The indices in the index buffer can be of different bit width. */ +enum class IndexType : uint8_t { UNDEFINED=0, UINT8=1, UINT16=2, UINT32=3 }; + +typedef struct { + // TODO define struct for samplers (low priority) + // NOTE: glTF defines samplers based on OpenGL, which can not be + // directly translated to Vulkan. Specifically, OpenGL (and glTF) + // define a different set of Min/Mag-filters than Vulkan. +} Sampler; + +/** struct for defining the loaded texture */ +typedef struct { + int sampler; // index into the sampler array of the Scene + uint8_t channels; // number of channels + uint16_t w, h; // width and height of the texture + std::vector<uint8_t> data; // binary data of the decoded texture +} Texture; + +/** The asset loader module only supports the PBR-MetallicRoughness model for + * materials.*/ +typedef struct { + uint16_t textureMask; // bit mask with active texture targets + // Indices into the Array.textures array + int baseColor, metalRough, normal, occlusion, emissive; + // Scaling factors for each texture target + struct { float r, g, b, a; } baseColorFactor; + float metallicFactor, roughnessFactor; + float normalScale; + float occlusionStrength; + struct { float r, g, b; } emissiveFactor; +} Material; + +/** Flags for the bit-mask in the Material struct. To check if a material has a + * certain texture target, you can use the hasTexture() function below, passing + * the material struct and the enum. */ +enum class PBRTextureTarget { + baseColor=1, metalRough=2, normal=4, occlusion=8, emissive=16 +}; + +/** This macro translates the index of an enum in the defined order to an + * integer with a single bit set in the corresponding place. It is used for + * working with the bitmask of texture targets ("textureMask") in the Material + * struct: + * Material mat = ...; + * if (mat.textureMask & bitflag(PBRTextureTarget::baseColor)) {...} + * However, this logic is also encapsulated in the convenience-function + * materialHasTexture() so users of the asset loader module can avoid direct + * contact with bit-level operations. */ +#define bitflag(ENUM) (0x1u << ((unsigned)(ENUM))) + +/** To signal that a certain texture target is active in a Material struct, its + * bit is set in the textureMask. You can use this function to check that: + * Material mat = ...; + * if (materialHasTexture(&mat, baseColor)) {...} */ +bool materialHasTexture(const Material *const m, const PBRTextureTarget t); + +/** With these enums, 0 is reserved to signal uninitialized or invalid data. */ enum class PrimitiveType : uint32_t { UNDEFINED = 0, POSITION = 1, NORMAL = 2, - TEXCOORD_0 = 3 + TEXCOORD_0 = 3, + TEXCOORD_1 = 4 }; -/* This struct describes one vertex attribute of a vertex buffer. */ + +/** These integer values are used the same way in OpenGL, Vulkan and glTF. This + * enum is not needed for translation, it's only for the programmers + * convenience (easier to read in if/switch statements etc). While this enum + * exists in (almost) the same definition in the fx-gltf library, we want to + * avoid exposing that dependency, thus it is re-defined here. */ +enum class ComponentType : uint16_t { + NONE = 0, INT8 = 5120, UINT8 = 5121, INT16 = 5122, UINT16 = 5123, + UINT32 = 5125, FLOAT32 = 5126 +}; + +/** This struct describes one vertex attribute of a vertex buffer. */ typedef struct { PrimitiveType type; // POSITION, NORMAL, ... uint32_t offset; // offset in bytes uint32_t length; // length of ... in bytes uint32_t stride; // stride in bytes - uint16_t componentType; // eg. 5126 for float + ComponentType componentType; // eg. 5126 for float uint8_t componentCount; // eg. 3 for vec3 } VertexAttribute; -typedef struct { - // TODO not yet needed for the first (unlit) triangle -} Material; - -/* This struct represents one (possibly the only) part of a mesh. There is +/** 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 index buffer, this is indicated * by indexBuffer.data being empty. Each vertex buffer can have one or more @@ -91,34 +155,39 @@ typedef struct { } vertexBuffer; struct { float x, y, z; } min; // bounding box lower left struct { float x, y, z; } max; // bounding box upper right - uint8_t materialIndex; // index to one of the meshes materials + int materialIndex; // index to one of the materials } VertexGroup; -/* This struct represents a single mesh loaded from a glTF file. It consists of - * at least one VertexVroup and any number of Materials. */ +/** This struct represents a single mesh as it was loaded from a glTF file. It + * consists of at least one VertexGroup, which then references other resources + * such as Materials. */ typedef struct { std::string name; - 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 - uint8_t *img; // raw bytes, free after use (deal with it) - } texture_hack; + std::array<float, 16> modelMatrix; + std::vector<int> vertexGroups; } Mesh; +/** The scene struct is simply a collection of objects in the scene as well as + * the resources used by those objects. + * For now the only type of object are the meshes and they are represented in a + * flat array. + * Note that parent-child relations are not yet possible. */ +typedef struct { + std::vector<Mesh> meshes; + std::vector<VertexGroup> vertexGroups; + std::vector<Material> materials; + std::vector<Texture> textures; + std::vector<Sampler> samplers; +} Scene; /** - * In its first iteration the asset loader module will only allow loading - * single meshes, one per glTF file. - * It will later be extended to allow loading entire scenes from glTF files. + * Load every mesh from the glTF file, as well as materials and textures. * - * @param path must be the path to a glTF file containing a single mesh. - * @param mesh is a reference to a Mesh struct that will be filled with the + * @param path must be the path to a glTF or glb file. + * @param scene is a reference to a Scene struct that will be filled with the * content of the glTF file being loaded. * */ -int loadMesh(const std::string &path, Mesh &mesh); +int loadScene(const std::string &path, Scene &scene); } diff --git a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp index f3823cc8f3fe54b53835f356dd14a086515118dd..97fd39515290ac9235b3936d44d3e40a584ef84f 100644 --- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp +++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp @@ -5,9 +5,10 @@ #include <fx/gltf.h> #define STB_IMAGE_IMPLEMENTATION #define STBI_ONLY_JPEG +#define STBI_ONLY_PNG #include <stb_image.h> - #include <vkcv/Logger.hpp> +#include <algorithm> namespace vkcv::asset { @@ -51,160 +52,318 @@ void print_what (const std::exception& e, const std::string &path) { } } -int loadMesh(const std::string &path, Mesh &mesh) { - fx::gltf::Document object; - - try { - if (path.rfind(".glb", (path.length()-4)) != std::string::npos) { - object = fx::gltf::LoadFromBinary(path); - } else { - object = 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; - } - - // TODO Temporary restriction: Only one mesh per glTF file allowed - // currently. Later, we want to support whole scenes with more than - // just meshes. - if (object.meshes.size() != 1) return 0; - - fx::gltf::Mesh const &objectMesh = object.meshes[0]; - // TODO We want to support more than one vertex group per mesh - // eventually... right now this is hard-coded to use only the first one - // because we only care about the example triangle and cube - fx::gltf::Primitive const &objectPrimitive = objectMesh.primitives[0]; - fx::gltf::Accessor posAccessor; - - std::vector<VertexAttribute> vertexAttributes; - vertexAttributes.reserve(objectPrimitive.attributes.size()); - - for (auto const & attrib : objectPrimitive.attributes) { - fx::gltf::Accessor accessor = object.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 = object.bufferViews[accessor.bufferView].byteOffset; - attribute.length = object.bufferViews[accessor.bufferView].byteLength; - attribute.stride = object.bufferViews[accessor.bufferView].byteStride; - 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); - } - - // TODO consider the case where there is no index buffer (not all - // meshes have to use indexed rendering) - 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]; - - 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)) { - vkcv_log(LogLevel::ERROR, "Copying index buffer data"); - return 0; - } - } - - const fx::gltf::BufferView& vertexBufferView = object.bufferViews[posAccessor.bufferView]; - const fx::gltf::Buffer& vertexBuffer = object.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)) { - vkcv_log(LogLevel::ERROR, "Copying vertex buffer data"); - return 0; - } - } - - IndexType indexType; - switch(indexAccessor.componentType) { +/** Translate the component type used in the index accessor of fx-gltf to our + * enum for index type. The reason we have defined an incompatible enum that + * needs translation is that only a subset of component types is valid for + * indices and we want to catch these incompatibilities here. */ +enum IndexType getIndexType(const enum fx::gltf::Accessor::ComponentType &t) +{ + switch (t) { case fx::gltf::Accessor::ComponentType::UnsignedByte: - indexType = UINT8; break; + return IndexType::UINT8; case fx::gltf::Accessor::ComponentType::UnsignedShort: - indexType = UINT16; break; + return IndexType::UINT16; case fx::gltf::Accessor::ComponentType::UnsignedInt: - indexType = UINT32; break; + return IndexType::UINT32; default: - vkcv_log(LogLevel::ERROR, "Index type (%u) not supported", - static_cast<uint16_t>(indexAccessor.componentType)); - return 0; + std::cerr << "ERROR: Index type not supported: " << + static_cast<uint16_t>(t) << std::endl; + return IndexType::UNDEFINED; } +} - const size_t numVertexGroups = objectMesh.primitives.size(); - - std::vector<VertexGroup> vertexGroups; - vertexGroups.reserve(numVertexGroups); - - vertexGroups.push_back({ - static_cast<PrimitiveMode>(objectPrimitive.mode), - object.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) - }); - - 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]; -#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 - - size_t pos = path.find_last_of("/"); - auto dir = path.substr(0, pos); - - mesh.texture_hack.img = stbi_load((dir + "/" + 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 - return 1; +/** + * This function computes the modelMatrix out of the data given in the gltf file. It also checks, whether a modelMatrix was given. + * @param translation possible translation vector (default 0,0,0) + * @param scale possible scale vector (default 1,1,1) + * @param rotation possible rotation, given in quaternion (default 0,0,0,1) + * @param matrix possible modelmatrix (default identity) + * @return model Matrix as an array of floats + */ +std::array<float, 16> computeModelMatrix(std::array<float, 3> translation, std::array<float, 3> scale, std::array<float, 4> rotation, std::array<float, 16> matrix){ + std::array<float, 16> modelMatrix = {1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1}; + if (matrix != modelMatrix){ + return matrix; + } else { + // translation + modelMatrix[3] = translation[0]; + modelMatrix[7] = translation[1]; + modelMatrix[11] = translation[2]; + // rotation and scale + auto a = rotation[0]; + auto q1 = rotation[1]; + auto q2 = rotation[2]; + auto q3 = rotation[3]; + + modelMatrix[0] = (2 * (a * a + q1 * q1) - 1) * scale[0]; + modelMatrix[1] = (2 * (q1 * q2 - a * q3)) * scale[1]; + modelMatrix[2] = (2 * (q1 * q3 + a * q2)) * scale[2]; + + modelMatrix[4] = (2 * (q1 * q2 + a * q3)) * scale[0]; + modelMatrix[5] = (2 * (a * a + q2 * q2) - 1) * scale[1]; + modelMatrix[6] = (2 * (q2 * q3 - a * q1)) * scale[2]; + + modelMatrix[8] = (2 * (q1 * q3 - a * q2)) * scale[0]; + modelMatrix[9] = (2 * (q2 * q3 + a * q1)) * scale[1]; + modelMatrix[10] = (2 * (a * a + q3 * q3) - 1) * scale[2]; + + // flip y, because GLTF uses y up, but vulkan -y up + modelMatrix[5] *= -1; + + return modelMatrix; + } + +} + +bool materialHasTexture(const Material *const m, const PBRTextureTarget t) +{ + return m->textureMask & bitflag(t); +} + +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; + int groupCount = 0; + + Mesh mesh = {}; + + for(int i = 0; i < sceneObjects.meshes.size(); i++){ + std::vector<int> vertexGroupsIndices; + 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.clear(); + 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 if (attrib.first == "TEXCOORD_1") { + attribute.type = PrimitiveType::TEXCOORD_1; + } else { + return 0; + } + + attribute.offset = sceneObjects.bufferViews[accessor.bufferView].byteOffset; + attribute.length = sceneObjects.bufferViews[accessor.bufferView].byteLength; + attribute.stride = sceneObjects.bufferViews[accessor.bufferView].byteStride; + attribute.componentType = static_cast<ComponentType>(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)) { + vkcv_log(LogLevel::ERROR, "Copying index buffer data"); + return 0; + } + } + + indexType = getIndexType(indexAccessor.componentType); + if (indexType == IndexType::UNDEFINED){ + vkcv_log(LogLevel::ERROR, "Index Type undefined."); + return 0; + } + } + + const fx::gltf::BufferView& vertexBufferView = sceneObjects.bufferViews[posAccessor.bufferView]; + const fx::gltf::Buffer& vertexBuffer = sceneObjects.buffers[vertexBufferView.buffer]; + + // only copy relevant part of vertex data + uint32_t relevantBufferOffset = std::numeric_limits<uint32_t>::max(); + uint32_t relevantBufferEnd = 0; + for (const auto &attribute : vertexAttributes) { + relevantBufferOffset = std::min(attribute.offset, relevantBufferOffset); + const uint32_t attributeEnd = attribute.offset + attribute.length; + relevantBufferEnd = std::max(relevantBufferEnd, attributeEnd); // TODO: need to incorporate stride? + } + const uint32_t relevantBufferSize = relevantBufferEnd - relevantBufferOffset; + + // FIXME: This only works when all vertex attributes are in one buffer + std::vector<uint8_t> vertexBufferData; + vertexBufferData.resize(relevantBufferSize); + { + const void *const ptr = ((char*)vertexBuffer.data.data()) + relevantBufferOffset; + if (!memcpy(vertexBufferData.data(), ptr, relevantBufferSize)) { + vkcv_log(LogLevel::ERROR, "Copying vertex buffer data"); + return 0; + } + } + + // make vertex attributes relative to copied section + for (auto &attribute : vertexAttributes) { + attribute.offset -= relevantBufferOffset; + } + + 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) + }); + + vertexGroupsIndices.push_back(groupCount); + groupCount++; + } + + mesh.name = sceneObjects.meshes[i].name; + mesh.vertexGroups = vertexGroupsIndices; + + meshes.push_back(mesh); + } + + for(int m = 0; m < sceneObjects.nodes.size(); m++) { + meshes[sceneObjects.nodes[m].mesh].modelMatrix = computeModelMatrix(sceneObjects.nodes[m].translation, + sceneObjects.nodes[m].scale, + sceneObjects.nodes[m].rotation, + sceneObjects.nodes[m].matrix); + } + + 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]; + 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) { + vkcv_log(LogLevel::ERROR, "Loading texture image data.") + return 0; + } + const size_t byteLen = w * h * c; + + std::vector<uint8_t> imgdata; + imgdata.resize(byteLen); + if (!memcpy(imgdata.data(), data, byteLen)) { + vkcv_log(LogLevel::ERROR, "Copying texture image data") + 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 + }); + + } + } + + if (sceneObjects.materials.size() > 0){ + materials.reserve(sceneObjects.materials.size()); + + for (int l = 0; l < sceneObjects.materials.size(); l++){ + fx::gltf::Material material = sceneObjects.materials[l]; + // TODO I think we shouldn't set the index for a texture target if + // it isn't defined. So we need to test first if there is a normal + // texture before assigning material.normalTexture.index. + // About the bitmask: If a normal texture is there, modify the + // materials textureMask like this: + // mat.textureMask |= bitflag(asset::normal); + materials.push_back({ + 0, + material.pbrMetallicRoughness.baseColorTexture.index, + material.pbrMetallicRoughness.metallicRoughnessTexture.index, + material.normalTexture.index, + material.occlusionTexture.index, + material.emissiveTexture.index, + { + material.pbrMetallicRoughness.baseColorFactor[0], + material.pbrMetallicRoughness.baseColorFactor[1], + material.pbrMetallicRoughness.baseColorFactor[2], + material.pbrMetallicRoughness.baseColorFactor[3] + }, + material.pbrMetallicRoughness.metallicFactor, + material.pbrMetallicRoughness.roughnessFactor, + material.normalTexture.scale, + material.occlusionTexture.strength, + { + material.emissiveFactor[0], + material.emissiveFactor[1], + material.emissiveFactor[2] + } + + }); + } + } + + scene = { + meshes, + vertexGroups, + materials, + textures, + samplers + }; + + return 1; } } diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index ccbdaf4101c5dabb3e9d43788e255eab85ad5776..474c9764bd29053c95ca2c4511d1287359350d02 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -2,4 +2,5 @@ # Add new projects/examples here: add_subdirectory(first_triangle) add_subdirectory(first_mesh) +add_subdirectory(first_scene) add_subdirectory(cmd_sync_test) \ No newline at end of file diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp index 43941368ab8832f3273c276bb0dbc63d652a16a8..c33f1adc985b40566aa25c5f51e2a1c622dfa280 100644 --- a/projects/cmd_sync_test/src/main.cpp +++ b/projects/cmd_sync_test/src/main.cpp @@ -39,10 +39,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); + int result = vkcv::asset::loadScene(path, mesh); if (result == 1) { std::cout << "Mesh loading successful!" << std::endl; @@ -136,8 +136,11 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, mesh.texture_hack.w, mesh.texture_hack.h); - texture.fill(mesh.texture_hack.img); + //vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, mesh.texture_hack.w, mesh.texture_hack.h); + //texture.fill(mesh.texture_hack.img); + vkcv::asset::Texture &tex = mesh.textures[0]; + vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); + texture.fill(tex.data.data()); vkcv::SamplerHandle sampler = core.createSampler( vkcv::SamplerFilterType::LINEAR, diff --git a/projects/first_mesh/resources/Szene/Szene.bin b/projects/first_mesh/resources/Szene/Szene.bin new file mode 100644 index 0000000000000000000000000000000000000000..c87d27637516b0bbf864251dd162773f5cc53e06 --- /dev/null +++ b/projects/first_mesh/resources/Szene/Szene.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee4742718f720d589a2a03f5d879f8c50ba9057718d191a43b046eaa9071080d +size 70328 diff --git a/projects/first_mesh/resources/Szene/Szene.gltf b/projects/first_mesh/resources/Szene/Szene.gltf new file mode 100644 index 0000000000000000000000000000000000000000..e5a32b29af5d0a2ac5f497e60b4b92c1873e1df9 --- /dev/null +++ b/projects/first_mesh/resources/Szene/Szene.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75ba834118792ebbacf528a1690c7d04df4b4c8122b9f99a9aa9a9d075d2c86a +size 7421 diff --git a/projects/first_mesh/resources/Szene/boards2_vcyc.jpg b/projects/first_mesh/resources/Szene/boards2_vcyc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2636039e272289c0fba3fa2d88a060b857501248 --- /dev/null +++ b/projects/first_mesh/resources/Szene/boards2_vcyc.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cca33a6e58ddd1b37a6e6853a9aa0e7b15ca678937119194752393dd2a0a0564 +size 1192476 diff --git a/projects/first_mesh/resources/Szene/boards2_vcyc_jpg.jpg b/projects/first_mesh/resources/Szene/boards2_vcyc_jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2636039e272289c0fba3fa2d88a060b857501248 --- /dev/null +++ b/projects/first_mesh/resources/Szene/boards2_vcyc_jpg.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cca33a6e58ddd1b37a6e6853a9aa0e7b15ca678937119194752393dd2a0a0564 +size 1192476 diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 3c1c73014501fd5922105ef35fe53e196b9cfb9b..8ffe501747fe516de9ab10834de788f110ad8722 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -29,10 +29,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); + int result = vkcv::asset::loadScene(path, mesh); if (result == 1) { std::cout << "Mesh loading successful!" << std::endl; @@ -118,8 +118,11 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, mesh.texture_hack.w, mesh.texture_hack.h); - texture.fill(mesh.texture_hack.img); + // FIXME There should be a test here to make sure there is at least 1 + // texture in the mesh. + vkcv::asset::Texture &tex = mesh.textures[0]; + vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); + texture.fill(tex.data.data()); vkcv::SamplerHandle sampler = core.createSampler( vkcv::SamplerFilterType::LINEAR, @@ -129,9 +132,9 @@ int main(int argc, const char** argv) { ); const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()), - vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; + vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[0].offset), vertexBuffer.getVulkanHandle()), + vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[1].offset), vertexBuffer.getVulkanHandle()), + vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; vkcv::DescriptorWrites setWrites; setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) }; @@ -194,7 +197,6 @@ int main(int argc, const char** argv) { renderTargets); core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); - core.endFrame(); } diff --git a/projects/first_scene/.gitignore b/projects/first_scene/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b0d802667a184267e6ee764264e976dfead8e9dd --- /dev/null +++ b/projects/first_scene/.gitignore @@ -0,0 +1 @@ +first_scene diff --git a/projects/first_scene/CMakeLists.txt b/projects/first_scene/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b90739750011a36b4c1d9e0bff7cba986074228 --- /dev/null +++ b/projects/first_scene/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.16) +project(first_scene) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(first_scene src/main.cpp) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(first_scene PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(first_scene PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(first_scene PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(first_scene SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(first_scene vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera) diff --git a/projects/first_scene/resources/Cutlery/Cutlery_chrome_BaseColor.png b/projects/first_scene/resources/Cutlery/Cutlery_chrome_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..8258525f22097f2382ec5c26ad0df7eb50718642 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Cutlery_chrome_BaseColor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ce87f6407ee40ffa60983587aeb52333d59b4b1c01a53e11f4bb227ba1099d9 +size 109 diff --git a/projects/first_scene/resources/Cutlery/Cutlery_chrome_Normal.png b/projects/first_scene/resources/Cutlery/Cutlery_chrome_Normal.png new file mode 100644 index 0000000000000000000000000000000000000000..620fe7621cf35409ae8c04099dc8bc4bbc04343b --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Cutlery_chrome_Normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68a0064d457a6f7994814b07d943deda778754128935689874334300ede6161d +size 2332064 diff --git a/projects/first_scene/resources/Cutlery/Cutlery_details_BaseColor.png b/projects/first_scene/resources/Cutlery/Cutlery_details_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..5570e88c569036b9d00155ef6113013aa23f2503 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Cutlery_details_BaseColor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:42c2715635081eb29c4489ce631798b0e9c881460efc0aa63d0e81641a0dcfe9 +size 108 diff --git a/projects/first_scene/resources/Cutlery/Cutlery_details_Normal.png b/projects/first_scene/resources/Cutlery/Cutlery_details_Normal.png new file mode 100644 index 0000000000000000000000000000000000000000..d07681f5bfa25c279321c3074e21e4900c5eb0fa --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Cutlery_details_Normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:15b0133e140899c47ccf35b0f99a7e337e3110ae089f45d27faf9983f3e0a1f7 +size 770758 diff --git a/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Caps_BaseColor.png b/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Caps_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..1845e8a7d586a0d23300ad9d04a82f1d5048fcf5 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Caps_BaseColor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea7c82c0f9e25afa401470df1fb6903f508fa138d21ad30f57a9153b0395b198 +size 521315 diff --git a/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Caps_Normal.png b/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Caps_Normal.png new file mode 100644 index 0000000000000000000000000000000000000000..1c800c0489693b66d6163bdc2156d453b68ca19b --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Caps_Normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:119efbbc020244ff9b7ff16ac9795a6d4b1808d1b90d81d20d2c874d0dc8a924 +size 1693468 diff --git a/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Glass_Wine_BaseColor.png b/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Glass_Wine_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..36f46ebf25158c78bc26d83860e1c08b2c9e96cf --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Glass_Wine_BaseColor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99896468c7d47dd5391d585eecf149f420eca3bfec31923c21fa86c45fe02d0f +size 108 diff --git a/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Glass_Wine_Normal.png b/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Glass_Wine_Normal.png new file mode 100644 index 0000000000000000000000000000000000000000..28c205d4e70867ec58448ca8ba2c2117c611a367 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Paris_LiquorBottle_01_Glass_Wine_Normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b31618aa5adce4ad476bec2c03718c5ae097250e784344f2d298b8a74c3bfd46 +size 90 diff --git a/projects/first_scene/resources/Cutlery/Plates_Ceramic_BaseColor.png b/projects/first_scene/resources/Cutlery/Plates_Ceramic_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..e0104189a1190c160152101e9e328e81ed89121b --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Plates_Ceramic_BaseColor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6eff6ccd12d8b39d60ae5ee91edd73d4d7838fcb5d9bc6ff0e671bdf009134e9 +size 109 diff --git a/projects/first_scene/resources/Cutlery/Plates_Ceramic_Normal.png b/projects/first_scene/resources/Cutlery/Plates_Ceramic_Normal.png new file mode 100644 index 0000000000000000000000000000000000000000..fa13483d25595ee6b3a00e7fe6ce48aed7b6aaca --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Plates_Ceramic_Normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fe92c40ff4032fdaf10eeafd943657a0c6e0bfb3f38770f5654aa943a660f421 +size 59419 diff --git a/projects/first_scene/resources/Cutlery/Plates_Details_BaseColor-Plates_Details_BaseColor.png b/projects/first_scene/resources/Cutlery/Plates_Details_BaseColor-Plates_Details_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..b91d0ac62fbeabbef1ed78f1343f919836cbca40 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Plates_Details_BaseColor-Plates_Details_BaseColor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ca7d436a68a2a1237aee6e763b2954f01666b21f1dbd46929a322ea277483d2 +size 779227 diff --git a/projects/first_scene/resources/Cutlery/Plates_Details_Normal.png b/projects/first_scene/resources/Cutlery/Plates_Details_Normal.png new file mode 100644 index 0000000000000000000000000000000000000000..6efd967984ee2e68b89de9e471b93396c13ca69a --- /dev/null +++ b/projects/first_scene/resources/Cutlery/Plates_Details_Normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b01fc6482054c64d7407b283731e57fce0601a8db28b6781c14fae3c6b30b0fe +size 504362 diff --git a/projects/first_scene/resources/Cutlery/ToffeeJar_Label_BaseColor.png b/projects/first_scene/resources/Cutlery/ToffeeJar_Label_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e0c4f4134cb99d3765d6f078f71efab8861bf1 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/ToffeeJar_Label_BaseColor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df138ee68c1d455652d1b9ae3dd03e93fcd2f6a0d8a1f12e3710f39143088674 +size 1593466 diff --git a/projects/first_scene/resources/Cutlery/ToffeeJar_Label_Normal.png b/projects/first_scene/resources/Cutlery/ToffeeJar_Label_Normal.png new file mode 100644 index 0000000000000000000000000000000000000000..9f310653b5211575da3cab2f6deb47ec6826a936 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/ToffeeJar_Label_Normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6af5da97cbb25d79aea2dde8dd71ecbd495334fe34e99497ba17821be93fd7fd +size 2696676 diff --git a/projects/first_scene/resources/Cutlery/TransparentGlass_BaseColor.png b/projects/first_scene/resources/Cutlery/TransparentGlass_BaseColor.png new file mode 100644 index 0000000000000000000000000000000000000000..4e4f0fcb312b8f8bd0df965bfe6b8ac62ec5df4d --- /dev/null +++ b/projects/first_scene/resources/Cutlery/TransparentGlass_BaseColor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2796affdfdcf6bc805176d9f85505680b5ee52eeec625e9eaeea4f0ff3854883 +size 108 diff --git a/projects/first_scene/resources/Cutlery/TransparentGlass_Normal.png b/projects/first_scene/resources/Cutlery/TransparentGlass_Normal.png new file mode 100644 index 0000000000000000000000000000000000000000..28c205d4e70867ec58448ca8ba2c2117c611a367 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/TransparentGlass_Normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b31618aa5adce4ad476bec2c03718c5ae097250e784344f2d298b8a74c3bfd46 +size 90 diff --git a/projects/first_scene/resources/Cutlery/cutlerySzene.bin b/projects/first_scene/resources/Cutlery/cutlerySzene.bin new file mode 100644 index 0000000000000000000000000000000000000000..ab9a0aa47205e8f3064d2f16a950d4733fb4f472 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/cutlerySzene.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f545b986e0a1ac5bff5d49693a52042aa37878425818f72c69c243da20d1f99d +size 183324 diff --git a/projects/first_scene/resources/Cutlery/cutlerySzene.glb b/projects/first_scene/resources/Cutlery/cutlerySzene.glb new file mode 100644 index 0000000000000000000000000000000000000000..b0c5f345aaaa3f96d7158a0992ee124aae99a69a --- /dev/null +++ b/projects/first_scene/resources/Cutlery/cutlerySzene.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb1bad604192ca36222c0ca485ba87b846ecbd11ee8254327e04e3c993b00116 +size 11150396 diff --git a/projects/first_scene/resources/Cutlery/cutlerySzene.gltf b/projects/first_scene/resources/Cutlery/cutlerySzene.gltf new file mode 100644 index 0000000000000000000000000000000000000000..53e339cda4511f3f1a8670b36469e184aac530e2 --- /dev/null +++ b/projects/first_scene/resources/Cutlery/cutlerySzene.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c77cd60e2327daca1a01044e45f2c38655f7b781bd07985fc0135328a8a96b57 +size 34312 diff --git a/projects/first_scene/resources/Sponza/Sponza.bin b/projects/first_scene/resources/Sponza/Sponza.bin new file mode 100644 index 0000000000000000000000000000000000000000..cfedd26ca5a67b6d0a47d44d13a75e14a141717a --- /dev/null +++ b/projects/first_scene/resources/Sponza/Sponza.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b809f7a17687dc99e6f41ca1ea32c06eded8779bf34d16f1f565d750b0ffd68 +size 6347696 diff --git a/projects/first_scene/resources/Sponza/Sponza.gltf b/projects/first_scene/resources/Sponza/Sponza.gltf new file mode 100644 index 0000000000000000000000000000000000000000..172ea07e21c94465211c860cd805355704cef230 --- /dev/null +++ b/projects/first_scene/resources/Sponza/Sponza.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5cc0ecad5c4694088ff820e663619c370421afc1323ac487406e8e9b4735d787 +size 713962 diff --git a/projects/first_scene/resources/Sponza/background.png b/projects/first_scene/resources/Sponza/background.png new file mode 100644 index 0000000000000000000000000000000000000000..b64def129da38f4e23d89e21b4af1039008a4327 --- /dev/null +++ b/projects/first_scene/resources/Sponza/background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f5b5f900ff8ed83a31750ec8e428b5b91273794ddcbfc4e4b8a6a7e781f8c686 +size 1417666 diff --git a/projects/first_scene/resources/Sponza/chain_texture.png b/projects/first_scene/resources/Sponza/chain_texture.png new file mode 100644 index 0000000000000000000000000000000000000000..c1e1768cff78e0614ad707eca8602a4c4edab5e5 --- /dev/null +++ b/projects/first_scene/resources/Sponza/chain_texture.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8362cfd472880daeaea37439326a4651d1338680ae69bb2513fc6b17c8de7d4 +size 490895 diff --git a/projects/first_scene/resources/Sponza/lion.png b/projects/first_scene/resources/Sponza/lion.png new file mode 100644 index 0000000000000000000000000000000000000000..c49c7f0ed31e762e19284d0d3624fbc47664e56b --- /dev/null +++ b/projects/first_scene/resources/Sponza/lion.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f882f746c3a9cd51a9c6eedc1189b97668721d91a3fe49232036e789912c652 +size 2088728 diff --git a/projects/first_scene/resources/Sponza/spnza_bricks_a_diff.png b/projects/first_scene/resources/Sponza/spnza_bricks_a_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..cde4c7a6511e9a5f03c63ad996437fcdba3ce2df --- /dev/null +++ b/projects/first_scene/resources/Sponza/spnza_bricks_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b94219c2f5f943f3f4715c74e7d1038bf0ab3b3b3216a758eaee67f875df0851 +size 1928829 diff --git a/projects/first_scene/resources/Sponza/sponza_arch_diff.png b/projects/first_scene/resources/Sponza/sponza_arch_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..bcd9bda2918d226039f9e2d03902d377b706fab6 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_arch_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0df2c8a01b2843b1c792b494f7173cdbc4f834840fc2177af3e5d690fceda57 +size 1596151 diff --git a/projects/first_scene/resources/Sponza/sponza_ceiling_a_diff.png b/projects/first_scene/resources/Sponza/sponza_ceiling_a_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..59de631ffac4414cabf69b2dc794c46fc187d6cb --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_ceiling_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab6c187a81aa68f4eba30119e17fce2e4882a9ec320f70c90482dbe9da82b1c6 +size 1872074 diff --git a/projects/first_scene/resources/Sponza/sponza_column_a_diff.png b/projects/first_scene/resources/Sponza/sponza_column_a_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..01a82432d3f9939bbefe850bdb900f1ff9a3f6db --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_column_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c291507e2808bb83e160ab4b020689817df273baad3713a9ad19ac15fac6826 +size 1840992 diff --git a/projects/first_scene/resources/Sponza/sponza_column_b_diff.png b/projects/first_scene/resources/Sponza/sponza_column_b_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..10a660cce2a5a9b8997772c746058ce23e7d45d7 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_column_b_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2820b0267c4289c6cedbb42721792a57ef244ec2d0935941011c2a7d3fe88a9b +size 2170433 diff --git a/projects/first_scene/resources/Sponza/sponza_column_c_diff.png b/projects/first_scene/resources/Sponza/sponza_column_c_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..bc46fd979044a938d3adca7601689e71504e48bf --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_column_c_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0bc993ff59865468ef4530798930c7dfefb07482d71db45bc2a520986b27735 +size 2066950 diff --git a/projects/first_scene/resources/Sponza/sponza_curtain_blue_diff.png b/projects/first_scene/resources/Sponza/sponza_curtain_blue_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..384c8c2c051160d530eb3ac8b05c9c60752a2d2b --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_curtain_blue_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b85c6bb3cd5105f48d3812ec8e7a1068521ce69e917300d79e136e19d45422fb +size 9510905 diff --git a/projects/first_scene/resources/Sponza/sponza_curtain_diff.png b/projects/first_scene/resources/Sponza/sponza_curtain_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..af842e9f5fe18c1f609875e00899a6770fa4488b --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_curtain_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:563c56bdbbee395a6ef7f0c51c8ac9223c162e517b4cdba0d4654e8de27c98d8 +size 9189263 diff --git a/projects/first_scene/resources/Sponza/sponza_curtain_green_diff.png b/projects/first_scene/resources/Sponza/sponza_curtain_green_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..6c9b6391a199407637fa71033d79fb58b8b4f0d7 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_curtain_green_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:238fe1c7f481388d1c1d578c2da8d411b99e8f0030ab62060a306db333124476 +size 8785458 diff --git a/projects/first_scene/resources/Sponza/sponza_details_diff.png b/projects/first_scene/resources/Sponza/sponza_details_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..12656686362c3e0a297e060491f33bd7351551f9 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_details_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb1223b3bb82f8757e7df25a6891f1239cdd7ec59990340e952fb2d6b7ea570c +size 1522643 diff --git a/projects/first_scene/resources/Sponza/sponza_fabric_blue_diff.png b/projects/first_scene/resources/Sponza/sponza_fabric_blue_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..879d16ef84722a4fc13e83a771778de326e4bc54 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_fabric_blue_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:467d290bf5d4b2a017da140ba9e244ed8a8a9be5418a9ac9bcb4ad572ae2d7ab +size 2229440 diff --git a/projects/first_scene/resources/Sponza/sponza_fabric_diff.png b/projects/first_scene/resources/Sponza/sponza_fabric_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..3311287a219d2148620b87fe428fea071688d051 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_fabric_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1594f59cc2848db26add47361f4e665e3d8afa147760ed915d839fea42b20287 +size 2267382 diff --git a/projects/first_scene/resources/Sponza/sponza_fabric_green_diff.png b/projects/first_scene/resources/Sponza/sponza_fabric_green_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..de110f369004388dae4cd5067c63428db3a07834 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_fabric_green_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:902b87faab221173bf370cea7c74cb9060b4d870ac6316b190dafded1cb12993 +size 2258220 diff --git a/projects/first_scene/resources/Sponza/sponza_flagpole_diff.png b/projects/first_scene/resources/Sponza/sponza_flagpole_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6e0812a0df80346318baa3cb50a6888afc58f8 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_flagpole_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bfffb62e770959c725d0f3db6dc7dbdd46a380ec55ef884dab94d44ca017b438 +size 1425673 diff --git a/projects/first_scene/resources/Sponza/sponza_floor_a_diff.png b/projects/first_scene/resources/Sponza/sponza_floor_a_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..788ed764f79ba724f04a2d603076a5b85013e188 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_floor_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a16f9230fa91f9f31dfca6216ce205f1ef132d44f3b012fbf6efc0fba69770ab +size 1996838 diff --git a/projects/first_scene/resources/Sponza/sponza_roof_diff.png b/projects/first_scene/resources/Sponza/sponza_roof_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..c5b84261fdd1cc776a94b3ce398c7806b895f9a3 --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_roof_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7fc412138c20da19f8173e53545e771f4652558dff624d4dc67143e40efe562b +size 2320533 diff --git a/projects/first_scene/resources/Sponza/sponza_thorn_diff.png b/projects/first_scene/resources/Sponza/sponza_thorn_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9142674a7d4a6f94a48c5152cf0300743b597a --- /dev/null +++ b/projects/first_scene/resources/Sponza/sponza_thorn_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a73a17c883cd0d0d67cfda2dc4118400a916366c05b9a5ac465f0c8b30fd9c8e +size 635001 diff --git a/projects/first_scene/resources/Sponza/vase_dif.png b/projects/first_scene/resources/Sponza/vase_dif.png new file mode 100644 index 0000000000000000000000000000000000000000..61236a81cb324af8797b05099cd264cefe189e56 --- /dev/null +++ b/projects/first_scene/resources/Sponza/vase_dif.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53d06f52bf9e59df4cf00237707cca76c4f692bda61a62b06a30d321311d6dd9 +size 1842101 diff --git a/projects/first_scene/resources/Sponza/vase_hanging.png b/projects/first_scene/resources/Sponza/vase_hanging.png new file mode 100644 index 0000000000000000000000000000000000000000..36a3cee71d8213225090c74f8c0dce33b9d44378 --- /dev/null +++ b/projects/first_scene/resources/Sponza/vase_hanging.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a9d10b4f27a3c9a78d5bac882fdd4b6a6987c262f48fa490670fe5e235951e31 +size 1432804 diff --git a/projects/first_scene/resources/Sponza/vase_plant.png b/projects/first_scene/resources/Sponza/vase_plant.png new file mode 100644 index 0000000000000000000000000000000000000000..7ad95e702e229f1ebd803e5203a266d15f2c07b9 --- /dev/null +++ b/projects/first_scene/resources/Sponza/vase_plant.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2087371ff02212fb7014b6daefa191cf5676d2227193fff261a5d02f554cb8e +size 998089 diff --git a/projects/first_scene/resources/Sponza/vase_round.png b/projects/first_scene/resources/Sponza/vase_round.png new file mode 100644 index 0000000000000000000000000000000000000000..c17953abc000c44b8991e23c136c2b67348f3d1b --- /dev/null +++ b/projects/first_scene/resources/Sponza/vase_round.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa23d48d492d5d4ada2ddb27d1ef22952b214e6eb3b301c65f9d88442723d20a +size 1871399 diff --git a/projects/first_scene/resources/Szene/Szene.bin b/projects/first_scene/resources/Szene/Szene.bin new file mode 100644 index 0000000000000000000000000000000000000000..c87d27637516b0bbf864251dd162773f5cc53e06 --- /dev/null +++ b/projects/first_scene/resources/Szene/Szene.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee4742718f720d589a2a03f5d879f8c50ba9057718d191a43b046eaa9071080d +size 70328 diff --git a/projects/first_scene/resources/Szene/Szene.gltf b/projects/first_scene/resources/Szene/Szene.gltf new file mode 100644 index 0000000000000000000000000000000000000000..e5a32b29af5d0a2ac5f497e60b4b92c1873e1df9 --- /dev/null +++ b/projects/first_scene/resources/Szene/Szene.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75ba834118792ebbacf528a1690c7d04df4b4c8122b9f99a9aa9a9d075d2c86a +size 7421 diff --git a/projects/first_scene/resources/Szene/boards2_vcyc.jpg b/projects/first_scene/resources/Szene/boards2_vcyc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2636039e272289c0fba3fa2d88a060b857501248 --- /dev/null +++ b/projects/first_scene/resources/Szene/boards2_vcyc.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cca33a6e58ddd1b37a6e6853a9aa0e7b15ca678937119194752393dd2a0a0564 +size 1192476 diff --git a/projects/first_scene/resources/Szene/boards2_vcyc_jpg.jpg b/projects/first_scene/resources/Szene/boards2_vcyc_jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2636039e272289c0fba3fa2d88a060b857501248 --- /dev/null +++ b/projects/first_scene/resources/Szene/boards2_vcyc_jpg.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cca33a6e58ddd1b37a6e6853a9aa0e7b15ca678937119194752393dd2a0a0564 +size 1192476 diff --git a/projects/first_scene/resources/shaders/compile.bat b/projects/first_scene/resources/shaders/compile.bat new file mode 100644 index 0000000000000000000000000000000000000000..b4521235c40fe5fb163bab874560c2f219b7517f --- /dev/null +++ b/projects/first_scene/resources/shaders/compile.bat @@ -0,0 +1,3 @@ +%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv +%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv +pause \ No newline at end of file diff --git a/projects/first_scene/resources/shaders/frag.spv b/projects/first_scene/resources/shaders/frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..087e4e22fb2fcec27d99b3ff2aa1a705fe755796 Binary files /dev/null and b/projects/first_scene/resources/shaders/frag.spv differ diff --git a/projects/first_scene/resources/shaders/shader.frag b/projects/first_scene/resources/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..b5494bea7d6497e2e3dcd8559606864a71adb74e --- /dev/null +++ b/projects/first_scene/resources/shaders/shader.frag @@ -0,0 +1,15 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 passNormal; +layout(location = 1) in vec2 passUV; + +layout(location = 0) out vec3 outColor; + +layout(set=0, binding=0) uniform texture2D meshTexture; +layout(set=0, binding=1) uniform sampler textureSampler; + +void main() { + outColor = texture(sampler2D(meshTexture, textureSampler), passUV).rgb; + //outColor = passNormal * 0.5 + 0.5; +} \ No newline at end of file diff --git a/projects/first_scene/resources/shaders/shader.vert b/projects/first_scene/resources/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..76855152253b48b7400f016d063ed4f0e507435e --- /dev/null +++ b/projects/first_scene/resources/shaders/shader.vert @@ -0,0 +1,19 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec2 inUV; + +layout(location = 0) out vec3 passNormal; +layout(location = 1) out vec2 passUV; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +void main() { + gl_Position = mvp * vec4(inPosition, 1.0); + passNormal = inNormal; + passUV = inUV; +} \ No newline at end of file diff --git a/projects/first_scene/resources/shaders/vert.spv b/projects/first_scene/resources/shaders/vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..374c023e14b351eb43cbcda5951cbb8b3d6f96a1 Binary files /dev/null and b/projects/first_scene/resources/shaders/vert.spv differ diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a59edf7549dfd50877e78e3ca5071bba72098b3 --- /dev/null +++ b/projects/first_scene/src/main.cpp @@ -0,0 +1,266 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/Logger.hpp> + +glm::mat4 arrayTo4x4Matrix(std::array<float,16> array){ + glm::mat4 matrix; + for (int i = 0; i < 4; i++){ + for (int j = 0; j < 4; j++){ + matrix[i][j] = array[j * 4 + i]; + } + } + return matrix; +} + +int main(int argc, const char** argv) { + const char* applicationName = "First Scene"; + + uint32_t windowWidth = 800; + uint32_t windowHeight = 600; + + vkcv::Window window = vkcv::Window::create( + applicationName, + windowWidth, + windowHeight, + true + ); + + vkcv::camera::CameraManager cameraManager(window); + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(0, 0, -3)); + cameraManager.getCamera(camIndex0).setNearFar(0.1f, 30.0f); + + cameraManager.getCamera(camIndex1).setNearFar(0.1f, 30.0f); + + window.initEvents(); + + vkcv::Core core = vkcv::Core::create( + window, + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer }, + {}, + { "VK_KHR_swapchain" } + ); + + vkcv::asset::Scene scene; + + const char* path = argc > 1 ? argv[1] : "resources/Sponza/Sponza.gltf"; + int result = vkcv::asset::loadScene(path, scene); + + if (result == 1) { + std::cout << "Mesh loading successful!" << std::endl; + } + else { + std::cout << "Mesh loading failed: " << result << std::endl; + return 1; + } + + assert(!scene.vertexGroups.empty()); + std::vector<std::vector<uint8_t>> vBuffers; + std::vector<std::vector<uint8_t>> iBuffers; + + std::vector<vkcv::VertexBufferBinding> vBufferBindings; + std::vector<std::vector<vkcv::VertexBufferBinding>> vertexBufferBindings; + std::vector<vkcv::asset::VertexAttribute> vAttributes; + + for (int i = 0; i < scene.vertexGroups.size(); i++) { + + vBuffers.push_back(scene.vertexGroups[i].vertexBuffer.data); + iBuffers.push_back(scene.vertexGroups[i].indexBuffer.data); + + auto& attributes = scene.vertexGroups[i].vertexBuffer.attributes; + + std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { + return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); + }); + } + + std::vector<vkcv::Buffer<uint8_t>> vertexBuffers; + for (const vkcv::asset::VertexGroup& group : scene.vertexGroups) { + vertexBuffers.push_back(core.createBuffer<uint8_t>( + vkcv::BufferType::VERTEX, + group.vertexBuffer.data.size())); + vertexBuffers.back().fill(group.vertexBuffer.data); + } + + std::vector<vkcv::Buffer<uint8_t>> indexBuffers; + for (const auto& dataBuffer : iBuffers) { + indexBuffers.push_back(core.createBuffer<uint8_t>( + vkcv::BufferType::INDEX, + dataBuffer.size())); + indexBuffers.back().fill(dataBuffer); + } + + int vertexBufferIndex = 0; + for (const auto& vertexGroup : scene.vertexGroups) { + for (const auto& attribute : vertexGroup.vertexBuffer.attributes) { + vAttributes.push_back(attribute); + vBufferBindings.push_back(vkcv::VertexBufferBinding(attribute.offset, vertexBuffers[vertexBufferIndex].getVulkanHandle())); + } + vertexBufferBindings.push_back(vBufferBindings); + vBufferBindings.clear(); + vertexBufferIndex++; + } + + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchainImageFormat() + ); + + const vkcv::AttachmentDescription depth_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + vk::Format::eD32Sfloat + ); + + vkcv::PassConfig scenePassDefinition({ present_color_attachment, depth_attachment }); + vkcv::PassHandle scenePass = core.createPass(scenePassDefinition); + + if (!scenePass) { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + vkcv::ShaderProgram sceneShaderProgram{}; + sceneShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv")); + sceneShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); + + const std::vector<vkcv::VertexAttachment> vertexAttachments = sceneShaderProgram.getVertexAttachments(); + std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + } + + const vkcv::VertexLayout sceneLayout(bindings); + + uint32_t setID = 0; + + std::vector<vkcv::DescriptorBinding> descriptorBindings = { sceneShaderProgram.getReflectedDescriptors()[setID] }; + + vkcv::SamplerHandle sampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + + std::vector<vkcv::Image> sceneImages; + std::vector<vkcv::DescriptorSetHandle> descriptorSets; + for (const auto& vertexGroup : scene.vertexGroups) { + descriptorSets.push_back(core.createDescriptorSet(descriptorBindings)); + + const auto& material = scene.materials[vertexGroup.materialIndex]; + + int baseColorIndex = material.baseColor; + if (baseColorIndex < 0) { + vkcv_log(vkcv::LogLevel::WARNING, "Material lacks base color"); + baseColorIndex = 0; + } + + vkcv::asset::Texture& sceneTexture = scene.textures[baseColorIndex]; + + sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Srgb, sceneTexture.w, sceneTexture.h)); + sceneImages.back().fill(sceneTexture.data.data()); + + vkcv::DescriptorWrites setWrites; + setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, sceneImages.back().getHandle()) }; + setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; + core.writeDescriptorSet(descriptorSets.back(), setWrites); + } + + const vkcv::PipelineConfig scenePipelineDefsinition{ + sceneShaderProgram, + UINT32_MAX, + UINT32_MAX, + scenePass, + {sceneLayout}, + { core.getDescriptorSet(descriptorSets[0]).layout }, + true }; + vkcv::PipelineHandle scenePipeline = core.createGraphicsPipeline(scenePipelineDefsinition); + + if (!scenePipeline) { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle(); + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + std::vector<vkcv::DrawcallInfo> drawcalls; + for(int i = 0; i < scene.vertexGroups.size(); i++){ + vkcv::Mesh renderMesh(vertexBufferBindings[i], indexBuffers[i].getVulkanHandle(), scene.vertexGroups[i].numIndices); + + vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSets[i]).vulkanHandle); + + drawcalls.push_back(vkcv::DrawcallInfo(renderMesh, {descriptorUsage})); + } + + std::vector<glm::mat4> modelMatrices; + modelMatrices.resize(scene.vertexGroups.size(), glm::mat4(1.f)); + for (const auto &mesh : scene.meshes) { + const glm::mat4 m = arrayTo4x4Matrix(mesh.modelMatrix); + for (const auto &vertexGroupIndex : mesh.vertexGroups) { + modelMatrices[vertexGroupIndex] = m; + } + } + std::vector<glm::mat4> mvp; + + auto start = std::chrono::system_clock::now(); + while (window.isWindowOpen()) { + vkcv::Window::pollEvents(); + + if(window.getHeight() == 0 || window.getWidth() == 0) + continue; + + uint32_t swapchainWidth, swapchainHeight; + if (!core.beginFrame(swapchainWidth, swapchainHeight)) { + continue; + } + + if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { + depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); + + windowWidth = swapchainWidth; + windowHeight = swapchainHeight; + } + + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + + start = end; + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + glm::mat4 vp = cameraManager.getActiveCamera().getMVP(); + + mvp.clear(); + for (const auto& m : modelMatrices) { + mvp.push_back(vp * m); + } + + vkcv::PushConstantData pushConstantData((void*)mvp.data(), sizeof(glm::mat4)); + + const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + core.recordDrawcallsToCmdStream( + cmdStream, + scenePass, + scenePipeline, + pushConstantData, + drawcalls, + renderTargets); + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + core.endFrame(); + } + + return 0; +}