texture loading
This commit is contained in:
parent
b2af1ca699
commit
249f6c9fa3
21 changed files with 397 additions and 65 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -4,3 +4,6 @@
|
||||||
[submodule "glm"]
|
[submodule "glm"]
|
||||||
path = lib/glm
|
path = lib/glm
|
||||||
url = https://github.com/g-truc/glm.git
|
url = https://github.com/g-truc/glm.git
|
||||||
|
[submodule "stb"]
|
||||||
|
path = lib/stb
|
||||||
|
url = https://github.com/nothings/stb.git
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -4,6 +4,7 @@ INCFLAGS = -Isrc
|
||||||
INCFLAGS += -Iengine
|
INCFLAGS += -Iengine
|
||||||
INCFLAGS += -Ilib/glfw/include
|
INCFLAGS += -Ilib/glfw/include
|
||||||
INCFLAGS += -Ilib/glm
|
INCFLAGS += -Ilib/glm
|
||||||
|
INCFLAGS += -Ilib/stb
|
||||||
|
|
||||||
CCFLAGS = -std=c++17 -O2 -g
|
CCFLAGS = -std=c++17 -O2 -g
|
||||||
CCFLAGS += $(INCFLAGS)
|
CCFLAGS += $(INCFLAGS)
|
||||||
|
|
|
@ -9,13 +9,15 @@ XeDescriptorSetLayout::Builder &XeDescriptorSetLayout::Builder::addBinding(
|
||||||
uint32_t binding,
|
uint32_t binding,
|
||||||
VkDescriptorType descriptorType,
|
VkDescriptorType descriptorType,
|
||||||
VkShaderStageFlags stageFlags,
|
VkShaderStageFlags stageFlags,
|
||||||
uint32_t count) {
|
VkSampler *sampler) {
|
||||||
assert(bindings.count(binding) == 0 && "Binding already in use");
|
assert(bindings.count(binding) == 0 && "Binding already in use");
|
||||||
|
uint32_t count = 1;
|
||||||
VkDescriptorSetLayoutBinding layoutBinding{};
|
VkDescriptorSetLayoutBinding layoutBinding{};
|
||||||
layoutBinding.binding = binding;
|
layoutBinding.binding = binding;
|
||||||
layoutBinding.descriptorType = descriptorType;
|
layoutBinding.descriptorType = descriptorType;
|
||||||
layoutBinding.descriptorCount = count;
|
layoutBinding.descriptorCount = count;
|
||||||
layoutBinding.stageFlags = stageFlags;
|
layoutBinding.stageFlags = stageFlags;
|
||||||
|
layoutBinding.pImmutableSamplers = sampler;
|
||||||
bindings[binding] = layoutBinding;
|
bindings[binding] = layoutBinding;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ class XeDescriptorSetLayout {
|
||||||
uint32_t binding,
|
uint32_t binding,
|
||||||
VkDescriptorType descriptorType,
|
VkDescriptorType descriptorType,
|
||||||
VkShaderStageFlags stageFlags,
|
VkShaderStageFlags stageFlags,
|
||||||
uint32_t count = 1);
|
VkSampler *sampler);
|
||||||
std::unique_ptr<XeDescriptorSetLayout> build() const;
|
std::unique_ptr<XeDescriptorSetLayout> build() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "xe_engine.hpp"
|
#include "xe_engine.hpp"
|
||||||
|
#include "xe_image.hpp"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -7,18 +8,15 @@ XeEngine::XeEngine(int width, int height, std::string name) : xeWindow{width, he
|
||||||
xeDevice{xeWindow},
|
xeDevice{xeWindow},
|
||||||
xeRenderer{xeWindow, xeDevice},
|
xeRenderer{xeWindow, xeDevice},
|
||||||
xeCamera{} {
|
xeCamera{} {
|
||||||
loadDescriptors();
|
loadDescriptorPool();
|
||||||
};
|
};
|
||||||
|
|
||||||
void XeEngine::loadDescriptors() {
|
void XeEngine::loadDescriptorPool() {
|
||||||
xeDescriptorPool = XeDescriptorPool::Builder(xeDevice)
|
xeDescriptorPool = XeDescriptorPool::Builder(xeDevice)
|
||||||
.setMaxSets(XeSwapChain::MAX_FRAMES_IN_FLIGHT)
|
.setMaxSets(XeSwapChain::MAX_FRAMES_IN_FLIGHT)
|
||||||
.addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
|
.addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
|
||||||
.addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
|
.addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
|
||||||
.build();
|
.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, XeSwapChain::MAX_FRAMES_IN_FLIGHT)
|
||||||
|
|
||||||
xeDescriptorSetLayout = XeDescriptorSetLayout::Builder(xeDevice)
|
|
||||||
.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT)
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +33,10 @@ std::shared_ptr<XeModel> XeEngine::loadModelFromData(std::vector<XeModel::Vertex
|
||||||
return std::make_shared<XeModel>(xeDevice, builder);
|
return std::make_shared<XeModel>(xeDevice, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<XeImage> XeEngine::loadImage(const std::string &filename) {
|
||||||
|
return std::make_shared<XeImage>(xeDevice, filename);
|
||||||
|
}
|
||||||
|
|
||||||
bool XeEngine::poll() {
|
bool XeEngine::poll() {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
auto newTime = std::chrono::high_resolution_clock::now();
|
auto newTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
#include "xe_renderer.hpp"
|
#include "xe_renderer.hpp"
|
||||||
#include "xe_camera.hpp"
|
#include "xe_camera.hpp"
|
||||||
#include "xe_descriptors.hpp"
|
#include "xe_descriptors.hpp"
|
||||||
#include <chrono>
|
#include "xe_image.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <string>
|
#include <string>
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ class XeEngine {
|
||||||
|
|
||||||
std::shared_ptr<XeModel> loadModelFromFile(const std::string &filename);
|
std::shared_ptr<XeModel> loadModelFromFile(const std::string &filename);
|
||||||
std::shared_ptr<XeModel> loadModelFromData(std::vector<XeModel::Vertex> vertices, std::vector<uint32_t> indices);
|
std::shared_ptr<XeModel> loadModelFromData(std::vector<XeModel::Vertex> vertices, std::vector<uint32_t> indices);
|
||||||
|
std::shared_ptr<XeImage> loadImage(const std::string &filename);
|
||||||
|
|
||||||
bool beginFrame() { return xeRenderer.beginFrame(); }
|
bool beginFrame() { return xeRenderer.beginFrame(); }
|
||||||
void endFrame() { xeRenderer.endFrame(); }
|
void endFrame() { xeRenderer.endFrame(); }
|
||||||
|
@ -36,7 +38,7 @@ class XeEngine {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void loadDescriptors();
|
void loadDescriptorPool();
|
||||||
|
|
||||||
XeWindow xeWindow;
|
XeWindow xeWindow;
|
||||||
XeDevice xeDevice;
|
XeDevice xeDevice;
|
||||||
|
@ -49,7 +51,6 @@ class XeEngine {
|
||||||
float FOV = 50.f;
|
float FOV = 50.f;
|
||||||
|
|
||||||
std::unique_ptr<XeDescriptorPool> xeDescriptorPool;
|
std::unique_ptr<XeDescriptorPool> xeDescriptorPool;
|
||||||
std::unique_ptr<XeDescriptorSetLayout> xeDescriptorSetLayout;
|
|
||||||
|
|
||||||
friend class XeRenderSystem;
|
friend class XeRenderSystem;
|
||||||
};
|
};
|
||||||
|
|
166
engine/xe_image.cpp
Normal file
166
engine/xe_image.cpp
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include "xe_image.hpp"
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
|
||||||
|
XeImage::XeImage(XeDevice &xeDevice, const std::string &filename) : xeDevice{xeDevice} {
|
||||||
|
createTextureImage(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
XeImage::~XeImage() {
|
||||||
|
vkDestroyImage(xeDevice.device(), textureImage, nullptr);
|
||||||
|
vkFreeMemory(xeDevice.device(), textureImageMemory, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void XeImage::createTextureImage(const std::string &filename) {
|
||||||
|
int texWidth, texHeight, texChannels;
|
||||||
|
stbi_uc* pixels = stbi_load(filename.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
|
||||||
|
VkDeviceSize imageSize = texWidth * texHeight * 4;
|
||||||
|
|
||||||
|
if (!pixels) {
|
||||||
|
throw std::runtime_error("failed to load texture: " + filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBuffer stagingBuffer;
|
||||||
|
VkDeviceMemory stagingBufferMemory;
|
||||||
|
|
||||||
|
xeDevice.createBuffer(
|
||||||
|
imageSize,
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
stagingBuffer,
|
||||||
|
stagingBufferMemory
|
||||||
|
);
|
||||||
|
|
||||||
|
void* data;
|
||||||
|
vkMapMemory(xeDevice.device(), stagingBufferMemory, 0, imageSize, 0, &data);
|
||||||
|
memcpy(data, pixels, static_cast<size_t>(imageSize));
|
||||||
|
vkUnmapMemory(xeDevice.device(), stagingBufferMemory);
|
||||||
|
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
|
||||||
|
createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
|
||||||
|
|
||||||
|
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
|
||||||
|
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
|
||||||
|
vkDestroyBuffer(xeDevice.device(), stagingBuffer, nullptr);
|
||||||
|
vkFreeMemory(xeDevice.device(), stagingBufferMemory, nullptr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XeImage::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
|
||||||
|
|
||||||
|
VkImageCreateInfo imageInfo{};
|
||||||
|
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
imageInfo.extent.width = width;
|
||||||
|
imageInfo.extent.height = height;
|
||||||
|
imageInfo.extent.depth = 1;
|
||||||
|
imageInfo.mipLevels = 1;
|
||||||
|
imageInfo.arrayLayers = 1;
|
||||||
|
imageInfo.format = format;
|
||||||
|
imageInfo.tiling = tiling;
|
||||||
|
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
imageInfo.usage = usage;
|
||||||
|
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
if (vkCreateImage(xeDevice.device(), &imageInfo, nullptr, &image) != VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("failed to create image!");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkMemoryRequirements memRequirements;
|
||||||
|
vkGetImageMemoryRequirements(xeDevice.device(), image, &memRequirements);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocInfo{};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
allocInfo.allocationSize = memRequirements.size;
|
||||||
|
allocInfo.memoryTypeIndex = xeDevice.findMemoryType(memRequirements.memoryTypeBits, properties);
|
||||||
|
|
||||||
|
if (vkAllocateMemory(xeDevice.device(), &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("failed to allocate image memory!");
|
||||||
|
}
|
||||||
|
|
||||||
|
vkBindImageMemory(xeDevice.device(), image, imageMemory, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void XeImage::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
||||||
|
VkCommandBuffer commandBuffer = xeDevice.beginSingleTimeCommands();
|
||||||
|
|
||||||
|
VkImageMemoryBarrier barrier{};
|
||||||
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
barrier.oldLayout = oldLayout;
|
||||||
|
barrier.newLayout = newLayout;
|
||||||
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.image = image;
|
||||||
|
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
barrier.subresourceRange.baseMipLevel = 0;
|
||||||
|
barrier.subresourceRange.levelCount = 1;
|
||||||
|
barrier.subresourceRange.baseArrayLayer = 0;
|
||||||
|
barrier.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
VkPipelineStageFlags sourceStage;
|
||||||
|
VkPipelineStageFlags destinationStage;
|
||||||
|
|
||||||
|
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||||
|
barrier.srcAccessMask = 0;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
|
||||||
|
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||||
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
|
||||||
|
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||||
|
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
|
} else {
|
||||||
|
throw std::invalid_argument("unsupported layout transition!");
|
||||||
|
}
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
commandBuffer,
|
||||||
|
sourceStage, destinationStage,
|
||||||
|
0,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
1, &barrier
|
||||||
|
);
|
||||||
|
|
||||||
|
xeDevice.endSingleTimeCommands(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void XeImage::copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) {
|
||||||
|
VkCommandBuffer commandBuffer = xeDevice.beginSingleTimeCommands();
|
||||||
|
|
||||||
|
VkBufferImageCopy region{};
|
||||||
|
region.bufferOffset = 0;
|
||||||
|
region.bufferRowLength = 0;
|
||||||
|
region.bufferImageHeight = 0;
|
||||||
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
region.imageSubresource.mipLevel = 0;
|
||||||
|
region.imageSubresource.baseArrayLayer = 0;
|
||||||
|
region.imageSubresource.layerCount = 1;
|
||||||
|
region.imageOffset = {0, 0, 0};
|
||||||
|
region.imageExtent = {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
vkCmdCopyBufferToImage(commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
|
|
||||||
|
xeDevice.endSingleTimeCommands(commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
engine/xe_image.hpp
Normal file
35
engine/xe_image.hpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "xe_device.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
|
||||||
|
class XeImage {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
XeImage(XeDevice &xeDevice, const std::string &filename);
|
||||||
|
~XeImage();
|
||||||
|
|
||||||
|
XeImage(const XeImage&) = delete;
|
||||||
|
XeImage operator=(const XeImage&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void createTextureImage(const std::string &filename);
|
||||||
|
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory);
|
||||||
|
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||||
|
void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height);
|
||||||
|
|
||||||
|
XeDevice &xeDevice;
|
||||||
|
|
||||||
|
VkImage textureImage;
|
||||||
|
VkDeviceMemory textureImageMemory;
|
||||||
|
|
||||||
|
friend class XeRenderSystem;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -21,19 +21,69 @@ XeRenderSystem::XeRenderSystem(
|
||||||
std::string vert,
|
std::string vert,
|
||||||
std::string frag,
|
std::string frag,
|
||||||
uint32_t pushCunstantDataSize,
|
uint32_t pushCunstantDataSize,
|
||||||
uint32_t uniformBufferDataSize)
|
uint32_t uniformBufferDataSize,
|
||||||
: xeDevice{xeEngine.xeDevice}, xeRenderer{xeEngine.xeRenderer} {
|
XeImage *image
|
||||||
createUniformBuffers(*xeEngine.xeDescriptorPool, *xeEngine.xeDescriptorSetLayout, uniformBufferDataSize);
|
) : xeDevice{xeEngine.xeDevice},
|
||||||
createPipelineLayout(*xeEngine.xeDescriptorSetLayout, pushCunstantDataSize, uniformBufferDataSize);
|
xeRenderer{xeEngine.xeRenderer},
|
||||||
|
pushCunstantDataSize{pushCunstantDataSize},
|
||||||
|
uniformBufferDataSize{uniformBufferDataSize},
|
||||||
|
textureSamplerBinding{image != nullptr} {
|
||||||
|
createDescriptorSetLayout();
|
||||||
|
createUniformBuffers();
|
||||||
|
createTextureImageView(image);
|
||||||
|
createDescriptorSets(*xeEngine.xeDescriptorPool);
|
||||||
|
createPipelineLayout();
|
||||||
createPipeline(xeRenderer.getSwapChainRenderPass(), vert, frag);
|
createPipeline(xeRenderer.getSwapChainRenderPass(), vert, frag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
XeRenderSystem::~XeRenderSystem() {
|
XeRenderSystem::~XeRenderSystem() {
|
||||||
vkDestroyPipelineLayout(xeDevice.device(), pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(xeDevice.device(), pipelineLayout, nullptr);
|
||||||
|
if ( textureSamplerBinding ) {
|
||||||
|
vkDestroySampler(xeDevice.device(), textureSampler, nullptr);
|
||||||
|
vkDestroyImageView(xeDevice.device(), textureImageView, nullptr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void XeRenderSystem::createUniformBuffers(XeDescriptorPool &xeDescriptorPool, XeDescriptorSetLayout &xeDescriptorSetLayout, uint32_t uniformBufferDataSize) {
|
void XeRenderSystem::createDescriptorSetLayout() {
|
||||||
|
XeDescriptorSetLayout::Builder builder{xeDevice};
|
||||||
|
int binding = 0;
|
||||||
|
|
||||||
|
if (uniformBufferDataSize > 0) {
|
||||||
|
builder.addBinding(binding, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, nullptr);
|
||||||
|
binding += 1;
|
||||||
|
}
|
||||||
|
if (textureSamplerBinding) {
|
||||||
|
|
||||||
|
VkSamplerCreateInfo samplerInfo{};
|
||||||
|
samplerInfo.sType = 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_FALSE;
|
||||||
|
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.mipLodBias = 0.0f;
|
||||||
|
samplerInfo.minLod = 0.0f;
|
||||||
|
samplerInfo.maxLod = 0.0f;
|
||||||
|
|
||||||
|
if (vkCreateSampler(xeDevice.device(), &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("failed to create texture sampler!");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addBinding(binding, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, &textureSampler);
|
||||||
|
binding += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xeDescriptorSetLayout = builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
void XeRenderSystem::createUniformBuffers() {
|
||||||
if(uniformBufferDataSize == 0) return;
|
if(uniformBufferDataSize == 0) return;
|
||||||
|
|
||||||
uboBuffers = std::vector<std::unique_ptr<XeBuffer>>(XeSwapChain::MAX_FRAMES_IN_FLIGHT);
|
uboBuffers = std::vector<std::unique_ptr<XeBuffer>>(XeSwapChain::MAX_FRAMES_IN_FLIGHT);
|
||||||
|
@ -42,22 +92,65 @@ void XeRenderSystem::createUniformBuffers(XeDescriptorPool &xeDescriptorPool, Xe
|
||||||
xeDevice,
|
xeDevice,
|
||||||
uniformBufferDataSize,
|
uniformBufferDataSize,
|
||||||
XeSwapChain::MAX_FRAMES_IN_FLIGHT,
|
XeSwapChain::MAX_FRAMES_IN_FLIGHT,
|
||||||
|
|
||||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
uboBuffers[i]->map();
|
uboBuffers[i]->map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XeRenderSystem::createTextureImageView(XeImage *image) {
|
||||||
|
|
||||||
|
if (!textureSamplerBinding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageViewCreateInfo viewInfo{};
|
||||||
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
viewInfo.image = image->textureImage;
|
||||||
|
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
viewInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
|
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||||
|
viewInfo.subresourceRange.levelCount = 1;
|
||||||
|
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
|
viewInfo.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
if (vkCreateImageView(xeDevice.device(), &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) {
|
||||||
|
throw std::runtime_error("failed to create texture image view!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XeRenderSystem::createDescriptorSets(XeDescriptorPool &xeDescriptorPool) {
|
||||||
|
|
||||||
descriptorSets = std::vector<VkDescriptorSet>(XeSwapChain::MAX_FRAMES_IN_FLIGHT);
|
descriptorSets = std::vector<VkDescriptorSet>(XeSwapChain::MAX_FRAMES_IN_FLIGHT);
|
||||||
for (int i = 0; i < descriptorSets.size(); i++) {
|
for (int i = 0; i < descriptorSets.size(); i++) {
|
||||||
auto bufferInfo = uboBuffers[i]->descriptorInfo();
|
auto bufferInfo = uboBuffers[i]->descriptorInfo();
|
||||||
XeDescriptorWriter(xeDescriptorSetLayout, xeDescriptorPool)
|
XeDescriptorWriter writer{*xeDescriptorSetLayout, xeDescriptorPool};
|
||||||
.writeBuffer(0, &bufferInfo)
|
|
||||||
.build(descriptorSets[i]);
|
int binding = 0;
|
||||||
|
|
||||||
|
if (uniformBufferDataSize > 0) {
|
||||||
|
writer.writeBuffer(binding, &bufferInfo);
|
||||||
|
binding += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (textureSamplerBinding) {
|
||||||
|
VkDescriptorImageInfo imageInfo{};
|
||||||
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
imageInfo.imageView = textureImageView;
|
||||||
|
imageInfo.sampler = textureSampler;
|
||||||
|
writer.writeImage(binding, &imageInfo);
|
||||||
|
binding += 1;
|
||||||
|
}
|
||||||
|
writer.build(descriptorSets[i]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void XeRenderSystem::createPipelineLayout(XeDescriptorSetLayout &xeDescriptorSetLayout, uint32_t pushCunstantDataSize, uint32_t uniformBufferDataSize) {
|
void XeRenderSystem::createPipelineLayout() {
|
||||||
|
|
||||||
VkPushConstantRange pushConstantRange;
|
VkPushConstantRange pushConstantRange;
|
||||||
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
@ -75,12 +168,13 @@ void XeRenderSystem::createPipelineLayout(XeDescriptorSetLayout &xeDescriptorSet
|
||||||
pipelineLayoutInfo.pPushConstantRanges = nullptr;
|
pipelineLayoutInfo.pPushConstantRanges = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<VkDescriptorSetLayout> descriptorSetLayouts{xeDescriptorSetLayout.getDescriptorSetLayout()};
|
std::vector<VkDescriptorSetLayout> descriptorSetLayouts{xeDescriptorSetLayout->getDescriptorSetLayout()};
|
||||||
|
|
||||||
if (uniformBufferDataSize > 0) {
|
if (uniformBufferDataSize > 0) {
|
||||||
pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(descriptorSetLayouts.size());
|
pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(descriptorSetLayouts.size());
|
||||||
pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
|
pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts.data();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
pipelineLayoutInfo.setLayoutCount = 0;
|
pipelineLayoutInfo.setLayoutCount = 0;
|
||||||
pipelineLayoutInfo.pSetLayouts = nullptr;
|
pipelineLayoutInfo.pSetLayouts = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -107,13 +201,11 @@ void XeRenderSystem::createPipeline(VkRenderPass renderPass, std::string vert, s
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XeRenderSystem::loadPushConstant(void *pushConstantData, uint32_t pushConstantSize) {
|
void XeRenderSystem::start() {
|
||||||
if(!boundPipeline) {
|
|
||||||
xeRenderer.beginSwapChainRenderPass(xeRenderer.getCurrentCommandBuffer());
|
xeRenderer.beginSwapChainRenderPass(xeRenderer.getCurrentCommandBuffer());
|
||||||
xePipeline->bind(xeRenderer.getCurrentCommandBuffer());
|
xePipeline->bind(xeRenderer.getCurrentCommandBuffer());
|
||||||
boundPipeline = true;
|
if(descriptorSets.size() > 0) {
|
||||||
}
|
|
||||||
if(!boundDescriptor) {
|
|
||||||
vkCmdBindDescriptorSets(
|
vkCmdBindDescriptorSets(
|
||||||
xeRenderer.getCurrentCommandBuffer(),
|
xeRenderer.getCurrentCommandBuffer(),
|
||||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
@ -123,28 +215,29 @@ void XeRenderSystem::loadPushConstant(void *pushConstantData, uint32_t pushConst
|
||||||
&descriptorSets[xeRenderer.getFrameIndex()],
|
&descriptorSets[xeRenderer.getFrameIndex()],
|
||||||
0,
|
0,
|
||||||
nullptr);
|
nullptr);
|
||||||
boundDescriptor = true;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XeRenderSystem::loadPushConstant(void *pushConstantData) {
|
||||||
vkCmdPushConstants(
|
vkCmdPushConstants(
|
||||||
xeRenderer.getCurrentCommandBuffer(),
|
xeRenderer.getCurrentCommandBuffer(),
|
||||||
pipelineLayout,
|
pipelineLayout,
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||||
0,
|
0,
|
||||||
pushConstantSize,
|
pushCunstantDataSize,
|
||||||
pushConstantData);
|
pushConstantData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XeRenderSystem::loadUniformObject(void *uniformBufferData, uint32_t uniformBufferSize) {
|
void XeRenderSystem::loadUniformObject(void *uniformBufferData) {
|
||||||
uboBuffers[xeRenderer.getFrameIndex()]->writeToBuffer(uniformBufferData);
|
uboBuffers[xeRenderer.getFrameIndex()]->writeToBuffer(uniformBufferData);
|
||||||
uboBuffers[xeRenderer.getFrameIndex()]->flush();
|
}
|
||||||
|
|
||||||
|
void XeRenderSystem::loadTexture(XeImage *image) {
|
||||||
|
// createTextureImageView(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XeRenderSystem::render(XeGameObject &gameObject) {
|
void XeRenderSystem::render(XeGameObject &gameObject) {
|
||||||
if(!boundPipeline){
|
|
||||||
xeRenderer.beginSwapChainRenderPass(xeRenderer.getCurrentCommandBuffer());
|
|
||||||
xePipeline->bind(xeRenderer.getCurrentCommandBuffer());
|
|
||||||
boundPipeline = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
gameObject.model->bind(xeRenderer.getCurrentCommandBuffer());
|
gameObject.model->bind(xeRenderer.getCurrentCommandBuffer());
|
||||||
gameObject.model->draw(xeRenderer.getCurrentCommandBuffer());
|
gameObject.model->draw(xeRenderer.getCurrentCommandBuffer());
|
||||||
|
@ -152,8 +245,6 @@ void XeRenderSystem::render(XeGameObject &gameObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void XeRenderSystem::stop() {
|
void XeRenderSystem::stop() {
|
||||||
boundPipeline = false;
|
|
||||||
boundDescriptor = false;
|
|
||||||
xeRenderer.endSwapChainRenderPass(xeRenderer.getCurrentCommandBuffer());
|
xeRenderer.endSwapChainRenderPass(xeRenderer.getCurrentCommandBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "xe_descriptors.hpp"
|
#include "xe_descriptors.hpp"
|
||||||
#include "xe_renderer.hpp"
|
#include "xe_renderer.hpp"
|
||||||
#include "xe_engine.hpp"
|
#include "xe_engine.hpp"
|
||||||
|
#include "xe_image.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -20,7 +21,8 @@ class XeRenderSystem {
|
||||||
std::string vert,
|
std::string vert,
|
||||||
std::string frag,
|
std::string frag,
|
||||||
uint32_t pushCunstantDataSize,
|
uint32_t pushCunstantDataSize,
|
||||||
uint32_t uniformBufferDataSize
|
uint32_t uniformBufferDataSize,
|
||||||
|
XeImage *image
|
||||||
);
|
);
|
||||||
|
|
||||||
~XeRenderSystem();
|
~XeRenderSystem();
|
||||||
|
@ -28,20 +30,29 @@ class XeRenderSystem {
|
||||||
XeRenderSystem(const XeRenderSystem &) = delete;
|
XeRenderSystem(const XeRenderSystem &) = delete;
|
||||||
XeRenderSystem operator=(const XeRenderSystem &) = delete;
|
XeRenderSystem operator=(const XeRenderSystem &) = delete;
|
||||||
|
|
||||||
void loadPushConstant(void *pushConstantData, uint32_t pushConstantSize);
|
void start();
|
||||||
void loadUniformObject(void *uniformBufferData, uint32_t uniformBufferSize);
|
void loadPushConstant(void *pushConstantData);
|
||||||
|
void loadUniformObject(void *uniformBufferData);
|
||||||
|
void loadTexture(XeImage *image);
|
||||||
void render(XeGameObject &gameObject);
|
void render(XeGameObject &gameObject);
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void createUniformBuffers(XeDescriptorPool &xeDescriptorPool, XeDescriptorSetLayout &xeDescriptorSetLayout, uint32_t uniformBufferDataSize);
|
void createDescriptorSetLayout();
|
||||||
void createPipelineLayout(XeDescriptorSetLayout &xeDescriptorSetLayout, uint32_t pushCunstantDataSize, uint32_t uniformBufferDataSize);
|
void createUniformBuffers();
|
||||||
|
void createTextureImageView(XeImage *image);
|
||||||
|
void createDescriptorSets(XeDescriptorPool &xeDescriptorPool);
|
||||||
|
void createPipelineLayout();
|
||||||
void createPipeline(VkRenderPass renderPass, std::string vert, std::string frag);
|
void createPipeline(VkRenderPass renderPass, std::string vert, std::string frag);
|
||||||
|
|
||||||
bool boundPipeline{false};
|
bool boundPipeline{false};
|
||||||
bool boundDescriptor{false};
|
bool boundDescriptor{false};
|
||||||
|
|
||||||
|
uint32_t uniformBufferDataSize;
|
||||||
|
uint32_t pushCunstantDataSize;
|
||||||
|
bool textureSamplerBinding;
|
||||||
|
|
||||||
XeDevice& xeDevice;
|
XeDevice& xeDevice;
|
||||||
XeRenderer& xeRenderer;
|
XeRenderer& xeRenderer;
|
||||||
|
|
||||||
|
@ -49,7 +60,11 @@ class XeRenderSystem {
|
||||||
std::vector<std::unique_ptr<XeBuffer>> uboBuffers;
|
std::vector<std::unique_ptr<XeBuffer>> uboBuffers;
|
||||||
std::vector<VkDescriptorSet> descriptorSets;
|
std::vector<VkDescriptorSet> descriptorSets;
|
||||||
|
|
||||||
|
VkSampler textureSampler;
|
||||||
|
VkImageView textureImageView;
|
||||||
|
|
||||||
VkPipelineLayout pipelineLayout;
|
VkPipelineLayout pipelineLayout;
|
||||||
|
std::unique_ptr<XeDescriptorSetLayout> xeDescriptorSetLayout;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace xe {
|
||||||
|
|
||||||
class XeSwapChain {
|
class XeSwapChain {
|
||||||
public:
|
public:
|
||||||
static constexpr int MAX_FRAMES_IN_FLIGHT = 2;
|
static constexpr int MAX_FRAMES_IN_FLIGHT = 3;
|
||||||
|
|
||||||
XeSwapChain(XeDevice &deviceRef, VkExtent2D windowExtent);
|
XeSwapChain(XeDevice &deviceRef, VkExtent2D windowExtent);
|
||||||
XeSwapChain(XeDevice &deviceRef, VkExtent2D windowExtent, std::shared_ptr<XeSwapChain> previous);
|
XeSwapChain(XeDevice &deviceRef, VkExtent2D windowExtent, std::shared_ptr<XeSwapChain> previous);
|
||||||
|
|
1
lib/stb
Submodule
1
lib/stb
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 8b5f1f37b5b75829fc72d38e7b5d4bcbf8a26d55
|
BIN
res/image/scaly.png
Normal file
BIN
res/image/scaly.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 MiB |
BIN
res/image/texture.png
Normal file
BIN
res/image/texture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
|
@ -1,19 +1,22 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout (location = 0) in vec3 fragColor;
|
layout (location = 0) in vec3 fragColor;
|
||||||
|
layout (location = 1) in vec2 fragUv;
|
||||||
|
|
||||||
layout (location = 0) out vec4 outColor;
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform GlobalUbo {
|
layout (binding = 0) uniform GlobalUbo {
|
||||||
mat4 projectionViewMatrix;
|
mat4 projectionViewMatrix;
|
||||||
vec3 directionToLight;
|
vec3 directionToLight;
|
||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
|
layout (binding = 1) uniform sampler2D texSampler;
|
||||||
|
|
||||||
layout(push_constant) uniform Push {
|
layout(push_constant) uniform Push {
|
||||||
mat4 transform;
|
mat4 transform;
|
||||||
mat4 normalMatrix;
|
mat4 normalMatrix;
|
||||||
} push;
|
} push;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = vec4(fragColor, 1.0);
|
outColor = mix(texture(texSampler, fragUv), vec4(fragColor, 1.0), .5);
|
||||||
}
|
}
|
Binary file not shown.
|
@ -6,8 +6,9 @@ layout(location = 2) in vec3 normal;
|
||||||
layout (location = 3) in vec2 uv;
|
layout (location = 3) in vec2 uv;
|
||||||
|
|
||||||
layout (location = 0) out vec3 fragColor;
|
layout (location = 0) out vec3 fragColor;
|
||||||
|
layout (location = 1) out vec2 fragUv;
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform GlobalUbo {
|
layout (binding = 0) uniform GlobalUbo {
|
||||||
mat4 projectionViewMatrix;
|
mat4 projectionViewMatrix;
|
||||||
vec3 directionToLight;
|
vec3 directionToLight;
|
||||||
} ubo;
|
} ubo;
|
||||||
|
@ -27,4 +28,5 @@ void main() {
|
||||||
float lightIntensity = AMBIENT + max(dot(normalWorldSpace, ubo.directionToLight), 0);
|
float lightIntensity = AMBIENT + max(dot(normalWorldSpace, ubo.directionToLight), 0);
|
||||||
|
|
||||||
fragColor = lightIntensity * vec3(1/position.y,position.y,clamp(sin(position.x - position.z), 0, 1));
|
fragColor = lightIntensity * vec3(1/position.y,position.y,clamp(sin(position.x - position.z), 0, 1));
|
||||||
|
fragUv = uv;
|
||||||
}
|
}
|
Binary file not shown.
|
@ -14,6 +14,8 @@
|
||||||
#include <glm/gtc/constants.hpp>
|
#include <glm/gtc/constants.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
FirstApp::FirstApp() : xeEngine{WIDTH, HEIGHT, "Hello, Vulkan!"} {
|
FirstApp::FirstApp() : xeEngine{WIDTH, HEIGHT, "Hello, Vulkan!"} {
|
||||||
|
@ -24,7 +26,12 @@ FirstApp::~FirstApp() {}
|
||||||
|
|
||||||
void FirstApp::run() {
|
void FirstApp::run() {
|
||||||
|
|
||||||
SimpleRenderer renderer{xeEngine};
|
const std::string s = "res/image/texture.png";
|
||||||
|
|
||||||
|
std::shared_ptr<xe::XeImage> image = xeEngine.loadImage("res/image/texture.png");
|
||||||
|
std::shared_ptr<xe::XeImage> image2 = xeEngine.loadImage("res/image/scaly.png");
|
||||||
|
|
||||||
|
SimpleRenderer renderer{xeEngine, image.get()};
|
||||||
|
|
||||||
auto viewerObject = xe::XeGameObject::createGameObject();
|
auto viewerObject = xe::XeGameObject::createGameObject();
|
||||||
viewerObject.transform.translation = {-7.f, 3.f, -7.f};
|
viewerObject.transform.translation = {-7.f, 3.f, -7.f};
|
||||||
|
@ -39,7 +46,7 @@ void FirstApp::run() {
|
||||||
xeEngine.getCamera().setViewYXZ(viewerObject.transform.translation, viewerObject.transform.rotation);
|
xeEngine.getCamera().setViewYXZ(viewerObject.transform.translation, viewerObject.transform.rotation);
|
||||||
|
|
||||||
if(xeEngine.beginFrame()) {
|
if(xeEngine.beginFrame()) {
|
||||||
renderer.render(gameObjects, xeEngine.getCamera());
|
renderer.render(gameObjects, xeEngine.getCamera(), image2.get());
|
||||||
xeEngine.endFrame();
|
xeEngine.endFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,20 +2,23 @@
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
SimpleRenderer::SimpleRenderer(xe::XeEngine &xeEngine)
|
SimpleRenderer::SimpleRenderer(xe::XeEngine &xeEngine, xe::XeImage *xeImage)
|
||||||
: xeRenderSystem{xeEngine, "res/shaders/simple_shader.vert.spv", "res/shaders/simple_shader.frag.spv", sizeof(PushConstant), sizeof(UniformBuffer)} {};
|
: xeRenderSystem{xeEngine, "res/shaders/simple_shader.vert.spv", "res/shaders/simple_shader.frag.spv", sizeof(PushConstant), sizeof(UniformBuffer), xeImage} {};
|
||||||
|
|
||||||
void SimpleRenderer::render(std::vector<xe::XeGameObject> &gameObjects, xe::XeCamera &xeCamera) {
|
void SimpleRenderer::render(std::vector<xe::XeGameObject> &gameObjects, xe::XeCamera &xeCamera, xe::XeImage *xeImage) {
|
||||||
|
|
||||||
|
xeRenderSystem.start();
|
||||||
|
|
||||||
UniformBuffer ubo{};
|
UniformBuffer ubo{};
|
||||||
ubo.projectionView = xeCamera.getProjection() * xeCamera.getView();
|
ubo.projectionView = xeCamera.getProjection() * xeCamera.getView();
|
||||||
xeRenderSystem.loadUniformObject(&ubo, sizeof(ubo));
|
xeRenderSystem.loadUniformObject(&ubo);
|
||||||
|
xeRenderSystem.loadTexture(xeImage);
|
||||||
|
|
||||||
for(auto &obj : gameObjects) {
|
for(auto &obj : gameObjects) {
|
||||||
PushConstant pc{};
|
PushConstant pc{};
|
||||||
pc.modelMatrix = obj.transform.mat4();
|
pc.modelMatrix = obj.transform.mat4();
|
||||||
pc.normalMatrix = obj.transform.normalMatrix();
|
pc.normalMatrix = obj.transform.normalMatrix();
|
||||||
xeRenderSystem.loadPushConstant(&pc, sizeof(pc));
|
xeRenderSystem.loadPushConstant(&pc);
|
||||||
xeRenderSystem.render(obj);
|
xeRenderSystem.render(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,14 @@ class SimpleRenderer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SimpleRenderer(xe::XeEngine &xeEngine);
|
SimpleRenderer(xe::XeEngine &xeEngine, xe::XeImage *xeImage);
|
||||||
|
|
||||||
~SimpleRenderer() {};
|
~SimpleRenderer() {};
|
||||||
|
|
||||||
SimpleRenderer(const SimpleRenderer&) = delete;
|
SimpleRenderer(const SimpleRenderer&) = delete;
|
||||||
SimpleRenderer operator=(const SimpleRenderer&) = delete;
|
SimpleRenderer operator=(const SimpleRenderer&) = delete;
|
||||||
|
|
||||||
void render(std::vector<xe::XeGameObject> &gameObjects, xe::XeCamera &xeCamera);
|
void render(std::vector<xe::XeGameObject> &gameObjects, xe::XeCamera &xeCamera, xe::XeImage *xeImage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
xe::XeRenderSystem xeRenderSystem;
|
xe::XeRenderSystem xeRenderSystem;
|
||||||
|
|
Loading…
Reference in a new issue