OSD working
[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 <math.h>
23 #include <system.h>
24 #include <string.h>
25 #include <fatfs.h>
26 #include <blockdev.h>
27
28 #include "font.h"
29 #include "logo.h"
30 #include "renderer.h"
31 #include "osd.h"
32
33 int osd_x;
34 int osd_y;
35 #define OSD_W 600
36 #define OSD_H 160
37 #define OSD_CORNER 15
38 #define OSD_CHROMAKEY 0x001f
39
40 static struct tmu_vertex osd_vertices[TMU_MESH_MAXSIZE][TMU_MESH_MAXSIZE] __attribute__((aligned(8)));
41
42 static unsigned short int osd_fb[OSD_W*OSD_H] __attribute__((aligned(32)));
43
44 static struct font_context osd_font;
45
46 static void round_corners()
47 {
48         int i;
49         int d;
50         int x;
51
52         for(i=0;i<OSD_CORNER;i++) {
53                 d = OSD_CORNER - sqrtf(2*OSD_CORNER*i - i*i);
54                 for(x=0;x<d;x++) {
55                         osd_fb[i*OSD_W+x] = OSD_CHROMAKEY;
56                         osd_fb[i*OSD_W+(OSD_W-1-x)] = OSD_CHROMAKEY;
57                         osd_fb[(OSD_H-1-i)*OSD_W+x] = OSD_CHROMAKEY;
58                         osd_fb[(OSD_H-1-i)*OSD_W+(OSD_W-1-x)] = OSD_CHROMAKEY;
59                 }
60         }
61 }
62
63 #define LOGO_W 46
64 #define LOGO_H 46
65
66 static void logo()
67 {
68         int x, y;
69
70         for(y=0;y<LOGO_H;y++)
71                 for(x=0;x<LOGO_W;x++)
72                         osd_fb[(x+OSD_W-LOGO_W-OSD_CORNER)+OSD_W*(y+OSD_CORNER)] = ((unsigned short *)logo_raw)[x+LOGO_W*y];
73 }
74
75 static void init_ui();
76
77 void osd_init()
78 {
79         osd_x = (vga_hres - OSD_W) >> 1;
80         osd_y = vga_vres - OSD_H - 20;
81         
82         osd_vertices[0][0].x = 0;
83         osd_vertices[0][0].y = 0;
84         osd_vertices[0][1].x = OSD_W << TMU_FIXEDPOINT_SHIFT;
85         osd_vertices[0][1].y = 0;
86         osd_vertices[1][0].x = 0;
87         osd_vertices[1][0].y = OSD_H << TMU_FIXEDPOINT_SHIFT;
88         osd_vertices[1][1].x = OSD_W << TMU_FIXEDPOINT_SHIFT;
89         osd_vertices[1][1].y = OSD_H << TMU_FIXEDPOINT_SHIFT;
90
91         round_corners();
92         logo();
93
94         init_ui();
95 }
96
97 static int previous_keys;
98 static int osd_alpha;
99 static int osd_timer;
100
101 #define OSD_DURATION 90
102 #define OSD_MAX_ALPHA 40
103
104 #define OSD_MAX_USER_X (OSD_W-OSD_CORNER-LOGO_W)
105
106 #define MAX_PATCH_TITLE 45
107 #define MAX_PATCHES 128
108 static char current_patch[MAX_PATCH_TITLE+1];
109 static char patchlist_filenames[MAX_PATCHES][13];
110 static char patchlist_titles[MAX_PATCHES][MAX_PATCH_TITLE+1];
111 static int patchlist_n;
112 static int patchlist_sel;
113 static int patchlist_page;
114
115 static int patchlist_maxpage;
116 static int patchlist_maxsel;
117
118 static int patchlist_pending;
119
120 static void clear_user_area()
121 {
122         int x, y;
123         
124         for(y=OSD_CORNER;y<(OSD_H-OSD_CORNER);y++)
125                 for(x=OSD_CORNER;x<OSD_MAX_USER_X;x++)
126                         osd_fb[x+y*OSD_W] = 0;
127 }
128
129 static void draw_user_area()
130 {
131         int i;
132         int h;
133         int nel;
134         
135         clear_user_area();
136         h = font_get_height(&osd_font);
137         font_draw_string(&osd_font, OSD_CORNER, OSD_CORNER, 0, current_patch);
138         nel = patchlist_page < patchlist_maxpage ? 4 : patchlist_maxsel;
139         for(i=0;i<nel;i++)
140                 font_draw_string(&osd_font, OSD_CORNER+20, OSD_CORNER+(i+1)*h, i == patchlist_sel, patchlist_titles[patchlist_page*4+i]);
141         flush_bridge_cache();
142 }
143
144 static void start_patch_from_list(int n)
145 {
146         strcpy(current_patch, patchlist_titles[n]);
147         patchlist_pending = n;
148 }
149
150 static void process_keys(unsigned int keys)
151 {
152         if(keys & GPIO_BTN1) {
153                 if(patchlist_sel > 0)
154                         patchlist_sel--;
155                 else if(patchlist_page > 0) {
156                         patchlist_page--;
157                         patchlist_sel = 3;
158                 }
159         }
160         if(keys & GPIO_BTN3) {
161                 if(patchlist_page < patchlist_maxpage) {
162                         if(patchlist_sel < 3)
163                                 patchlist_sel++;
164                         else {
165                                 patchlist_page++;
166                                 patchlist_sel = 0;
167                         }
168                 } else if(patchlist_sel < (patchlist_maxsel-1))
169                         patchlist_sel++;
170         }
171         if(keys & GPIO_BTN2)
172                 start_patch_from_list(patchlist_page*4+patchlist_sel);
173
174         draw_user_area();
175 }
176
177 static int lscb(const char *filename, const char *longname, void *param)
178 {
179         char *c;
180
181         if(strlen(longname) < 5) return 1;
182         c = (char *)longname + strlen(longname) - 5;
183         if(strcmp(c, ".milk") != 0) return 1;
184         strcpy(patchlist_filenames[patchlist_n], filename);
185         strncpy(patchlist_titles[patchlist_n], longname, MAX_PATCH_TITLE);
186         patchlist_titles[patchlist_n][MAX_PATCH_TITLE] = 0;
187         c = patchlist_titles[patchlist_n] + strlen(patchlist_titles[patchlist_n]) - 5;
188         if(strcmp(c, ".milk") == 0) *c = 0;
189         patchlist_n++;
190         return patchlist_n < MAX_PATCHES;
191 }
192
193 static void init_ui()
194 {
195         previous_keys = 0;
196         osd_alpha = 0;
197         osd_timer = OSD_DURATION;
198
199         patchlist_n = 0;
200         patchlist_sel = 0;
201         patchlist_page = 0;
202         patchlist_pending = -1;
203
204         if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
205         fatfs_list_files(lscb, NULL);
206         fatfs_done();
207
208         patchlist_maxpage = (patchlist_n+3)/4 - 1;
209         patchlist_maxsel = patchlist_n % 4;
210         
211         if(patchlist_n > 0)
212                 start_patch_from_list(0);
213
214         font_init_context(&osd_font, vera20_tff, osd_fb, OSD_W, OSD_H);
215         draw_user_area();
216 }
217
218 void osd_service()
219 {
220         if(patchlist_pending != -1) {
221                 char buffer[8192];
222                 int size;
223                 int n;
224
225                 n = patchlist_pending;
226                 patchlist_pending = -1;
227                 if(!fatfs_init(BLOCKDEV_FLASH, 0)) return;
228                 if(!fatfs_load(patchlist_filenames[n], buffer, sizeof(buffer), &size)) return;
229                 fatfs_done();
230                 buffer[size] = 0;
231
232                 renderer_start(buffer);
233         }
234 }
235
236 int osd_fill_blit_td(struct tmu_td *td, tmu_callback callback, void *user)
237 {
238         unsigned int keys;
239         unsigned int new_keys;
240
241         keys = CSR_GPIO_IN & (GPIO_BTN1|GPIO_BTN2|GPIO_BTN3);
242         new_keys = keys & ~previous_keys;
243         previous_keys = keys;
244
245         if(new_keys) {
246                 osd_timer = OSD_DURATION;
247                 if(osd_alpha != 0)
248                         process_keys(new_keys);
249         }
250
251         osd_timer--;
252         if(osd_timer > 0) {
253                 osd_alpha += 4;
254                 if(osd_alpha > OSD_MAX_ALPHA)
255                         osd_alpha = OSD_MAX_ALPHA;
256         } else {
257                 osd_alpha--;
258                 if(osd_alpha < 0)
259                         osd_alpha = 0;
260         }
261
262         td->flags = TMU_CTL_CHROMAKEY;
263         td->hmeshlast = 1;
264         td->vmeshlast = 1;
265         td->brightness = TMU_BRIGHTNESS_MAX;
266         td->chromakey = OSD_CHROMAKEY;
267         td->vertices = &osd_vertices[0][0];
268         td->texfbuf = osd_fb;
269         td->texhres = OSD_W;
270         td->texvres = OSD_H;
271         td->texhmask = TMU_MASK_NOFILTER;
272         td->texvmask = TMU_MASK_NOFILTER;
273         td->dstfbuf = vga_backbuffer;
274         td->dsthres = vga_hres;
275         td->dstvres = vga_vres;
276         td->dsthoffset = osd_x;
277         td->dstvoffset = osd_y;
278         td->dstsquarew = OSD_W;
279         td->dstsquareh = OSD_H;
280         td->alpha = osd_alpha;
281         td->callback = callback;
282         td->user = user;
283
284         return osd_alpha != 0;
285 }
286