From eef93efc29bb0e264a436e17052ddfc802cae28c Mon Sep 17 00:00:00 2001 From: James Grogan Date: Tue, 15 Nov 2022 15:50:36 +0000 Subject: [PATCH] Continue adding opengl font support. --- README.md | 2 +- src/core/Color.h | 2 +- src/core/file_utilities/File.cpp | 16 ++ src/core/file_utilities/File.h | 2 + src/fonts/BasicFontEngine.h | 3 +- src/fonts/CMakeLists.txt | 1 + src/fonts/FontGlyph.cpp | 43 ++++ src/fonts/FontGlyph.h | 29 +++ src/fonts/FontItem.cpp | 0 src/fonts/FontItem.h | 35 ++++ src/fonts/FontReader.h | 2 +- src/fonts/FontsManager.cpp | 16 ++ src/fonts/FontsManager.h | 6 + src/fonts/FreeTypeFontEngine.cpp | 13 +- src/fonts/FreeTypeFontEngine.h | 2 +- src/fonts/IFontEngine.h | 5 +- src/fonts/TrueTypeFont.h | 3 +- src/graphics/CMakeLists.txt | 10 +- src/graphics/DrawingContext.cpp | 7 + src/graphics/DrawingContext.h | 2 + src/graphics/opengl/OpenGlFontTexture.cpp | 36 ++++ src/graphics/opengl/OpenGlFontTexture.h | 13 ++ src/graphics/opengl/OpenGlPainter.cpp | 187 +++++++++--------- src/graphics/opengl/OpenGlPainter.h | 22 ++- src/graphics/opengl/OpenGlShaderProgram.cpp | 68 +++++++ src/graphics/opengl/OpenGlShaderProgram.h | 15 ++ src/graphics/opengl/shaders/default.frag | 11 ++ src/graphics/opengl/shaders/default.vert | 10 + src/graphics/opengl/shaders/text.frag | 12 ++ src/graphics/opengl/shaders/text.vert | 11 ++ src/visual_elements/Scene.cpp | 11 +- src/visual_elements/Scene.h | 10 +- src/visual_elements/TextData.h | 16 ++ src/visual_elements/TextNode.cpp | 52 ++--- src/visual_elements/TextNode.h | 12 +- .../ui_interfaces/AbstractUiInterface.h | 1 + test/fonts/TestFreeTypeFontEngine.cpp | 1 + 37 files changed, 530 insertions(+), 157 deletions(-) create mode 100644 src/fonts/FontGlyph.cpp create mode 100644 src/fonts/FontGlyph.h create mode 100644 src/fonts/FontItem.cpp create mode 100644 src/fonts/FontItem.h create mode 100644 src/graphics/opengl/OpenGlFontTexture.cpp create mode 100644 src/graphics/opengl/OpenGlFontTexture.h create mode 100644 src/graphics/opengl/OpenGlShaderProgram.cpp create mode 100644 src/graphics/opengl/OpenGlShaderProgram.h create mode 100644 src/graphics/opengl/shaders/default.frag create mode 100644 src/graphics/opengl/shaders/default.vert create mode 100644 src/graphics/opengl/shaders/text.frag create mode 100644 src/graphics/opengl/shaders/text.vert create mode 100644 src/visual_elements/TextData.h diff --git a/README.md b/README.md index 99188cc..b47a1bb 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ In `xdg-shell-protocol.cpp` - we need access to `xdg_wm_base_interface` so expor #### 3D Rendering ```bash -sudo apt-get install libgl-dev libegl1-mesa-dev libglu1-mesa-dev +sudo apt-get install libgl-dev libegl1-mesa-dev libglu1-mesa-dev libglm-dev ``` #### fonts diff --git a/src/core/Color.h b/src/core/Color.h index b1af736..b432c8b 100644 --- a/src/core/Color.h +++ b/src/core/Color.h @@ -7,7 +7,7 @@ class Color { public: - Color(unsigned r, unsigned g, unsigned b, double a = 1.0); + Color(unsigned r = 0, unsigned g = 0, unsigned b = 0, double a = 1.0); static std::shared_ptr CreateShared(unsigned r, unsigned g, unsigned b, double a = 1.0); static std::unique_ptr Create(unsigned r, unsigned g, unsigned b, double a = 1.0); diff --git a/src/core/file_utilities/File.cpp b/src/core/file_utilities/File.cpp index 74202ab..28673de 100644 --- a/src/core/file_utilities/File.cpp +++ b/src/core/file_utilities/File.cpp @@ -113,6 +113,22 @@ std::vector File::readLines() return content; } +std::string File::read() +{ + if (!PathExists()) + { + return {}; + } + + Open(false); + + std::stringstream buffer; + buffer << mInHandle->rdbuf(); + + Close(); + return buffer.str(); +} + std::string File::getBaseFilename(const Path& path) { return path.stem().string(); diff --git a/src/core/file_utilities/File.h b/src/core/file_utilities/File.h index c654310..c594f0a 100644 --- a/src/core/file_utilities/File.h +++ b/src/core/file_utilities/File.h @@ -36,6 +36,8 @@ public: std::vector readLines(); + std::string read(); + static std::string getBaseFilename(const Path& path); bool PathExists() const; diff --git a/src/fonts/BasicFontEngine.h b/src/fonts/BasicFontEngine.h index 0938245..3db266d 100644 --- a/src/fonts/BasicFontEngine.h +++ b/src/fonts/BasicFontEngine.h @@ -3,6 +3,7 @@ #include "IFontEngine.h" #include "Image.h" +#include "FontGlyph.h" class BasicFontEngine : public IFontEngine { @@ -10,5 +11,5 @@ class BasicFontEngine : public IFontEngine virtual void loadFontFace(const std::filesystem::path& fontFile, int penSize = 16){}; - virtual std::unique_ptr > loadGlyph(unsigned charCode){return nullptr;}; + virtual std::unique_ptr loadGlyph(unsigned charCode){return nullptr;}; }; diff --git a/src/fonts/CMakeLists.txt b/src/fonts/CMakeLists.txt index b29fe49..05ebc36 100644 --- a/src/fonts/CMakeLists.txt +++ b/src/fonts/CMakeLists.txt @@ -5,6 +5,7 @@ list(APPEND fonts_LIB_INCLUDES FontReader.cpp TrueTypeFont.cpp FontsManager.cpp + FontGlyph.cpp ) if(UNIX) diff --git a/src/fonts/FontGlyph.cpp b/src/fonts/FontGlyph.cpp new file mode 100644 index 0000000..0a2c24f --- /dev/null +++ b/src/fonts/FontGlyph.cpp @@ -0,0 +1,43 @@ +#include "FontGlyph.h" + +FontGlyph::FontGlyph(unsigned width, unsigned height, unsigned bearingX, unsigned bearingY, + unsigned advanceX, std::unique_ptr > image) + : mImage(std::move(image)), + mWidth(width), + mHeight(height), + mBearingX(mBearingX), + mBearingY(mBearingY), + mAdvanceX(mAdvanceX) +{ + +} + +Image* FontGlyph::getImage() const +{ + return mImage.get(); +} + +unsigned FontGlyph::getWidth() const +{ + return mWidth; +} + +unsigned FontGlyph::getHeight() const +{ + return mHeight; +} + +unsigned FontGlyph::getBearingX() const +{ + return mBearingX; +} + +unsigned FontGlyph::getBearingY() const +{ + return mBearingY; +} + +unsigned FontGlyph::getAdvanceX() const +{ + return mAdvanceX; +} diff --git a/src/fonts/FontGlyph.h b/src/fonts/FontGlyph.h new file mode 100644 index 0000000..54c3246 --- /dev/null +++ b/src/fonts/FontGlyph.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "Image.h" + +class FontGlyph +{ + +public: + FontGlyph(unsigned width, unsigned height, unsigned bearingX, unsigned bearingY, + unsigned advanceX, std::unique_ptr > image); + + Image* getImage() const; + + unsigned getWidth() const; + unsigned getHeight() const; + unsigned getBearingX() const; + unsigned getBearingY() const; + unsigned getAdvanceX() const; + +private: + unsigned mWidth{0}; + unsigned mHeight{0}; + unsigned mBearingX{0}; + unsigned mBearingY{0}; + unsigned mAdvanceX{0}; + std::unique_ptr > mImage; +}; diff --git a/src/fonts/FontItem.cpp b/src/fonts/FontItem.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/fonts/FontItem.h b/src/fonts/FontItem.h new file mode 100644 index 0000000..5b48bf9 --- /dev/null +++ b/src/fonts/FontItem.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +class FontItem +{ +public: + FontItem(const std::string& faceName = "Arial", unsigned size = 16) + : mFaceName(faceName), + mSize(size) + { + + } + + bool hasPath() const + { + return !mPath.empty(); + } + + const std::filesystem::path& getPath() const + { + return mPath; + } + + void setPath(std::filesystem::path path) + { + mPath = path; + } + +private: + unsigned mSize{16}; + std::string mFaceName; + std::filesystem::path mPath; +}; diff --git a/src/fonts/FontReader.h b/src/fonts/FontReader.h index 02cd07b..091ebed 100644 --- a/src/fonts/FontReader.h +++ b/src/fonts/FontReader.h @@ -3,8 +3,8 @@ #include #include #include -#include "IFont.h" #include "File.h" +#include "IFont.h" class File; diff --git a/src/fonts/FontsManager.cpp b/src/fonts/FontsManager.cpp index 9621802..4d00e7f 100644 --- a/src/fonts/FontsManager.cpp +++ b/src/fonts/FontsManager.cpp @@ -20,4 +20,20 @@ IFontEngine* FontsManager::getFontEngine() const return mFontEngine.get(); } +FontGlyph* FontsManager::getGlyph(char c) +{ + auto iter = mGlyphs.find(c); + if(iter != mGlyphs.end()) + { + return iter->second.get(); + } + else + { + auto glyph = mFontEngine->loadGlyph(c); + auto glyph_ptr = glyph.get(); + mGlyphs[c] = std::move(glyph); + return glyph_ptr; + } +} + diff --git a/src/fonts/FontsManager.h b/src/fonts/FontsManager.h index a539a80..19fe3bd 100644 --- a/src/fonts/FontsManager.h +++ b/src/fonts/FontsManager.h @@ -2,8 +2,10 @@ #include #include +#include class IFontEngine; +class FontGlyph; class FontsManager { @@ -13,8 +15,12 @@ public: IFontEngine* getFontEngine() const; + FontGlyph* getGlyph(char c); + private: std::unique_ptr mFontEngine; + + std::unordered_map > mGlyphs; }; using FontsManagerPtr = std::unique_ptr; diff --git a/src/fonts/FreeTypeFontEngine.cpp b/src/fonts/FreeTypeFontEngine.cpp index 5cf100b..bf26e3e 100644 --- a/src/fonts/FreeTypeFontEngine.cpp +++ b/src/fonts/FreeTypeFontEngine.cpp @@ -2,6 +2,7 @@ #include "Image.h" #include "FileLogger.h" +#include "FontGlyph.h" void FreeTypeFontEngine::initialize() { @@ -37,7 +38,7 @@ void FreeTypeFontEngine::loadFontFace(const std::filesystem::path& fontFile, int FT_Set_Pixel_Sizes(mWorkingFontFace, penSize, 0); } -std::unique_ptr > FreeTypeFontEngine::loadGlyph(unsigned charCode) +std::unique_ptr FreeTypeFontEngine::loadGlyph(unsigned charCode) { auto glyph_index = FT_Get_Char_Index( mWorkingFontFace, 65 ); if (glyph_index == 0) @@ -83,5 +84,13 @@ std::unique_ptr > FreeTypeFontEngine::loadGlyph(unsigned ch } } image->setData(data); - return image; + + auto glyph = std::make_unique(mWorkingFontFace->glyph->bitmap.width, + mWorkingFontFace->glyph->bitmap.rows, + mWorkingFontFace->glyph->bitmap_left, + mWorkingFontFace->glyph->bitmap_top, + mWorkingFontFace->glyph->advance.x, + std::move(image)); + + return glyph; } diff --git a/src/fonts/FreeTypeFontEngine.h b/src/fonts/FreeTypeFontEngine.h index 51049a8..40a4d5c 100644 --- a/src/fonts/FreeTypeFontEngine.h +++ b/src/fonts/FreeTypeFontEngine.h @@ -19,7 +19,7 @@ public: void loadFontFace(const std::filesystem::path& fontFile, int penSize = 16) override; - std::unique_ptr > loadGlyph(unsigned charCode) override; + std::unique_ptr loadGlyph(unsigned charCode) override; private: std::filesystem::path mSystemFontLocation{"/usr/share/fonts/"}; diff --git a/src/fonts/IFontEngine.h b/src/fonts/IFontEngine.h index 82b410a..082fd43 100644 --- a/src/fonts/IFontEngine.h +++ b/src/fonts/IFontEngine.h @@ -3,8 +3,7 @@ #include #include -template -class Image; +class FontGlyph; class IFontEngine { @@ -16,5 +15,5 @@ public: virtual void loadFontFace(const std::filesystem::path& fontFile, int penSize = 16) = 0; - virtual std::unique_ptr > loadGlyph(unsigned charCode) = 0; + virtual std::unique_ptr loadGlyph(unsigned charCode) = 0; }; diff --git a/src/fonts/TrueTypeFont.h b/src/fonts/TrueTypeFont.h index 5749dec..ba6c184 100644 --- a/src/fonts/TrueTypeFont.h +++ b/src/fonts/TrueTypeFont.h @@ -1,9 +1,8 @@ #pragma once -#include "IFont.h" - #include #include +#include "IFont.h" class TrueTypeFont : public IFont { diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt index 8cc6fe4..94f78ca 100644 --- a/src/graphics/CMakeLists.txt +++ b/src/graphics/CMakeLists.txt @@ -19,8 +19,14 @@ set(OpenGL_GL_PREFERENCE "GLVND") find_package(OpenGL QUIET) if (OpenGL_FOUND) list(APPEND platform_LIBS OpenGL::GL OpenGL::GLU) - list(APPEND graphics_LIB_INCLUDES opengl/OpenGlPainter.cpp) - list(APPEND graphics_HEADERS opengl/OpenGlPainter.h) + list(APPEND graphics_LIB_INCLUDES + opengl/OpenGlPainter.cpp + opengl/OpenGlFontTexture.cpp + opengl/OpenGlShaderProgram.cpp) + list(APPEND graphics_HEADERS + opengl/OpenGlPainter.h + opengl/OpenGlFontTexture.h + opengl/OpenGlShaderProgram.h) else() message(STATUS "OpenGL headers not found - skipping OpenGL support") endif() diff --git a/src/graphics/DrawingContext.cpp b/src/graphics/DrawingContext.cpp index 495d24d..c81ae0e 100644 --- a/src/graphics/DrawingContext.cpp +++ b/src/graphics/DrawingContext.cpp @@ -2,6 +2,8 @@ #include "AbstractPainter.h" #include "OpenGlPainter.h" +#include "OpenGlShaderProgram.h" +#include "OpenGlFontTexture.h" #include "RasterPainter.h" #include "Grid.h" #include "TriMesh.h" @@ -40,6 +42,11 @@ DrawingSurface* DrawingContext::getSurface() const return mSurface; } +FontsManager* DrawingContext::getFontsManager() const +{ + return mFontsManager; +} + void DrawingContext::paint() { mScene->update(mFontsManager, mDrawingMode == DrawingMode::RASTER ? mSurface->getImage() : nullptr); diff --git a/src/graphics/DrawingContext.h b/src/graphics/DrawingContext.h index fab6d46..3140a54 100644 --- a/src/graphics/DrawingContext.h +++ b/src/graphics/DrawingContext.h @@ -25,6 +25,8 @@ public: DrawingSurface* getSurface() const; + FontsManager* getFontsManager() const; + void paint(); private: diff --git a/src/graphics/opengl/OpenGlFontTexture.cpp b/src/graphics/opengl/OpenGlFontTexture.cpp new file mode 100644 index 0000000..048b670 --- /dev/null +++ b/src/graphics/opengl/OpenGlFontTexture.cpp @@ -0,0 +1,36 @@ +#include "OpenGlFontTexture.h" + +#include "FontGlyph.h" +#include "Image.h" + +#define GL_GLEXT_PROTOTYPES +#include + +OpenGlFontTexture::OpenGlFontTexture(FontGlyph* glyph) + : mGlyph(glyph) +{ + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glGenTextures(1, &mHandle); + glBindTexture(GL_TEXTURE_2D, mHandle); + + auto buffer = glyph->getImage()->getDataPtr(); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RED, + mGlyph->getWidth(), + mGlyph->getHeight(), + 0, + GL_RED, + GL_UNSIGNED_BYTE, + buffer + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + +} diff --git a/src/graphics/opengl/OpenGlFontTexture.h b/src/graphics/opengl/OpenGlFontTexture.h new file mode 100644 index 0000000..9388bc9 --- /dev/null +++ b/src/graphics/opengl/OpenGlFontTexture.h @@ -0,0 +1,13 @@ +#pragma once + +class FontGlyph; + +class OpenGlFontTexture +{ +public: + OpenGlFontTexture(FontGlyph* glyph); + +private: + unsigned int mHandle{0}; + FontGlyph* mGlyph{nullptr}; +}; diff --git a/src/graphics/opengl/OpenGlPainter.cpp b/src/graphics/opengl/OpenGlPainter.cpp index 32e9698..9fa1177 100644 --- a/src/graphics/opengl/OpenGlPainter.cpp +++ b/src/graphics/opengl/OpenGlPainter.cpp @@ -5,6 +5,15 @@ #include "Scene.h" #include "TriMesh.h" +#include "FontsManager.h" +#include "FontGlyph.h" + +#include "OpenGlFontTexture.h" +#include "OpenGlShaderProgram.h" +#include "TextData.h" + +#include "File.h" + #ifdef _WIN32 #include #endif @@ -14,30 +23,18 @@ #include #include +#include +#include +#include + #include -const char* vertexShaderSource = "#version 330 core\n" - "layout (location = 0) in vec3 aPos;\n" - "void main()\n" - "{\n" - " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" - "}\0"; - - -const char* fragmentShaderSource = "#version 330 core\n" - "out vec4 FragColor;\n" - "void main()\n" - "{\n" - "FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" - "}\n"; - - OpenGlPainter::OpenGlPainter() { } -void OpenGlPainter::initialize() +void OpenGlPainter::initializeMeshShader() { if (auto context = glXGetCurrentContext()) { @@ -54,99 +51,70 @@ void OpenGlPainter::initialize() glGetIntegerv(GL_MINOR_VERSION, &minor_version); std::cout << "Using opengl version " << major_version << "|" << minor_version << std::endl; - std::cout << "Creating opengl painter" << std::endl; - unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr); - glCompileShader(vertexShader); + auto vert_shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders/default.vert"; + auto frag_shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders/default.frag"; - int success; - char infoLog[512]; - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); - if(!success) + mMeshShaderProgram = std::make_unique(vert_shader_path, frag_shader_path); +} + +void OpenGlPainter::initializeTextShader() +{ + auto vert_shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders/text.vert"; + auto frag_shader_path = std::filesystem::path(__FILE__).parent_path() / "shaders/text.frag"; + + mTextShaderProgram = std::make_unique(vert_shader_path, frag_shader_path); +} + +void OpenGlPainter::renderTextLayer(const TextData& textData, DrawingContext* context) +{ + if (!mTextShaderProgram) { - glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog); - std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED: " << std::string(infoLog) << std::endl; + initializeTextShader(); + } - if (auto errCode = glGetError(); errCode != GL_NO_ERROR) - { - auto errString = gluErrorString(errCode); - std::cout << "Got gl error" << errString << std::endl; - } + auto first_char = textData.mContent[0]; + auto iter = mFontTextures.find(first_char); + OpenGlFontTexture* working_texture{nullptr}; + if (iter == mFontTextures.end()) + { + auto glyph = context->getFontsManager()->getGlyph(first_char); + auto new_texture = std::make_unique(nullptr); + working_texture = new_texture.get(); + mFontTextures[first_char] = std::move(new_texture); } else { - std::cout << "Shader compiled ok" << std::endl; - if (auto errCode = glGetError(); errCode != GL_NO_ERROR) - { - auto errString = gluErrorString(errCode); - std::cout << "Got gl error after ok" << errString << std::endl; - } + working_texture = iter->second.get(); } - unsigned int fragmentShader; - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr); - glCompileShader(fragmentShader); - - glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); - - if(!success) - { - glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); - std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED: " << infoLog << std::endl; - } - - mShaderProgram = glCreateProgram(); - - glAttachShader(mShaderProgram, vertexShader); - glAttachShader(mShaderProgram, fragmentShader); - glLinkProgram(mShaderProgram); - - glGetProgramiv(mShaderProgram, GL_LINK_STATUS, &success); - if(!success) - { - glGetProgramInfoLog(mShaderProgram, 512, NULL, infoLog); - std::cout << "Shader linking FAILED\n" << infoLog << std::endl; - } - - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - mInitialized = true; + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } -void OpenGlPainter::paint(DrawingContext* context) +void OpenGlPainter::renderMeshLayer(TriMesh* mesh, DrawingContext* context) { - if (!mInitialized) + if (!mMeshShaderProgram) { - initialize(); + initializeMeshShader(); } - auto surface = context->getSurface(); - const auto width = double(surface->getWidth()); - const auto height = double(surface->getHeight()); - const auto num_mesh = context->getScene()->getNumMeshes(); - - glViewport(0, 0, width, height); - //glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); - //glScissor(0, 0, width, height); - //glMatrixMode(GL_PROJECTION); - //glLoadIdentity(); - - glClearColor(0.5, 0.5, 1.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - - //glMatrixMode(GL_MODELVIEW); - //glLoadIdentity(); - float vertices[] = { - -0.5f, -0.5f, 0.0f, - 0.5f, -0.5f, 0.0f, - 0.0f, 0.5f, 0.0f + 0.5f, 0.5f, 0.0f, // top right + 0.5f, -0.5f, 0.0f, // bottom right + -0.5f, -0.5f, 0.0f, // bottom left + -0.5f, 0.5f, 0.0f // top left + }; + + unsigned int indices[] = { // note that we start from 0! + 0, 1, 3, // first triangle + 1, 2, 3 // second triangle }; unsigned int vbo{0}; glGenBuffers(1, &vbo); + unsigned int EBO; + glGenBuffers(1, &EBO); + unsigned int VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); @@ -154,14 +122,22 @@ void OpenGlPainter::paint(DrawingContext* context) glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); - glUseProgram(mShaderProgram); + int vertexColorLocation = glGetUniformLocation(mMeshShaderProgram->getHandle(), "ourColor"); + + glUseProgram(mMeshShaderProgram->getHandle()); glBindVertexArray(VAO); - glDrawArrays(GL_TRIANGLES, 0, 3); + glUniform4f(vertexColorLocation, 0.0f, 1.0, 0.0f, 1.0f); + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); /* std::cout << "Bounds are : " << width << " | " << height << std::endl; @@ -207,6 +183,31 @@ void OpenGlPainter::paint(DrawingContext* context) break; } */ +} + +void OpenGlPainter::paint(DrawingContext* context) +{ + auto surface = context->getSurface(); + const auto width = double(surface->getWidth()); + const auto height = double(surface->getHeight()); + + glViewport(0, 0, width, height); + //glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); + //glScissor(0, 0, width, height); + //glMatrixMode(GL_PROJECTION); + //glLoadIdentity(); + + glClearColor(0.5, 0.5, 1.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + //glMatrixMode(GL_MODELVIEW); + //glLoadIdentity(); + + const auto num_mesh = context->getScene()->getNumMeshes(); + //renderMeshLayer(nullptr, context); + + auto text_data = context->getScene()->getTextData(); + renderTextLayer(text_data[0], context); glFlush(); } diff --git a/src/graphics/opengl/OpenGlPainter.h b/src/graphics/opengl/OpenGlPainter.h index e02a4b2..d848cd7 100644 --- a/src/graphics/opengl/OpenGlPainter.h +++ b/src/graphics/opengl/OpenGlPainter.h @@ -2,21 +2,33 @@ #include "AbstractPainter.h" +#include +#include + class DrawingContext; +class OpenGlFontTexture; +class OpenGlShaderProgram; + +class TextData; +class TriMesh; class OpenGlPainter : public AbstractPainter { public: - OpenGlPainter(); - - void initialize(); void paint(DrawingContext* context) override; private: - bool mInitialized{false}; - unsigned int mShaderProgram{0}; + void initializeMeshShader(); + void initializeTextShader(); + + void renderTextLayer(const TextData& textData, DrawingContext* context); + void renderMeshLayer(TriMesh* mesh, DrawingContext* context); + + std::unique_ptr mMeshShaderProgram; + std::unique_ptr mTextShaderProgram; + std::unordered_map > mFontTextures; }; diff --git a/src/graphics/opengl/OpenGlShaderProgram.cpp b/src/graphics/opengl/OpenGlShaderProgram.cpp new file mode 100644 index 0000000..7375687 --- /dev/null +++ b/src/graphics/opengl/OpenGlShaderProgram.cpp @@ -0,0 +1,68 @@ +#include "OpenGlShaderProgram.h" + +#include "File.h" +#include "FileLogger.h" + +#define GL_GLEXT_PROTOTYPES +#include +#include + +OpenGlShaderProgram::OpenGlShaderProgram(const Path& vertShaderPath, const Path& fragShaderPath) +{ + const auto vert_shader_source = File(vertShaderPath).read(); + const auto frag_shader_source = File(fragShaderPath).read(); + + unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); + + const char* vert_source = vert_shader_source.c_str(); + glShaderSource(vertexShader, 1, &vert_source, nullptr); + glCompileShader(vertexShader); + + int success; + char infoLog[512]; + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + if(!success) + { + glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog); + MLOG_ERROR("ERROR::SHADER::VERTEX::COMPILATION_FAILED: " << infoLog); + if (auto errCode = glGetError(); errCode != GL_NO_ERROR) + { + auto errString = gluErrorString(errCode); + MLOG_ERROR("Got gl error " << errString); + } + } + + unsigned int fragmentShader; + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + const char* frag_source = frag_shader_source.c_str(); + glShaderSource(fragmentShader, 1, &frag_source, nullptr); + glCompileShader(fragmentShader); + + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); + if(!success) + { + glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); + MLOG_ERROR("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED: " << infoLog); + } + + mHandle = glCreateProgram(); + + glAttachShader(mHandle, vertexShader); + glAttachShader(mHandle, fragmentShader); + glLinkProgram(mHandle); + + glGetProgramiv(mHandle, GL_LINK_STATUS, &success); + if(!success) + { + glGetProgramInfoLog(mHandle, 512, NULL, infoLog); + MLOG_ERROR("Shader linking FAILED: " << infoLog); + } + + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); +} + +unsigned int OpenGlShaderProgram::getHandle() const +{ + return mHandle; +} diff --git a/src/graphics/opengl/OpenGlShaderProgram.h b/src/graphics/opengl/OpenGlShaderProgram.h new file mode 100644 index 0000000..aea57f9 --- /dev/null +++ b/src/graphics/opengl/OpenGlShaderProgram.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +using Path = std::filesystem::path; + +class OpenGlShaderProgram +{ +public: + OpenGlShaderProgram(const Path& vertShaderPath, const Path& fragShaderPath); + + unsigned int getHandle() const; +private: + unsigned int mHandle{0}; +}; diff --git a/src/graphics/opengl/shaders/default.frag b/src/graphics/opengl/shaders/default.frag new file mode 100644 index 0000000..1c107f1 --- /dev/null +++ b/src/graphics/opengl/shaders/default.frag @@ -0,0 +1,11 @@ +#version 330 core +out vec4 FragColor; + +in vec4 vertexColor; // the input variable from the vertex shader (same name and same type) + +uniform vec4 ourColor; // we set this variable in the OpenGL code. + +void main() +{ + FragColor = ourColor; +} diff --git a/src/graphics/opengl/shaders/default.vert b/src/graphics/opengl/shaders/default.vert new file mode 100644 index 0000000..6ba1af4 --- /dev/null +++ b/src/graphics/opengl/shaders/default.vert @@ -0,0 +1,10 @@ +#version 330 core +layout (location = 0) in vec3 aPos; // the position variable has attribute position 0 + +out vec4 vertexColor; // specify a color output to the fragment shader + +void main() +{ + gl_Position = vec4(aPos, 1.0); // see how we directly give a vec3 to vec4's constructor + vertexColor = vec4(aPos.x, aPos.y, 0.0, 1.0); // set the output variable to a dark-red color +} diff --git a/src/graphics/opengl/shaders/text.frag b/src/graphics/opengl/shaders/text.frag new file mode 100644 index 0000000..0ee9f07 --- /dev/null +++ b/src/graphics/opengl/shaders/text.frag @@ -0,0 +1,12 @@ +#version 330 core +in vec2 TexCoords; +out vec4 color; + +uniform sampler2D text; +uniform vec3 textColor; + +void main() +{ + vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r); + color = vec4(textColor, 1.0) * sampled; +} diff --git a/src/graphics/opengl/shaders/text.vert b/src/graphics/opengl/shaders/text.vert new file mode 100644 index 0000000..5985616 --- /dev/null +++ b/src/graphics/opengl/shaders/text.vert @@ -0,0 +1,11 @@ +#version 330 core +layout (location = 0) in vec4 vertex; // +out vec2 TexCoords; + +uniform mat4 projection; + +void main() +{ + gl_Position = projection * vec4(vertex.xy, 0.0, 1.0); + TexCoords = vertex.zw; +} diff --git a/src/visual_elements/Scene.cpp b/src/visual_elements/Scene.cpp index 69aa2aa..31fda5f 100644 --- a/src/visual_elements/Scene.cpp +++ b/src/visual_elements/Scene.cpp @@ -34,25 +34,28 @@ void Scene::update(FontsManager* fontsManager, Image* image) node->update(fontsManager); layer->setIsDirty(false); } - mWorkingMeshs.push_back(dynamic_cast(node->getMesh())); mTextures.push_back(nullptr); } else { - auto node = layer->getTextNode(); + auto node = dynamic_cast(layer->getTextNode()); if (layer->getIsDirty()) { node->update(fontsManager); layer->setIsDirty(false); } - mWorkingMeshs.push_back(dynamic_cast(node->getMesh())); - mTextures.push_back(node->getTexture()); + mTextData.push_back(node->getTextData()); } } } } +const std::vector& Scene::getTextData() const +{ + return mTextData; +} + void Scene::processRectangleNode(RectangleNode* node) { diff --git a/src/visual_elements/Scene.h b/src/visual_elements/Scene.h index c2625f2..d0962fc 100644 --- a/src/visual_elements/Scene.h +++ b/src/visual_elements/Scene.h @@ -1,5 +1,7 @@ #pragma once +#include "TextData.h" + #include #include @@ -15,6 +17,7 @@ class Image; class Scene { public: + Scene() = default; void syncLayers(const std::vector& layers); @@ -27,11 +30,14 @@ public: Image* getTexture(std::size_t idx) const; -private: + const std::vector& getTextData() const; +private: void processRectangleNode(RectangleNode* node); - std::vector mWorkingMeshs; std::vector mLayers; + std::vector mWorkingMeshs; std::vector* > mTextures; + + std::vector mTextData; }; diff --git a/src/visual_elements/TextData.h b/src/visual_elements/TextData.h new file mode 100644 index 0000000..ccc2290 --- /dev/null +++ b/src/visual_elements/TextData.h @@ -0,0 +1,16 @@ +#pragma once + +#include "DiscretePoint.h" +#include "Color.h" +#include "FontItem.h" + +class TextData +{ +public: + TextData() = default; + DiscretePoint mLocation; + std::string mContent; + Color mFillColor; + Color mStrokeColor; + FontItem mFont; +}; diff --git a/src/visual_elements/TextNode.cpp b/src/visual_elements/TextNode.cpp index 6bd0f72..5ecdd9a 100644 --- a/src/visual_elements/TextNode.cpp +++ b/src/visual_elements/TextNode.cpp @@ -4,17 +4,18 @@ #include "FontsManager.h" #include "IFontEngine.h" #include "MeshPrimitives.h" +#include "FontItem.h" #include "Color.h" TextNode::TextNode(const std::string& content, const DiscretePoint& loc) - : AbstractVisualNode(loc), - mContent(content), - mFontLabel("fixed"), - mFillColor(Color(255, 255, 255)), - mStrokeColor(Color(0, 0, 0)) + : AbstractVisualNode(loc) { -// https://en.wikipedia.org/wiki/Fixed_(typeface)#:~:text=misc%2Dfixed%20is%20a%20collection,to%20a%20single%20font%20family. + mTextData.mContent = content; + mTextData.mFont = FontItem("Arial", 16); + mTextData.mLocation = loc; + mTextData.mFillColor = Color(255, 255, 255); + mTextData.mStrokeColor = Color(0, 0, 0); } TextNode::~TextNode() @@ -29,36 +30,36 @@ std::unique_ptr TextNode::Create(const std::string& content, const Dis const Color& TextNode::getFillColor() const { - return mFillColor; + return mTextData.mFillColor; } const Color& TextNode::getStrokeColor() const { - return mStrokeColor; + return mTextData.mStrokeColor; } std::string TextNode::getFontLabel() const { - return mFontLabel; + return {}; } std::string TextNode::getContent() const { - return mContent; + return mTextData.mContent; } void TextNode::setContent(const std::string& content) { - mContent = content; + mTextData.mContent = content; } void TextNode::setFillColor(const Color& color) { - mFillColor = color; + mTextData.mFillColor = color; } void TextNode::setStrokeColor(const Color& color) { - mStrokeColor = color; + mTextData.mStrokeColor = color; } void TextNode::update(FontsManager* drawingManager) @@ -67,32 +68,17 @@ void TextNode::update(FontsManager* drawingManager) updateTexture(drawingManager); } +const TextData& TextNode::getTextData() const +{ + return mTextData; +} + void TextNode::updateMesh() { - double font_height = 16; - double font_width = 16; - double text_width = mContent.size() * font_width; - - const auto rect = Rectangle(mLocation, text_width, font_height); - - auto mesh = MeshPrimitives::build(rect); - auto color = Color(0, 0, 0, 1.0); - - mesh->addConstantFaceVectorAttribute("Color", color.getAsVectorDouble()); - mMesh = std::move(mesh); } void TextNode::updateTexture(FontsManager* fontsManager) { - fontsManager->getFontEngine()->loadFontFace("truetype/msttcorefonts/arial.ttf"); - auto glyph = fontsManager->getFontEngine()->loadGlyph('A'); - if (!glyph) - { - return; - } - - mTexture = std::make_unique >(glyph->getWidth(), glyph->getHeight()); - mTexture->setData(glyph->getData()); } diff --git a/src/visual_elements/TextNode.h b/src/visual_elements/TextNode.h index 8156038..956db03 100644 --- a/src/visual_elements/TextNode.h +++ b/src/visual_elements/TextNode.h @@ -4,12 +4,12 @@ #include "AbstractVisualNode.h" #include "Color.h" +#include "FontItem.h" +#include "TextData.h" #include #include -class Color; - class TextNode : public AbstractVisualNode { public: @@ -24,6 +24,9 @@ public: std::string getContent() const; std::string getFontLabel() const; + + const TextData& getTextData() const; + void setContent(const std::string& content); void setFillColor(const Color& color); void setStrokeColor(const Color& color); @@ -34,10 +37,7 @@ private: void updateMesh() override; void updateTexture(FontsManager* fontsManager) override; - std::string mContent; - std::string mFontLabel; - Color mFillColor; - Color mStrokeColor; + TextData mTextData; }; using TextNodetr = std::unique_ptr; diff --git a/src/windows/ui_interfaces/AbstractUiInterface.h b/src/windows/ui_interfaces/AbstractUiInterface.h index dd82523..91219df 100644 --- a/src/windows/ui_interfaces/AbstractUiInterface.h +++ b/src/windows/ui_interfaces/AbstractUiInterface.h @@ -3,6 +3,7 @@ #include #include "IFontEngine.h" #include "FontsManager.h" +#include "FontGlyph.h" namespace mt { diff --git a/test/fonts/TestFreeTypeFontEngine.cpp b/test/fonts/TestFreeTypeFontEngine.cpp index fc6ff4e..b770a0d 100644 --- a/test/fonts/TestFreeTypeFontEngine.cpp +++ b/test/fonts/TestFreeTypeFontEngine.cpp @@ -1,5 +1,6 @@ #include "FreeTypeFontEngine.h" +#include "FontGlyph.h" #include "Image.h" #include