]> git.tdb.fi Git - libs/gl.git/blob - source/font.cpp
Add functions for setting arrays of 2x2 and 3x3 matrix uniforms
[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         MatrixStack::Push push_mtx(bld.matrix());
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.matrix() *= 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::Loader::Loader(Font &f):
144         DataFile::CollectionObjectLoader<Font>(f, 0)
145 {
146         init();
147 }
148
149 Font::Loader::Loader(Font &f, Collection &c):
150         DataFile::CollectionObjectLoader<Font>(f, &c)
151 {
152         init();
153 }
154
155 void Font::Loader::init()
156 {
157         add("native_size", &Font::native_size);
158         add("ascent",      &Font::ascent);
159         add("cap_height",  &Font::cap_height);
160         add("descent",     &Font::descent);
161         add("texture",     &Loader::texture);
162         add("texture",     &Loader::texture_ref);
163         add("glyph",       &Loader::glyph);
164         add("kerning",     &Loader::kerning);
165         add("ligature",    &Loader::ligature);
166         add("x_height",    &Font::x_height);
167 }
168
169 void Font::Loader::glyph(unsigned c)
170 {
171         Glyph gl;
172         gl.code = c;
173         load_sub(gl);
174         obj.glyphs.insert(GlyphMap::value_type(c, gl));
175 }
176
177 void Font::Loader::kerning(unsigned l, unsigned r, float d)
178 {
179         obj.kerning[CodePair(l, r)] = d;
180 }
181
182 void Font::Loader::ligature(unsigned l, unsigned r, unsigned g)
183 {
184         obj.ligatures[CodePair(l, r)] = g;
185 }
186
187 void Font::Loader::texture()
188 {
189         RefPtr<Texture2D> tex = new Texture2D;
190         load_sub(*tex);
191         obj.texture = tex;
192 }
193
194 void Font::Loader::texture_ref(const string &name)
195 {
196         obj.texture = &get_collection().get<Texture2D>(name);
197         obj.texture.keep();
198 }
199
200
201 Font::Glyph::Loader::Loader(Glyph &g):
202         DataFile::ObjectLoader<Glyph>(g)
203 {
204         add("texcoords", &Loader::texcoords);
205         add("size",      &Glyph::w,     &Glyph::h);
206         add("offset",    &Glyph::off_x, &Glyph::off_y);
207         add("advance",   &Glyph::advance);
208 }
209
210 void Font::Glyph::Loader::texcoords(float x1_, float y1_, float x2_, float y2_)
211 {
212         obj.x1 = x1_;
213         obj.y1 = y1_;
214         obj.x2 = x2_;
215         obj.y2 = y2_;
216 }
217
218 } // namespace GL
219 } // namespace Msp