summaryrefslogtreecommitdiff
path: root/src/plot
diff options
context:
space:
mode:
authorVincent Sanders <vince@netsurf-browser.org>2010-01-20 17:18:28 +0000
committerVincent Sanders <vince@netsurf-browser.org>2010-01-20 17:18:28 +0000
commit131b6c4a00575c9e996a9ae60c90a9647fb5ef75 (patch)
treedba439673b801a22a833270dbd615628bf0614e4 /src/plot
parenta3097232844a20ea918d63722dbe6a7c71493bab (diff)
downloadlibnsfb-131b6c4a00575c9e996a9ae60c90a9647fb5ef75.tar.gz
libnsfb-131b6c4a00575c9e996a9ae60c90a9647fb5ef75.tar.bz2
move plot functions to their own sub directory
fix 8 and 16bpp plotters when used with cursor svn path=/trunk/libnsfb/; revision=9850
Diffstat (limited to 'src/plot')
-rw-r--r--src/plot/16bpp.c448
-rw-r--r--src/plot/1bpp.c266
-rw-r--r--src/plot/24bpp.c442
-rw-r--r--src/plot/32bpp.c442
-rw-r--r--src/plot/8bpp.c425
-rw-r--r--src/plot/Makefile4
-rw-r--r--src/plot/api.c169
-rw-r--r--src/plot/generic.c663
-rw-r--r--src/plot/util.c199
9 files changed, 3058 insertions, 0 deletions
diff --git a/src/plot/16bpp.c b/src/plot/16bpp.c
new file mode 100644
index 0000000..8feb095
--- /dev/null
+++ b/src/plot/16bpp.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright 2009 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of libnsfb, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+#include <stdbool.h>
+#include <endian.h>
+#include <stdlib.h>
+
+#include "libnsfb.h"
+#include "libnsfb_plot.h"
+#include "libnsfb_plot_util.h"
+
+#include "nsfb.h"
+#include "plot.h"
+
+static inline uint16_t *get_xy_loc(nsfb_t *nsfb, int x, int y)
+{
+ return (void *)(nsfb->ptr + (y * nsfb->linelen) + (x << 1));
+}
+
+static inline nsfb_colour_t pixel_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 colour_to_pixel(nsfb_colour_t c)
+{
+ return ((c & 0xF8) << 8) | ((c & 0xFC00 ) >> 5) | ((c & 0xF80000) >> 19);
+}
+
+#define SIGN(x) ((x<0) ? -1 : ((x>0) ? 1 : 0))
+
+
+static bool
+line(nsfb_t *nsfb, int linec, nsfb_bbox_t *line, nsfb_plot_pen_t *pen)
+{
+ int w;
+ uint16_t ent;
+ uint16_t *pvideo;
+ int x, y, i;
+ int dx, dy, sdy;
+ int dxabs, dyabs;
+
+ ent = colour_to_pixel(pen->stroke_colour);
+
+ for (;linec > 0; linec--) {
+
+ if (line->y0 == line->y1) {
+ /* horizontal line special cased */
+
+ if (!nsfb_plot_clip_ctx(nsfb, line)) {
+ /* line outside clipping */
+ line++;
+ continue;
+ }
+
+ pvideo = get_xy_loc(nsfb, line->x0, line->y0);
+
+ w = line->x1 - line->x0;
+ while (w-- > 0)
+ *(pvideo + w) = ent;
+
+ } else {
+ /* standard bresenham line */
+ if (!nsfb_plot_clip_line_ctx(nsfb, line)) {
+ /* line outside clipping */
+ line++;
+ continue;
+ }
+
+ /* 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>>1);
+ }
+ }
+ } else {
+ /* the line is more vertical than horizontal */
+ for (i = 0; i < dyabs; i++) {
+ *pvideo = ent;
+ pvideo += sdy * (nsfb->linelen >> 1);
+
+ x += dxabs;
+ if (x >= dyabs) {
+ x -= dyabs;
+ pvideo++;
+ }
+ }
+ }
+
+ }
+ line++;
+ }
+ return true;
+}
+
+
+
+static bool fill(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t 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 (!nsfb_plot_clip_ctx(nsfb, rect))
+ return true; /* fill lies outside current clipping region */
+
+ ent16 = colour_to_pixel(c);
+ width = rect->x1 - rect->x0;
+ height = rect->y1 - rect->y0;
+
+ pvid16 = get_xy_loc(nsfb, rect->x0, rect->y0);
+
+ if (((rect->x0 & 1) == 0) && ((width & 1) == 0)) {
+ /* aligned to 32bit value and width is even */
+ width = width >> 1;
+ llen = (nsfb->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 = (nsfb->linelen >> 1) - width;
+
+
+ while (height-- > 0) {
+ for (w = width; w > 0; w--) *pvid16++ = ent16;
+ pvid16 += llen;
+ }
+ }
+ return true;
+}
+
+
+static bool point(nsfb_t *nsfb, int x, int y, nsfb_colour_t c)
+{
+ uint16_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
+glyph1(nsfb_t *nsfb,
+ nsfb_bbox_t *loc,
+ const uint8_t *pixel,
+ int pitch,
+ nsfb_colour_t c)
+{
+ uint16_t *pvideo;
+ 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;
+ uint16_t fgcol;
+ const uint8_t *fntd;
+ uint8_t row;
+
+ if (!nsfb_plot_clip_ctx(nsfb, loc))
+ return true;
+
+ if (height > (loc->y1 - loc->y0))
+ height = (loc->y1 - loc->y0);
+
+ if (width > (loc->x1 - loc->x0))
+ width = (loc->x1 - loc->x0);
+
+ xoff = loc->x0 - x;
+ yoff = loc->y0 - y;
+
+ pvideo = get_xy_loc(nsfb, loc->x0, loc->y0);
+
+ fgcol = colour_to_pixel(c);
+
+ for (yloop = yoff; yloop < height; yloop++) {
+ fntd = pixel + (yloop * (pitch>>3)) + (xoff>>3);
+ row = (*fntd++) << (xoff & 3);
+ for (xloop = xoff; xloop < width ; xloop++) {
+ if (((xloop % 8) == 0) && (xloop != 0)) {
+ row = *fntd++;
+ }
+
+ if ((row & 0x80) != 0) {
+ *(pvideo + xloop) = fgcol;
+ }
+ row = row << 1;
+
+ }
+
+ pvideo += (nsfb->linelen >> 1);
+ }
+
+ return true;
+}
+
+static bool
+glyph8(nsfb_t *nsfb,
+ nsfb_bbox_t *loc,
+ const uint8_t *pixel,
+ int pitch,
+ nsfb_colour_t c)
+{
+ uint16_t *pvideo;
+ nsfb_colour_t abpixel; /* 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;
+ uint16_t fgcol;
+
+ if (!nsfb_plot_clip_ctx(nsfb, loc))
+ return true;
+
+ if (height > (loc->y1 - loc->y0))
+ height = (loc->y1 - loc->y0);
+
+ if (width > (loc->x1 - loc->x0))
+ width = (loc->x1 - loc->x0);
+
+ xoff = loc->x0 - x;
+ yoff = loc->y0 - y;
+
+ pvideo = get_xy_loc(nsfb, loc->x0, loc->y0);
+
+ fgcol = c & 0xFFFFFF;
+
+ for (yloop = 0; yloop < height; yloop++) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = (pixel[((yoff + yloop) * pitch) + xloop + xoff] << 24) | fgcol;
+ if ((abpixel & 0xFF000000) != 0) {
+ /* pixel is not transparent */
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = nsfb_plot_ablend(abpixel,
+ pixel_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = colour_to_pixel(abpixel);
+ }
+ }
+ pvideo += (nsfb->linelen >> 1);
+ }
+
+ return true;
+}
+
+static bool
+bitmap(nsfb_t *nsfb,
+ const nsfb_bbox_t *loc,
+ const nsfb_colour_t *pixel,
+ int bmp_width,
+ int bmp_height,
+ int bmp_stride,
+ bool alpha)
+{
+ uint16_t *pvideo;
+ nsfb_colour_t abpixel; /* 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 bitmap->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_width + 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 >> 1);
+ }
+ } 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 >> 1);
+ }
+ }
+
+ return true;
+}
+
+
+static bool readrect(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t *buffer)
+{
+ uint16_t *pvideo;
+ int xloop, yloop;
+ int width;
+
+ if (!nsfb_plot_clip_ctx(nsfb, rect)) {
+ return true;
+ }
+
+ width = rect->x1 - rect->x0;
+
+ pvideo = get_xy_loc(nsfb, rect->x0, rect->y0);
+
+ for (yloop = rect->y0; yloop < rect->y1; yloop += 1) {
+ for (xloop = 0; xloop < width; xloop++) {
+ *buffer = pixel_to_colour(*(pvideo + xloop));
+ buffer++;
+ }
+ pvideo += (nsfb->linelen >> 1);
+ }
+ return true;
+}
+
+
+const nsfb_plotter_fns_t _nsfb_16bpp_plotters = {
+ .line = line,
+ .fill = fill,
+ .point = point,
+ .bitmap = bitmap,
+ .glyph8 = glyph8,
+ .glyph1 = glyph1,
+ .readrect = readrect,
+};
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/src/plot/1bpp.c b/src/plot/1bpp.c
new file mode 100644
index 0000000..bd511e7
--- /dev/null
+++ b/src/plot/1bpp.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/plot/24bpp.c b/src/plot/24bpp.c
new file mode 100644
index 0000000..0fa53e9
--- /dev/null
+++ b/src/plot/24bpp.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2009 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of libnsfb, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+#include <stdbool.h>
+#include <endian.h>
+#include <stdlib.h>
+
+#include "libnsfb.h"
+#include "libnsfb_plot.h"
+#include "libnsfb_plot_util.h"
+
+#include "nsfb.h"
+#include "plot.h"
+
+static inline uint8_t *
+get_xy_loc(nsfb_t *nsfb, int x, int y)
+{
+ return (uint8_t *)(nsfb->ptr + (y * nsfb->linelen) + (x * 3));
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static inline nsfb_colour_t pixel_to_colour(uint8_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, int linec, nsfb_bbox_t *line, nsfb_plot_pen_t *pen)
+{
+ int w;
+ uint32_t ent;
+ uint32_t *pvideo;
+ int x, y, i;
+ int dx, dy, sdy;
+ int dxabs, dyabs;
+
+ ent = colour_to_pixel(pen->stroke_colour);
+
+ for (;linec > 0; linec--) {
+
+ if (line->y0 == line->y1) {
+ /* horizontal line special cased */
+
+ if (!nsfb_plot_clip_ctx(nsfb, line)) {
+ /* line outside clipping */
+ line++;
+ continue;
+ }
+
+ pvideo = get_xy_loc(nsfb, line->x0, line->y0);
+
+ w = line->x1 - line->x0;
+ while (w-- > 0)
+ *(pvideo + w) = ent;
+
+ } else {
+ /* standard bresenham line */
+
+ if (!nsfb_plot_clip_line_ctx(nsfb, line)) {
+ /* line outside clipping */
+ line++;
+ continue;
+ }
+
+ /* 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++;
+ }
+ }
+ }
+
+ }
+ line++;
+ }
+ 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
+glyph1(nsfb_t *nsfb,
+ nsfb_bbox_t *loc,
+ const uint8_t *pixel,
+ int pitch,
+ nsfb_colour_t c)
+{
+ uint32_t *pvideo;
+ 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;
+ uint32_t fgcol;
+ const uint8_t *fntd;
+ uint8_t row;
+
+ if (!nsfb_plot_clip_ctx(nsfb, loc))
+ return true;
+
+ if (height > (loc->y1 - loc->y0))
+ height = (loc->y1 - loc->y0);
+
+ if (width > (loc->x1 - loc->x0))
+ width = (loc->x1 - loc->x0);
+
+ xoff = loc->x0 - x;
+ yoff = loc->y0 - y;
+
+ pvideo = get_xy_loc(nsfb, loc->x0, loc->y0);
+
+ fgcol = colour_to_pixel(c);
+
+ for (yloop = yoff; yloop < height; yloop++) {
+ fntd = pixel + (yloop * (pitch>>3)) + (xoff>>3);
+ row = (*fntd++) << (xoff & 3);
+ for (xloop = xoff; xloop < width ; xloop++) {
+ if (((xloop % 8) == 0) && (xloop != 0)) {
+ row = *fntd++;
+ }
+
+ if ((row & 0x80) != 0) {
+ *(pvideo + xloop) = fgcol;
+ }
+ row = row << 1;
+
+ }
+
+ pvideo += (nsfb->linelen >> 2);
+ }
+
+ return true;
+}
+
+static bool
+glyph8(nsfb_t *nsfb,
+ nsfb_bbox_t *loc,
+ const uint8_t *pixel,
+ int pitch,
+ nsfb_colour_t c)
+{
+ uint32_t *pvideo;
+ nsfb_colour_t abpixel; /* 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;
+ uint32_t fgcol;
+
+ if (!nsfb_plot_clip_ctx(nsfb, loc))
+ return true;
+
+ if (height > (loc->y1 - loc->y0))
+ height = (loc->y1 - loc->y0);
+
+ if (width > (loc->x1 - loc->x0))
+ width = (loc->x1 - loc->x0);
+
+ xoff = loc->x0 - x;
+ yoff = loc->y0 - y;
+
+ pvideo = get_xy_loc(nsfb, loc->x0, loc->y0);
+
+ fgcol = c & 0xFFFFFF;
+
+ for (yloop = 0; yloop < height; yloop++) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = (pixel[((yoff + yloop) * pitch) + xloop + xoff] << 24) | fgcol;
+ if ((abpixel & 0xFF000000) != 0) {
+ /* pixel is not transparent */
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = nsfb_plot_ablend(abpixel,
+ pixel_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = colour_to_pixel(abpixel);
+ }
+ }
+ pvideo += (nsfb->linelen >> 2);
+ }
+
+ return true;
+}
+
+static bool
+bitmap(nsfb_t *nsfb,
+ const nsfb_bbox_t *loc,
+ const 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;
+}
+
+static bool readrect(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t *buffer)
+{
+ uint32_t *pvideo;
+ int xloop, yloop;
+ int width;
+
+ if (!nsfb_plot_clip_ctx(nsfb, rect)) {
+ return true;
+ }
+
+ width = rect->x1 - rect->x0;
+
+ pvideo = get_xy_loc(nsfb, rect->x0, rect->y0);
+
+ for (yloop = rect->y0; yloop < rect->y1; yloop += 1) {
+ for (xloop = 0; xloop < width; xloop++) {
+ *buffer = pixel_to_colour(*(pvideo + xloop));
+ buffer++;
+ }
+ pvideo += (nsfb->linelen >> 2);
+ }
+ return true;
+}
+
+const nsfb_plotter_fns_t _nsfb_24bpp_plotters = {
+ .line = line,
+ .fill = fill,
+ .point = point,
+ .bitmap = bitmap,
+ .glyph8 = glyph8,
+ .glyph1 = glyph1,
+ .readrect = readrect,
+};
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/src/plot/32bpp.c b/src/plot/32bpp.c
new file mode 100644
index 0000000..243cdb4
--- /dev/null
+++ b/src/plot/32bpp.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2009 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of libnsfb, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+#include <stdbool.h>
+#include <endian.h>
+#include <stdlib.h>
+
+#include "libnsfb.h"
+#include "libnsfb_plot.h"
+#include "libnsfb_plot_util.h"
+
+#include "nsfb.h"
+#include "plot.h"
+
+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, int linec, nsfb_bbox_t *line, nsfb_plot_pen_t *pen)
+{
+ int w;
+ uint32_t ent;
+ uint32_t *pvideo;
+ int x, y, i;
+ int dx, dy, sdy;
+ int dxabs, dyabs;
+
+ ent = colour_to_pixel(pen->stroke_colour);
+
+ for (;linec > 0; linec--) {
+
+ if (line->y0 == line->y1) {
+ /* horizontal line special cased */
+
+ if (!nsfb_plot_clip_ctx(nsfb, line)) {
+ /* line outside clipping */
+ line++;
+ continue;
+ }
+
+ pvideo = get_xy_loc(nsfb, line->x0, line->y0);
+
+ w = line->x1 - line->x0;
+ while (w-- > 0)
+ *(pvideo + w) = ent;
+
+ } else {
+ /* standard bresenham line */
+
+ if (!nsfb_plot_clip_line_ctx(nsfb, line)) {
+ /* line outside clipping */
+ line++;
+ continue;
+ }
+
+ /* 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++;
+ }
+ }
+ }
+
+ }
+ line++;
+ }
+ 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
+glyph1(nsfb_t *nsfb,
+ nsfb_bbox_t *loc,
+ const uint8_t *pixel,
+ int pitch,
+ nsfb_colour_t c)
+{
+ uint32_t *pvideo;
+ 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;
+ uint32_t fgcol;
+ const uint8_t *fntd;
+ uint8_t row;
+
+ if (!nsfb_plot_clip_ctx(nsfb, loc))
+ return true;
+
+ if (height > (loc->y1 - loc->y0))
+ height = (loc->y1 - loc->y0);
+
+ if (width > (loc->x1 - loc->x0))
+ width = (loc->x1 - loc->x0);
+
+ xoff = loc->x0 - x;
+ yoff = loc->y0 - y;
+
+ pvideo = get_xy_loc(nsfb, loc->x0, loc->y0);
+
+ fgcol = colour_to_pixel(c);
+
+ for (yloop = yoff; yloop < height; yloop++) {
+ fntd = pixel + (yloop * (pitch>>3)) + (xoff>>3);
+ row = (*fntd++) << (xoff & 3);
+ for (xloop = xoff; xloop < width ; xloop++) {
+ if (((xloop % 8) == 0) && (xloop != 0)) {
+ row = *fntd++;
+ }
+
+ if ((row & 0x80) != 0) {
+ *(pvideo + xloop) = fgcol;
+ }
+ row = row << 1;
+
+ }
+
+ pvideo += (nsfb->linelen >> 2);
+ }
+
+ return true;
+}
+
+static bool
+glyph8(nsfb_t *nsfb,
+ nsfb_bbox_t *loc,
+ const uint8_t *pixel,
+ int pitch,
+ nsfb_colour_t c)
+{
+ uint32_t *pvideo;
+ nsfb_colour_t abpixel; /* 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;
+ uint32_t fgcol;
+
+ if (!nsfb_plot_clip_ctx(nsfb, loc))
+ return true;
+
+ if (height > (loc->y1 - loc->y0))
+ height = (loc->y1 - loc->y0);
+
+ if (width > (loc->x1 - loc->x0))
+ width = (loc->x1 - loc->x0);
+
+ xoff = loc->x0 - x;
+ yoff = loc->y0 - y;
+
+ pvideo = get_xy_loc(nsfb, loc->x0, loc->y0);
+
+ fgcol = c & 0xFFFFFF;
+
+ for (yloop = 0; yloop < height; yloop++) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = (pixel[((yoff + yloop) * pitch) + xloop + xoff] << 24) | fgcol;
+ if ((abpixel & 0xFF000000) != 0) {
+ /* pixel is not transparent */
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = nsfb_plot_ablend(abpixel,
+ pixel_to_colour(*(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = colour_to_pixel(abpixel);
+ }
+ }
+ pvideo += (nsfb->linelen >> 2);
+ }
+
+ return true;
+}
+
+static bool
+bitmap(nsfb_t *nsfb,
+ const nsfb_bbox_t *loc,
+ const 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;
+}
+
+static bool readrect(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t *buffer)
+{
+ uint32_t *pvideo;
+ int xloop, yloop;
+ int width;
+
+ if (!nsfb_plot_clip_ctx(nsfb, rect)) {
+ return true;
+ }
+
+ width = rect->x1 - rect->x0;
+
+ pvideo = get_xy_loc(nsfb, rect->x0, rect->y0);
+
+ for (yloop = rect->y0; yloop < rect->y1; yloop += 1) {
+ for (xloop = 0; xloop < width; xloop++) {
+ *buffer = pixel_to_colour(*(pvideo + xloop));
+ buffer++;
+ }
+ pvideo += (nsfb->linelen >> 2);
+ }
+ return true;
+}
+
+const nsfb_plotter_fns_t _nsfb_32bpp_plotters = {
+ .line = line,
+ .fill = fill,
+ .point = point,
+ .bitmap = bitmap,
+ .glyph8 = glyph8,
+ .glyph1 = glyph1,
+ .readrect = readrect,
+};
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/src/plot/8bpp.c b/src/plot/8bpp.c
new file mode 100644
index 0000000..c95565c
--- /dev/null
+++ b/src/plot/8bpp.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright 2009 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of libnsfb, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+#include <stdbool.h>
+#include <endian.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+#include "libnsfb.h"
+#include "libnsfb_plot.h"
+#include "libnsfb_plot_util.h"
+
+#include "nsfb.h"
+#include "plot.h"
+
+static inline uint8_t *get_xy_loc(nsfb_t *nsfb, int x, int y)
+{
+ return (uint8_t *)(nsfb->ptr + (y * nsfb->linelen) + (x));
+}
+
+
+static inline nsfb_colour_t pixel_to_colour(nsfb_t *nsfb, uint8_t pixel)
+{
+ return nsfb->palette[pixel];
+}
+
+static uint8_t
+colour_to_pixel(nsfb_t *nsfb, nsfb_colour_t c)
+{
+ nsfb_colour_t palent;
+ int col;
+
+ int dr, dg, db; /* delta red, green blue values */
+
+ int cur_distance;
+ int best_distance = INT_MAX;
+ uint8_t best_col = 0;
+
+ for (col = 0; col < 256; col++) {
+ palent = nsfb->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;
+}
+
+#define SIGN(x) ((x<0) ? -1 : ((x>0) ? 1 : 0))
+
+static bool
+line(nsfb_t *nsfb, int linec, nsfb_bbox_t *line, nsfb_plot_pen_t *pen)
+{
+ int w;
+ uint8_t ent;
+ uint8_t *pvideo;
+ int x, y, i;
+ int dx, dy, sdy;
+ int dxabs, dyabs;
+
+ ent = colour_to_pixel(nsfb, pen->stroke_colour);
+
+ for (;linec > 0; linec--) {
+
+ if (line->y0 == line->y1) {
+ /* horizontal line special cased */
+
+ if (!nsfb_plot_clip_ctx(nsfb, line)) {
+ /* line outside clipping */
+ line++;
+ continue;
+ }
+
+ pvideo = get_xy_loc(nsfb, line->x0, line->y0);
+
+ w = line->x1 - line->x0;
+ while (w-- > 0)
+ *(pvideo + w) = ent;
+
+ } else {
+ /* standard bresenham line */
+
+ if (!nsfb_plot_clip_line_ctx(nsfb, line)) {
+ /* line outside clipping */
+ line++;
+ continue;
+ }
+
+ /* 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;
+ }
+ }
+ } else {
+ /* the line is more vertical than horizontal */
+ for (i = 0; i < dyabs; i++) {
+ *pvideo = ent;
+ pvideo += sdy * nsfb->linelen;
+
+ x += dxabs;
+ if (x >= dyabs) {
+ x -= dyabs;
+ pvideo++;
+ }
+ }
+ }
+
+ }
+ line++;
+ }
+
+ return true;
+}
+
+static bool fill(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t c)
+{
+ int y;
+ uint8_t ent;
+ uint8_t *pvideo;
+
+ if (!nsfb_plot_clip_ctx(nsfb, rect))
+ return true; /* fill lies outside current clipping region */
+
+ pvideo = get_xy_loc(nsfb, rect->x0, rect->y0);
+
+ ent = colour_to_pixel(nsfb, c);
+
+ for (y = rect->y0; y < rect->y1; y++) {
+ memset(pvideo, ent, rect->x1 - rect->x0);
+ pvideo += nsfb->linelen;
+ }
+
+ return true;
+}
+
+static bool point(nsfb_t *nsfb, int x, int y, nsfb_colour_t c)
+{
+ uint8_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(nsfb, *pvideo));
+ }
+
+ *pvideo = colour_to_pixel(nsfb, c);
+ }
+ return true;
+}
+
+static bool
+glyph1(nsfb_t *nsfb,
+ nsfb_bbox_t *loc,
+ const uint8_t *pixel,
+ int pitch,
+ nsfb_colour_t c)
+{
+ uint8_t *pvideo;
+ 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;
+ uint8_t fgcol;
+ const uint8_t *fntd;
+ uint8_t row;
+
+ if (!nsfb_plot_clip_ctx(nsfb, loc))
+ return true;
+
+ if (height > (loc->y1 - loc->y0))
+ height = (loc->y1 - loc->y0);
+
+ if (width > (loc->x1 - loc->x0))
+ width = (loc->x1 - loc->x0);
+
+ xoff = loc->x0 - x;
+ yoff = loc->y0 - y;
+
+ pvideo = get_xy_loc(nsfb, loc->x0, loc->y0);
+
+ fgcol = colour_to_pixel(nsfb, c);
+
+ for (yloop = yoff; yloop < height; yloop++) {
+ fntd = pixel + (yloop * (pitch>>3)) + (xoff>>3);
+ row = (*fntd++) << (xoff & 3);
+ for (xloop = xoff; xloop < width ; xloop++) {
+ if (((xloop % 8) == 0) && (xloop != 0)) {
+ row = *fntd++;
+ }
+
+ if ((row & 0x80) != 0) {
+ *(pvideo + xloop) = fgcol;
+ }
+ row = row << 1;
+
+ }
+
+ pvideo += nsfb->linelen;
+ }
+
+ return true;
+}
+
+static bool
+glyph8(nsfb_t *nsfb,
+ nsfb_bbox_t *loc,
+ const uint8_t *pixel,
+ int pitch,
+ nsfb_colour_t c)
+{
+ uint8_t *pvideo;
+ nsfb_colour_t abpixel; /* 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;
+ uint8_t fgcol;
+
+ if (!nsfb_plot_clip_ctx(nsfb, loc))
+ return true;
+
+ if (height > (loc->y1 - loc->y0))
+ height = (loc->y1 - loc->y0);
+
+ if (width > (loc->x1 - loc->x0))
+ width = (loc->x1 - loc->x0);
+
+ xoff = loc->x0 - x;
+ yoff = loc->y0 - y;
+
+ pvideo = get_xy_loc(nsfb, loc->x0, loc->y0);
+
+ fgcol = c & 0xFFFFFF;
+
+ for (yloop = 0; yloop < height; yloop++) {
+ for (xloop = 0; xloop < width; xloop++) {
+ abpixel = (pixel[((yoff + yloop) * pitch) + xloop + xoff] << 24) | fgcol;
+ if ((abpixel & 0xFF000000) != 0) {
+ /* pixel is not transparent */
+ if ((abpixel & 0xFF000000) != 0xFF000000) {
+ abpixel = nsfb_plot_ablend(abpixel,
+ pixel_to_colour(nsfb, *(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = colour_to_pixel(nsfb, abpixel);
+ }
+ }
+ pvideo += nsfb->linelen;
+ }
+
+ return true;
+}
+
+static bool
+bitmap(nsfb_t *nsfb,
+ const nsfb_bbox_t *loc,
+ const nsfb_colour_t *pixel,
+ int bmp_width,
+ int bmp_height,
+ int bmp_stride,
+ bool alpha)
+{
+ uint8_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(nsfb, *(pvideo + xloop)));
+ }
+
+ *(pvideo + xloop) = colour_to_pixel(nsfb, abpixel);
+ }
+ }
+ pvideo += nsfb->linelen;
+ }
+ } 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(nsfb, abpixel);
+ }
+ pvideo += nsfb->linelen;
+ }
+ }
+ return true;
+}
+
+
+static bool readrect(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t *buffer)
+{
+ uint8_t *pvideo;
+ int xloop, yloop;
+ int width;
+
+ if (!nsfb_plot_clip_ctx(nsfb, rect)) {
+ return true;
+ }
+
+ width = rect->x1 - rect->x0;
+
+ pvideo = get_xy_loc(nsfb, rect->x0, rect->y0);
+
+ for (yloop = rect->y0; yloop < rect->y1; yloop += 1) {
+ for (xloop = 0; xloop < width; xloop++) {
+ *buffer = pixel_to_colour(nsfb,*(pvideo + xloop));
+ buffer++;
+ }
+ pvideo += nsfb->linelen;
+ }
+ return true;
+}
+
+
+
+
+const nsfb_plotter_fns_t _nsfb_8bpp_plotters = {
+ .line = line,
+ .fill = fill,
+ .point = point,
+ .bitmap = bitmap,
+ .glyph8 = glyph8,
+ .glyph1 = glyph1,
+ .readrect = readrect,
+};
+
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/src/plot/Makefile b/src/plot/Makefile
new file mode 100644
index 0000000..0c51c02
--- /dev/null
+++ b/src/plot/Makefile
@@ -0,0 +1,4 @@
+# Sources
+DIR_SOURCES := api.c util.c generic.c 32bpp.c 16bpp.c 8bpp.c
+
+include build/makefiles/Makefile.subdir
diff --git a/src/plot/api.c b/src/plot/api.c
new file mode 100644
index 0000000..4de25c9
--- /dev/null
+++ b/src/plot/api.c
@@ -0,0 +1,169 @@
+/* public plotter interface */
+
+#include <stdbool.h>
+
+#include "libnsfb.h"
+#include "libnsfb_plot.h"
+
+#include "nsfb.h"
+#include "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->set_clip(nsfb, clip);
+}
+
+/** Get the previously set clipping region.
+ */
+bool nsfb_plot_get_clip(nsfb_t *nsfb, nsfb_bbox_t *clip)
+{
+ return nsfb->plotter_fns->get_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, nsfb_plot_pen_t *pen)
+{
+ return nsfb->plotter_fns->line(nsfb, 1, line, pen);
+}
+
+/** Plots more than one line.
+ *
+ * Draw a line from (x0,y0) to (x1,y1). Coordinates are at centre of line
+ * width/thickness.
+ */
+bool nsfb_plot_lines(nsfb_t *nsfb, int linec, nsfb_bbox_t *line, nsfb_plot_pen_t *pen)
+{
+ return nsfb->plotter_fns->line(nsfb, linec, line, pen);
+}
+
+/** 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, nsfb_bbox_t *srcbox, nsfb_bbox_t *dstbox)
+{
+ return nsfb->plotter_fns->copy(nsfb, srcbox, dstbox);
+}
+
+bool nsfb_plot_bitmap(nsfb_t *nsfb, const nsfb_bbox_t *loc, const 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);
+}
+
+/** Plot an 8 bit glyph.
+ */
+bool nsfb_plot_glyph8(nsfb_t *nsfb, nsfb_bbox_t *loc, const uint8_t *pixel, int pitch, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->glyph8(nsfb, loc, pixel, pitch, c);
+}
+
+
+/** Plot an 1 bit glyph.
+ */
+bool nsfb_plot_glyph1(nsfb_t *nsfb, nsfb_bbox_t *loc, const uint8_t *pixel, int pitch, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->glyph1(nsfb, loc, pixel, pitch, c);
+}
+
+/* read a rectangle from screen into buffer */
+bool nsfb_plot_readrect(nsfb_t *nsfb, nsfb_bbox_t *rect, nsfb_colour_t *buffer)
+{
+ return nsfb->plotter_fns->readrect(nsfb, rect, buffer);
+}
+
+
+bool nsfb_plot_cubic_bezier(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_point_t *ctrlb, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->cubic(nsfb, curve, ctrla, ctrlb, c);
+}
+
+bool nsfb_plot_quadratic_bezier(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->quadratic(nsfb, curve, ctrla, c);
+}
+
+bool nsfb_plot_path(nsfb_t *nsfb, int pathc, nsfb_plot_pathop_t *pathop, nsfb_plot_pen_t *pen)
+{
+ return nsfb->plotter_fns->path(nsfb, pathc, pathop, pen);
+}
diff --git a/src/plot/generic.c b/src/plot/generic.c
new file mode 100644
index 0000000..d04559e
--- /dev/null
+++ b/src/plot/generic.c
@@ -0,0 +1,663 @@
+/*
+ * Copyright 2009 Vincent Sanders <vince@simtec.co.uk>
+ * Copyright 2009 Michael Drake <tlsa@netsurf-browser.org>
+ *
+ * This file is part of libnsfb, http://www.netsurf-browser.org/
+ * Licenced under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+/** \file
+ * generic plotter functions which are not depth dependant (implementation).
+ */
+
+#include <stdbool.h>
+#include <limits.h>
+#include <malloc.h>
+#include <string.h>
+
+#include "libnsfb.h"
+#include "libnsfb_plot.h"
+#include "libnsfb_plot_util.h"
+
+#include "nsfb.h"
+#include "plot.h"
+#include "frontend.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 get_clip(nsfb_t *nsfb, nsfb_bbox_t *clip)
+{
+ *clip = nsfb->clip;
+ return true;
+}
+
+static bool clg(nsfb_t *nsfb, nsfb_colour_t c)
+{
+ return nsfb->plotter_fns->fill(nsfb, &nsfb->clip, c);
+}
+
+/**
+ * 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 nsfb framebuffer context
+ * \param p array of polygon vertices (x1, y1, x2, y2, ... , xN, yN)
+ * \param n number of polygon vertices (N)
+ * \param c fill colour
+ * \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;
+ nsfb_plot_pen_t pen;
+
+ /* find no. of vertex values */
+ int v = n * 2;
+
+ /* Can't plot polygons with 2 or fewer vertices */
+ if (n <= 2)
+ return true;
+
+ pen.stroke_colour = c;
+
+ /* 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, 1, &fline, &pen);
+
+ /* 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[4];
+ nsfb_plot_pen_t pen;
+
+ pen.stroke_colour = c;
+ pen.stroke_width = line_width;
+ if (dotted || dashed) {
+ pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN;
+ } else {
+ pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
+ }
+
+ side[0] = *rect;
+ side[1] = *rect;
+ side[2] = *rect;
+ side[3] = *rect;
+
+ side[0].y1 = side[0].y0;
+ side[1].y0 = side[1].y1;
+ side[2].x1 = side[2].x0;
+ side[3].x0 = side[3].x1;
+
+ return nsfb->plotter_fns->line(nsfb, 4, side, &pen);
+}
+
+/* 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[2];
+ nsfb_plot_pen_t pen;
+
+ pen.stroke_colour = c;
+
+ fline[0].x0 = fline[1].x0 = cx - x;
+ fline[0].x1 = fline[1].x1 = cx + x;
+ fline[0].y0 = fline[0].y1 = cy + y;
+ fline[1].y0 = fline[1].y1 = cy - y;
+
+ nsfb->plotter_fns->line(nsfb, 2, fline, &pen);
+
+}
+
+#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[4];
+ nsfb_plot_pen_t pen;
+
+ pen.stroke_colour = c;
+
+ fline[0].x0 = fline[1].x0 = cx - x;
+ fline[0].x1 = fline[1].x1 = cx + x;
+ fline[0].y0 = fline[0].y1 = cy + y;
+ fline[1].y0 = fline[1].y1 = cy - y;
+
+ fline[2].x0 = fline[3].x0 = cx - y;
+ fline[2].x1 = fline[3].x1 = cx + y;
+ fline[2].y0 = fline[2].y1 = cy + x;
+ fline[3].y0 = fline[3].y1 = cy - x;
+
+ nsfb->plotter_fns->line(nsfb, 4, fline, &pen);
+}
+
+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);
+ }
+}
+
+
+
+/* copy an area of screen from one location to another.
+ *
+ * @warning This implementation is woefully incomplete!
+ */
+static bool
+copy(nsfb_t *nsfb, nsfb_bbox_t *srcbox, nsfb_bbox_t *dstbox)
+{
+ int srcx = srcbox->x0;
+ int srcy = srcbox->y0;
+ int dstx = dstbox->x0;
+ int dsty = dstbox->y0;
+ int width = dstbox->x1 - dstbox->x0;
+ int height = dstbox->y1 - dstbox->y0;
+ uint8_t *srcptr;
+ uint8_t *dstptr;
+ int hloop;
+ nsfb_bbox_t allbox;
+
+ nsfb_plot_add_rect(srcbox, dstbox, &allbox);
+
+ nsfb->frontend_rtns->claim(nsfb, &allbox);
+
+ srcptr = (nsfb->ptr +
+ (srcy * nsfb->linelen) +
+ ((srcx * nsfb->bpp) / 8));
+
+ dstptr = (nsfb->ptr +
+ (dsty * nsfb->linelen) +
+ ((dstx * nsfb->bpp) / 8));
+
+
+ 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);
+ }
+ }
+ }
+
+ nsfb->frontend_rtns->update(nsfb, dstbox);
+
+ 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;
+}
+
+#define N_SEG 30
+
+static bool
+cubic(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_point_t *ctrlb, nsfb_colour_t cl)
+{
+ nsfb_bbox_t line;
+ nsfb_plot_pen_t pen;
+
+ unsigned int seg_loop;
+ double t;
+ double one_minus_t;
+ double a;
+ double b;
+ double c;
+ double d;
+ double x;
+ double y;
+
+ pen.stroke_colour = cl;
+
+ x = curve->x0;
+ y = curve->y0;
+
+ for (seg_loop = 1; seg_loop <= N_SEG; ++seg_loop) {
+ t = (double)seg_loop / (double)N_SEG;
+
+ one_minus_t = 1.0 - t;
+
+ a = one_minus_t * one_minus_t * one_minus_t;
+ b = 3.0 * t * one_minus_t * one_minus_t;
+ c = 3.0 * t * t * one_minus_t;
+ d = t * t * t;
+
+ line.x0 = x;
+ line.y0 = y;
+
+ x = a * curve->x0 + b * ctrla->x + c * ctrlb->x + d * curve->x1;
+ y = a * curve->y0 + b * ctrla->y + c * ctrlb->y + d * curve->y1;
+
+ line.x1 = x;
+ line.y1 = y;
+
+ nsfb->plotter_fns->line(nsfb, 1, &line, &pen);
+ }
+
+ return true;
+}
+
+static bool quadratic(nsfb_t *nsfb, nsfb_bbox_t *curve, nsfb_point_t *ctrla, nsfb_colour_t cl)
+{
+ nsfb_bbox_t line;
+ nsfb_plot_pen_t pen;
+
+ unsigned int seg_loop;
+ double t;
+ double one_minus_t;
+ double a;
+ double b;
+ double c;
+ double x;
+ double y;
+
+ pen.stroke_colour = cl;
+
+ x = curve->x0;
+ y = curve->y0;
+
+ for (seg_loop = 1; seg_loop <= N_SEG; ++seg_loop) {
+ t = (double)seg_loop / (double)N_SEG;
+
+ one_minus_t = 1.0 - t;
+
+ a = one_minus_t * one_minus_t;
+ b = 2.0 * t * one_minus_t;
+ c = t * t;
+
+ line.x0 = x;
+ line.y0 = y;
+
+ x = a * curve->x0 + b * ctrla->x + c * curve->x1;
+ y = a * curve->y0 + b * ctrla->y + c * curve->y1;
+
+ line.x1 = x;
+ line.y1 = y;
+
+ nsfb->plotter_fns->line(nsfb, 1, &line, &pen);
+ }
+
+ return true;
+}
+
+bool select_plotters(nsfb_t *nsfb)
+{
+ const nsfb_plotter_fns_t *table = NULL;
+
+ 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->set_clip = set_clip;
+ nsfb->plotter_fns->get_clip = get_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;
+ nsfb->plotter_fns->quadratic = quadratic;
+ nsfb->plotter_fns->cubic = cubic;
+
+ /* 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;
+}
diff --git a/src/plot/util.c b/src/plot/util.c
new file mode 100644
index 0000000..cf2ec9b
--- /dev/null
+++ b/src/plot/util.c
@@ -0,0 +1,199 @@
+#include <stdbool.h>
+
+#include "libnsfb.h"
+#include "libnsfb_plot.h"
+#include "libnsfb_plot_util.h"
+
+#include "nsfb.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);
+}
+
+/* documented in libnsfb_plot_util.h */
+bool
+nsfb_plot_add_rect(const nsfb_bbox_t *box1, const nsfb_bbox_t *box2, nsfb_bbox_t *result)
+{
+ /* lower x coordinate */
+ if (box1->x0 < box2->x0)
+ result->x0 = box1->x0;
+ else
+ result->x0 = box2->x0;
+
+ /* lower y coordinate */
+ if (box1->y0 < box2->y0)
+ result->y0 = box1->y0;
+ else
+ result->y0 = box2->y0;
+
+ /* upper x coordinate */
+ if (box1->x1 > box2->x1)
+ result->x1 = box1->x1;
+ else
+ result->x1 = box2->x1;
+
+ /* upper y coordinate */
+ if (box1->y1 > box2->y1)
+ result->y1 = box1->y1;
+ else
+ result->y1 = box2->y1;
+
+ return true;
+}
+
+bool nsfb_plot_bbox_intersect(const nsfb_bbox_t *box1, const nsfb_bbox_t *box2)
+{
+ if (box2->x1 < box1->x0)
+ return false;
+
+ if (box2->y1 < box1->y0)
+ return false;
+
+ if (box2->x0 > box1->x1)
+ return false;
+
+ if (box2->y0 > box1->y1)
+ return false;
+
+ return true;
+}