summaryrefslogtreecommitdiff
path: root/source/framebuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/framebuffer.c')
-rw-r--r--source/framebuffer.c431
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);
+ }
+ }
+ }
+ }
+}