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 // adds a draw call to the queue
// vertexBuffer is required, indexBuffer can be NULL, uniformData is required // 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. // Call once per frame. Executes all queued draw calls and renders to the screen.
void renderFrame(); void renderFrame();

View File

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

View File

@ -77,7 +77,6 @@ void Camera::usePerspective(float fovDeg)
float fovRad = glm::radians(fovDeg); float fovRad = glm::radians(fovDeg);
m_projMatrix = glm::perspectiveFovRH_ZO(fovRad, viewportDim.x, viewportDim.y, NEAR, FAR); m_projMatrix = glm::perspectiveFovRH_ZO(fovRad, viewportDim.x, viewportDim.y, NEAR, FAR);
m_projMatrix[1][1] *= -1;
} }
void Camera::useOrtho() void Camera::useOrtho()
@ -88,7 +87,6 @@ void Camera::useOrtho()
float aspect = viewportDim.x / viewportDim.y; 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 = 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) Renderer::Renderer(Object* parent) : Component(parent, TypeEnum::RENDERER)
{ {
m_shader = this->parent.res.get<resources::Shader>("shader.glsl"); 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() 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)); gfxdev->updateUniformBuffer(m_shader->getPipeline(), &uniformData.color, sizeof(uniformData.color), offsetof(resources::Shader::UniformBuffer, color));
glm::mat4 pushConsts[] = { transform, view }; 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) void Renderer::setMesh(const std::string& name)

View File

@ -58,7 +58,6 @@ namespace engine {
VkQueue handle; VkQueue handle;
}; };
struct DepthBuffer { struct DepthBuffer {
VkImage image; VkImage image;
VmaAllocation allocation; VmaAllocation allocation;
@ -91,6 +90,7 @@ namespace engine {
const gfx::Buffer* indexBuffer = nullptr; // if this is nullptr, don't use indexed const gfx::Buffer* indexBuffer = nullptr; // if this is nullptr, don't use indexed
uint32_t count = 0; uint32_t count = 0;
uint8_t pushConstantData[PUSH_CONSTANT_MAX_SIZE]; uint8_t pushConstantData[PUSH_CONSTANT_MAX_SIZE];
const gfx::Texture* texture = nullptr;
}; };
enum class QueueFlags : uint32_t { enum class QueueFlags : uint32_t {
@ -119,6 +119,11 @@ namespace engine {
struct gfx::Texture { struct gfx::Texture {
VkImage image; VkImage image;
VmaAllocation alloc; 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.SetOptimizationLevel(shaderc_optimization_level_size);
options.SetTargetSpirv(shaderc_spirv_version_1_6); options.SetTargetSpirv(shaderc_spirv_version_1_6);
options.SetAutoBindUniforms(false); options.SetAutoBindUniforms(false);
options.SetInvertY(false);
// preprocess // preprocess
shaderc::PreprocessedSourceCompilationResult preprocessed = compiler.PreprocessGlsl(source, kind, filename, options); shaderc::PreprocessedSourceCompilationResult preprocessed = compiler.PreprocessGlsl(source, kind, filename, options);
@ -774,7 +778,7 @@ namespace engine {
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); 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 }; VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
@ -785,7 +789,7 @@ namespace engine {
barrier.image = image; barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0; barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1; barrier.subresourceRange.levelCount = mipLevels;
barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1; 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 // class definitions
struct GFXDevice::Impl { struct GFXDevice::Impl {
@ -845,7 +920,10 @@ namespace engine {
std::map<const gfx::Pipeline*, std::queue<DrawCall>> drawQueues{}; std::map<const gfx::Pipeline*, std::queue<DrawCall>> drawQueues{};
VkDescriptorSetLayoutBinding uboLayoutBinding{}; VkDescriptorSetLayoutBinding uboLayoutBinding{};
VkDescriptorSetLayout uboLayout{}; VkDescriptorSetLayout descriptorSetLayout{};
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
VkDescriptorSetLayout samplerSetLayout{};
}; };
@ -1032,6 +1110,19 @@ namespace engine {
continue; 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; pimpl->physicalDevice = dev;
break; break;
@ -1127,6 +1218,9 @@ namespace engine {
throw std::runtime_error("The selected queue family does not support this surface"); throw std::runtime_error("The selected queue family does not support this surface");
} }
VkPhysicalDeviceFeatures deviceFeatures{};
deviceFeatures.samplerAnisotropy = VK_TRUE;
VkDeviceCreateInfo deviceCreateInfo{ VkDeviceCreateInfo deviceCreateInfo{
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
@ -1137,7 +1231,7 @@ namespace engine {
// IGNORED: .ppEnabledLayerNames // IGNORED: .ppEnabledLayerNames
.enabledExtensionCount = (uint32_t)requiredDeviceExtensions.size(), .enabledExtensionCount = (uint32_t)requiredDeviceExtensions.size(),
.ppEnabledExtensionNames = requiredDeviceExtensions.data(), .ppEnabledExtensionNames = requiredDeviceExtensions.data(),
.pEnabledFeatures = nullptr, .pEnabledFeatures = &deviceFeatures,
}; };
res = vkCreateDevice(pimpl->physicalDevice, &deviceCreateInfo, nullptr, &pimpl->device); res = vkCreateDevice(pimpl->physicalDevice, &deviceCreateInfo, nullptr, &pimpl->device);
@ -1244,24 +1338,41 @@ namespace engine {
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
} }
// create uniform buffer stuff // create uniform buffer descriptor set layout
pimpl->uboLayoutBinding.binding = 0; pimpl->uboLayoutBinding.binding = 0;
pimpl->uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; pimpl->uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
pimpl->uboLayoutBinding.descriptorCount = 1; pimpl->uboLayoutBinding.descriptorCount = 1;
pimpl->uboLayoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; pimpl->uboLayoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
pimpl->uboLayoutBinding.pImmutableSamplers = nullptr; pimpl->uboLayoutBinding.pImmutableSamplers = nullptr;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
descriptorSetLayoutInfo.bindingCount = 1; descriptorSetLayoutInfo.bindingCount = 1;
descriptorSetLayoutInfo.pBindings = &pimpl->uboLayoutBinding; descriptorSetLayoutInfo.pBindings = &pimpl->uboLayoutBinding;
res = vkCreateDescriptorSetLayout(pimpl->device, &descriptorSetLayoutInfo, nullptr, &pimpl->uboLayout); res = vkCreateDescriptorSetLayout(pimpl->device, &descriptorSetLayoutInfo, nullptr, &pimpl->descriptorSetLayout);
assert(res == VK_SUCCESS); 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() GFXDevice::~GFXDevice()
{ {
TRACE("Destroying 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++) { for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
@ -1298,7 +1409,7 @@ namespace engine {
*h = (uint32_t)height; *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->type == gfx::BufferType::VERTEX);
assert(vertexBuffer != nullptr); assert(vertexBuffer != nullptr);
@ -1313,6 +1424,8 @@ namespace engine {
memcpy(call.pushConstantData, pushConstantData, pushConstantSize); memcpy(call.pushConstantData, pushConstantData, pushConstantSize);
call.texture = texture; // will be ignored if nullptr
pimpl->drawQueues[pipeline].push(call); pimpl->drawQueues[pipeline].push(call);
} }
@ -1367,9 +1480,9 @@ namespace engine {
VkViewport viewport{}; VkViewport viewport{};
viewport.x = 0.0f; viewport.x = 0.0f;
viewport.y = 0.0f; viewport.y = (float)pimpl->swapchain.extent.height;
viewport.width = (float)pimpl->swapchain.extent.width; 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.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
vkCmdSetViewport(pimpl->commandBuffers[frameIndex], 0, 1, &viewport); vkCmdSetViewport(pimpl->commandBuffers[frameIndex], 0, 1, &viewport);
@ -1390,6 +1503,8 @@ namespace engine {
DrawCall call = queue.front(); 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); 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); vkCmdBindVertexBuffers(pimpl->commandBuffers[frameIndex], 0, 1, &call.vertexBuffer->buffer, offsets);
@ -1490,10 +1605,11 @@ namespace engine {
pipeline->uniformBuffers[i] = buf; pipeline->uniformBuffers[i] = buf;
} }
// create descriptor pool for uniform buffers // create descriptor pools
VkDescriptorPoolSize poolSize{}; VkDescriptorPoolSize poolSize{};
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSize.descriptorCount = FRAMES_IN_FLIGHT; poolSize.descriptorCount = FRAMES_IN_FLIGHT;
VkDescriptorPoolCreateInfo poolInfo{}; VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = 1; poolInfo.poolSizeCount = 1;
@ -1503,19 +1619,21 @@ namespace engine {
assert(res == VK_SUCCESS); assert(res == VK_SUCCESS);
std::array<VkDescriptorSetLayout, FRAMES_IN_FLIGHT> layouts; std::array<VkDescriptorSetLayout, FRAMES_IN_FLIGHT> layouts;
layouts.fill(pimpl->uboLayout); layouts.fill(pimpl->descriptorSetLayout);
VkDescriptorSetAllocateInfo dSetAllocInfo{}; VkDescriptorSetAllocateInfo dSetAllocInfo{};
dSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; dSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
dSetAllocInfo.descriptorPool = pipeline->descriptorPool; dSetAllocInfo.descriptorPool = pipeline->descriptorPool;
dSetAllocInfo.descriptorSetCount = FRAMES_IN_FLIGHT; dSetAllocInfo.descriptorSetCount = FRAMES_IN_FLIGHT;
dSetAllocInfo.pSetLayouts = layouts.data(); dSetAllocInfo.pSetLayouts = layouts.data();
res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, pipeline->descriptorSets.data()); res = vkAllocateDescriptorSets(pimpl->device, &dSetAllocInfo, pipeline->descriptorSets.data());
assert(res == VK_SUCCESS);
for (int i = 0; i < FRAMES_IN_FLIGHT; i++) { for (int i = 0; i < FRAMES_IN_FLIGHT; i++) {
VkDescriptorBufferInfo bufferInfo{}; VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = pipeline->uniformBuffers[i]->buffer; bufferInfo.buffer = pipeline->uniformBuffers[i]->buffer;
bufferInfo.offset = 0; bufferInfo.offset = 0;
bufferInfo.range = uniformBufferSize; bufferInfo.range = uniformBufferSize;
VkWriteDescriptorSet descriptorWrite{}; VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = pipeline->descriptorSets[i]; descriptorWrite.dstSet = pipeline->descriptorSets[i];
@ -1576,9 +1694,9 @@ namespace engine {
VkViewport viewport{}; VkViewport viewport{};
viewport.x = 0.0f; viewport.x = 0.0f;
viewport.y = 0.0f; viewport.y = (float)pimpl->swapchain.extent.height;
viewport.width = (float)pimpl->swapchain.extent.width; 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.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
@ -1667,10 +1785,12 @@ namespace engine {
pushConstantRange.size = PUSH_CONSTANT_MAX_SIZE; pushConstantRange.size = PUSH_CONSTANT_MAX_SIZE;
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
std::array<VkDescriptorSetLayout, 2> setLayouts{ pimpl->descriptorSetLayout, pimpl->samplerSetLayout};
VkPipelineLayoutCreateInfo layoutInfo{}; VkPipelineLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layoutInfo.setLayoutCount = 1; layoutInfo.setLayoutCount = setLayouts.size();
layoutInfo.pSetLayouts = &pimpl->uboLayout; layoutInfo.pSetLayouts = setLayouts.data();
layoutInfo.pushConstantRangeCount = 1; layoutInfo.pushConstantRangeCount = 1;
layoutInfo.pPushConstantRanges = &pushConstantRange; layoutInfo.pPushConstantRanges = &pushConstantRange;
@ -1810,6 +1930,8 @@ namespace engine {
size_t imageSize = w * h * 4; 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 // first load image into staging buffer
VkBuffer stagingBuffer; VkBuffer stagingBuffer;
VmaAllocation stagingAllocation; VmaAllocation stagingAllocation;
@ -1841,12 +1963,12 @@ namespace engine {
imageInfo.extent.width = w; imageInfo.extent.width = w;
imageInfo.extent.height = h; imageInfo.extent.height = h;
imageInfo.extent.depth = 1; imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1; imageInfo.mipLevels = out->mipLevels;
imageInfo.arrayLayers = 1; imageInfo.arrayLayers = 1;
imageInfo.format = VK_FORMAT_R8G8B8A8_SRGB; imageInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 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.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.flags = 0; imageInfo.flags = 0;
@ -1863,7 +1985,7 @@ namespace engine {
// begin cmd buffer // 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{}; VkBufferImageCopy region{};
region.bufferOffset = 0; region.bufferOffset = 0;
@ -1880,7 +2002,8 @@ namespace engine {
vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, out->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region); 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 // end cmd buffer
endOneTimeCommands(pimpl->device, pimpl->commandPool, commandBuffer, pimpl->gfxQueue.handle); endOneTimeCommands(pimpl->device, pimpl->commandPool, commandBuffer, pimpl->gfxQueue.handle);
@ -1890,11 +2013,101 @@ namespace engine {
// destroy staging buffer // destroy staging buffer
vmaDestroyBuffer(pimpl->allocator, stagingBuffer, stagingAllocation); 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; return out;
} }
void GFXDevice::destroyTexture(const gfx::Texture* texture) 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); 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); vertices->resize(header.vertex_count);
fread(indices->data(), sizeof(uint32_t) * header.index_count, 1, fp); 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); fclose(fp);
} }

View File

@ -10,7 +10,7 @@
namespace engine::resources { namespace engine::resources {
// returns false if unable to open file // 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; int x, y, n;
unsigned char *data = stbi_load(path.c_str(), &x, &y, &n, STBI_rgb_alpha); 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; const size_t size = (size_t)x * (size_t)y * 4;
texbuf.resize(size); texbuf->resize(size);
memcpy(texbuf.data(), data, size); memcpy(texbuf->data(), data, size);
*width = x; *width = x;
*height = y; *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"); FILE *fp = fopen(path.c_str(), "rb");
if (!fp) { if (!fp) {
@ -49,9 +49,9 @@ static bool readGLRaw(const std::string& path, std::vector<uint8_t>& texbuf, int
fseek(fp, 0L, SEEK_END); fseek(fp, 0L, SEEK_END);
uint64_t end = ftell(fp); uint64_t end = ftell(fp);
texbuf.resize(end); texbuf->resize(end);
fseek(fp, (long)tex_data_offset, SEEK_SET); fseek(fp, (long)tex_data_offset, SEEK_SET);
fread(texbuf.data(), 1, end, fp); fread(texbuf->data(), 1, end, fp);
fclose(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") 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; int width, height;
bool isRGBA, success; bool isRGBA, success;
if (resPath.extension() == ".png") { if (resPath.extension() == ".png" || resPath.extension() == ".jpg") {
success = readPNG(resPath.string(), texbuf, &width, &height, &isRGBA); success = readPNG(resPath.string(), texbuf.get(), &width, &height, &isRGBA);
} else { } else {
success = readGLRaw(resPath.string(), texbuf, &width, &height, &isRGBA); success = readGLRaw(resPath.string(), texbuf.get(), &width, &height, &isRGBA);
} }
if (!success) { if (!success) {
@ -82,12 +82,12 @@ Texture::Texture(const std::filesystem::path& resPath) : Resource(resPath, "text
} }
if (isRGBA == false) { 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); 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) void Window::setFullscreen(bool fullscreen, bool exclusive)
{ {
if (m_resizable) { 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) { 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"); throw std::runtime_error("Unable to set window to fullscreen/windowed");
} }
m_fullscreen = fullscreen; m_fullscreen = fullscreen;
if (fullscreen) { if (fullscreen) {
int width, height; int width, height;
SDL_GetWindowSize(m_handle, &width, &height); SDL_GetWindowSize(m_handle, &width, &height);
onResize(width, height); onResize(width, height);
@ -291,7 +298,7 @@ namespace engine {
void Window::toggleFullscreen() void Window::toggleFullscreen()
{ {
setFullscreen(!m_fullscreen, false); setFullscreen(!m_fullscreen, true);
} }
bool Window::isFullscreen() const 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; layout(location = 0) out vec4 outColor;
float snoise(vec2 v); layout(set = 1, binding = 0) uniform sampler2D texSampler;
void main() { void main() {
@ -16,7 +16,7 @@ void main() {
vec3 lightColor = vec3(1.0, 1.0, 1.0); vec3 lightColor = vec3(1.0, 1.0, 1.0);
vec3 ambientColor = vec3(1.0, 1.0, 1.0); vec3 ambientColor = vec3(1.0, 1.0, 1.0);
float ambientStrength = 0.1; 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); vec3 emission = vec3(0.0, 0.0, 0.0);
// code // code
@ -36,36 +36,3 @@ void main() {
vec3 lighting = min(diffuse + ambient + specular, 1.0); vec3 lighting = min(diffuse + ambient + specular, 1.0);
outColor = min( ( vec4(baseColor, 1.0) ) * vec4(lighting + emission, 1.0), vec4(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>(); auto camCamera = cam->createComponent<engine::components::Camera>();
camCamera->usePerspective(70.0f); camCamera->usePerspective(70.0f);
cam->createComponent<CameraController>(); cam->createComponent<CameraController>();
cam->createComponent<engine::components::Renderer>()->m_mesh = genSphereMesh(0.2f, 20); //cam->createComponent<engine::components::Renderer>()->m_mesh = genSphereMesh(0.2f, 20);
cam->getComponent<engine::components::Renderer>()->setTexture("textures/cobble_stone.png"); //cam->getComponent<engine::components::Renderer>()->setTexture("textures/cobble_stone.png");
auto gun = cam->createChild("gun"); auto gun = cam->createChild("gun");
gun->transform.position = glm::vec3{ 0.2f, -0.1f, -0.15f }; gun->transform.position = glm::vec3{ 0.2f, -0.1f, -0.15f };
@ -76,7 +76,7 @@ void playGame()
auto floor = app.scene()->createChild("floor"); auto floor = app.scene()->createChild("floor");
auto floorRenderer = floor->createComponent<engine::components::Renderer>(); auto floorRenderer = floor->createComponent<engine::components::Renderer>();
floor->transform.position = glm::vec3{ 0.0f, 0.0f, 0.0f }; 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>{ 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 }, { 0.0f, GRASS_DENSITY } },
{ { 16.0f, 0.0f, -16.0f }, { 0.0f, 1.0f, 0.0f }, { GRASS_DENSITY, 0.0f } }, { { 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->m_mesh = genSphereMesh(5.0f, 100, false);
sphereRenderer->setTexture("textures/cobble_stone.png"); 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(); app.gameLoop();
} }