From dd5c3a06386f4eb6d572e872186b27938ba45899 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Mon, 30 Jun 2025 20:24:31 +0200 Subject: [PATCH] feat(rendering): simple font renderer --- assets/shaders/font.fs | 22 ++++++++++ assets/shaders/font.vs | 12 ++++++ assets/textures/NOTE.txt | 1 + assets/textures/debugfnt.bmp | Bin 0 -> 196662 bytes core/src/rendering/debug/debugrenderer.cpp | 45 +++++++++++++++++++++ core/src/rendering/renderer.cpp | 17 +++++++- core/src/rendering/renderer.h | 6 ++- core/src/rendering/shader.cpp | 6 ++- core/src/rendering/shader.h | 2 + editor/mainglwidget.cpp | 6 +++ 10 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 assets/shaders/font.fs create mode 100644 assets/shaders/font.vs create mode 100644 assets/textures/NOTE.txt create mode 100644 assets/textures/debugfnt.bmp create mode 100644 core/src/rendering/debug/debugrenderer.cpp diff --git a/assets/shaders/font.fs b/assets/shaders/font.fs new file mode 100644 index 0000000..4eedf4f --- /dev/null +++ b/assets/shaders/font.fs @@ -0,0 +1,22 @@ +#version 330 core + +out vec4 FragColor; +in vec3 vPos; +in vec2 vTexCoord; + +uniform sampler2D fontTex; +uniform int charIndex; + +// Main + +void main() { + int x = (charIndex-32) % 16; + int y = (charIndex-32) / 16; + + float fx = float(x) / 16; + float fy = float(y) / 8; + + vec4 color = texture(fontTex, vec2(fx, fy) + vTexCoord * vec2(1.f/32, 1.f/16)); + FragColor = vec3(color) == vec3(0, 0, 0) ? vec4(0, 0, 0, 0) : color; +// FragColor = color; +} \ No newline at end of file diff --git a/assets/shaders/font.vs b/assets/shaders/font.vs new file mode 100644 index 0000000..b6c200f --- /dev/null +++ b/assets/shaders/font.vs @@ -0,0 +1,12 @@ +#version 330 core +in vec3 aPos; +in vec2 aTexCoord; + +out vec3 vPos; +out vec2 vTexCoord; +void main() +{ + gl_Position = vec4(aPos, 1.0); + vPos = aPos; + vTexCoord = aTexCoord; +} diff --git a/assets/textures/NOTE.txt b/assets/textures/NOTE.txt new file mode 100644 index 0000000..7c93e18 --- /dev/null +++ b/assets/textures/NOTE.txt @@ -0,0 +1 @@ +debugfnt.bmp is Iosevka NFM Thin generated via CBFG diff --git a/assets/textures/debugfnt.bmp b/assets/textures/debugfnt.bmp new file mode 100644 index 0000000000000000000000000000000000000000..437dac9d9419f14f14e9ec8def103460879eae22 GIT binary patch literal 196662 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 KFiBwk`~P2x$WX-q literal 0 HcmV?d00001 diff --git a/core/src/rendering/debug/debugrenderer.cpp b/core/src/rendering/debug/debugrenderer.cpp new file mode 100644 index 0000000..6c8030c --- /dev/null +++ b/core/src/rendering/debug/debugrenderer.cpp @@ -0,0 +1,45 @@ +#include "rendering/shader.h" +#include "rendering/texture3d.h" +#include +#include + +extern int viewportWidth, viewportHeight; +extern Texture3D* fontTexture; +extern Shader* fontShader; + +void renderChar(char c, int x, int y, float scale=1.f) { + fontShader->use(); + fontTexture->activate(1); + fontShader->set("fontTex", 1); + + fontShader->set("charIndex", (int)c); + + // https://stackoverflow.com/a/10631263 + int tex = fontShader->getAttribute("aTexCoord"); + + y = viewportHeight - y - 16*scale; + float x0 = float(x)/viewportWidth, y0 = float(y)/viewportHeight, x1 = ((float)x + 8*scale)/viewportWidth, y1 = ((float)y + 16*scale)/viewportHeight; + x0 *= 2, y0 *= 2, x1 *= 2, y1 *= 2; + x0 -= 1, y0 -= 1, x1 -= 1, y1 -= 1; + + glBegin(GL_QUADS); + glVertex3f(x0, y0, 0); glVertexAttrib2f(tex, 1, 1); + glVertex3f(x1, y0, 0); glVertexAttrib2f(tex, 1, 0); + glVertex3f(x1, y1, 0); glVertexAttrib2f(tex, 0, 0); + glVertex3f(x0, y1, 0); glVertexAttrib2f(tex, 0, 1); + glEnd(); +} + +void renderString(std::string str, int x, int y, float scale=1.f) { + for (int i = 0; i < (int)str.length(); i++) { + char c = str[i]; + renderChar(c, x+i*8*scale, y, scale); + } +} + +// Draws debug info window +// Including info about framerates, etc. +void renderDebugInfo() { + // renderString("Hello, test!", 50, 50, 2); + renderString("Hello, test!", 0, 0, 1); +} \ No newline at end of file diff --git a/core/src/rendering/renderer.cpp b/core/src/rendering/renderer.cpp index 8854453..b403e8a 100644 --- a/core/src/rendering/renderer.cpp +++ b/core/src/rendering/renderer.cpp @@ -21,6 +21,7 @@ #include "math_helper.h" #include "objects/service/selection.h" #include "partassembly.h" +#include "rendering/texture.h" #include "rendering/torus.h" #include "shader.h" #include "mesh.h" @@ -41,13 +42,18 @@ Shader* identityShader = NULL; Shader* ghostShader = NULL; Shader* wireframeShader = NULL; Shader* outlineShader = NULL; +Shader* fontShader = NULL; extern Camera camera; Skybox* skyboxTexture = NULL; Texture3D* studsTexture = NULL; +Texture* fontTexture = NULL; +bool debugRendererEnabled = false; bool wireframeRendering = false; -static int viewportWidth, viewportHeight; +int viewportWidth, viewportHeight; + +void renderDebugInfo(); void renderInit(GLFWwindow* window, int width, int height) { viewportWidth = width, viewportHeight = height; @@ -60,6 +66,8 @@ void renderInit(GLFWwindow* window, int width, int height) { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + fontTexture = new Texture("assets/textures/debugfnt.bmp", GL_RGB); + skyboxTexture = new Skybox({ "assets/textures/skybox/null_plainsky512_lf.jpg", "assets/textures/skybox/null_plainsky512_rt.jpg", @@ -79,6 +87,7 @@ void renderInit(GLFWwindow* window, int width, int height) { ghostShader = new Shader("assets/shaders/ghost.vs", "assets/shaders/ghost.fs"); wireframeShader = new Shader("assets/shaders/wireframe.vs", "assets/shaders/wireframe.fs"); outlineShader = new Shader("assets/shaders/outline.vs", "assets/shaders/outline.fs"); + fontShader = new Shader("assets/shaders/font.vs", "assets/shaders/font.fs"); } void renderParts() { @@ -639,10 +648,16 @@ void render(GLFWwindow* window) { renderRotationArcs(); if (wireframeRendering) renderWireframe(); + if (debugRendererEnabled) + renderDebugInfo(); // TODO: Make this a debug flag // renderAABB(); } void setViewport(int width, int height) { viewportWidth = width, viewportHeight = height; +} + +void setDebugRendererEnabled(bool enabled) { + debugRendererEnabled = enabled; } \ No newline at end of file diff --git a/core/src/rendering/renderer.h b/core/src/rendering/renderer.h index 5aa33bb..7e0b5ae 100644 --- a/core/src/rendering/renderer.h +++ b/core/src/rendering/renderer.h @@ -3,10 +3,12 @@ extern bool wireframeRendering; -namespace Data { class CFrame; class Color3; }; +class CFrame; +class Color3; void renderInit(GLFWwindow* window, int width, int height); void render(GLFWwindow* window); void setViewport(int width, int height); void addDebugRenderCFrame(CFrame); -void addDebugRenderCFrame(CFrame, Color3); \ No newline at end of file +void addDebugRenderCFrame(CFrame, Color3); +void setDebugRendererEnabled(bool enabled); \ No newline at end of file diff --git a/core/src/rendering/shader.cpp b/core/src/rendering/shader.cpp index efdfd81..0ed676b 100644 --- a/core/src/rendering/shader.cpp +++ b/core/src/rendering/shader.cpp @@ -106,4 +106,8 @@ void Shader::set(std::string key, glm::mat3 value) { void Shader::set(std::string key, glm::mat4 value) { glUniformMatrix4fv(glGetUniformLocation(id, key.c_str()), 1, GL_FALSE, glm::value_ptr(value)); -} \ No newline at end of file +} + +int Shader::getAttribute(std::string key) { + return glGetAttribLocation(id, key.c_str()); +} diff --git a/core/src/rendering/shader.h b/core/src/rendering/shader.h index 77aa5b6..897b275 100644 --- a/core/src/rendering/shader.h +++ b/core/src/rendering/shader.h @@ -21,4 +21,6 @@ public: void set(std::string key, glm::vec3 value); void set(std::string key, glm::mat3 value); void set(std::string key, glm::mat4 value); + + int getAttribute(std::string key); }; \ No newline at end of file diff --git a/editor/mainglwidget.cpp b/editor/mainglwidget.cpp index d40cef3..725ffc7 100755 --- a/editor/mainglwidget.cpp +++ b/editor/mainglwidget.cpp @@ -524,6 +524,12 @@ void MainGLWidget::keyPressEvent(QKeyEvent* evt) { lastPart->name = "Part" + std::to_string(partId++); M_mainWindow->undoManager.PushState({ UndoStateInstanceCreated { lastPart, gWorkspace() } }); } + + if (evt->key() == Qt::Key_BracketLeft) { + static bool debugRenderEnabled; + debugRenderEnabled = !debugRenderEnabled; + setDebugRendererEnabled(debugRenderEnabled); + } } void MainGLWidget::keyReleaseEvent(QKeyEvent* evt) {