Ignore remote control commands when OSD is not displayed
[mw/milkymist.git] / software / demo / osd.c
1 /*
2  * Milkymist VJ SoC (Software)
3  * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3 of the License.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <hal/vga.h>
19 #include <hal/tmu.h>
20 #include <hw/sysctl.h>
21 #include <hw/gpio.h>
22 #include <hw/rc5.h>
23 #include <hw/interrupts.h>
24 #include <irq.h>
25 #include <math.h>
26 #include <system.h>
27 #include <string.h>
28 #include <fatfs.h>
29 #include <blockdev.h>
30
31 #include "font.h"
32 #include "logo.h"
33 #include "renderer.h"
34 #include "version.h"
35 #include "osd.h"
36
37 int osd_x;
38 int osd_y;
39 #define OSD_W 600
40 #define OSD_H 160
41 #define OSD_CORNER 15
42 #define OSD_CHROMAKEY 0x001f
43
44 static struct tmu_vertex osd_vertices[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
45
46 static unsigned short int osd_fb[OSD_W*OSD_H] __attribute__((aligned(32)));
47
48 static struct font_context osd_font;
49
50 static void round_corners()
51 {
52         int i;
53         int d;
54         int x;
55
56         for(i=0;i<OSD_CORNER;i++) {
57                 d = OSD_CORNER - sqrtf(2*OSD_CORNER*i - i*i);
58                 for(x=0;x<d;x++) {
59                         osd_fb[i*OSD_W+x] = OSD_CHROMAKEY;
60                         osd_fb[i*OSD_W+(OSD_W-1-x)] = OSD_CHROMAKEY;
61                         osd_fb[(OSD_H-1-i)*OSD_W+x] = OSD_CHROMAKEY;
62                         osd_fb[(OSD_H-1-i)*OSD_W+(OSD_W-1-x)] = OSD_CHROMAKEY;
63                 }
64         }
65 }
66
67 #define LOGO_W 46
68 #define LOGO_H 46
69
70 static void logo()
71 {
72         int x, y;
73
74         for(y=0;y<LOGO_H;y++)
75                 for(x=0;x<LOGO_W;x++)
76                         osd_fb[(x+OSD_W-LOGO_W-OSD_CORNER)+OSD_W*(y+OSD_CORNER)] = ((unsigned short *)logo_raw)[x+LOGO_W*y];
77         font_draw_string(&osd_font, OSD_W-LOGO_W-OSD_CORNER, OSD_H-font_get_height(&osd_font), 0, VERSION);
78 }
79
80 static void init_ui();
81
82 void osd_init()
83 {
84         osd_x = (vga_hres - OSD_W) >> 1;
85         osd_y = vga_vres - OSD_H - 20;
86         
87         osd_vertices[0][0].x = 0;
88         osd_vertices[0][0].y = 0;
89         osd_vertices[0][1].x = OSD_W << TMU_FIXEDPOINT_SHIFT;
90         osd_vertices[0][1].y = 0;
91         osd_vertices[1][0].x = 0;
92         osd_vertices[1][0].y = OSD_H << TMU_FIXEDPOINT_SHIFT;
93         osd_vertices[1][1].x = OSD_W << TMU_FIXEDPOINT_SHIFT;
94         osd_vertices[1][1].y = OSD_H << TMU_FIXEDPOINT_SHIFT;
95
96         memset(osd_fb, 0, sizeof(osd_fb));
97         font_init_context(&osd_font, vera20_tff, osd_fb, OSD_W, OSD_H);
98         round_corners();
99         logo();
100
101         init_ui();
102 }
103
104 static int previous_keys;
105 static int up1_last_toggle;
106 static int up2_last_toggle;
107 static int down1_last_toggle;
108 static int down2_last_toggle;
109 static int ok_last_toggle;
110 static int osd_alpha;
111 static int osd_timer;
112
113 #define OSD_DURATION 90
114 #define OSD_MAX_ALPHA 40
115
116 #define OSD_MAX_USER_X (OSD_W-OSD_CORNER-LOGO_W)
117
118 #define MAX_PATCH_TITLE 45
119 #define MAX_PATCHES 128
120 static char current_patch[MAX_PATCH_TITLE+1];
121 static char patchlist_filenames[MAX_PATCHES][13];
122 static char patchlist_titles[MAX_PATCHES][MAX_PATCH_TITLE+1];
123 static int patchlist_n;
124 static int patchlist_sel;
125 static int patchlist_page;
126
127 static int patchlist_maxpage;
128 static int patchlist_maxsel;
129
130 static int patchlist_pending;
131
132 static void clear_user_area()
133 {
134         int x, y;
135         
136         for(y=OSD_CORNER;y<(OSD_H-OSD_CORNER);y++)
137                 for(x=OSD_CORNER;x<OSD_MAX_USER_X;x++)
138                         osd_fb[x+y*OSD_W] = 0;
139 }
140
141 static void draw_user_area()
142 {
143         int i;
144         int h;
145         int nel;
146         
147         clear_user_area();
148         h = font_get_height(&osd_font);
149         font_draw_string(&osd_font, OSD_CORNER, OSD_CORNER, 0, current_patch);
150         nel = patchlist_page < patchlist_maxpage ? 4 : patchlist_maxsel;
151         for(i=0;i<nel;i++)
152                 font_draw_string(&osd_font, OSD_CORNER+20, OSD_CORNER+(i+1)*h, i == patchlist_sel, patchlist_titles[patchlist_page*4+i]);
153         flush_bridge_cache();
154 }
155
156 static void start_patch_from_list(int n)
157 {
158         strcpy(current_patch, patchlist_titles[n]);
159         patchlist_pending = n;
160 }
161
162 static void process_keys(unsigned int keys)
163 {
164         osd_timer = OSD_DURATION;
165         if(osd_alpha == 0)
166                 return;
167
168         if(keys & GPIO_BTN1) {
169                 if(patchlist_sel > 0)
170                         patchlist_sel--;
171                 else if(patchlist_page > 0) {
172                         patchlist_page--;
173                         patchlist_sel = 3;
174                 }
175         }
176         if(keys & GPIO_BTN3) {
177                 if(patchlist_page < patchlist_maxpage) {
178                         if(patchlist_sel < 3)
179                                 patchlist_sel++;
180                         else {
181                                 patchlist_page++;
182                                 patchlist_sel = 0;
183                         }
184                 } else if(patchlist_sel < (patchlist_maxsel-1))
185                         patchlist_sel++;
186         }
187         if(keys & GPIO_BTN2)
188                 start_patch_from_list(patchlist_page*4+patchlist_sel);
189
190         draw_user_area();
191 }
192
193 static int lscb(const char *filename, const char *longname, void *param)
194 {
195         char *c;
196
197         if(strlen(longname) < 5) return 1;
198         c = (char *)longname + strlen(longname) - 5;
199         if(strcmp(c, ".milk") != 0) return 1;
200         strcpy(patchlist_filenames[patchlist_n], filename);
201         strncpy(patchlist_titles[patchlist_n], longname, MAX_PATCH_TITLE);
202         patchlist_titles[patchlist_n][MAX_PATCH_TITLE] = 0;
203         c = patchlist_titles[patchlist_n] + strlen(patchlist_titles[patchlist_n]) - 5;
204         if(strcmp(c, ".milk") == 0) *c = 0;
205         patchlist_n++;
206         return patchlist_n < MAX_PATCHES;
207 }
208
209 static void init_ui()
210 {
211         previous_keys = 0;
212         up1_last_toggle = 2;
213         up2_last_toggle = 2;
214         down1_last_toggle = 2;
215         down2_last_toggle = 2;
216         ok_last_toggle = 2;
217         osd_alpha = 0;
218         osd_timer = OSD_DURATION;
219
220         patchlist_n = 0;
221         patchlist_sel = 0;
222         patchlist_page = 0;
223         patchlist_pending = -1;
224
225         if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
226         fatfs_list_files(lscb, NULL);
227         fatfs_done();
228
229         patchlist_maxpage = (patchlist_n+3)/4 - 1;
230         patchlist_maxsel = patchlist_n % 4;
231         if(patchlist_maxsel == 0)
232                 patchlist_maxsel = 4;
233         
234         if(patchlist_n > 0)
235                 start_patch_from_list(0);
236
237         draw_user_area();
238 }
239
240 void osd_service()
241 {
242         if(patchlist_pending != -1) {
243                 char buffer[8192];
244                 int size;
245                 int n;
246
247                 n = patchlist_pending;
248                 patchlist_pending = -1;
249                 if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
250                 if(!fatfs_load(patchlist_filenames[n], buffer, sizeof(buffer), &size)) return;
251                 fatfs_done();
252                 buffer[size] = 0;
253
254                 renderer_start(buffer);
255         }
256 }
257
258 int osd_fill_blit_td(struct tmu_td *td, tmu_callback callback, void *user)
259 {
260         unsigned int keys;
261         unsigned int new_keys;
262
263         /* handle pushbuttons */
264         keys = CSR_GPIO_IN & (GPIO_BTN1|GPIO_BTN2|GPIO_BTN3);
265         new_keys = keys & ~previous_keys;
266         previous_keys = keys;
267
268         if(new_keys)
269                 process_keys(new_keys);
270
271         /* handle IR remote */
272         if(irq_pending() & IRQ_IR) {
273                 unsigned int r;
274                 int toggle;
275                 int cmd;
276
277                 r = CSR_RC5_RX;
278                 irq_ack(IRQ_IR);
279                 toggle = (r & 0x0800) >> 11;
280                 cmd = r & 0x003f;
281                 switch(cmd) {
282                         case 16:
283                                 if(up1_last_toggle != toggle) {
284                                         up1_last_toggle = toggle;
285                                         process_keys(GPIO_BTN1);
286                                 }
287                                 break;
288                         case 32:
289                                 if(up2_last_toggle != toggle) {
290                                         up2_last_toggle = toggle;
291                                         process_keys(GPIO_BTN1);
292                                 }
293                                 break;
294                         case 17:
295                                 if(down1_last_toggle != toggle) {
296                                         down1_last_toggle = toggle;
297                                         process_keys(GPIO_BTN3);
298                                 }
299                                 break;
300                         case 33:
301                                 if(down2_last_toggle != toggle) {
302                                         down2_last_toggle = toggle;
303                                         process_keys(GPIO_BTN3);
304                                 }
305                                 break;
306                         case 12:
307                                 if(ok_last_toggle != toggle) {
308                                         ok_last_toggle = toggle;
309                                         process_keys(GPIO_BTN2);
310                                 }
311                                 break;
312                 }
313         }
314
315         osd_timer--;
316         if(osd_timer > 0) {
317                 osd_alpha += 4;
318                 if(osd_alpha > OSD_MAX_ALPHA)
319                         osd_alpha = OSD_MAX_ALPHA;
320         } else {
321                 osd_alpha--;
322                 if(osd_alpha < 0)
323                         osd_alpha = 0;
324         }
325
326         td->flags = TMU_CTL_CHROMAKEY;
327         td->hmeshlast = 1;
328         td->vmeshlast = 1;
329         td->brightness = TMU_BRIGHTNESS_MAX;
330         td->chromakey = OSD_CHROMAKEY;
331         td->vertices = &osd_vertices[0][0];
332         td->texfbuf = osd_fb;
333         td->texhres = OSD_W;
334         td->texvres = OSD_H;
335         td->texhmask = TMU_MASK_NOFILTER;
336         td->texvmask = TMU_MASK_NOFILTER;
337         td->dstfbuf = vga_backbuffer;
338         td->dsthres = vga_hres;
339         td->dstvres = vga_vres;
340         td->dsthoffset = osd_x;
341         td->dstvoffset = osd_y;
342         td->dstsquarew = OSD_W;
343         td->dstsquareh = OSD_H;
344         td->alpha = osd_alpha;
345         td->callback = callback;
346         td->user = user;
347
348         return osd_alpha != 0;
349 }
350