-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbdf-font.cc
127 lines (116 loc) · 4.1 KB
/
bdf-font.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
// Copyright (C) 2014 Henner Zeller <[email protected]>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://gnu.org/licenses/gpl-2.0.txt>
#include "graphics.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// The little question-mark box "�" for unknown code.
static const uint32_t kUnicodeReplacementCodepoint = 0xFFFD;
// Bitmap for one row. This limits the number of available columns.
// Make wider if running into trouble.
typedef uint32_t rowbitmap_t;
namespace rgb_matrix {
struct Font::Glyph {
int width, height;
int y_offset;
rowbitmap_t bitmap[0]; // contains 'height' elements.
};
Font::Font() : font_height_(-1) {}
Font::~Font() {
for (CodepointGlyphMap::iterator it = glyphs_.begin();
it != glyphs_.end(); ++it) {
free(it->second);
}
}
// TODO: that might not be working for all input files yet.
bool Font::LoadFont(const char *path) {
if (!path || !*path) return false;
FILE *f = fopen(path, "r");
if (f == NULL)
return false;
uint32_t codepoint;
char buffer[1024];
int dummy;
Glyph tmp;
Glyph *current_glyph = NULL;
int row = 0;
int x_offset = 0;
int bitmap_shift = 0;
while (fgets(buffer, sizeof(buffer), f)) {
if (sscanf(buffer, "FONTBOUNDINGBOX %d %d %d %d",
&dummy, &font_height_, &dummy, &base_line_) == 4) {
base_line_ += font_height_;
}
else if (sscanf(buffer, "ENCODING %ud", &codepoint) == 1) {
// parsed.
}
else if (sscanf(buffer, "BBX %d %d %d %d", &tmp.width, &tmp.height,
&x_offset, &tmp.y_offset) == 4) {
current_glyph = (Glyph*) malloc(sizeof(Glyph)
+ tmp.height * sizeof(rowbitmap_t));
*current_glyph = tmp;
// We only get number of bytes large enough holding our width. We want
// it always left-aligned.
bitmap_shift =
8 * (sizeof(rowbitmap_t) - ((current_glyph->width + 7) / 8)) + x_offset;
row = -1; // let's not start yet, wait for BITMAP
}
else if (strncmp(buffer, "BITMAP", strlen("BITMAP")) == 0) {
row = 0;
}
else if (current_glyph && row >= 0 && row < current_glyph->height
&& (sscanf(buffer, "%x", ¤t_glyph->bitmap[row]) == 1)) {
current_glyph->bitmap[row] <<= bitmap_shift;
row++;
}
else if (strncmp(buffer, "ENDCHAR", strlen("ENDCHAR")) == 0) {
if (current_glyph && row == current_glyph->height) {
free(glyphs_[codepoint]); // just in case there was one.
glyphs_[codepoint] = current_glyph;
current_glyph = NULL;
}
}
}
fclose(f);
return true;
}
const Font::Glyph *Font::FindGlyph(uint32_t unicode_codepoint) const {
CodepointGlyphMap::const_iterator found = glyphs_.find(unicode_codepoint);
if (found == glyphs_.end())
return NULL;
return found->second;
}
int Font::CharacterWidth(uint32_t unicode_codepoint) const {
const Glyph *g = FindGlyph(unicode_codepoint);
return g ? g->width : -1;
}
int Font::DrawGlyph(Canvas *c, int x_pos, int y_pos, const Color &color,
uint32_t unicode_codepoint) const {
const Glyph *g = FindGlyph(unicode_codepoint);
if (g == NULL) g = FindGlyph(kUnicodeReplacementCodepoint);
if (g == NULL) return 0;
y_pos = y_pos - g->height - g->y_offset;
for (int y = 0; y < g->height; ++y) {
const rowbitmap_t row = g->bitmap[y];
rowbitmap_t x_mask = 0x80000000;
for (int x = 0; x < g->width; ++x, x_mask >>= 1) {
if (row & x_mask) {
c->SetPixel(x_pos + x, y_pos + y, color.r, color.g, color.b);
}
}
}
return g->width;
}
} // namespace rgb_matrix