paulo@0: /* paulo@0: Variable width font drawing library for DS (and GBA) paulo@0: paulo@0: Copyright 2007-2008 Damian Yerrick paulo@0: paulo@0: This work is provided 'as-is', without any express or implied paulo@0: warranty. In no event will the authors be held liable for any paulo@0: damages arising from the use of this work. paulo@0: paulo@0: Permission is granted to anyone to use this work for any purpose, paulo@0: including commercial applications, and to alter it and redistribute paulo@0: it freely, subject to the following restrictions: paulo@0: paulo@0: 1. The origin of this work must not be misrepresented; you must paulo@0: not claim that you wrote the original work. If you use paulo@0: this work in a product, an acknowledgment in the product paulo@0: documentation would be appreciated but is not required. paulo@0: 2. Altered source versions must be plainly marked as such, and must paulo@0: not be misrepresented as being the original work. paulo@0: 3. This notice may not be removed or altered from any source paulo@0: distribution. paulo@0: paulo@0: "Source" is the preferred form of a work for making changes to it. paulo@0: paulo@0: */ paulo@0: paulo@0: #include paulo@0: #include paulo@0: #include "fontdraw.h" paulo@0: paulo@0: paulo@0: extern const unsigned char vwfont_bin[]; paulo@0: paulo@0: typedef struct GlyphRec { paulo@0: unsigned short dataOffset; paulo@0: unsigned char glyphWidth; paulo@0: unsigned char reserved; paulo@0: } GlyphRec; paulo@0: paulo@0: #ifndef FONTDRAW_SPLIT_COMPILE paulo@0: #include "fontdraw_engine.c" paulo@0: #else paulo@0: __attribute__((long_call)) paulo@0: unsigned int fontdraw_putchar(u32 *dst, unsigned int colStride, int wid, int x, int glyph); paulo@0: __attribute__((long_call)) paulo@0: void vwfRectfillColumn(u32 *dst, unsigned int colStride, paulo@0: unsigned int l, unsigned int t, paulo@0: unsigned int r, unsigned int b, paulo@0: unsigned int c); paulo@0: #endif paulo@0: paulo@0: paulo@0: unsigned int fontdraw_charWidth(int glyph) { paulo@0: glyph &= 0xFF; paulo@0: if (glyph < vwfont_bin[1]) { paulo@0: return 0; paulo@0: } paulo@0: glyph -= vwfont_bin[1]; paulo@0: if (vwfont_bin[2] != 0 && glyph >= vwfont_bin[2]) { paulo@0: return 0; paulo@0: } paulo@0: const GlyphRec *glyphRec = paulo@0: ((const GlyphRec *)(vwfont_bin + vwfont_bin[0])) + glyph; paulo@0: return glyphRec->glyphWidth; paulo@0: } paulo@0: paulo@0: unsigned int fontdraw_strWidth(const char *s) { paulo@0: unsigned int width = 0; paulo@0: for (; *s; ++s) { paulo@0: width += fontdraw_charWidth(*s); paulo@0: } paulo@0: return width; paulo@0: } paulo@0: paulo@0: size_t fontdraw_cutStr(const char *s, int targetWidth) { paulo@0: size_t len; paulo@0: for (len = 0; s[len]; ++len) { paulo@0: int charWidth = fontdraw_charWidth(s[len]); paulo@0: if (charWidth > targetWidth) { paulo@0: return len; paulo@0: } paulo@0: targetWidth -= charWidth; paulo@0: } paulo@0: return len; paulo@0: } paulo@0: paulo@0: static unsigned int fontdraw_putline(u32 *dst, unsigned int colStride, int wid, int x, const char *src) { paulo@0: unsigned int startX = x; paulo@0: for (int c = *src; c != 0 && wid > 0; c = *++src) { paulo@0: int chWidth = fontdraw_putchar(dst, colStride, wid, x, c & 0xFF); paulo@0: x += chWidth; paulo@0: wid -= chWidth; paulo@0: } paulo@0: return x - startX; paulo@0: } paulo@0: paulo@0: #ifdef ARM9 paulo@0: const VWFWindow vwfTop = { paulo@0: .left = 0, .top = 0, .width = 32, .height = 24, paulo@0: .chrBase = (u32 *)BG_TILE_RAM(0), paulo@0: .map = 31, paulo@0: .core = 0, paulo@0: .mapTileBase = 0 paulo@0: }; paulo@0: paulo@0: const VWFWindow vwfTouch = { paulo@0: .left = 0, .top = 0, .width = 32, .height = 24, paulo@0: .chrBase = (u32 *)BG_TILE_RAM_SUB(0), paulo@0: .map = 31, paulo@0: .core = 1, paulo@0: .mapTileBase = 0 paulo@0: }; paulo@0: #else paulo@0: const VWFWindow vwfTop = { paulo@0: .left = 0, .top = 0, .width = 30, .height = 20, paulo@0: .chrBase = (u32 *)PATRAM4(0, 0), paulo@0: .map = 31, paulo@0: .core = 0, paulo@0: .mapTileBase = 0 paulo@0: }; paulo@0: #endif paulo@0: paulo@0: void vwfRectfill(const VWFWindow *v, int l, int t, int r, int b, int c) paulo@0: { paulo@0: u32 *dst = v->chrBase; paulo@0: c &= 0x0000000F; paulo@0: c |= c << 4; paulo@0: c |= c << 8; paulo@0: c |= c << 16; paulo@0: paulo@0: unsigned int x = l; paulo@0: unsigned int stride = v->height * 8; paulo@0: u32 *tile = dst + stride * (l >> 3); paulo@0: paulo@0: if (t < 0) { paulo@0: t = 0; paulo@0: } paulo@0: if (b > v->height * 8) { paulo@0: b = v->height * 8; paulo@0: } paulo@0: paulo@0: for(x = l; x < r; x = (x + 8) & -8) { paulo@0: vwfRectfillColumn(tile, stride, x & 7, t, paulo@0: (r & -8) > (x & -8) ? 8 : (r & 7), paulo@0: b, c); paulo@0: tile += stride; paulo@0: } paulo@0: } paulo@0: paulo@0: void vwfHline(const VWFWindow *v, int l, int t, int r, int c) { paulo@0: if (r < l) { paulo@0: int temp = l; paulo@0: l = r; paulo@0: r = temp; paulo@0: } paulo@0: vwfRectfill(v, l, t, r, t + 1, c); paulo@0: } paulo@0: paulo@0: void vwfVline(const VWFWindow *v, int l, int t, int b, int c) { paulo@0: if (b < t) { paulo@0: int temp = t; paulo@0: t = b; paulo@0: b = temp; paulo@0: } paulo@0: vwfRectfill(v, l, t, l + 1, b, c); paulo@0: } paulo@0: paulo@0: void vwfRect(const VWFWindow *v, int l, int t, int r, int b, int c) { paulo@0: vwfVline(v, l, t, b, c); paulo@0: vwfVline(v, r - 1, t, b, c); paulo@0: vwfHline(v, l, t, r, c); paulo@0: vwfHline(v, l, b - 1, r, c); paulo@0: } paulo@0: paulo@0: void vwfWinClear(const VWFWindow *w) { paulo@0: size_t nBytes = 32 * w->width * w->height; paulo@0: memset(w->chrBase, 0, nBytes); paulo@0: } paulo@0: paulo@0: static inline NAMETABLE *vwfGetMapBase(int core, int map) { paulo@0: #if ARM9 paulo@0: NAMETABLE *dst = core ? &(MAP_SUB[map]) : &(MAP[map]); paulo@0: #else paulo@0: NAMETABLE *dst = &(MAP[map]); paulo@0: #endif paulo@0: paulo@0: return dst; paulo@0: } paulo@0: paulo@0: void vwfPutMap(const VWFWindow *w, paulo@0: int l, int t, int r, int b, paulo@0: unsigned int orMask) { paulo@0: paulo@0: if (r > (int)w->width) { paulo@0: r = (int)w->width; paulo@0: } paulo@0: if (l < 0) { paulo@0: l = 0; paulo@0: } paulo@0: if (r <= l) { paulo@0: return; paulo@0: } paulo@0: paulo@0: if (b > (int)w->height) { paulo@0: b = (int)w->height; paulo@0: } paulo@0: if (t < 0) { paulo@0: t = 0; paulo@0: } paulo@0: if (b <= t) { paulo@0: return; paulo@0: } paulo@0: paulo@0: NAMETABLE *dst = vwfGetMapBase(w->core, w->map); paulo@0: paulo@0: int mapTile = (w->mapTileBase + w->height * l + t) | orMask; paulo@0: for (int x = w->left + l; x < w->left + r; ++x) { paulo@0: for (int y = w->top + t; y < w->top + b; ++y) { paulo@0: (*dst)[y][x] = mapTile++; paulo@0: } paulo@0: mapTile += w->height + t - b; paulo@0: } paulo@0: } paulo@0: paulo@0: void vwfWinInit(const VWFWindow *w) { paulo@0: vwfWinClear(w); paulo@0: vwfPutMap(w, 0, 0, w->width, w->height, 0x0000); paulo@0: } paulo@0: paulo@0: #if 0 paulo@0: void vwfWinInit(const VWFWindow *w) { paulo@0: #if ARM9 paulo@0: NAMETABLE *dst = w->core ? &(MAP_SUB[w->map]) : &(MAP[w->map]); paulo@0: #else paulo@0: NAMETABLE *dst = &(MAP[w->map]); paulo@0: #endif paulo@0: paulo@0: int mapTile = w->mapTileBase; paulo@0: for (int x = w->left; x < w->left + w->width; ++x) { paulo@0: for (int y = w->top; y < w->top + w->height; ++y) { paulo@0: (*dst)[y][x] = mapTile++; paulo@0: } paulo@0: } paulo@0: vwfWinClear(w); paulo@0: } paulo@0: #endif paulo@0: paulo@0: unsigned int vwfPuts(const VWFWindow *w, paulo@0: const char *str, paulo@0: int x, int y) { paulo@0: return fontdraw_putline(w->chrBase + y, 8 * w->height, paulo@0: w->width * 8 - x, x, str); paulo@0: } paulo@0: paulo@0: unsigned int vwfPutc(const VWFWindow *w, paulo@0: int c, paulo@0: int x, int y) { paulo@0: int width = 8 * w->width - x; paulo@0: if (width >= fontdraw_charWidth(c)) { paulo@0: return fontdraw_putchar(w->chrBase + y, 8 * w->height, paulo@0: w->width * 8 - x, x, c & 0xFF); paulo@0: } else { paulo@0: return 0; paulo@0: } paulo@0: } paulo@0: paulo@0: // old api emulation paulo@0: paulo@0: #if 0 paulo@0: void fontdraw_demo_putline(int x, int y, const char *str) { paulo@0: const VWFWindow *w = &vwfTop; paulo@0: #if ARM9 paulo@0: if (y >= 288) { paulo@0: w = &vwfTouch; paulo@0: y -= 288; paulo@0: } paulo@0: #endif paulo@0: vwfPuts(w, str, x, y); paulo@0: } paulo@0: #endif paulo@0: paulo@0: void fontdraw_setupVRAM(int sub) { paulo@0: #if ARM9 paulo@0: const VWFWindow *w = sub ? &vwfTouch : &vwfTop; paulo@0: #else paulo@0: const VWFWindow *w = &vwfTop; paulo@0: #endif paulo@0: paulo@0: #if ARM9 paulo@0: if (sub == 0) { paulo@0: BGCTRL_SUB[0] = BG_MAP_BASE(31) | BG_TILE_BASE(0); paulo@0: BG_OFFSET_SUB[0].x = 0; paulo@0: BG_OFFSET_SUB[0].y = 0; paulo@0: } else paulo@0: #endif paulo@0: { paulo@0: BGCTRL[0] = BG_MAP_BASE(31) | BG_TILE_BASE(0); paulo@0: BG_OFFSET[0].x = 0; paulo@0: BG_OFFSET[0].y = 0; paulo@0: } paulo@0: paulo@0: vwfWinInit(w); paulo@0: } paulo@0: paulo@0: void fontdraw_cls(int sub) { paulo@0: #if ARM9 paulo@0: vwfWinClear(sub ? &vwfTouch : &vwfTop); paulo@0: #else paulo@0: vwfWinClear(&vwfTop); paulo@0: #endif paulo@0: } paulo@0: paulo@0: void vwfBlitAligned(const VWFWindow *src, const VWFWindow *dst, paulo@0: int srcX, int srcY, int dstX, int dstY, paulo@0: int w, int h) { paulo@0: paulo@0: /* Clip in X */ paulo@0: if (srcX < 0) { paulo@0: dstX -= srcX; paulo@0: w -= srcX; paulo@0: srcX = 0; paulo@0: } paulo@0: if (dstX < 0) { paulo@0: srcX -= dstX; paulo@0: w -= dstX; paulo@0: dstX = 0; paulo@0: } paulo@0: if (srcX + w > (int)src->width) { paulo@0: w = src->width - srcX; paulo@0: } paulo@0: if (dstX + w > (int)dst->width) { paulo@0: w = dst->width - dstX; paulo@0: } paulo@0: if (w <= 0) { paulo@0: return; paulo@0: } paulo@0: paulo@0: /* Clip in Y */ paulo@0: if (srcY < 0) { paulo@0: dstY -= srcY; paulo@0: h -= srcY; paulo@0: srcY = 0; paulo@0: } paulo@0: if (dstY < 0) { paulo@0: srcY -= dstY; paulo@0: h -= dstY; paulo@0: dstY = 0; paulo@0: } paulo@0: if (srcY + h > src->height * 8) { paulo@0: h = src->height * 8 - srcY; paulo@0: } paulo@0: if (dstX + w > dst->height * 8) { paulo@0: h = dst->height * 8 - dstY; paulo@0: } paulo@0: if (h < 0) { paulo@0: return; paulo@0: } paulo@0: paulo@0: { paulo@0: const u32 *srcCol = src->chrBase + srcX * src->height * 8 + srcY; paulo@0: u32 *dstCol = dst->chrBase + dstX * dst->height * 8 + dstY; paulo@0: paulo@0: for (; w > 0; --w) { paulo@0: for (unsigned int y = 0; y < h; ++y) { paulo@0: dstCol[y] = srcCol[y]; paulo@0: } paulo@0: srcCol += src->height * 8; paulo@0: dstCol += dst->height * 8; paulo@0: } paulo@0: } paulo@0: paulo@0: }