rev |
line source |
paulo@0
|
1 /*
|
paulo@0
|
2 Variable width font drawing library for DS (and GBA)
|
paulo@0
|
3
|
paulo@0
|
4 Copyright 2007-2008 Damian Yerrick <pinoandchester@pineight.com>
|
paulo@0
|
5
|
paulo@0
|
6 This work is provided 'as-is', without any express or implied
|
paulo@0
|
7 warranty. In no event will the authors be held liable for any
|
paulo@0
|
8 damages arising from the use of this work.
|
paulo@0
|
9
|
paulo@0
|
10 Permission is granted to anyone to use this work for any purpose,
|
paulo@0
|
11 including commercial applications, and to alter it and redistribute
|
paulo@0
|
12 it freely, subject to the following restrictions:
|
paulo@0
|
13
|
paulo@0
|
14 1. The origin of this work must not be misrepresented; you must
|
paulo@0
|
15 not claim that you wrote the original work. If you use
|
paulo@0
|
16 this work in a product, an acknowledgment in the product
|
paulo@0
|
17 documentation would be appreciated but is not required.
|
paulo@0
|
18 2. Altered source versions must be plainly marked as such, and must
|
paulo@0
|
19 not be misrepresented as being the original work.
|
paulo@0
|
20 3. This notice may not be removed or altered from any source
|
paulo@0
|
21 distribution.
|
paulo@0
|
22
|
paulo@0
|
23 "Source" is the preferred form of a work for making changes to it.
|
paulo@0
|
24
|
paulo@0
|
25 */
|
paulo@0
|
26
|
paulo@0
|
27 #include <string.h>
|
paulo@0
|
28 #include <stdio.h>
|
paulo@0
|
29 #include "fontdraw.h"
|
paulo@0
|
30
|
paulo@0
|
31
|
paulo@0
|
32 extern const unsigned char vwfont_bin[];
|
paulo@0
|
33
|
paulo@0
|
34 typedef struct GlyphRec {
|
paulo@0
|
35 unsigned short dataOffset;
|
paulo@0
|
36 unsigned char glyphWidth;
|
paulo@0
|
37 unsigned char reserved;
|
paulo@0
|
38 } GlyphRec;
|
paulo@0
|
39
|
paulo@0
|
40 #ifndef FONTDRAW_SPLIT_COMPILE
|
paulo@0
|
41 #include "fontdraw_engine.c"
|
paulo@0
|
42 #else
|
paulo@0
|
43 __attribute__((long_call))
|
paulo@0
|
44 unsigned int fontdraw_putchar(u32 *dst, unsigned int colStride, int wid, int x, int glyph);
|
paulo@0
|
45 __attribute__((long_call))
|
paulo@0
|
46 void vwfRectfillColumn(u32 *dst, unsigned int colStride,
|
paulo@0
|
47 unsigned int l, unsigned int t,
|
paulo@0
|
48 unsigned int r, unsigned int b,
|
paulo@0
|
49 unsigned int c);
|
paulo@0
|
50 #endif
|
paulo@0
|
51
|
paulo@0
|
52
|
paulo@0
|
53 unsigned int fontdraw_charWidth(int glyph) {
|
paulo@0
|
54 glyph &= 0xFF;
|
paulo@0
|
55 if (glyph < vwfont_bin[1]) {
|
paulo@0
|
56 return 0;
|
paulo@0
|
57 }
|
paulo@0
|
58 glyph -= vwfont_bin[1];
|
paulo@0
|
59 if (vwfont_bin[2] != 0 && glyph >= vwfont_bin[2]) {
|
paulo@0
|
60 return 0;
|
paulo@0
|
61 }
|
paulo@0
|
62 const GlyphRec *glyphRec =
|
paulo@0
|
63 ((const GlyphRec *)(vwfont_bin + vwfont_bin[0])) + glyph;
|
paulo@0
|
64 return glyphRec->glyphWidth;
|
paulo@0
|
65 }
|
paulo@0
|
66
|
paulo@0
|
67 unsigned int fontdraw_strWidth(const char *s) {
|
paulo@0
|
68 unsigned int width = 0;
|
paulo@0
|
69 for (; *s; ++s) {
|
paulo@0
|
70 width += fontdraw_charWidth(*s);
|
paulo@0
|
71 }
|
paulo@0
|
72 return width;
|
paulo@0
|
73 }
|
paulo@0
|
74
|
paulo@0
|
75 size_t fontdraw_cutStr(const char *s, int targetWidth) {
|
paulo@0
|
76 size_t len;
|
paulo@0
|
77 for (len = 0; s[len]; ++len) {
|
paulo@0
|
78 int charWidth = fontdraw_charWidth(s[len]);
|
paulo@0
|
79 if (charWidth > targetWidth) {
|
paulo@0
|
80 return len;
|
paulo@0
|
81 }
|
paulo@0
|
82 targetWidth -= charWidth;
|
paulo@0
|
83 }
|
paulo@0
|
84 return len;
|
paulo@0
|
85 }
|
paulo@0
|
86
|
paulo@0
|
87 static unsigned int fontdraw_putline(u32 *dst, unsigned int colStride, int wid, int x, const char *src) {
|
paulo@0
|
88 unsigned int startX = x;
|
paulo@0
|
89 for (int c = *src; c != 0 && wid > 0; c = *++src) {
|
paulo@0
|
90 int chWidth = fontdraw_putchar(dst, colStride, wid, x, c & 0xFF);
|
paulo@0
|
91 x += chWidth;
|
paulo@0
|
92 wid -= chWidth;
|
paulo@0
|
93 }
|
paulo@0
|
94 return x - startX;
|
paulo@0
|
95 }
|
paulo@0
|
96
|
paulo@0
|
97 #ifdef ARM9
|
paulo@0
|
98 const VWFWindow vwfTop = {
|
paulo@0
|
99 .left = 0, .top = 0, .width = 32, .height = 24,
|
paulo@0
|
100 .chrBase = (u32 *)BG_TILE_RAM(0),
|
paulo@0
|
101 .map = 31,
|
paulo@0
|
102 .core = 0,
|
paulo@0
|
103 .mapTileBase = 0
|
paulo@0
|
104 };
|
paulo@0
|
105
|
paulo@0
|
106 const VWFWindow vwfTouch = {
|
paulo@0
|
107 .left = 0, .top = 0, .width = 32, .height = 24,
|
paulo@0
|
108 .chrBase = (u32 *)BG_TILE_RAM_SUB(0),
|
paulo@0
|
109 .map = 31,
|
paulo@0
|
110 .core = 1,
|
paulo@0
|
111 .mapTileBase = 0
|
paulo@0
|
112 };
|
paulo@0
|
113 #else
|
paulo@0
|
114 const VWFWindow vwfTop = {
|
paulo@0
|
115 .left = 0, .top = 0, .width = 30, .height = 20,
|
paulo@0
|
116 .chrBase = (u32 *)PATRAM4(0, 0),
|
paulo@0
|
117 .map = 31,
|
paulo@0
|
118 .core = 0,
|
paulo@0
|
119 .mapTileBase = 0
|
paulo@0
|
120 };
|
paulo@0
|
121 #endif
|
paulo@0
|
122
|
paulo@0
|
123 void vwfRectfill(const VWFWindow *v, int l, int t, int r, int b, int c)
|
paulo@0
|
124 {
|
paulo@0
|
125 u32 *dst = v->chrBase;
|
paulo@0
|
126 c &= 0x0000000F;
|
paulo@0
|
127 c |= c << 4;
|
paulo@0
|
128 c |= c << 8;
|
paulo@0
|
129 c |= c << 16;
|
paulo@0
|
130
|
paulo@0
|
131 unsigned int x = l;
|
paulo@0
|
132 unsigned int stride = v->height * 8;
|
paulo@0
|
133 u32 *tile = dst + stride * (l >> 3);
|
paulo@0
|
134
|
paulo@0
|
135 if (t < 0) {
|
paulo@0
|
136 t = 0;
|
paulo@0
|
137 }
|
paulo@0
|
138 if (b > v->height * 8) {
|
paulo@0
|
139 b = v->height * 8;
|
paulo@0
|
140 }
|
paulo@0
|
141
|
paulo@0
|
142 for(x = l; x < r; x = (x + 8) & -8) {
|
paulo@0
|
143 vwfRectfillColumn(tile, stride, x & 7, t,
|
paulo@0
|
144 (r & -8) > (x & -8) ? 8 : (r & 7),
|
paulo@0
|
145 b, c);
|
paulo@0
|
146 tile += stride;
|
paulo@0
|
147 }
|
paulo@0
|
148 }
|
paulo@0
|
149
|
paulo@0
|
150 void vwfHline(const VWFWindow *v, int l, int t, int r, int c) {
|
paulo@0
|
151 if (r < l) {
|
paulo@0
|
152 int temp = l;
|
paulo@0
|
153 l = r;
|
paulo@0
|
154 r = temp;
|
paulo@0
|
155 }
|
paulo@0
|
156 vwfRectfill(v, l, t, r, t + 1, c);
|
paulo@0
|
157 }
|
paulo@0
|
158
|
paulo@0
|
159 void vwfVline(const VWFWindow *v, int l, int t, int b, int c) {
|
paulo@0
|
160 if (b < t) {
|
paulo@0
|
161 int temp = t;
|
paulo@0
|
162 t = b;
|
paulo@0
|
163 b = temp;
|
paulo@0
|
164 }
|
paulo@0
|
165 vwfRectfill(v, l, t, l + 1, b, c);
|
paulo@0
|
166 }
|
paulo@0
|
167
|
paulo@0
|
168 void vwfRect(const VWFWindow *v, int l, int t, int r, int b, int c) {
|
paulo@0
|
169 vwfVline(v, l, t, b, c);
|
paulo@0
|
170 vwfVline(v, r - 1, t, b, c);
|
paulo@0
|
171 vwfHline(v, l, t, r, c);
|
paulo@0
|
172 vwfHline(v, l, b - 1, r, c);
|
paulo@0
|
173 }
|
paulo@0
|
174
|
paulo@0
|
175 void vwfWinClear(const VWFWindow *w) {
|
paulo@0
|
176 size_t nBytes = 32 * w->width * w->height;
|
paulo@0
|
177 memset(w->chrBase, 0, nBytes);
|
paulo@0
|
178 }
|
paulo@0
|
179
|
paulo@0
|
180 static inline NAMETABLE *vwfGetMapBase(int core, int map) {
|
paulo@0
|
181 #if ARM9
|
paulo@0
|
182 NAMETABLE *dst = core ? &(MAP_SUB[map]) : &(MAP[map]);
|
paulo@0
|
183 #else
|
paulo@0
|
184 NAMETABLE *dst = &(MAP[map]);
|
paulo@0
|
185 #endif
|
paulo@0
|
186
|
paulo@0
|
187 return dst;
|
paulo@0
|
188 }
|
paulo@0
|
189
|
paulo@0
|
190 void vwfPutMap(const VWFWindow *w,
|
paulo@0
|
191 int l, int t, int r, int b,
|
paulo@0
|
192 unsigned int orMask) {
|
paulo@0
|
193
|
paulo@0
|
194 if (r > (int)w->width) {
|
paulo@0
|
195 r = (int)w->width;
|
paulo@0
|
196 }
|
paulo@0
|
197 if (l < 0) {
|
paulo@0
|
198 l = 0;
|
paulo@0
|
199 }
|
paulo@0
|
200 if (r <= l) {
|
paulo@0
|
201 return;
|
paulo@0
|
202 }
|
paulo@0
|
203
|
paulo@0
|
204 if (b > (int)w->height) {
|
paulo@0
|
205 b = (int)w->height;
|
paulo@0
|
206 }
|
paulo@0
|
207 if (t < 0) {
|
paulo@0
|
208 t = 0;
|
paulo@0
|
209 }
|
paulo@0
|
210 if (b <= t) {
|
paulo@0
|
211 return;
|
paulo@0
|
212 }
|
paulo@0
|
213
|
paulo@0
|
214 NAMETABLE *dst = vwfGetMapBase(w->core, w->map);
|
paulo@0
|
215
|
paulo@0
|
216 int mapTile = (w->mapTileBase + w->height * l + t) | orMask;
|
paulo@0
|
217 for (int x = w->left + l; x < w->left + r; ++x) {
|
paulo@0
|
218 for (int y = w->top + t; y < w->top + b; ++y) {
|
paulo@0
|
219 (*dst)[y][x] = mapTile++;
|
paulo@0
|
220 }
|
paulo@0
|
221 mapTile += w->height + t - b;
|
paulo@0
|
222 }
|
paulo@0
|
223 }
|
paulo@0
|
224
|
paulo@0
|
225 void vwfWinInit(const VWFWindow *w) {
|
paulo@0
|
226 vwfWinClear(w);
|
paulo@0
|
227 vwfPutMap(w, 0, 0, w->width, w->height, 0x0000);
|
paulo@0
|
228 }
|
paulo@0
|
229
|
paulo@0
|
230 #if 0
|
paulo@0
|
231 void vwfWinInit(const VWFWindow *w) {
|
paulo@0
|
232 #if ARM9
|
paulo@0
|
233 NAMETABLE *dst = w->core ? &(MAP_SUB[w->map]) : &(MAP[w->map]);
|
paulo@0
|
234 #else
|
paulo@0
|
235 NAMETABLE *dst = &(MAP[w->map]);
|
paulo@0
|
236 #endif
|
paulo@0
|
237
|
paulo@0
|
238 int mapTile = w->mapTileBase;
|
paulo@0
|
239 for (int x = w->left; x < w->left + w->width; ++x) {
|
paulo@0
|
240 for (int y = w->top; y < w->top + w->height; ++y) {
|
paulo@0
|
241 (*dst)[y][x] = mapTile++;
|
paulo@0
|
242 }
|
paulo@0
|
243 }
|
paulo@0
|
244 vwfWinClear(w);
|
paulo@0
|
245 }
|
paulo@0
|
246 #endif
|
paulo@0
|
247
|
paulo@0
|
248 unsigned int vwfPuts(const VWFWindow *w,
|
paulo@0
|
249 const char *str,
|
paulo@0
|
250 int x, int y) {
|
paulo@0
|
251 return fontdraw_putline(w->chrBase + y, 8 * w->height,
|
paulo@0
|
252 w->width * 8 - x, x, str);
|
paulo@0
|
253 }
|
paulo@0
|
254
|
paulo@0
|
255 unsigned int vwfPutc(const VWFWindow *w,
|
paulo@0
|
256 int c,
|
paulo@0
|
257 int x, int y) {
|
paulo@0
|
258 int width = 8 * w->width - x;
|
paulo@0
|
259 if (width >= fontdraw_charWidth(c)) {
|
paulo@0
|
260 return fontdraw_putchar(w->chrBase + y, 8 * w->height,
|
paulo@0
|
261 w->width * 8 - x, x, c & 0xFF);
|
paulo@0
|
262 } else {
|
paulo@0
|
263 return 0;
|
paulo@0
|
264 }
|
paulo@0
|
265 }
|
paulo@0
|
266
|
paulo@0
|
267 // old api emulation
|
paulo@0
|
268
|
paulo@0
|
269 #if 0
|
paulo@0
|
270 void fontdraw_demo_putline(int x, int y, const char *str) {
|
paulo@0
|
271 const VWFWindow *w = &vwfTop;
|
paulo@0
|
272 #if ARM9
|
paulo@0
|
273 if (y >= 288) {
|
paulo@0
|
274 w = &vwfTouch;
|
paulo@0
|
275 y -= 288;
|
paulo@0
|
276 }
|
paulo@0
|
277 #endif
|
paulo@0
|
278 vwfPuts(w, str, x, y);
|
paulo@0
|
279 }
|
paulo@0
|
280 #endif
|
paulo@0
|
281
|
paulo@0
|
282 void fontdraw_setupVRAM(int sub) {
|
paulo@0
|
283 #if ARM9
|
paulo@0
|
284 const VWFWindow *w = sub ? &vwfTouch : &vwfTop;
|
paulo@0
|
285 #else
|
paulo@0
|
286 const VWFWindow *w = &vwfTop;
|
paulo@0
|
287 #endif
|
paulo@0
|
288
|
paulo@0
|
289 #if ARM9
|
paulo@0
|
290 if (sub == 0) {
|
paulo@0
|
291 BGCTRL_SUB[0] = BG_MAP_BASE(31) | BG_TILE_BASE(0);
|
paulo@0
|
292 BG_OFFSET_SUB[0].x = 0;
|
paulo@0
|
293 BG_OFFSET_SUB[0].y = 0;
|
paulo@0
|
294 } else
|
paulo@0
|
295 #endif
|
paulo@0
|
296 {
|
paulo@0
|
297 BGCTRL[0] = BG_MAP_BASE(31) | BG_TILE_BASE(0);
|
paulo@0
|
298 BG_OFFSET[0].x = 0;
|
paulo@0
|
299 BG_OFFSET[0].y = 0;
|
paulo@0
|
300 }
|
paulo@0
|
301
|
paulo@0
|
302 vwfWinInit(w);
|
paulo@0
|
303 }
|
paulo@0
|
304
|
paulo@0
|
305 void fontdraw_cls(int sub) {
|
paulo@0
|
306 #if ARM9
|
paulo@0
|
307 vwfWinClear(sub ? &vwfTouch : &vwfTop);
|
paulo@0
|
308 #else
|
paulo@0
|
309 vwfWinClear(&vwfTop);
|
paulo@0
|
310 #endif
|
paulo@0
|
311 }
|
paulo@0
|
312
|
paulo@0
|
313 void vwfBlitAligned(const VWFWindow *src, const VWFWindow *dst,
|
paulo@0
|
314 int srcX, int srcY, int dstX, int dstY,
|
paulo@0
|
315 int w, int h) {
|
paulo@0
|
316
|
paulo@0
|
317 /* Clip in X */
|
paulo@0
|
318 if (srcX < 0) {
|
paulo@0
|
319 dstX -= srcX;
|
paulo@0
|
320 w -= srcX;
|
paulo@0
|
321 srcX = 0;
|
paulo@0
|
322 }
|
paulo@0
|
323 if (dstX < 0) {
|
paulo@0
|
324 srcX -= dstX;
|
paulo@0
|
325 w -= dstX;
|
paulo@0
|
326 dstX = 0;
|
paulo@0
|
327 }
|
paulo@0
|
328 if (srcX + w > (int)src->width) {
|
paulo@0
|
329 w = src->width - srcX;
|
paulo@0
|
330 }
|
paulo@0
|
331 if (dstX + w > (int)dst->width) {
|
paulo@0
|
332 w = dst->width - dstX;
|
paulo@0
|
333 }
|
paulo@0
|
334 if (w <= 0) {
|
paulo@0
|
335 return;
|
paulo@0
|
336 }
|
paulo@0
|
337
|
paulo@0
|
338 /* Clip in Y */
|
paulo@0
|
339 if (srcY < 0) {
|
paulo@0
|
340 dstY -= srcY;
|
paulo@0
|
341 h -= srcY;
|
paulo@0
|
342 srcY = 0;
|
paulo@0
|
343 }
|
paulo@0
|
344 if (dstY < 0) {
|
paulo@0
|
345 srcY -= dstY;
|
paulo@0
|
346 h -= dstY;
|
paulo@0
|
347 dstY = 0;
|
paulo@0
|
348 }
|
paulo@0
|
349 if (srcY + h > src->height * 8) {
|
paulo@0
|
350 h = src->height * 8 - srcY;
|
paulo@0
|
351 }
|
paulo@0
|
352 if (dstX + w > dst->height * 8) {
|
paulo@0
|
353 h = dst->height * 8 - dstY;
|
paulo@0
|
354 }
|
paulo@0
|
355 if (h < 0) {
|
paulo@0
|
356 return;
|
paulo@0
|
357 }
|
paulo@0
|
358
|
paulo@0
|
359 {
|
paulo@0
|
360 const u32 *srcCol = src->chrBase + srcX * src->height * 8 + srcY;
|
paulo@0
|
361 u32 *dstCol = dst->chrBase + dstX * dst->height * 8 + dstY;
|
paulo@0
|
362
|
paulo@0
|
363 for (; w > 0; --w) {
|
paulo@0
|
364 for (unsigned int y = 0; y < h; ++y) {
|
paulo@0
|
365 dstCol[y] = srcCol[y];
|
paulo@0
|
366 }
|
paulo@0
|
367 srcCol += src->height * 8;
|
paulo@0
|
368 dstCol += dst->height * 8;
|
paulo@0
|
369 }
|
paulo@0
|
370 }
|
paulo@0
|
371
|
paulo@0
|
372 }
|