]> code.bitgloo.com Git - clyne/gamedev2.git/commitdiff
Added UI rendering support to render loop, although fonts don't render yet
authorAndy Belle-Isle <drumsetmonkey@gmail.com>
Wed, 18 Sep 2019 18:40:23 +0000 (14:40 -0400)
committerAndy Belle-Isle <drumsetmonkey@gmail.com>
Wed, 18 Sep 2019 18:40:23 +0000 (14:40 -0400)
1  2 
Scripts/init.lua
Shaders/ui.frag
Shaders/ui.vert
src/render.cpp
src/render.hpp
src/text.cpp
src/world.cpp

index d2abb006f64e92f173348d142dded4c3cd484052,d76a4020a4b121f3a7a7bb9d74a978a5d8a91088..9e6848e9f41f31546fb422ee272697a190a81243
@@@ -8,11 -6,10 +8,11 @@@ player = 
              self.Render.flipx = true;
          end,
          MoveLeftReleased = function(self)
-             self.Velocity.x = self.Velocity.x + 3
 +            game.puts("default", self.Position.x, self.Position.y, "Hey.")
+             self.Velocity.x = self.Velocity.x + 3.0
          end,
          MoveRightPressed = function(self)
-             self.Velocity.x = self.Velocity.x + 3
+             self.Velocity.x = self.Velocity.x + 3.0
              self.Render.flipx = false;
          end,
          MoveRightReleased = function(self)
diff --cc Shaders/ui.frag
index 0000000000000000000000000000000000000000,737344e12975e21bc816cbc813e2992afffb09ec..118108c8d64b36dc322f9cfe982b07279f6a2a7d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,12 +1,16 @@@
 -varying vec2 texCoord;
 -varying vec4 color;
++#version 130
++
+ uniform sampler2D sampler;
 -      gl_FragColor = pixelColor * color;
++in vec2 texCoord;
++in vec4 color;
++
++out vec4 FragColor;
+ void main(){
+     vec4 pixelColor = texture2D(sampler, vec2(texCoord.x, texCoord.y));
+     //TODO allow antialiasing
+       //if (pixelColor.w != 1.0f)
+       //      discard;
++      FragColor = pixelColor * color;
+ }
diff --cc Shaders/ui.vert
index 0000000000000000000000000000000000000000,b2fcba4bc8793714286383123839c3d670f6cec2..ee4f92c01dcd7187c74da0d85ef40d13bd4a91fa
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,14 +1,19 @@@
 -attribute vec3 coord2d;
 -attribute vec2 tex_coord;
++#version 130
 -uniform mat4 ortho;
 -uniform vec4 tex_color;
++in vec3 coord2d;
++in vec2 tex_coord;
 -varying vec2 texCoord;
 -varying vec4 color;
++uniform mat4 projection;
++uniform mat4 view;
++uniform mat4 model;
++
++out vec2 texCoord;
++out vec4 color;
+ void main(){
+     texCoord = tex_coord;
 -    color = tex_color;
 -    gl_Position = ortho * vec4(coord2d.xyz, 1.0);
++    color = vec4(1.0, 1.0, 1.0, 1.0);
++    //color = tex_color;
++    //gl_Position = ortho * vec4(coord2d.xyz, 1.0);
++    gl_Position = projection * view * model * vec4(coord2d, 1.0f);
+ }
diff --cc src/render.cpp
index 3eea57b242cfb61b4eab1f4ed3da50819aa3982d,0c92475d158746c332760101deb60b56c9380744..1b5ba62c6a47027d265d9185016ab4f406d87ef9
@@@ -223,32 -221,32 +223,74 @@@ void RenderSystem::update([[maybe_unuse
          glDrawArrays(GL_TRIANGLES, 0, worldVertex);
      }
  
 -    view = glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f),  // Pos
++    glDisableVertexAttribArray(a);
++    glDisableVertexAttribArray(t);
++
+     /******************
+     *  UI RENDERING  *
+     ******************/
-         glUniform1i(q, 0);
++    static GLuint uiS = uiShader.getProgram();
++    static GLuint uiS_v = uiShader.getUniform("view");
++    static GLuint uiS_p = uiShader.getUniform("projection");
++    static GLuint uiS_m = uiShader.getUniform("model");
++    static GLuint uiS_a = uiShader.getAttribute("coord2d");
++    static GLuint uiS_t = uiShader.getAttribute("tex_coord");
++    static GLuint uiS_q = uiShader.getUniform("sampler");
++
++    glUseProgram(uiS);
++
++    view = glm::lookAt(glm::vec3(0.0f, 0.0f, 10.0f),  // Pos
+                        glm::vec3(0.0f, 0.0f, 0.0f),  // Facing
+                        glm::vec3(0.0f, 1.0f, 0.0f)); // Up
+     scale = 1.0f;
+     scaleWidth = static_cast<float>(width) / scale;
+     scaleHeight = static_cast<float>(height) / scale;
+     projection = glm::ortho(-(scaleWidth/2),    // Left
+                              (scaleWidth/2),    // Right
+                             -(scaleHeight/2),   // Bottom
+                              (scaleHeight/2),   // Top
+                              10.0f,             // zFar
+                             -10.0f);            // zNear
+     model = glm::mat4(1.0f);
++    glUniformMatrix4fv(uiS_v, 1, GL_FALSE, glm::value_ptr(view));
++    glUniformMatrix4fv(uiS_p, 1, GL_FALSE, glm::value_ptr(projection));
++    glUniformMatrix4fv(uiS_m, 1, GL_FALSE, glm::value_ptr(model));
++
++    glEnableVertexAttribArray(uiS_a);
++    glEnableVertexAttribArray(uiS_t);
++
 +    // Update all UI VBOs
 +    for (auto& r : uiRenders) {
 +        auto& render = r.second;
 +
 +        glActiveTexture(GL_TEXTURE0);
 +        glBindTexture(GL_TEXTURE_2D, render.tex);
-         glActiveTexture(GL_TEXTURE1);
-         glBindTexture(GL_TEXTURE_2D, render.normal);
-         glUniform1i(n, 1);
++        glUniform1i(uiS_q, 0);
 +
-         glVertexAttribPointer(a, 3, GL_FLOAT, GL_FALSE,
++        //glActiveTexture(GL_TEXTURE1);
++        //glBindTexture(GL_TEXTURE_2D, render.normal);
++        //glUniform1i(n, 1);
 +
 +        glBindBuffer(GL_ARRAY_BUFFER, r.first);
 +
-         glVertexAttribPointer(t, 2, GL_FLOAT, GL_FALSE, 
++        glVertexAttribPointer(uiS_a, 3, GL_FLOAT, GL_FALSE,
 +                              6*sizeof(float), 0);
++        glVertexAttribPointer(uiS_t, 2, GL_FLOAT, GL_FALSE, 
 +                              6*sizeof(float), (void*)(3*sizeof(float)));
 +        glDrawArrays(GL_TRIANGLES, 0, render.vertex);
 +    }
 +
++    glDisableVertexAttribArray(uiS_a);
++    glDisableVertexAttribArray(uiS_t);
++
      /*************
      *  CLEANUP  *
      *************/
--    glDisableVertexAttribArray(a);
--    glDisableVertexAttribArray(t);
  
      glDisable(GL_POLYGON_OFFSET_FILL);
      glDisable(GL_CULL_FACE);
@@@ -317,8 -315,8 +359,19 @@@ int RenderSystem::init(void
      worldShader.addUniform("AmbientLight");
      worldShader.addUniform("Flipped");
  
++    uiShader.createProgram("Shaders/ui.vert", "Shaders/ui.frag");
++
++    uiShader.addUniform("projection");
++    uiShader.addUniform("view");
++    uiShader.addUniform("model");
++
++    uiShader.addAttribute("coord2d");
++    uiShader.addAttribute("tex_coord");
++
++    uiShader.addUniform("sampler");
++
      glEnableVertexAttribArray(worldShader.getAttribute("vertex"));
--    glUseProgram(worldShader.getProgram());
++    glEnableVertexAttribArray(uiShader.getAttribute("coord2d"));
  
      // TODO
      //glPolygonOffset(1.0, 1.0);
diff --cc src/render.hpp
index eabf4becf4b519040af30b75ea6c076314ae5abb,f3064d155c55b793db558863dfc02ee1fcdfae1f..88668cc459f2672220578905cccedb67a877613b
@@@ -64,11 -52,8 +64,12 @@@ private
      SDL_GLContext context;
  
      Shader worldShader;
++    Shader uiShader;
      glm::vec3 camPos;
  
 +    // Map of VBOs and their render data
 +    std::map<GLuint, UIRenderData> uiRenders;
 +
      GLuint worldVBO = 0;
      unsigned int worldVertex = 0;
      GLuint worldTexture = 0;
diff --cc src/text.cpp
index 1381eb2563ad5927bd338db84ea004a1aa52fb1d,0000000000000000000000000000000000000000..fdb32452e343eb7d0b7bbb4920dffa2b611588f7
mode 100644,000000..100644
--- /dev/null
@@@ -1,152 -1,0 +1,199 @@@
-                     text.x, text.y, text.z,
-                     d.data[c].offset.first, d.data[c].offset.second,
 +#include "text.hpp"
 +
 +#include "events/render.hpp"
 +
 +#include <iostream>
 +
 +void TextSystem::configure([[maybe_unused]] entityx::EntityManager& entities,
 +                           [[maybe_unused]] entityx::EventManager& events)
 +{
 +    if (FT_Init_FreeType(&freetype) != 0) {
 +        // TODO handle error
 +    }
 +
 +    shouldUpdateVBOs = false;
 +}
 +    
 +/**
 + * Draws the text for all entities.
 + */
 +void TextSystem::update([[maybe_unused]] entityx::EntityManager& entites,
 +                        entityx::EventManager& events,
 +                        [[maybe_unused]] entityx::TimeDelta dt)
 +{
 +    if (shouldUpdateVBOs) {
 +        shouldUpdateVBOs = false;
 +        updateVBOs();
 +
 +        for (auto& data : fontData) {
 +            auto& d = data.second;
 +            if (d.text.size() == 0)
 +                continue;
 +
 +            // TODO make normal
 +            events.emit<NewRenderEvent>(d.vbo, d.tex, 0, d.buffer.size());
 +        }
 +    }
 +}
 +
 +void TextSystem::loadFont(const std::string& name,
 +                          const std::string& file,
 +                          int size)
 +{
 +    // Find or load font at given size
 +    //
 +
 +    if (fonts.find(file) == fonts.end()) {
 +        FT_Face face;
 +        if (FT_New_Face(freetype, file.c_str(), 0, &face)) {
 +            // TODO handle this error
 +        }
 +        fonts.emplace(file, face);
 +    }
 +
 +    auto& face = fonts[file];
 +    FT_Set_Pixel_Sizes(face, 0, size);
 +    fontData.try_emplace(name);
 +
 +    // Calculate dimensions of final texture
 +    //
 +
 +    float width = 0, height = 0;
 +    for (int c = 32; c < 128; c++) {
 +        FT_Load_Char(face, c, FT_LOAD_RENDER);
 +        width += face->glyph->bitmap.width + 1;
 +        height = std::max(height, static_cast<float>(face->glyph->bitmap.rows));
 +    }
 +
 +    // Generate texture to hold entire font
 +    //
 +
 +    auto& font = fontData[name];
 +    glGenTextures(1, &font.tex);
 +    glGenBuffers(1, &font.vbo);
 +    glBindTexture(GL_TEXTURE_2D, font.tex);
 +    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height,
 +                 0, GL_RED, GL_UNSIGNED_BYTE, 0);
 +    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 +    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 +    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 +    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 +    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 +
 +    //    // convert red-on-black to RGBA
 +    //    auto& g = face->glyph;
 +    //    std::vector<uint32_t> buf (g->bitmap.width * g->bitmap.rows, 0xFFFFFF);
 +    //    for (auto j = buf.size(); j--;)
 +    //        buf[j] |= g->bitmap.buffer[j] << 24;
 +
 +    // Load each character and add it to the texture
 +    //
 +
 +    float offsetX = 0, offsetY = 0;
 +    for (int c = 32; c < 128; c++) {
 +        FT_Load_Char(face, c, FT_LOAD_RENDER);
 +
 +        auto* g = face->glyph;
 +        glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY,
 +                        g->bitmap.width, g->bitmap.rows,
 +                        GL_RED, GL_UNSIGNED_BYTE,
 +                        g->bitmap.buffer);
 +
 +        auto& d = font.data[c - 32];
 +        d.dim = { g->bitmap.width, g->bitmap.rows };
 +        d.bitmap = { g->bitmap_left, g->bitmap_top };
 +        d.advance = { g->advance.x >> 6, g->advance.y >> 6 };
 +
 +        d.offset = { offsetX / width, offsetY / height };
 +        offsetX += g->bitmap.width;
 +        // Keep offsetY at zero?
 +    }
 +
 +    std::cout << "Loaded font: " << file << " (size: " << size << ", tex: "
 +              << font.tex << ")" << std::endl;
 +}
 +
 +void TextSystem::put(const std::string& font,
 +                     float x,
 +                     float y,
 +                     const std::string& text)
 +{
 +    if (fontData.find(font) == fontData.end())
 +        return;
 +
 +    fontData[font].text.emplace_back(text, x, y, -9.0f);
 +    shouldUpdateVBOs = true;
 +}
 +
 +void TextSystem::updateVBOs(void)
 +{
 +    for (auto& data : fontData) {
 +        auto& d = data.second;
 +        d.buffer.clear();
 +        for (auto& text : d.text) {
++            float cOff = 0.0f;
 +            for (char c : text.text) {
 +                if (c < 32)
 +                    continue;
 +
 +                d.buffer += {
++                    text.x+cOff,
++                    text.y,
++                    text.z,
++                    d.data[c].offset.first,
++                    d.data[c].offset.second+d.data[c].dim.second,
 +                    1.0f
 +                };
++                d.buffer += {
++                    text.x+cOff+d.data[c].dim.first,
++                    text.y,
++                    text.z,
++                    d.data[c].offset.first+d.data[c].dim.first, 
++                    d.data[c].offset.second+d.data[c].dim.second,
++                    1.0f
++                };
++                d.buffer += {
++                    text.x+cOff,
++                    text.y+d.data[c].dim.second,
++                    text.z,
++                    d.data[c].offset.first, 
++                    d.data[c].offset.second,
++                    1.0f
++                };
++
++                d.buffer += {
++                    text.x+cOff+d.data[c].dim.first,
++                    text.y,
++                    text.z,
++                    d.data[c].offset.first+d.data[c].dim.first, 
++                    d.data[c].offset.second+d.data[c].dim.second,
++                    1.0f
++                };
++                d.buffer += {
++                    text.x+cOff+d.data[c].dim.first,
++                    text.y+d.data[c].dim.second,
++                    text.z,
++                    d.data[c].offset.first+d.data[c].dim.first, 
++                    d.data[c].offset.second,
++                    1.0f
++                };
++                d.buffer += {
++                    text.x+cOff,
++                    text.y+d.data[c].dim.second,
++                    text.z,
++                    d.data[c].offset.first+d.data[c].dim.first, 
++                    d.data[c].offset.second,
++                    1.0f
++                };
++
++                cOff += d.data[c].dim.first + d.data[c].advance.first;
 +            }
 +        }
 +
 +        glBindBuffer(GL_ARRAY_BUFFER, d.vbo);
 +        glBufferData(GL_ARRAY_BUFFER,
 +                     d.text.size() * sizeof(TextMeshData), d.text.data(),
 +                     GL_STREAM_DRAW);
 +    }
 +}
 +
diff --cc src/world.cpp
index 93cf51121b6155b4b95254d0bf31d59a533f0072,c20ce1711e1c4d628bf091e3c3f62badc7ce4869..fb7870d676268ab5b2bf2334d552bef5aaff172c
@@@ -230,7 -229,7 +230,6 @@@ void WorldSystem::update([[maybe_unused
      if (currentWorld == nullptr) {
          currentWorld = &(worlds.front());
          events.emit<WorldChangeEvent>(currentWorld);
--        std::cout << "Emitted" << std::endl;
      }
  
      if (currentWorld->meshUpdated) {