diff --git a/base/VulkanHeightmap.hpp b/base/VulkanHeightmap.hpp index 08592270..86099811 100644 --- a/base/VulkanHeightmap.hpp +++ b/base/VulkanHeightmap.hpp @@ -14,134 +14,136 @@ #include "VulkanDevice.hpp" #include "VulkanBuffer.hpp" -namespace vkTools +namespace vks { - class HeightMap + namespace utils { - private: - uint16_t *heightdata; - uint32_t dim; - uint32_t scale; - - vks::VulkanDevice *device = nullptr; - VkQueue copyQueue = VK_NULL_HANDLE; - public: - enum Topology { topologyTriangles, topologyQuads }; - - float heightScale = 1.0f; - float uvScale = 1.0f; - - vks::Buffer vertexBuffer; - vks::Buffer indexBuffer; - - struct Vertex { - glm::vec3 pos; - glm::vec3 normal; - glm::vec2 uv; - }; - - size_t vertexBufferSize = 0; - size_t indexBufferSize = 0; - uint32_t indexCount = 0; - - HeightMap(vks::VulkanDevice *device, VkQueue copyQueue) + class HeightMap { - this->device = device; - this->copyQueue = copyQueue; - }; + private: + uint16_t *heightdata; + uint32_t dim; + uint32_t scale; - ~HeightMap() - { - vertexBuffer.destroy(); - indexBuffer.destroy(); - delete[] heightdata; - } + vks::VulkanDevice *device = nullptr; + VkQueue copyQueue = VK_NULL_HANDLE; + public: + enum Topology { topologyTriangles, topologyQuads }; - float getHeight(uint32_t x, uint32_t y) - { - glm::ivec2 rpos = glm::ivec2(x, y) * glm::ivec2(scale); - rpos.x = std::max(0, std::min(rpos.x, (int)dim - 1)); - rpos.y = std::max(0, std::min(rpos.y, (int)dim - 1)); - rpos /= glm::ivec2(scale); - return *(heightdata + (rpos.x + rpos.y * dim) * scale) / 65535.0f * heightScale; - } + float heightScale = 1.0f; + float uvScale = 1.0f; -#if defined(__ANDROID__) - void loadFromFile(const std::string filename, uint32_t patchsize, glm::vec3 scale, Topology topology, AAssetManager* assetManager) -#else - void loadFromFile(const std::string filename, uint32_t patchsize, glm::vec3 scale, Topology topology) -#endif - { - assert(device); - assert(copyQueue != VK_NULL_HANDLE); + vks::Buffer vertexBuffer; + vks::Buffer indexBuffer; -#if defined(__ANDROID__) - AAsset* asset = AAssetManager_open(assetManager, filename.c_str(), AASSET_MODE_STREAMING); - assert(asset); - size_t size = AAsset_getLength(asset); - assert(size > 0); - void *textureData = malloc(size); - AAsset_read(asset, textureData, size); - AAsset_close(asset); - gli::texture2d heightTex(gli::load((const char*)textureData, size)); - free(textureData); -#else - gli::texture2d heightTex(gli::load(filename)); -#endif - dim = static_cast(heightTex.extent().x); - heightdata = new uint16_t[dim * dim]; - memcpy(heightdata, heightTex.data(), heightTex.size()); - this->scale = dim / patchsize; - this->heightScale = scale.y; + struct Vertex { + glm::vec3 pos; + glm::vec3 normal; + glm::vec2 uv; + }; - // Generate vertices + size_t vertexBufferSize = 0; + size_t indexBufferSize = 0; + uint32_t indexCount = 0; - Vertex * vertices = new Vertex[patchsize * patchsize * 4]; - - const float wx = 2.0f; - const float wy = 2.0f; - - for (uint32_t x = 0; x < patchsize; x++) + HeightMap(vks::VulkanDevice *device, VkQueue copyQueue) { - for (uint32_t y = 0; y < patchsize; y++) - { - uint32_t index = (x + y * patchsize); - vertices[index].pos[0] = (x * wx + wx / 2.0f - (float)patchsize * wx / 2.0f) * scale.x; - vertices[index].pos[1] = -getHeight(x, y); - vertices[index].pos[2] = (y * wy + wy / 2.0f - (float)patchsize * wy / 2.0f) * scale.z; - vertices[index].uv = glm::vec2((float)x / patchsize, (float)y / patchsize) * uvScale; - } + this->device = device; + this->copyQueue = copyQueue; + }; + + ~HeightMap() + { + vertexBuffer.destroy(); + indexBuffer.destroy(); + delete[] heightdata; } - for (uint32_t y = 0; y < patchsize; y++) + float getHeight(uint32_t x, uint32_t y) { + glm::ivec2 rpos = glm::ivec2(x, y) * glm::ivec2(scale); + rpos.x = std::max(0, std::min(rpos.x, (int)dim - 1)); + rpos.y = std::max(0, std::min(rpos.y, (int)dim - 1)); + rpos /= glm::ivec2(scale); + return *(heightdata + (rpos.x + rpos.y * dim) * scale) / 65535.0f * heightScale; + } + +#if defined(__ANDROID__) + void loadFromFile(const std::string filename, uint32_t patchsize, glm::vec3 scale, Topology topology, AAssetManager* assetManager) +#else + void loadFromFile(const std::string filename, uint32_t patchsize, glm::vec3 scale, Topology topology) +#endif + { + assert(device); + assert(copyQueue != VK_NULL_HANDLE); + +#if defined(__ANDROID__) + AAsset* asset = AAssetManager_open(assetManager, filename.c_str(), AASSET_MODE_STREAMING); + assert(asset); + size_t size = AAsset_getLength(asset); + assert(size > 0); + void *textureData = malloc(size); + AAsset_read(asset, textureData, size); + AAsset_close(asset); + gli::texture2d heightTex(gli::load((const char*)textureData, size)); + free(textureData); +#else + gli::texture2d heightTex(gli::load(filename)); +#endif + dim = static_cast(heightTex.extent().x); + heightdata = new uint16_t[dim * dim]; + memcpy(heightdata, heightTex.data(), heightTex.size()); + this->scale = dim / patchsize; + this->heightScale = scale.y; + + // Generate vertices + + Vertex * vertices = new Vertex[patchsize * patchsize * 4]; + + const float wx = 2.0f; + const float wy = 2.0f; + for (uint32_t x = 0; x < patchsize; x++) { - float dx = getHeight(x < patchsize - 1 ? x + 1 : x, y) - getHeight(x > 0 ? x - 1 : x, y); - if (x == 0 || x == patchsize - 1) - dx *= 2.0f; - - float dy = getHeight(x, y < patchsize - 1 ? y + 1 : y) - getHeight(x, y > 0 ? y - 1 : y); - if (y == 0 || y == patchsize - 1) - dy *= 2.0f; - - glm::vec3 A = glm::vec3(1.0f, 0.0f, dx); - glm::vec3 B = glm::vec3(0.0f, 1.0f, dy); - - glm::vec3 normal = (glm::normalize(glm::cross(A, B)) + 1.0f) * 0.5f; - - vertices[x + y * patchsize].normal = glm::vec3(normal.x, normal.z, normal.y); + for (uint32_t y = 0; y < patchsize; y++) + { + uint32_t index = (x + y * patchsize); + vertices[index].pos[0] = (x * wx + wx / 2.0f - (float)patchsize * wx / 2.0f) * scale.x; + vertices[index].pos[1] = -getHeight(x, y); + vertices[index].pos[2] = (y * wy + wy / 2.0f - (float)patchsize * wy / 2.0f) * scale.z; + vertices[index].uv = glm::vec2((float)x / patchsize, (float)y / patchsize) * uvScale; + } } - } - // Generate indices + for (uint32_t y = 0; y < patchsize; y++) + { + for (uint32_t x = 0; x < patchsize; x++) + { + float dx = getHeight(x < patchsize - 1 ? x + 1 : x, y) - getHeight(x > 0 ? x - 1 : x, y); + if (x == 0 || x == patchsize - 1) + dx *= 2.0f; - const uint32_t w = (patchsize - 1); - uint32_t *indices; - - switch (topology) - { - // Indices for triangles + float dy = getHeight(x, y < patchsize - 1 ? y + 1 : y) - getHeight(x, y > 0 ? y - 1 : y); + if (y == 0 || y == patchsize - 1) + dy *= 2.0f; + + glm::vec3 A = glm::vec3(1.0f, 0.0f, dx); + glm::vec3 B = glm::vec3(0.0f, 1.0f, dy); + + glm::vec3 normal = (glm::normalize(glm::cross(A, B)) + 1.0f) * 0.5f; + + vertices[x + y * patchsize].normal = glm::vec3(normal.x, normal.z, normal.y); + } + } + + // Generate indices + + const uint32_t w = (patchsize - 1); + uint32_t *indices; + + switch (topology) + { + // Indices for triangles case topologyTriangles: { indices = new uint32_t[w * w * 6]; @@ -183,72 +185,73 @@ namespace vkTools indexBufferSize = (w * w * 4) * sizeof(uint32_t); break; } - + + } + + assert(indexBufferSize > 0); + + vertexBufferSize = (patchsize * patchsize * 4) * sizeof(Vertex); + + // Generate Vulkan buffers + + vks::Buffer vertexStaging, indexStaging; + + // Create staging buffers + device->createBuffer( + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &vertexStaging, + vertexBufferSize, + vertices); + + device->createBuffer( + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &indexStaging, + indexBufferSize, + indices); + + // Device local (target) buffer + device->createBuffer( + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + &vertexBuffer, + vertexBufferSize); + + device->createBuffer( + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + &indexBuffer, + indexBufferSize); + + // Copy from staging buffers + VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + + VkBufferCopy copyRegion = {}; + + copyRegion.size = vertexBufferSize; + vkCmdCopyBuffer( + copyCmd, + vertexStaging.buffer, + vertexBuffer.buffer, + 1, + ©Region); + + copyRegion.size = indexBufferSize; + vkCmdCopyBuffer( + copyCmd, + indexStaging.buffer, + indexBuffer.buffer, + 1, + ©Region); + + device->flushCommandBuffer(copyCmd, copyQueue, true); + + vkDestroyBuffer(device->logicalDevice, vertexStaging.buffer, nullptr); + vkFreeMemory(device->logicalDevice, vertexStaging.memory, nullptr); + vkDestroyBuffer(device->logicalDevice, indexStaging.buffer, nullptr); + vkFreeMemory(device->logicalDevice, indexStaging.memory, nullptr); } - - assert(indexBufferSize > 0); - - vertexBufferSize = (patchsize * patchsize * 4) * sizeof(Vertex); - - // Generate Vulkan buffers - - vks::Buffer vertexStaging, indexStaging; - - // Create staging buffers - device->createBuffer( - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &vertexStaging, - vertexBufferSize, - vertices); - - device->createBuffer( - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &indexStaging, - indexBufferSize, - indices); - - // Device local (target) buffer - device->createBuffer( - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - &vertexBuffer, - vertexBufferSize); - - device->createBuffer( - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - &indexBuffer, - indexBufferSize); - - // Copy from staging buffers - VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - VkBufferCopy copyRegion = {}; - - copyRegion.size = vertexBufferSize; - vkCmdCopyBuffer( - copyCmd, - vertexStaging.buffer, - vertexBuffer.buffer, - 1, - ©Region); - - copyRegion.size = indexBufferSize; - vkCmdCopyBuffer( - copyCmd, - indexStaging.buffer, - indexBuffer.buffer, - 1, - ©Region); - - device->flushCommandBuffer(copyCmd, copyQueue, true); - - vkDestroyBuffer(device->logicalDevice, vertexStaging.buffer, nullptr); - vkFreeMemory(device->logicalDevice, vertexStaging.memory, nullptr); - vkDestroyBuffer(device->logicalDevice, indexStaging.buffer, nullptr); - vkFreeMemory(device->logicalDevice, indexStaging.memory, nullptr); - } - }; + }; + } } diff --git a/texturesparseresidency/texturesparseresidency.cpp b/texturesparseresidency/texturesparseresidency.cpp index 151c4254..6f033b1c 100644 --- a/texturesparseresidency/texturesparseresidency.cpp +++ b/texturesparseresidency/texturesparseresidency.cpp @@ -197,7 +197,7 @@ public: vks::Texture2D source; } textures; - vkTools::HeightMap *heightMap = nullptr; + vks::utils::HeightMap *heightMap = nullptr; struct { VkPipelineVertexInputStateCreateInfo inputState; @@ -660,11 +660,11 @@ public: // Generate a terrain quad patch for feeding to the tessellation control shader void generateTerrain() { - heightMap = new vkTools::HeightMap(vulkanDevice, queue); + heightMap = new vks::utils::HeightMap(vulkanDevice, queue); #if defined(__ANDROID__) - heightMap->loadFromFile(getAssetPath() + "textures/terrain_heightmap_r16.ktx", 128, glm::vec3(2.0f, 48.0f, 2.0f), vkTools::HeightMap::topologyTriangles, androidApp->activity->assetManager); + heightMap->loadFromFile(getAssetPath() + "textures/terrain_heightmap_r16.ktx", 128, glm::vec3(2.0f, 48.0f, 2.0f), vks::utils::HeightMap::topologyTriangles, androidApp->activity->assetManager); #else - heightMap->loadFromFile(getAssetPath() + "textures/terrain_heightmap_r16.ktx", 128, glm::vec3(2.0f, 48.0f, 2.0f), vkTools::HeightMap::topologyTriangles); + heightMap->loadFromFile(getAssetPath() + "textures/terrain_heightmap_r16.ktx", 128, glm::vec3(2.0f, 48.0f, 2.0f), vks::utils::HeightMap::topologyTriangles); #endif }