static bool framebuffer_plot_bitmap(int x, int y, int width, int height, struct bitmap *bitmap, colour bg, bitmap_flags_t flags) { int xf,yf; nsfb_bbox_t loc; nsfb_bbox_t clipbox; bool repeat_x = (flags & BITMAPF_REPEAT_X); bool repeat_y = (flags & BITMAPF_REPEAT_Y); int bmwidth; int bmheight; unsigned char *bmptr; nsfb_t *bm = (nsfb_t *)bitmap; /* x and y define coordinate of top left of of the initial explicitly * placed tile. The width and height are the image scaling and the * bounding box defines the extent of the repeat (which may go in all * four directions from the initial tile). */ if (!(repeat_x || repeat_y)) { /* Not repeating at all, so just plot it */ loc.x0 = x; loc.y0 = y; loc.x1 = loc.x0 + width; loc.y1 = loc.y0 + height; return nsfb_plot_copy(bm, NULL, nsfb, &loc); } nsfb_plot_get_clip(nsfb, &clipbox); nsfb_get_geometry(bm, &bmwidth, &bmheight, NULL); nsfb_get_buffer(bm, &bmptr, NULL); /* Optimise tiled plots of 1x1 bitmaps by replacing with a flat fill * of the area. Can only be done when image is fully opaque. */ if ((bmwidth == 1) && (bmheight == 1)) { if ((*(nsfb_colour_t *)bmptr & 0xff000000) != 0) { return nsfb_plot_rectangle_fill(nsfb, &clipbox, *(nsfb_colour_t *)bmptr); } } /* Optimise tiled plots of bitmaps scaled to 1x1 by replacing with * a flat fill of the area. Can only be done when image is fully * opaque. */ if ((width == 1) && (height == 1)) { if (bitmap_get_opaque(bm)) { /** TODO: Currently using top left pixel. Maybe centre * pixel or average value would be better. */ return nsfb_plot_rectangle_fill(nsfb, &clipbox, *(nsfb_colour_t *)bmptr); } } /* get left most tile position */ if (repeat_x) for (; x > clipbox.x0; x -= width); /* get top most tile position */ if (repeat_y) for (; y > clipbox.y0; y -= height); /* tile down and across to extents */ for (xf = x; xf < clipbox.x1; xf += width) { for (yf = y; yf < clipbox.y1; yf += height) { loc.x0 = xf; loc.y0 = yf; loc.x1 = loc.x0 + width; loc.y1 = loc.y0 + height; nsfb_plot_copy(bm, NULL, nsfb, &loc); if (!repeat_y) break; } if (!repeat_x) break; } return true; }
static void fb_pan(fbtk_widget_t *widget, struct browser_widget_s *bwidget, struct browser_window *bw) { int x; int y; int width; int height; nsfb_bbox_t srcbox; nsfb_bbox_t dstbox; nsfb_t *nsfb = fbtk_get_nsfb(widget); height = fbtk_get_height(widget); width = fbtk_get_width(widget); LOG(("panning %d, %d", bwidget->panx, bwidget->pany)); x = fbtk_get_absx(widget); y = fbtk_get_absy(widget); /* if the pan exceeds the viewport size just redraw the whole area */ if (bwidget->pany >= height || bwidget->pany <= -height || bwidget->panx >= width || bwidget->panx <= -width) { bwidget->scrolly += bwidget->pany; bwidget->scrollx += bwidget->panx; fb_queue_redraw(widget, 0, 0, width, height); /* ensure we don't try to scroll again */ bwidget->panx = 0; bwidget->pany = 0; bwidget->pan_required = false; return; } if (bwidget->pany < 0) { /* pan up by less then viewport height */ srcbox.x0 = x; srcbox.y0 = y; srcbox.x1 = srcbox.x0 + width; srcbox.y1 = srcbox.y0 + height + bwidget->pany; dstbox.x0 = x; dstbox.y0 = y - bwidget->pany; dstbox.x1 = dstbox.x0 + width; dstbox.y1 = dstbox.y0 + height + bwidget->pany; /* move part that remains visible up */ nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox); /* redraw newly exposed area */ bwidget->scrolly += bwidget->pany; fb_queue_redraw(widget, 0, 0, width, - bwidget->pany); } else if (bwidget->pany > 0) { /* pan down by less then viewport height */ srcbox.x0 = x; srcbox.y0 = y + bwidget->pany; srcbox.x1 = srcbox.x0 + width; srcbox.y1 = srcbox.y0 + height - bwidget->pany; dstbox.x0 = x; dstbox.y0 = y; dstbox.x1 = dstbox.x0 + width; dstbox.y1 = dstbox.y0 + height - bwidget->pany; /* move part that remains visible down */ nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox); /* redraw newly exposed area */ bwidget->scrolly += bwidget->pany; fb_queue_redraw(widget, 0, height - bwidget->pany, width, height); } if (bwidget->panx < 0) { /* pan left by less then viewport width */ srcbox.x0 = x; srcbox.y0 = y; srcbox.x1 = srcbox.x0 + width + bwidget->panx; srcbox.y1 = srcbox.y0 + height; dstbox.x0 = x - bwidget->panx; dstbox.y0 = y; dstbox.x1 = dstbox.x0 + width + bwidget->panx; dstbox.y1 = dstbox.y0 + height; /* move part that remains visible left */ nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox); /* redraw newly exposed area */ bwidget->scrollx += bwidget->panx; fb_queue_redraw(widget, 0, 0, -bwidget->panx, height); } else if (bwidget->panx > 0) { /* pan right by less then viewport width */ srcbox.x0 = x + bwidget->panx; srcbox.y0 = y; srcbox.x1 = srcbox.x0 + width - bwidget->panx; srcbox.y1 = srcbox.y0 + height; dstbox.x0 = x; dstbox.y0 = y; dstbox.x1 = dstbox.x0 + width - bwidget->panx; dstbox.y1 = dstbox.y0 + height; /* move part that remains visible right */ nsfb_plot_copy(nsfb, &srcbox, nsfb, &dstbox); /* redraw newly exposed area */ bwidget->scrollx += bwidget->panx; fb_queue_redraw(widget, width - bwidget->panx, 0, width, height); } bwidget->pan_required = false; bwidget->panx = 0; bwidget->pany = 0; }
static bool framebuffer_plot_bitmap(int x, int y, int width, int height, struct bitmap *bitmap, colour bg, bitmap_flags_t flags) { nsfb_bbox_t loc; nsfb_bbox_t clipbox; bool repeat_x = (flags & BITMAPF_REPEAT_X); bool repeat_y = (flags & BITMAPF_REPEAT_Y); int bmwidth; int bmheight; int bmstride; enum nsfb_format_e bmformat; unsigned char *bmptr; nsfb_t *bm = (nsfb_t *)bitmap; /* x and y define coordinate of top left of of the initial explicitly * placed tile. The width and height are the image scaling and the * bounding box defines the extent of the repeat (which may go in all * four directions from the initial tile). */ if (!(repeat_x || repeat_y)) { /* Not repeating at all, so just plot it */ loc.x0 = x; loc.y0 = y; loc.x1 = loc.x0 + width; loc.y1 = loc.y0 + height; return nsfb_plot_copy(bm, NULL, nsfb, &loc); } nsfb_plot_get_clip(nsfb, &clipbox); nsfb_get_geometry(bm, &bmwidth, &bmheight, &bmformat); nsfb_get_buffer(bm, &bmptr, &bmstride); /* Optimise tiled plots of 1x1 bitmaps by replacing with a flat fill * of the area. Can only be done when image is fully opaque. */ if ((bmwidth == 1) && (bmheight == 1)) { if ((*(nsfb_colour_t *)bmptr & 0xff000000) != 0) { return nsfb_plot_rectangle_fill(nsfb, &clipbox, *(nsfb_colour_t *)bmptr); } } /* Optimise tiled plots of bitmaps scaled to 1x1 by replacing with * a flat fill of the area. Can only be done when image is fully * opaque. */ if ((width == 1) && (height == 1)) { if (framebuffer_bitmap_get_opaque(bm)) { /** TODO: Currently using top left pixel. Maybe centre * pixel or average value would be better. */ return nsfb_plot_rectangle_fill(nsfb, &clipbox, *(nsfb_colour_t *)bmptr); } } /* get left most tile position */ if (repeat_x) for (; x > clipbox.x0; x -= width); /* get top most tile position */ if (repeat_y) for (; y > clipbox.y0; y -= height); /* set up top left tile location */ loc.x0 = x; loc.y0 = y; loc.x1 = loc.x0 + width; loc.y1 = loc.y0 + height; /* plot tiling across and down to extents */ nsfb_plot_bitmap_tiles(nsfb, &loc, repeat_x ? ((clipbox.x1 - x) + width - 1) / width : 1, repeat_y ? ((clipbox.y1 - y) + height - 1) / height : 1, (nsfb_colour_t *)bmptr, bmwidth, bmheight, bmstride * 8 / 32, bmformat == NSFB_FMT_ABGR8888); return true; }
int main(int argc, char **argv) { const char *fename; enum nsfb_type_e fetype; nsfb_t *nsfb; nsfb_event_t event; int waitloop = 3; nsfb_bbox_t box; nsfb_bbox_t box2; nsfb_bbox_t box3; uint8_t *fbptr; int fbstride; int p[] = { 300,300, 350,350, 400,300, 450,250, 400,200}; int loop; nsfb_plot_pen_t pen; const char *dumpfile = NULL; if (argc < 2) { fename="sdl"; } else { fename = argv[1]; if (argc >= 3) { dumpfile = argv[2]; } } fetype = nsfb_type_from_name(fename); if (fetype == NSFB_SURFACE_NONE) { fprintf(stderr, "Unable to convert \"%s\" to nsfb surface type\n", fename); return 1; } nsfb = nsfb_new(fetype); if (nsfb == NULL) { fprintf(stderr, "Unable to allocate \"%s\" nsfb surface\n", fename); return 2; } if (nsfb_init(nsfb) == -1) { fprintf(stderr, "Unable to initialise nsfb surface\n"); nsfb_free(nsfb); return 4; } /* get the geometry of the whole screen */ box.x0 = box.y0 = 0; nsfb_get_geometry(nsfb, &box.x1, &box.y1, NULL); nsfb_get_buffer(nsfb, &fbptr, &fbstride); /* claim the whole screen for update */ nsfb_claim(nsfb, &box); /* first test, repeatedly clear the graphics area, should result in the * same operation as a single clear to the final colour */ for (loop = 0; loop < 256;loop++) { nsfb_plot_clg(nsfb, 0xffffff00 | loop); } /* draw black radial lines from the origin */ pen.stroke_colour = 0xff000000; for (loop = 0; loop < box.x1; loop += 20) { box2 = box; box2.x1 = loop; nsfb_plot_line(nsfb, &box2, &pen); } /* draw blue radial lines from the bottom right */ pen.stroke_colour = 0xffff0000; for (loop = 0; loop < box.x1; loop += 20) { box2 = box; box2.x0 = loop; nsfb_plot_line(nsfb, &box2, &pen); } /* draw green radial lines from the bottom left */ pen.stroke_colour = 0xff00ff00; for (loop = 0; loop < box.x1; loop += 20) { box2.x0 = box.x0; box2.x1 = loop; box2.y0 = box.y1; box2.y1 = box.y0; nsfb_plot_line(nsfb, &box2, &pen); } /* draw red radial lines from the top right */ pen.stroke_colour = 0xff0000ff; for (loop = 0; loop < box.x1; loop += 20) { box2.x0 = box.x1; box2.x1 = loop; box2.y0 = box.y0; box2.y1 = box.y1; nsfb_plot_line(nsfb, &box2, &pen); } /* draw an unclipped rectangle */ box2.x0 = box2.y0 = 100; box2.x1 = box2.y1 = 300; nsfb_plot_rectangle_fill(nsfb, &box2, 0xff0000ff); nsfb_plot_rectangle(nsfb, &box2, 1, 0xff00ff00, false, false); nsfb_plot_polygon(nsfb, p, 5, 0xffff0000); nsfb_plot_set_clip(nsfb, &box2); box3.x0 = box3.y0 = 200; box3.x1 = box3.y1 = 400; nsfb_plot_rectangle_fill(nsfb, &box3, 0xff00ffff); nsfb_plot_rectangle(nsfb, &box3, 1, 0xffffff00, false, false); for (loop = 100; loop < 400;loop++) { nsfb_plot_point(nsfb, loop, 150, 0xffaa1111); nsfb_plot_point(nsfb, loop, 160, 0x99aa1111); } nsfb_plot_set_clip(nsfb, NULL); box3.x0 = box3.y0 = 400; box3.x1 = box3.y1 = 600; nsfb_plot_ellipse_fill(nsfb, &box3, 0xffff0000); nsfb_plot_ellipse(nsfb, &box3, 0xff0000ff); box3.x0 = 500; box3.x1 = 700; box3.y0 = 400; box3.y1 = 500; nsfb_plot_ellipse_fill(nsfb, &box3, 0xffff0000); nsfb_plot_ellipse(nsfb, &box3, 0xff0000ff); box3.x0 = 600; box3.x1 = 700; box3.y0 = 300; box3.y1 = 500; nsfb_plot_ellipse_fill(nsfb, &box3, 0xff0000ff); nsfb_plot_ellipse(nsfb, &box3, 0xffff0000); box2.x0 = 400; box2.y0 = 400; box2.x1 = 500; box2.y1 = 500; box3.x0 = 600; box3.y0 = 200; box3.x1 = 700; box3.y1 = 300; nsfb_plot_copy(nsfb, &box2, nsfb, &box3); /* test glyph plotting */ for (loop = 100; loop < 200; loop+= Mglyph1.w) { box3.x0 = loop; box3.y0 = 20; box3.x1 = box3.x0 + Mglyph8.w; box3.y1 = box3.y0 + Mglyph8.h; nsfb_plot_glyph1(nsfb, &box3, Mglyph1.data, Mglyph1.w, 0xff000000); } /* test glyph plotting */ for (loop = 100; loop < 200; loop+= Mglyph8.w) { box3.x0 = loop; box3.y0 = 50; box3.x1 = box3.x0 + Mglyph8.w; box3.y1 = box3.y0 + Mglyph8.h; nsfb_plot_glyph8(nsfb, &box3, Mglyph8.data, Mglyph8.w, 0xff000000); } nsfb_update(nsfb, &box); /* random rectangles in clipped area*/ box2.x0 = 400; box2.y0 = 50; box2.x1 = 600; box2.y1 = 100; nsfb_plot_set_clip(nsfb, &box2); srand(1234); for (loop=0; loop < 10000; loop++) { nsfb_claim(nsfb, &box2); box3.x0 = rand() / (RAND_MAX / box.x1); box3.y0 = rand() / (RAND_MAX / box.y1); box3.x1 = rand() / (RAND_MAX / 400); box3.y1 = rand() / (RAND_MAX / 400); nsfb_plot_rectangle_fill(nsfb, &box3, 0xff000000 | rand()); nsfb_update(nsfb, &box2); } /* wait for quit event or timeout */ while (waitloop > 0) { if (nsfb_event(nsfb, &event, 1000) == false) { break; } if (event.type == NSFB_EVENT_CONTROL) { if (event.value.controlcode == NSFB_CONTROL_TIMEOUT) { /* timeout */ waitloop--; } else if (event.value.controlcode == NSFB_CONTROL_QUIT) { break; } } } dump(nsfb, dumpfile); nsfb_free(nsfb); return 0; }