add input, basic config
[sdl_omap.git] / src / video / omapdss / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <strings.h>
5 #include <ctype.h>
6 #include <sys/time.h>
7 #include <SDL/SDL.h>
8
9 #include "pmsdl.h"
10 #include "common/input.h"
11 #include "linux/fbdev.h"
12 #include "linux/oshide.h"
13
14 static SDL_Surface *g_screen;
15 static void *g_screen_fbp;
16 static Uint16 g_8bpp_pal[256];
17 static Uint32 g_start_ticks;
18
19 static inline int min(int v1, int v2)
20 {
21         return v1 < v2 ? v1 : v2;
22 }
23
24 static SDL_Surface *alloc_surface(int w, int h, int bpp)
25 {
26         // SDL has some pointer overuse, every surface has a format,
27         // why make format accessible through pointer?
28         struct {
29                 SDL_Surface s;
30                 SDL_PixelFormat f;
31         } *ret;
32
33         ret = calloc(1, sizeof(*ret));
34         if (ret == NULL)
35                 return NULL;
36
37         ret->s.format = &ret->f;
38         ret->f.BitsPerPixel = bpp;
39         ret->f.BytesPerPixel = (bpp + 7) / 8;
40
41         ret->s.w = w;
42         ret->s.h = h;
43         ret->s.pitch = w * ret->f.BytesPerPixel;
44         // XXX: more fields
45
46         return &ret->s;
47 }
48
49 static char *sskip(char *p)
50 {
51         while (*p && isspace(*p))
52                 p++;
53         return p;
54 }
55
56 static char *nsskip(char *p)
57 {
58         while (*p && !isspace(*p))
59                 p++;
60         return p;
61 }
62
63 static int check_token(const char *p, const char *token)
64 {
65         int tlen = strlen(token);
66         return strncasecmp(p, token, tlen) == 0 && isspace(p[tlen]);
67 }
68
69 static void do_config(void)
70 {
71         char buff[256];
72         FILE *f;
73
74         f = fopen("pmsdl.cfg", "r");
75         if (f == NULL)
76                 return;
77
78         while (!feof(f)) {
79                 char *p, *line = fgets(buff, sizeof(buff), f);
80                 if (line == NULL)
81                         break;
82                 p = line = sskip(line);
83                 if (*p == '#')
84                         continue;
85
86                 if (check_token(p, "bind")) {
87                         char *key, *key_end, *sdlkey, *sdlkey_end;
88                         key = sskip(p + 5);
89                         key_end = nsskip(key);
90                         p = sskip(key_end);
91                         if (*p != '=')
92                                 goto bad;
93                         sdlkey = sskip(p + 1);
94                         sdlkey_end = nsskip(sdlkey);
95                         p = sskip(sdlkey_end);
96                         if (*key == 0 || *sdlkey == 0 || *p != 0)
97                                 goto bad;
98                         *key_end = *sdlkey_end = 0;
99
100                         pmsdl_input_bind(key, sdlkey);
101                         continue;
102                 }
103
104 bad:
105                 err("config: failed to parse: %s", line);
106         }
107         fclose(f);
108 }
109
110 DECLSPEC int SDLCALL
111 SDL_Init(Uint32 flags)
112 {
113         trace("%08x", flags);
114
115         if (g_start_ticks == 0) {
116                 pmsdl_input_init();
117                 oshide_init();
118                 do_config();
119         }
120
121         g_start_ticks = 0;
122         g_start_ticks = SDL_GetTicks();
123
124         return 0;
125 }
126
127 DECLSPEC void SDLCALL
128 SDL_Quit(void)
129 {
130         trace("");
131
132         if (g_start_ticks != 0) {
133                 oshide_finish();
134                 g_start_ticks = 0;
135         }
136 }
137
138 DECLSPEC int SDLCALL
139 SDL_InitSubSystem(Uint32 flags)
140 {
141         trace("%08x", flags);
142         return 0;
143 }
144
145 DECLSPEC void SDLCALL
146 SDL_QuitSubSystem(Uint32 flags)
147 {
148         trace("%08x", flags);
149 }
150
151 DECLSPEC Uint32 SDLCALL
152 SDL_GetTicks(void)
153 {
154         struct timeval tv;
155         Uint32 ret;
156
157         gettimeofday(&tv, NULL);
158         ret = tv.tv_sec * 1000;
159         ret += tv.tv_usec * 1048 >> 20;
160
161         ret -= g_start_ticks;
162         dbg(" SDL_GetTicks %d", ret);
163         return ret;
164 }
165
166 DECLSPEC SDL_Surface * SDLCALL
167 SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
168 {
169         struct vout_fbdev *fbdev;
170
171         trace("%d, %d, %d, %08x", width, height, bpp, flags);
172
173         if (bpp == 0)
174                 bpp = 16;
175
176         if (bpp != 8 && bpp != 16) {
177                 err("unsupported bpp: %d\n", bpp);
178                 return NULL;
179         }
180
181         // XXX: destroy old g_screen?
182
183         g_screen = alloc_surface(width, height, bpp);
184         if (g_screen == NULL)
185                 return NULL;
186
187         fbdev = vout_fbdev_init("/dev/fb0", &width, &height, 0);
188         if (fbdev == NULL)
189                 goto fail_fbdev_init;
190
191         g_screen_fbp = vout_fbdev_flip(fbdev);
192         if (bpp == 16)
193                 g_screen->pixels = g_screen_fbp;
194         else
195                 // we have to fake this for now..
196                 g_screen->pixels = calloc(g_screen->pitch * height, 1);
197
198         if (g_screen->pixels == NULL) {
199                 err("fb NULL");
200                 goto fail_pixels;
201         }
202         g_screen->hwdata = (void *)fbdev;
203
204         dbg("returning %p", g_screen);
205         return g_screen;
206
207 fail_pixels:
208         vout_fbdev_finish(fbdev);
209 fail_fbdev_init:
210         free(g_screen);
211         g_screen = NULL;
212         return NULL;
213 }
214
215 DECLSPEC int SDLCALL
216 SDL_Flip(SDL_Surface *screen)
217 {
218         struct vout_fbdev *fbdev;
219
220         trace("%p", screen);
221
222         if (screen != g_screen) {
223                 err("flip not on screen surface?");
224                 return -1;
225         }
226
227         if (screen->format->BitsPerPixel == 8) {
228                 int l = screen->pitch * screen->h;
229 #ifdef __arm__
230                 do_clut(g_screen_fbp, screen->pixels, g_8bpp_pal, l);
231 #else
232                 Uint16 *d = g_screen_fbp;
233                 Uint8 *s = screen->pixels;
234
235                 // XXX: perhaps optimize this sh*t
236                 for (; l > 0; d++, s++, l--)
237                         *d = g_8bpp_pal[*s];
238 #endif
239         }
240
241         fbdev = (void *)screen->hwdata;
242         g_screen_fbp = vout_fbdev_flip(fbdev);
243
244         if (screen->format->BitsPerPixel != 8)
245                 screen->pixels = g_screen_fbp;
246
247         return 0;
248 }
249
250 static int do_rect_clip(const SDL_Surface *s, SDL_Rect *r)
251 {
252         int x = r->x, y = r->y, w = r->w, h = r->h;
253
254         if (x < 0) {
255                 w += x;
256                 if (w < 0)
257                         w = 0;
258                 x = 0;
259         }
260         if (y < 0) {
261                 h += y;
262                 if (h < 0)
263                         h = 0;
264                 y = 0;
265         }
266         if (x + w > s->w) {
267                 w = s->w - x;
268                 if (w < 0)
269                         w = 0;
270         }
271         if (y + h > s->h) {
272                 h = s->h - y;
273                 if (h < 0)
274                         h = 0;
275         }
276
277         r->x = x; r->y = y; r->w = w; r->h = h;
278         return (w > 0 && h > 0) ? 0 : -1;
279 }
280
281 DECLSPEC int SDLCALL
282 SDL_UpperBlit(SDL_Surface *src, SDL_Rect *srcrect,
283                 SDL_Surface *dst, SDL_Rect *dstrect)
284 {
285         int sx = 0, sy = 0, sw, sh;
286         int dx = 0, dy = 0;
287         SDL_Rect tmprect = { 0, };
288
289         trace("%p, %p, %p, %p", src, srcrect, dst, dstrect);
290
291         if (src == NULL || dst == NULL)
292                 return -1;
293
294         if (srcrect != NULL) {
295                 // XXX: dst pos may need to be adjusted in some corner cases
296                 if (do_rect_clip(src, srcrect) < 0)
297                         return -1;
298                 sx = srcrect->x;
299                 sy = srcrect->y;
300                 sw = srcrect->w;
301                 sh = srcrect->h;
302         } else {
303                 sw = src->w;
304                 sh = src->h;
305         }
306
307         if (dstrect == NULL)
308                 dstrect = &tmprect;
309
310         // SDL just uses source w and h
311         dstrect->w = sw;
312         dstrect->h = sh;
313         if (do_rect_clip(dst, dstrect) < 0)
314                 return -1;
315         dx = dstrect->x;
316         dy = dstrect->y;
317         sw = dstrect->w;
318         sh = dstrect->h;
319
320         dbg("(%d %d %d %d) -> (%d %d %d %d)", sx, sy, sw, sh, dx, dy, sw, sh);
321
322         if (src->format->BitsPerPixel == dst->format->BitsPerPixel) {
323                 int Bpp = src->format->BytesPerPixel;
324                 int dpitch = dst->pitch;
325                 int spitch = src->pitch;
326                 Uint8 *d = (Uint8 *)dst->pixels + dpitch * dy + dx * Bpp;
327                 Uint8 *s = (Uint8 *)src->pixels + spitch * sy + sx * Bpp;
328
329                 for (sw *= Bpp; sh > 0; d += dpitch, s += spitch, sh--)
330                         memcpy(d, s, sw);
331         }
332         else
333                 not_supported();
334
335         return 0;
336 }
337
338 DECLSPEC SDL_Surface * SDLCALL
339 SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth,
340                      Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
341 {
342         SDL_Surface *ret;
343
344         trace("%08x, %d, %d, %d, %04x, %04x, %04x, %04x",
345                 flags, width, height, depth, Rmask, Gmask, Bmask, Amask);
346
347         ret = alloc_surface(width, height, depth);
348         if (ret == NULL)
349                 return NULL;
350
351         ret->pixels = calloc(ret->pitch * height, 1);
352         if (ret->pixels == NULL)
353                 goto fail;
354
355         dbg("returning %p", ret);
356         return ret;
357
358 fail:
359         free(ret);
360         return NULL;
361 }
362
363 DECLSPEC int SDLCALL
364 SDL_SetColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors)
365 {
366         int i, to;
367
368         trace("%p, %p, %d, %d", surface, colors, firstcolor, ncolors);
369
370         if (surface != g_screen)
371                 return 0;
372
373         to = min(ARRAY_SIZE(g_8bpp_pal), firstcolor + ncolors);
374         for (i = firstcolor; i < to; i++) {
375                 SDL_Color *c = &colors[i - firstcolor];
376                 int r = c->r, g = c->g, b = c->b;
377                 // noiz2sa gets a good deal darker that real SDL,
378                 // don't know what's going on there
379 /*
380                 if (r < 0xf8 && (r & 7) > 3) r += 8;
381                 if (g < 0xfc && (g & 3) > 1) g += 4;
382                 if (b < 0xf8 && (b & 7) > 3) b += 8;
383 */
384                 g_8bpp_pal[i] = ((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | (b >> 3);
385 //              g_8bpp_pal[i] += 0x0821;
386         }
387
388         return 0;
389 }
390
391 DECLSPEC int SDLCALL
392 SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
393 {
394         trace("%p, %p, %04x", dst, dstrect, color);
395
396         if (dst->format->BytesPerPixel != 1) {
397                 not_supported();
398                 return -1;
399         }
400         else
401                 memset(dst->pixels, color, dst->pitch * dst->h);
402
403         return 0;
404 }
405
406 /*
407 DECLSPEC SDL_Surface * SDLCALL
408 SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch,
409                          Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
410 {
411 }
412 */
413
414 DECLSPEC SDL_RWops * SDLCALL
415 SDL_RWFromFile(const char *file, const char *mode)
416 {
417         SDL_RWops *ret;
418         FILE *f;
419
420         trace("%s, %s", file, mode);
421
422         f = fopen(file, mode);
423         if (f == NULL)
424                 return NULL;
425
426         ret = calloc(1, sizeof(*ret));
427         if (ret == NULL) {
428                 fclose(f);
429                 return NULL;
430         }
431         ret->hidden.stdio.fp = f;
432
433         return ret;
434 }
435
436 DECLSPEC void SDLCALL
437 SDL_FreeRW(SDL_RWops *area)
438 {
439         if (area->hidden.stdio.fp) {
440                 fclose(area->hidden.stdio.fp);
441                 area->hidden.stdio.fp = NULL;
442         }
443         free(area);
444 }
445
446 DECLSPEC SDL_Surface * SDLCALL
447 SDL_LoadBMP_RW(SDL_RWops *src, int freesrc)
448 {
449         struct bmp_dib_v3 {
450                 unsigned char magic[2];
451                 uint32_t filesz;
452                 uint16_t creator1;
453                 uint16_t creator2;
454                 uint32_t bmp_offset;
455                 uint32_t header_sz;
456                 int32_t width;
457                 int32_t height;
458                 uint16_t nplanes;
459                 uint16_t bitspp;
460                 uint32_t compress_type;
461                 uint32_t bmp_bytesz;
462                 int32_t hres;
463                 int32_t vres;
464                 uint32_t ncolors;
465                 uint32_t nimpcolors;
466         } __attribute__((packed)) bmp;
467         SDL_Surface *ret = NULL;
468         int data_size, read_size;
469         uint8_t *tmp_buf = NULL;
470         int i, bytespp;
471         FILE *f;
472
473         trace("%p, %d", src, freesrc);
474
475         f = src->hidden.stdio.fp;
476         if (f == NULL)
477                 goto out;
478
479         if (fread(&bmp, 1, sizeof(bmp), f) != sizeof(bmp)) {
480                 err("bmp read error");
481                 goto out;
482         }
483
484         if (bmp.magic[0] != 'B' || bmp.magic[1] != 'M' || bmp.header_sz != 40) {
485                 err("unhandled BMP format, sz=%d", bmp.header_sz);
486                 goto out;
487         }
488
489         if ((unsigned)bmp.width > 0xffff || (unsigned)bmp.height > 0xffff) {
490                 err("BMP size %dx%d out of range", bmp.width, bmp.height);
491                 goto out;
492         }
493
494         if (bmp.bitspp != 4) {
495                 err("BMP unhandled bpp: %d", bmp.bitspp);
496                 goto out;
497         }
498
499         bytespp = bmp.bitspp < 8 ? 1 : (bmp.bitspp + 7) / 8;
500         data_size = bmp.width * bmp.height * bytespp;
501         tmp_buf = malloc(data_size);
502         if (tmp_buf == NULL)
503                 goto out;
504
505         if (fseek(f, bmp.bmp_offset, SEEK_SET) != 0) {
506                 err("BMP seek error");
507                 goto out;
508         }
509
510         read_size = bmp.width * bmp.bitspp / 8;
511         for (i = bmp.height - 1; i > 0; i--) {
512                 if (fread((char *)tmp_buf + i * read_size, 1, read_size, f) != read_size) {
513                         err("BMP read error");
514                         goto out;
515                 }
516         }
517
518         if (bmp.bitspp == 4) {
519                 // just convert to 8bpp now
520                 int c = bmp.width * bmp.height / 2;
521                 uint8_t *p = tmp_buf;
522                 for (i = c - 1; i >= 0; i--) {
523                         p[i * 2 + 1] = p[i] & 0xf;
524                         p[i * 2] = p[i] >> 4;
525                 }
526         }
527
528         ret = alloc_surface(bmp.width, bmp.height, 8);
529         if (ret == NULL)
530                 goto out;
531
532         ret->pixels = tmp_buf;
533         tmp_buf = NULL;
534
535 out:
536         if (tmp_buf != NULL)
537                 free(tmp_buf);
538         if (freesrc)
539                 SDL_FreeRW(src);
540
541         return ret;
542 }
543
544 DECLSPEC SDL_Surface * SDLCALL
545 SDL_ConvertSurface(SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags)
546 {
547         SDL_Surface *ret;
548         void *data;
549
550         trace("%p, %p, %08x", src, fmt, flags);
551
552         if (src->format->BitsPerPixel != fmt->BitsPerPixel) {
553                 err("convert: not implemented");
554                 return NULL;
555         }
556
557         data = malloc(src->pitch * src->h);
558         if (data == NULL)
559                 return NULL;
560         memcpy(data, src->pixels, src->pitch * src->h);
561
562         ret = alloc_surface(src->w, src->h, fmt->BitsPerPixel);
563         if (ret == NULL) {
564                 free(data);
565                 return NULL;
566         }
567         ret->pixels = data;
568         return ret;
569 }
570
571 DECLSPEC int SDLCALL
572 SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key)
573 {
574         trace("%p, %08x, %04x", surface, flag, key);
575         return 0;
576 }
577
578 DECLSPEC void SDLCALL
579 SDL_WM_SetCaption(const char *title, const char *icon)
580 {
581         trace("%s, %s", title, icon);
582 }
583
584 DECLSPEC int SDLCALL
585 SDL_ShowCursor(int toggle)
586 {
587         trace("%d", toggle);
588         return 0;
589 }
590
591 DECLSPEC char * SDLCALL
592 SDL_GetError(void)
593 {
594         trace("");
595
596         return "";
597 }
598