]> git.tdb.fi Git - libs/gl.git/blob - source/builders/font.cpp
Avoid generating invalid interfaces in geometry shader
[libs/gl.git] / source / builders / font.cpp
1 #include <msp/core/maputils.h>
2 #include <msp/datafile/collection.h>
3 #include "bindable.h"
4 #include "gl.h"
5 #include "font.h"
6 #include "primitivebuilder.h"
7 #include "texture2d.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace GL {
13
14 Font::Font():
15         native_size(1),
16         ascent(1),
17         descent(0),
18         cap_height(1),
19         x_height(0.5)
20 { }
21
22 // Avoid synthesizing ~RefPtr in files including font.h
23 Font::~Font()
24 { }
25
26 void Font::set_texture(const Texture2D &t)
27 {
28         texture = &t;
29         texture.keep();
30 }
31
32 const Texture2D &Font::get_texture() const
33 {
34         if(!texture)
35                 throw logic_error("No texture");
36         return *texture;
37 }
38
39 void Font::add_glyph(const Glyph &g)
40 {
41         insert_unique(glyphs, g.code, g);
42 }
43
44 void Font::set_kerning(unsigned l, unsigned r, float d)
45 {
46         kerning[CodePair(l, r)] = d;
47 }
48
49 float Font::get_string_width(const string &str, StringCodec::Decoder &dec) const
50 {
51         float x = 0;
52
53         unsigned prev = 0;
54         for(string::const_iterator i=str.begin(); i!=str.end();)
55         {
56                 unsigned c = dec.decode_char(str, i);
57                 if(prev)
58                         x += get_glyph_advance(prev, c);
59                 prev = c;
60         }
61         x += get_glyph_advance(prev);
62
63         return x;
64 }
65
66 void Font::build_string(const string &str, StringCodec::Decoder &dec, PrimitiveBuilder &bld) const
67 {
68         VertexBuilder::PushMatrix push_mtx(bld);
69
70         unsigned prev = 0;
71         unsigned next = 0;
72         for(string::const_iterator i=str.begin(); (next || i!=str.end());)
73         {
74                 unsigned c = (next ? next : dec.decode_char(str, i));
75                 next = (i!=str.end() ? dec.decode_char(str, i) : 0);
76
77                 if(unsigned lig = get_ligature(c, next))
78                 {
79                         c = lig;
80                         next = 0;
81                 }
82
83                 GlyphMap::const_iterator j = glyphs.find(c);
84                 if(j==glyphs.end())
85                         continue;
86
87                 if(prev)
88                         bld.transform(Matrix::translation(get_glyph_advance(prev, c), 0, 0));
89
90                 create_glyph_quad(j->second, bld);
91                 prev = c;
92         }
93 }
94
95 void Font::create_glyph_quad(const Glyph &glyph, PrimitiveBuilder &bld) const
96 {
97         bld.begin(TRIANGLE_STRIP);
98         bld.texcoord(glyph.x1, glyph.y2);
99         bld.vertex(glyph.off_x, glyph.off_y+glyph.h);
100         bld.texcoord(glyph.x1, glyph.y1);
101         bld.vertex(glyph.off_x, glyph.off_y);
102         bld.texcoord(glyph.x2, glyph.y2);
103         bld.vertex(glyph.off_x+glyph.w, glyph.off_y+glyph.h);
104         bld.texcoord(glyph.x2, glyph.y1);
105         bld.vertex(glyph.off_x+glyph.w, glyph.off_y);
106         bld.end();
107 }
108
109 float Font::get_glyph_advance(unsigned code, unsigned next) const
110 {
111         GlyphMap::const_iterator i = glyphs.find(code);
112         if(i==glyphs.end())
113                 return 0;
114
115         float advance = i->second.advance;
116
117         if(next)
118         {
119                 KerningMap::const_iterator j = kerning.find(CodePair(code, next));
120                 if(j!=kerning.end())
121                         advance += j->second;
122         }
123
124         return advance;
125 }
126
127 unsigned Font::get_ligature(unsigned code, unsigned next) const
128 {
129         LigatureMap::const_iterator i = ligatures.find(CodePair(code, next));
130         return (i!=ligatures.end() ? i->second : 0);
131 }
132
133
134 Font::Glyph::Glyph():
135         code(0),
136         x1(0),
137         y1(0),
138         x2(1),
139         y2(1),
140         w(1),
141         h(1),
142         off_x(0),
143         off_y(0),
144         advance(1)
145 { }
146
147
148 Font::Loader::Loader(Font &f):
149         DataFile::CollectionObjectLoader<Font>(f, 0)
150 {
151         init();
152 }
153
154 Font::Loader::Loader(Font &f, Collection &c):
155         DataFile::CollectionObjectLoader<Font>(f, &c)
156 {
157         init();
158 }
159
160 void Font::Loader::init()
161 {
162         add("native_size", &Font::native_size);
163         add("ascent",      &Font::ascent);
164         add("cap_height",  &Font::cap_height);
165         add("descent",     &Font::descent);
166         add("texture",     &Loader::texture);
167         add("texture",     &Loader::texture_ref);
168         add("glyph",       &Loader::glyph);
169         add("kerning",     &Loader::kerning);
170         add("ligature",    &Loader::ligature);
171         add("x_height",    &Font::x_height);
172 }
173
174 void Font::Loader::glyph(unsigned c)
175 {
176         Glyph gl;
177         gl.code = c;
178         load_sub(gl);
179         obj.glyphs.insert(GlyphMap::value_type(c, gl));
180 }
181
182 void Font::Loader::kerning(unsigned l, unsigned r, float d)
183 {
184         obj.kerning[CodePair(l, r)] = d;
185 }
186
187 void Font::Loader::ligature(unsigned l, unsigned r, unsigned g)
188 {
189         obj.ligatures[CodePair(l, r)] = g;
190 }
191
192 void Font::Loader::texture()
193 {
194         RefPtr<Texture2D> tex = new Texture2D;
195         load_sub(*tex);
196         obj.texture = tex;
197 }
198
199 void Font::Loader::texture_ref(const string &name)
200 {
201         obj.texture = &get_collection().get<Texture2D>(name);
202         obj.texture.keep();
203 }
204
205
206 Font::Glyph::Loader::Loader(Glyph &g):
207         DataFile::ObjectLoader<Glyph>(g)
208 {
209         add("texcoords", &Loader::texcoords);
210         add("size",      &Glyph::w,     &Glyph::h);
211         add("offset",    &Glyph::off_x, &Glyph::off_y);
212         add("advance",   &Glyph::advance);
213 }
214
215 void Font::Glyph::Loader::texcoords(float x1_, float y1_, float x2_, float y2_)
216 {
217         obj.x1 = x1_;
218         obj.y1 = y1_;
219         obj.x2 = x2_;
220         obj.y2 = y2_;
221 }
222
223 } // namespace GL
224 } // namespace Msp