1 /*****************************************************************************
2 * This file is part of gfxprim library. *
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. *
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. *
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 *
19 * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
20 * <jiri.bluebear.dluhos@gmail.com> *
22 * Copyright (C) 2009-2010 Cyril Hrubis <metan@ucw.cz> *
24 *****************************************************************************/
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
*);
46 static void (*GP_SDL_update_video_callback
)(void) = NULL
;
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
);
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
) {
69 if (GP_SDL_CheckPixelMasks(surf
, 0, 0, 0, 0)) {
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
;
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
;
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
;
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) {
130 enum GP_PixelType pixeltype
= GP_SDL_FindSurfacePixelType(surf
);
131 if (pixeltype
== GP_PIXEL_UNKNOWN
) {
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
;
144 context
->axes_swap
= 0;
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;
157 static void GP_SDL_ShutdownFn(void)
162 static struct GP_Backend
*GP_SDL_InitFn(void)
164 void *library
= dlopen("libSDL.so", RTLD_LAZY
);
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)
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
)
188 GP_RetCode retcode
= GP_SDL_ContextFromSurface(
189 &GP_SDL_context
, GP_SDL_display
);
190 if (retcode
!= GP_ESUCCESS
)
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
)
211 if (dyn_SDL_WaitEvent(&sdl_event
) == 0)
214 switch (sdl_event
.type
) {
215 case SDL_VIDEOEXPOSE
:
216 event
->type
= GP_BACKEND_EVENT_UPDATE_VIDEO
;
219 event
->type
= GP_BACKEND_EVENT_QUIT_REQUEST
;
223 /* for the time being, unknown events are simply ignored */
227 struct GP_Backend GP_SDL_backend
= {
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 */