From 6bf6f3de96bc0f7884341de312a27b7e6a18a23c Mon Sep 17 00:00:00 2001 From: Stefan `Sec` Zehl Date: Fri, 5 Aug 2011 19:17:31 +0200 Subject: [PATCH] Commit of pippin vector/graphics lib. Yay! --- firmware/applications/rockets.c | 44 + firmware/l0dable/EXPORTS | 9 + firmware/l0dable/rockets.c | 155 ++++ firmware/lcd/Makefile | 1 + firmware/lcd/lcd.h | 1 + firmware/lcd/o-glyphs.c | 703 +++++++++++++++ firmware/lcd/o.c | 1489 +++++++++++++++++++++++++++++++ firmware/lcd/o.h | 141 +++ firmware/lpc1xxx/linkscript.ld | 162 ++-- 9 files changed, 2624 insertions(+), 81 deletions(-) create mode 100644 firmware/applications/rockets.c create mode 100644 firmware/l0dable/rockets.c create mode 100644 firmware/lcd/o-glyphs.c create mode 100644 firmware/lcd/o.c create mode 100644 firmware/lcd/o.h diff --git a/firmware/applications/rockets.c b/firmware/applications/rockets.c new file mode 100644 index 0000000..e2dacd6 --- /dev/null +++ b/firmware/applications/rockets.c @@ -0,0 +1,44 @@ +#include +#include "basic/basic.h" +#include "lcd/lcd.h" + +static void draw_rakett (int x, int y, int angle); + +void main_rockets (void) { + char test[512]; /* scratch space */ + o_init (test, sizeof(test)); + int frame_no; + while (1) { + o_identity (); /* reset transforms */ + o_rectangle (0,0,RESX, RESY); + o_set_gray (500); + o_fill (); /* fill with 50% gray */ + + draw_rakett (20, 20, 10*frame_no++); + draw_rakett (50, 40, 450+14*frame_no++); + lcdDisplay(); + delayms(1); + } +} + +signed char rakett[] = { + ' ', + 'm',38,6, + 'c',38,6,36,13,36,15, + 'c',24,22,23,26,21,32,'c',19,41,23,61,23,61,'c',15,73,14,95,17,110,'l',26,109,'c',26,102,26,87,30,83,'c',30,83,30,88,30,95,'c',31,103,31,108,31,108,'l',36,108,'c',36,108,35,98,36,91,'c',37,83,38,80,38,80,'c',41,79,43,80,47,79,'c',56,85,56,89,58,99,'c',58,103,58,108,58,108,'l',68,108,'c',67,89,69,73,54,58,'c',54,58,56,41,53,31,'c',50,21,40,15,40,15,'l',38,6,'z','g',0,'f','g',100,'s', + ' ', + 'm',33,20,'c',31,20,29,21,27,22,'c',25,24,23,27,22,29,'c',20,35,21,38,21,38,'c',26,38,29,36,34,33,'c',38,31,42,24,34,21,'c',34,21,33,20,33,20,'z','g',100,'f','\0' +}; + +static void draw_rakett (int x, int y, int angle) +{ + //o_save (); + o_identity (); /* reset transform stack */ + o_translate(x * 1000, y * 1000); + o_rotate (angle); + o_scale (500, 500); + o_translate (-37000, -60000); + o_render (rakett); /* render a rocket */ + //o_restore (); +} + diff --git a/firmware/l0dable/EXPORTS b/firmware/l0dable/EXPORTS index b156bfd..c74165a 100644 --- a/firmware/l0dable/EXPORTS +++ b/firmware/l0dable/EXPORTS @@ -104,3 +104,12 @@ systickGetTicks uint32touint8p uint8ptouint32 #Add stuff here +o_init +o_path_new +o_move_to +o_line_to +o_curve_to +o_close +o_set_gray +o_fill +o_set_shader diff --git a/firmware/l0dable/rockets.c b/firmware/l0dable/rockets.c new file mode 100644 index 0000000..0d42500 --- /dev/null +++ b/firmware/l0dable/rockets.c @@ -0,0 +1,155 @@ +#include +#include "basic/basic.h" +#include "lcd/lcd.h" +#include "usetable.h" + +#define SPP 10 + +static void draw_rakett (int x, int y, int scale, int angle); + +void ram (void) { + char test[384]; /* scratch space */ + o_init (test, sizeof(test)); + int frame_no = 0; + int frame_dir = 1; + while (1) { + o_rectangle (0,0,RESX, RESY); + o_set_gray (1000); + o_fill (); /* fill with 50% gray */ + + draw_rakett (40, 20, frame_no / 3, 150*frame_no); + draw_rakett (20, 20, frame_no, 10*frame_no); + draw_rakett (80, 30, 1000-frame_no, 450+14*frame_no); + frame_no += frame_dir; + lcdDisplay(); + delayms(2); + + if (frame_no > 1000 || frame_no < 0) + frame_dir *= -1; + } +} + +static signed char rakett[] = { + ' ', + 'm',38,6, + 'c',38,6,36,13,36,15, + 'c',24,22,23,26,21,32,'c',19,41,23,61,23,61,'c',15,73,14,95,17,110,'l',26,109,'c',26,102,26,87,30,83,'c',30,83,30,88,30,95,'c',31,103,31,108,31,108,'l',36,108,'c',36,108,35,98,36,91,'c',37,83,38,80,38,80,'c',41,79,43,80,47,79,'c',56,85,56,89,58,99,'c',58,103,58,108,58,108,'l',68,108,'c',67,89,69,73,54,58,'c',54,58,56,41,53,31,'c',50,21,40,15,40,15,'l',38,6,'z','g',0,'f', + ' ', + 'm',33,20,'c',31,20,29,21,27,22,'c',25,24,23,27,22,29,'c',20,35,21,38,21,38,'c',26,38,29,36,34,33,'c',38,31,42,24,34,21,'c',34,21,33,20,33,20,'z','g', 50,'f','.' +}; + +#define GRAY_PRECISION 4 +/* Default color generator shader */ +static int shader_gray (int x, int y, void *data) +{ + int value = (int)(data); /* stored gray value as 8bit value */ + switch (value) /* the dither patterns are can be seen */ + { /* at the end of the lines */ + case 0: /* 0.0 */ + return 0; + case 1: /* 0.16 */ + return (x%3==0) ? (y %2)? 0:0: + (x%3==1) ? (y %2)? 0:0: + (y %2)? 0:1; + case 2: /* 0.25 */ + return (x%2) ? (y %2)? 1:0: + (y %2)? 0:0; + case 3: /* 0.33 */ + return (x%3==0) ? (y %2)? 1:0: + (x%3==1) ? (y %2)? 0:0: + (y %2)? 0:1; + case 4: /* 0.50 */ + return (x%2==0) ? (y %2)? 1:0: + (y %2)? 0:1; + case 5: /* 0.66 */ + return (x%3==0) ? (y %2)? 0:1: + (x%3==1) ? (y %2)? 1:1: + (y %2)? 1:0; + case 6: /* 0.75 */ + return (x%2) ? (y %2)? 1:0: + (y %2)? 1:1; + case 7: /* 0.85 */ + return (x%3==0) ? (y %2)? 1:1: + (x%3==1) ? (y %2)? 1:0: + (y %2)? 1:1; + case 8: /* 1.0 */ + return 1; + default: // return ((char)(rnd1())) < value; + /* XXX: use a faster "random" source + for this fallback */ + break; + } + return 0; +} + +static const signed char * o_process_op (const signed char *g, + int scale, + int x, + int y) +{ + scale *= SPP; + switch (*g++) { + + case ' ': o_path_new (); break; + /* all of these path commands are directly in integer coordinates */ + case 'm': + o_move_to (g[0]*scale/1000+x, g[1]*scale/1000+y); g += 2; +break; + case 'l': o_line_to (g[0]*scale/1000+x, g[1]*scale/1000+y); g += 2; break; + case 'c': o_curve_to (g[0]*scale/1000+x, g[1]*scale/1000+y, g[2]*scale/1000+x, g[3]*scale/1000+y, g[4]*scale/1000+x, g[5]*scale/1000+y); g += 6; break; + case 'z': o_close (); break; + + case 'g': o_set_gray (g[0]*10); g ++; break; + + case 'f': o_fill (); break; + /* 1 = 1 10 = 10 100 = 100 */ +#if 0 + case '!': o_identity (); break; + case 'T': o_translate (g[0] * 100, g[1] * 100); g+=2; break; + /* 1 = 0.01 10 = 0.1 50 = 0.5 100 = 10x */ + case 'S': o_scale (g[0] * 10, g[1] * 10); g+=2; break; + /* -128 = -360 64 = 180 128 = 360 */ + case 'R': o_rotate ((g[0] * 3600)/127); g+=1; break; +#endif + + default: + case '\0': + case '.': /* end */ + return NULL; + } + return g; +} + +static void +orender (const signed char *g, int scale, int x, int y) +{ + o_set_shader (shader_gray, NULL); + for (; g; g = o_process_op (g, scale, x, y)); +} + + +void o_rectangle (int x0, int y0, int width, int height) +{ + o_path_new (); + x0*=SPP; + y0*=SPP; + width*=SPP; + height*=SPP; + o_move_to (x0, y0); + o_line_to (x0 + width, y0); + o_line_to (x0 + width, y0+height); + o_line_to (x0, y0+height); + o_close (); +} + +void draw_rakett (int x, int y, int scale, int angle) +{ + //o_save (); + //o_identity (); /* reset transform stack */ + //o_translate(x * 1000, y * 1000); + //o_rotate (angle); + //o_scale (scale, scale); + //o_translate (-37000, -60000); + orender (rakett, scale, x, y); /* render a rocket */ + //o_restore (); +} diff --git a/firmware/lcd/Makefile b/firmware/lcd/Makefile index e9b8d76..60e2f08 100644 --- a/firmware/lcd/Makefile +++ b/firmware/lcd/Makefile @@ -10,6 +10,7 @@ OBJS += decoder.o OBJS += backlight.o OBJS += print.o OBJS += image.o +OBJS += o.o FONTS = $(basename $(wildcard fonts/*.c)) diff --git a/firmware/lcd/lcd.h b/firmware/lcd/lcd.h index cfff09e..91e3490 100644 --- a/firmware/lcd/lcd.h +++ b/firmware/lcd/lcd.h @@ -3,3 +3,4 @@ #include "lcd/display.h" #include "lcd/render.h" #include "lcd/fonts/smallfonts.h" +#include "lcd/o.h" diff --git a/firmware/lcd/o-glyphs.c b/firmware/lcd/o-glyphs.c new file mode 100644 index 0000000..0ee2c6b --- /dev/null +++ b/firmware/lcd/o-glyphs.c @@ -0,0 +1,703 @@ +/* + * Hershey glyph set string encoded in C, copied from Keith Packards twin system. + * + * Copyright © 2004 Keith Packard + * Copyright © 2011 Øyvind Kolås + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +const signed char _o_glyphs[] = { +/* 0x0 '\0' */ + 'm', 0, 0, + 'l', 0, -42, + 'l', 24, -42, + 'l', 24, 0, + 'z', + 's', '.', +/* 0x20 ' ' */ + 's', '.', +/* 0x21 '!' */ + 'm', 2, -42, + 'l', 2, -14, + 'm', 2, -4, + 'c', 1, -4, 0, -3, 0, -2, + 'c', 0, -1, 1, 0, 2, 0, + 'c', 3, 0, 4, -1, 4, -2, + 'c', 4, -3, 3, -4, 2, -4, + 's', '.', +/* 0x22 '"' */ + 'm', 0, -42, + 'l', 0, -28, + 'm', 16, -42, + 'l', 16, -28, + 's', '.', +/* 0x23 '#' */ + 'm', 16, -50, + 'l', 2, 14, + 'm', 28, -50, + 'l', 14, 14, + 'm', 2, -24, + 'l', 30, -24, + 'm', 0, -12, + 'l', 28, -12, + 's', '.', +/* 0x24 '$' */ + 's', '.', +/* 0x25 '%' */ + 's', '.', +/* 0x26 '&' */ + 'm', 40, -24, + 'c', 40, -27, 39, -28, 37, -28, + 'c', 29, -28, 32, 0, 12, 0, + 'c', 0, 0, 0, -8, 0, -10, + 'c', 0, -24, 22, -20, 22, -34, + 'c', 22, -45, 10, -45, 10, -34, + 'c', 10, -27, 25, 0, 36, 0, + 'c', 39, 0, 40, -1, 40, -4, + 's', '.', +/* 0x27 ''' */ + 'm', 2, -38, + 'c', -1, -38, -1, -42, 2, -42, + 'c', 6, -42, 5, -33, 0, -30, + 's', '.', +/* 0x28 '(' */ + 'm', 14, -50, + 'c', -5, -32, -5, -5, 14, 14, + 's', '.', +/* 0x29 ')' */ + 'm', 0, -50, + 'c', 19, -34, 19, -2, 0, 14, + 's', '.', +/* 0x2a '*' */ + 'm', 10, -30, + 'l', 10, -6, + 'm', 0, -24, + 'l', 20, -12, + 'm', 20, -24, + 'l', 0, -12, + 's', '.', +/* 0x2b '+' */ + 'm', 18, -36, + 'l', 18, 0, + 'm', 0, -18, + 'l', 36, -18, + 's', '.', +/* 0x2c ',' */ + 'm', 4, -2, + 'c', 4, 1, 0, 1, 0, -2, + 'c', 0, -5, 4, -5, 4, -2, + 'c', 4, 4, 2, 6, 0, 8, + 's', '.', +/* 0x2d '-' */ + 'm', 0, -18, + 'l', 36, -18, + 's', '.', +/* 0x2e 's', '.' */ + 'm', 2, -4, + 'c', -1, -4, -1, 0, 2, 0, + 'c', 5, 0, 5, -4, 2, -4, + 's', '.', +/* 0x2f '/' */ + 'm', 36, -50, + 'l', 0, 14, + 's', '.', +/* 0x30 '0' */ + 'm', 14, -42, + 'c', 9, -42, 0, -42, 0, -21, + 'c', 0, 0, 9, 0, 14, 0, + 'c', 19, 0, 28, 0, 28, -21, + 'c', 28, -42, 19, -42, 14, -42, + 's', '.', +/* 0x31 '1' */ + 'm', 7, -34, + 'c', 11, -35, 15, -38, 17, -42, + 'l', 17, 0, + 's', '.', +/* 0x32 '2' */ + 'm', 2, -32, + 'c', 2, -34, 2, -42, 14, -42, + 'c', 26, -42, 26, -34, 26, -32, + 'c', 26, -30, 25, -25, 10, -10, + 'l', 0, 0, + 'l', 28, 0, + 's', '.', +/* 0x33 '3' */ + 'm', 4, -42, + 'l', 26, -42, + 'l', 14, -26, + 'c', 21, -26, 28, -26, 28, -14, + 'c', 28, 0, 17, 0, 13, 0, + 'c', 8, 0, 3, -1, 0, -8, + 's', '.', +/* 0x34 '4' */ + 'm', 20, -42, + 'l', 0, -14, + 'l', 30, -14, + 'm', 20, -42, + 'l', 20, 0, + 's', '.', +/* 0x35 '5' */ + 'm', 24, -42, + 'l', 4, -42, + 'l', 2, -24, + 'c', 5, -27, 10, -28, 13, -28, + 'c', 16, -28, 28, -28, 28, -14, + 'c', 28, 0, 16, 0, 13, 0, + 'c', 10, 0, 3, 0, 0, -8, + 's', '.', +/* 0x36 '6' */ + 'm', 24, -36, + 'c', 22, -41, 19, -42, 14, -42, + 'c', 9, -42, 0, -41, 0, -19, + 'c', 0, -1, 9, 0, 13, 0, + 'c', 18, 0, 26, -3, 26, -13, + 'c', 26, -18, 23, -26, 13, -26, + 'c', 10, -26, 1, -24, 0, -14, + 's', '.', +/* 0x37 '7' */ + 'm', 28, -42, + 'l', 8, 0, + 'm', 0, -42, + 'l', 28, -42, + 's', '.', +/* 0x38 '8' */ + 'm', 14, -42, + 'c', 5, -42, 2, -40, 2, -34, + 'c', 2, -18, 28, -32, 28, -11, + 'c', 28, 0, 18, 0, 14, 0, + 'c', 10, 0, 0, 0, 0, -11, + 'c', 0, -32, 26, -18, 26, -34, + 'c', 26, -40, 23, -42, 14, -42, + 's', '.', +/* 0x39 '9' */ + 'm', 26, -28, + 'c', 25, -16, 13, -16, 13, -16, + 'c', 8, -16, 0, -19, 0, -29, + 'c', 0, -34, 3, -42, 13, -42, + 'c', 24, -42, 26, -32, 26, -23, + 'c', 26, -14, 24, 0, 12, 0, + 'c', 7, 0, 4, -2, 2, -6, + 's', '.', +/* 0x3a ':' */ + 'm', 2, -28, + 'c', -1, -28, -1, -24, 2, -24, + 'c', 5, -24, 5, -28, 2, -28, + 'm', 2, -4, + 'c', -1, -4, -1, 0, 2, 0, + 'c', 5, 0, 5, -4, 2, -4, + 's', '.', +/* 0x3b ';' */ + 'm', 2, -28, + 'c', -1, -28, -1, -24, 2, -24, + 'c', 5, -24, 5, -28, 2, -28, + 'm', 4, -2, + 'c', 4, 1, 0, 1, 0, -2, + 'c', 0, -5, 4, -5, 4, -2, + 'c', 4, 3, 2, 6, 0, 8, + 's', '.', +/* 0x3c '<' */ + 'm', 32, -36, + 'l', 0, -18, + 'l', 32, 0, + 's', '.', +/* 0x3d '=' */ + 'm', 0, -24, + 'l', 36, -24, + 'm', 0, -12, + 'l', 36, -12, + 's', '.', +/* 0x3e '>' */ + 'm', 0, -36, + 'l', 32, -18, + 'l', 0, 0, + 's', '.', +/* 0x3f '?' */ + 'm', 0, -32, + 'c', 0, -34, 0, -42, 12, -42, + 'c', 24, -42, 24, -34, 24, -32, + 'c', 24, -29, 24, -24, 12, -20, + 'l', 12, -14, + 'm', 12, -4, + 'c', 9, -4, 9, 0, 12, 0, + 'c', 15, 0, 15, -4, 12, -4, + 's', '.', +/* 0x40 '@' */ + 'm', 30, -26, + 'c', 28, -31, 24, -32, 21, -32, + 'c', 10, -32, 10, -23, 10, -19, + 'c', 10, -13, 11, -10, 19, -10, + 'c', 30, -10, 28, -21, 30, -32, + 'c', 27, -10, 30, -10, 34, -10, + 'c', 41, -10, 42, -19, 42, -22, + 'c', 42, -34, 34, -42, 21, -42, + 'c', 9, -42, 0, -34, 0, -21, + 'c', 0, -9, 8, 0, 21, 0, + 'c', 30, 0, 34, -3, 36, -6, + 's', '.', +/* 0x41 'A' */ + 'm', 16, -42, + 'l', 0, 0, + 'm', 16, -42, + 'l', 32, 0, + 'm', 6, -14, + 'l', 26, -14, + 's', '.', +/* 0x42 'B' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -42, + 'l', 18, -42, + 'c', 32, -42, 32, -22, 18, -22, + 'm', 0, -22, + 'l', 18, -22, + 'c', 32, -22, 32, 0, 18, 0, + 'l', 0, 0, + 's', '.', +/* 0x43 'C' */ + 'm', 30, -32, + 'c', 26, -42, 21, -42, 16, -42, + 'c', 2, -42, 0, -29, 0, -21, + 'c', 0, -13, 2, 0, 16, 0, + 'c', 21, 0, 26, 0, 30, -10, + 's', '.', +/* 0x44 'D' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -42, + 'l', 14, -42, + 'c', 33, -42, 33, 0, 14, 0, + 'l', 0, 0, + 's', '.', +/* 0x45 'E' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -42, + 'l', 26, -42, + 'm', 0, -22, + 'l', 16, -22, + 'm', 0, 0, + 'l', 26, 0, + 's', '.', +/* 0x46 'F' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -42, + 'l', 26, -42, + 'm', 0, -22, + 'l', 16, -22, + 's', '.', +/* 0x47 'G' */ + 'm', 30, -32, + 'c', 26, -42, 21, -42, 16, -42, + 'c', 2, -42, 0, -29, 0, -21, + 'c', 0, -13, 2, 0, 16, 0, + 'c', 28, 0, 30, -7, 30, -16, + 'm', 20, -16, + 'l', 30, -16, + 's', '.', +/* 0x48 'H' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 28, -42, + 'l', 28, 0, + 'm', 0, -22, + 'l', 28, -22, + 's', '.', +/* 0x49 'I' */ + 'm', 0, -42, + 'l', 0, 0, + 's', '.', +/* 0x4a 'J' */ + 'm', 20, -42, + 'l', 20, -10, + 'c', 20, 3, 0, 3, 0, -10, + 'l', 0, -14, + 's', '.', +/* 0x4b 'K' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 28, -42, + 'l', 0, -14, + 'm', 10, -24, + 'l', 28, 0, + 's', '.', +/* 0x4c 'L' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, 0, + 'l', 24, 0, + 's', '.', +/* 0x4d 'M' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -42, + 'l', 16, 0, + 'm', 32, -42, + 'l', 16, 0, + 'm', 32, -42, + 'l', 32, 0, + 's', '.', +/* 0x4e 'N' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -42, + 'l', 28, 0, + 'm', 28, -42, + 'l', 28, 0, + 's', '.', +/* 0x4f 'O' */ + 'm', 16, -42, + 'c', 2, -42, 0, -29, 0, -21, + 'c', 0, -13, 2, 0, 16, 0, + 'c', 30, 0, 32, -13, 32, -21, + 'c', 32, -29, 30, -42, 16, -42, + 's', '.', +/* 0x50 'P' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -42, + 'l', 18, -42, + 'c', 32, -42, 32, -20, 18, -20, + 'l', 0, -20, + 's', '.', +/* 0x51 'Q' */ + 'm', 16, -42, + 'c', 2, -42, 0, -29, 0, -21, + 'c', 0, -13, 2, 0, 16, 0, + 'c', 30, 0, 32, -13, 32, -21, + 'c', 32, -29, 30, -42, 16, -42, + 'm', 18, -8, + 'l', 30, 4, + 's', '.', +/* 0x52 'R' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -42, + 'l', 18, -42, + 'c', 32, -42, 31, -22, 18, -22, + 'l', 0, -22, + 'm', 14, -22, + 'l', 28, 0, + 's', '.', +/* 0x53 'S' */ + 'm', 28, -36, + 'c', 25, -41, 21, -42, 14, -42, + 'c', 10, -42, 0, -42, 0, -34, + 'c', 0, -17, 28, -28, 28, -9, + 'c', 28, 0, 19, 0, 14, 0, + 'c', 7, 0, 3, -1, 0, -6, + 's', '.', +/* 0x54 'T' */ + 'm', 14, -42, + 'l', 14, 0, + 'm', 0, -42, + 'l', 28, -42, + 's', '.', +/* 0x55 'U' */ + 'm', 0, -42, + 'l', 0, -12, + 'c', 0, 4, 28, 4, 28, -12, + 'l', 28, -42, + 's', '.', +/* 0x56 'V' */ + 'm', 0, -42, + 'l', 16, 0, + 'm', 32, -42, + 'l', 16, 0, + 's', '.', +/* 0x57 'W' */ + 'm', 0, -42, + 'l', 10, 0, + 'm', 20, -42, + 'l', 10, 0, + 'm', 20, -42, + 'l', 30, 0, + 'm', 40, -42, + 'l', 30, 0, + 's', '.', +/* 0x58 'X' */ + 'm', 0, -42, + 'l', 28, 0, + 'm', 28, -42, + 'l', 0, 0, + 's', '.', +/* 0x59 'Y' */ + 'm', 0, -42, + 'l', 16, -22, + 'l', 16, 0, + 'm', 32, -42, + 'l', 16, -22, + 's', '.', +/* 0x5a 'Z' */ + 'm', 28, -42, + 'l', 0, 0, + 'm', 0, -42, + 'l', 28, -42, + 'm', 0, 0, + 'l', 28, 0, + 's', '.', +/* 0x5b '[' */ + 'm', 14, -44, + 'l', 0, -44, + 'l', 0, 0, + 'l', 14, 0, + 's', '.', +/* 0x5c '\' */ + 'm', 0, -50, + 'l', 36, 14, + 's', '.', +/* 0x5d ']' */ + 'm', 0, -44, + 'l', 14, -44, + 'l', 14, 0, + 'l', 0, 0, + 's', '.', +/* 0x5e '^' */ + 'm', 16, -46, + 'l', 0, -18, + 'm', 16, -46, + 'l', 32, -18, + 's', '.', +/* 0x5f '_' */ + 'm', 0, 0, + 'l', 36, 0, + 's', '.', +/* 0x60 '`' */ + 'm', 4, -42, + 'c', 2, -40, 0, -39, 0, -32, + 'c', 0, -31, 1, -30, 2, -30, + 'c', 5, -30, 5, -34, 2, -34, + 's', '.', +/* 0x61 'a' */ + 'm', 24, -28, + 'l', 24, 0, + 'm', 24, -22, + 'c', 21, -27, 18, -28, 13, -28, + 'c', 2, -28, 0, -19, 0, -14, + 'c', 0, -9, 2, 0, 13, 0, + 'c', 18, 0, 21, -1, 24, -6, + 's', '.', +/* 0x62 'b' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -22, + 'c', 3, -26, 6, -28, 11, -28, + 'c', 22, -28, 24, -19, 24, -14, + 'c', 24, -9, 22, 0, 11, 0, + 'c', 6, 0, 3, -2, 0, -6, + 's', '.', +/* 0x63 'c' */ + 'm', 24, -22, + 'c', 21, -26, 18, -28, 13, -28, + 'c', 2, -28, 0, -19, 0, -14, + 'c', 0, -9, 2, 0, 13, 0, + 'c', 18, 0, 21, -2, 24, -6, + 's', '.', +/* 0x64 'd' */ + 'm', 24, -42, + 'l', 24, 0, + 'm', 24, -22, + 'c', 21, -26, 18, -28, 13, -28, + 'c', 2, -28, 0, -19, 0, -14, + 'c', 0, -9, 2, 0, 13, 0, + 'c', 18, 0, 21, -2, 24, -6, + 's', '.', +/* 0x65 's', '.' */ + 'm', 0, -16, + 'l', 24, -16, + 'c', 24, -20, 24, -28, 13, -28, + 'c', 2, -28, 0, -19, 0, -14, + 'c', 0, -9, 2, 0, 13, 0, + 'c', 18, 0, 21, -2, 24, -6, + 's', '.', +/* 0x66 'f' */ + 'm', 16, -42, + 'c', 8, -42, 6, -40, 6, -34, + 'l', 6, 0, + 'm', 0, -28, + 'l', 14, -28, + 's', '.', +/* 0x67 'g' */ + 'm', 24, -28, + 'l', 24, 4, + 'c', 23, 14, 16, 14, 13, 14, + 'c', 10, 14, 8, 14, 6, 12, + 'm', 24, -22, + 'c', 21, -26, 18, -28, 13, -28, + 'c', 2, -28, 0, -19, 0, -14, + 'c', 0, -9, 2, 0, 13, 0, + 'c', 18, 0, 21, -2, 24, -6, + 's', '.', +/* 0x68 'h' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 0, -20, + 'c', 8, -32, 22, -31, 22, -20, + 'l', 22, 0, + 's', '.', +/* 0x69 'i' */ + 'm', 0, -42, + 'c', 0, -39, 4, -39, 4, -42, + 'c', 4, -45, 0, -45, 0, -42, + 'm', 2, -28, + 'l', 2, 0, + 's', '.', +/* 0x6a 'j' */ + 'm', 0, -42, + 'c', 0, -39, 4, -39, 4, -42, + 'c', 4, -45, 0, -45, 0, -42, + 'm', 2, -28, + 'l', 2, 6, + 'c', 2, 13, -1, 14, -8, 14, + 's', '.', +/* 0x6b 'k' */ + 'm', 0, -42, + 'l', 0, 0, + 'm', 20, -28, + 'l', 0, -8, + 'm', 8, -16, + 'l', 22, 0, + 's', '.', +/* 0x6c 'l' */ + 'm', 0, -42, + 'l', 0, 0, + 's', '.', +/* 0x6d 'm' */ + 'm', 0, -28, + 'l', 0, 0, + 'm', 0, -20, + 'c', 5, -29, 22, -33, 22, -20, + 'l', 22, 0, + 'm', 22, -20, + 'c', 27, -29, 44, -33, 44, -20, + 'l', 44, 0, + 's', '.', +/* 0x6e 'n' */ + 'm', 0, -28, + 'l', 0, 0, + 'm', 0, -20, + 'c', 4, -28, 22, -34, 22, -20, + 'l', 22, 0, + 's', '.', +/* 0x6f 'o' */ + 'm', 13, -28, + 'c', 2, -28, 0, -19, 0, -14, + 'c', 0, -9, 2, 0, 13, 0, + 'c', 24, 0, 26, -9, 26, -14, + 'c', 26, -19, 24, -28, 13, -28, + 's', '.', +/* 0x70 'p' */ + 'm', 0, -28, + 'l', 0, 14, + 'm', 0, -22, + 'c', 3, -26, 6, -28, 11, -28, + 'c', 22, -28, 24, -19, 24, -14, + 'c', 24, -9, 22, 0, 11, 0, + 'c', 6, 0, 3, -2, 0, -6, + 's', '.', +/* 0x71 'q' */ + 'm', 24, -28, + 'l', 24, 14, + 'm', 24, -22, + 'c', 21, -26, 18, -28, 13, -28, + 'c', 2, -28, 0, -19, 0, -14, + 'c', 0, -9, 2, 0, 13, 0, + 'c', 18, 0, 21, -2, 24, -6, + 's', '.', +/* 0x72 'r' */ + 'm', 0, -28, + 'l', 0, 0, + 'm', 0, -16, + 'c', 2, -27, 7, -28, 16, -28, + 's', '.', +/* 0x73 's' */ + 'm', 22, -22, + 'c', 22, -27, 16, -28, 11, -28, + 'c', 4, -28, 0, -26, 0, -22, + 'c', 0, -11, 22, -20, 22, -7, + 'c', 22, 0, 17, 0, 11, 0, + 'c', 6, 0, 0, -1, 0, -6, + 's', '.', +/* 0x74 't' */ + 'm', 6, -42, + 'l', 6, -8, + 'c', 6, -2, 8, 0, 16, 0, + 'm', 0, -28, + 'l', 14, -28, + 's', '.', +/* 0x75 'u' */ + 'm', 0, -28, + 'l', 0, -8, + 'c', 0, 6, 18, 0, 22, -8, + 'm', 22, -28, + 'l', 22, 0, + 's', '.', +/* 0x76 'v' */ + 'm', 0, -28, + 'l', 12, 0, + 'm', 24, -28, + 'l', 12, 0, + 's', '.', +/* 0x77 'w' */ + 'm', 0, -28, + 'l', 8, 0, + 'm', 16, -28, + 'l', 8, 0, + 'm', 16, -28, + 'l', 24, 0, + 'm', 32, -28, + 'l', 24, 0, + 's', '.', +/* 0x78 'x' */ + 'm', 0, -28, + 'l', 22, 0, + 'm', 22, -28, + 'l', 0, 0, + 's', '.', +/* 0x79 'y' */ + 'm', 0, -28, + 'l', 12, 0, + 'm', 24, -28, + 'l', 12, 0, + 'c', 6, 13, 0, 14, -2, 14, + 's', '.', +/* 0x7a 'z' */ + 'm', 22, -28, + 'l', 0, 0, + 'm', 0, -28, + 'l', 22, -28, + 'm', 0, 0, + 'l', 22, 0, + 's', '.', +/* 0x7b '{' */ + 's', '.', +/* 0x7c '|' */ + 'm', 0, -50, + 'l', 0, 14, + 's', '.', +/* 0x7d '}' */ + 's', '.', +/* 0x7e '~' */ + 'm', 0, -14, + 'c', 1, -21, 4, -24, 8, -24, + 'c', 18, -24, 18, -12, 28, -12, + 'c', 32, -12, 35, -15, 36, -22, + 's', '.', +}; diff --git a/firmware/lcd/o.c b/firmware/lcd/o.c new file mode 100644 index 0000000..33a1933 --- /dev/null +++ b/firmware/lcd/o.c @@ -0,0 +1,1489 @@ +/* + * o - a project called circle - that draws stuff + * + * Copyright (c) 2011 Øyvind Kolås + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#ifdef SIMULATOR +#include +#else +#endif + +#define WIDTH RESX +#define HEIGHT RESY + +#include "o.h" + +/* the following defines turn on and of capabilities, most capabilities can + * be independently toggled, and the rest of the API should work with a smaller + * code footprint as things are removed. + */ + +#define O_ENABLE_FILL +//#define O_ENABLE_STROKE +#define O_ENABLE_USER_SHADER +#define O_ENABLE_BW /* pick one ,. */ +//#define O_ENABLE_GRAY +//#define O_ENABLE_GRAY_EXTRA +//#define O_ENABLE_RECTANGLE +//#define O_ENABLE_STACK +//#define O_ENABLE_CLIP +//#define O_ENABLE_TRANSFORM +//#define O_ENABLE_TRANSFORM_FUNCS +//#define O_ENABLE_RENDER +//#define O_ENABLE_TEXT +//#define O_ENABLE_EXTERNAL_FONT /* needs O_ENABLE_TEXT */ +//#define O_ENABLE_FONT_DUMP /* dumps font to font path upon first use */ +//#define O_ENABLE_FILE /* compile file accessing calls */ + +#ifdef O_ENABLE_EXTERNAL_FONT +#ifndef O_ENABLE_FILE +#define O_ENABLE_FILE +#endif +#endif + +#ifdef O_ENABLE_EXTERNAL_CLIP +#ifndef O_ENABLE_FILL +#define O_ENABLE_FILL +#endif +#endif + +#ifdef O_ENABLE_TEXT +#ifndef O_ENABLE_STROKE +#define O_ENABLE_STROKE +#endif +#endif + + +#define BEZIER_SEGMENTS 16 +#define MAX_SPANS_PER_LINE 7 /* maximum number of intersecting spans on one line */ +#define SPP 10 /* sup pixel precision divider, each pixel is 6 such units internally */ +#define STACK_DEPTH 3 /* needs O_ENABLE_STACK */ +#define FONT_PATH "/tmp/font.bin" /* if O_ENABLE_EXTERNAL_FONT */ +#define FIXED_ONE 1023 /* XXX: using 1023 instead of 1024 gives smaller + code size.. evil.. */ + +typedef struct _Node Node; +typedef struct _Path Path; +typedef struct _Context Context; + +#define CLAMP(val,min,max) ((val)<(min)?(min):(val)>(max)?(max):(val)) + +/* Default color generator shader */ +static int shader_gray (int x, int y, void *data); + +struct _Node +{ + short int x; + short int y; + unsigned char type; /* can maybe be removed and put in context? + or < 0 values indicate move, and -127 indicate curve_to? */ +}; + + +#ifdef O_ENABLE_CLIP +typedef struct _Clip Clip; +struct _Clip +{ + unsigned char row[HEIGHT][2]; /* 0 start 1 end */ +}; +#endif + +struct _Context +{ +#ifdef O_ENABLE_USER_SHADER + ShaderFunction shader; +#endif + void *shader_data; +#ifdef O_ENABLE_TRANSFORM + OMatrix transform; +#endif +#ifdef O_ENABLE_STROKE + char line_width; +#endif +#ifdef O_ENABLE_TEXT + char font_size; +#endif +}; + +struct _Path +{ + signed short int x; + signed short int y; + int count; + int max_size; + Node *nodes; +#ifdef O_ENABLE_STACK + Context *context; + int context_no; +#else + Context context; +#endif +#ifdef O_ENABLE_CLIP /* would be better if it was part of the + * context stack, but it uses a lot of ram + */ + Clip clip; +#endif +}; +static Path *path = NULL; + + +/* the actual inner draw function used for doing the real painting */ +static void o_render_span(int x0, int y, + int x1, +#ifdef O_ENABLE_USER_SHADER + ShaderFunction shader, +#endif + void *shader_data) +{ +#ifdef O_ENABLE_CLIP + x0 = CLAMP (x0, path->clip.row[y][0], path->clip.row[y][1]); + x1 = CLAMP (x1, path->clip.row[y][0], path->clip.row[y][1]); +#else + x0 = CLAMP (x0, 0, WIDTH); + x1 = CLAMP (x1, 0, WIDTH); +#endif + if (y <0 || y>=HEIGHT) + return; + for(int x=x0; xcontext[path->context_no]; +} +#else +#define context() (&path->context) +#endif + +#ifdef O_ENABLE_TRANSFORM + +/* copied from twin */ +static void +o_matrix_multiply (OMatrix *result, + const OMatrix *a, + const OMatrix *b) +{ + OMatrix r; + + for (int row = 0; row < 3; row++) + for (int col = 0; col < 2; col++) + { + int t = (row == 2) ? t = b->m[2][col] : 0; + + for (int n = 0; n < 2; n++) + t = t + ((a->m[row][n] * b->m[n][col])) / FIXED_ONE; + r.m[row][col] = t; + } + *result = r; +} + +static void +o_matrix_identity (OMatrix *m) +{ + m->m[0][0] = m->m[1][1] = FIXED_ONE; + m->m[0][1] = m->m[1][0] = m->m[2][0] = m->m[2][1] = 0; +} + +void o_transform (OMatrix *matrix, int replace) +{ + OMatrix *m = &context()->transform; + if (replace) + context()->transform = *matrix; + else + o_matrix_multiply (m, matrix, m); +} + +void +o_identity (void) +{ + o_matrix_identity (&context()->transform); +} + +#endif + +#ifdef O_ENABLE_TRANSFORM_FUNCS +static int o_sin(int x) +{ +#define qN 13 +#define qA 12 +#define qP 15 +#define qR (2*qN-qP) +#define qS (qN+qP+1-qA) + + x= x<<(30-qN); // shift to full s32 range (Q13->Q30) + + if( (x^(x<<1)) < 0) // test for quadrant 1 or 2 + x= (1<<31) - x; + + x= x>>(30-qN); + + return (x * ( (3<>qR) ) >> qS ); +} + +static inline int o_cos(int x) +{ + return o_sin(x + 8192); +} + +void +o_translate (int tx, int ty) +{ + OMatrix t; + OMatrix *m = &context()->transform; + o_matrix_identity (&t); + + t.m[2][0] = tx * FIXED_ONE / 1000; + t.m[2][1] = ty * FIXED_ONE / 1000; + o_matrix_multiply (m, &t, m); +} + +void +o_scale (int sx, int sy) +{ + OMatrix t; + OMatrix *m = &context()->transform; + o_matrix_identity (&t); + t.m[0][0] = sx * FIXED_ONE / 1000; + t.m[1][1] = sy * FIXED_ONE / 1000; + o_matrix_multiply (m, &t, m); +} + + +static int o_sin(int x) +{ +#define qN 13 +#define qA 12 +#define qP 15 +#define qR (2*qN-qP) +#define qS (qN+qP+1-qA) + + x= x<<(30-qN); // shift to full s32 range (Q13->Q30) + + if( (x^(x<<1)) < 0) // test for quadrant 1 or 2 + x= (1<<31) - x; + + x= x>>(30-qN); + + return (x * ( (3<>qR) ) >> qS ); +} + +static inline int o_cos(int x) +{ + return o_sin(x + 8192); +} + +void +o_rotate (int angle) +{ + OMatrix *m = &context()->transform; + OMatrix t; + int c = o_cos ( angle * 4 * 8192 / 3600 ) / 4; + int s = o_sin ( angle * 4 * 8192 / 3600 ) / 4; + + t.m[0][0] = c; t.m[0][1] = s; + t.m[1][0] = -s; t.m[1][1] = c; + t.m[2][0] = 0; t.m[2][1] = 0; + o_matrix_multiply (m, &t, m); +} +#endif + +#ifdef O_ENABLE_STROKE + +static unsigned int o_sqrt (unsigned int n) +{ + unsigned int root = 0, bit, trial; + bit = (n >= 0x10000) ? 1<<30 : 1<<14; + do + { + trial = root+bit; + if (n >= trial) + { + n -= trial; + root = trial+bit; + } + root >>= 1; + bit >>= 2; + } while (bit); + return root; +} + +static int +point_dist (Node *a, + Node *b) +{ + return o_sqrt ((a->x-b->x)*(a->x-b->x) + + (a->y-b->y)*(a->y-b->y)); +} +#endif + +/* linear interpolation between two points */ +static void +lerp (Node *dest, + Node *a, + Node *b, + int t) +{ + dest->x = a->x + (((b->x-a->x) * t) / FIXED_ONE); + dest->y = a->y + (((b->y-a->y) * t) / FIXED_ONE); +} + +/* evaluate a point on a bezier-curve. + */ +static void +bezier (Node **curve, + Node *dest, + int t) +{ + Node ab,bc,cd,abbc,bccd; + + lerp (&ab, curve[0], curve[1], t); + lerp (&bc, curve[1], curve[2], t); + lerp (&cd, curve[2], curve[3], t); + lerp (&abbc, &ab, &bc,t); + lerp (&bccd, &bc, &cd,t); + lerp (dest, &abbc, &bccd, t); +} + +void o_current_point (int *x, int *y) +{ + if (x) *x = path->x; + if (y) *y = path->y; +} + +#ifdef O_ENABLE_STACK +void o_save (void) +{ + path->context_no ++; +#ifdef SIMULATOR + if (path->context_no >= STACK_DEPTH) + { + fprintf (stderr, "stack depth bust\n"); + } + /* copy existing state */ + path->context[path->context_no] = path->context[path->context_no-1]; +#endif +} + +void o_restore (void) +{ + path->context_no --; +#ifdef SIMULATOR + if (path->context_no < 0) + fprintf (stderr, "stack underflow\n"); +#endif +} +#endif + +/* types: + * 's' : initialized state (last pen coordinates) + * 'm' : move_to 'l' : line_to + * 'c' : curve_to '.' : curve_to_ 'C' : curve_to__ + */ + +static void +o_add (unsigned char type, + int x, + int y) +{ + Node *iter = NULL; + +#if 0 + if (type != 'A') + { + x *= SPP; + y *= SPP; + } +#endif + + /* transform inputed coords here */ + path->x = x; + path->y = y; + + if (type=='A') + { + type = 'l'; + } +#ifdef O_ENABLE_TRANSFORM + else + { + OMatrix *m = &context()->transform; + x = ((path->x * m->m[0][0]) + (path->y * m->m[1][0]) + m->m[2][0]) / FIXED_ONE; + y = ((path->y * m->m[1][1]) + (path->x * m->m[0][1]) + m->m[2][1]) / FIXED_ONE; + } +#endif + +#if 0 + x = CLAMP(x, -32000, 32000); + y = CLAMP(y, -32000, 32000); +#endif + + if (path->count) + iter = &path->nodes[0]; + if (path->count+1 >= path->max_size) + return; + + iter = &path->nodes[path->count++]; + + iter->type=type; + iter->x = x; + iter->y = y; +} + +void o_init (void *data, int data_size); + +#ifdef O_ENABLE_USER_SHADER +void o_set_shader (ShaderFunction shader, void *shader_data) +{ + context()->shader = shader; + context()->shader_data = shader_data; +} +#endif + +#ifdef O_ENABLE_STROKE +void +o_set_line_width (int line_width) +{ + context()->line_width = line_width; +} +#endif + +#ifdef O_ENABLE_BW +#define GRAY_PRECISION 8 +static int shader_gray (int x, int y, void *data) +{ + return (int)(data); /* stored gray value as 8bit value */ +} +#endif + +#ifdef O_ENABLE_GRAY_EXTRA +#define GRAY_PRECISION 8 +/* Default color generator shader */ +static int shader_gray (int x, int y, void *data) +{ + int value = (int)(data); /* stored gray value as 8bit value */ + if (value >= 3) return 1; + else if (value > 0) + return (x%2==0) ? (y %2)? 1:0: + (y %2)? 0:1; + return 0; +} +#endif + +#ifdef O_ENABLE_GRAY +#define GRAY_PRECISION 4 +/* Default color generator shader */ +static int shader_gray (int x, int y, void *data) +{ + int value = (int)(data); /* stored gray value as 8bit value */ + switch (value) /* the dither patterns are can be seen */ + { /* at the end of the lines */ + case 0: /* 0.0 */ + return 0; + case 1: /* 0.16 */ + return (x%3==0) ? (y %2)? 0:0: + (x%3==1) ? (y %2)? 0:0: + (y %2)? 0:1; + case 2: /* 0.25 */ + return (x%2) ? (y %2)? 1:0: + (y %2)? 0:0; + case 3: /* 0.33 */ + return (x%3==0) ? (y %2)? 1:0: + (x%3==1) ? (y %2)? 0:0: + (y %2)? 0:1; + case 4: /* 0.50 */ + return (x%2==0) ? (y %2)? 1:0: + (y %2)? 0:1; + case 5: /* 0.66 */ + return (x%3==0) ? (y %2)? 0:1: + (x%3==1) ? (y %2)? 1:1: + (y %2)? 1:0; + case 6: /* 0.75 */ + return (x%2) ? (y %2)? 1:0: + (y %2)? 1:1; + case 7: /* 0.85 */ + return (x%3==0) ? (y %2)? 1:1: + (x%3==1) ? (y %2)? 1:0: + (y %2)? 1:1; + case 8: /* 1.0 */ + return 1; + default: // return ((char)(rnd1())) < value; + /* XXX: use a faster "random" source + for this fallback */ + break; + } + return 0; +} +#endif + +#ifndef GRAY_PRECISION +#define GRAY_PRECISION 8 +#endif + +void o_set_gray (int value) +{ +#ifdef O_ENABLE_USER_SHADER +#ifdef O_ENABLE_BW /* hack, that permits setting a user shader for grayscale.. + when only bw has been enabled, _and_ we have user shader */ + context()->shader_data = (void*)((int)(value * GRAY_PRECISION / 1000)); +#else + o_set_shader (shader_gray, (void*)((int)(value * GRAY_PRECISION / 1000))); +#endif +#else + context()->shader_data = (void*)((int)(value * GRAY_PRECISION / 1000)); +#endif +} + +#ifdef O_ENABLE_CLIP +void o_reset_clip (void) +{ + int i; + for (i=0; iclip.row[i][0] = 0; + path->clip.row[i][1] = WIDTH; + } +} +#endif + +void +o_init (void *dat, int data_size) +{ + char *data = ((char*)dat); + path = (void*)data; + + data += sizeof (Path); + data_size -= sizeof (Path); +#ifdef O_ENABLE_STACK + path->context = (void*)data; + + data += sizeof (Context) * STACK_DEPTH; + data_size -= sizeof (Context) * STACK_DEPTH; +#endif + path->nodes = (void*)data; + + path->max_size = data_size / sizeof (Node); + +#ifdef O_ENABLE_STACK + path->context_no = 0; +#endif +#ifdef O_ENABLE_STROKE + context()->line_width = 1; +#endif +#ifdef O_ENABLE_TEXT + context()->font_size = 7; +#endif + o_path_new (); +#ifdef O_ENABLE_TRANSFORM + o_matrix_identity (&context()->transform); +#endif +#ifdef O_ENABLE_CLIP + o_reset_clip (); +#endif + + + o_set_gray (1000); +#ifdef O_ENABLE_BW /* hack, that permits setting a user shader for grayscale.. + when only bw has been enabled, _and_ we have user shader */ + context()->shader = shader_gray; +#endif +} + +void +o_path_new (void) +{ + path->count = 0; +} + +void o_move_to (int x, int y) +{ + o_add ('m', x, y); +} + +void o_line_to (int x, int y) +{ + o_add ('l', x, y); +} + +void o_curve_to (int x1, int y1, + int x2, int y2, + int x3, int y3) +{ + o_add ('c', x1, y1); + o_add ('.', x2, y2); + o_add ('C', x3, y3); +} + +#ifdef O_ENABLE_STROKE + +static void +o_line (int x0, int y0, int x1, int y1, int *need_to_travel, int *traveled_length) +{ + Node a, b; + int spacing, local_pos, distance, offset, leftover; + + a.x = x0; + a.y = y0; + + b.x = x1; + b.y = y1; + + spacing = SPP - 1; /* *0.99 with divider!=1 */ + + distance = point_dist (&a, &b); + + leftover = *need_to_travel - *traveled_length; + offset = spacing - leftover; + + local_pos = offset; + + if (distance > 0) + for (;local_pos <= distance; local_pos += spacing) + { + Node spot; + int ratio = (local_pos * FIXED_ONE) / distance; + int line_width; + line_width = context()->line_width; + + /* scale line width by scaling factor */ + + lerp (&spot, &a, &b, ratio); + /* only 1px wide... */ + if (line_width <= 1) + { +#ifdef O_ENABLE_USER_SHADER + lcdSetPixel (spot.x / SPP, spot.y / SPP, + context()->shader(spot.x / SPP, spot.y / SPP, + context()->shader_data)); +#else + lcdSetPixel (spot.x / SPP, spot.y / SPP, + shader_gray(spot.x / SPP, spot.y / SPP, + context()->shader_data)); +#endif + } + else + { + int line_radius = line_width /2; + /* should use a more circular brush */ + int y; + for (y = spot.y/SPP - line_radius; + y < spot.y/SPP + line_radius; y++) + o_render_span (spot.x/SPP - line_radius, + y, + spot.x/SPP + line_radius, +#ifdef O_ENABLE_USER_SHADER + context()->shader, +#endif + context()->shader_data); + } + + *traveled_length += spacing; + } + *need_to_travel += distance; +} + + +void +o_stroke (void) +{ + Node *iter = &path->nodes[0]; + int traveled_length = 0; + int need_to_travel = 0; + int x = 0, y = 0; + int i = 0; + + i=0; + while (i < path->count) + { + switch (iter->type) + { + case 'm': + need_to_travel = 0; + traveled_length = 0; + x = iter->x; + y = iter->y; + break; + case 'C': + { /* create piecevize linear approximation of bezier curve */ + int i; + Node *pts[4]; + + for (i=0;i<4;i++) + pts[i]=&iter[i-3]; + for (i=0; i< FIXED_ONE; i+= FIXED_ONE/ BEZIER_SEGMENTS) + { + Node iter2; + bezier (pts, &iter2, i); + o_line (x, y, iter2.x, iter2.y, &need_to_travel, &traveled_length); + x = iter2.x; + y = iter2.y; + } + } + case 'l': + o_line (x, y, iter->x, iter->y, &need_to_travel, &traveled_length); + x = iter->x; + y = iter->y; + break; + } + iter++; + i++; + } +} +#endif + +#ifdef O_ENABLE_FILL + +#define EMPTY_SCAN_SLOT -126 + +/* insertion sort integer into array */ +static void insert_sorted (signed char *array, int value) +{ + for (int j=0; j value) + { + for (int k=MAX_SPANS_PER_LINE -1; k >= j+1; k--) + array[k] = array[k-1]; + array[j] = value; + return; + } + } +} + +static void fill_line (int prev_x, int prev_y, int dest_x, int dest_y, + signed char scanlines[HEIGHT][MAX_SPANS_PER_LINE], + int *lastdir, int *lastline) +{ + int ydir; + int dx, dy; + dx = dest_x - prev_x; + dy = dest_y - prev_y; + + ydir = (dy < 0) ? -1 : 1; + + /* do linear interpolation between vertexes */ + for (int y = prev_y; y != dest_y; y += ydir) + if (y >= 0 && y < HEIGHT && *lastline != y) + { + int x = prev_x + (dx * (y-prev_y)) / dy; + insert_sorted(&scanlines[y][0], x); + if (ydir != *lastdir) // && *lastdir != -2) //XXX: ugly optimizing hack + insert_sorted(&scanlines[y][0], x); + + *lastdir = ydir; + *lastline = y; + } +} + +void o_fill (void) +{ + if (path->count < 1) + return; + + { + signed char scanlines[HEIGHT][MAX_SPANS_PER_LINE]; + /* Stack allocated scanline intersection list */ + Node *iter; + int prev_x, prev_y; + int first_x, first_y; + int lastline = -1; + int lastdir = -2; + + for (int i = 0; inodes[0].x / SPP; + first_y = prev_y = path->nodes[0].y / SPP; + + /* saturate scanline intersection list */ + iter = &path->nodes[1]; + for (int i=1; icount; i++, iter++) + { + switch (iter->type) + { + int dest_x; + int dest_y; + case 'm': + { + first_x = prev_x = iter->x / SPP; + first_y = prev_y = iter->y / SPP; + break; + } + case 'l': + { + dest_x = iter->x / SPP; + dest_y = iter->y / SPP; +fill_close: /* label used for goto to close last segment */ + + fill_line (prev_x, prev_y, dest_x, dest_y, scanlines, &lastdir, &lastline); + + prev_x = dest_x; + prev_y = dest_y; + /* if we're on the last knot, fake the first vertex being a next one */ + if (i+1 == path->count) + { + dest_x = first_x; + dest_y = first_y; + i++; /* to make the loop finally end */ + goto fill_close; + } + break; + } + case 'C': + { /* create piecevize linear approximation of bezier curve */ + int i; + Node *pts[4]; + + for (i=0;i<4;i++) + pts[i]=&iter[i-3]; + for (i=0; i< FIXED_ONE; i+= FIXED_ONE/ BEZIER_SEGMENTS) + { + Node iter2; + bezier (pts, &iter2, i); + fill_line (prev_x, prev_y, iter2.x/SPP, iter2.y/SPP, scanlines, &lastdir, &lastline); + prev_x = iter2.x / SPP; + prev_y = iter2.y / SPP; + } + if (i+1 == path->count) + { + dest_x = first_x; + dest_y = first_y; + i++; /* to make the loop finally end */ + goto fill_close; + } + break; + } + } + } + + /* Fill the spans */ + for (int i=0; i < HEIGHT; i++) + { + for (int j=0; j EMPTY_SCAN_SLOT) + { + o_render_span (scanlines[i][j], i, scanlines[i][j+1], +#ifdef O_ENABLE_USER_SHADER + context()->shader, +#endif + context()->shader_data); + } + } + } + } +} + +#endif + +#ifdef O_ENABLE_CLIP +void o_clip (void) +{ + /* massive code duplication with o_fill */ + if (path->count < 1) + return; + + { + Node *iter; + int prev_x, prev_y; + int first_x, first_y; + int lastline = -1; + + first_x = prev_x = path->nodes[0].x / SPP; + first_y = prev_y = path->nodes[0].y / SPP; + + /* saturate scanline intersection list */ + iter = &path->nodes[1]; + for (int i=1; icount; i++, iter++) + { + int dest_x = iter->x / SPP; + int dest_y = iter->y / SPP; + int ydir; + int dx, dy; +fill_close: /* label used for goto to close last segment */ + dx = dest_x - prev_x; + dy = dest_y - prev_y; + + ydir = (dy < 0) ? -1 : 1; + + /* do linear interpolation between vertexes */ + for (int y = prev_y; y != dest_y; y += ydir) + if (y >= 0 && y < HEIGHT && lastline != y) + { + int x = prev_x + (dx * (y-prev_y)) / dy; + if (path->clip.row[y][0] < x) + path->clip.row[y][0] = x; + if (path->clip.row[y][1] > x) + path->clip.row[y][1] = x; + lastline = y; + } + + prev_x = dest_x; + prev_y = dest_y; + /* if we're on the last knot, fake the first vertex being a next one */ + if (i+1 == path->count) + { + dest_x = first_x; + dest_y = first_y; + i++; /* to make the loop finally end */ + goto fill_close; + } + } + } +} +#endif + + +void o_close (void) +{ + Node *iter; + int i = path->count; + if (path->count == 0) + return; + iter = &path->nodes[path->count]; + while (i>0 && iter->type != 'm') /* find previous move to */ + { + iter --; + i--; + } + if (i>=0 && iter->type == 'm') + o_add ('A', iter->x, iter->y); +} + +#ifdef O_ENABLE_RECTANGLE +void o_orectangle (int x0, int y0, int width, int height) +{ + o_path_new (); + o_move_to (x0, y0); + o_line_to (x0 + width, y0); + o_line_to (x0 + width, y0+height); + o_line_to (x0, y0+height); + o_close (); +} +#endif + +static const signed char *_o_bounds_op (const signed char *g, + int *xmin, int *ymin, int *xmax, int *ymax) +{ + int ccount = 0; + switch (*g++) { + case 'l': case 'm': ccount = 1; break; + case 'c': ccount = 3; break; + case 'g': case 'w': g++; break; + case 'e': case '.': /* end */ return NULL; + default: + case 'z': case 'f': case 's': case ' ': break; + } + for (int c = 0; c < ccount; c++) + { + if (xmin && *xmin > g[c*2+0]) + *xmin = g[c*2+0]; + if (ymin && *ymin > g[c*2+1]) + *ymin = g[c*2+1]; + if (xmax && *xmax < g[c*2+0]) + *xmax = g[c*2+0]; + if (ymax && *ymax < g[c*2+1]) + *ymax = g[c*2+1]; + } + g += ccount * 2; + return g; +} + +#ifdef O_ENABLE_RENDER +static const signed char * _o_process_op (const signed char *g) +{ + switch (*g++) { + + case ' ': o_path_new (); break; + /* all of these path commands are directly in integer coordinates */ + case 'm': o_move_to (g[0], g[1]); g += 2; break; + case 'l': o_line_to (g[0], g[1]); g += 2; break; + case 'c': o_curve_to (g[0], g[1], g[2], g[3], g[4], g[5]); g += 6; break; + case 'z': o_close (); break; + + /* directly in px XXX: should be 10 = 1.0 instead? */ + case 'w': o_set_line_width (g[0]); g ++; break; + /* 0 = black, 50 = gray, 100 = white */ + case 'g': o_set_gray (g[0]*10); g ++; break; + +#ifdef O_ENABLE_FILL + case 'f': o_fill (); break; +#endif +#ifdef O_ENABLE_STROKE + case 's': o_stroke (); break; +#endif + +#ifdef O_ENABLE_FLUFF_CODE + case 'r': o_rectangle (g[0], g[1], g[2], g[3]); g += 4; break; +#endif +#ifdef O_ENABLE_STACK + case '+': o_save (); break; + case '-': o_restore (); break; +#endif +#ifdef O_ENABLE_TRANSFORM + /* 1 = 1 10 = 10 100 = 100 */ + case '!': o_identity (); break; + case 'T': o_translate (g[0] * 100, g[1] * 100); g+=2; break; + /* 1 = 0.01 10 = 0.1 50 = 0.5 100 = 10x */ + case 'S': o_scale (g[0] * 10, g[1] * 10); g+=2; break; + /* -128 = -360 64 = 180 128 = 360 */ + case 'R': o_rotate ((g[0] * 3600)/127); g+=1; break; +#else + case 'T': case 'S': g+=2;break; + case 'R': g+=1;break; +#endif + +#ifdef O_ENABLE_CLIP + case 'x': o_clip (); break; + case 'X': o_reset_clip (); break; +#endif +#ifdef O_ENABLE_TEXT_API + case 't': o_text_path (g); while (*g) g++; break; +#endif + default: + case '\0': + case '.': /* end */ + return NULL; + } + return g; +} + +void +o_render (const signed char *g) +{ + for (; g; g = _o_process_op (g)); +} + +void +o_bounds (const signed char *g, + int *minx, int *miny, + int *maxx, int *maxy) +{ + if (minx) *minx= 10000; + if (miny) *miny= 10000; + if (maxx) *maxx= -10000; + if (maxy) *maxy= -10000; + for (; g; g = _o_bounds_op (g, minx, miny, maxx, maxy)); +} + +#ifdef O_ENABLE_FILE + +#ifdef SIMULATOR +static FILE *file; +#else +static FIL file; /* font file */ +#endif + +void o_render_file (const char *file_path, int offset) +{ + unsigned int readbytes; +#ifdef SIMULATOR + if (!(file = fopen (file_path, "r"))) +#else + unsigned int res; + if ((res = f_open (&file, file_path, FA_OPEN_EXISTING|FA_READ))) +#endif + { + /* XX: failed to open */ + return; + } +#ifdef SIMULATOR + fseek(file, offset, SEEK_SET); +#else + f_lseek(&file, offset); +#endif + signed char buf[8]; + const signed char *b; + int chunk = sizeof (buf); + do { +#ifdef SIMULATOR + readbytes = fread (buf + sizeof(buf) - chunk, 1, chunk, file); +#else + res = f_read (&file, buf + sizeof(buf)-chunk, chunk, &readbytes); +#endif + b = buf; + b = _o_process_op (b); + chunk = b-buf; + if (b) + memmove (buf, b, sizeof (buf) - chunk); + } while (b && readbytes); + if (b) + for (b=buf;b;b = _o_process_op (b)); +#ifdef SIMULATOR + fclose (file); +#else + f_close (&file); +#endif +} + +int +o_file_offset (const char *file_path, + int no) +{ + short count; + short offset; +#ifdef SIMULATOR + if (!(file = fopen (file_path, "r"))) +#else + unsigned int readbytes; + unsigned int res; + if ((res = f_open (&file, file_path, FA_OPEN_EXISTING|FA_READ))) +#endif + /* XX: failed to open */ + return -1; + +#ifdef SIMULATOR + fread (&count, sizeof(count), 1, file); +#else + res = f_read (&file, &count, sizeof(count), &readbytes); +#endif + if (no > count) + { +#ifdef SIMULATOR + fclose (file); +#else + f_close (&file); +#endif + return -1; + } + +#ifdef SIMULATOR + fseek(file, 2 * (no+1), SEEK_SET); +#else + f_lseek(&file, 2 * (no+1)); +#endif + +#ifdef SIMULATOR + fread (&offset, sizeof(offset), 1, file); +#else + res = f_read (&file, &offset, sizeof(offset), &readbytes); +#endif + +#ifdef SIMULATOR + fclose (file); +#else + f_close (&file); +#endif + return offset; +} + +void +o_bounds_file (const char *file_path, + int offset, + int *minx, int *miny, + int *maxx, int *maxy) +{ + unsigned int readbytes; + unsigned int res; + if (minx) *minx= 10000; + if (miny) *miny= 10000; + if (maxx) *maxx= -10000; + if (maxy) *maxy= -10000; +#ifdef SIMULATOR + if (!(file = fopen (file_path, "r"))) +#else + if ((res = f_open (&file, file_path, FA_OPEN_EXISTING|FA_READ))) +#endif + { + /* XX: failed to open */ + return; + } +#ifdef SIMULATOR + fseek(file, offset, SEEK_SET); +#else + f_lseek(&file, offset); +#endif + signed char buf[8]; + const signed char *b; + int chunk = sizeof (buf); + do { +#ifdef SIMULATOR + readbytes = fread (buf + sizeof(buf) - chunk, 1, chunk, file); +#else + res = f_read (&file, buf + sizeof(buf)-chunk, chunk, &readbytes); +#endif + b = buf; + b = _o_bounds_op (b, minx, miny, maxx, maxy); + chunk = b-buf; + if (b) + memmove (buf, b, sizeof (buf) - chunk); + } while (b && readbytes); + if (b) + for (b=buf;b;b = _o_bounds_op (b, minx, miny, maxx, maxy)); +#ifdef SIMULATOR + fclose (file); +#else + f_close (&file); +#endif + /* */ +} +#endif + +#endif + +/******************************************************************************/ + +#ifndef O_ENABLE_TEXT + +void o_set_font_size (int font_size) +{/*adding the symbol to make things still compile without having fontsupport*/} + +void o_show_text (const char *ascii, + int wrap_width) +{/*adding the symbol to make things still compile without having fontsupport*/} + +#else + +void o_set_font_size (int font_size) +{ + context()->font_size = font_size; +} + +#ifndef O_ENABLE_EXTERNAL_FONT +#include "o-glyphs.c" /* include the font data directly */ + +static const signed char * +glyph_data (char ascii) +{ + int no = 0; + int pos = 0; + ascii -= 31; + if (ascii > 126) + return _o_glyphs; + + while (no < ascii) + { + int val = _o_glyphs[pos]; + if (val == '.') + no ++; + pos++; + } + if (no == ascii) + return _o_glyphs + pos; + return _o_glyphs; +} +#endif + +/* end of glue */ + +#define PARA_DET 3 /* 1.5 */ +#define PARA_NOM 2 +#define WORD_DET 4 /* 0.4 */ +#define WORD_NOM 10 +#define LINE_DET 12 /* 1.2 */ +#define LINE_NOM 10 + +static int +block_width (int font_size, + char ascii) +{ + int maxx = 0; +#ifndef O_ENABLE_EXTERNAL_FONT + const signed char *g = glyph_data (ascii); + o_bounds (g, NULL, NULL, &maxx, NULL); +#else + int offset = o_file_offset (FONT_PATH, ascii); + o_bounds_file (FONT_PATH, offset, NULL, NULL, &maxx, NULL); +#endif + return (maxx + 12) * font_size / 42; +} + +static void +font_ascii_path (int font_size, + int x, + int y, + char ascii) +{ + OMatrix orig_transform; + + int origin_x, origin_y; + int next_x; + int baseline; + + o_current_point (&origin_x, &origin_y); + next_x = origin_x + block_width (font_size, ascii); + baseline = origin_y; + orig_transform = context()->transform; + o_translate (origin_x * 1000, origin_y * 1000); + o_scale (font_size * 1000 / 42, font_size * 1000 / 42); +#ifndef O_ENABLE_EXTERNAL_FONT + const signed char *g = glyph_data (ascii); + o_render (g); +#else + int offset = o_file_offset (FONT_PATH, ascii); + o_render_file (FONT_PATH, offset); +#endif + o_move_to (next_x, baseline); + context()->transform = orig_transform; +} + +static int +wordlength (int font_size, + const char *ascii) +{ + int sum = 0; + while (*ascii && + *ascii != ' ' && + *ascii != '\n') + { + sum += block_width (font_size, *ascii); + ascii++; + } + return sum; +} + +static void +font_path (int font_size, + int width, + const char *ascii) +{ + int x = path->x / SPP; + int y = path->y / SPP; + + while (*ascii) + { + if (*ascii == '\n') + { + o_move_to (x, y += (font_size * PARA_DET) / PARA_NOM); + } + else if (*ascii == ' ') + { + int pen_x; + o_current_point (&pen_x, NULL); + if (width && + pen_x + wordlength (font_size, ascii+1) > x + width && + wordlength (font_size, ascii+1) < width) + { + o_move_to (x, y += (font_size * LINE_DET) / LINE_NOM); + } + else + { + /* word spacing */ + o_move_to (pen_x + (font_size * WORD_DET) / WORD_NOM, y); + } + } + else + { + font_ascii_path (font_size, x,y, *ascii); + } + ascii++; + } +} + +#ifdef SIMULATOR +#ifdef O_ENABLE_FONT_DUMP + +#define wordout(w) \ + { short int temp = (w);\ + fwrite (&temp, sizeof (temp), 1, file); \ + } +#define byteout(c) \ + { signed char temp = (c);\ + fwrite (&temp, sizeof (temp), 1, file); \ + } + +#define FUDGE 3 +#define FIRST_CHAR 32 /* padding out of first few entires */ + +void o_write_font (void) +{ + FILE *file; + static char done = 0; + if (done) + return; + int count = 0; + done = 1; + fprintf (stderr, "@write the font\n"); + file = fopen (FONT_PATH, "w"); + + for (int pos = 0; pos < sizeof (_o_glyphs); pos++) + { + int val = _o_glyphs[pos]; + if (val == '.') + count ++; + } + + fprintf (stderr, "%d\n", count + FIRST_CHAR); + wordout(count+FIRST_CHAR); + int no = 0; + for (int pos = 0; pos < FIRST_CHAR; pos ++) + { + fprintf (stderr, "%i, ", 0); + wordout (0 + (2 * (count + FIRST_CHAR) + FUDGE)); + } + for (int pos = 0; pos < sizeof (_o_glyphs); pos++) + { + int val = _o_glyphs[pos]; + if (val == '.' && no < 129) + { + fprintf (stderr, "%i, ", pos + (2 * (count + FIRST_CHAR) + FUDGE)); + wordout (pos + (2 * (count + FIRST_CHAR)) + FUDGE ); + no ++; + } + } + no = FIRST_CHAR - 1; //31; XXX: might not work quite out.. + + fprintf (stderr, "\n\n /* unknown box 0x%x - %i*/\n", 0, + 0 + (2 * (count + FIRST_CHAR) + FUDGE )); + + for (int pos = 0; pos < sizeof (_o_glyphs); pos++) + { + int val = _o_glyphs[pos]; + if (((val >= 'a') && (val <= 'z')) || (val == ' ') || (val == '.')) + fprintf (stderr, "\n'%c', ", _o_glyphs[pos]); + else + fprintf (stderr, "%i, ", _o_glyphs[pos]); + byteout (_o_glyphs[pos]); + if (val == '.') + { + no ++; + fprintf (stderr, "\n\n /* '%c' 0x%x - %i*/\n", no, no, + pos + (2 * (count + FIRST_CHAR)) + FUDGE); + } + } + fprintf (stderr, "\n"); + fclose (file); +} +#endif +#endif + +void o_show_text (const char *ascii, int wrap_width) +{ +#ifdef SIMULATOR +#ifdef O_ENABLE_FONT_DUMP + o_write_font (); +#endif +#endif + font_path (context()->font_size, wrap_width, ascii); +} + +#endif diff --git a/firmware/lcd/o.h b/firmware/lcd/o.h new file mode 100644 index 0000000..7a4d133 --- /dev/null +++ b/firmware/lcd/o.h @@ -0,0 +1,141 @@ +/* + * o - a project called circle - that draws stuff + * + * Copyright (c) 2011 Øyvind Kolås + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _O_H +#define _O_H + +/* initialize o with a given work data buffer, and the size of the data buffer + in bytes. This data buffer should be allocated on the stack (char buf[2048]; + o_init (buf, sizeof (buf)); + */ +void o_init (void *data, int data_size); + +/* macro defines for relative commands */ +#define o_rel_move_to(x, y) do { int ox, oy;\ + o_current_point (&ox, &oy);\ + o_move_to (ox + (x), oy + (y)); } while(0); +#define o_rel_line_to(x, y) do { int ox, oy;\ + o_current_point (&ox, &oy);\ + o_line_to (ox + (x), oy + (y)); } while(0); +#define o_rel_curve_to(x1, y1, x2,y2,x3,y3) do { int ox, oy;\ + o_current_point (&ox, &oy);\ + o_curve_to (ox + (x1), oy + (y1),\ + ox + (x2), oy + (y2),\ + ox + (x3), oy + (y3));} } while(0); + + +/* start drawing a new path */ +/* clear current path */ +void o_path_new (void); +/* move to */ +void o_move_to (int x, int y); +/* line to */ +void o_line_to (int x, int y); +/* bezier curve */ +void o_curve_to (int x1, int y1, int x2, int y2, int x3, int y3); +/* close path with a straight line */ +void o_close (void); + +/* only available if compiled with stack*/ +void o_save (void); +/* saved graphics drawing and transformation state*/ +void o_restore (void); + +/* retrieve the current pen coordinates */ +void o_current_point (int *x, int *y); + + +void o_rectangle (int x0, int y0, int width, int height); + +/* the shader is the rendering function invoked for each fragment/pixel touched + * when stroking and filling, setting the shader only possible when specially + * compiled with such support. + */ +typedef int (*ShaderFunction)(int x, int y, void *shader_data); +void o_set_shader (ShaderFunction shader, void *shader_data); + +/* set a solid grayscale color, uses an internal shader for generating + * dither + */ +/* 0 = black 500 = gray 1000 = white */ +void o_set_gray (int value); + +/* fill currnet path (does not clear the path) */ +void o_fill (void); + +/* set the stroking line width */ +void o_set_line_width (int line_width); + +/* stroke path with current shader and line width */ +void o_stroke (void); + + +/* Interface for binary "EPS"/SVG like renderer, can be used for storing sprites/ + * icons inline with code or separately on disk + */ + +void o_render (const signed char *vector_data); + +/* query the offset in a file containing vector sprite number no */ +int o_file_offset (const char *file_path, int no); + +/* renders the sprite starting at the given offset in a file */ +void o_render_file (const char *file_path, int offset); + +/*** clipping ***/ +void o_clip (void); +void o_reset_clip (void); + +/* query the rough bounds of a program in mem/file, + o_path_extents would be a better API for this ... */ +void o_bounds (const signed char *vector_data, int *minx, int *miny, int *maxx, int *maxy); +void o_bounds_file (const char *file_path, int offset, int *minx, int *miny, int *maxx, int *maxy); + + +/*** transformation manipulation ***/ + +typedef struct _OMatrix OMatrix; +struct _OMatrix +{ + int m[3][2]; +}; + +void o_transform (OMatrix *matrix, int replace); + +void o_identity (void); +/* 1000 = 1.0 */ +void o_translate (int x, int y); +/* 1000 = 1.0 */ +void o_scale (int sx, int sy); +/* 1000 = 1.0, expressed in radians */ +void o_rotate (int angle); + +/*** font rendering ***/ + +void o_set_font_size (int size); + +/* appends a path of the given ascii text. + * + * x,y : positioning of baseline for first characther + * width : the right margin. 0 means no wrapping + * ascii : a text string that may contain newlines. + * + */ +void o_show_text (const char *ascii, int wrap_width); + +#endif diff --git a/firmware/lpc1xxx/linkscript.ld b/firmware/lpc1xxx/linkscript.ld index b632d78..7138861 100644 --- a/firmware/lpc1xxx/linkscript.ld +++ b/firmware/lpc1xxx/linkscript.ld @@ -1,81 +1,81 @@ -/* - * Software License Agreement (BSD License) - * - * Copyright (c) 2010, Roel Verdult - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -sram_top = ORIGIN(sram) + LENGTH(sram); -ENTRY(boot_entry) - -SECTIONS -{ - .text : - { - KEEP(*(.irq_vectors)) - KEEP(*(table)) - *(.text.boot_entry) -. = 0x000002FC ; /* or 1FC for LPC2000 */ - KEEP(*(crp)) - *(.text*) - *(.rodata*) - } > flash - - /* - * More information about Special Section Indexes is available in the - * free "ELF for the ARM Architecture" document from ARM Limited - * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf - * - */ - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > flash - __exidx_start = .; - .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > flash - __exidx_end = .; - - _etext = .; - - .data : AT (__exidx_end) - { - _data = .; - *(vtable) - *(.data*) - _edata = .; - } > sram - - /* zero initialized data */ - .bss : - { - _bss = .; - *(.bss*) - *(COMMON) - _ebss = .; - } > sram - - end = .; - - /* For GDB compatibility we decrease the top with 16 bytes */ - stack_entry = sram_top - 16; -} +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2010, Roel Verdult + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +sram_top = ORIGIN(sram) + LENGTH(sram); +ENTRY(boot_entry) + +SECTIONS +{ + .text : + { + KEEP(*(.irq_vectors)) + KEEP(*(table)) + *(.text.main) +. = 0x000002FC ; /* or 1FC for LPC2000 */ + KEEP(*(crp)) + *(.text*) + *(.rodata*) + } > flash + + /* + * More information about Special Section Indexes is available in the + * free "ELF for the ARM Architecture" document from ARM Limited + * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf + * + */ + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > flash + __exidx_start = .; + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > flash + __exidx_end = .; + + _etext = .; + + .data : AT (__exidx_end) + { + _data = .; + *(vtable) + *(.data*) + _edata = .; + } > sram + + /* zero initialized data */ + .bss : + { + _bss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > sram + + end = .; + + /* For GDB compatibility we decrease the top with 16 bytes */ + stack_entry = sram_top - 16; +}