diff --git a/src/application.cpp b/src/application.cpp index f0ea6af..1dc3d73 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -29,6 +29,7 @@ #include "scene.h" #include "scene_manager.h" #include "window.h" +#include "util/gltf_loader.h" #ifdef _MSC_VER #include @@ -326,19 +327,15 @@ void Application::GameLoop() ImGui::Checkbox("Show entity hitboxes", &debug_menu_state.show_entity_boxes); ImGui::Checkbox("Show bounding volumes", &debug_menu_state.show_bounding_volumes); ImGui::Separator(); -#ifndef _WIN32 - ImGui::BeginDisabled(); -#endif + if (!scene) ImGui::BeginDisabled(); // load gltf file dialog if (ImGui::Button("Load glTF")) { #ifdef _WIN32 std::string path = std::filesystem::path(openGLTFDialog()).string(); - LOG_ERROR("Not yet implemented!"); + util::LoadGLTF(*scene, std::filesystem::path(path).string(), false); #endif } -#ifndef _WIN32 - ImGui::EndDisabled(); -#endif + if (!scene) ImGui::EndDisabled(); } ImGui::End(); } diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 2220d34..b7f4b15 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -583,16 +583,17 @@ void GFXDevice::ChangePresentMode(gfx::PresentMode mode) pimpl->swapchainIsOutOfDate = true; } -gfx::PresentMode GFXDevice::GetPresentMode() { +gfx::PresentMode GFXDevice::GetPresentMode() +{ switch (pimpl->swapchain.presentMode) { - case VK_PRESENT_MODE_FIFO_KHR: - return gfx::PresentMode::kDoubleBufferedVsync; - case VK_PRESENT_MODE_IMMEDIATE_KHR: - return gfx::PresentMode::kDoubleBufferedNoVsync; - case VK_PRESENT_MODE_MAILBOX_KHR: - return gfx::PresentMode::kTripleBuffered; - default: - throw std::runtime_error("Unknown present mode"); + case VK_PRESENT_MODE_FIFO_KHR: + return gfx::PresentMode::kDoubleBufferedVsync; + case VK_PRESENT_MODE_IMMEDIATE_KHR: + return gfx::PresentMode::kDoubleBufferedNoVsync; + case VK_PRESENT_MODE_MAILBOX_KHR: + return gfx::PresentMode::kTripleBuffered; + default: + throw std::runtime_error("Unknown present mode"); } } @@ -736,7 +737,7 @@ gfx::DrawBuffer* GFXDevice::BeginRender(bool window_resized) createSwapchain(&pimpl->swapchain, pimpl->swapchainInfo); } // THIS FUNCTION BLOCKS UNTIL AN IMAGE IS AVAILABLE (it waits for vsync) - res = vkAcquireNextImageKHR(pimpl->device.device, pimpl->swapchain.swapchain, 1000000000LL, frameData.presentSemaphore, VK_NULL_HANDLE, + res = vkAcquireNextImageKHR(pimpl->device.device, pimpl->swapchain.swapchain, 1'000'000'000LL, frameData.presentSemaphore, VK_NULL_HANDLE, &swapchainImageIndex); if (res != VK_SUBOPTIMAL_KHR && res != VK_ERROR_OUT_OF_DATE_KHR) VKCHECK(res); if (res == VK_ERROR_OUT_OF_DATE_KHR) pimpl->swapchainIsOutOfDate = true; @@ -1594,7 +1595,7 @@ void GFXDevice::UpdateDescriptorCombinedImageSampler(const gfx::DescriptorSet* s assert(image != nullptr); assert(sampler != nullptr); - if (pimpl->FRAMECOUNT != 0) abort(); // TODO. This is annoying + // if (pimpl->FRAMECOUNT != 0) abort(); // TODO. This is annoying VkDescriptorImageInfo imageInfo{}; imageInfo.sampler = sampler->sampler; @@ -1620,6 +1621,8 @@ gfx::UniformBuffer* GFXDevice::CreateUniformBuffer(uint64_t size, const void* in { assert(initialData != nullptr); + if (pimpl->FRAMECOUNT != 0) abort(); + gfx::UniformBuffer* out = new gfx::UniformBuffer{}; /* first make staging buffer */ @@ -1778,7 +1781,7 @@ gfx::Image* GFXDevice::CreateImage(uint32_t w, uint32_t h, gfx::ImageFormat inpu { assert(imageData != nullptr); - if (pimpl->FRAMECOUNT != 0) abort(); // TODO. This is annoying + // if (pimpl->FRAMECOUNT != 0) abort(); // TODO. This is annoying gfx::Image* out = new gfx::Image{}; diff --git a/src/resources/font.cpp b/src/resources/font.cpp index fcc2657..f80bd97 100644 --- a/src/resources/font.cpp +++ b/src/resources/font.cpp @@ -10,125 +10,123 @@ namespace engine { -Font::Font(const std::string& path) { - font_buffer_ = util::ReadBinaryFile(path); - font_info_ = std::make_unique(); +Font::Font(const std::string& path) +{ + font_buffer_ = util::ReadBinaryFile(path); + font_info_ = std::make_unique(); - if (stbtt_InitFont(font_info_.get(), font_buffer_->data(), 0) == 0) { - throw std::runtime_error("Failed to initialise font!"); - } + if (stbtt_InitFont(font_info_.get(), font_buffer_->data(), 0) == 0) { + throw std::runtime_error("Failed to initialise font!"); + } - LOG_DEBUG("Created font: {}", path); + LOG_DEBUG("Created font: {}", path); } Font::~Font() { LOG_DEBUG("Destroyed font"); } -std::unique_ptr> Font::GetTextBitmap( - const std::string& text, float height_px, int& width_out, int& height_out) { - const float sf = stbtt_ScaleForPixelHeight(font_info_.get(), height_px); +std::unique_ptr> Font::GetTextBitmap(const std::string& text, float height_px, int& width_out, int& height_out) +{ + const float sf = stbtt_ScaleForPixelHeight(font_info_.get(), height_px); - int ascent, descent, line_gap; - stbtt_GetFontVMetrics(font_info_.get(), &ascent, &descent, &line_gap); + int ascent, descent, line_gap; + stbtt_GetFontVMetrics(font_info_.get(), &ascent, &descent, &line_gap); - struct CharacterRenderInfo { - int advance; // bitmap advance - bool isEmpty; - int xoff, yoff, width, height; - unsigned char* bitmap; - }; + struct CharacterRenderInfo { + int advance; // bitmap advance + bool isEmpty; + int xoff, yoff, width, height; + unsigned char* bitmap; + }; - std::vector characterRenderInfos{}; + std::vector characterRenderInfos{}; - int width = 0; - for (size_t i = 0; i < text.size(); i++) { - const int glyph_index = GetGlyphIndex(static_cast(text.at(i))); + int width = 0; + for (size_t i = 0; i < text.size(); i++) { + const int glyph_index = GetGlyphIndex(static_cast(text.at(i))); - int advanceWidth, leftSideBearing; - stbtt_GetGlyphHMetrics(font_info_.get(), glyph_index, &advanceWidth, - &leftSideBearing); + int advanceWidth, leftSideBearing; + stbtt_GetGlyphHMetrics(font_info_.get(), glyph_index, &advanceWidth, &leftSideBearing); - if (i == 0 && leftSideBearing < 0) { - // if the character extends before the current point - width -= leftSideBearing; - } - width += advanceWidth; - - CharacterRenderInfo renderInfo{}; - - renderInfo.advance = static_cast(static_cast(advanceWidth) * sf); - - if (stbtt_IsGlyphEmpty(font_info_.get(), glyph_index) == 0) { - renderInfo.isEmpty = false; - } else { - renderInfo.isEmpty = true; - } - - if (!renderInfo.isEmpty) { - renderInfo.bitmap = stbtt_GetGlyphBitmap( - font_info_.get(), sf, sf, glyph_index, &renderInfo.width, - &renderInfo.height, &renderInfo.xoff, &renderInfo.yoff); - } - - characterRenderInfos.push_back(renderInfo); - } - - const size_t bitmap_width = std::ceil(static_cast(width) * sf); - const size_t bitmap_height = - std::ceil(static_cast(ascent - descent) * sf); - auto bitmap = - std::make_unique>(bitmap_width * bitmap_height * 4); - - for (size_t i = 0; i < bitmap->size() / 4; i++) { - bitmap->at(i * 4 + 0) = 0x00; - bitmap->at(i * 4 + 1) = 0x00; - bitmap->at(i * 4 + 2) = 0x00; - bitmap->at(i * 4 + 3) = 0x00; - } - - int top_left_x = 0; - for (const auto& renderInfo : characterRenderInfos) { - if (renderInfo.isEmpty == false) { - top_left_x += renderInfo.xoff; - const int top_left_y = static_cast(ascent * sf) + renderInfo.yoff; - const int char_bitmap_width = renderInfo.width; - const int char_bitmap_height = renderInfo.height; - - // copy the 8bpp char bitmap to the 4bpp output - for (int y = 0; y < char_bitmap_height; y++) { - for (int x = 0; x < char_bitmap_width; x++) { - const int out_index = - ((bitmap_width * (top_left_y + y)) + (top_left_x + x)) * 4; - const uint8_t pixel = renderInfo.bitmap[y * char_bitmap_width + x]; - (*bitmap)[out_index + 0] = pixel; - (*bitmap)[out_index + 1] = pixel; - (*bitmap)[out_index + 2] = pixel; - (*bitmap)[out_index + 3] = (pixel == 0x00) ? 0x00 : 0xFF; + if (i == 0 && leftSideBearing < 0) { + // if the character extends before the current point + width -= leftSideBearing; } - } + width += advanceWidth; - stbtt_FreeBitmap(renderInfo.bitmap, nullptr); + CharacterRenderInfo renderInfo{}; + + renderInfo.advance = static_cast(static_cast(advanceWidth) * sf); + + if (stbtt_IsGlyphEmpty(font_info_.get(), glyph_index) == 0) { + renderInfo.isEmpty = false; + } + else { + renderInfo.isEmpty = true; + } + + if (!renderInfo.isEmpty) { + renderInfo.bitmap = + stbtt_GetGlyphBitmap(font_info_.get(), sf, sf, glyph_index, &renderInfo.width, &renderInfo.height, &renderInfo.xoff, &renderInfo.yoff); + } + + characterRenderInfos.push_back(renderInfo); } - top_left_x += renderInfo.advance - renderInfo.xoff; - } + const size_t bitmap_width = static_cast(std::ceil(static_cast(width) * sf)); + const size_t bitmap_height = static_cast(std::ceil(static_cast(ascent - descent) * sf)); + auto bitmap = std::make_unique>(bitmap_width * bitmap_height * 4); - width_out = bitmap_width; - height_out = bitmap_height; - return bitmap; -} - -int Font::GetGlyphIndex(int unicode_codepoint) { - if (unicode_to_glyph_.contains(unicode_codepoint)) { - return unicode_to_glyph_.at(unicode_codepoint); - } else { - const int glyph_index = - stbtt_FindGlyphIndex(font_info_.get(), unicode_codepoint); - if (glyph_index == 0) { - throw std::runtime_error("Glyph not found in font!"); + for (size_t i = 0; i < bitmap->size() / 4; i++) { + bitmap->at(i * 4 + 0) = 0x00; + bitmap->at(i * 4 + 1) = 0x00; + bitmap->at(i * 4 + 2) = 0x00; + bitmap->at(i * 4 + 3) = 0x00; } - unicode_to_glyph_.emplace(std::make_pair(unicode_codepoint, glyph_index)); - return glyph_index; - } + + int top_left_x = 0; + for (const auto& renderInfo : characterRenderInfos) { + if (renderInfo.isEmpty == false) { + top_left_x += renderInfo.xoff; + const int top_left_y = static_cast(ascent * sf) + renderInfo.yoff; + const int char_bitmap_width = renderInfo.width; + const int char_bitmap_height = renderInfo.height; + + // copy the 8bpp char bitmap to the 4bpp output + for (int y = 0; y < char_bitmap_height; y++) { + for (int x = 0; x < char_bitmap_width; x++) { + const size_t out_index = ((bitmap_width * (static_cast(top_left_y) + y)) + (static_cast(top_left_x) + x)) * 4; + const uint8_t pixel = renderInfo.bitmap[y * char_bitmap_width + x]; + (*bitmap)[out_index + 0] = pixel; + (*bitmap)[out_index + 1] = pixel; + (*bitmap)[out_index + 2] = pixel; + (*bitmap)[out_index + 3] = (pixel == 0x00) ? 0x00 : 0xFF; + } + } + + stbtt_FreeBitmap(renderInfo.bitmap, nullptr); + } + + top_left_x += renderInfo.advance - renderInfo.xoff; + } + + width_out = static_cast(bitmap_width); + height_out = static_cast(bitmap_height); + return bitmap; } -} // namespace engine +int Font::GetGlyphIndex(int unicode_codepoint) +{ + if (unicode_to_glyph_.contains(unicode_codepoint)) { + return unicode_to_glyph_.at(unicode_codepoint); + } + else { + const int glyph_index = stbtt_FindGlyphIndex(font_info_.get(), unicode_codepoint); + if (glyph_index == 0) { + throw std::runtime_error("Glyph not found in font!"); + } + unicode_to_glyph_.emplace(std::make_pair(unicode_codepoint, glyph_index)); + return glyph_index; + } +} + +} // namespace engine diff --git a/src/util/gltf_loader.cpp b/src/util/gltf_loader.cpp index d5a85c6..42c5fce 100644 --- a/src/util/gltf_loader.cpp +++ b/src/util/gltf_loader.cpp @@ -15,7 +15,7 @@ struct Color { uint8_t r, g, b, a; Color(const std::vector& doubles) { - if (doubles.size() != 4) throw std::runtime_error("Invalid color doubles array"); + assert(doubles.size() == 4 && "Invalid color doubles array"); r = static_cast(lround(doubles[0] * 255.0)); g = static_cast(lround(doubles[1] * 255.0)); b = static_cast(lround(doubles[2] * 255.0)); diff --git a/src/vulkan/device.cpp b/src/vulkan/device.cpp index 254cf52..ee242ac 100644 --- a/src/vulkan/device.cpp +++ b/src/vulkan/device.cpp @@ -244,6 +244,8 @@ Device createDevice(VkInstance instance, const DeviceRequirements& requirements, } } + // TODO: Remove optional extensions. They'll never be handled anyway. Just stick to well-supported extensions. + bool formatsSupported = true; for (const FormatRequirements& formatRequirements : requirements.formats) { VkFormatFeatureFlags requiredLinearFlags = formatRequirements.properties.linearTilingFeatures; diff --git a/test/res/models/box.glb b/test/res/models/box.glb index 7b7b8db..fe92cc9 100644 Binary files a/test/res/models/box.glb and b/test/res/models/box.glb differ diff --git a/test/res/models/floor2.glb b/test/res/models/floor2.glb new file mode 100644 index 0000000..240dbab Binary files /dev/null and b/test/res/models/floor2.glb differ diff --git a/test/src/game.cpp b/test/src/game.cpp index 1977e17..31af3b5 100644 --- a/test/src/game.cpp +++ b/test/src/game.cpp @@ -97,7 +97,7 @@ void PlayGame(GameSettings settings) main_scene->AddComponent(camera); /* floor */ - engine::Entity floor = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/floor.glb"), true); + engine::Entity floor = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/floor2.glb"), true); //main_scene->GetComponent(main_scene->GetEntity("Cube", floor))->visible = false; engine::Entity monke = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/monke.glb"), true); @@ -159,13 +159,13 @@ void PlayGame(GameSettings settings) engine::Entity box = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/box.glb"), true); main_scene->GetPosition(box) = glm::vec3{ -5.0f, -17.0f, 0.1f }; main_scene->GetScale(box) *= 10.0f; - main_scene->GetRotation(box) = glm::angleAxis(glm::pi(), glm::vec3{ 0.0f, 0.0f, 1.0f }); + main_scene->GetRotation(box) = glm::angleAxis(glm::pi() * 0.0f, glm::vec3{ 0.0f, 0.0f, 1.0f }); main_scene->GetRotation(box) *= glm::angleAxis(glm::half_pi(), glm::vec3{ 1.0f, 0.0f, 0.0f }); } start_scene->GetSystem()->next_scene_ = main_scene; main_scene->GetSystem()->next_scene_ = start_scene; - app.scene_manager()->SetActiveScene(main_scene); + app.scene_manager()->SetActiveScene(start_scene); app.GameLoop(); }