]> git.tdb.fi Git - libs/gl.git/commitdiff
Add a class for easier text rendering
authorMikko Rasa <tdb@tdb.fi>
Wed, 15 Jul 2015 20:36:54 +0000 (23:36 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 15 Jul 2015 20:36:54 +0000 (23:36 +0300)
I've written the equivalent in various applications a few times, so might
as well put it here.

source/text.cpp [new file with mode: 0644]
source/text.h [new file with mode: 0644]

diff --git a/source/text.cpp b/source/text.cpp
new file mode 100644 (file)
index 0000000..e3a8540
--- /dev/null
@@ -0,0 +1,95 @@
+#include "meshbuilder.h"
+#include "text.h"
+#include "texture2d.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Text::Text(const Font &f, const Technique *tech):
+       font(f),
+       mesh((TEXCOORD2, VERTEX2)),
+       horz_align(0.0f),
+       vert_offset(0.0f)
+{
+       object.set_mesh(&mesh);
+       if(tech)
+               set_technique(tech);
+}
+
+void Text::set_technique(const Technique *tech)
+{
+       if(tech)
+       {
+               technique = *tech;
+               technique.replace_texture("diffusemap", font.get_texture());
+               object.set_technique(&technique);
+       }
+       else
+               object.set_technique(0);
+}
+
+void Text::set_text(const string &text, StringCodec::Decoder &dec)
+{
+       clear();
+       width = font.get_string_width(text, dec);
+       GL::MeshBuilder bld(mesh);
+       bld.matrix() *= Matrix::translation(Vector3(-horz_align*width, vert_offset, 0.0f));
+       font.build_string(text, dec, bld);
+}
+
+void Text::clear()
+{
+       mesh.clear();
+       width = 0;
+}
+
+void Text::set_alignment(HorizontalAlign ha, VerticalAlign va)
+{
+       float h;
+       switch(ha)
+       {
+       case LEFT: h = 0.0f; break;
+       case CENTER: h = 0.5f; break;
+       case RIGHT: h = 1.0f; break;
+       default: throw invalid_argument("Text::set_alignment");
+       }
+
+       float v;
+       switch(va)
+       {
+       case DESCENT: v = -font.get_descent(); break;
+       case BASELINE: v = 0.0f; break;
+       case MIDLINE: v = font.get_ascent()/2; break;  // XXX Midline should be cap height / 2
+       case ASCENT: v = font.get_ascent(); break;
+       default: throw invalid_argument("Text::set_alignment");
+       }
+
+       set_alignment(h, v);
+}
+
+void Text::set_alignment(float h, float v)
+{
+       float horz_adjust = (horz_align-h)*width;
+       float vert_adjust = -v-vert_offset;
+       horz_align = h;
+       vert_offset = -v;
+
+       unsigned pos_offset = mesh.get_vertices().get_format().offset(VERTEX2);
+       unsigned n_vertices = mesh.get_n_vertices();
+       for(unsigned i=0; i<n_vertices; ++i)
+       {
+               float *pos = mesh.modify_vertex(i)+pos_offset;
+               pos[0] += horz_adjust;
+               pos[1] += vert_adjust;
+       }
+}
+
+void Text::render(Renderer &renderer, const Tag &tag) const
+{
+       object.render(renderer, tag);
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/text.h b/source/text.h
new file mode 100644 (file)
index 0000000..ab1bfe9
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef MSP_GL_TEXT_H_
+#define MSP_GL_TEXT_H_
+
+#include "font.h"
+#include "mesh.h"
+#include "object.h"
+#include "technique.h"
+
+namespace Msp {
+namespace GL {
+
+/**
+Creates an object consisting of the visual representation of a string.  Can be
+used with an ObjectInstance to further customize the appearance.
+*/
+class Text: public Renderable
+{
+public:
+       enum HorizontalAlign
+       {
+               LEFT,
+               CENTER,
+               RIGHT
+       };
+
+       enum VerticalAlign
+       {
+               DESCENT,
+               BASELINE,
+               MIDLINE,
+               ASCENT
+       };
+
+private:
+       const Font &font;
+       Mesh mesh;
+       Object object;
+       Technique technique;
+       float horz_align;
+       float vert_offset;
+       float width;
+
+public:
+       Text(const Font &, const Technique * = 0);
+
+       const Mesh *get_mesh() const { return &mesh; }
+
+       /** Sets technique to render with.  It should have a texture slot named
+       "diffusemap", which will be replaced with the font's texture. */
+       void set_technique(const Technique *);
+
+       const Technique *get_technique() const { return object.get_technique(); }
+
+       /// Sets the string to be displayed.
+       void set_text(const std::string &, StringCodec::Decoder &);
+
+       template<typename C>
+       void set_text(const std::string &t)
+       {
+               typename C::Decoder dec;
+               set_text(t, dec);
+       }
+
+       void set_text(const std::string &t)
+       { set_text<StringCodec::Utf8>(t); }
+
+       /// Clears the object's contents.
+       void clear();
+
+       /// Sets horizontal and vertical alignment with predefined anchors.
+       void set_alignment(HorizontalAlign, VerticalAlign = BASELINE);
+
+       /** Sets horizontal and vertical alignment.  0.0 means left or baseline,
+       1.0 means right or top. */
+       void set_alignment(float, float = 0.0f);
+
+       float get_width() const { return width; }
+
+       virtual void render(Renderer &, const Tag &) const;
+
+       operator const Object &() const { return object; }
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif