67f3578479cae1998a125fccb5aece59e0354de0
[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
166         if(keys & GPIO_BTN1) {
167                 if(patchlist_sel > 0)
168                         patchlist_sel--;
169                 else if(patchlist_page > 0) {
170                         patchlist_page--;
171                         patchlist_sel = 3;
172                 }
173         }
174         if(keys & GPIO_BTN3) {
175                 if(patchlist_page < patchlist_maxpage) {
176                         if(patchlist_sel < 3)
177                                 patchlist_sel++;
178                         else {
179                                 patchlist_page++;
180                                 patchlist_sel = 0;
181                         }
182                 } else if(patchlist_sel < (patchlist_maxsel-1))
183                         patchlist_sel++;
184         }
185         if(keys & GPIO_BTN2)
186                 start_patch_from_list(patchlist_page*4+patchlist_sel);
187
188         draw_user_area();
189 }
190
191 static int lscb(const char *filename, const char *longname, void *param)
192 {
193         char *c;
194
195         if(strlen(longname) < 5) return 1;
196         c = (char *)longname + strlen(longname) - 5;
197         if(strcmp(c, ".milk") != 0) return 1;
198         strcpy(patchlist_filenames[patchlist_n], filename);
199         strncpy(patchlist_titles[patchlist_n], longname, MAX_PATCH_TITLE);
200         patchlist_titles[patchlist_n][MAX_PATCH_TITLE] = 0;
201         c = patchlist_titles[patchlist_n] + strlen(patchlist_titles[patchlist_n]) - 5;
202         if(strcmp(c, ".milk") == 0) *c = 0;
203         patchlist_n++;
204         return patchlist_n < MAX_PATCHES;
205 }
206
207 static void init_ui()
208 {
209         previous_keys = 0;
210         up1_last_toggle = 2;
211         up2_last_toggle = 2;
212         down1_last_toggle = 2;
213         down2_last_toggle = 2;
214         ok_last_toggle = 2;
215         osd_alpha = 0;
216         osd_timer = OSD_DURATION;
217
218         patchlist_n = 0;
219         patchlist_sel = 0;
220         patchlist_page = 0;
221         patchlist_pending = -1;
222
223         if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
224         fatfs_list_files(lscb, NULL);
225         fatfs_done();
226
227         patchlist_maxpage = (patchlist_n+3)/4 - 1;
228         patchlist_maxsel = patchlist_n % 4;
229         if(patchlist_maxsel == 0)
230                 patchlist_maxsel = 4;
231         
232         if(patchlist_n > 0)
233                 start_patch_from_list(0);
234
235         draw_user_area();
236 }
237
238 void osd_service()
239 {
240         if(patchlist_pending != -1) {
241                 char buffer[8192];
242                 int size;
243                 int n;
244
245                 n = patchlist_pending;
246                 patchlist_pending = -1;
247                 if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
248                 if(!fatfs_load(patchlist_filenames[n], buffer, sizeof(buffer), &size)) return;
249                 fatfs_done();
250                 buffer[size] = 0;
251
252                 renderer_start(buffer);
253         }
254 }
255
256 int osd_fill_blit_td(struct tmu_td *td, tmu_callback callback, void *user)
257 {
258         unsigned int keys;
259         unsigned int new_keys;
260
261         /* handle pushbuttons */
262         keys = CSR_GPIO_IN & (GPIO_BTN1|GPIO_BTN2|GPIO_BTN3);
263         new_keys = keys & ~previous_keys;
264         previous_keys = keys;
265
266         if(new_keys) {
267                 if(osd_alpha != 0)
268                         process_keys(new_keys);
269         }
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