From ab50f0b9a2f0f266dc3dd051602b5c0c3a7eae35 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 4 Oct 2022 23:15:52 -0500 Subject: [PATCH] Add texture loading in GlContext --- scwx-qt/source/scwx/qt/gl/gl_context.cpp | 120 ++++++++++++++++++++++- scwx-qt/source/scwx/qt/gl/gl_context.hpp | 2 + 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.cpp b/scwx-qt/source/scwx/qt/gl/gl_context.cpp index 3db875a8..8384a8ef 100644 --- a/scwx-qt/source/scwx/qt/gl/gl_context.cpp +++ b/scwx-qt/source/scwx/qt/gl/gl_context.cpp @@ -1,5 +1,14 @@ #include +#include #include +#include + +#pragma warning(push, 0) +#include +#include +#include +#include +#pragma warning(pop) namespace scwx { @@ -8,19 +17,34 @@ namespace qt namespace gl { +static const std::string logPrefix_ = "scwx::qt::gl::gl_context"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + class GlContext::Impl { public: - explicit Impl() : gl_ {}, shaderProgramMap_ {}, shaderProgramMutex_ {} {} + explicit Impl() : + gl_ {}, + shaderProgramMap_ {}, + shaderProgramMutex_ {}, + textureMap_ {}, + textureMutex_ {} + { + } ~Impl() {} + GLuint CreateTexture(const std::string& texturePath); + gl::OpenGLFunctions gl_; std::unordered_map, std::shared_ptr, - util::hash>> + scwx::util::hash>> shaderProgramMap_; std::mutex shaderProgramMutex_; + + std::unordered_map textureMap_; + std::mutex textureMutex_; }; GlContext::GlContext() : p(std::make_unique()) {} @@ -59,6 +83,98 @@ GlContext::GetShaderProgram(const std::string& vertexPath, return shaderProgram; } +GLuint GlContext::GetTexture(const std::string& texturePath) +{ + GLuint texture = GL_INVALID_INDEX; + + std::unique_lock lock(p->textureMutex_); + + auto it = p->textureMap_.find(texturePath); + + if (it == p->textureMap_.end()) + { + texture = p->CreateTexture(texturePath); + p->textureMap_[texturePath] = texture; + } + else + { + texture = it->second; + } + + return texture; +} + +// TODO: Move to dedicated file +GLuint GlContext::Impl::CreateTexture(const std::string& texturePath) +{ + logger_->warn("Create Texture: {}", texturePath); + + GLuint texture; + + QFile textureFile(texturePath.c_str()); + + textureFile.open(QIODevice::ReadOnly); + + if (!textureFile.isOpen()) + { + logger_->error("Could not load texture: {}", texturePath); + return GL_INVALID_INDEX; + } + + boost::iostreams::stream dataStream(textureFile); + + boost::gil::rgba8_image_t image; + + try + { + boost::gil::read_and_convert_image( + dataStream, image, boost::gil::png_tag()); + } + catch (const std::exception& ex) + { + logger_->error("Error reading texture: {}", ex.what()); + return GL_INVALID_INDEX; + } + + boost::gil::rgba8_view_t view = boost::gil::view(image); + + std::vector pixelData(view.width() * + view.height()); + + boost::gil::copy_pixels( + view, + boost::gil::interleaved_view(view.width(), + view.height(), + pixelData.data(), + view.width() * + sizeof(boost::gil::rgba8_pixel_t))); + + OpenGLFunctions& gl = gl_; + + gl.glGenTextures(1, &texture); + gl.glBindTexture(GL_TEXTURE_2D, texture); + + // TODO: Change to GL_REPEAT once a texture atlas is used + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl.glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + gl.glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + view.width(), + view.height(), + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + pixelData.data()); + gl.glGenerateMipmap(GL_TEXTURE_2D); + + return texture; +} + } // namespace gl } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.hpp b/scwx-qt/source/scwx/qt/gl/gl_context.hpp index cf81262f..d1fb6645 100644 --- a/scwx-qt/source/scwx/qt/gl/gl_context.hpp +++ b/scwx-qt/source/scwx/qt/gl/gl_context.hpp @@ -28,6 +28,8 @@ public: GetShaderProgram(const std::string& vertexPath, const std::string& fragmentPath); + GLuint GetTexture(const std::string& texturePath); + private: class Impl;