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