From c07813452c658f1f441b104fbe836380a6ddd18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sun, 4 Aug 2019 01:22:01 +0200 Subject: [PATCH 2/3] Port sdl-display to SDL2 The SDL2 Video API is split into several orthogonal parts, see https://wiki.libsdl.org/MigrationGuide#Video. Fixes half of #184 --- operations/common/display.c | 1 + operations/external/Makefile.am | 6 + operations/external/sdl2-display.c | 209 +++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 operations/external/sdl2-display.c diff --git a/operations/common/display.c b/operations/common/display.c index 826ae4caa..9e06f1eb5 100644 --- a/operations/common/display.c +++ b/operations/common/display.c @@ -60,6 +60,7 @@ set_display_handler (GeglOperation *operation) GeglOp *self = GEGL_OP (operation); const gchar *known_handlers[] = {"gegl-gtk3:display", "gegl-gtk2:display", + "gegl:sdl2-display", "gegl:sdl-display"}; char *handler = NULL; gchar **operations = NULL; diff --git a/operations/external/Makefile.am b/operations/external/Makefile.am index 498ffb062..719698401 100644 --- a/operations/external/Makefile.am +++ b/operations/external/Makefile.am @@ -81,6 +81,12 @@ exr_save_la_LIBADD = $(op_libs) $(OPENEXR_LIBS) exr_save_la_CXXFLAGS = $(AM_CFLAGS) $(OPENEXR_CFLAGS) endif +if HAVE_SDL2 +ops += sdl2-display.la +sdl2_display_la_LIBADD = $(op_libs) $(SDL2_LIBS) +sdl2_display_la_CFLAGS = $(AM_CFLAGS) $(SDL2_CFLAGS) +endif + if HAVE_SDL ops += sdl-display.la sdl_display_la_LIBADD = $(op_libs) $(SDL_LIBS) diff --git a/operations/external/sdl2-display.c b/operations/external/sdl2-display.c new file mode 100644 index 000000000..a3bab50a5 --- /dev/null +++ b/operations/external/sdl2-display.c @@ -0,0 +1,209 @@ +/* This file is an image processing operation for GEGL + * + * GEGL 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 3 of the License, or (at your option) any later version. + * + * GEGL 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 GEGL; if not, see . + * + * Copyright 2019 Stefan Brüns + * + * Based on sdl-display.c: + * Copyright 2006 Øyvind Kolås + */ + +#include "config.h" +#include + + +#ifdef GEGL_PROPERTIES + +property_string (window_title, _("Window title"), "window_title") + description (_("Title to be given to output window")) +#else + +#define GEGL_OP_SINK +#define GEGL_OP_NAME sdl2_display +#define GEGL_OP_C_SOURCE sdl2-display.c + +#include "gegl-op.h" +#include + +typedef struct { + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Texture *texture; + SDL_Surface *screen; + gint width; + gint height; +} SDLState; + +static void +init_sdl (void) +{ + static int inited = 0; + + if (!inited) + { + inited = 1; + + if (SDL_Init (SDL_INIT_VIDEO) < 0) + { + fprintf (stderr, "Unable to init SDL: %s\n", SDL_GetError ()); + return; + } + atexit (SDL_Quit); + } +} + +static gboolean idle (gpointer data) +{ + SDL_Event event; + while (SDL_PollEvent (&event)) + { + switch (event.type) + { + case SDL_QUIT: + exit (0); + } + } + return TRUE; +} + +static guint handle = 0; + +static gboolean +process (GeglOperation *operation, + GeglBuffer *input, + const GeglRectangle *result, + gint level) +{ + GeglProperties *o = GEGL_PROPERTIES (operation); + SDLState *state = NULL; + + if(!o->user_data) + o->user_data = g_new0 (SDLState, 1); + state = o->user_data; + + init_sdl (); + + if (!handle) + handle = g_timeout_add (500, idle, NULL); + + if (!state->window || + state->width != result->width || + state->height != result->height) + { + + if (state->window) + { + SDL_SetWindowSize (state->window, + result->width, result->height); + } + else + { + if (SDL_CreateWindowAndRenderer (result->width, + result->height, 0, + &state->window, &state->renderer)) + { + fprintf (stderr, "Unable to create window: %s\n", + SDL_GetError ()); + return -1; + } + } + + SDL_FreeSurface (state->screen); + state->screen = SDL_CreateRGBSurfaceWithFormat (0, + result->width, result->height, 32, SDL_PIXELFORMAT_RGBA32); + if (!state->screen) + { + fprintf (stderr, "Unable to create surface: %s\n", + SDL_GetError ()); + return -1; + } + + if (state->texture) + SDL_DestroyTexture (state->texture); + state->texture = SDL_CreateTextureFromSurface (state->renderer, state->screen); + if (!state->texture) + { + fprintf (stderr, "Unable to create texture: %s\n", + SDL_GetError ()); + return -1; + } + + state->width = result->width ; + state->height = result->height; + } + + /* + * There seems to be a valid faster path to the SDL desired display format + * in B'G'R'A, perhaps babl should have been able to figure this out ito? + * + */ + gegl_buffer_get (input, + NULL, + 1.0, + babl_format_new (babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("B'"), + babl_component ("G'"), + babl_component ("R'"), + babl_component ("A"), + NULL), + state->screen->pixels, GEGL_AUTO_ROWSTRIDE, + GEGL_ABYSS_NONE); + + SDL_UpdateTexture (state->texture, NULL, state->screen->pixels, state->screen->pitch); + + SDL_RenderClear (state->renderer); + SDL_RenderCopy (state->renderer, state->texture, NULL, NULL); + SDL_RenderPresent (state->renderer); + SDL_SetWindowTitle (state->window, o->window_title); + + return TRUE; +} + +static void +finalize (GObject *object) +{ + GeglProperties *o = GEGL_PROPERTIES (object); + + g_clear_pointer (&o->user_data, g_free); + + G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object); +} + +static void +gegl_op_class_init (GeglOpClass *klass) +{ + GObjectClass *object_class; + GeglOperationClass *operation_class; + GeglOperationSinkClass *sink_class; + + object_class = G_OBJECT_CLASS (klass); + operation_class = GEGL_OPERATION_CLASS (klass); + sink_class = GEGL_OPERATION_SINK_CLASS (klass); + + object_class->finalize = finalize; + + sink_class->process = process; + sink_class->needs_full = TRUE; + + gegl_operation_class_set_keys (operation_class, + "name", "gegl:sdl2-display", + "title", _("SDL2 Display"), + "categories", "display", + "description", + _("Displays the input buffer in an SDL2 window (restricted to one" + " display op/process, due to SDL2 implementation issues)."), + NULL); +} +#endif -- 2.22.0