blob: dec75c03e96fc35b681c07ebd011ddcadb338898 [file] [log] [blame]
zongqiang.zhang0c6a0882019-08-07 14:48:21 +08001/**
2 \file graphics.c
3 \brief Functions relating to graphics. e.g drawing lines, rectangles, circles etc.
4 \author Andy Gock
5
6 Some functions based on Limor Fried's PCD8544 Arduino library.
7
8 */
9
10/*
11 Copyright (c) 2012, Andy Gock
12
13 Copyright (c) 2012, Adafruit Industries
14
15 All rights reserved.
16
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions are met:
19 * Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
21 * Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in the
23 documentation and/or other materials provided with the distribution.
24 * Neither the name of Andy Gock nor the
25 names of its contributors may be used to endorse or promote products
26 derived from this software without specific prior written permission.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
29 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 DISCLAIMED. IN NO EVENT SHALL ANDY GOCK BE LIABLE FOR ANY
32 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38*/
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include "glcd.h"
44
45/* Based on PCD8544 library by Limor Fried */
46void glcd_set_pixel(uint8_t x, uint8_t y, uint8_t color) {
47 if (x > (GLCD_LCD_WIDTH-1) || y > (GLCD_LCD_HEIGHT-1)) {
48 /* don't do anything if x/y is outside bounds of display size */
49 return;
50 }
51
52 if (color) {
53 /* Set black */
54 glcd_buffer[x+ (y/8)*GLCD_LCD_WIDTH] |= ( 1 << (y%8));
55 } else {
56 /* Set white */
57 glcd_buffer[x+ (y/8)*GLCD_LCD_WIDTH] &= ~ (1 << (y%8));
58 }
59
60 glcd_update_bbox(x,y,x,y);
61}
62
63/* Based on PCD8544 library by Limor Fried */
64uint8_t glcd_get_pixel(uint8_t x, uint8_t y) {
65 if ((x >= GLCD_LCD_WIDTH) || (y >= GLCD_LCD_HEIGHT)) {
66 return 0;
67 }
68
69 if ( glcd_buffer[x+ (y/8)*GLCD_LCD_WIDTH] & ( 1 << (y%8)) ) {
70 return 1;
71 } else {
72 return 0;
73 }
74}
75
76void glcd_invert_pixel(uint8_t x, uint8_t y) {
77 if ((x >= GLCD_LCD_WIDTH) || (y >= GLCD_LCD_HEIGHT)) {
78 return;
79 }
80 glcd_update_bbox(x,y,x,y);
81 glcd_buffer[x+ (y/8)*GLCD_LCD_WIDTH] ^= ( 1 << (y%8));
82}
83
84/* Bresenham's algorithm - based on PCD8544 library Limor Fried */
85void glcd_draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color) {
86 uint8_t steep = abs(y1 - y0) > abs(x1 - x0);
87 uint8_t dx, dy;
88 int8_t err;
89 int8_t ystep;
90
91 if (steep) {
92 swap(x0, y0);
93 swap(x1, y1);
94 }
95
96 if (x0 > x1) {
97 swap(x0, x1);
98 swap(y0, y1);
99 }
100
101 glcd_update_bbox( x0, y0, x1, y1 );
102
103 dx = x1 - x0;
104 dy = abs(y1 - y0);
105
106 err = dx / 2;
107
108 if (y0 < y1) {
109 ystep = 1;
110 } else {
111 ystep = -1;
112 }
113
114 for (; x0<=x1; x0++) {
115 if (steep) {
116 glcd_set_pixel(y0, x0, color);
117 } else {
118 glcd_set_pixel(x0, y0, color);
119 }
120 err -= dy;
121 if (err < 0) {
122 y0 += ystep;
123 err += dx;
124 }
125 }
126}
127
128void glcd_fill_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
129{
130 int16_t i;
131 for (i=x; i<x+w; i++) {
132 int16_t j;
133 for (j=y; j<y+h; j++) {
134 glcd_set_pixel(i, j, color);
135 }
136 }
137 glcd_update_bbox(x, y, x+w-1, y+h-1);
138}
139
140void glcd_draw_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
141{
142 int16_t i;
143 for (i=x; i<x+w; i++) {
144 glcd_set_pixel(i, y, color);
145 glcd_set_pixel(i, y+h-1, color);
146 }
147 for (i=y; i<y+h; i++) {
148 glcd_set_pixel(x, i, color);
149 glcd_set_pixel(x+w-1, i, color);
150 }
151 glcd_update_bbox(x, y, x+w-1, y+h-1);
152}
153
154void glcd_draw_rect_thick(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t tx, uint8_t ty, uint8_t color)
155{
156 int16_t i, t;
157
158 if (tx == 0) {
159 tx = 1;
160 }
161
162 if (ty == 0) {
163 ty = 1;
164 }
165
166 for (i=x; i<x+w; i++) {
167 /* Top and bottom sides */
168 for (t=0; t<(ty); t++) {
169 glcd_set_pixel(i, y+t, color);
170 glcd_set_pixel(i, y+h-1-t, color);
171 }
172 }
173 for (i=y; i<y+h; i++) {
174 /* Left and right sides */
175 for (t=0; t<(tx); t++) {
176 glcd_set_pixel(x+t, i, color);
177 glcd_set_pixel(x+w-1-t, i, color);
178 }
179 }
180 glcd_update_bbox(x, y, x+w-1, y+h-1);
181}
182
183void glcd_draw_rect_shadow(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color)
184{
185 glcd_draw_rect(x, y, w, h, color);
186 glcd_draw_line(x+1, y+h, x+w, y+h, color);
187 glcd_draw_line(x+w, y+1, x+w, y+h, color);
188}
189
190void glcd_draw_circle(uint8_t x0, uint8_t y0, uint8_t r, uint8_t color)
191{
192
193 int8_t f = 1 - r;
194 int8_t ddF_x = 1;
195 int8_t ddF_y = -2 * r;
196 int8_t x = 0;
197 int8_t y = r;
198
199 glcd_update_bbox(x0-r, y0-r, x0+r, y0+r);
200
201 glcd_set_pixel(x0, y0+r, color);
202 glcd_set_pixel(x0, y0-r, color);
203 glcd_set_pixel(x0+r, y0, color);
204 glcd_set_pixel(x0-r, y0, color);
205
206 while (x<y) {
207 if (f >= 0) {
208 y--;
209 ddF_y += 2;
210 f += ddF_y;
211 }
212 x++;
213 ddF_x += 2;
214 f += ddF_x;
215
216 glcd_set_pixel(x0 + x, y0 + y, color);
217 glcd_set_pixel(x0 - x, y0 + y, color);
218 glcd_set_pixel(x0 + x, y0 - y, color);
219 glcd_set_pixel(x0 - x, y0 - y, color);
220
221 glcd_set_pixel(x0 + y, y0 + x, color);
222 glcd_set_pixel(x0 - y, y0 + x, color);
223 glcd_set_pixel(x0 + y, y0 - x, color);
224 glcd_set_pixel(x0 - y, y0 - x, color);
225
226 }
227}
228
229void glcd_fill_circle(uint8_t x0, uint8_t y0, uint8_t r, uint8_t color)
230{
231
232 int8_t f = 1 - r;
233 int8_t ddF_x = 1;
234 int8_t ddF_y = -2 * r;
235 int8_t x = 0;
236 int8_t y = r;
237
238 int16_t i;
239
240 glcd_update_bbox(x0-r, y0-r, x0+r, y0+r);
241
242 for (i=y0-r; i<=y0+r; i++) {
243 glcd_set_pixel(x0, i, color);
244 }
245
246 while (x < y) {
247 if (f >= 0) {
248 y--;
249 ddF_y += 2;
250 f += ddF_y;
251 }
252 x++;
253 ddF_x += 2;
254 f += ddF_x;
255
256 for (i=y0-y; i<=y0+y; i++) {
257 glcd_set_pixel(x0+x, i, color);
258 glcd_set_pixel(x0-x, i, color);
259 }
260 for (i=y0-x; i<=y0+x; i++) {
261 glcd_set_pixel(x0+y, i, color);
262 glcd_set_pixel(x0-y, i, color);
263 }
264 }
265}
266
267void glcd_invert_area(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
268{
269 uint8_t xx, yy;
270 for (xx = x; xx < (x+w); xx++) {
271 /* Loop through each partial column */
272 for (yy = y; yy < (y+h); yy++) {
273 /* Go down and invert every pixel */
274 glcd_invert_pixel(xx,yy);
275 }
276 }
277}
278
279void glcd_draw_bitmap(const unsigned char *data)
280{
281
282#if 0
283 /* Testing purposes only: Writing to the LCD right away (not for AVR) */
284 /* Normally, we do not do this, we just write to the screen buffer */
285 uint8_t *original_buffer;
286
287 /* Save the location of original screen buffer */
288 original_buffer = glcd_buffer_selected;
289
290 /* Use bitmap location as screen buffer (this won't work when using AVR8 PGM_P) */
291 glcd_select_screen((uint8_t *)data, glcd_bbox_selected);
292
293 /* Make sure we write the entre display */
294 glcd_bbox_refresh();
295 glcd_write();
296
297 /* Restore the screen buffer back to original */
298 glcd_select_screen(original_buffer, glcd_bbox_selected);
299#endif
300
301 /* Copy bitmap data to the screen buffer */
302#if defined(GLCD_DEVICE_AVR8)
303 memcpy_P(glcd_buffer_selected, data, (GLCD_LCD_WIDTH * GLCD_LCD_HEIGHT / 8));
304#else
305 memcpy(glcd_buffer_selected, data, (GLCD_LCD_WIDTH * GLCD_LCD_HEIGHT / 8));
306#endif
307
308 glcd_bbox_refresh();
309}