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