diff --git a/cogl/Makefile.am b/cogl/Makefile.am index a99ccd8e7..d77849753 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -449,9 +449,11 @@ cogl_sources_c += \ $(srcdir)/winsys/cogl-winsys-egl-private.h endif if SUPPORT_SDL +cogl_experimental_h += $(srcdir)/cogl-sdl.h cogl_sources_c += \ $(srcdir)/winsys/cogl-winsys-sdl-private.h \ - $(srcdir)/winsys/cogl-winsys-sdl.c + $(srcdir)/winsys/cogl-winsys-sdl.c \ + $(srcdir)/cogl-sdl.c endif EXTRA_DIST += stb_image.c diff --git a/cogl/cogl-renderer-private.h b/cogl/cogl-renderer-private.h index 11dc0bb07..0d119cb81 100644 --- a/cogl/cogl-renderer-private.h +++ b/cogl/cogl-renderer-private.h @@ -62,6 +62,12 @@ struct _CoglRenderer struct wl_compositor *foreign_wayland_compositor; struct wl_shell *foreign_wayland_shell; #endif + +#ifdef COGL_HAS_SDL_SUPPORT + gboolean sdl_event_type_set; + guint8 sdl_event_type; +#endif + /* List of callback functions that will be given every native event */ GSList *event_filters; void *winsys; diff --git a/cogl/cogl-sdl.c b/cogl/cogl-sdl.c new file mode 100644 index 000000000..97795932c --- /dev/null +++ b/cogl/cogl-sdl.c @@ -0,0 +1,85 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2012 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl-sdl.h" +#include "cogl-context-private.h" +#include "cogl-renderer-private.h" + +void +cogl_sdl_renderer_set_event_type (CoglRenderer *renderer, guint8 type) +{ + renderer->sdl_event_type_set = TRUE; + renderer->sdl_event_type = type; +} + +guint8 +cogl_sdl_renderer_get_event_type (CoglRenderer *renderer) +{ + _COGL_RETURN_VAL_IF_FAIL (renderer->sdl_event_type_set, SDL_USEREVENT); + + return renderer->sdl_event_type; +} + +CoglContext * +cogl_sdl_context_new (guint8 type, GError **error) +{ + CoglRenderer *renderer = cogl_renderer_new (); + CoglDisplay *display; + + cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_SDL); + + cogl_sdl_renderer_set_event_type (renderer, type); + + if (!cogl_renderer_connect (renderer, error)) + return NULL; + + display = cogl_display_new (renderer, NULL); + if (!cogl_display_setup (display, error)) + return NULL; + + return cogl_context_new (display, error); +} + +void +cogl_sdl_handle_event (CoglContext *context, SDL_Event *event) +{ + const CoglWinsysVtable *winsys; + + _COGL_RETURN_IF_FAIL (cogl_is_context (context)); + + winsys = _cogl_context_get_winsys (context); + + if (winsys->poll_dispatch) + winsys->poll_dispatch (context, NULL, 0); +} + +void +cogl_sdl_idle (CoglContext *context) +{ + /* NOP since Cogl doesn't currently need to do anything when idle */ +} diff --git a/cogl/cogl-sdl.h b/cogl/cogl-sdl.h new file mode 100644 index 000000000..6f33be6f7 --- /dev/null +++ b/cogl/cogl-sdl.h @@ -0,0 +1,198 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2012 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __COGL_SDL_H__ +#define __COGL_SDL_H__ + +#include +#include + +G_BEGIN_DECLS + +/** + * SECTION:cogl-sdl + * @short_description: Integration api for the Simple DirectMedia + * Layer library. + * + * Cogl is a portable graphics api that can either be used standalone + * or alternatively integrated with certain existing frameworks. This + * api enables Cogl to be used in conjunction with the Simple + * DirectMedia Layer library. + * + * Using this API a typical SDL application would look something like + * this: + * |[ + * MyAppData data; + * GError *error = NULL; + * + * data.ctx = cogl_sdl_context_new (NULL, SDL_USEREVENT, &error); + * if (!data.ctx) + * { + * fprintf (stderr, "Failed to create context: %s\n", + * error->message); + * return 1; + * } + * + * my_application_setup (&data); + * + * data.redraw_queued = TRUE; + * while (!data.quit) + * { + * while (!data.quit) + * { + * if (!SDL_PollEvent (&event)) + * { + * if (data.redraw_queued) + * break; + * + * cogl_sdl_idle (ctx); + * if (!SDL_WaitEvent (&event)) + * { + * fprintf (stderr, "Error waiting for SDL events"); + * return 1; + * } + * } + * + * handle_event (&data, &event); + * cogl_sdl_handle_event (ctx, &event); + * } + * + * data.redraw_queued = redraw (&data); + * } + * ]| + */ + +/** + * cogl_sdl_context_new: + * @type: An SDL user event type between %SDL_USEREVENT and + * %SDL_NUMEVENTS - %1 + * @error: A GError return location. + * + * This is a convenience function for creating a new #CoglContext for + * use with SDL and specifying what SDL user event type Cogl can use + * as a way to interrupt SDL_WaitEvent(). + * + * This function is equivalent to the following code: + * |[ + * CoglRenderer *renderer = cogl_renderer_new (); + * CoglDisplay *display; + * + * cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_SDL); + * + * cogl_sdl_renderer_set_event_type (renderer, type); + * + * if (!cogl_renderer_connect (renderer, error)) + * return NULL; + * + * display = cogl_display_new (renderer, NULL); + * if (!cogl_display_setup (display, error)) + * return NULL; + * + * return cogl_context_new (display, error); + * ]| + * + * SDL applications are required to either use this API or + * to manually create a #CoglRenderer and call + * cogl_sdl_renderer_set_event_type(). + * + * Since: 2.0 + * Stability: unstable + */ +CoglContext * +cogl_sdl_context_new (guint8 type, GError **error); + +/** + * cogl_sdl_renderer_set_event_type: + * @renderer: A #CoglRenderer + * @type: An SDL user event type between %SDL_USEREVENT and + * %SDL_NUMEVENTS - %1 + * + * Tells Cogl what SDL user event type it can use as a way to + * interrupt SDL_WaitEvent() to ensure that cogl_sdl_handle_event() + * will be called in a finite amount of time. + * + * This should only be called on an un-connected + * @renderer. + * + * For convenience most simple applications can use + * cogl_sdl_context_new() if they don't want to manually create + * #CoglRenderer and #CoglDisplay objects during + * initialization. + * + * Since: 2.0 + * Stability: unstable + */ +void +cogl_sdl_renderer_set_event_type (CoglRenderer *renderer, guint8 type); + +/** + * cogl_sdl_renderer_get_event_type: + * @renderer: A #CoglRenderer + * + * Queries what SDL user event type Cogl is using as a way to + * interrupt SDL_WaitEvent(). This is set either using + * cogl_sdl_context_new or by using + * cogl_sdl_renderer_set_event_type(). + * + * Since: 2.0 + * Stability: unstable + */ +guint8 +cogl_sdl_renderer_get_event_type (CoglRenderer *renderer); + +/** + * cogl_sdl_handle_event: + * @context: A #CoglContext + * @event: An SDL event + * + * Passes control to Cogl so that it may dispatch any internal event + * callbacks in response to the given SDL @event. This function must + * be called for every SDL event. + * + * Since: 2.0 + * Stability: unstable + */ +void +cogl_sdl_handle_event (CoglContext *context, SDL_Event *event); + +/** + * cogl_sdl_idle: + * @context: A #CoglContext + * + * Notifies Cogl that the application is idle and about to call + * SDL_WaitEvent(). Cogl may use this to run low priority book keeping + * tasks. + * + * Since: 2.0 + * Stability: unstable + */ +void +cogl_sdl_idle (CoglContext *context); + +G_END_DECLS + +#endif /* __COGL_SDL_H__ */ diff --git a/cogl/cogl.h b/cogl/cogl.h index 3f1eb5303..0e3c7b6fb 100644 --- a/cogl/cogl.h +++ b/cogl/cogl.h @@ -117,6 +117,9 @@ * code has been migrated down into Cogl! */ #include #endif +#ifdef COGL_HAS_SDL_SUPPORT +#include +#endif /* * 2.0 only api... diff --git a/cogl/winsys/cogl-winsys-sdl.c b/cogl/winsys/cogl-winsys-sdl.c index deda04520..04fa636a4 100644 --- a/cogl/winsys/cogl-winsys-sdl.c +++ b/cogl/winsys/cogl-winsys-sdl.c @@ -159,6 +159,12 @@ error: static gboolean _cogl_winsys_context_init (CoglContext *context, GError **error) { + CoglRenderer *renderer = context->display->renderer; + + if (G_UNLIKELY (renderer->sdl_event_type_set == FALSE)) + g_error ("cogl_sdl_renderer_set_event_type() or cogl_sdl_context_new() " + "must be called during initialization"); + return _cogl_context_update_features (context, error); } diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in index 92a47b61f..6c9b91ce6 100644 --- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in +++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in @@ -18,6 +18,7 @@ 2009 2010 2011 + 2012 Intel Corporation @@ -130,6 +131,7 @@
Binding and Integrating +
diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt index a3852bc52..ade861d62 100644 --- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt +++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt @@ -777,3 +777,13 @@ CoglColorMask GType Integration API cogl_gtype_matrix_get_type + +
+SDL +SDL Integration +cogl_sdl_context_new +cogl_sdl_renderer_set_event_type +cogl_sdl_renderer_get_event_type +cogl_sdl_handle_event +cogl_sdl_idle +
diff --git a/examples/cogl-sdl-hello.c b/examples/cogl-sdl-hello.c index 8643c38f6..65e4fee7e 100644 --- a/examples/cogl-sdl-hello.c +++ b/examples/cogl-sdl-hello.c @@ -13,9 +13,10 @@ typedef struct Data float center_x, center_y; CoglFramebuffer *fb; gboolean quit; + gboolean redraw_queued; } Data; -static void +static gboolean redraw (Data *data) { CoglFramebuffer *fb = data->fb; @@ -29,6 +30,8 @@ redraw (Data *data) cogl_framebuffer_pop_matrix (fb); cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb)); + + return FALSE; } static void @@ -37,7 +40,7 @@ handle_event (Data *data, SDL_Event *event) switch (event->type) { case SDL_VIDEOEXPOSE: - redraw (data); + data->redraw_queued = TRUE; break; case SDL_MOUSEMOTION: @@ -50,7 +53,7 @@ handle_event (Data *data, SDL_Event *event) data->center_x = event->motion.x * 2.0f / width - 1.0f; data->center_y = event->motion.y * 2.0f / height - 1.0f; - redraw (data); + data->redraw_queued = TRUE; } break; @@ -60,61 +63,9 @@ handle_event (Data *data, SDL_Event *event) } } -static Uint32 -timer_handler (Uint32 interval, void *user_data) -{ - static const SDL_UserEvent dummy_event = - { - SDL_USEREVENT - }; - - /* Post an event to wake up from SDL_WaitEvent */ - SDL_PushEvent ((SDL_Event *) &dummy_event); - - return 0; -} - -static gboolean -wait_event_with_timeout (Data *data, SDL_Event *event, gint64 timeout) -{ - if (timeout == -1) - { - if (SDL_WaitEvent (event)) - return TRUE; - else - { - data->quit = TRUE; - return FALSE; - } - } - else if (timeout == 0) - return SDL_PollEvent (event); - else - { - gboolean ret; - /* Add a timer so that we can wake up the event loop */ - SDL_TimerID timer_id = - SDL_AddTimer (timeout / 1000, timer_handler, data); - - if (SDL_WaitEvent (event)) - ret = TRUE; - else - { - data->quit = TRUE; - ret = FALSE; - } - - SDL_RemoveTimer (timer_id); - - return ret; - } -} - int main (int argc, char **argv) { - CoglRenderer *renderer; - CoglDisplay *display; CoglContext *ctx; CoglOnscreen *onscreen; GError *error = NULL; @@ -126,19 +77,13 @@ main (int argc, char **argv) Data data; SDL_Event event; - /* Force the SDL winsys */ - renderer = cogl_renderer_new (); - cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_SDL); - display = cogl_display_new (renderer, NULL); - ctx = cogl_context_new (display, &error); + ctx = cogl_sdl_context_new (SDL_USEREVENT, &error); if (!ctx) { fprintf (stderr, "Failed to create context: %s\n", error->message); return 1; } - SDL_InitSubSystem (SDL_INIT_TIMER); - onscreen = cogl_onscreen_new (ctx, 800, 600); data.fb = COGL_FRAMEBUFFER (onscreen); @@ -151,31 +96,33 @@ main (int argc, char **argv) data.triangle = cogl_primitive_new_p2c4 (ctx, COGL_VERTICES_MODE_TRIANGLES, 3, triangle_vertices); data.pipeline = cogl_pipeline_new (ctx); + + data.redraw_queued = TRUE; while (!data.quit) { - CoglPollFD *poll_fds; - int n_poll_fds; - gint64 timeout; + while (!data.quit) + { + if (!SDL_PollEvent (&event)) + { + if (data.redraw_queued) + break; - cogl_poll_get_info (ctx, &poll_fds, &n_poll_fds, &timeout); + cogl_sdl_idle (ctx); + if (!SDL_WaitEvent (&event)) + { + fprintf (stderr, "Error waiting for SDL events"); + return 1; + } + } - /* It's difficult to wait for file descriptors using the SDL - event mechanism, but it the SDL winsys is documented that it - will never require this so we can assert that there are no - fds */ - g_assert (n_poll_fds == 0); - - if (wait_event_with_timeout (&data, &event, timeout)) - do handle_event (&data, &event); - while (SDL_PollEvent (&event)); + cogl_sdl_handle_event (ctx, &event); + } - cogl_poll_dispatch (ctx, poll_fds, n_poll_fds); + data.redraw_queued = redraw (&data); } cogl_object_unref (ctx); - cogl_object_unref (display); - cogl_object_unref (renderer); return 0; }