Theme Editor: Added support for larger fonts
[kugel-rb.git] / utils / themeeditor / graphics / rbfont.cpp
blob23791497fdfc669fb3d9b57df42fe47814a86d2e
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2010 Robert Bieber
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "rbfont.h"
23 #include "rbfontcache.h"
24 #include "rbtextcache.h"
26 #include <QFont>
27 #include <QBrush>
28 #include <QFile>
29 #include <QPainter>
30 #include <QBitmap>
31 #include <QImage>
32 #include <QSettings>
34 #include <QDebug>
36 quint16 RBFont::maxFontSizeFor16BitOffsets = 0xFFDB;
38 RBFont::RBFont(QString file)
39 : valid(false), imageData(0), offsetData(0), widthData(0)
42 /* Attempting to locate the correct file name */
43 if(!QFile::exists(file))
45 /* Checking in the fonts repository */
46 QSettings settings;
47 settings.beginGroup("RBFont");
49 file = file.split("/").last();
50 file = settings.value("fontDir", "").toString() + "/" + file;
52 settings.endGroup();
54 if(!QFile::exists(file))
55 file = ":/fonts/08-Schumacher-Clean.fnt";
57 header.insert("filename", file);
59 /* Checking for a cache entry */
60 RBFontCache::CacheInfo* cache = RBFontCache::lookup(file);
61 if(cache)
63 imageData = cache->imageData;
64 offsetData = cache->offsetData;
65 widthData = cache->widthData;
66 header = cache->header;
68 return;
71 /* Opening the file */
72 QFile fin(file);
73 fin.open(QFile::ReadOnly);
75 /* Loading the header info */
76 quint8 byte;
77 quint16 word;
78 quint32 dword;
80 QDataStream data(&fin);
81 data.setByteOrder(QDataStream::LittleEndian);
83 /* Grabbing the magic number and version */
84 data >> dword;
85 header.insert("version", dword);
87 /* Max font width */
88 data >> word;
89 header.insert("maxwidth", word);
91 /* Font height */
92 data >> word;
93 header.insert("height", word);
95 /* Ascent */
96 data >> word;
97 header.insert("ascent", word);
99 /* Padding */
100 data >> word;
102 /* First character code */
103 data >> dword;
104 header.insert("firstchar", dword);
106 /* Default character code */
107 data >> dword;
108 header.insert("defaultchar", dword);
110 /* Number of characters */
111 data >> dword;
112 header.insert("size", dword);
114 /* Bytes of imagebits in file */
115 data >> dword;
116 header.insert("nbits", dword);
118 /* Longs (dword) of offset data in file */
119 data >> dword;
120 header.insert("noffset", dword);
122 /* Bytes of width data in file */
123 data >> dword;
124 header.insert("nwidth", dword);
126 /* Loading the image data */
127 imageData = new quint8[header.value("nbits").toInt()];
128 data.readRawData(reinterpret_cast<char*>(imageData),
129 header.value("nbits").toInt());
131 /* Aligning on 16-bit boundary */
132 if(header.value("nbits").toInt() % 2 == 1)
133 data >> byte;
135 /* Loading the offset table if necessary */
136 if(header.value("noffset").toInt() > 0)
138 int bytesToRead;
139 if(header.value("nbits").toInt() > maxFontSizeFor16BitOffsets)
140 bytesToRead = 4 * header.value("noffset").toInt();
141 else
142 bytesToRead = 2 * header.value("noffset").toInt();
143 offsetData = new quint16[bytesToRead];
144 data.readRawData(reinterpret_cast<char*>(offsetData), bytesToRead);
147 /* Loading the width table if necessary */
148 if(header.value("nwidth").toInt() > 0)
150 widthData = new quint8[header.value("nwidth").toInt()];
151 data.readRawData(reinterpret_cast<char*>(widthData),
152 header.value("nwidth").toInt());
155 fin.close();
157 /* Caching the font data */
158 cache = new RBFontCache::CacheInfo;
159 cache->imageData = imageData;
160 cache->offsetData = offsetData;
161 cache->widthData = widthData;
162 cache->header = header;
163 RBFontCache::insert(file, cache);
167 RBFont::~RBFont()
171 RBText* RBFont::renderText(QString text, QColor color, int viewWidth,
172 QGraphicsItem *parent)
175 /* Checking for a cache hit first */
176 QImage* image = RBTextCache::lookup(header.value("filename").toString()
177 + text);
178 if(image)
179 return new RBText(image, viewWidth, parent);
181 int firstChar = header.value("firstchar").toInt();
182 int height = header.value("height").toInt();
183 int maxWidth = header.value("maxwidth").toInt();
185 bool extendedSet = header.value("nbits").
186 toUInt() > maxFontSizeFor16BitOffsets;
188 /* First we determine the width of the combined text */
189 QList<int> widths;
190 for(int i = 0; i < text.length(); i++)
192 if(widthData)
193 widths.append(widthData[text[i].unicode() - firstChar]);
194 else
195 widths.append(maxWidth);
198 int totalWidth = 0;
199 for(int i = 0; i < widths.count(); i++)
200 totalWidth += widths[i];
202 image = new QImage(totalWidth, height, QImage::Format_Indexed8);
204 image->setColor(0, qRgba(0,0,0,0));
205 image->setColor(1, color.rgb());
207 /* Drawing the text */
208 int startX = 0;
209 for(int i = 0; i < text.length(); i++)
211 unsigned int offset;
212 if(offsetData)
214 if(extendedSet)
215 offset = reinterpret_cast<quint32*>(offsetData)[text[i].unicode() - firstChar];
216 else
217 offset = offsetData[text[i].unicode() - firstChar];
219 else
221 offset = (text[i].unicode() - firstChar) * maxWidth;
224 int bytesHigh = height / 8;
225 if(height % 8 > 0)
226 bytesHigh++;
228 int bytes = bytesHigh * widths[i];
230 for(int byte = 0; byte < bytes; byte++)
232 int x = startX + byte % widths[i];
233 int y = byte / widths[i] * 8;
234 quint8 data = imageData[offset];
235 quint8 mask = 0x1;
236 for(int bit = 0; bit < 8; bit++)
238 if(mask & data)
239 image->setPixel(x, y, 1);
240 else
241 image->setPixel(x, y, 0);
243 y++;
244 mask <<= 1;
245 if(y >= height)
246 break;
249 offset++;
252 startX += widths[i];
255 RBTextCache::insert(header.value("filename").toString() + text, image);
256 return new RBText(image, viewWidth, parent);