bullshit commit, sync for travel (to zn00H!) :)
[my-code/arm.git] / betty / display.c
1 /*
2  * display.c - handling the display
3  *
4  * author: hackbard@hackdaworld.org
5  *
6  */
7
8 /*
9  * some comments on alpha blending!
10  * ################################
11  *
12  * if c is the result of layer a over layer b with opacity alpha:
13  * 
14  * c=alpha*a+(1-alpha)*b and if alpha is a byte (0-255)
15  * => c=alpha*a+(255-alpha)*b
16  * 
17  */
18
19 #include "display.h"
20
21 // debug
22 #include "uart.h"
23
24 /*
25  * functions
26  */
27
28 void display_fill_screen(u8 fill) {
29
30         u8 page,width;
31         u8 buf[2];
32
33         buf[0]=0;
34         buf[1]=0;
35
36         switch(fill) {
37                 case DISPLAY_FILL_LG:
38                         buf[1]=0xff;
39                         break;
40                 case DISPLAY_FILL_DG:
41                         buf[0]=0xff;
42                         break;
43                 case DISPLAY_FILL_B:
44                         buf[0]=0xff;
45                         buf[1]=0xff;
46                         break;
47                 case DISPLAY_FILL_W:
48                 default:
49                         break;
50         }
51
52         for(page=0;page<DISPLAY_PAGE_MAX;page++) {
53                 DISPLAY_SET_COL_ADDR(0);
54                 DISPLAY_SET_PAGE_ADDR(page);
55                 for(width=0;width<DISPLAY_DIMX;width++) {
56                         DISPLAY_DATA=buf[0];
57                         DISPLAY_DATA=buf[1];
58                 }
59         }
60 }
61
62 void display_clear_screen(void) {
63
64         display_fill_screen(DISPLAY_FILL_W);
65 }
66
67 void display_init(void) {
68
69         /* oscillator, regulator, boost, opamp, contrast */
70         DISPLAY_START_OSCILLATOR;
71         DISPLAY_SET_REGULATOR(7);
72         DISPLAY_SET_CONTRAST(0x38);
73         DISPLAY_SET_CONV_FACTOR(0x01);
74         DISPLAY_SET_POWER(DISPLAY_V_BOOST|DISPLAY_REGULATOR|DISPLAY_OPAMP);
75
76         // gray scale palette
77         DISPLAY_SET_WHITE(0,0,0,0);
78         DISPLAY_SET_LGRAY(5,5,5,5);     // obviously 3, but it's too bright!
79         DISPLAY_SET_DGRAY(7,7,7,7);     // obviously 6, but again too bright!
80         DISPLAY_SET_BLACK(9,9,9,9);
81
82         /* normal mode, display depending ram content */
83         DISPLAY_RAM_CONTENTS_ON;
84         display_clear_screen();
85         DISPLAY_NORMAL;                 // 00 -> white, 11 -> black
86         DISPLAY_SET_COM_ODIR_REMAPPED;  // start counting at the top
87
88         /* switch on the display */
89         DISPLAY_SET_ON;
90 }
91
92 void display_logo(u8 *src) {
93
94         u8 page,width;
95
96         for(page=0;page<DISPLAY_PAGE_MAX;page++) {
97                 DISPLAY_SET_COL_ADDR(0);
98                 DISPLAY_SET_PAGE_ADDR(page);
99                 for(width=0;width<DISPLAY_DIMX;width++) {
100                         DISPLAY_DATA=*src++;
101                         DISPLAY_DATA=*src++;
102                 }
103         }
104 }
105
106 #define display_m2i(m,r) (((((m)[0]>>r)&1)<<1)|(((m)[1]>>r)&1))
107
108 void display_draw_rectangle(u8 x,u8 y,u8 w,u8 h,u8 fill,u8 alpha) {
109
110         u8 page,col,row,rmax,cnt;
111         u8 d[2];
112         int ca,cb;
113         u8 a,b,c;                       // c = a over b
114
115         a=fill&0x03;
116         ca=0;
117         for(cnt=0;cnt<a;cnt++)          // contribution of a: alpha*a
118                 ca+=alpha;
119
120         for(page=(y>>3);page<=((y+h)>>3);page++) {      // page = y/8
121                 DISPLAY_SET_PAGE_ADDR(page);
122                 rmax=(page+1)<<3;                       // row max
123                 if(rmax>y+h)
124                         rmax=y+h;
125                 for(col=x;col<x+w;col++) {
126                         DISPLAY_SET_COL_ADDR(col);
127                         d[0]=DISPLAY_DATA; // dummy read (p.16)
128                         d[0]=DISPLAY_DATA;
129                         d[1]=DISPLAY_DATA;
130                         row=DISPLAY_DATA; // aligne
131                         for(row=y;row<rmax;row++) {
132                                 // contribution of b: (255-alpha)*b
133                                 b=display_m2i(d,row);
134                                 cb=0;
135                                 for(cnt=0;cnt<b;cnt++)
136                                         cb+=(255-alpha);
137                                 // finally there is c
138                                 c=(ca+cb)>>8;
139                                 d[0]&=~(1<<row);
140                                 d[1]&=~(1<<row);
141                                 d[0]|=((c>>1)&1)<<row;
142                                 d[1]|=(c&1)<<row;
143                         }
144                         DISPLAY_SET_COL_ADDR(col);
145                         DISPLAY_DATA=d[0];
146                         DISPLAY_DATA=d[1];
147                 }
148                 h-=(rmax-y);
149                 y=rmax;
150         }
151 }
152
153 void display_rectangle_page(u8 x,u8 p,u8 w,u8 h,u8 fill,u8 alpha) {
154
155         u8 page,col,row;
156         u8 buf[2];
157         u8 b,c;
158
159         for(page=p;page<p+h;page++) {
160                 DISPLAY_SET_PAGE_ADDR(page);
161                 for(col=x;col<x+w;col++) {
162                         DISPLAY_SET_COL_ADDR(col);
163                         buf[0]=DISPLAY_DATA; // dummy read
164                         buf[0]=DISPLAY_DATA;
165                         buf[1]=DISPLAY_DATA;
166                         row=DISPLAY_DATA; // aligne dummy read
167                         for(row=0;row<8;row++) {
168                                 b=display_m2i(buf,row);
169                                 c=(b*(255-alpha)+fill*alpha)>>8;
170                                 buf[0]&=~(1<<row);
171                                 buf[1]&=~(1<<row);
172                                 if(c&2)
173                                         buf[0]|=(1<<row);
174                                 if(c&1)
175                                         buf[1]|=(1<<row);
176                         }
177                         DISPLAY_SET_COL_ADDR(col);
178                         DISPLAY_DATA=buf[0];
179                         DISPLAY_DATA=buf[1];
180                 }
181         }
182 }
183
184 void display_font_page(u8 x,u8 page,u8 *font,u8 fill) {
185
186         /* this only draws page aligned fonts! */
187         u8 cnt,row;
188         u8 c[16];
189
190         /* set the page */
191         DISPLAY_SET_PAGE_ADDR(page);
192
193         /* read old content */
194         DISPLAY_SET_COL_ADDR(x);
195         c[0]=DISPLAY_DATA; // dummy read
196         for(cnt=0;cnt<16;cnt++) {
197                 c[cnt++]=DISPLAY_DATA;
198                 c[cnt]=DISPLAY_DATA;
199         }
200         cnt=DISPLAY_DATA; // 2 byte aligne dummy read
201
202         /* write new content */
203         DISPLAY_SET_COL_ADDR(x);
204         for(cnt=0;cnt<16;cnt++) {
205                 for(row=0;row<8;row++) {
206                         if((font[cnt>>1]>>row)&1) {
207                                 c[cnt]&=~(1<<row);
208                                 c[cnt+1]&=~(1<<row);
209                                 c[cnt]|=(((fill>>1)&1)<<row);
210                                 c[cnt+1]|=((fill&1)<<row);
211                         }
212                 }
213                 DISPLAY_DATA=c[cnt++];
214                 DISPLAY_DATA=c[cnt];
215         }
216 }
217
218 void display_draw_font(u8 x,u8 y,u8 *font,u8 fill,u8 alpha) {
219
220         u8 page,col,row,rmax,cnt,left,cf,rf;
221         u8 d[2];
222         int ca,cb;
223         u8 a,b,c;                       // c = a over b
224
225         left=8;
226
227         a=fill&0x03;
228         ca=0;
229         for(cnt=0;cnt<a;cnt++)          // contribution of a: alpha*a
230                 ca+=alpha;
231
232         for(page=(y>>3);page<=((y+8)>>3);page++) {      // page = y/8
233                 DISPLAY_SET_PAGE_ADDR(page);
234                 rmax=(page+1)<<3;                       // row max
235                 if(rmax>y+left)
236                         rmax=y+left;
237                 cf=0;
238                 for(col=x;col<x+8;col++) {
239                         DISPLAY_SET_COL_ADDR(col);
240                         d[0]=DISPLAY_DATA;              // dummy read (p.16)
241                         d[0]=DISPLAY_DATA;
242                         d[1]=DISPLAY_DATA;
243                         rf=0;
244                         for(row=y;row<rmax;row++) {
245                                 // contribution of b: (255-alpha)*b
246                                 b=display_m2i(d,row);
247                                 cb=0;
248                                 for(cnt=0;cnt<b;cnt++)
249                                         cb+=(255-alpha);
250                                 // finally there is c
251                                 if((font[cf]>>row)&1) {
252                                         c=(ca+cb)>>8;
253                                         d[0]&=~(1<<row);
254                                         d[1]&=~(1<<row);
255                                         d[0]|=((c>>1)&1)<<row;
256                                         d[1]|=(c&1)<<row;
257                                 }
258                                 rf+=1;
259                         }
260                         DISPLAY_SET_COL_ADDR(col);
261                         DISPLAY_DATA=d[0];
262                         DISPLAY_DATA=d[1];
263                         cf+=1;
264                 }
265                 left-=(rmax-y);
266                 y=rmax;
267         }
268 }
269
270 void display_bl_init(void) {
271
272         IODIR0|=(1<<4);
273         IOSET0=(1<<4);  // off by default
274 }
275
276 void display_bl_toggle(void) {
277
278         if(IOPIN0&(1<<4))
279                 IOCLR0=(1<<4);
280         else
281                 IOSET0=(1<<4);
282 }
283
284 void display_bl_on(void) {
285
286         IOCLR0=(1<<4);
287 }
288
289 void display_bl_off(void) {
290
291         IOSET0=(1<<4);
292 }
293