summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVincent Sanders <vince@netsurf-browser.org>2009-04-08 10:17:09 +0000
committerVincent Sanders <vince@netsurf-browser.org>2009-04-08 10:17:09 +0000
commit056e1ebed94379db41ebb2e40cc88a873cfb4411 (patch)
treed1d01c4b9f9d4c2c2b1db4b705e631d49cf2e6b0 /src
downloadlibnsfb-056e1ebed94379db41ebb2e40cc88a873cfb4411.tar.gz
libnsfb-056e1ebed94379db41ebb2e40cc88a873cfb4411.tar.bz2
initial commit of netsurf framebuffer library
svn path=/trunk/libnsfb/; revision=7060
Diffstat (limited to 'src')
-rw-r--r--src/16bpp_plotters.c569
-rw-r--r--src/1bpp_plotters.c266
-rw-r--r--src/24bpp_plotters.c469
-rw-r--r--src/32bpp_plotters.c320
-rw-r--r--src/8bpp_plotters.c469
-rw-r--r--src/Makefile6
-rw-r--r--src/frontend.c98
-rw-r--r--src/frontend_linux.c9
-rw-r--r--src/frontend_sdl.c105
-rw-r--r--src/libnsfb.c71
-rw-r--r--src/plot.c114
-rw-r--r--src/plot_util.c150
-rw-r--r--src/plotters.c522
13 files changed, 3168 insertions, 0 deletions
diff --git a/src/16bpp_plotters.c b/src/16bpp_plotters.c
new file mode 100644
index 0000000..b97c42d
--- /dev/null
+++ b/src/16bpp_plotters.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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/>.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+
+#include "utils/log.h"
+#include "utils/utf8.h"
+#include "desktop/plotters.h"
+
+#include "framebuffer/fb_gui.h"
+#include "framebuffer/fb_plotters.h"
+#include "framebuffer/fb_bitmap.h"
+#include "framebuffer/fb_font.h"
+
+static inline uint16_t *
+fb_16bpp_get_xy_loc(int x, int y)
+{
+ return (void *)(framebuffer->ptr +
+ (y * framebuffer->linelen) +
+ (x << 1));
+}
+
+static inline colour fb_16bpp_to_colour(uint16_t pixel)
+{
+ return ((pixel & 0x1F) << 19) |
+ ((pixel & 0x7E0) << 5) |
+ ((pixel & 0xF800) >> 8);
+}
+
+/* convert a colour value to a 16bpp pixel value ready for screen output */
+static inline uint16_t fb_colour_to_pixel(colour c)
+{
+ return ((c & 0xF8) << 8) | ((c & 0xFC00 ) >> 5) | ((c & 0xF80000) >> 19);
+}
+
+#define SIGN(x) ((x<0) ? -1 : ((x>0) ? 1 : 0))
+
+static bool fb_16bpp_line(int x0, int y0, int x1, int y1, int width,
+ colour c, bool dotted, bool dashed)
+{
+ int w;
+ uint16_t ent;
+ uint16_t *pvideo;
+
+ int x, y, i;
+ int dx, dy, sdy;
+ int dxabs, dyabs;
+
+ /*LOG(("%d, %d, %d, %d, %d, 0x%lx, %d, %d",
+ x0,y0,x1,y1,width,c,dotted,dashed));*/
+
+ if (y1 > fb_plot_ctx.y1)
+ return true;
+ if (y0 < fb_plot_ctx.y0)
+ return true;
+
+ ent = fb_colour_to_pixel(c);
+
+ if (y0 == y1) {
+ /* horizontal line special cased */
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true; /* line outside clipping */
+
+ /*LOG(("horiz: %d, %d, %d, %d, %d, 0x%lx, %d, %d",
+ x0,y0,x1,y1,width,c,dotted,dashed));*/
+
+ pvideo = fb_16bpp_get_xy_loc(x0, y0);
+
+ w = x1 - x0;
+ while (w-- > 0) {
+ *(pvideo + w) = ent;
+ }
+ return true;
+ } else {
+ /* standard bresenham line */
+ if (!fb_plotters_clip_line_ctx(&x0, &y0, &x1, &y1))
+ return true; /* line outside clipping */
+
+ //LOG(("%d, %d, %d, %d", x0,y0,x1,y1));
+
+ /* the horizontal distance of the line */
+ dx = x1 - x0;
+ dxabs = abs (dx);
+
+ /* the vertical distance of the line */
+ dy = y1 - y0;
+ dyabs = abs (dy);
+
+ sdy = dx ? SIGN(dy) * SIGN(dx) : SIGN(dy);
+
+ if (dx >= 0)
+ pvideo = fb_16bpp_get_xy_loc(x0, y0);
+ else
+ pvideo = fb_16bpp_get_xy_loc(x1, y1);
+
+ x = dyabs >> 1;
+ y = dxabs >> 1;
+
+ if (dxabs >= dyabs) {
+ /* the line is more horizontal than vertical */
+ for (i = 0; i <= dxabs; i++) {
+ *pvideo = ent;
+
+ pvideo++;
+ y += dyabs;
+ if (y > dxabs) {
+ y -= dxabs;
+ pvideo += sdy * (framebuffer->linelen>>1);
+ }
+ }
+ } else {
+ /* the line is more vertical than horizontal */
+ for (i = 0; i <= dyabs; i++) {
+ *pvideo = ent;
+ pvideo += sdy * (framebuffer->linelen >> 1);
+
+ x += dxabs;
+ if (x > dyabs) {
+ x -= dyabs;
+ pvideo++;
+ }
+ }
+ }
+
+ }
+
+
+
+ return true;
+}
+
+static bool fb_16bpp_rectangle(int x0, int y0, int width, int height,
+ int line_width, colour c, bool dotted, bool dashed)
+{
+ fb_16bpp_line(x0, y0, x0 + width, y0, line_width, c, dotted, dashed);
+ fb_16bpp_line(x0, y0 + height, x0 + width, y0 + height, line_width, c, dotted, dashed);
+ fb_16bpp_line(x0, y0, x0, y0 + height, line_width, c, dotted, dashed);
+ fb_16bpp_line(x0 + width, y0, x0 + width, y0 + height, line_width, c, dotted, dashed);
+ return true;
+}
+
+static bool fb_16bpp_polygon(const int *p, unsigned int n, colour fill)
+{
+ return fb_plotters_polygon(p, n, fill, fb_16bpp_line);
+}
+
+
+static bool fb_16bpp_fill(int x0, int y0, int x1, int y1, colour c)
+{
+ int w;
+ uint16_t *pvid16;
+ uint16_t ent16;
+ uint32_t *pvid32;
+ uint32_t ent32;
+ uint32_t llen;
+ uint32_t width;
+ uint32_t height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true; /* fill lies outside current clipping region */
+
+ ent16 = fb_colour_to_pixel(c);
+ width = x1 - x0;
+ height = y1 - y0;
+
+ pvid16 = fb_16bpp_get_xy_loc(x0, y0);
+
+ if (((x0 & 1) == 0) && ((width & 1) == 0)) {
+ /* aligned to 32bit value and width is even */
+ width = width >> 1;
+ llen = (framebuffer->linelen >> 2) - width;
+ ent32 = ent16 | (ent16 << 16);
+ pvid32 = (uint32_t *)pvid16;
+
+ while (height-- > 0) {
+ w = width;
+ while (w >= 16) {
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ w-=16;
+ }
+ while (w >= 4) {
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ *pvid32++ = ent32; *pvid32++ = ent32;
+ w-=4;
+ }
+ while (w > 0) {
+ *pvid32++ = ent32;
+ w--;
+ }
+ // for (w = width; w > 0; w--) *pvid32++ = ent32;
+ pvid32 += llen;
+ }
+
+ } else {
+ llen = (framebuffer->linelen >> 1) - width;
+
+
+ while (height-- > 0) {
+ for (w = width; w > 0; w--) *pvid16++ = ent16;
+ pvid16 += llen;
+ }
+ }
+ return true;
+}
+
+static bool fb_16bpp_clg(colour c)
+{
+ /* LOG(("c %lx", c)); */
+ fb_16bpp_fill(fb_plot_ctx.x0,
+ fb_plot_ctx.y0,
+ fb_plot_ctx.x1,
+ fb_plot_ctx.y1,
+ c);
+ return true;
+}
+
+#ifdef FB_USE_FREETYPE
+
+static bool
+fb_16bpp_draw_ft_monobitmap(FT_Bitmap *bp, int x, int y, colour c)
+{
+ return false;
+}
+
+static bool
+fb_16bpp_draw_ft_bitmap(FT_Bitmap *bp, int x, int y, colour c)
+{
+ uint16_t *pvideo;
+ uint8_t *pixel = (uint8_t *)bp->buffer;
+ colour abpixel; /* alphablended pixel */
+ int xloop, yloop;
+ int x0,y0,x1,y1;
+ int xoff, yoff; /* x and y offset into image */
+ int height = bp->rows;
+ int width = bp->width;
+ uint32_t fgcol;
+
+ /* The part of the scaled image actually displayed is cropped to the
+ * current context.
+ */
+ x0 = x;
+ y0 = y;
+ x1 = x + width;
+ y1 = y + height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true;
+
+ if (height > (y1 - y0))
+ height = (y1 - y0);
+
+ if (width > (x1 - x0))
+ width = (x1 - x0);
+
+ xoff = x0 - x;
+ yoff = y0 - y;
+
+ /* plot the image */
+ pvideo = fb_16bpp_get_xy_loc(x0, y0);
+
+ fgcol = c & 0xFFFFFF;
+
+ for (yloop = 0; yloop < height; yloop++) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = (pixel[((yoff + yloop) * bp->pitch) + xloop + xoff] << 24) | fgcol;
+ if ((abpixel & 0xFF000000) != 0) {
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = fb_plotters_ablend(abpixel,
+ fb_16bpp_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = fb_colour_to_pixel(abpixel);
+
+ }
+ }
+ pvideo += (framebuffer->linelen >> 1);
+ }
+
+ return true;
+}
+
+static bool fb_16bpp_text(int x, int y, const struct css_style *style,
+ const char *text, size_t length, colour bg, colour c)
+{
+ uint32_t ucs4;
+ size_t nxtchr = 0;
+ FT_Glyph glyph;
+ FT_BitmapGlyph bglyph;
+
+ while (nxtchr < length) {
+ ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
+ nxtchr = utf8_next(text, length, nxtchr);
+
+ glyph = fb_getglyph(style, ucs4);
+ if (glyph == NULL)
+ continue;
+ if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
+ bglyph = (FT_BitmapGlyph)glyph;
+
+ /* now, draw to our target surface */
+ if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
+ fb_16bpp_draw_ft_monobitmap(&bglyph->bitmap,
+ x + bglyph->left,
+ y - bglyph->top,
+ c);
+ } else {
+ fb_16bpp_draw_ft_bitmap(&bglyph->bitmap,
+ x + bglyph->left,
+ y - bglyph->top,
+ c);
+ }
+ }
+ x += glyph->advance.x >> 16;
+
+ }
+ return true;
+}
+
+#else
+static bool fb_16bpp_text(int x, int y, const struct css_style *style,
+ const char *text, size_t length, colour bg, colour c)
+{
+ const struct fb_font_desc* fb_font = fb_get_font(style);
+ const uint32_t *font_data;
+ int xloop, yloop;
+ uint32_t row;
+ size_t chr;
+
+ uint16_t *pvideo;
+ uint16_t fgcol;
+ uint16_t bgcol;
+
+ unsigned char *buffer = NULL;
+ int x0,y0,x1,y1;
+ int xoff, yoff; /* x and y offset into image */
+ int height = fb_font->height;
+
+ /* aquire thge text in local font encoding */
+ utf8_to_font_encoding(fb_font, text, length, (char **)&buffer);
+ if (!buffer)
+ return true;
+ length = strlen((char *)buffer);
+
+
+ /* y is given to the fonts baseline we need it to the fonts top */
+ y-=((fb_font->height * 75)/100);
+
+ y+=1; /* the coord is the bottom-left of the pixels offset by 1 to make
+ * it work since fb coords are the top-left of pixels
+ */
+
+ /* The part of the text displayed is cropped to the current context. */
+ x0 = x;
+ y0 = y;
+ x1 = x + (fb_font->width * length);
+ y1 = y + fb_font->height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true; /* text lies outside current clipping region */
+
+ /* find width and height to plot */
+ if (height > (y1 - y0))
+ height = (y1 - y0);
+
+ xoff = x0 - x;
+ yoff = y0 - y;
+
+ fgcol = fb_colour_to_pixel(c);
+
+ bgcol = fb_colour_to_pixel(bg);
+
+ /*LOG(("x %d, y %d, style %p, txt %.*s , len %d, bg 0x%lx, fg 0x%lx",
+ x,y,style,length,text,length,bg,c));*/
+
+ for (chr = 0; chr < length; chr++, x += fb_font->width) {
+ if ((x + fb_font->width) > x1)
+ break;
+
+ if (x < x0)
+ continue;
+
+ pvideo = fb_16bpp_get_xy_loc(x, y0);
+
+ /* move our font-data to the correct position */
+ font_data = fb_font->data + (buffer[chr] * fb_font->height);
+
+ for (yloop = 0; yloop < height; yloop++) {
+ row = font_data[yoff + yloop];
+ for (xloop = fb_font->width; xloop > 0 ; xloop--) {
+ if ((row & 1) != 0)
+ *(pvideo + xloop) = fgcol;
+ row = row >> 1;
+ }
+ pvideo += (framebuffer->linelen >> 1);
+ }
+ }
+
+ free(buffer);
+ return true;
+}
+#endif
+
+static bool fb_16bpp_disc(int x, int y, int radius, colour c, bool filled)
+{
+ LOG(("x %d, y %d, r %d, c 0x%lx, fill %d",
+ x, y, radius, (unsigned long)c, filled));
+
+ return true;
+}
+
+static bool fb_16bpp_arc(int x, int y, int radius, int angle1, int angle2,
+ colour c)
+{
+ LOG(("x %d, y %d, r %d, a1 %d, a2 %d, c 0x%lx",
+ x, y, radius, angle1, angle2, (unsigned long)c));
+ return true;
+}
+
+
+static bool fb_16bpp_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ struct content *content)
+{
+ uint16_t *pvideo;
+ colour *pixel = (colour *)bitmap->pixdata;
+ colour abpixel; /* alphablended pixel */
+ int xloop, yloop;
+ int x0,y0,x1,y1;
+ int xoff, yoff; /* x and y offset into image */
+
+
+ /* TODO here we should scale the image from bitmap->width to width, for
+ * now simply crop.
+ */
+ if (width > bitmap->width)
+ width = bitmap->width;
+
+ if (height > bitmap->height)
+ height = bitmap->height;
+
+ /* The part of the scaled image actually displayed is cropped to the
+ * current context.
+ */
+ x0 = x;
+ y0 = y;
+ x1 = x + width;
+ y1 = y + height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true;
+
+
+ LOG(("%d, %d %d, %d bitmap %p, content %p",
+ x0,y0,x1,y1,bitmap,content));
+
+ if (height > (y1 - y0))
+ height = (y1 - y0);
+
+ if (width > (x1 - x0))
+ width = (x1 - x0);
+
+
+ xoff = x0 - x;
+ yoff = (y0 - y) * bitmap->width;
+ height = height * bitmap->width + yoff;
+
+ /* plot the image */
+ pvideo = fb_16bpp_get_xy_loc(x0, y0);
+
+ if (bitmap->opaque) {
+ for (yloop = yoff; yloop < height; yloop += bitmap->width) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = pixel[yloop + xloop + xoff];
+ *(pvideo + xloop) = fb_colour_to_pixel(abpixel);
+ }
+ pvideo += (framebuffer->linelen >> 1);
+ }
+ } else {
+ for (yloop = yoff; yloop < height; yloop += bitmap->width) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = pixel[yloop + xloop + xoff];
+ if ((abpixel & 0xFF000000) != 0) {
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = fb_plotters_ablend(abpixel,
+ fb_16bpp_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = fb_colour_to_pixel(abpixel);
+ }
+ }
+ pvideo += (framebuffer->linelen >> 1);
+ }
+ }
+
+ return true;
+}
+
+static bool fb_16bpp_bitmap_tile(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bool repeat_x, bool repeat_y,
+ struct content *content)
+{
+ return fb_plotters_bitmap_tile(x, y, width, height,
+ bitmap, bg, repeat_x, repeat_y,
+ content, fb_16bpp_bitmap);
+}
+
+static bool fb_16bpp_flush(void)
+{
+ LOG(("optional"));
+ return true;
+}
+
+static bool fb_16bpp_path(const float *p, unsigned int n, colour fill, float width,
+ colour c, const float transform[6])
+{
+ LOG(("%f, %d, 0x%lx, %f, 0x%lx, %f",
+ *p, n, (unsigned long)fill, width, (unsigned long)c, *transform));
+ return true;
+}
+
+
+const struct plotter_table framebuffer_16bpp_plot = {
+ .clg = fb_16bpp_clg,
+ .rectangle = fb_16bpp_rectangle,
+ .line = fb_16bpp_line,
+ .polygon = fb_16bpp_polygon,
+ .fill = fb_16bpp_fill,
+ .clip = fb_clip,
+ .text = fb_16bpp_text,
+ .disc = fb_16bpp_disc,
+ .arc = fb_16bpp_arc,
+ .bitmap = fb_16bpp_bitmap,
+ .bitmap_tile = fb_16bpp_bitmap_tile,
+ .flush = fb_16bpp_flush,
+ .path = fb_16bpp_path,
+ .option_knockout = true,
+};
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/src/1bpp_plotters.c b/src/1bpp_plotters.c
new file mode 100644
index 0000000..bd511e7
--- /dev/null
+++ b/src/1bpp_plotters.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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/>.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+
+#include "utils/log.h"
+#include "utils/utf8.h"
+#include "desktop/plotters.h"
+
+#include "framebuffer/fb_gui.h"
+#include "framebuffer/fb_plotters.h"
+#include "framebuffer/fb_bitmap.h"
+#include "framebuffer/fb_font.h"
+
+extern struct fb_info_s *fbinfo;
+
+
+static bool fb_1bpp_rectangle(int x0, int y0, int width, int height,
+ int line_width, colour c, bool dotted, bool dashed)
+{
+ LOG(("%s(%d, %d, %d, %d, %d, 0x%lx, %d, %d)\n", __func__,
+ x0,y0,width,height,line_width,c,dotted,dashed));
+ return true;
+}
+
+static bool fb_1bpp_line(int x0, int y0, int x1, int y1, int width,
+ colour c, bool dotted, bool dashed)
+{
+ LOG(("%s(%d, %d, %d, %d, %d, 0x%lx, %d, %d)\n", __func__,
+ x0,y0,x1,y1,width,c,dotted,dashed));
+
+ return true;
+}
+
+static bool fb_1bpp_polygon(const int *p, unsigned int n, colour fill)
+{
+ LOG(("%s(%p, %d, 0x%lx)\n", __func__, p,n,fill));
+ return true;
+}
+
+
+static bool fb_1bpp_fill(int x0, int y0, int x1, int y1, colour c)
+{
+ int x;
+ int y;
+ int pent;
+
+ LOG(("%s(%d, %d, %d, %d, 0x%lx)\n", __func__,
+ x0,y0,x1,y1,c));
+
+ if (c != 0)
+ pent = 0xff;
+ else
+ pent = 0;
+
+ fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1);
+
+ x = x1 - x0;
+ for (y = y0; y < y1; y++) {
+ memset(fb_plotters_get_xy_loc(x0, y, fbinfo), pent, x);
+ }
+ return true;
+}
+
+static bool fb_1bpp_clg(colour c)
+{
+ LOG(("%s(%lx)\n", __func__, c));
+ fb_1bpp_fill(fb_plot_ctx.x0,
+ fb_plot_ctx.y0,
+ fb_plot_ctx.x1,
+ fb_plot_ctx.y1,
+ c);
+ return true;
+}
+
+
+static bool fb_1bpp_text(int x, int y, const struct css_style *style,
+ const char *text, size_t length, colour bg, colour c)
+{
+ const struct fb_font_desc* fb_font = fb_get_font(style);
+ u8_t *video_char_start;
+ const u8_t *font_data;
+ int yloop;
+ unsigned char row;
+ int chr;
+
+ LOG(("%s(%d, %d, %p, %.*s , %d, 0x%lx, 0x%lx)\n", __func__,
+ x,y,style,length,text,length,bg,c));
+
+ for (chr=0; chr < length; chr++) {
+ video_char_start = fb_plotters_get_xy_loc(x + (chr * (fb_font->width)), y, fbinfo);
+
+ /* move our font-data to the correct position */
+ font_data = fb_font->data + (text[chr] * fb_font->height);
+
+ for (yloop = 0; yloop < fb_font->height; yloop++) {
+ row = font_data[yloop];
+ *video_char_start = row;
+ video_char_start += fbinfo->line_len;
+ }
+ }
+ return true;
+
+
+ /* copied from css/css.h - need to open the correct font here
+ * font properties *
+ css_font_family font_family;
+ struct {
+ css_font_size_type size;
+ union {
+ struct css_length length;
+ float absolute;
+ float percent;
+ } value;
+ } font_size;
+ css_font_style font_style;
+ css_font_variant font_variant;
+ css_font_weight font_weight;
+ */
+ return true;
+}
+
+static bool fb_1bpp_disc(int x, int y, int radius, colour c, bool filled)
+{
+ LOG(("%s(%d, %d, %d, 0x%lx, %d)\n", __func__,
+ x, y, radius, c, filled));
+ return true;
+}
+
+static bool fb_1bpp_arc(int x, int y, int radius, int angle1, int angle2,
+ colour c)
+{
+ LOG(("x %d, y %d, radius %d, angle1 %d, angle2 %d, c 0x%lx",
+ x, y, radius, angle1, angle2, c));
+ return true;
+}
+
+static inline colour ablend(colour pixel)
+{
+ return pixel;
+}
+
+
+static bool fb_1bpp_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ struct content *content)
+{
+ u8_t *video_char_start;
+ colour *pixel = (colour *)bitmap->pixdata;
+ colour abpixel; /* alphablended pixel */
+ int xloop,yloop;
+
+ video_char_start = fb_plotters_get_xy_loc(x, y, fbinfo);
+
+ for (yloop = 0; yloop < height; yloop++) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = pixel[(yloop * bitmap->width) + xloop];
+ if ((abpixel & 0xFF000000) != 0) {
+ if ((abpixel & 0xFF000000) != 0xFF)
+ abpixel = ablend(abpixel);
+ if (abpixel == 0)
+ video_char_start[xloop] |= (1 << (xloop % 8));
+ else
+ video_char_start[xloop] &= ~(1 << (xloop % 8));
+
+ }
+ }
+ video_char_start += fbinfo->line_len;
+ }
+
+ return true;
+}
+
+static bool fb_1bpp_bitmap_tile(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bool repeat_x, bool repeat_y,
+ struct content *content)
+{
+ unsigned long xf,yf,wf,hf;
+
+ if (!(repeat_x || repeat_y)) {
+ /* Not repeating at all, so just pass it on */
+ return fb_1bpp_bitmap(x,y,width,height,bitmap,bg,content);
+ }
+
+ for (xf = 0; xf < width; xf += bitmap->width) {
+ for(yf = 0;yf < height; yf += bitmap->height) {
+ if(width > xf+bitmap->width)
+ {
+ wf = width-(xf+bitmap->width);
+ }
+ else
+ {
+ wf=bitmap->width;
+ }
+
+ if(height > yf+bitmap->height)
+ {
+ hf = height-(yf+bitmap->height);
+ }
+ else
+ {
+ hf=bitmap->height;
+ }
+
+ fb_1bpp_bitmap(x+xf, y+yf, wf, hf, bitmap, bg, content);
+
+ }
+ }
+
+ return true;
+}
+
+static bool fb_1bpp_flush(void)
+{
+ LOG(("%s()\n", __func__));
+ return true;
+}
+
+static bool fb_1bpp_path(const float *p, unsigned int n, colour fill, float width,
+ colour c, const float transform[6])
+{
+ LOG(("%s(%f, %d, 0x%lx, %f, 0x%lx, %f)\n", __func__,
+ *p, n, fill, width, c, *transform));
+ return true;
+}
+
+const struct plotter_table framebuffer_1bpp_plot = {
+ .clg = fb_1bpp_clg,
+ .rectangle = fb_1bpp_rectangle,
+ .line = fb_1bpp_line,
+ .polygon = fb_1bpp_polygon,
+ .fill = fb_1bpp_fill,
+ .clip = fb_clip,
+ .text = fb_1bpp_text,
+ .disc = fb_1bpp_disc,
+ .arc = fb_1bpp_arc,
+ .bitmap = fb_1bpp_bitmap,
+ .bitmap_tile = fb_1bpp_bitmap_tile,
+ .flush = fb_1bpp_flush,
+ .path = fb_1bpp_path
+};
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/src/24bpp_plotters.c b/src/24bpp_plotters.c
new file mode 100644
index 0000000..777b896
--- /dev/null
+++ b/src/24bpp_plotters.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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/>.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+
+#include "utils/log.h"
+#include "utils/utf8.h"
+#include "desktop/plotters.h"
+
+#include "framebuffer/fb_gui.h"
+#include "framebuffer/fb_plotters.h"
+#include "framebuffer/fb_bitmap.h"
+#include "framebuffer/fb_font.h"
+
+static inline uint8_t *
+fb_8bpp_get_xy_loc(int x, int y)
+{
+ return (uint8_t *)(framebuffer->ptr +
+ (y * framebuffer->linelen) +
+ (x));
+}
+
+
+static bool fb_8bpp_line(int x0, int y0, int x1, int y1, int width,
+ colour c, bool dotted, bool dashed)
+{
+ LOG(("%d, %d, %d, %d, %d, 0x%lx, %d, %d",
+ x0, y0, x1, y1, width, (unsigned long)c, dotted, dashed));
+
+ return true;
+}
+
+static bool fb_8bpp_rectangle(int x0, int y0, int width, int height,
+ int line_width, colour c, bool dotted, bool dashed)
+{
+ fb_8bpp_line(x0, y0, x0 + width, y0, line_width, c, dotted, dashed);
+ fb_8bpp_line(x0, y0 + height, x0 + width, y0 + height, line_width, c, dotted, dashed);
+ fb_8bpp_line(x0, y0, x0, y0 + height, line_width, c, dotted, dashed);
+ fb_8bpp_line(x0 + width, y0, x0 + width, y0 + height, line_width, c, dotted, dashed);
+ return true;
+}
+
+static bool fb_8bpp_polygon(const int *p, unsigned int n, colour fill)
+{
+ /*LOG(("%p, %d, 0x%lx", p,n,fill));*/
+ return fb_plotters_polygon(p, n, fill, fb_8bpp_line);
+}
+
+static colour calc_colour(uint8_t c)
+{
+ return framebuffer->palette[c];
+}
+
+
+static int
+find_closest_palette_entry(colour c)
+{
+ colour palent;
+ int col;
+
+ int dr, dg, db; /* delta red, green blue values */
+
+ int cur_distance;
+ int best_distance = INT_MAX;
+ int best_col = 0;
+
+ for (col = 0; col < 256; col++) {
+ palent = framebuffer->palette[col];
+
+ dr = (c & 0xFF) - (palent & 0xFF);
+ dg = ((c >> 8) & 0xFF) - ((palent >> 8) & 0xFF);
+ db = ((c >> 16) & 0xFF) - ((palent >> 16) & 0xFF);
+ cur_distance = ((dr * dr) + (dg * dg) + (db *db));
+ if (cur_distance < best_distance) {
+ best_distance = cur_distance;
+ best_col = col;
+ }
+ }
+
+ return best_col;
+}
+
+static inline uint8_t fb_colour_to_pixel(colour c)
+{
+ return find_closest_palette_entry(c);
+}
+
+static inline colour fb_8bpp_to_colour(uint8_t pixel)
+{
+ return framebuffer->palette[pixel];
+}
+
+static bool fb_8bpp_fill(int x0, int y0, int x1, int y1, colour c)
+{
+ int y;
+ uint8_t ent;
+ uint8_t *pvideo;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true; /* fill lies outside current clipping region */
+
+ pvideo = fb_8bpp_get_xy_loc(x0, y0);
+
+ ent = find_closest_palette_entry(c);
+
+ for (y = y0; y < y1; y++) {
+ memset(pvideo, ent, x1 - x0);
+ pvideo += framebuffer->linelen;
+ }
+
+ return true;
+}
+
+static bool fb_8bpp_clg(colour c)
+{
+ LOG(("colour %lx", (unsigned long)c));
+ fb_8bpp_fill(fb_plot_ctx.x0,
+ fb_plot_ctx.y0,
+ fb_plot_ctx.x1,
+ fb_plot_ctx.y1,
+ c);
+ return true;
+}
+
+#ifdef FB_USE_FREETYPE
+
+static bool
+fb_8bpp_draw_ft_monobitmap(FT_Bitmap *bp, int x, int y, colour c)
+{
+ return false;
+}
+
+static bool
+fb_8bpp_draw_ft_bitmap(FT_Bitmap *bp, int x, int y, colour c)
+{
+ uint8_t *pvideo;
+ uint8_t *pixel = (uint8_t *)bp->buffer;
+ colour abpixel; /* alphablended pixel */
+ int xloop, yloop;
+ int x0,y0,x1,y1;
+ int xoff, yoff; /* x and y offset into image */
+ int height = bp->rows;
+ int width = bp->width;
+ uint32_t fgcol;
+
+ /* The part of the scaled image actually displayed is cropped to the
+ * current context.
+ */
+ x0 = x;
+ y0 = y;
+ x1 = x + width;
+ y1 = y + height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true;
+
+ if (height > (y1 - y0))
+ height = (y1 - y0);
+
+ if (width > (x1 - x0))
+ width = (x1 - x0);
+
+ xoff = x0 - x;
+ yoff = y0 - y;
+
+ /* plot the image */
+ pvideo = fb_8bpp_get_xy_loc(x0, y0);
+
+ fgcol = c & 0xFFFFFF;
+
+ for (yloop = 0; yloop < height; yloop++) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = (pixel[((yoff + yloop) * bp->pitch) + xloop + xoff] << 24) | fgcol;
+ if ((abpixel & 0xFF000000) != 0) {
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = fb_plotters_ablend(abpixel,
+ fb_8bpp_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = fb_colour_to_pixel(abpixel);
+
+ }
+ }
+ pvideo += framebuffer->linelen;
+ }
+
+ return true;
+}
+
+static bool fb_8bpp_text(int x, int y, const struct css_style *style,
+ const char *text, size_t length, colour bg, colour c)
+{
+ uint32_t ucs4;
+ size_t nxtchr = 0;
+ FT_Glyph glyph;
+ FT_BitmapGlyph bglyph;
+
+ while (nxtchr < length) {
+ ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
+ nxtchr = utf8_next(text, length, nxtchr);
+
+ glyph = fb_getglyph(style, ucs4);
+ if (glyph == NULL)
+ continue;
+ if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
+ bglyph = (FT_BitmapGlyph)glyph;
+
+ /* now, draw to our target surface */
+ if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
+ fb_8bpp_draw_ft_monobitmap(&bglyph->bitmap,
+ x + bglyph->left,
+ y - bglyph->top,
+ c);
+ } else {
+ fb_8bpp_draw_ft_bitmap(&bglyph->bitmap,
+ x + bglyph->left,
+ y - bglyph->top,
+ c);
+ }
+ }
+ x += glyph->advance.x >> 16;
+
+ }
+ return true;
+
+}
+#else
+static bool fb_8bpp_text(int x, int y, const struct css_style *style,
+ const char *text, size_t length, colour bg, colour c)
+{
+ const struct fb_font_desc* fb_font = fb_get_font(style);
+ const uint32_t *font_data;
+ uint32_t row;
+
+ int xloop, yloop;
+ size_t chr;
+
+ uint8_t *pvideo;
+ uint8_t fgcol;
+
+ unsigned char *buffer = NULL;
+ int x0,y0,x1,y1;
+ int xoff, yoff; /* x and y offset into image */
+ int height = fb_font->height;
+
+ /* aquire thge text in local font encoding */
+ utf8_to_font_encoding(fb_font, text, length, (char **)&buffer);
+ if (!buffer)
+ return true;
+ length = strlen((char *)buffer);
+
+
+ /* y is given to the fonts baseline we need it to the fonts top */
+ y-=((fb_font->height * 75)/100);
+
+ y+=1; /* the coord is the bottom-left of the pixels offset by 1 to make
+ * it work since fb coords are the top-left of pixels
+ */
+
+ /* The part of the text displayed is cropped to the current context. */
+ x0 = x;
+ y0 = y;
+ x1 = x + (fb_font->width * length);
+ y1 = y + fb_font->height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true; /* text lies outside current clipping region */
+
+ /* find width and height to plot */
+ if (height > (y1 - y0))
+ height = (y1 - y0);
+
+ xoff = x0 - x;
+ yoff = y0 - y;
+
+ fgcol = find_closest_palette_entry(c);
+
+ /*LOG(("x %d, y %d, style %p, txt %.*s , len %d, bg 0x%lx, fg 0x%lx",
+ x,y,style,length,text,length,bg,c));*/
+
+ for (chr = 0; chr < length; chr++, x += fb_font->width) {
+ if ((x + fb_font->width) > x1)
+ break;
+
+ if (x < x0)
+ continue;
+
+ pvideo = fb_8bpp_get_xy_loc(x, y0);
+
+ /* move our font-data to the correct position */
+ font_data = fb_font->data + (buffer[chr] * fb_font->height);
+
+ for (yloop = 0; yloop < height; yloop++) {
+ row = font_data[yoff + yloop];
+ for (xloop = fb_font->width; xloop > 0 ; xloop--) {
+ if ((row & 1) != 0)
+ *(pvideo + xloop) = fgcol;
+ row = row >> 1;
+ }
+ pvideo += framebuffer->linelen;
+ }
+ }
+
+ free(buffer);
+ return true;
+}
+#endif
+
+static bool fb_8bpp_disc(int x, int y, int radius, colour c, bool filled)
+{
+ LOG(("x %d, y %d, rad %d, c 0x%lx, fill %d", x, y, radius, (unsigned long)c, filled));
+ return true;
+}
+
+static bool fb_8bpp_arc(int x, int y, int radius, int angle1, int angle2,
+ colour c)
+{
+ LOG(("x %d, y %d, radius %d, angle1 %d, angle2 %d, c 0x%lx",
+ x, y, radius, angle1, angle2, (unsigned long)c));
+ return true;
+}
+
+
+
+static bool fb_8bpp_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ struct content *content)
+{
+ uint8_t *pvideo;
+ colour *pixel = (colour *)bitmap->pixdata;
+ colour abpixel; /* alphablended pixel */
+ int xloop, yloop;
+ int x0,y0,x1,y1;
+ int xoff, yoff; /* x and y offset into image */
+
+ /* LOG(("x %d, y %d, width %d, height %d, bitmap %p, content %p",
+ x,y,width,height,bitmap,content));*/
+
+ /* TODO here we should scale the image from bitmap->width to width, for
+ * now simply crop.
+ */
+ if (width > bitmap->width)
+ width = bitmap->width;
+
+ if (height > bitmap->height)
+ height = bitmap->height;
+
+ /* The part of the scaled image actually displayed is cropped to the
+ * current context.
+ */
+ x0 = x;
+ y0 = y;
+ x1 = x + width;
+ y1 = y + height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true;
+
+ if (height > (y1 - y0))
+ height = (y1 - y0);
+
+ if (width > (x1 - x0))
+ width = (x1 - x0);
+
+ xoff = x0 - x;
+ yoff = (y0 - y) * bitmap->width;
+ height = height * bitmap->width + yoff;
+
+ /* plot the image */
+ pvideo = fb_8bpp_get_xy_loc(x0, y0);
+
+ if (bitmap->opaque) {
+ for (yloop = yoff; yloop < height; yloop += bitmap->width) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = pixel[yloop + xloop + xoff];
+ *(pvideo + xloop) = fb_colour_to_pixel(abpixel);
+ }
+ pvideo += framebuffer->linelen;
+ }
+ } else {
+ for (yloop = yoff; yloop < height; yloop += bitmap->width) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = pixel[yloop + xloop + xoff];
+ if ((abpixel & 0xFF000000) != 0) {
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = fb_plotters_ablend(abpixel,
+ fb_8bpp_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = fb_colour_to_pixel(abpixel);
+ }
+ }
+ pvideo += framebuffer->linelen;
+ }
+ }
+
+ return true;
+}
+
+static bool fb_8bpp_bitmap_tile(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bool repeat_x, bool repeat_y,
+ struct content *content)
+{
+ return fb_plotters_bitmap_tile(x, y, width, height,
+ bitmap, bg, repeat_x, repeat_y,
+ content, fb_8bpp_bitmap);
+}
+
+static bool fb_8bpp_flush(void)
+{
+ LOG(("%s()\n", __func__));
+ return true;
+}
+
+static bool fb_8bpp_path(const float *p,
+ unsigned int n,
+ colour fill,
+ float width,
+ colour c,
+ const float transform[6])
+{
+ LOG(("%f, %d, 0x%lx, %f, 0x%lx, %f",
+ *p, n, (unsigned long)fill, width, (unsigned long)c, *transform));
+
+ return true;
+}
+
+const struct plotter_table framebuffer_8bpp_plot = {
+ .clg = fb_8bpp_clg,
+ .rectangle = fb_8bpp_rectangle,
+ .line = fb_8bpp_line,
+ .polygon = fb_8bpp_polygon,
+ .fill = fb_8bpp_fill,
+ .clip = fb_clip,
+ .text = fb_8bpp_text,
+ .disc = fb_8bpp_disc,
+ .arc = fb_8bpp_arc,
+ .bitmap = fb_8bpp_bitmap,
+ .bitmap_tile = fb_8bpp_bitmap_tile,
+ .flush = fb_8bpp_flush,
+ .path = fb_8bpp_path,
+ .option_knockout = true,
+};
+
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/src/32bpp_plotters.c b/src/32bpp_plotters.c
new file mode 100644
index 0000000..eb6d162
--- /dev/null
+++ b/src/32bpp_plotters.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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/>.
+ */
+
+#include <stdbool.h>
+#include <endian.h>
+#include <stdlib.h>
+
+#include "libnsfb.h"
+#include "nsfb.h"
+#include "nsfb_plot.h"
+#include "plotters.h"
+#include "plot_util.h"
+
+/* global plot context */
+extern nsfb_t *_plot_nsfb;
+
+static inline uint32_t *
+get_xy_loc(nsfb_t *nsfb, int x, int y)
+{
+ return (uint32_t *)(nsfb->ptr + (y * nsfb->linelen) + (x << 2));
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static inline nsfb_colour_t pixel_to_colour(uint32_t pixel)
+{
+ return (pixel >> 8) & ~0xFF000000U;
+}
+
+/* convert a colour value to a 32bpp pixel value ready for screen output */
+static inline uint32_t colour_to_pixel(nsfb_colour_t c)
+{
+ return (c << 8);
+}
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+static inline nsfb_colour_t pixel_to_colour(uint32_t pixel)
+{
+ return ((pixel & 0xFF) << 16) |
+ ((pixel & 0xFF00)) |
+ ((pixel & 0xFF0000) >> 16);
+}
+
+/* convert a colour value to a 32bpp pixel value ready for screen output */
+static inline uint32_t colour_to_pixel(nsfb_colour_t c)
+{
+ return ((c & 0xff0000) >> 16) | (c & 0xff00) | ((c & 0xff) << 16);
+}
+#endif
+
+#define SIGN(x) ((x<0) ? -1 : ((x>0) ? 1 : 0))
+
+static bool
+line(nsfb_t *nsfb,
+ nsfb_bbox_t *line,
+ int line_width,
+ nsfb_colour_t c,
+ bool dotted,
+ bool dashed)
+{
+ int w;
+ uint32_t ent;
+ uint32_t *pvideo;
+ int x, y, i;
+ int dx, dy, sdy;
+ int dxabs, dyabs;
+
+ line_width = line_width;
+ dotted = dotted;
+ dashed = dashed;
+
+ ent = colour_to_pixel(c);
+
+ if (line->y0 == line->y1) {
+ /* horizontal line special cased */
+ if (!nsfb_plot_clip_ctx(nsfb, line))
+ return true; /* line outside clipping */
+
+ pvideo = get_xy_loc(nsfb, line->x0, line->y0);
+
+ w = line->x1 - line->x0;
+ while (w-- > 0)
+ *(pvideo + w) = ent;
+
+ return true;
+ } else {
+ /* standard bresenham line */
+ if (!nsfb_plot_clip_line_ctx(nsfb, line))
+ return true; /* line outside clipping */
+
+ /* the horizontal distance of the line */
+ dx = line->x1 - line->x0;
+ dxabs = abs (dx);
+
+ /* the vertical distance of the line */
+ dy = line->y1 - line->y0;
+ dyabs = abs (dy);
+
+ sdy = dx ? SIGN(dy) * SIGN(dx) : SIGN(dy);
+
+ if (dx >= 0)
+ pvideo = get_xy_loc(nsfb, line->x0, line->y0);
+ else
+ pvideo = get_xy_loc(nsfb, line->x1, line->y1);
+
+ x = dyabs >> 1;
+ y = dxabs >> 1;
+
+ if (dxabs >= dyabs) {
+ /* the line is more horizontal than vertical */
+ for (i = 0; i < dxabs; i++) {
+ *pvideo = ent;
+
+ pvideo++;
+ y += dyabs;
+ if (y >= dxabs) {
+ y -= dxabs;
+ pvideo += sdy * (nsfb->linelen>>2);
+ }
+ }
+ } else {
+ /* the line is more vertical than horizontal */
+ for (i = 0; i < dyabs; i++) {
+ *pvideo = ent;
+ pvideo += sdy * (nsfb->linelen >> 2);
+
+ x += dxabs;
+ if (x >= dyabs) {
+ x -= dyabs;
+ pvideo++;
+ }
+ }
+ }
+
+ }
+
+ return true;
+}
+
+
+
+static bool fill(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t c)
+{
+ int w;
+ uint32_t *pvid;
+ uint32_t ent;
+ uint32_t llen;
+ uint32_t width;
+ uint32_t height;
+
+ if (!nsfb_plot_clip_ctx(nsfb, rect))
+ return true; /* fill lies outside current clipping region */
+
+ ent = colour_to_pixel(c);
+ width = rect->x1 - rect->x0;
+ height = rect->y1 - rect->y0;
+ llen = (nsfb->linelen >> 2) - width;
+
+ pvid = get_xy_loc(nsfb, rect->x0, rect->y0);
+
+ while (height-- > 0) {
+ w = width;
+ while (w >= 16) {
+ *pvid++ = ent; *pvid++ = ent;
+ *pvid++ = ent; *pvid++ = ent;
+ *pvid++ = ent; *pvid++ = ent;
+ *pvid++ = ent; *pvid++ = ent;
+ *pvid++ = ent; *pvid++ = ent;
+ *pvid++ = ent; *pvid++ = ent;
+ *pvid++ = ent; *pvid++ = ent;
+ *pvid++ = ent; *pvid++ = ent;
+ w-=16;
+ }
+ while (w >= 4) {
+ *pvid++ = ent; *pvid++ = ent;
+ *pvid++ = ent; *pvid++ = ent;
+ w-=4;
+ }
+ while (w > 0) {
+ *pvid++ = ent;
+ w--;
+ }
+ pvid += llen;
+ }
+
+ return true;
+}
+
+
+
+
+static bool point(nsfb_t *nsfb, int x, int y, nsfb_colour_t c)
+{
+ uint32_t *pvideo;
+
+ /* check point lies within clipping region */
+ if ((x < nsfb->clip.x0) ||
+ (x >= nsfb->clip.x1) ||
+ (y < nsfb->clip.y0) ||
+ (y >= nsfb->clip.y1))
+ return true;
+
+ pvideo = get_xy_loc(nsfb, x, y);
+
+ if ((c & 0xFF000000) != 0) {
+ if ((c & 0xFF000000) != 0xFF000000) {
+ c = nsfb_plot_ablend(c, pixel_to_colour(*pvideo));
+ }
+
+ *pvideo = colour_to_pixel(c);
+ }
+ return true;
+}
+
+static bool
+bitmap(nsfb_t *nsfb,
+ nsfb_bbox_t *loc,
+ nsfb_colour_t *pixel,
+ int bmp_width,
+ int bmp_height,
+ int bmp_stride,
+ bool alpha)
+{
+ uint32_t *pvideo;
+ nsfb_colour_t abpixel = 0; /* alphablended pixel */
+ int xloop, yloop;
+ int xoff, yoff; /* x and y offset into image */
+ int x = loc->x0;
+ int y = loc->y0;
+ int width = loc->x1 - loc->x0;
+ int height = loc->y1 - loc->y0;
+ nsfb_bbox_t clipped; /* clipped display */
+
+ /* TODO here we should scale the image from bmp_width to width, for
+ * now simply crop.
+ */
+ if (width > bmp_width)
+ width = bmp_width;
+
+ if (height > bmp_height)
+ height = bmp_height;
+
+ /* The part of the scaled image actually displayed is cropped to the
+ * current context.
+ */
+ clipped.x0 = x;
+ clipped.y0 = y;
+ clipped.x1 = x + width;
+ clipped.y1 = y + height;
+
+ if (!nsfb_plot_clip_ctx(nsfb, &clipped))
+ return true;
+
+ if (height > (clipped.y1 - clipped.y0))
+ height = (clipped.y1 - clipped.y0);
+
+ if (width > (clipped.x1 - clipped.x0))
+ width = (clipped.x1 - clipped.x0);
+
+ xoff = clipped.x0 - x;
+ yoff = (clipped.y0 - y) * bmp_width;
+ height = height * bmp_stride + yoff;
+
+ /* plot the image */
+ pvideo = get_xy_loc(nsfb, clipped.x0, clipped.y0);
+
+ if (alpha) {
+ for (yloop = yoff; yloop < height; yloop += bmp_stride) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = pixel[yloop + xloop + xoff];
+ if ((abpixel & 0xFF000000) != 0) {
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = nsfb_plot_ablend(abpixel,
+ pixel_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = colour_to_pixel(abpixel);
+ }
+ }
+ pvideo += (nsfb->linelen >> 2);
+ }
+ } else {
+ for (yloop = yoff; yloop < height; yloop += bmp_stride) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = pixel[yloop + xloop + xoff];
+ *(pvideo + xloop) = colour_to_pixel(abpixel);
+ }
+ pvideo += (nsfb->linelen >> 2);
+ }
+ }
+ return true;
+}
+
+
+
+const nsfb_plotter_fns_t _nsfb_32bpp_plotters = {
+ .line = line,
+ .fill = fill,
+ .point = point,
+ .bitmap = bitmap,
+};
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/src/8bpp_plotters.c b/src/8bpp_plotters.c
new file mode 100644
index 0000000..777b896
--- /dev/null
+++ b/src/8bpp_plotters.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2008 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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/>.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+
+#include "utils/log.h"
+#include "utils/utf8.h"
+#include "desktop/plotters.h"
+
+#include "framebuffer/fb_gui.h"
+#include "framebuffer/fb_plotters.h"
+#include "framebuffer/fb_bitmap.h"
+#include "framebuffer/fb_font.h"
+
+static inline uint8_t *
+fb_8bpp_get_xy_loc(int x, int y)
+{
+ return (uint8_t *)(framebuffer->ptr +
+ (y * framebuffer->linelen) +
+ (x));
+}
+
+
+static bool fb_8bpp_line(int x0, int y0, int x1, int y1, int width,
+ colour c, bool dotted, bool dashed)
+{
+ LOG(("%d, %d, %d, %d, %d, 0x%lx, %d, %d",
+ x0, y0, x1, y1, width, (unsigned long)c, dotted, dashed));
+
+ return true;
+}
+
+static bool fb_8bpp_rectangle(int x0, int y0, int width, int height,
+ int line_width, colour c, bool dotted, bool dashed)
+{
+ fb_8bpp_line(x0, y0, x0 + width, y0, line_width, c, dotted, dashed);
+ fb_8bpp_line(x0, y0 + height, x0 + width, y0 + height, line_width, c, dotted, dashed);
+ fb_8bpp_line(x0, y0, x0, y0 + height, line_width, c, dotted, dashed);
+ fb_8bpp_line(x0 + width, y0, x0 + width, y0 + height, line_width, c, dotted, dashed);
+ return true;
+}
+
+static bool fb_8bpp_polygon(const int *p, unsigned int n, colour fill)
+{
+ /*LOG(("%p, %d, 0x%lx", p,n,fill));*/
+ return fb_plotters_polygon(p, n, fill, fb_8bpp_line);
+}
+
+static colour calc_colour(uint8_t c)
+{
+ return framebuffer->palette[c];
+}
+
+
+static int
+find_closest_palette_entry(colour c)
+{
+ colour palent;
+ int col;
+
+ int dr, dg, db; /* delta red, green blue values */
+
+ int cur_distance;
+ int best_distance = INT_MAX;
+ int best_col = 0;
+
+ for (col = 0; col < 256; col++) {
+ palent = framebuffer->palette[col];
+
+ dr = (c & 0xFF) - (palent & 0xFF);
+ dg = ((c >> 8) & 0xFF) - ((palent >> 8) & 0xFF);
+ db = ((c >> 16) & 0xFF) - ((palent >> 16) & 0xFF);
+ cur_distance = ((dr * dr) + (dg * dg) + (db *db));
+ if (cur_distance < best_distance) {
+ best_distance = cur_distance;
+ best_col = col;
+ }
+ }
+
+ return best_col;
+}
+
+static inline uint8_t fb_colour_to_pixel(colour c)
+{
+ return find_closest_palette_entry(c);
+}
+
+static inline colour fb_8bpp_to_colour(uint8_t pixel)
+{
+ return framebuffer->palette[pixel];
+}
+
+static bool fb_8bpp_fill(int x0, int y0, int x1, int y1, colour c)
+{
+ int y;
+ uint8_t ent;
+ uint8_t *pvideo;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true; /* fill lies outside current clipping region */
+
+ pvideo = fb_8bpp_get_xy_loc(x0, y0);
+
+ ent = find_closest_palette_entry(c);
+
+ for (y = y0; y < y1; y++) {
+ memset(pvideo, ent, x1 - x0);
+ pvideo += framebuffer->linelen;
+ }
+
+ return true;
+}
+
+static bool fb_8bpp_clg(colour c)
+{
+ LOG(("colour %lx", (unsigned long)c));
+ fb_8bpp_fill(fb_plot_ctx.x0,
+ fb_plot_ctx.y0,
+ fb_plot_ctx.x1,
+ fb_plot_ctx.y1,
+ c);
+ return true;
+}
+
+#ifdef FB_USE_FREETYPE
+
+static bool
+fb_8bpp_draw_ft_monobitmap(FT_Bitmap *bp, int x, int y, colour c)
+{
+ return false;
+}
+
+static bool
+fb_8bpp_draw_ft_bitmap(FT_Bitmap *bp, int x, int y, colour c)
+{
+ uint8_t *pvideo;
+ uint8_t *pixel = (uint8_t *)bp->buffer;
+ colour abpixel; /* alphablended pixel */
+ int xloop, yloop;
+ int x0,y0,x1,y1;
+ int xoff, yoff; /* x and y offset into image */
+ int height = bp->rows;
+ int width = bp->width;
+ uint32_t fgcol;
+
+ /* The part of the scaled image actually displayed is cropped to the
+ * current context.
+ */
+ x0 = x;
+ y0 = y;
+ x1 = x + width;
+ y1 = y + height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true;
+
+ if (height > (y1 - y0))
+ height = (y1 - y0);
+
+ if (width > (x1 - x0))
+ width = (x1 - x0);
+
+ xoff = x0 - x;
+ yoff = y0 - y;
+
+ /* plot the image */
+ pvideo = fb_8bpp_get_xy_loc(x0, y0);
+
+ fgcol = c & 0xFFFFFF;
+
+ for (yloop = 0; yloop < height; yloop++) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = (pixel[((yoff + yloop) * bp->pitch) + xloop + xoff] << 24) | fgcol;
+ if ((abpixel & 0xFF000000) != 0) {
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = fb_plotters_ablend(abpixel,
+ fb_8bpp_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = fb_colour_to_pixel(abpixel);
+
+ }
+ }
+ pvideo += framebuffer->linelen;
+ }
+
+ return true;
+}
+
+static bool fb_8bpp_text(int x, int y, const struct css_style *style,
+ const char *text, size_t length, colour bg, colour c)
+{
+ uint32_t ucs4;
+ size_t nxtchr = 0;
+ FT_Glyph glyph;
+ FT_BitmapGlyph bglyph;
+
+ while (nxtchr < length) {
+ ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr);
+ nxtchr = utf8_next(text, length, nxtchr);
+
+ glyph = fb_getglyph(style, ucs4);
+ if (glyph == NULL)
+ continue;
+ if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
+ bglyph = (FT_BitmapGlyph)glyph;
+
+ /* now, draw to our target surface */
+ if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
+ fb_8bpp_draw_ft_monobitmap(&bglyph->bitmap,
+ x + bglyph->left,
+ y - bglyph->top,
+ c);
+ } else {
+ fb_8bpp_draw_ft_bitmap(&bglyph->bitmap,
+ x + bglyph->left,
+ y - bglyph->top,
+ c);
+ }
+ }
+ x += glyph->advance.x >> 16;
+
+ }
+ return true;
+
+}
+#else
+static bool fb_8bpp_text(int x, int y, const struct css_style *style,
+ const char *text, size_t length, colour bg, colour c)
+{
+ const struct fb_font_desc* fb_font = fb_get_font(style);
+ const uint32_t *font_data;
+ uint32_t row;
+
+ int xloop, yloop;
+ size_t chr;
+
+ uint8_t *pvideo;
+ uint8_t fgcol;
+
+ unsigned char *buffer = NULL;
+ int x0,y0,x1,y1;
+ int xoff, yoff; /* x and y offset into image */
+ int height = fb_font->height;
+
+ /* aquire thge text in local font encoding */
+ utf8_to_font_encoding(fb_font, text, length, (char **)&buffer);
+ if (!buffer)
+ return true;
+ length = strlen((char *)buffer);
+
+
+ /* y is given to the fonts baseline we need it to the fonts top */
+ y-=((fb_font->height * 75)/100);
+
+ y+=1; /* the coord is the bottom-left of the pixels offset by 1 to make
+ * it work since fb coords are the top-left of pixels
+ */
+
+ /* The part of the text displayed is cropped to the current context. */
+ x0 = x;
+ y0 = y;
+ x1 = x + (fb_font->width * length);
+ y1 = y + fb_font->height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true; /* text lies outside current clipping region */
+
+ /* find width and height to plot */
+ if (height > (y1 - y0))
+ height = (y1 - y0);
+
+ xoff = x0 - x;
+ yoff = y0 - y;
+
+ fgcol = find_closest_palette_entry(c);
+
+ /*LOG(("x %d, y %d, style %p, txt %.*s , len %d, bg 0x%lx, fg 0x%lx",
+ x,y,style,length,text,length,bg,c));*/
+
+ for (chr = 0; chr < length; chr++, x += fb_font->width) {
+ if ((x + fb_font->width) > x1)
+ break;
+
+ if (x < x0)
+ continue;
+
+ pvideo = fb_8bpp_get_xy_loc(x, y0);
+
+ /* move our font-data to the correct position */
+ font_data = fb_font->data + (buffer[chr] * fb_font->height);
+
+ for (yloop = 0; yloop < height; yloop++) {
+ row = font_data[yoff + yloop];
+ for (xloop = fb_font->width; xloop > 0 ; xloop--) {
+ if ((row & 1) != 0)
+ *(pvideo + xloop) = fgcol;
+ row = row >> 1;
+ }
+ pvideo += framebuffer->linelen;
+ }
+ }
+
+ free(buffer);
+ return true;
+}
+#endif
+
+static bool fb_8bpp_disc(int x, int y, int radius, colour c, bool filled)
+{
+ LOG(("x %d, y %d, rad %d, c 0x%lx, fill %d", x, y, radius, (unsigned long)c, filled));
+ return true;
+}
+
+static bool fb_8bpp_arc(int x, int y, int radius, int angle1, int angle2,
+ colour c)
+{
+ LOG(("x %d, y %d, radius %d, angle1 %d, angle2 %d, c 0x%lx",
+ x, y, radius, angle1, angle2, (unsigned long)c));
+ return true;
+}
+
+
+
+static bool fb_8bpp_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ struct content *content)
+{
+ uint8_t *pvideo;
+ colour *pixel = (colour *)bitmap->pixdata;
+ colour abpixel; /* alphablended pixel */
+ int xloop, yloop;
+ int x0,y0,x1,y1;
+ int xoff, yoff; /* x and y offset into image */
+
+ /* LOG(("x %d, y %d, width %d, height %d, bitmap %p, content %p",
+ x,y,width,height,bitmap,content));*/
+
+ /* TODO here we should scale the image from bitmap->width to width, for
+ * now simply crop.
+ */
+ if (width > bitmap->width)
+ width = bitmap->width;
+
+ if (height > bitmap->height)
+ height = bitmap->height;
+
+ /* The part of the scaled image actually displayed is cropped to the
+ * current context.
+ */
+ x0 = x;
+ y0 = y;
+ x1 = x + width;
+ y1 = y + height;
+
+ if (!fb_plotters_clip_rect_ctx(&x0, &y0, &x1, &y1))
+ return true;
+
+ if (height > (y1 - y0))
+ height = (y1 - y0);
+
+ if (width > (x1 - x0))
+ width = (x1 - x0);
+
+ xoff = x0 - x;
+ yoff = (y0 - y) * bitmap->width;
+ height = height * bitmap->width + yoff;
+
+ /* plot the image */
+ pvideo = fb_8bpp_get_xy_loc(x0, y0);
+
+ if (bitmap->opaque) {
+ for (yloop = yoff; yloop < height; yloop += bitmap->width) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = pixel[yloop + xloop + xoff];
+ *(pvideo + xloop) = fb_colour_to_pixel(abpixel);
+ }
+ pvideo += framebuffer->linelen;
+ }
+ } else {
+ for (yloop = yoff; yloop < height; yloop += bitmap->width) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = pixel[yloop + xloop + xoff];
+ if ((abpixel & 0xFF000000) != 0) {
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = fb_plotters_ablend(abpixel,
+ fb_8bpp_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = fb_colour_to_pixel(abpixel);
+ }
+ }
+ pvideo += framebuffer->linelen;
+ }
+ }
+
+ return true;
+}
+
+static bool fb_8bpp_bitmap_tile(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bool repeat_x, bool repeat_y,
+ struct content *content)
+{
+ return fb_plotters_bitmap_tile(x, y, width, height,
+ bitmap, bg, repeat_x, repeat_y,
+ content, fb_8bpp_bitmap);
+}
+
+static bool fb_8bpp_flush(void)
+{
+ LOG(("%s()\n", __func__));
+ return true;
+}
+
+static bool fb_8bpp_path(const float *p,
+ unsigned int n,
+ colour fill,
+ float width,
+ colour c,
+ const float transform[6])
+{
+ LOG(("%f, %d, 0x%lx, %f, 0x%lx, %f",
+ *p, n, (unsigned long)fill, width, (unsigned long)c, *transform));
+
+ return true;
+}
+
+const struct plotter_table framebuffer_8bpp_plot = {
+ .clg = fb_8bpp_clg,
+ .rectangle = fb_8bpp_rectangle,
+ .line = fb_8bpp_line,
+ .polygon = fb_8bpp_polygon,
+ .fill = fb_8bpp_fill,
+ .clip = fb_clip,
+ .text = fb_8bpp_text,
+ .disc = fb_8bpp_disc,
+ .arc = fb_8bpp_arc,
+ .bitmap = fb_8bpp_bitmap,
+ .bitmap_tile = fb_8bpp_bitmap_tile,
+ .flush = fb_8bpp_flush,
+ .path = fb_8bpp_path,
+ .option_knockout = true,
+};
+
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..5220060
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,6 @@
+# Sources
+DIR_SOURCES := libnsfb.c frontend.c frontend_sdl.c plot.c plot_util.c plotters.c 32bpp_plotters.c
+
+#frontend_linux.c
+
+include build/makefiles/Makefile.subdir
diff --git a/src/frontend.c b/src/frontend.c
new file mode 100644
index 0000000..171a7f3
--- /dev/null
+++ b/src/frontend.c
@@ -0,0 +1,98 @@
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <string.h>
+
+#include "frontend.h"
+#include "plotters.h"
+
+#define MAX_FRONTENDS 16
+
+struct nsfb_frontend_s {
+ enum nsfb_frontend_e type;
+ const nsfb_frontend_rtns_t *rtns;
+ const char *name;
+};
+
+static struct nsfb_frontend_s frontends[MAX_FRONTENDS];
+static int frontend_count = 0;
+
+/* internal routine which lets frontends register their presence at runtime */
+void _nsfb_register_frontend(const enum nsfb_frontend_e type,
+ const nsfb_frontend_rtns_t *rtns,
+ const char *name)
+{
+ if (frontend_count >= MAX_FRONTENDS)
+ return; /* no space for additional frontends */
+
+ frontends[frontend_count].type = type;
+ frontends[frontend_count].rtns = rtns;
+ frontends[frontend_count].name = name;
+ frontend_count++;
+}
+
+/* default frontend implementations */
+static int frontend_defaults(nsfb_t *nsfb)
+{
+ nsfb->width = 800;
+ nsfb->height = 600;
+ nsfb->bpp = 32;
+
+ /* select plotters for bpp */
+ select_plotters(nsfb);
+
+ return 0;
+}
+
+static int frontend_claim(nsfb_t *nsfb, nsfb_bbox_t *box)
+{
+ nsfb=nsfb;
+ box=box;
+ return 0;
+}
+
+static int frontend_release(nsfb_t *nsfb, nsfb_bbox_t *box)
+{
+ nsfb=nsfb;
+ box=box;
+ return 0;
+}
+
+nsfb_frontend_rtns_t *nsfb_frontend_get_rtns(enum nsfb_frontend_e type)
+{
+ int fend_loop;
+ nsfb_frontend_rtns_t *rtns = NULL;
+
+ for (fend_loop = 0; fend_loop < frontend_count; fend_loop++) {
+ if (frontends[fend_loop].type == type) {
+ rtns = malloc(sizeof(nsfb_frontend_rtns_t));
+ memcpy(rtns,
+ frontends[fend_loop].rtns,
+ sizeof(nsfb_frontend_rtns_t));
+
+ /* frontend must have an initialisor, finaliser and input method */
+ if ((rtns->initialise == NULL) ||
+ (rtns->finalise == NULL) ||
+ (rtns->input == NULL) ) {
+ free(rtns);
+ rtns = NULL;
+ }
+
+ /* The rest may be empty but to avoid the null check every time
+ * provide default implementations.
+ */
+ if (rtns->defaults == NULL)
+ rtns->defaults = frontend_defaults;
+
+ if (rtns->claim == NULL)
+ rtns->claim = frontend_claim;
+
+ if (rtns->release == NULL)
+ rtns->release = frontend_release;
+
+ break;
+ }
+ }
+ return rtns;
+}
diff --git a/src/frontend_linux.c b/src/frontend_linux.c
new file mode 100644
index 0000000..ad95542
--- /dev/null
+++ b/src/frontend_linux.c
@@ -0,0 +1,9 @@
+#include "libnsfb.h"
+#include "nsfb.h"
+#include "frontend.h"
+
+const nsfb_frontend_rtns_t linux_rtns = {
+ .foo = 2,
+};
+
+NSFB_FRONTEND_DEF(linux, NSFB_FRONTEND_LINUX, &linux_rtns)
diff --git a/src/frontend_sdl.c b/src/frontend_sdl.c
new file mode 100644
index 0000000..a9da09e
--- /dev/null
+++ b/src/frontend_sdl.c
@@ -0,0 +1,105 @@
+
+#include <SDL/SDL.h>
+
+#include "libnsfb.h"
+#include "nsfb.h"
+#include "frontend.h"
+
+static void
+set_palette(nsfb_t *nsfb)
+{
+ SDL_Surface *sdl_screen = nsfb->frontend_priv;
+ SDL_Color colors[256];
+ int loop;
+ for(loop=0; loop < 256; loop++){
+ colors[loop].r = loop;
+ colors[loop].g = loop;
+ colors[loop].b = loop;
+ nsfb->palette[loop] = loop << 16 | loop << 8 | loop;
+ }
+
+ /* Set palette */
+ SDL_SetColors(sdl_screen, colors, 0, 256);
+
+}
+
+static int sdl_initialise(nsfb_t *nsfb)
+{
+ SDL_Surface *sdl_screen;
+
+ if (nsfb->frontend_priv != NULL)
+ return -1;
+
+ /* sanity checked depth. */
+ if ((nsfb->bpp != 32) && (nsfb->bpp != 16) && (nsfb->bpp != 8))
+ nsfb->bpp = 16;
+
+ /* initialise SDL library */
+ if (SDL_Init(SDL_INIT_VIDEO) < 0 ) {
+ fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
+ return -1;
+ }
+ atexit(SDL_Quit);
+
+ sdl_screen = SDL_SetVideoMode(nsfb->width,
+ nsfb->height,
+ nsfb->bpp,
+ SDL_SWSURFACE);
+
+ if (sdl_screen == NULL ) {
+ fprintf(stderr, "Unable to set video: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ nsfb->frontend_priv = sdl_screen;
+
+ if (nsfb->bpp == 8)
+ set_palette(nsfb);
+
+ nsfb->ptr = sdl_screen->pixels;
+ nsfb->linelen = sdl_screen->pitch;
+
+ SDL_ShowCursor(SDL_DISABLE);
+
+ return 0;
+}
+
+static int sdl_finalise(nsfb_t *nsfb)
+{
+ nsfb=nsfb;
+ return 0;
+}
+
+static int sdl_input(nsfb_t *nsfb)
+{
+ int got_event;
+ SDL_Event event;
+
+ got_event = SDL_WaitEvent(&event);
+ if (event.type == SDL_QUIT)
+ exit(0);
+ nsfb=nsfb;
+ return 1;
+}
+
+static int sdl_release(nsfb_t *nsfb, nsfb_bbox_t *box)
+{
+ SDL_Surface *sdl_screen = nsfb->frontend_priv;
+
+ SDL_UpdateRect(sdl_screen,
+ box->x0,
+ box->y0,
+ box->x1 - box->x0,
+ box->y1 - box->y0);
+
+ return 0;
+}
+
+const nsfb_frontend_rtns_t sdl_rtns = {
+ .initialise = sdl_initialise,
+ .finalise = sdl_finalise,
+ .input = sdl_input,
+ .release = sdl_release,
+};
+
+NSFB_FRONTEND_DEF(sdl, NSFB_FRONTEND_SDL, &sdl_rtns)
diff --git a/src/libnsfb.c b/src/libnsfb.c
new file mode 100644
index 0000000..ec6ba86
--- /dev/null
+++ b/src/libnsfb.c
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <malloc.h>
+
+#include "libnsfb.h"
+#include "nsfb.h"
+#include "frontend.h"
+
+
+/* documented in libnsfb.h */
+nsfb_t*
+nsfb_init(const enum nsfb_frontend_e frontend_type)
+{
+ nsfb_t *newfb;
+ newfb = calloc(1, sizeof(nsfb_t));
+ if (newfb == NULL)
+ return NULL;
+
+ /* obtain frontend routines */
+ newfb->frontend_rtns = nsfb_frontend_get_rtns(frontend_type);
+ if (newfb->frontend_rtns == NULL) {
+ free(newfb);
+ return NULL;
+ }
+
+ newfb->frontend_rtns->defaults(newfb);
+
+ return newfb;
+}
+
+
+int
+nsfb_init_frontend(nsfb_t *nsfb)
+{
+ return nsfb->frontend_rtns->initialise(nsfb);
+}
+
+int nsfb_input(nsfb_t *nsfb)
+{
+ return nsfb->frontend_rtns->input(nsfb);
+}
+
+int nsfb_claim(nsfb_t *nsfb, nsfb_bbox_t *box)
+{
+ return nsfb->frontend_rtns->claim(nsfb, box);
+}
+
+int nsfb_release(nsfb_t *nsfb, nsfb_bbox_t *box)
+{
+ return nsfb->frontend_rtns->release(nsfb, box);
+}
+
+int nsfb_get_geometry(nsfb_t *nsfb, int *width, int *height, int *bpp)
+{
+ if (width != NULL)
+ *width = nsfb->width;
+
+ if (height != NULL)
+ *height = nsfb->height;
+
+ if (bpp != NULL)
+ *bpp = nsfb->bpp;
+
+ return 0;
+}
+
+int nsfb_get_framebuffer(nsfb_t *nsfb, uint8_t **ptr, int *linelen)
+{
+ *ptr = nsfb->ptr;
+ *linelen = nsfb->linelen;
+ return 0;
+}
diff --git a/src/plot.c b/src/plot.c
new file mode 100644
index 0000000..8f46cfe
--- /dev/null
+++ b/src/plot.c
@@ -0,0 +1,114 @@
+/* public plotter interface */
+
+#include <stdbool.h>
+
+#include "libnsfb.h"
+#include "libnsfb_plot.h"
+#include "nsfb.h"
+#include "nsfb_plot.h"
+
+/** Sets a clip rectangle for subsequent plots.
+ *
+ * Sets a clipping area which constrains all subsequent plotting operations.
+ * The clipping area must lie within the framebuffer visible screen or false
+ * will be returned and the new clipping area not set.
+ */
+bool nsfb_plot_set_clip(nsfb_t *nsfb, nsfb_bbox_t *clip)
+{
+ return nsfb->plotter_fns->clip(nsfb, clip);
+}
+
+/** Clears plotting area to a flat colour.
+ */
+bool nsfb_plot_clg(nsfb_t *nsfb, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->clg(nsfb, c);
+}
+
+/** Plots a rectangle outline.
+ *
+ * The line can be solid, dotted or dashed. Top left corner at (x0,y0) and
+ * rectangle has given width and height.
+ */
+bool
+nsfb_plot_rectangle(nsfb_t *nsfb,
+ nsfb_bbox_t *rect,
+ int line_width,
+ nsfb_colour_t c,
+ bool dotted,
+ bool dashed)
+{
+ return nsfb->plotter_fns->rectangle(nsfb, rect, line_width, c, dotted, dashed);
+
+}
+
+/** Plots a filled rectangle. Top left corner at (x0,y0), bottom
+ * right corner at (x1,y1). Note: (x0,y0) is inside filled area,
+ * but (x1,y1) is below and to the right. See diagram below.
+ */
+bool nsfb_plot_rectangle_fill(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->fill(nsfb, rect, c);
+}
+
+/** Plots a line.
+ *
+ * Draw a line from (x0,y0) to (x1,y1). Coordinates are at centre of line
+ * width/thickness.
+ */
+bool nsfb_plot_line(nsfb_t *nsfb, nsfb_bbox_t *line, int line_width, nsfb_colour_t c, bool dotted, bool dashed)
+{
+ return nsfb->plotter_fns->line(nsfb, line, line_width, c, dotted, dashed);
+}
+
+/** Plots a filled polygon.
+ *
+ * Plots a filled polygon with straight lines between points. The lines around
+ * the edge of the ploygon are not plotted. The polygon is filled with a
+ * non-zero winding rule.
+ *
+ *
+ */
+bool nsfb_plot_polygon(nsfb_t *nsfb, const int *p, unsigned int n, nsfb_colour_t fill)
+{
+ return nsfb->plotter_fns->polygon(nsfb, p, n, fill);
+}
+
+/** Plots an arc.
+ *
+ * around (x,y), from anticlockwise from angle1 to angle2. Angles are measured
+ * anticlockwise from horizontal, in degrees.
+ */
+bool nsfb_plot_arc(nsfb_t *nsfb, int x, int y, int radius, int angle1, int angle2, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->arc(nsfb, x, y, radius, angle1, angle2, c);
+}
+
+/** Plots an alpha blended pixel.
+ *
+ * plots an alpha blended pixel.
+ */
+bool nsfb_plot_point(nsfb_t *nsfb, int x, int y, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->point(nsfb, x, y, c);
+}
+
+bool nsfb_plot_ellipse(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->ellipse(nsfb, ellipse, c);
+}
+
+bool nsfb_plot_ellipse_fill(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->ellipse_fill(nsfb, ellipse, c);
+}
+
+bool nsfb_plot_copy(nsfb_t *nsfb, int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ return nsfb->plotter_fns->copy(nsfb, srcx, srcy, width, height, dstx, dsty);
+}
+
+bool nsfb_plot_bitmap(nsfb_t *nsfb, nsfb_bbox_t *loc, nsfb_colour_t *pixel, int bmp_width, int bmp_height, int bmp_stride, bool alpha)
+{
+ return nsfb->plotter_fns->bitmap(nsfb, loc, pixel, bmp_width, bmp_height, bmp_stride, alpha);
+}
diff --git a/src/plot_util.c b/src/plot_util.c
new file mode 100644
index 0000000..058a0f9
--- /dev/null
+++ b/src/plot_util.c
@@ -0,0 +1,150 @@
+#include <stdbool.h>
+
+#include "libnsfb.h"
+#include "nsfb.h"
+#include "plot_util.h"
+
+enum {
+ POINT_LEFTOF_REGION = 1,
+ POINT_RIGHTOF_REGION = 2,
+ POINT_ABOVE_REGION = 4,
+ POINT_BELOW_REGION = 8,
+};
+
+#define REGION(x,y,cx1,cx2,cy1,cy2) \
+ ( ( (y) > (cy2) ? POINT_BELOW_REGION : 0) | \
+ ( (y) < (cy1) ? POINT_ABOVE_REGION : 0) | \
+ ( (x) > (cx2) ? POINT_RIGHTOF_REGION : 0) | \
+ ( (x) < (cx1) ? POINT_LEFTOF_REGION : 0) )
+
+#define SWAP(a, b) do { int t; t=(a); (a)=(b); (b)=t; } while(0)
+
+/* clip a rectangle with another clipping rectangle.
+ *
+ * @param clip The rectangle to clip to.
+ * @param rect The rectangle to clip.
+ * @return false if the \a rect lies completely outside the \a clip rectangle,
+ * true if some of the \a rect is still visible.
+ */
+bool
+nsfb_plot_clip(const nsfb_bbox_t * restrict clip, nsfb_bbox_t * restrict rect)
+{
+ char region1;
+ char region2;
+
+ if (rect->x1 < rect->x0) SWAP(rect->x0, rect->x1);
+
+ if (rect->y1 < rect->y0) SWAP(rect->y0, rect->y1);
+
+ region1 = REGION(rect->x0, rect->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
+ region2 = REGION(rect->x1, rect->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
+
+ /* area lies entirely outside the clipping rectangle */
+ if ((region1 | region2) && (region1 & region2))
+ return false;
+
+ if (rect->x0 < clip->x0)
+ rect->x0 = clip->x0;
+ if (rect->x0 > clip->x1)
+ rect->x0 = clip->x1;
+
+ if (rect->x1 < clip->x0)
+ rect->x1 = clip->x0;
+ if (rect->x1 > clip->x1)
+ rect->x1 = clip->x1;
+
+ if (rect->y0 < clip->y0)
+ rect->y0 = clip->y0;
+ if (rect->y0 > clip->y1)
+ rect->y0 = clip->y1;
+
+ if (rect->y1 < clip->y0)
+ rect->y1 = clip->y0;
+ if (rect->y1 > clip->y1)
+ rect->y1 = clip->y1;
+
+ return true;
+}
+
+bool
+nsfb_plot_clip_ctx(nsfb_t *nsfb, nsfb_bbox_t * restrict rect)
+{
+ return nsfb_plot_clip(&nsfb->clip, rect);
+}
+
+/** Clip a line to a bounding box.
+ */
+bool nsfb_plot_clip_line(const nsfb_bbox_t *clip, nsfb_bbox_t * restrict line)
+{
+ char region1;
+ char region2;
+ region1 = REGION(line->x0, line->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
+ region2 = REGION(line->x1, line->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
+
+ while (region1 | region2) {
+ if (region1 & region2) {
+ /* line lies entirely outside the clipping rectangle */
+ return false;
+ }
+
+ if (region1) {
+ /* first point */
+ if (region1 & POINT_BELOW_REGION) {
+ /* divide line at bottom */
+ line->x0 = (line->x0 + (line->x1 - line->x0) *
+ (clip->y1 - 1 - line->y0) / (line->y1 - line->y0));
+ line->y0 = clip->y1 - 1;
+ } else if (region1 & POINT_ABOVE_REGION) {
+ /* divide line at top */
+ line->x0 = (line->x0 + (line->x1 - line->x0) *
+ (clip->y0 - line->y0) / (line->y1 - line->y0));
+ line->y0 = clip->y0;
+ } else if (region1 & POINT_RIGHTOF_REGION) {
+ /* divide line at right */
+ line->y0 = (line->y0 + (line->y1 - line->y0) *
+ (clip->x1 - 1 - line->x0) / (line->x1 - line->x0));
+ line->x0 = clip->x1 - 1;
+ } else if (region1 & POINT_LEFTOF_REGION) {
+ /* divide line at right */
+ line->y0 = (line->y0 + (line->y1 - line->y0) *
+ (clip->x0 - line->x0) / (line->x1 - line->x0));
+ line->x0 = clip->x0;
+ }
+
+ region1 = REGION(line->x0, line->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
+ } else {
+ /* second point */
+ if (region2 & POINT_BELOW_REGION) {
+ /* divide line at bottom*/
+ line->x1 = (line->x0 + (line->x1 - line->x0) *
+ (clip->y1 - 1 - line->y0) / (line->y1 - line->y0));
+ line->y1 = clip->y1 - 1;
+ } else if (region2 & POINT_ABOVE_REGION) {
+ /* divide line at top*/
+ line->x1 = (line->x0 + (line->x1 - line->x0) *
+ (clip->y0 - line->y0) / (line->y1 - line->y0));
+ line->y1 = clip->y0;
+ } else if (region2 & POINT_RIGHTOF_REGION) {
+ /* divide line at right*/
+ line->y1 = (line->y0 + (line->y1 - line->y0) *
+ (clip->x1 - 1 - line->x0) / (line->x1 - line->x0));
+ line->x1 = clip->x1 - 1;
+ } else if (region2 & POINT_LEFTOF_REGION) {
+ /* divide line at right*/
+ line->y1 = (line->y0 + (line->y1 - line->y0) *
+ (clip->x0 - line->x0) / (line->x1 - line->x0));
+ line->x1 = clip->x0;
+ }
+
+ region2 = REGION(line->x1, line->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
+ }
+ }
+
+ return true;
+}
+
+bool nsfb_plot_clip_line_ctx(nsfb_t *nsfb, nsfb_bbox_t * restrict line)
+{
+ return nsfb_plot_clip_line(&nsfb->clip, line);
+}
+
diff --git a/src/plotters.c b/src/plotters.c
new file mode 100644
index 0000000..b439d55
--- /dev/null
+++ b/src/plotters.c
@@ -0,0 +1,522 @@
+/* generic plotter functions which are not depth dependant */
+
+#include <stdbool.h>
+#include <limits.h>
+#include <malloc.h>
+#include <string.h>
+
+#include "libnsfb.h"
+#include "nsfb.h"
+#include "nsfb_plot.h"
+#include "plot_util.h"
+#include "plotters.h"
+
+extern const nsfb_plotter_fns_t _nsfb_1bpp_plotters;
+extern const nsfb_plotter_fns_t _nsfb_8bpp_plotters;
+extern const nsfb_plotter_fns_t _nsfb_16bpp_plotters;
+extern const nsfb_plotter_fns_t _nsfb_24bpp_plotters;
+extern const nsfb_plotter_fns_t _nsfb_32bpp_plotters;
+
+static bool set_clip(nsfb_t *nsfb, nsfb_bbox_t *clip)
+{
+ nsfb_bbox_t fbarea;
+
+ /* screen area */
+ fbarea.x0 = 0;
+ fbarea.y0 = 0;
+ fbarea.x1 = nsfb->width;
+ fbarea.y1 = nsfb->height;
+
+ if (clip == NULL) {
+ nsfb->clip = fbarea;
+ } else {
+ if (!nsfb_plot_clip(&fbarea, clip))
+ return false;
+
+ nsfb->clip = *clip;
+ }
+ return true;
+}
+
+static bool clg(nsfb_t *nsfb, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->fill(nsfb, &nsfb->clip, c);
+}
+
+/**
+ * Find find first filled span along horizontal line at given coordinate
+ *
+ * \param p array of polygon vertices (x1, y1, x2, y2, ... , xN, yN)
+ * \param n number of polygon vertex values (N * 2)
+ * \param x current position along current scan line
+ * \param y position of current scan line
+ * \param x0 updated to start of filled area
+ * \param x1 updated to end of filled area
+ * \return true if an intersection was found
+ */
+static bool find_span(const int *p, int n, int x, int y, int *x0, int *x1)
+{
+ int i;
+ int p_x0, p_y0;
+ int p_x1, p_y1;
+ int x_new;
+ bool direction = false;
+
+ *x0 = *x1 = INT_MAX;
+
+ for (i = 0; i < n; i = i + 2) {
+ /* get line endpoints */
+ if (i != n - 2) {
+ /* not the last line */
+ p_x0 = p[i]; p_y0 = p[i + 1];
+ p_x1 = p[i + 2]; p_y1 = p[i + 3];
+ } else {
+ /* last line; 2nd endpoint is first vertex */
+ p_x0 = p[i]; p_y0 = p[i + 1];
+ p_x1 = p[0]; p_y1 = p[1];
+ }
+ /* ignore horizontal lines */
+ if (p_y0 == p_y1)
+ continue;
+
+ /* ignore lines that don't cross this y level */
+ if ((y < p_y0 && y < p_y1) || (y > p_y0 && y > p_y1))
+ continue;
+
+ if (p_x0 == p_x1) {
+ /* vertical line, x is constant */
+ x_new = p_x0;
+ } else {
+ /* find intersect */
+ x_new = p_x0 + ((long long)(y - p_y0) * (p_x1 - p_x0)) /
+ (p_y1 - p_y0);
+ }
+
+ /* ignore intersections before current x */
+ if (x_new < x)
+ continue;
+
+ /* set nearest intersections as filled area endpoints */
+ if (x_new < *x0) {
+ /* nearer than first endpoint */
+ *x1 = *x0;
+ *x0 = x_new;
+ direction = (p_y0 > p_y1);
+ } else if (x_new == *x0) {
+ /* same as first endpoint */
+ if ((p_y0 > p_y1) != direction)
+ *x1 = x_new;
+ } else if (x_new < *x1) {
+ /* nearer than second endpoint */
+ *x1 = x_new;
+ }
+
+ }
+ if (*x0 == INT_MAX)
+ /* no span found */
+ return false;
+
+ /* span found */
+ if (*x1 == INT_MAX) {
+ *x1 = *x0;
+ *x0 = x;
+ return true;
+ }
+
+ return true;
+}
+
+
+/**
+ * Plot a polygon
+ *
+ * \param p array of polygon vertices (x1, y1, x2, y2, ... , xN, yN)
+ * \param n number of polygon vertices (N)
+ * \param c fill colour
+ * \param linefn function to call to plot a horizontal line
+ * \return true if no errors
+ */
+static bool polygon(nsfb_t *nsfb, const int *p, unsigned int n, nsfb_colour_t c)
+{
+ int poly_x0, poly_y0; /* Bounding box top left corner */
+ int poly_x1, poly_y1; /* Bounding box bottom right corner */
+ int i, j; /* indexes */
+ int x0, x1; /* filled span extents */
+ int y; /* current y coordinate */
+ int y_max; /* bottom of plot area */
+ nsfb_bbox_t fline;
+
+ /* find no. of vertex values */
+ int v = n * 2;
+
+ /* Can't plot polygons with 2 or fewer vertices */
+ if (n <= 2)
+ return true;
+
+ /* Find polygon bounding box */
+ poly_x0 = poly_x1 = *p;
+ poly_y0 = poly_y1 = p[1];
+ for (i = 2; i < v; i = i + 2) {
+ j = i + 1;
+ if (p[i] < poly_x0)
+ poly_x0 = p[i];
+ else if (p[i] > poly_x1)
+ poly_x1 = p[i];
+ if (p[j] < poly_y0)
+ poly_y0 = p[j];
+ else if (p[j] > poly_y1)
+ poly_y1 = p[j];
+ }
+
+ /* Don't try to plot it if it's outside the clip rectangle */
+ if (nsfb->clip.y1 < poly_y0 ||
+ nsfb->clip.y0 > poly_y1 ||
+ nsfb->clip.x1 < poly_x0 ||
+ nsfb->clip.x0 > poly_x1)
+ return true;
+
+ /* Find the top of the important area */
+ if (poly_y0 > nsfb->clip.y0)
+ y = poly_y0;
+ else
+ y = nsfb->clip.y0;
+
+ /* Find the bottom of the important area */
+ if (poly_y1 < nsfb->clip.y1)
+ y_max = poly_y1;
+ else
+ y_max = nsfb->clip.y1;
+
+ for (; y < y_max; y++) {
+ x1 = poly_x0;
+ /* For each row */
+ while (find_span(p, v, x1, y, &x0, &x1)) {
+ /* don't draw anything outside clip region */
+ if (x1 < nsfb->clip.x0)
+ continue;
+ else if (x0 < nsfb->clip.x0)
+ x0 = nsfb->clip.x0;
+ if (x0 > nsfb->clip.x1)
+ break;
+ else if (x1 > nsfb->clip.x1)
+ x1 = nsfb->clip.x1;
+
+ fline.x0 = x0;
+ fline.y0 = y;
+ fline.x1 = x1;
+ fline.y1 = y;
+
+ /* draw this filled span on current row */
+ nsfb->plotter_fns->line(nsfb, &fline, 1, c, false, false);
+
+ /* don't look for more spans if already at end of clip
+ * region or polygon */
+ if (x1 == nsfb->clip.x1 || x1 == poly_x1)
+ break;
+
+ if (x0 == x1)
+ x1++;
+ }
+ }
+ return true;
+}
+
+static bool rectangle(nsfb_t *nsfb, nsfb_bbox_t *rect,
+ int line_width, nsfb_colour_t c,
+ bool dotted, bool dashed)
+{
+ nsfb_bbox_t side;
+
+ side = *rect;
+ side.y1 = side.y0;
+
+ nsfb->plotter_fns->line(nsfb, &side, line_width, c, dotted, dashed);
+
+ side = *rect;
+ side.y0 = side.y1;
+
+ nsfb->plotter_fns->line(nsfb, &side, line_width, c, dotted, dashed);
+
+ side = *rect;
+ side.x1 = side.x0;
+
+ nsfb->plotter_fns->line(nsfb, &side, line_width, c, dotted, dashed);
+
+ side = *rect;
+ side.x0 = side.x1;
+
+ return nsfb->plotter_fns->line(nsfb, &side, line_width, c, dotted, dashed);
+}
+
+/* plotter routine for ellipse points */
+static void ellipsepoints(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
+{
+ nsfb->plotter_fns->point(nsfb, cx + x, cy + y, c);
+ nsfb->plotter_fns->point(nsfb, cx - x, cy + y, c);
+ nsfb->plotter_fns->point(nsfb, cx + x, cy - y, c);
+ nsfb->plotter_fns->point(nsfb, cx - x, cy - y, c);
+}
+
+static void ellipsefill(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
+{
+ nsfb_bbox_t fline;
+ fline.x0 = cx - x;
+ fline.x1 = cx + x;
+ fline.y0 = fline.y1 = cy + y;
+ nsfb->plotter_fns->line(nsfb, &fline, 1, c, false, false);
+
+ fline.x0 = cx - x;
+ fline.x1 = cx + x;
+ fline.y0 = fline.y1 = cy - y;
+ nsfb->plotter_fns->line(nsfb, &fline, 1, c, false, false);
+
+}
+
+#define ROUND(a) ((int)(a+0.5))
+
+static bool ellipse_midpoint(nsfb_t *nsfb,
+ int cx,
+ int cy,
+ int rx,
+ int ry,
+ nsfb_colour_t c,
+ void (ellipsefn)(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c))
+{
+ int rx2 = rx * rx;
+ int ry2 = ry * ry;
+ int tworx2 = 2 * rx2;
+ int twory2 = 2 * ry2;
+ int p;
+ int x = 0;
+ int y = ry;
+ int px = 0;
+ int py = tworx2 * y;
+
+ ellipsefn(nsfb, cx, cy, x, y, c);
+
+ /* region 1 */
+ p = ROUND(ry2 - (rx2 * ry) + (0.25 * rx2));
+ while (px < py) {
+ x++;
+ px += twory2;
+ if (p <0) {
+ p+=ry2 + px;
+ } else {
+ y--;
+ py -= tworx2;
+ p+=ry2 + px - py;
+ }
+ ellipsefn(nsfb, cx, cy, x, y, c);
+ }
+
+ /* region 2 */
+ p = ROUND(ry2*(x+0.5)*(x+0.5) + rx2*(y-1)*(y-1) - rx2*ry2);
+ while (y > 0) {
+ y--;
+ py -= tworx2;
+ if (p > 0) {
+ p+=rx2 - py;
+ } else {
+ x++;
+ px += twory2;
+ p+=rx2 - py + px;
+ }
+ ellipsefn(nsfb, cx, cy, x, y, c);
+ }
+ return true;
+}
+
+
+/* plotter routine for 8way circle symetry */
+static void circlepoints(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
+{
+ nsfb->plotter_fns->point(nsfb, cx + x, cy + y, c);
+ nsfb->plotter_fns->point(nsfb, cx - x, cy + y, c);
+ nsfb->plotter_fns->point(nsfb, cx + x, cy - y, c);
+ nsfb->plotter_fns->point(nsfb, cx - x, cy - y, c);
+ nsfb->plotter_fns->point(nsfb, cx + y, cy + x, c);
+ nsfb->plotter_fns->point(nsfb, cx - y, cy + x, c);
+ nsfb->plotter_fns->point(nsfb, cx + y, cy - x, c);
+ nsfb->plotter_fns->point(nsfb, cx - y, cy - x, c);
+}
+
+static void circlefill(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c)
+{
+ nsfb_bbox_t fline;
+ fline.x0 = cx - x;
+ fline.x1 = cx + x;
+ fline.y0 = fline.y1 = cy + y;
+ nsfb->plotter_fns->line(nsfb, &fline, 1, c, false, false);
+
+ fline.x0 = cx - x;
+ fline.x1 = cx + x;
+ fline.y0 = fline.y1 = cy - y;
+ nsfb->plotter_fns->line(nsfb, &fline, 1, c, false, false);
+
+ fline.x0 = cx - y;
+ fline.x1 = cx + y;
+ fline.y0 = fline.y1 = cy + x;
+ nsfb->plotter_fns->line(nsfb, &fline, 1, c, false, false);
+
+ fline.x0 = cx - y;
+ fline.x1 = cx + y;
+ fline.y0 = fline.y1 = cy - x;
+ nsfb->plotter_fns->line(nsfb, &fline, 1, c, false, false);
+}
+
+static bool circle_midpoint(nsfb_t *nsfb,
+ int cx,
+ int cy,
+ int r,
+ nsfb_colour_t c,
+ void (circfn)(nsfb_t *nsfb, int cx, int cy, int x, int y, nsfb_colour_t c))
+{
+ int x = 0;
+ int y = r;
+ int p = 1 - r;
+
+ circfn(nsfb, cx, cy, x, y, c);
+ while (x < y) {
+ x++;
+ if (p < 0) {
+ p += 2 * x + 1;
+ } else {
+ y--;
+ p += 2 * (x - y) + 1;
+ }
+ circfn(nsfb, cx, cy, x, y, c);
+ }
+ return true;
+}
+
+static bool ellipse(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c)
+{
+ int width = (ellipse->x1 - ellipse->x0)>>1;
+ int height = (ellipse->y1 - ellipse->y0)>>1;
+
+ if (width == height) {
+ /* circle */
+ return circle_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, c, circlepoints);
+ } else {
+ return ellipse_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, height, c, ellipsepoints);
+ }
+}
+
+static bool ellipse_fill(nsfb_t *nsfb, nsfb_bbox_t *ellipse, nsfb_colour_t c)
+{
+ int width = (ellipse->x1 - ellipse->x0) >> 1;
+ int height = (ellipse->y1 - ellipse->y0) >> 1;
+
+ if (width == height) {
+ /* circle */
+ return circle_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, c, circlefill);
+ } else {
+ return ellipse_midpoint(nsfb, ellipse->x0 + width, ellipse->y0 + height, width, height, c, ellipsefill);
+ }
+}
+
+static bool copy(nsfb_t *nsfb, int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+ uint8_t *srcptr = (nsfb->ptr +
+ (srcy * nsfb->linelen) +
+ ((srcx * nsfb->bpp) / 8));
+
+ uint8_t *dstptr = (nsfb->ptr +
+ (dsty * nsfb->linelen) +
+ ((dstx * nsfb->bpp) / 8));
+
+ int hloop;
+
+ if (width == nsfb->width) {
+ /* take shortcut and use memmove */
+ memmove(dstptr, srcptr, (width * height * nsfb->bpp) / 8);
+ } else {
+ if (srcy > dsty) {
+ for (hloop = height; hloop > 0; hloop--) {
+ memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
+ srcptr += nsfb->linelen;
+ dstptr += nsfb->linelen;
+ }
+ } else {
+ srcptr += height * nsfb->linelen;
+ dstptr += height * nsfb->linelen;
+ for (hloop = height; hloop > 0; hloop--) {
+ srcptr -= nsfb->linelen;
+ dstptr -= nsfb->linelen;
+ memmove(dstptr, srcptr, (width * nsfb->bpp) / 8);
+ }
+ }
+ }
+ return true;
+}
+
+static bool arc(nsfb_t *nsfb, int x, int y, int radius, int angle1, int angle2, nsfb_colour_t c)
+{
+ nsfb=nsfb;
+ x = x;
+ y = y;
+ radius = radius;
+ c = c;
+ angle1=angle1;
+ angle2=angle2;
+ return true;
+}
+
+bool select_plotters(nsfb_t *nsfb)
+{
+ const nsfb_plotter_fns_t *table;
+
+ switch (nsfb->bpp) {
+ /* case 1:
+ table = &_nsfb_1bpp_plotters;
+ break;
+ */
+ /*
+
+ case 8:
+ table = &_nsfb_8bpp_plotters;
+ break;
+ */
+ /*
+
+ case 16:
+ table = &_nsfb_16bpp_plotters;
+ break;
+ */
+ /*
+ case 24:
+ table = &_nsfb_24bpp_plotters;
+ break;
+ */
+ case 32:
+ table = &_nsfb_32bpp_plotters;
+ break;
+
+ default:
+ return false;
+ }
+
+ if (nsfb->plotter_fns != NULL)
+ free(nsfb->plotter_fns);
+
+ nsfb->plotter_fns = calloc(1, sizeof(nsfb_plotter_fns_t));
+ memcpy(nsfb->plotter_fns, table, sizeof(nsfb_plotter_fns_t));
+
+ /* set the generics */
+ nsfb->plotter_fns->clg = clg;
+ nsfb->plotter_fns->clip = set_clip;
+ nsfb->plotter_fns->polygon = polygon;
+ nsfb->plotter_fns->rectangle = rectangle;
+ nsfb->plotter_fns->ellipse = ellipse;
+ nsfb->plotter_fns->ellipse_fill = ellipse_fill;
+ nsfb->plotter_fns->copy = copy;
+ nsfb->plotter_fns->arc = arc;
+
+ /* set default clip rectangle to size of framebuffer */
+ nsfb->clip.x0 = 0;
+ nsfb->clip.y0 = 0;
+ nsfb->clip.x1 = nsfb->width;
+ nsfb->clip.y1 = nsfb->height;
+
+ return true;
+}