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