Fork of Chris Styles' C12832 LCD driver

Dependents:   co657_lcdplay co657_nrf52_beacons door_lock co657_IoT

Fork of C12832 by Chris Styles

Revision:
18:8c294697c901
Parent:
17:67f9ca828270
Child:
19:de1f73b31288
--- a/C12832.cpp	Wed Oct 28 21:01:40 2015 +0000
+++ b/C12832.cpp	Sun Nov 01 02:22:53 2015 +0000
@@ -17,6 +17,9 @@
 // 25.10.12    add standart font
 // 20.12.12    add bitmap graphics
 
+// Assorted changes/updates by Fred Barnes, University of Kent <frmb@kent.ac.uk>
+// 31.10.15    minor bugfixes, some drawing optimisation
+
 // optional defines :
 // #define debug_lcd  1
 
@@ -137,19 +140,39 @@
 
 // set one pixel in buffer
 
-void C12832::pixel(int x, int y, int color)
+void C12832::pixel (int x, int y, int color)
 {
-    // first check parameter
-    if(x > 128 || y > 32 || x < 0 || y < 0) return;
+    if ((x >= 128) || (y >= 32) || (x < 0) || (y < 0)) {
+        /* out of bounds */
+        return;
+    }
 
-    if(draw_mode == NORMAL) {
-        if(color == 0)
-            buffer[x + ((y/8) * 128)] &= ~(1 << (y%8));  // erase pixel
-        else
-            buffer[x + ((y/8) * 128)] |= (1 << (y%8));   // set pixel
+    if (draw_mode == NORMAL) {
+        if (color == 0) {
+            buffer[x + ((y >> 3) << 7)] &= ~(1 << (y & 0x07));  // erase pixel
+        } else {
+            buffer[x + ((y >> 3) << 7)] |= (1 << (y & 0x07));   // set pixel
+        }
     } else { // XOR mode
-        if(color == 1)
-            buffer[x + ((y/8) * 128)] ^= (1 << (y%8));   // xor pixel
+        if (color == 1) {
+            buffer[x + ((y >> 3) << 7)] ^= (1 << (y & 0x07));   // xor pixel
+        }
+    }
+}
+
+/* plots a pixel, but without bounds checking (assumed to be done elsewhere) */
+void C12832::pixel_nochk (int x, int y, int colour)
+{
+    if (draw_mode == NORMAL) {
+        if (colour == 0) {
+            buffer[x + ((y >> 3) << 7)] &= ~(1 << (y & 0x07));  // erase pixel
+        } else {
+            buffer[x + ((y >> 3) << 7)] |= (1 << (y & 0x07));   // set pixel
+        }
+    } else { // XOR mode
+        if (colour == 1) {
+            buffer[x + ((y >> 3) << 7)] ^= (1 << (y & 0x07));   // xor pixel
+        }
     }
 }
 
@@ -201,103 +224,214 @@
 
 }
 
-void C12832::cls(void)
+void C12832::cls (void)
 {
-    memset(buffer,0x00,512);  // clear display buffer
-    if (auto_up) copy_to_lcd();
+    memset (buffer, 0x00, 512);  // clear display buffer
+    if (auto_up) {
+        copy_to_lcd();
+    }
 }
 
-
-void C12832::line(int x0, int y0, int x1, int y1, int color)
+/*
+ *  based on Foley and van Dam, Computer Graphics Principles and Practice,
+ *  Second edition in C, Fig 3.8
+ *
+ *  Adapted back into C from David Wood's occam implementation (line.occ).
+ */
+void C12832::line (int x0, int y0, int x1, int y1, int colour)
 {
-    int   dx = 0, dy = 0;
-    int   dx_sym = 0, dy_sym = 0;
-    int   dx_x2 = 0, dy_x2 = 0;
-    int   di = 0;
+    int dx = x1 - x0;
+    int dy = y1 - y0;
+    int x, y, a_dx, s_x, a_dy, s_y;
+    int d, strt, diag;
 
-    dx = x1-x0;
-    dy = y1-y0;
-
-    if (dx == 0) {        /* vertical line */
-        if (y1 > y0) vline(x0,y0,y1,color);
-        else vline(x0,y1,y0,color);
+    
+    if (dx == 0) {
+        /* vertical line */
+        if (y0 > y1) {
+            vline (x0, y1, y0, colour);
+        } else {
+            vline (x0, y0, y1, colour);
+        }
         return;
-    } else if (dy == 0) {   /* horizontal line */
-        if (x1 > x0) hline(x0,y0,x1,color);
-        else  hline(x1,y0,x0,color);
+    }
+    if (dy == 0) {
+        /* horizontal line */
+        if (x0 > x1) {
+            hline (x1, y0, x0, colour);
+        } else {
+            hline (x0, y0, x1, colour);
+        }
+        return;
+    }
+    
+    if ((x0 >= 128) || (x0 < 0) || (y0 >= 32) || (y0 < 0)) {
+        /* starts outside raster, so abort */
         return;
     }
-
+    
+    x = x0;
+    y = y0;
     if (dx > 0) {
-        dx_sym = 1;
+        a_dx = dx;  s_x = 1;
     } else {
-        dx_sym = -1;
+        a_dx = -dx; s_x = -1;
+    }
+    if (dy > 0) {
+        a_dy = dy;  s_y = 1;
+    } else {
+        a_dy = -dy; s_y = -1;
     }
+    
+    if (a_dx > a_dy) {
+        strt = a_dy * 2;            /* straight */
+        diag = strt - (2 * a_dx);   /* diagonal */
+        d = strt - a_dx;
 
-    if (dy > 0) {
-        dy_sym = 1;
+        while ((a_dx >= 0) && (x >= 0) && (x < 128) && (y >= 0) && (y < 32)) {
+            pixel_nochk (x, y, colour);
+            x += s_x;
+            a_dx--;
+            
+            if (d <= 0) {
+                d += strt;
+            } else {
+                d += diag;
+                y += s_y;
+            }
+        }
     } else {
-        dy_sym = -1;
+        strt = a_dx * 2;            /* straight */
+        diag = strt - (2 * a_dy);   /* diagonal */
+        d = strt - a_dy;
+
+        while ((a_dy >= 0) && (x >= 0) && (x < 128) && (y >= 0) && (y < 32)) {
+            pixel_nochk (x, y, colour);
+            y += s_y;
+            a_dy--;
+            
+            if (d <= 0) {
+                d += strt;
+            } else {
+                d += diag;
+                x += s_x;
+            }
+        }
     }
 
-    dx = dx_sym*dx;
-    dy = dy_sym*dy;
-
-    dx_x2 = dx*2;
-    dy_x2 = dy*2;
-
-    if (dx >= dy) {
-        di = dy_x2 - dx;
-        while (x0 != x1) {
-
-            pixel(x0, y0, color);
-            x0 += dx_sym;
-            if (di<0) {
-                di += dy_x2;
-            } else {
-                di += dy_x2 - dx_x2;
-                y0 += dy_sym;
-            }
-        }
-        pixel(x0, y0, color);
-    } else {
-        di = dx_x2 - dy;
-        while (y0 != y1) {
-            pixel(x0, y0, color);
-            y0 += dy_sym;
-            if (di < 0) {
-                di += dx_x2;
-            } else {
-                di += dx_x2 - dy_x2;
-                x0 += dx_sym;
-            }
-        }
-        pixel(x0, y0, color);
-    }
-    if(auto_up) copy_to_lcd();
-}
-
-void C12832::hline(int x0, int y0, int x1, int colour)
-{
-    int x;
-    
-    /* FIXME: do this sensibly, in blocks of 8 pixels */
-    for (x=x0; x<=x1; x++) {
-        pixel (x, y0, colour);
-    }
     if (auto_up) {
         copy_to_lcd ();
     }
 }
 
-void C12832::vline(int x0, int y0, int y1, int colour)
+/* Note: x1 >= x0 */
+void C12832::hline (int x0, int y0, int x1, int colour)
 {
-    int y;
+    int x;
+    int yoff;
+    uint8_t ybit;
+
+    if (((x0 < 0) && (x1 < 0)) || ((x0 >= 128) && (x1 >= 128)) || (y0 < 0) || (y0 >= 32)) {
+        return;                 /* completely outside */
+    }
+    if (x0 < 0) {
+        x0 = 0;
+    } else if (x1 >= 128) {
+        x1 = 127;
+    }
+
+    yoff = ((y0 >> 3) << 7);
+    ybit = (1 << (y0 & 0x07));
     
-    /* FIXME: do this sensibly, computing the bit positioning once */
-    for (y=y0; y<=y1; y++) {
-        pixel (x0, y, colour);
+    if (draw_mode == NORMAL) {
+        if (colour == 0) {
+            for (x=x0; x<=x1; x++) {
+                buffer[x + yoff] &= ~ybit;  // erase pixel
+            }
+        } else {
+            for (x=x0; x<=x1; x++) {
+                buffer[x + yoff] |= ybit;   // set pixel
+            }
+        }
+    } else { // XOR mode
+        if (colour == 1) {
+            for (x=x0; x<=x1; x++) {
+                buffer[x + yoff] ^= ybit;   // xor pixel
+            }
+        }
+    }
+
+    if (auto_up) {
+        copy_to_lcd ();
+    }
+}
+
+/* Note: y1 >= y0 */
+void C12832::vline (int x0, int y0, int y1, int colour)
+{
+    if (((y0 < 0) && (y1 < 0)) || ((y0 >= 32) && (y1 >= 32)) || (x0 < 0) || (x0 >= 128)) {
+        return;                 /* completely outside */
+    }
+    if (y0 < 0) {
+        y0 = 0;
+    } else if (y1 >= 32) {
+        y1 = 31;
     }
+
+    if ((y0 & ~0x07) == (y1 & ~0x07)) {
+        /* first and last pixels are in the same byte */
+        uint8_t ybits = ((1 << ((y1 & 0x07) + 1)) - 1) ^ ((1 << (y0 & 0x07)) - 1);
+        int yoff = (y0 >> 3) << 7;      /* same as y1 */
+        
+        if (draw_mode == NORMAL) {
+            if (colour == 1) {
+                buffer[x0 + yoff] |= ybits;
+            } else {
+                buffer[x0 + yoff] &= ~ybits;
+            }
+        } else {    /* XOR mode */
+            buffer[x0 + yoff] ^= ybits;
+        }
+    } else {
+        uint8_t st_ybits = (0xff << (y0 & 0x07));
+        uint8_t sp_ybits = ((1 << ((y1 & 0x07) + 1)) - 1);
+        int st_yoff = (y0 >> 3) << 7;
+        int sp_yoff = (y1 >> 3) << 7;
+        
+        /* fill in first byte */
+        if (draw_mode == NORMAL) {
+            if (colour == 1) {
+                buffer[x0 + st_yoff] |= st_ybits;
+            } else {
+                buffer[x0 + st_yoff] &= ~st_ybits;
+            }
+        } else {    /* XOR mode */
+            buffer[x0 + st_yoff] ^= st_ybits;
+        }
+        for (st_yoff += 128; st_yoff < sp_yoff; st_yoff += 128) {
+            /* intervening bytes 0xff */
+            if (draw_mode == NORMAL) {
+                if (colour == 1) {
+                    buffer[x0 + st_yoff] = 0xff;
+                } else {
+                    buffer[x0 + st_yoff] = 0x00;
+                }
+            } else {    /* XOR mode */
+                buffer[x0 + st_yoff] ^= 0xff;
+            }
+        }
+        /* and the last byte */
+        if (draw_mode == NORMAL) {
+            if (colour == 1) {
+                buffer[x0 + sp_yoff] |= sp_ybits;
+            } else {
+                buffer[x0 + sp_yoff] &= ~sp_ybits;
+            }
+        } else {    /* XOR mode */
+            buffer[x0 + sp_yoff] ^= sp_ybits;
+        }
+    }
+        
     if (auto_up) {
         copy_to_lcd ();
     }