Added .gitignore
[gfxprim.git] / backends / GP_Backend_SDL.c
blobaf746c1bc0759356c136d20ee5401c804caa36d8
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim 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 GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
20 * <jiri.bluebear.dluhos@gmail.com> *
21 * *
22 * Copyright (C) 2009-2010 Cyril Hrubis <metan@ucw.cz> *
23 * *
24 *****************************************************************************/
26 #include "GP.h"
27 #include "config.h"
29 #ifdef GP_HAVE_SDL
31 #include <dlfcn.h>
32 #include <SDL/SDL.h>
34 struct GP_Backend GP_SDL_backend;
35 static SDL_Surface *GP_SDL_display = NULL;
36 static GP_Context GP_SDL_context;
38 /* Functions from the SDL library, dynamically loaded in GP_SDL_InitFn(). */
39 static void (*dyn_SDL_Quit)(void);
40 static int (*dyn_SDL_Init)(int);
41 static SDL_Surface *(*dyn_SDL_SetVideoMode)(int, int, int, uint32_t);
42 static void (*dyn_SDL_UpdateRect)(SDL_Surface *, int, int, int, int);
43 static int (*dyn_SDL_WaitEvent)(SDL_Event *);
45 /* User callbacks. */
46 static void (*GP_SDL_update_video_callback)(void) = NULL;
48 /*
49 * Checks whether pixel color component masks in the given surface are equal
50 * to specified. Returns nonzero if they match, zero otherwise.
52 static int GP_SDL_CheckPixelMasks(SDL_Surface *surf, unsigned int rmask,
53 unsigned int gmask, unsigned int bmask, unsigned int amask)
55 return (surf->format->Rmask == rmask
56 && surf->format->Gmask == gmask
57 && surf->format->Bmask == bmask
58 && surf->format->Ashift == amask);
61 /*
62 * Detects the pixel type of the SDL surface.
63 * Returns the pixel type, or GP_PIXEL_UNKNOWN if the type was not recognized.
65 static enum GP_PixelType GP_SDL_FindSurfacePixelType(SDL_Surface *surf)
67 switch (surf->format->BytesPerPixel) {
68 case 1:
69 if (GP_SDL_CheckPixelMasks(surf, 0, 0, 0, 0)) {
70 return GP_PIXEL_PAL8;
72 break;
73 case 2:
74 if (GP_SDL_CheckPixelMasks(surf, 0x7c00, 0x03e0, 0x001f, 0)) {
75 return GP_PIXEL_RGB555;
77 if (GP_SDL_CheckPixelMasks(surf, 0xf800, 0x07e0, 0x001f, 0)) {
78 return GP_PIXEL_RGB565;
80 break;
81 case 3:
82 if (GP_SDL_CheckPixelMasks(surf, 0xff0000, 0xff00, 0xff, 0)) {
83 return GP_PIXEL_RGB888;
85 if (GP_SDL_CheckPixelMasks(surf, 0xff, 0xff00, 0xff0000, 0)) {
86 return GP_PIXEL_BGR888;
88 break;
89 case 4:
90 if (GP_SDL_CheckPixelMasks(surf, 0xff0000, 0xff00, 0xff, 0)) {
91 return GP_PIXEL_XRGB8888;
93 if (GP_SDL_CheckPixelMasks(surf, 0xff, 0xff00, 0xff0000, 0)) {
94 return GP_PIXEL_XBGR8888;
96 if (GP_SDL_CheckPixelMasks(surf, 0xff000000, 0xff0000, 0xff00, 0)) {
97 return GP_PIXEL_RGBX8888;
99 if (GP_SDL_CheckPixelMasks(surf, 0xff00, 0xff0000, 0xff000000, 0)) {
100 return GP_PIXEL_BGRX8888;
102 if (GP_SDL_CheckPixelMasks(surf, 0xff0000, 0xff00, 0xff, 0xff000000)) {
103 return GP_PIXEL_ARGB8888;
105 if (GP_SDL_CheckPixelMasks(surf, 0xff, 0xff00, 0xff0000, 0xff000000)) {
106 return GP_PIXEL_ABGR8888;
108 if (GP_SDL_CheckPixelMasks(surf, 0xff000000, 0xff0000, 0xff00, 0xff)) {
109 return GP_PIXEL_RGBA8888;
111 if (GP_SDL_CheckPixelMasks(surf, 0xff00, 0xff0000, 0xff000000, 0xff)) {
112 return GP_PIXEL_BGRA8888;
114 break;
117 return GP_PIXEL_UNKNOWN;
120 inline GP_RetCode GP_SDL_ContextFromSurface(
121 GP_Context *context, SDL_Surface *surf)
123 GP_CHECK(context, "context is NULL");
124 GP_CHECK(surf, "surface is NULL");
126 /* sanity checks on the SDL surface */
127 if (surf->format->BytesPerPixel == 0 || surf->format->BytesPerPixel > 4) {
128 return GP_ENOIMPL;
130 enum GP_PixelType pixeltype = GP_SDL_FindSurfacePixelType(surf);
131 if (pixeltype == GP_PIXEL_UNKNOWN) {
132 return GP_ENOIMPL;
135 /* basic structure and size */
136 context->pixels = surf->pixels;
137 context->bpp = 8 * surf->format->BytesPerPixel;
138 context->pixel_type = pixeltype;
139 context->bytes_per_row = surf->pitch;
140 context->w = surf->w;
141 context->h = surf->h;
143 /* orientation */
144 context->axes_swap = 0;
145 context->x_swap = 0;
146 context->y_swap = 0;
148 /* clipping */
149 context->clip_h_min = surf->clip_rect.y;
150 context->clip_h_max = surf->clip_rect.y + surf->clip_rect.h - 1;
151 context->clip_w_min = surf->clip_rect.x;
152 context->clip_w_max = surf->clip_rect.x + surf->clip_rect.w - 1;
154 return GP_ESUCCESS;
157 static void GP_SDL_ShutdownFn(void)
159 dyn_SDL_Quit();
162 static struct GP_Backend *GP_SDL_InitFn(void)
164 void *library = dlopen("libSDL.so", RTLD_LAZY);
165 if (!library)
166 return NULL;
168 dyn_SDL_Init = dlsym(library, "SDL_Init");
169 dyn_SDL_Quit = dlsym(library, "SDL_Quit");
170 dyn_SDL_UpdateRect = dlsym(library, "SDL_UpdateRect");
171 dyn_SDL_SetVideoMode = dlsym(library, "SDL_SetVideoMode");
172 dyn_SDL_WaitEvent = dlsym(library, "SDL_WaitEvent");
174 if (dyn_SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0)
175 return NULL;
177 return &GP_SDL_backend;
180 static GP_Context *GP_SDL_OpenVideoFn(int w, int h, int flags)
182 GP_SDL_display = dyn_SDL_SetVideoMode(w, h, 0,
183 SDL_SWSURFACE|SDL_DOUBLEBUF);
185 if (GP_SDL_display == NULL)
186 return NULL;
188 GP_RetCode retcode = GP_SDL_ContextFromSurface(
189 &GP_SDL_context, GP_SDL_display);
190 if (retcode != GP_ESUCCESS)
191 return NULL;
193 return &GP_SDL_context;
196 static GP_Context *GP_SDL_VideoContextFn(void)
198 return &GP_SDL_context;
201 static void GP_SDL_UpdateVideoFn(void)
203 dyn_SDL_UpdateRect(GP_SDL_display, 0, 0,
204 GP_SDL_display->w, GP_SDL_display->h);
207 static int GP_SDL_GetEventFn(struct GP_BackendEvent *event)
209 SDL_Event sdl_event;
211 if (dyn_SDL_WaitEvent(&sdl_event) == 0)
212 return 0;
214 switch (sdl_event.type) {
215 case SDL_VIDEOEXPOSE:
216 event->type = GP_BACKEND_EVENT_UPDATE_VIDEO;
217 return 1;
218 case SDL_QUIT:
219 event->type = GP_BACKEND_EVENT_QUIT_REQUEST;
220 return 1;
223 /* for the time being, unknown events are simply ignored */
224 return 0;
227 struct GP_Backend GP_SDL_backend = {
228 .name = "SDL",
229 .init_fn = GP_SDL_InitFn,
230 .shutdown_fn = GP_SDL_ShutdownFn,
231 .open_video_fn = GP_SDL_OpenVideoFn,
232 .video_context_fn = GP_SDL_VideoContextFn,
233 .update_video_fn = GP_SDL_UpdateVideoFn,
234 .get_event_fn = GP_SDL_GetEventFn,
237 #endif /* GP_HAVE_SDL */