Add textures

This commit is contained in:
bailwillharr 2022-11-11 16:18:22 +00:00
parent 7cc09484c1
commit d71254985b
23 changed files with 298 additions and 81 deletions

View File

@ -23,7 +23,7 @@ namespace engine {
// adds a draw call to the queue
// vertexBuffer is required, indexBuffer can be NULL, uniformData is required
void draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData, size_t pushConstantSize);
void draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData, size_t pushConstantSize, const gfx::Texture* texture);
// Call once per frame. Executes all queued draw calls and renders to the screen.
void renderFrame();

View File

@ -14,6 +14,8 @@ public:
Texture(const std::filesystem::path& resPath);
~Texture() override;
gfx::Texture* getHandle();
private:
gfx::Texture* m_gpuTexture;
};

View File

@ -77,7 +77,6 @@ void Camera::usePerspective(float fovDeg)
float fovRad = glm::radians(fovDeg);
m_projMatrix = glm::perspectiveFovRH_ZO(fovRad, viewportDim.x, viewportDim.y, NEAR, FAR);
m_projMatrix[1][1] *= -1;
}
void Camera::useOrtho()
@ -88,7 +87,6 @@ void Camera::useOrtho()
float aspect = viewportDim.x / viewportDim.y;
m_projMatrix = glm::orthoRH_ZO(-10.0f * aspect, 10.0f * aspect, -10.0f, 10.0f, -100.0f, 100.0f);
m_projMatrix[1][1] *= -1;
}
}

View File

@ -17,7 +17,7 @@ namespace engine::components {
Renderer::Renderer(Object* parent) : Component(parent, TypeEnum::RENDERER)
{
m_shader = this->parent.res.get<resources::Shader>("shader.glsl");
// m_texture = this->parent.res.get<resources::Texture>("textures/missing.png");
m_texture = this->parent.res.get<resources::Texture>("textures/missing.png");
}
Renderer::~Renderer()
@ -32,7 +32,7 @@ void Renderer::render(glm::mat4 transform, glm::mat4 view)
gfxdev->updateUniformBuffer(m_shader->getPipeline(), &uniformData.color, sizeof(uniformData.color), offsetof(resources::Shader::UniformBuffer, color));
glm::mat4 pushConsts[] = { transform, view };
gfxdev->draw(m_shader->getPipeline(), m_mesh->vb, m_mesh->ib, m_mesh->m_vertices.size(), pushConsts, sizeof(glm::mat4) * 2);
gfxdev->draw(m_shader->getPipeline(), m_mesh->vb, m_mesh->ib, m_mesh->m_indices.size(), pushConsts, sizeof(glm::mat4) * 2, m_texture->getHandle());
}
void Renderer::setMesh(const std::string& name)

View File

@ -58,7 +58,6 @@ namespace engine {
VkQueue handle;
};
struct DepthBuffer {
VkImage image;
VmaAllocation allocation;
@ -91,6 +90,7 @@ namespace engine {
const gfx::Buffer* indexBuffer = nullptr; // if this is nullptr, don't use indexed
uint32_t count = 0;
uint8_t pushConstantData[PUSH_CONSTANT_MAX_SIZE];
const gfx::Texture* texture = nullptr;
};
enum class QueueFlags : uint32_t {
@ -119,6 +119,11 @@ namespace engine {
struct gfx::Texture {
VkImage image;
VmaAllocation alloc;
VkImageView imageView;
VkSampler sampler;
VkDescriptorPool pool;
std::array<VkDescriptorSet, FRAMES_IN_FLIGHT> descriptorSets{};
uint32_t mipLevels;
};
@ -164,7 +169,6 @@ namespace engine {
options.SetOptimizationLevel(shaderc_optimization_level_size);
options.SetTargetSpirv(shaderc_spirv_version_1_6);
options.SetAutoBindUniforms(false);
options.SetInvertY(false);
// preprocess
shaderc::PreprocessedSourceCompilationResult preprocessed = compiler.PreprocessGlsl(source, kind, filename, options);
@ -774,7 +778,7 @@ namespace engine {
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
}
static void cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImageLayout oldLayout, VkImageLayout newLayout, VkImage image)
static void cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t mipLevels, VkImage image)
{
VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
@ -785,7 +789,7 @@ namespace engine {
barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.levelCount = mipLevels;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
@ -814,6 +818,77 @@ namespace engine {
}
static void cmdGenerateMipmaps(VkCommandBuffer commandBuffer, VkImage image, int32_t width, int32_t height, uint32_t mipLevels)
{
VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
barrier.image = image;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.subresourceRange.levelCount = 1;
int32_t mipWidth = width;
int32_t mipHeight = height;
for (uint32_t i = 1; i < mipLevels; i++) {
barrier.subresourceRange.baseMipLevel = i - 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
0, nullptr,
0, nullptr,
1, &barrier);
VkImageBlit blit{};
blit.srcOffsets[0] = { 0, 0, 0 };
blit.srcOffsets[1] = { mipWidth, mipHeight, 1 };
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = i - 1;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = 1;
blit.dstOffsets[0] = { 0, 0, 0 };
blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = i;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = 1;
vkCmdBlitImage(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, nullptr,
0, nullptr,
1, &barrier);
if (mipWidth > 1) mipWidth /= 2;
if (mipHeight > 1) mipHeight /= 2;
}
barrier.subresourceRange.baseMipLevel = mipLevels - 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr,
0, nullptr,
1, &barrier);
}
// class definitions
struct GFXDevice::Impl {
@ -845,7 +920,10 @@ namespace engine {
std::map<const gfx::Pipeline*, std::queue<DrawCall>> drawQueues{};
VkDescriptorSetLayoutBinding uboLayoutBinding{};
VkDescriptorSetLayout uboLayout{};
VkDescriptorSetLayout descriptorSetLayout{};
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
VkDescriptorSetLayout samplerSetLayout{};
};
@ -1032,6 +1110,19 @@ namespace engine {
continue;
}
// check for some features:
VkPhysicalDeviceFeatures devFeatures;
vkGetPhysicalDeviceFeatures(dev, &devFeatures);
// anisotropic filtering is needed
if (devFeatures.samplerAnisotropy == VK_FALSE) continue;
// check for linear filtering for mipmaps
VkFormatProperties formatProperties{};
vkGetPhysicalDeviceFormatProperties(dev, VK_FORMAT_R8G8B8A8_SRGB, &formatProperties);
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
continue;
}
pimpl->physicalDevice = dev;
break;
@ -1127,6 +1218,9 @@ namespace engine {
throw std::runtime_error("The selected queue family does not support this surface");
}
VkPhysicalDeviceFeatures deviceFeatures{};
deviceFeatures.samplerAnisotropy = VK_TRUE;
VkDeviceCreateInfo deviceCreateInfo{
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = nullptr,
@ -1137,7 +1231,7 @@ namespace engine {
// IGNORED: .ppEnabledLayerNames
.enabledExtensionCount = (uint32_t)requiredDeviceExtensions.size(),
.ppEnabledExtensionNames = requiredDeviceExtensions.data(),
.pEnabledFeatures = nullptr,
.pEnabledFeatures = &deviceFeatures,
};
res = vkCreateDevice(pimpl->physicalDevice, &deviceCreateInfo, nullptr, &pimpl->device);
@ -1244,24 +1338,41 @@ namespace engine {
assert(res == VK_SUCCESS);
}
// create uniform buffer stuff
// create uniform buffer descriptor set layout
pimpl->uboLayoutBinding.binding = 0;
pimpl->uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
pimpl->uboLayoutBinding.descriptorCount = 1;
pimpl->uboLayoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
pimpl->uboLayoutBinding.pImmutableSamplers = nullptr;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
descriptorSetLayoutInfo.bindingCount = 1;
descriptorSetLayoutInfo.pBindings = &pimpl->uboLayoutBinding;
res = vkCreateDescriptorSetLayout(pimpl->device, &descriptorSetLayoutInfo, nullptr, &pimpl->uboLayout);
res = vkCreateDescriptorSetLayout(pimpl->device, &descriptorSetLayoutInfo, nullptr, &pimpl->descriptorSetLayout);
assert(res == VK_SUCCESS);
// create texture sampler descriptor set layout
pimpl->samplerLayoutBinding.binding = 0;
pimpl->samplerLayoutBinding.descriptorCount = 1;
pimpl->samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
pimpl->samplerLayoutBinding.pImmutableSamplers = nullptr;
pimpl->samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo samplerSetLayoutInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
samplerSetLayoutInfo.bindingCount = 1;
samplerSetLayoutInfo.pBindings = &pimpl->samplerLayoutBinding;
res = vkCreateDescriptorSetLayout(pimpl->device, &samplerSetLayoutInfo, nullptr, &pimpl->samplerSetLayout);
assert(res == VK_SUCCESS);
}
GFXDevice::~GFXDevice()
{
TRACE("Destroying GFXDevice...");
vkDestroyDescriptorSetLayout(pimpl->device, pimpl->uboLayout, nullptr);
vkDestroyDescriptorSetLayout(pimpl->device, pimpl->samplerSetLayout, nullptr);
vkDestroyDescriptorSetLayout(pimpl->device, pimpl->descriptorSetLayout, nullptr);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
@ -1298,7 +1409,7 @@ namespace engine {
*h = (uint32_t)height;
}
void GFXDevice::draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData, size_t pushConstantSize)
void GFXDevice::draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData, size_t pushConstantSize, const gfx::Texture* texture)
{
assert(vertexBuffer->type == gfx::BufferType::VERTEX);
assert(vertexBuffer != nullptr);
@ -1313,6 +1424,8 @@ namespace engine {
memcpy(call.pushConstantData, pushConstantData, pushConstantSize);
call.texture = texture; // will be ignored if nullptr
pimpl->drawQueues[pipeline].push(call);
}
@ -1367,9 +1480,9 @@ namespace engine {
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.y = (float)pimpl->swapchain.extent.height;
viewport.width = (float)pimpl->swapchain.extent.width;
viewport.height = (float)pimpl->swapchain.extent.height;
viewport.height = -(float)pimpl->swapchain.extent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(pimpl->commandBuffers[frameIndex], 0, 1, &viewport);
@ -1390,6 +1503,8 @@ namespace engine {
DrawCall call = queue.front();
vkCmdBindDescriptorSets(pimpl->commandBuffers[frameIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->layout, 1, 1, &call.texture->descriptorSets[frameIndex], 0, nullptr);
vkCmdPushConstants(pimpl->commandBuffers[frameIndex], pipeline->layout, VK_SHADER_STAGE_VERTEX_BIT, 0, PUSH_CONSTANT_MAX_SIZE, call.pushConstantData);
vkCmdBindVertexBuffers(pimpl->commandBuffers[frameIndex], 0, 1, &call.vertexBuffer->buffer, offsets);
@ -1465,7 +1580,7 @@ namespace engine {
VkShaderModule vertShaderModule = compileShader(pimpl->device, shaderc_vertex_shader, vertShaderCode.data(), vertShaderPath);
VkShaderModule fragShaderModule = compileShader(pimpl->device, shaderc_fragment_shader, fragShaderCode.data(), fragShaderPath);
// create uniform buffers
pipeline->uniformBuffers.resize(FRAMES_IN_FLIGHT);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
@ -1490,10 +1605,11 @@ namespace engine {
pipeline->uniformBuffers[i] = buf;
}
// create descriptor pool for uniform buffers
// create descriptor pools
VkDescriptorPoolSize poolSize{};
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSize.descriptorCount = FRAMES_IN_FLIGHT;
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = 1;
@ -1503,19 +1619,21 @@ namespace engine {
assert(res == VK_SUCCESS);
std::array<VkDescriptorSetLayout, FRAMES_IN_FLIGHT> layouts;
layouts.fill(pimpl->uboLayout);
layouts.fill(pimpl->descriptorSetLayout);
VkDescriptorSetAllocateInfo dSetAllocInfo{};
dSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
dSetAllocInfo.descriptorPool = pipeline->descriptorPool;
dSetAllocInfo.descriptorSetCount = FRAMES_IN_FLIGHT;
dSetAllocInfo.pSetLayouts = layouts.data();
res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, pipeline->descriptorSets.data());
assert(res == VK_SUCCESS);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = pipeline->uniformBuffers[i]->buffer;
bufferInfo.offset = 0;
bufferInfo.range = uniformBufferSize;
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = pipeline->descriptorSets[i];
@ -1576,9 +1694,9 @@ namespace engine {
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.y = (float)pimpl->swapchain.extent.height;
viewport.width = (float)pimpl->swapchain.extent.width;
viewport.height = (float)pimpl->swapchain.extent.height;
viewport.height = -(float)pimpl->swapchain.extent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
@ -1667,10 +1785,12 @@ namespace engine {
pushConstantRange.size = PUSH_CONSTANT_MAX_SIZE;
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
std::array<VkDescriptorSetLayout, 2> setLayouts{ pimpl->descriptorSetLayout, pimpl->samplerSetLayout};
VkPipelineLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layoutInfo.setLayoutCount = 1;
layoutInfo.pSetLayouts = &pimpl->uboLayout;
layoutInfo.setLayoutCount = setLayouts.size();
layoutInfo.pSetLayouts = setLayouts.data();
layoutInfo.pushConstantRangeCount = 1;
layoutInfo.pPushConstantRanges = &pushConstantRange;
@ -1810,6 +1930,8 @@ namespace engine {
size_t imageSize = w * h * 4;
out->mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(w, h)))) + 1;
// first load image into staging buffer
VkBuffer stagingBuffer;
VmaAllocation stagingAllocation;
@ -1841,12 +1963,12 @@ namespace engine {
imageInfo.extent.width = w;
imageInfo.extent.height = h;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.mipLevels = out->mipLevels;
imageInfo.arrayLayers = 1;
imageInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.flags = 0;
@ -1863,7 +1985,7 @@ namespace engine {
// begin cmd buffer
cmdTransitionImageLayout(commandBuffer, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, out->image);
cmdTransitionImageLayout(commandBuffer, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, out->mipLevels, out->image);
VkBufferImageCopy region{};
region.bufferOffset = 0;
@ -1880,7 +2002,8 @@ namespace engine {
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, out->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
cmdTransitionImageLayout(commandBuffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, out->image);
// Mipmap generation handles the transition to SHADER_READ_ONLY_OPTIMAL
cmdGenerateMipmaps(commandBuffer, out->image, w, h, out->mipLevels);
// end cmd buffer
endOneTimeCommands(pimpl->device, pimpl->commandPool, commandBuffer, pimpl->gfxQueue.handle);
@ -1890,11 +2013,101 @@ namespace engine {
// destroy staging buffer
vmaDestroyBuffer(pimpl->allocator, stagingBuffer, stagingAllocation);
// create image view
VkImageViewCreateInfo imageViewInfo{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
imageViewInfo.image = out->image;
imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
imageViewInfo.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = out->mipLevels,
.baseArrayLayer = 0,
.layerCount = 1
};
res = vkCreateImageView(pimpl->device, &imageViewInfo, nullptr, &out->imageView);
assert(res == VK_SUCCESS);
// create texture sampler
{
VkSamplerCreateInfo samplerInfo{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.anisotropyEnable = VK_TRUE;
// Find max anisotropic filtering level
{
VkPhysicalDeviceProperties properties{};
vkGetPhysicalDeviceProperties(pimpl->physicalDevice, &properties);
INFO("Anisotropic filtering level: {}", properties.limits.maxSamplerAnisotropy);
samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
}
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
samplerInfo.unnormalizedCoordinates = VK_FALSE;
samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = static_cast<float>(out->mipLevels);
samplerInfo.mipLodBias = 0.0f;
res = vkCreateSampler(pimpl->device, &samplerInfo, nullptr, &out->sampler);
assert(res == VK_SUCCESS);
}
// create descriptor pools
VkDescriptorPoolSize poolSize{};
poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
poolSize.descriptorCount = FRAMES_IN_FLIGHT;
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = 1;
poolInfo.pPoolSizes = &poolSize;
poolInfo.maxSets = FRAMES_IN_FLIGHT;
res = vkCreateDescriptorPool(pimpl->device, &poolInfo, nullptr, &out->pool);
assert(res == VK_SUCCESS);
std::array<VkDescriptorSetLayout, FRAMES_IN_FLIGHT> layouts{};
layouts.fill(pimpl->samplerSetLayout);
VkDescriptorSetAllocateInfo dSetAllocInfo{};
dSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
dSetAllocInfo.descriptorPool = out->pool;
dSetAllocInfo.descriptorSetCount = FRAMES_IN_FLIGHT;
dSetAllocInfo.pSetLayouts = layouts.data();
res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, out->descriptorSets.data());
assert(res == VK_SUCCESS);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfo.imageView = out->imageView;
imageInfo.sampler = out->sampler;
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = out->descriptorSets[i];
descriptorWrite.dstBinding = 0;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pImageInfo = &imageInfo;
vkUpdateDescriptorSets(pimpl->device, 1, &descriptorWrite, 0, nullptr);
}
return out;
}
void GFXDevice::destroyTexture(const gfx::Texture* texture)
{
vkDestroyDescriptorPool(pimpl->device, texture->pool, nullptr);
vkDestroySampler(pimpl->device, texture->sampler, nullptr);
vkDestroyImageView(pimpl->device, texture->imageView, nullptr);
vmaDestroyImage(pimpl->allocator, texture->image, texture->alloc);
}

View File

@ -31,7 +31,7 @@ static void loadMeshFromFile(const std::filesystem::path& path, std::vector<Vert
vertices->resize(header.vertex_count);
fread(indices->data(), sizeof(uint32_t) * header.index_count, 1, fp);
fread(vertices->data(), sizeof(float) * 8 * header.vertex_count, 1, fp);
fread(vertices->data(), sizeof(Vertex) * header.vertex_count, 1, fp);
fclose(fp);
}

View File

@ -10,7 +10,7 @@
namespace engine::resources {
// returns false if unable to open file
static bool readPNG(const std::string& path, std::vector<uint8_t>& texbuf, int *width, int *height, bool *isRGBA)
static bool readPNG(const std::string& path, std::vector<uint8_t>* texbuf, int *width, int *height, bool *isRGBA)
{
int x, y, n;
unsigned char *data = stbi_load(path.c_str(), &x, &y, &n, STBI_rgb_alpha);
@ -22,8 +22,8 @@ static bool readPNG(const std::string& path, std::vector<uint8_t>& texbuf, int *
const size_t size = (size_t)x * (size_t)y * 4;
texbuf.resize(size);
memcpy(texbuf.data(), data, size);
texbuf->resize(size);
memcpy(texbuf->data(), data, size);
*width = x;
*height = y;
@ -35,7 +35,7 @@ static bool readPNG(const std::string& path, std::vector<uint8_t>& texbuf, int *
}
static bool readGLRaw(const std::string& path, std::vector<uint8_t>& texbuf, int *width, int *height, bool *isRGBA)
static bool readGLRaw(const std::string& path, std::vector<uint8_t>* texbuf, int *width, int *height, bool *isRGBA)
{
FILE *fp = fopen(path.c_str(), "rb");
if (!fp) {
@ -49,9 +49,9 @@ static bool readGLRaw(const std::string& path, std::vector<uint8_t>& texbuf, int
fseek(fp, 0L, SEEK_END);
uint64_t end = ftell(fp);
texbuf.resize(end);
texbuf->resize(end);
fseek(fp, (long)tex_data_offset, SEEK_SET);
fread(texbuf.data(), 1, end, fp);
fread(texbuf->data(), 1, end, fp);
fclose(fp);
@ -66,15 +66,15 @@ static bool readGLRaw(const std::string& path, std::vector<uint8_t>& texbuf, int
Texture::Texture(const std::filesystem::path& resPath) : Resource(resPath, "texture")
{
std::vector<uint8_t> texbuf;
auto texbuf = std::make_unique<std::vector<uint8_t>>();
int width, height;
bool isRGBA, success;
if (resPath.extension() == ".png") {
success = readPNG(resPath.string(), texbuf, &width, &height, &isRGBA);
if (resPath.extension() == ".png" || resPath.extension() == ".jpg") {
success = readPNG(resPath.string(), texbuf.get(), &width, &height, &isRGBA);
} else {
success = readGLRaw(resPath.string(), texbuf, &width, &height, &isRGBA);
success = readGLRaw(resPath.string(), texbuf.get(), &width, &height, &isRGBA);
}
if (!success) {
@ -82,12 +82,12 @@ Texture::Texture(const std::filesystem::path& resPath) : Resource(resPath, "text
}
if (isRGBA == false) {
throw std::runtime_error("Currently, only RGBA textures are supported. Size: " + std::to_string(texbuf.size()));
throw std::runtime_error("Currently, only RGBA textures are supported. Size: " + std::to_string(texbuf->size()));
}
m_gpuTexture = gfxdev->createTexture(texbuf.data(), (uint32_t)width, (uint32_t)height);
m_gpuTexture = gfxdev->createTexture(texbuf->data(), (uint32_t)width, (uint32_t)height);
DEBUG("loaded texture {} width: {} height: {} size: {}", resPath.filename().string(), width, height, texbuf.size());
DEBUG("loaded texture {} width: {} height: {} size: {}", resPath.filename().string(), width, height, texbuf->size());
}
@ -96,4 +96,9 @@ Texture::~Texture()
gfxdev->destroyTexture(m_gpuTexture);
}
gfx::Texture* Texture::getHandle()
{
return m_gpuTexture;
}
}

View File

@ -276,12 +276,19 @@ namespace engine {
void Window::setFullscreen(bool fullscreen, bool exclusive)
{
if (m_resizable) {
SDL_DisplayMode mode;
SDL_GetDesktopDisplayMode(SDL_GetWindowDisplayIndex(m_handle), &mode);
SDL_SetWindowDisplayMode(m_handle, &mode);
if (SDL_SetWindowFullscreen(m_handle, fullscreen ? (exclusive ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP) : 0) != 0) {
throw std::runtime_error("Unable to set window to fullscreen/windowed");
}
m_fullscreen = fullscreen;
if (fullscreen) {
int width, height;
SDL_GetWindowSize(m_handle, &width, &height);
onResize(width, height);
@ -291,7 +298,7 @@ namespace engine {
void Window::toggleFullscreen()
{
setFullscreen(!m_fullscreen, false);
setFullscreen(!m_fullscreen, true);
}
bool Window::isFullscreen() const

BIN
test/game.aps Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -8,7 +8,7 @@ layout(location = 4) in vec3 fragColor;
layout(location = 0) out vec4 outColor;
float snoise(vec2 v);
layout(set = 1, binding = 0) uniform sampler2D texSampler;
void main() {
@ -16,7 +16,7 @@ void main() {
vec3 lightColor = vec3(1.0, 1.0, 1.0);
vec3 ambientColor = vec3(1.0, 1.0, 1.0);
float ambientStrength = 0.1;
vec3 baseColor = vec3(fragColor.x * snoise(fragUV * 10.0), mod(fragUV.x, 1.0), mod(fragUV.y, 1.0));
vec3 baseColor = vec3(texture(texSampler, fragUV));
vec3 emission = vec3(0.0, 0.0, 0.0);
// code
@ -35,37 +35,4 @@ void main() {
vec3 lighting = min(diffuse + ambient + specular, 1.0);
outColor = min( ( vec4(baseColor, 1.0) ) * vec4(lighting + emission, 1.0), vec4(1.0));
}
// Simplex 2D noise
//
vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }
float snoise(vec2 v){
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
-0.577350269189626, 0.024390243902439);
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
vec2 i1;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod(i, 289.0);
vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
+ i.x + vec3(0.0, i1.x, 1.0 ));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
dot(x12.zw,x12.zw)), 0.0);
m = m*m ;
m = m*m ;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}

Binary file not shown.

Binary file not shown.

BIN
test/res/textures/door.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

BIN
test/res/textures/grass.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

BIN
test/res/textures/metal.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
test/res/textures/rock.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 KiB

View File

@ -56,8 +56,8 @@ void playGame()
auto camCamera = cam->createComponent<engine::components::Camera>();
camCamera->usePerspective(70.0f);
cam->createComponent<CameraController>();
cam->createComponent<engine::components::Renderer>()->m_mesh = genSphereMesh(0.2f, 20);
cam->getComponent<engine::components::Renderer>()->setTexture("textures/cobble_stone.png");
//cam->createComponent<engine::components::Renderer>()->m_mesh = genSphereMesh(0.2f, 20);
//cam->getComponent<engine::components::Renderer>()->setTexture("textures/cobble_stone.png");
auto gun = cam->createChild("gun");
gun->transform.position = glm::vec3{ 0.2f, -0.1f, -0.15f };
@ -76,7 +76,7 @@ void playGame()
auto floor = app.scene()->createChild("floor");
auto floorRenderer = floor->createComponent<engine::components::Renderer>();
floor->transform.position = glm::vec3{ 0.0f, 0.0f, 0.0f };
floorRenderer->setTexture("textures/stone_bricks.png");
floorRenderer->setTexture("textures/grass.jpg");
floorRenderer->m_mesh = std::make_unique<engine::resources::Mesh>(std::vector<Vertex>{
{ { -16.0f, 0.0f, 16.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, GRASS_DENSITY } },
{ { 16.0f, 0.0f, -16.0f }, { 0.0f, 1.0f, 0.0f }, { GRASS_DENSITY, 0.0f } },
@ -128,5 +128,30 @@ void playGame()
sphereRenderer->m_mesh = genSphereMesh(5.0f, 100, false);
sphereRenderer->setTexture("textures/cobble_stone.png");
/* castle */
auto castle = app.scene()->createChild("castle");
castle->transform.scale = { 0.01f, 0.01f, 0.01f };
std::vector<engine::Object*> castleParts(6);
for (int i = 0; i < castleParts.size(); i++) {
if (i == 2) continue;
castleParts[i] = castle->createChild(std::to_string(i));
auto ren = castleParts[i]->createComponent<engine::components::Renderer>();
ren->setMesh("meshes/castle_" + std::to_string(i) + ".mesh");
ren->setTexture("textures/rock.jpg");
if (i == 5) {
ren->setTexture("textures/metal.jpg");
}
if (i == 4) {
ren->setTexture("textures/door.jpg");
}
}
// boundary
auto bounds = app.scene()->createChild("bounds");
auto boundsRen = bounds->createComponent<engine::components::Renderer>();
boundsRen->m_mesh = genSphereMesh(100.0f, 100, true);
boundsRen->setTexture("textures/metal.jpg");
app.gameLoop();
}