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