diff options
Diffstat (limited to 'source/framebuffer.c')
-rw-r--r-- | source/framebuffer.c | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/source/framebuffer.c b/source/framebuffer.c new file mode 100644 index 0000000..978623f --- /dev/null +++ b/source/framebuffer.c @@ -0,0 +1,431 @@ +/* + 3dsspec - Nintendo 3DS Spectrum emulator. + + Copyright (C) 2021 Ian Cowburn <ianc@noddybox.co.uk> + + 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; either version 3 + of the License, or (at your option) any later version. + + 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://www.gnu.org/licenses/> + + $Id: framebuffer.c 43 2007-03-12 00:59:51Z ianc $ +*/ + +#include <3ds.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#include "framebuffer.h" + +#include "keyb_bgr.h" +#include "splashimg_bgr.h" + +/* ---------------------------------------- STATIC DATA +*/ +static u16 pal[COL_YELLOW + 1]; + +static Framebuffer image[IMG_SPLASH + 1]; + +static u8 font[]= +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, + 0x00, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x24, 0x7e, 0x24, 0x24, 0x7e, 0x24, 0x00, + 0x00, 0x10, 0x7c, 0x14, 0x7c, 0x50, 0x7c, 0x10, + 0x00, 0x46, 0x26, 0x10, 0x08, 0x64, 0x62, 0x00, + 0x00, 0x08, 0x14, 0x08, 0x54, 0x22, 0x5c, 0x00, + 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, + 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x00, + 0x00, 0x00, 0x28, 0x10, 0x7c, 0x10, 0x28, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, + 0x00, 0x3c, 0x62, 0x52, 0x4a, 0x46, 0x3c, 0x00, + 0x00, 0x18, 0x14, 0x10, 0x10, 0x10, 0x7c, 0x00, + 0x00, 0x3c, 0x42, 0x40, 0x3c, 0x02, 0x7e, 0x00, + 0x00, 0x3c, 0x42, 0x30, 0x40, 0x42, 0x3c, 0x00, + 0x00, 0x10, 0x18, 0x14, 0x12, 0x7e, 0x10, 0x00, + 0x00, 0x7e, 0x02, 0x3e, 0x40, 0x42, 0x3c, 0x00, + 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x7e, 0x40, 0x20, 0x10, 0x08, 0x08, 0x00, + 0x00, 0x3c, 0x42, 0x3c, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x3c, 0x42, 0x42, 0x7c, 0x40, 0x3c, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x04, + 0x00, 0x00, 0x20, 0x10, 0x08, 0x10, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x20, 0x10, 0x08, 0x00, + 0x00, 0x3c, 0x42, 0x20, 0x10, 0x00, 0x10, 0x00, + 0x00, 0x3c, 0x52, 0x6a, 0x7a, 0x02, 0x3c, 0x00, + 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x00, + 0x00, 0x3e, 0x42, 0x3e, 0x42, 0x42, 0x3e, 0x00, + 0x00, 0x3c, 0x42, 0x02, 0x02, 0x42, 0x3c, 0x00, + 0x00, 0x1e, 0x22, 0x42, 0x42, 0x22, 0x1e, 0x00, + 0x00, 0x7e, 0x02, 0x3e, 0x02, 0x02, 0x7e, 0x00, + 0x00, 0x7e, 0x02, 0x3e, 0x02, 0x02, 0x02, 0x00, + 0x00, 0x3c, 0x42, 0x02, 0x72, 0x42, 0x3c, 0x00, + 0x00, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00, + 0x00, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, + 0x00, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x22, 0x12, 0x0e, 0x12, 0x22, 0x42, 0x00, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7e, 0x00, + 0x00, 0x42, 0x66, 0x5a, 0x42, 0x42, 0x42, 0x00, + 0x00, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x00, + 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x3e, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x00, + 0x00, 0x3c, 0x42, 0x42, 0x4a, 0x52, 0x3c, 0x00, + 0x00, 0x3e, 0x42, 0x42, 0x3e, 0x22, 0x42, 0x00, + 0x00, 0x3c, 0x02, 0x3c, 0x40, 0x42, 0x3c, 0x00, + 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, + 0x00, 0x42, 0x42, 0x42, 0x42, 0x5a, 0x24, 0x00, + 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, + 0x00, 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x7e, 0x20, 0x10, 0x08, 0x04, 0x7e, 0x00, + 0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, + 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, + 0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, + 0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x38, 0x44, 0x1e, 0x04, 0x04, 0x7e, 0x00, + 0x00, 0x00, 0x1c, 0x20, 0x3c, 0x22, 0x3c, 0x00, + 0x00, 0x04, 0x04, 0x3c, 0x44, 0x44, 0x3c, 0x00, + 0x00, 0x00, 0x38, 0x04, 0x04, 0x04, 0x38, 0x00, + 0x00, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x3c, 0x00, + 0x00, 0x00, 0x1c, 0x22, 0x1e, 0x02, 0x3c, 0x00, + 0x00, 0x30, 0x08, 0x18, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x3c, 0x22, 0x22, 0x3c, 0x20, 0x1c, + 0x00, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x00, + 0x00, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x1c, 0x00, + 0x00, 0x20, 0x00, 0x20, 0x20, 0x20, 0x24, 0x18, + 0x00, 0x04, 0x14, 0x0c, 0x0c, 0x14, 0x24, 0x00, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x30, 0x00, + 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x2a, 0x00, + 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, + 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, + 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, + 0x00, 0x00, 0x3c, 0x22, 0x22, 0x3c, 0x20, 0x60, + 0x00, 0x00, 0x38, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x1c, 0x02, 0x1c, 0x20, 0x1e, 0x00, + 0x00, 0x08, 0x1c, 0x08, 0x08, 0x08, 0x30, 0x00, + 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, + 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, + 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, + 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, + 0x00, 0x00, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x1c, + 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, + 0x00, 0x70, 0x10, 0x0c, 0x10, 0x10, 0x70, 0x00, + 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, + 0x00, 0x0e, 0x08, 0x30, 0x08, 0x08, 0x0e, 0x00, + 0x00, 0x28, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x42, 0x99, 0x85, 0x85, 0x99, 0x42, 0x3c +}; + + +/* ---------------------------------------- PRIVATE INTERFACES +*/ +static void LoadImage(Framebuffer *fb, const u8* img, u16 w, u16 h) +{ + int f; + int x,y; + + fb->width = w; + fb->height = h; + + fb->buffer = malloc(sizeof *fb->buffer * w * h); + + x = 0; + y = h - 1; + + for(f = 0; f < w * h; f++) + { + u8 b = *img++; + u8 g = *img++; + u8 r = *img++; + + FB_ADDR(fb, x, y) = RGB8_to_565(r, g, b); + + if (++x == w) + { + x = 0; + y--; + } + } +} + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void FB_Init(void) +{ + pal[COL_BLACK] = RGB8_to_565(0,0,0); + pal[COL_WHITE] = RGB8_to_565(255,255,255); + pal[COL_RED] = RGB8_to_565(255,0,0); + pal[COL_GREEN] = RGB8_to_565(0,255,0); + pal[COL_BLUE] = RGB8_to_565(0,0,255); + pal[COL_GUISELECT] = RGB8_to_565(128,128,255); + pal[COL_GREY] = RGB8_to_565(128,128,128); + pal[COL_LIGHTGREY] = RGB8_to_565(200,200,200); + pal[COL_DARKGREY] = RGB8_to_565(64,64,64); + pal[COL_YELLOW] = RGB8_to_565(255,255,0); + + LoadImage(image + IMG_KEYBOARD, keyb_bgr, 320, 240); + LoadImage(image + IMG_SPLASH, splashimg_bgr, 400, 240); +} + + +void FB_StartFrame(Framebuffer *upper, Framebuffer *lower) +{ + if (upper) + { + upper->buffer = (u16*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, + &upper->height, &upper->width); + } + + if (lower) + { + lower->buffer = (u16*)gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, + &lower->height, &lower->width); + } +} + + +void FB_EndFrame(void) +{ + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); + hidScanInput(); +} + + +u16 FB_GetColour(FB_Colour col) +{ + return pal[col]; +} + + +void FB_Print(Framebuffer *fb, const char *text, int x, int y, + FB_Colour colour, FB_Colour paper) +{ + int cx,cy; + int ch; + u16 fg,bg; + u16 fg_trans,bg_trans; + + fg = pal[colour]; + bg = pal[paper]; + fg_trans = colour == COL_TRANSPARENT; + bg_trans = paper == COL_TRANSPARENT; + + while(*text) + { + if (*text == 1) + { + u16 t; + + t = fg; + fg = bg; + bg = t; + + t = fg_trans; + fg_trans = bg_trans; + bg_trans = t; + + text++; + } + else if (*text == '\n') + { + x = 0; + y -= 8; + + text++; + + if (y < -7) + { + return; + } + } + else + { + ch=((*text)-32)*8; + + for(cy=0;cy<8;cy++) + { + for(cx=0;cx<8;cx++) + { + if (font[ch]&(1<<cx)) + { + if (!fg_trans) + { + FB_PLOT_CLIPPED(fb, x + cx, y - cy, fg); + } + } + else + { + if (!bg_trans) + { + FB_PLOT_CLIPPED(fb, x + cx, y - cy, bg); + } + } + } + + ch++; + } + + x+=8; + text++; + + if (x > fb->width) + { + break; + } + } + } +} + + +void FB_Centre(Framebuffer *fb, const char *text, int y, + FB_Colour colour, FB_Colour paper) +{ + FB_Print(fb, text, fb->width / 2 - strlen(text) * 4, y, colour, paper); +} + + +void FB_printf(Framebuffer *fb, int x, int y, + FB_Colour colour, FB_Colour paper, const char *format, ...) +{ + char buff[256]; + va_list va; + + va_start(va,format); + vsnprintf(buff,sizeof buff,format,va); + va_end(va); + + FB_Print(fb, buff, x, y, colour, paper); +} + + +void FB_HLine(Framebuffer *fb, u16 x1, u16 x2, u16 y, FB_Colour colour) +{ + if (x1 > x2) + { + u16 t; + + t = x1; + x1 = x2; + x2 = t; + } + + while(x1<=x2) + { + FB_PLOT_CLIPPED(fb, x1, y, pal[colour]); + x1++; + } +} + + +void FB_VLine(Framebuffer *fb, u16 x, u16 y1, u16 y2, FB_Colour colour) +{ + if (y1 > y2) + { + u16 t; + + t = y1; + y1 = y2; + y2 = t; + } + + while(y1<=y2) + { + FB_PLOT_CLIPPED(fb, x, y1, pal[colour]); + y1++; + } +} + + +void FB_Box(Framebuffer *fb, u16 x, u16 y, u16 w, u16 h, FB_Colour colour) +{ + FB_HLine(fb, x, x + w - 1, y, colour); + FB_HLine(fb, x, x + w - 1, y - h + 1, colour); + FB_VLine(fb, x, y, y - h + 1, colour); + FB_VLine(fb, x + w - 1, y, y - h + 1, colour); +} + + +void FB_FillBox(Framebuffer *fb, u16 x, u16 y, u16 w, u16 h, FB_Colour colour) +{ + while(h--) + { + FB_HLine(fb, x, x + w - 1, y--, colour); + } +} + + +void FB_Clear(Framebuffer *fb, FB_Colour col) +{ + u16 *p; + int f; + u16 c; + + f = fb->width * fb->height; + p = fb->buffer; + c = pal[col]; + + while(f--) + { + *p++ = c; + } +} + + +void FB_Blit(Framebuffer *fb, FB_Image img, u16 x, u16 y) +{ + Framebuffer *src; + u16 px,py; + + src = image + img; + + if (fb->width == src->width && fb->height == src->height && + x == 0 && y == 0) + { + memcpy(fb->buffer, src->buffer, src->width * src->height * 2); + } + else + { + for(px = 0; px < src->width; px++) + { + u16 dx; + + dx = x + px; + + if (dx < fb->width) + { + u16 dy; + + dy = y; + + for(py = 0; dy < fb->height && py < src->height; py++, dy++) + { + dy = y + py; + FB_ADDR(fb, dx, dy) = FB_ADDR(src, px, py); + } + } + } + } +} |