aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile8
-rw-r--r--layer.cpp70
-rw-r--r--layer.h76
-rw-r--r--layer_box.cpp29
-rw-r--r--layer_box.h37
-rw-r--r--layer_image.cpp157
-rw-r--r--layer_image.h54
-rw-r--r--layer_video.cpp232
-rw-r--r--layer_video.h57
-rw-r--r--main.cpp860
-rw-r--r--osc_graphics.h41
11 files changed, 852 insertions, 769 deletions
diff --git a/Makefile b/Makefile
index ed8c08f..30fa973 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
PREFIX := /usr/local
+CXX := g++
CC := gcc
SDL_CFLAGS := $(shell sdl-config --cflags)
@@ -18,17 +19,18 @@ LIBLO_CFLAGS := $(shell pkg-config liblo --cflags)
LIBLO_LDFLAGS := $(shell pkg-config liblo --libs)
CFLAGS ?= -g -O0
-CFLAGS += -std=c99 -Wall \
+CFLAGS += -Wall \
$(SDL_CFLAGS) $(SDL_IMAGE_CFLAGS) $(SDL_GFX_CFLAGS) \
$(LIBVLC_CFLAGS) $(LIBLO_CFLAGS)
+CXXFLAGS := $(CFLAGS)
LDFLAGS := -lm \
$(SDL_LDFLAGS) $(SDL_IMAGE_LDFLAGS) $(SDL_GFX_LDFLAGS) \
$(LIBVLC_LDFLAGS) $(LIBLO_LDFLAGS)
all : osc-graphics
-osc-graphics : main.o
- $(CC) $(LDFLAGS) $^ -o $@
+osc-graphics : main.o layer.o layer_box.o layer_image.o layer_video.o
+ $(CXX) $(LDFLAGS) $^ -o $@
install : all
cp osc-graphics $(PREFIX)/bin
diff --git a/layer.cpp b/layer.cpp
new file mode 100644
index 0000000..89f437f
--- /dev/null
+++ b/layer.cpp
@@ -0,0 +1,70 @@
+#include <string.h>
+
+#include <SDL.h>
+
+#include "osc_graphics.h"
+#include "layer.h"
+
+#define FOREACH_LAYER(VAR) \
+ for (Layer *VAR = head; VAR; VAR = VAR->next)
+
+void
+LayerList::insert(int pos, Layer *layer)
+{
+ Layer *cur, *prev = NULL;
+
+ lock();
+
+ for (cur = head; cur && pos; prev = cur, cur = cur->next, pos--);
+
+ layer->next = cur;
+ if (prev)
+ prev->next = layer;
+ else
+ head = layer;
+
+ unlock();
+}
+
+bool
+LayerList::delete_by_name(const char *name)
+{
+ Layer *prev = NULL;
+
+ lock();
+
+ FOREACH_LAYER(cur) {
+ if (!strcmp(cur->name, name)) {
+ if (prev)
+ prev->next = cur->next;
+ else
+ head = cur->next;
+ delete cur;
+
+ unlock();
+ return false;
+ }
+
+ prev = cur;
+ }
+
+ unlock();
+
+ return true;
+}
+
+void
+LayerList::render(SDL_Surface *target)
+{
+ SDL_FillRect(target, NULL, SDL_MapRGB(target->format, 0, 0, 0));
+
+ lock();
+
+ FOREACH_LAYER(cur) {
+ cur->lock();
+ cur->frame(target);
+ cur->unlock();
+ }
+
+ unlock();
+}
diff --git a/layer.h b/layer.h
new file mode 100644
index 0000000..ce9a417
--- /dev/null
+++ b/layer.h
@@ -0,0 +1,76 @@
+#ifndef __HAVE_LAYER_H
+#define __HAVE_LAYER_H
+
+#include <string.h>
+
+#include <SDL.h>
+#include <SDL_thread.h>
+
+class Layer {
+ SDL_mutex *mutex;
+
+public:
+ Layer *next;
+
+ char *name;
+
+ Layer(const char *name)
+ {
+ mutex = SDL_CreateMutex();
+ Layer::name = strdup(name);
+ }
+ ~Layer()
+ {
+ free(name);
+ SDL_DestroyMutex(mutex);
+ }
+
+ inline void
+ lock()
+ {
+ SDL_LockMutex(mutex);
+ }
+ inline void
+ unlock()
+ {
+ SDL_UnlockMutex(mutex);
+ }
+
+ virtual void geo(SDL_Rect geo) = 0;
+ virtual void alpha(float opacity) = 0;
+
+ virtual void frame(SDL_Surface *target) = 0;
+};
+
+class LayerList {
+ Layer *head;
+
+ SDL_mutex *mutex;
+
+ inline void
+ lock()
+ {
+ SDL_LockMutex(mutex);
+ }
+ inline void
+ unlock()
+ {
+ SDL_UnlockMutex(mutex);
+ }
+
+public:
+ LayerList() : head(NULL)
+ {
+ mutex = SDL_CreateMutex();
+ }
+ ~LayerList()
+ {
+ SDL_DestroyMutex(mutex);
+ }
+
+ void insert(int pos, Layer *layer);
+ bool delete_by_name(const char *name);
+ void render(SDL_Surface *target);
+};
+
+#endif \ No newline at end of file
diff --git a/layer_box.cpp b/layer_box.cpp
new file mode 100644
index 0000000..d229833
--- /dev/null
+++ b/layer_box.cpp
@@ -0,0 +1,29 @@
+#include <math.h>
+
+#include <SDL.h>
+#include <SDL_gfxPrimitives.h>
+
+#include "osc_graphics.h"
+#include "layer_box.h"
+
+void
+LayerBox::geo(SDL_Rect geo)
+{
+ x1 = geo.x;
+ y1 = geo.y;
+ x2 = geo.x + geo.w;
+ y2 = geo.y + geo.h;
+}
+
+void
+LayerBox::alpha(float opacity)
+{
+ a = (Uint8)ceilf(opacity*SDL_ALPHA_OPAQUE);
+}
+
+void
+LayerBox::frame(SDL_Surface *target)
+{
+ boxRGBA(target, x1, y1, x2 ? : target->w, y2 ? : target->h,
+ r, g, b, a);
+}
diff --git a/layer_box.h b/layer_box.h
new file mode 100644
index 0000000..f6f6667
--- /dev/null
+++ b/layer_box.h
@@ -0,0 +1,37 @@
+#ifndef __HAVE_LAYER_BOX_H
+#define __HAVE_LAYER_BOX_H
+
+#include <SDL.h>
+
+#include "osc_graphics.h"
+#include "layer.h"
+
+class LayerBox : public Layer {
+ Sint16 x1, y1, x2, y2;
+ Uint8 r, g, b, a;
+
+public:
+ LayerBox(const char *name, SDL_Rect geo, float opacity,
+ SDL_Color color) : Layer(name)
+ {
+ LayerBox::geo(geo);
+ LayerBox::color(color);
+ LayerBox::alpha(opacity);
+ }
+
+ void geo(SDL_Rect geo);
+ void alpha(float opacity);
+
+ void
+ color(SDL_Color color)
+ {
+ r = color.r;
+ g = color.g;
+ b = color.b;
+ }
+
+
+ void frame(SDL_Surface *target);
+};
+
+#endif \ No newline at end of file
diff --git a/layer_image.cpp b/layer_image.cpp
new file mode 100644
index 0000000..11079be
--- /dev/null
+++ b/layer_image.cpp
@@ -0,0 +1,157 @@
+#include <math.h>
+
+#include <SDL.h>
+#include <SDL_image.h>
+#include <SDL_rotozoom.h>
+#include <SDL_gfxBlitFunc.h>
+
+#include "osc_graphics.h"
+#include "layer_image.h"
+
+#if 0
+
+static inline void
+rgba_blit_with_alpha(SDL_Surface *src_surf, SDL_Surface *dst_surf, Uint8 alpha)
+{
+ SDL_FillRect(dst_surf, NULL,
+ SDL_MapRGBA(dst_surf->format,
+ 0, 0, 0, SDL_ALPHA_TRANSPARENT));
+ SDL_gfxBlitRGBA(src_surf, NULL, dst_surf, NULL);
+ SDL_gfxMultiplyAlpha(dst_surf, alpha);
+}
+
+#else
+
+static inline void
+rgba_blit_with_alpha(SDL_Surface *src_surf, SDL_Surface *dst_surf, Uint8 alpha)
+{
+ Uint8 *src = (Uint8 *)src_surf->pixels;
+ Uint8 *dst = (Uint8 *)dst_surf->pixels;
+ SDL_PixelFormat *fmt = src_surf->format;
+
+ int inc = fmt->BytesPerPixel;
+ int len = src_surf->w * src_surf->h;
+
+ SDL_MAYBE_LOCK(src_surf);
+ SDL_MAYBE_LOCK(dst_surf);
+
+ GFX_DUFFS_LOOP4({
+ register Uint32 pixel;
+ register int a;
+
+ pixel = *(Uint32 *)src;
+ a = ((pixel & fmt->Amask) >> fmt->Ashift) << fmt->Aloss;
+ a = (a*alpha)/SDL_ALPHA_OPAQUE;
+ a = (a << fmt->Aloss) << fmt->Ashift;
+ pixel &= ~fmt->Amask;
+ pixel |= a;
+ *(Uint32 *)dst = pixel;
+
+ src += inc;
+ dst += inc;
+ }, len)
+
+ SDL_MAYBE_UNLOCK(dst_surf);
+ SDL_MAYBE_UNLOCK(src_surf);
+}
+
+#endif
+
+void
+LayerImage::geo(SDL_Rect geo)
+{
+ if (!geo.x && !geo.y && !geo.w && !geo.h)
+ geov = (SDL_Rect){0, 0, screen->w, screen->h};
+ else
+ geov = geo;
+
+ if (!surf)
+ return;
+
+ if (surf_scaled &&
+ surf_scaled->w == geov.w && surf_scaled->h == geov.h)
+ return;
+
+ SDL_FREESURFACE_SAFE(surf_alpha);
+ SDL_FREESURFACE_SAFE(surf_scaled);
+
+ if (surf->w != geov.w || surf->h != geov.h) {
+ surf_scaled = zoomSurface(surf,
+ (double)geov.w/surf->w,
+ (double)geov.h/surf->h,
+ SMOOTHING_ON);
+ }
+
+ alpha(alphav);
+}
+
+void
+LayerImage::alpha(float opacity)
+{
+ SDL_Surface *use_surf = surf_scaled ? : surf;
+ Uint8 alpha = (Uint8)ceilf(opacity*SDL_ALPHA_OPAQUE);
+
+ alphav = opacity;
+
+ if (!use_surf)
+ return;
+
+ if (!use_surf->format->Amask) {
+ if (alpha == SDL_ALPHA_OPAQUE)
+ SDL_SetAlpha(use_surf, 0, 0);
+ else
+ SDL_SetAlpha(use_surf, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
+
+ return;
+ }
+
+ if (alpha == SDL_ALPHA_OPAQUE) {
+ SDL_FREESURFACE_SAFE(surf_alpha);
+ return;
+ }
+
+ if (!surf_alpha) {
+ surf_alpha = SDL_CreateRGBSurface(use_surf->flags,
+ use_surf->w, use_surf->h,
+ use_surf->format->BitsPerPixel,
+ use_surf->format->Rmask,
+ use_surf->format->Gmask,
+ use_surf->format->Bmask,
+ use_surf->format->Amask);
+ }
+
+ if (alpha == SDL_ALPHA_TRANSPARENT) {
+ SDL_FillRect(surf_alpha, NULL,
+ SDL_MapRGBA(surf_alpha->format,
+ 0, 0, 0, SDL_ALPHA_TRANSPARENT));
+ } else {
+ rgba_blit_with_alpha(use_surf, surf_alpha, alpha);
+ }
+}
+
+void
+LayerImage::file(const char *file)
+{
+ SDL_FREESURFACE_SAFE(surf_alpha);
+ SDL_FREESURFACE_SAFE(surf_scaled);
+ SDL_FREESURFACE_SAFE(surf);
+
+ if (!file || !*file)
+ return;
+
+ surf = IMG_Load(file);
+ if (!surf) {
+ SDL_IMAGE_ERROR("IMG_Load");
+ exit(EXIT_FAILURE);
+ }
+
+ geo(geov);
+}
+
+void
+LayerImage::frame(SDL_Surface *target)
+{
+ if (surf)
+ SDL_BlitSurface(surf_alpha ? : surf_scaled ? : surf, NULL,
+ target, &geov);
+}
diff --git a/layer_image.h b/layer_image.h
new file mode 100644
index 0000000..7f51885
--- /dev/null
+++ b/layer_image.h
@@ -0,0 +1,54 @@
+#ifndef __HAVE_LAYER_IMAGE_H
+#define __HAVE_LAYER_IMAGE_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <SDL.h>
+
+#include "osc_graphics.h"
+#include "layer.h"
+
+class LayerImage : public Layer {
+ SDL_Surface *surf_alpha; /* with per-surface alpha */
+ SDL_Surface *surf_scaled; /* scaled image */
+ SDL_Surface *surf; /* original image */
+
+ SDL_Rect geov;
+ float alphav;
+
+public:
+ LayerImage(const char *name,
+ SDL_Rect geo = (SDL_Rect){0, 0, 0, 0},
+ float opacity = 1.,
+ const char *file = NULL) : Layer(name), surf_alpha(NULL), surf_scaled(NULL), surf(NULL)
+ {
+ LayerImage::alpha(opacity);
+ LayerImage::geo(geo);
+ LayerImage::file(file);
+ }
+
+ ~LayerImage()
+ {
+ SDL_FREESURFACE_SAFE(surf_alpha);
+ SDL_FREESURFACE_SAFE(surf_scaled);
+ SDL_FREESURFACE_SAFE(surf);
+ }
+
+ void geo(SDL_Rect geo);
+ void alpha(float opacity);
+
+ void file(const char *file = NULL);
+
+ void frame(SDL_Surface *target);
+};
+
+/*
+ * Macros
+ */
+#define SDL_IMAGE_ERROR(FMT, ...) do { \
+ fprintf(stderr, "%s(%d): " FMT ": %s\n", \
+ __FILE__, __LINE__, ##__VA_ARGS__, IMG_GetError()); \
+} while (0)
+
+#endif
diff --git a/layer_video.cpp b/layer_video.cpp
new file mode 100644
index 0000000..ec9e258
--- /dev/null
+++ b/layer_video.cpp
@@ -0,0 +1,232 @@
+#include <assert.h>
+#include <math.h>
+
+#include <SDL.h>
+#include <SDL_thread.h>
+#include <SDL_rotozoom.h>
+
+#include <vlc/vlc.h>
+#include <vlc/libvlc_version.h>
+
+#include "osc_graphics.h"
+#include "layer_video.h"
+
+static void *
+lock_cb(void *data, void **p_pixels)
+{
+ LayerVideo *video = (LayerVideo *)data;
+
+ *p_pixels = video->lock_surf();
+
+ return NULL; /* picture identifier, not needed here */
+}
+
+static void
+unlock_cb(void *data, void *id __attribute__((unused)), void *const *p_pixels)
+{
+ LayerVideo *video = (LayerVideo *)data;
+
+ video->unlock_surf();
+}
+
+static void
+display_cb(void *data __attribute__((unused)), void *id __attribute__((unused)))
+{
+ /* VLC wants to display the video */
+}
+
+LayerVideo::LayerVideo(const char *name, SDL_Rect geo, float opacity,
+ const char *url) : Layer(name), mp(NULL), surf(NULL)
+{
+ char const *vlc_argv[] = {
+ "--no-audio", /* skip any audio track */
+ "--no-xlib" /* tell VLC to not use Xlib */
+ };
+
+ LayerVideo::geo(geo);
+ LayerVideo::alpha(opacity);
+ LayerVideo::rate(1.);
+ LayerVideo::paused(true);
+
+ mutex = SDL_CreateMutex();
+ vlcinst = libvlc_new(NARRAY(vlc_argv), vlc_argv);
+
+ LayerVideo::url(url);
+}
+
+void
+LayerVideo::geo(SDL_Rect geo)
+{
+ if (!geo.x && !geo.y && !geo.w && !geo.h)
+ geov = (SDL_Rect){0, 0, screen->w, screen->h};
+ else
+ geov = geo;
+}
+
+#if LIBVLC_VERSION_INT < LIBVLC_VERSION(2,0,0,0)
+
+/*
+ * libvlc_video_get_size() cannot be used before playback has started and
+ * libvlc_media_get_tracks_info() is broken in libVLC v1.x.x so we just
+ * use the screen size on those versions (results in unnecessary scaling).
+ */
+static inline void
+media_get_video_size(libvlc_media_t *media __attribute__((unused)),
+ unsigned int &width, unsigned int &height)
+{
+ width = screen->w;
+ height = screen->h;
+}
+
+#else
+
+static inline void
+media_get_video_size(libvlc_media_t *media,
+ unsigned int &width, unsigned int &height)
+{
+ libvlc_media_track_info_t *tracks = NULL;
+ int num_tracks;
+
+ width = height = 0;
+
+ libvlc_media_parse(media);
+
+ num_tracks = libvlc_media_get_tracks_info(media, &tracks);
+ for (int i = 0; i < num_tracks; i++) {
+ if (tracks[i].i_type == libvlc_track_video) {
+ width = tracks[i].u.video.i_width;
+ height = tracks[i].u.video.i_height;
+ break;
+ }
+ }
+
+ free(tracks);
+
+ assert(width && height);
+}
+
+#endif
+
+void
+LayerVideo::url(const char *url)
+{
+ libvlc_media_t *m;
+ unsigned int width, height;
+
+ SDL_FREESURFACE_SAFE(surf);
+
+ if (mp) {
+ libvlc_media_player_release(mp);
+ mp = NULL;
+ }
+
+ if (!url || !*url)
+ return;
+
+ m = libvlc_media_new_location(vlcinst, url);
+ mp = libvlc_media_player_new_from_media(m);
+ media_get_video_size(m, width, height);
+ libvlc_media_release(m);
+
+ /*
+ * Cannot change buffer dimensions on the fly, so we let
+ * libVLC render into a statically sized buffer and do the resizing
+ * on our own.
+ * We use the original video size so libVLC does not have to do
+ * unnecessary scaling.
+ */
+ surf = SDL_CreateRGBSurface(SDL_HWSURFACE, width, height,
+ 16, 0x001f, 0x07e0, 0xf800, 0);
+
+ libvlc_video_set_callbacks(mp, lock_cb, unlock_cb, display_cb, this);
+ libvlc_video_set_format(mp, "RV16", surf->w, surf->h, surf->pitch);
+
+ rate(ratev);
+ paused(pausedv);
+}
+
+void
+LayerVideo::alpha(float opacity)
+{
+ alphav = opacity;
+}
+
+void
+LayerVideo::rate(float rate)
+{
+ ratev = rate;
+
+ if (mp)
+ libvlc_media_player_set_rate(mp, rate);
+}
+
+void
+LayerVideo::position(float position)
+{
+ if (mp)
+ libvlc_media_player_set_position(mp, position);
+}
+
+void
+LayerVideo::paused(bool paused)
+{
+ pausedv = paused;
+
+ if (!mp)
+ return;
+
+#if 0
+ libvlc_media_player_set_pause(mp, paused);
+#else
+ int playing = libvlc_media_player_is_playing(mp);
+ if (playing && paused)
+ libvlc_media_player_pause(mp);
+ else if (!playing && !paused)
+ libvlc_media_player_play(mp);
+#endif
+}
+
+void
+LayerVideo::frame(SDL_Surface *target)
+{
+ Uint8 alpha = (Uint8)ceilf(alphav*SDL_ALPHA_OPAQUE);
+
+ if (!surf)
+ return;
+
+ if (surf->w != geov.w || surf->h != geov.h) {
+ SDL_Surface *surf_scaled;
+
+ SDL_LockMutex(mutex);
+ surf_scaled = zoomSurface(surf,
+ (double)geov.w/surf->w,
+ (double)geov.h/surf->h,
+ SMOOTHING_ON);
+ SDL_UnlockMutex(mutex);
+
+ if (alpha < SDL_ALPHA_OPAQUE)
+ SDL_SetAlpha(surf_scaled, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
+
+ SDL_BlitSurface(surf_scaled, NULL, target, &geov);
+ SDL_FreeSurface(surf_scaled);
+ } else {
+ if (alpha == SDL_ALPHA_OPAQUE)
+ SDL_SetAlpha(surf, 0, 0);
+ else
+ SDL_SetAlpha(surf, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
+
+ SDL_LockMutex(mutex);
+ SDL_BlitSurface(surf, NULL, target, &geov);
+ SDL_UnlockMutex(mutex);
+ }
+}
+
+LayerVideo::~LayerVideo()
+{
+ if (mp)
+ libvlc_media_player_release(mp);
+ libvlc_release(vlcinst);
+ SDL_DestroyMutex(mutex);
+ if (surf)
+ SDL_FreeSurface(surf);
+}
diff --git a/layer_video.h b/layer_video.h
new file mode 100644
index 0000000..f16d334
--- /dev/null
+++ b/layer_video.h
@@ -0,0 +1,57 @@
+#ifndef __HAVE_LAYER_VIDEO_H
+#define __HAVE_LAYER_VIDEO_H
+
+#include <SDL.h>
+#include <SDL_thread.h>
+
+#include <vlc/vlc.h>
+
+#include "osc_graphics.h"
+#include "layer.h"
+
+class LayerVideo : public Layer {
+ libvlc_instance_t *vlcinst;
+ libvlc_media_player_t *mp;
+
+ SDL_Surface *surf;
+ SDL_mutex *mutex;
+
+ SDL_Rect geov;
+ float alphav;
+
+ float ratev;
+ bool pausedv;
+
+public:
+ LayerVideo(const char *name,
+ SDL_Rect geo = (SDL_Rect){0, 0, 0, 0},
+ float opacity = 1.,
+ const char *url = NULL);
+ ~LayerVideo();
+
+ inline void *
+ lock_surf()
+ {
+ SDL_LockMutex(mutex);
+ SDL_MAYBE_LOCK(surf);
+ return surf->pixels;
+ }
+ inline void
+ unlock_surf()
+ {
+ SDL_MAYBE_UNLOCK(surf);
+ SDL_UnlockMutex(mutex);
+ }
+
+ void geo(SDL_Rect geo);
+ void alpha(float opacity);
+
+ void url(const char *url = NULL);
+ void rate(float rate);
+ void position(float position);
+ void paused(bool paused);
+
+ void frame(SDL_Surface *target);
+};
+
+#endif
diff --git a/main.cpp b/main.cpp
index c476c0c..5461d82 100644
--- a/main.cpp
+++ b/main.cpp
@@ -2,55 +2,18 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdint.h>
-#include <assert.h>
-#include <math.h>
#include <SDL.h>
-#include <SDL_thread.h>
-#include <SDL_image.h>
#include <SDL_framerate.h>
-#include <SDL_rotozoom.h>
-#include <SDL_gfxPrimitives.h>
-#include <SDL_gfxBlitFunc.h>
-
-#include <vlc/vlc.h>
-#include <vlc/libvlc_version.h>
#include <lo/lo.h>
-/*
- * Macros
- */
-#define NARRAY(ARRAY) \
- (sizeof(ARRAY) / sizeof((ARRAY)[0]))
-
-#define SDL_MAYBE_LOCK(SURFACE) do { \
- if (SDL_MUSTLOCK(SURFACE)) \
- SDL_LockSurface(SURFACE); \
-} while (0)
-
-#define SDL_MAYBE_UNLOCK(SURFACE) do { \
- if (SDL_MUSTLOCK(SURFACE)) \
- SDL_UnlockSurface(SURFACE); \
-} while (0)
-
-#define SDL_FREESURFACE_SAFE(SURFACE) do { \
- if (SURFACE) { \
- SDL_FreeSurface(SURFACE); \
- SURFACE = NULL; \
- } \
-} while (0)
-
-#define SDL_ERROR(FMT, ...) do { \
- fprintf(stderr, "%s(%d): " FMT ": %s\n", \
- __FILE__, __LINE__, ##__VA_ARGS__, SDL_GetError()); \
-} while (0)
-
-#define SDL_IMAGE_ERROR(FMT, ...) do { \
- fprintf(stderr, "%s(%d): " FMT ": %s\n", \
- __FILE__, __LINE__, ##__VA_ARGS__, IMG_GetError()); \
-} while (0)
+#include "osc_graphics.h"
+
+#include "layer.h"
+#include "layer_box.h"
+#include "layer_image.h"
+#include "layer_video.h"
#define GEO_TYPES "iiii" /* x, y, width, height */
#define NEW_LAYER_TYPES "is" GEO_TYPES "f" /* position, name, GEO, alpha */
@@ -66,48 +29,16 @@
/*
* Declarations
*/
-typedef void (*layer_frame_cb_t)(void *data, SDL_Surface *target);
-typedef void (*layer_free_cb_t)(void *data);
-
-static int layer_insert(int pos, const char *name, void *data,
- layer_frame_cb_t frame_cb, layer_free_cb_t free_cb);
-static int layer_delete_by_name(const char *name);
-
-static struct layer_image *layer_image_new(SDL_Rect geo, float opacity,
- const char *file);
-static void layer_image_geo(struct layer_image *ctx, SDL_Rect geo);
-static void layer_image_file(struct layer_image *ctx, const char *file);
-static void layer_image_alpha(struct layer_image *ctx, float opacity);
-static void layer_image_frame_cb(void *data, SDL_Surface *target);
-static void layer_image_free_cb(void *data);
-
-static struct layer_video *layer_video_new(SDL_Rect geo, float opacity,
- const char *url);
-static void layer_video_geo(struct layer_video *ctx, SDL_Rect geo);
-static void layer_video_url(struct layer_video *ctx, const char *url);
-static void layer_video_alpha(struct layer_video *ctx, float opacity);
-static void layer_video_rate(struct layer_video *ctx, float rate);
-static void layer_video_position(struct layer_video *ctx, float position);
-static void layer_video_paused(struct layer_video *ctx, int paused);
-static void layer_video_frame_cb(void *data, SDL_Surface *target);
-static void layer_video_free_cb(void *data);
-
-static struct layer_box *layer_box_new(SDL_Rect geo, float opacity,
- SDL_Color color);
-static void layer_box_geo(struct layer_box *ctx, SDL_Rect geo);
-static void layer_box_color(struct layer_box *ctx, SDL_Color color);
-static void layer_box_alpha(struct layer_box *ctx, float opacity);
-static void layer_box_frame_cb(void *data, SDL_Surface *target);
-static void layer_box_free_cb(void *data);
-
-static SDL_Surface *screen;
-static SDL_mutex *render_mutex;
+SDL_Surface *screen;
+
+static LayerList layers;
+
static int config_dump_osc = 0;
static void
lo_server_thread_add_method_v(lo_server_thread server, const char *types,
- lo_method_handler handler, void *data,
- const char *fmt, ...)
+ lo_method_handler handler, void *data,
+ const char *fmt, ...)
{
char buf[255];
va_list ap;
@@ -119,7 +50,8 @@ lo_server_thread_add_method_v(lo_server_thread server, const char *types,
}
static void
-lo_server_thread_del_method_v(lo_server_thread server, const char *types, const char *fmt, ...)
+lo_server_thread_del_method_v(lo_server_thread server, const char *types,
+ const char *fmt, ...)
{
char buf[255];
va_list ap;
@@ -149,7 +81,7 @@ osc_generic_handler(const char *path, const char *types, lo_arg **argv,
printf("path: <%s>\n", path);
for (int i = 0; i < argc; i++) {
printf("arg %d '%c' ", i, types[i]);
- lo_arg_pp(types[i], argv[i]);
+ lo_arg_pp((lo_type)types[i], argv[i]);
printf("\n");
}
printf("\n");
@@ -175,7 +107,7 @@ osc_layer_delete(const char *path, const char *types, lo_arg **argv,
char *name;
name = get_layer_name_from_path(path);
- layer_delete_by_name(name);
+ layers.delete_by_name(name);
free(name);
lo_server_thread_del_method(server, path, types);
@@ -189,22 +121,20 @@ osc_add_layer_delete(lo_server_thread server, const char *name,
{
if (custom_delete)
lo_server_thread_add_method_v(server, "", custom_delete, server,
- "/layer/%s/delete", name);
+ "/layer/%s/delete", name);
lo_server_thread_add_method_v(server, "", osc_layer_delete, server,
- "/layer/%s/delete", name);
+ "/layer/%s/delete", name);
}
static int
osc_image_geo(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_image *ctx = user_data;
+ LayerImage *ctx = (LayerImage *)user_data;
- SDL_LockMutex(render_mutex);
- layer_image_geo(ctx, (SDL_Rect){
- argv[0]->i, argv[1]->i, argv[2]->i, argv[3]->i
- });
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->geo((SDL_Rect){argv[0]->i, argv[1]->i, argv[2]->i, argv[3]->i});
+ ctx->unlock();
return 0;
}
@@ -212,11 +142,11 @@ static int
osc_image_alpha(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_image *ctx = user_data;
+ LayerImage *ctx = (LayerImage *)user_data;
- SDL_LockMutex(render_mutex);
- layer_image_alpha(ctx, argv[0]->f);
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->alpha(argv[0]->f);
+ ctx->unlock();
return 0;
}
@@ -224,11 +154,11 @@ static int
osc_image_file(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_image *ctx = user_data;
+ LayerImage *ctx = (LayerImage *)user_data;
- SDL_LockMutex(render_mutex);
- layer_image_file(ctx, &argv[0]->s);
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->file(&argv[0]->s);
+ ctx->unlock();
return 0;
}
@@ -236,7 +166,7 @@ static int
osc_image_delete(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- lo_server_thread server = user_data;
+ lo_server_thread server = (lo_server_thread)user_data;
char *name;
name = get_layer_name_from_path(path);
@@ -256,26 +186,22 @@ static int
osc_image_new(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- lo_server_thread server = user_data;
+ lo_server_thread server = (lo_server_thread)user_data;
SDL_Rect geo = {
(Sint16)argv[2]->i, (Sint16)argv[3]->i,
(Uint16)argv[4]->i, (Uint16)argv[5]->i
};
- struct layer_image *ctx = layer_image_new(geo, argv[6]->f, &argv[7]->s);
+ LayerImage *ctx = new LayerImage(&argv[1]->s, geo, argv[6]->f, &argv[7]->s);
- SDL_LockMutex(render_mutex);
- if (layer_insert(argv[0]->i, &argv[1]->s, ctx,
- layer_image_frame_cb, layer_image_free_cb))
- return 0;
- SDL_UnlockMutex(render_mutex);
+ layers.insert(argv[0]->i, ctx);
lo_server_thread_add_method_v(server, GEO_TYPES, osc_image_geo, ctx,
- "/layer/%s/geo", &argv[1]->s);
+ "/layer/%s/geo", &argv[1]->s);
lo_server_thread_add_method_v(server, "f", osc_image_alpha, ctx,
- "/layer/%s/alpha", &argv[1]->s);
+ "/layer/%s/alpha", &argv[1]->s);
lo_server_thread_add_method_v(server, "s", osc_image_file, ctx,
- "/layer/%s/file", &argv[1]->s);
+ "/layer/%s/file", &argv[1]->s);
osc_add_layer_delete(server, &argv[1]->s, osc_image_delete);
@@ -286,13 +212,11 @@ static int
osc_video_geo(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_video *ctx = user_data;
+ LayerVideo *ctx = (LayerVideo *)user_data;
- SDL_LockMutex(render_mutex);
- layer_video_geo(ctx, (SDL_Rect){
- argv[0]->i, argv[1]->i, argv[2]->i, argv[3]->i
- });
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->geo((SDL_Rect){argv[0]->i, argv[1]->i, argv[2]->i, argv[3]->i});
+ ctx->unlock();
return 0;
}
@@ -300,11 +224,11 @@ static int
osc_video_alpha(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_video *ctx = user_data;
+ LayerVideo *ctx = (LayerVideo *)user_data;
- SDL_LockMutex(render_mutex);
- layer_video_alpha(ctx, argv[0]->f);
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->alpha(argv[0]->f);
+ ctx->unlock();
return 0;
}
@@ -312,11 +236,11 @@ static int
osc_video_url(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_video *ctx = user_data;
+ LayerVideo *ctx = (LayerVideo *)user_data;
- SDL_LockMutex(render_mutex);
- layer_video_url(ctx, &argv[0]->s);
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->url(&argv[0]->s);
+ ctx->unlock();
return 0;
}
@@ -324,11 +248,11 @@ static int
osc_video_rate(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_video *ctx = user_data;
+ LayerVideo *ctx = (LayerVideo *)user_data;
- SDL_LockMutex(render_mutex);
- layer_video_rate(ctx, argv[0]->f);
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->rate(argv[0]->f);
+ ctx->unlock();
return 0;
}
@@ -336,11 +260,11 @@ static int
osc_video_position(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_video *ctx = user_data;
+ LayerVideo *ctx = (LayerVideo *)user_data;
- SDL_LockMutex(render_mutex);
- layer_video_position(ctx, argv[0]->f);
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->position(argv[0]->f);
+ ctx->unlock();
return 0;
}
@@ -348,11 +272,11 @@ static int
osc_video_paused(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_video *ctx = user_data;
+ LayerVideo *ctx = (LayerVideo *)user_data;
- SDL_LockMutex(render_mutex);
- layer_video_paused(ctx, argv[0]->i);
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->paused(argv[0]->i);
+ ctx->unlock();
return 0;
}
@@ -360,7 +284,7 @@ static int
osc_video_delete(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- lo_server_thread server = user_data;
+ lo_server_thread server = (lo_server_thread)user_data;
char *name;
name = get_layer_name_from_path(path);
@@ -383,32 +307,28 @@ static int
osc_video_new(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- lo_server_thread server = user_data;
+ lo_server_thread server = (lo_server_thread)user_data;
SDL_Rect geo = {
(Sint16)argv[2]->i, (Sint16)argv[3]->i,
(Uint16)argv[4]->i, (Uint16)argv[5]->i
};
- struct layer_video *ctx = layer_video_new(geo, argv[6]->f, &argv[7]->s);
+ LayerVideo *ctx = new LayerVideo(&argv[1]->s, geo, argv[6]->f, &argv[7]->s);
- SDL_LockMutex(render_mutex);
- if (layer_insert(argv[0]->i, &argv[1]->s, ctx,
- layer_video_frame_cb, layer_video_free_cb))
- return 0;
- SDL_UnlockMutex(render_mutex);
+ layers.insert(argv[0]->i, ctx);
lo_server_thread_add_method_v(server, GEO_TYPES, osc_video_geo, ctx,
- "/layer/%s/geo", &argv[1]->s);
+ "/layer/%s/geo", &argv[1]->s);
lo_server_thread_add_method_v(server, "f", osc_video_alpha, ctx,
- "/layer/%s/alpha", &argv[1]->s);
+ "/layer/%s/alpha", &argv[1]->s);
lo_server_thread_add_method_v(server, "s", osc_video_url, ctx,
- "/layer/%s/url", &argv[1]->s);
+ "/layer/%s/url", &argv[1]->s);
lo_server_thread_add_method_v(server, "f", osc_video_rate, ctx,
- "/layer/%s/rate", &argv[1]->s);
+ "/layer/%s/rate", &argv[1]->s);
lo_server_thread_add_method_v(server, "f", osc_video_position, ctx,
- "/layer/%s/position", &argv[1]->s);
+ "/layer/%s/position", &argv[1]->s);
lo_server_thread_add_method_v(server, "i", osc_video_paused, ctx,
- "/layer/%s/paused", &argv[1]->s);
+ "/layer/%s/paused", &argv[1]->s);
osc_add_layer_delete(server, &argv[1]->s, osc_video_delete);
return 0;
@@ -418,13 +338,11 @@ static int
osc_box_geo(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_box *ctx = user_data;
+ LayerBox *ctx = (LayerBox *)user_data;
- SDL_LockMutex(render_mutex);
- layer_box_geo(ctx, (SDL_Rect){
- argv[0]->i, argv[1]->i, argv[2]->i, argv[3]->i
- });
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->geo((SDL_Rect){argv[0]->i, argv[1]->i, argv[2]->i, argv[3]->i});
+ ctx->unlock();
return 0;
}
@@ -432,11 +350,11 @@ static int
osc_box_alpha(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_box *ctx = user_data;
+ LayerBox *ctx = (LayerBox *)user_data;
- SDL_LockMutex(render_mutex);
- layer_box_alpha(ctx, argv[0]->f);
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->alpha(argv[0]->f);
+ ctx->unlock();
return 0;
}
@@ -444,11 +362,11 @@ static int
osc_box_color(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- struct layer_box *ctx = user_data;
+ LayerBox *ctx = (LayerBox *)user_data;
- SDL_LockMutex(render_mutex);
- layer_box_color(ctx, (SDL_Color){argv[0]->i, argv[1]->i, argv[2]->i});
- SDL_UnlockMutex(render_mutex);
+ ctx->lock();
+ ctx->color((SDL_Color){argv[0]->i, argv[1]->i, argv[2]->i});
+ ctx->unlock();
return 0;
}
@@ -456,7 +374,7 @@ static int
osc_box_delete(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- lo_server_thread server = user_data;
+ lo_server_thread server = (lo_server_thread)user_data;
char *name;
name = get_layer_name_from_path(path);
@@ -476,7 +394,7 @@ static int
osc_box_new(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
- lo_server_thread server = user_data;
+ lo_server_thread server = (lo_server_thread)user_data;
SDL_Rect geo = {
(Sint16)argv[2]->i, (Sint16)argv[3]->i,
(Uint16)argv[4]->i, (Uint16)argv[5]->i
@@ -485,20 +403,16 @@ osc_box_new(const char *path, const char *types, lo_arg **argv,
(Uint8)argv[7]->i, (Uint8)argv[8]->i, (Uint8)argv[9]->i
};
- struct layer_box *ctx = layer_box_new(geo, argv[6]->f, color);
+ LayerBox *ctx = new LayerBox(&argv[1]->s, geo, argv[6]->f, color);
- SDL_LockMutex(render_mutex);
- if (layer_insert(argv[0]->i, &argv[1]->s, ctx,
- layer_box_frame_cb, layer_box_free_cb))
- return 0;
- SDL_UnlockMutex(render_mutex);
+ layers.insert(argv[0]->i, ctx);
lo_server_thread_add_method_v(server, GEO_TYPES, osc_box_geo, ctx,
- "/layer/%s/geo", &argv[1]->s);
+ "/layer/%s/geo", &argv[1]->s);
lo_server_thread_add_method_v(server, "f", osc_box_alpha, ctx,
- "/layer/%s/alpha", &argv[1]->s);
+ "/layer/%s/alpha", &argv[1]->s);
lo_server_thread_add_method_v(server, COLOR_TYPES, osc_box_color, ctx,
- "/layer/%s/color", &argv[1]->s);
+ "/layer/%s/color", &argv[1]->s);
osc_add_layer_delete(server, &argv[1]->s, osc_box_delete);
@@ -513,535 +427,15 @@ osc_init(const char *port)
lo_server_thread_add_method(server, NULL, NULL, osc_generic_handler, NULL);
lo_server_thread_add_method(server, "/layer/new/image", NEW_LAYER_TYPES "s",
- osc_image_new, server);
+ osc_image_new, server);
lo_server_thread_add_method(server, "/layer/new/video", NEW_LAYER_TYPES "s",
- osc_video_new, server);
+ osc_video_new, server);
lo_server_thread_add_method(server, "/layer/new/box", NEW_LAYER_TYPES COLOR_TYPES,
- osc_box_new, server);
+ osc_box_new, server);
return server;
}
-/*
- * Image layers
- */
-struct layer_image {
- SDL_Surface *surf_alpha; /* with per-surface alpha */
- SDL_Surface *surf_scaled; /* scaled image */
- SDL_Surface *surf; /* original image */
-
- SDL_Rect geo;
- float alpha;
-};
-
-static struct layer_image *
-layer_image_new(SDL_Rect geo, float opacity, const char *file)
-{
- struct layer_image *ctx = malloc(sizeof(struct layer_image));
-
- if (!ctx)
- return NULL;
-
- memset(ctx, 0, sizeof(*ctx));
-
- layer_image_alpha(ctx, opacity);
- layer_image_geo(ctx, geo);
- layer_image_file(ctx, file);
-
- return ctx;
-}
-
-static void
-layer_image_geo(struct layer_image *ctx, SDL_Rect geo)
-{
- if (!geo.x && !geo.y && !geo.w && !geo.h)
- ctx->geo = (SDL_Rect){0, 0, screen->w, screen->h};
- else
- ctx->geo = geo;
-
- if (!ctx->surf)
- return;
-
- if (ctx->surf_scaled &&
- ctx->surf_scaled->w == ctx->geo.w &&
- ctx->surf_scaled->h == ctx->geo.h)
- return;
-
- SDL_FREESURFACE_SAFE(ctx->surf_alpha);
- SDL_FREESURFACE_SAFE(ctx->surf_scaled);
-
- if (ctx->surf->w != ctx->geo.w || ctx->surf->h != ctx->geo.h) {
- ctx->surf_scaled = zoomSurface(ctx->surf,
- (double)ctx->geo.w/ctx->surf->w,
- (double)ctx->geo.h/ctx->surf->h,
- SMOOTHING_ON);
- }
-
- layer_image_alpha(ctx, ctx->alpha);
-}
-
-static void
-layer_image_file(struct layer_image *ctx, const char *file)
-{
- SDL_FREESURFACE_SAFE(ctx->surf_alpha);
- SDL_FREESURFACE_SAFE(ctx->surf_scaled);
- SDL_FREESURFACE_SAFE(ctx->surf);
-
- if (!file || !*file)
- return;
-
- ctx->surf = IMG_Load(file);
- if (!ctx->surf) {
- SDL_IMAGE_ERROR("IMG_Load");
- exit(EXIT_FAILURE);
- }
-
- layer_image_geo(ctx, ctx->geo);
-}
-
-#if 0
-
-static inline void
-rgba_blit_with_alpha(SDL_Surface *src_surf, SDL_Surface *dst_surf, Uint8 alpha)
-{
- SDL_FillRect(dst_surf, NULL,
- SDL_MapRGBA(dst_surf->format,
- 0, 0, 0, SDL_ALPHA_TRANSPARENT));
- SDL_gfxBlitRGBA(src_surf, NULL, dst_surf, NULL);
- SDL_gfxMultiplyAlpha(dst_surf, alpha);
-}
-
-#else
-
-static inline void
-rgba_blit_with_alpha(SDL_Surface *src_surf, SDL_Surface *dst_surf, Uint8 alpha)
-{
- Uint8 *src = src_surf->pixels;
- Uint8 *dst = dst_surf->pixels;
- SDL_PixelFormat *fmt = src_surf->format;
-
- int inc = fmt->BytesPerPixel;
- int len = src_surf->w * src_surf->h;
-
- SDL_MAYBE_LOCK(src_surf);
- SDL_MAYBE_LOCK(dst_surf);
-
- GFX_DUFFS_LOOP4({
- register Uint32 pixel;
- register int a;
-
- pixel = *(Uint32 *)src;
- a = ((pixel & fmt->Amask) >> fmt->Ashift) << fmt->Aloss;
- a = (a*alpha)/SDL_ALPHA_OPAQUE;
- a = (a << fmt->Aloss) << fmt->Ashift;
- pixel &= ~fmt->Amask;
- pixel |= a;
- *(Uint32 *)dst = pixel;
-
- src += inc;
- dst += inc;
- }, len)
-
- SDL_MAYBE_UNLOCK(dst_surf);
- SDL_MAYBE_UNLOCK(src_surf);
-}
-
-#endif
-
-static void
-layer_image_alpha(struct layer_image *ctx, float opacity)
-{
- SDL_Surface *surf = ctx->surf_scaled ? : ctx->surf;
- Uint8 alpha = (Uint8)ceilf(opacity*SDL_ALPHA_OPAQUE);
-
- ctx->alpha = opacity;
-
- if (!surf)
- return;
-
- if (!surf->format->Amask) {
- if (alpha == SDL_ALPHA_OPAQUE)
- SDL_SetAlpha(surf, 0, 0);
- else
- SDL_SetAlpha(surf, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
-
- return;
- }
-
- if (alpha == SDL_ALPHA_OPAQUE) {
- SDL_FREESURFACE_SAFE(ctx->surf_alpha);
- return;
- }
-
- if (!ctx->surf_alpha) {
- ctx->surf_alpha = SDL_CreateRGBSurface(surf->flags,
- surf->w, surf->h,
- surf->format->BitsPerPixel,
- surf->format->Rmask,
- surf->format->Gmask,
- surf->format->Bmask,
- surf->format->Amask);
- }
-
- if (alpha == SDL_ALPHA_TRANSPARENT) {
- SDL_FillRect(ctx->surf_alpha, NULL,
- SDL_MapRGBA(ctx->surf_alpha->format,
- 0, 0, 0, SDL_ALPHA_TRANSPARENT));
- } else {
- rgba_blit_with_alpha(surf, ctx->surf_alpha, alpha);
- }
-}
-
-static void
-layer_image_frame_cb(void *data, SDL_Surface *target)
-{
- struct layer_image *ctx = data;
-
- if (!ctx->surf)
- return;
-
- SDL_BlitSurface(ctx->surf_alpha ? : ctx->surf_scaled ? : ctx->surf,
- NULL, target, &ctx->geo);
-}
-
-static void
-layer_image_free_cb(void *data)
-{
- struct layer_image *ctx = data;
-
- SDL_FREESURFACE_SAFE(ctx->surf_alpha);
- SDL_FREESURFACE_SAFE(ctx->surf_scaled);
- SDL_FREESURFACE_SAFE(ctx->surf);
-
- free(ctx);
-}
-
-/*
- * Video layer
- */
-struct layer_video {
- libvlc_instance_t *vlcinst;
- libvlc_media_player_t *mp;
-
- SDL_Surface *surf;
- SDL_mutex *mutex;
-
- SDL_Rect geo;
- float alpha;
-
- float rate;
- int paused;
-};
-
-static void *
-layer_video_lock_cb(void *data, void **p_pixels)
-{
- struct layer_video *ctx = data;
-
- SDL_LockMutex(ctx->mutex);
- SDL_MAYBE_LOCK(ctx->surf);
- *p_pixels = ctx->surf->pixels;
-
- return NULL; /* picture identifier, not needed here */
-}
-
-static void
-layer_video_unlock_cb(void *data, void *id, void *const *p_pixels)
-{
- struct layer_video *ctx = data;
-
- assert(id == NULL); /* picture identifier, not needed here */
-
- SDL_MAYBE_UNLOCK(ctx->surf);
- SDL_UnlockMutex(ctx->mutex);
-}
-
-static void
-layer_video_display_cb(void *data __attribute__((unused)), void *id)
-{
- /* VLC wants to display the video */
- assert(id == NULL); /* picture identifier, not needed here */
-}
-
-static struct layer_video *
-layer_video_new(SDL_Rect geo, float opacity, const char *url)
-{
- char const *vlc_argv[] = {
- "--no-audio", /* skip any audio track */
- "--no-xlib" /* tell VLC to not use Xlib */
- };
- struct layer_video *ctx = malloc(sizeof(struct layer_video));
-
- if (!ctx)
- return NULL;
-
- memset(ctx, 0, sizeof(*ctx));
-
- layer_video_geo(ctx, geo);
- layer_video_alpha(ctx, opacity);
- layer_video_rate(ctx, 1.);
- layer_video_paused(ctx, 1);
-
- ctx->mutex = SDL_CreateMutex();
- ctx->vlcinst = libvlc_new(NARRAY(vlc_argv), vlc_argv);
- ctx->mp = NULL;
-
- layer_video_url(ctx, url);
-
- return ctx;
-}
-
-static void
-layer_video_geo(struct layer_video *ctx, SDL_Rect geo)
-{
- if (!geo.x && !geo.y && !geo.w && !geo.h)
- ctx->geo = (SDL_Rect){0, 0, screen->w, screen->h};
- else
- ctx->geo = geo;
-}
-
-#if LIBVLC_VERSION_INT < LIBVLC_VERSION(2,0,0,0)
-
-/*
- * libvlc_video_get_size() cannot be used before playback has started and
- * libvlc_media_get_tracks_info() is broken in libVLC v1.x.x so we just
- * use the screen size on those versions (results in unnecessary scaling).
- */
-static inline void
-media_get_video_size(libvlc_media_t *media,
- unsigned int *width, unsigned int *height)
-{
- *width = screen->w;
- *height = screen->h;
-}
-
-#else
-
-static inline void
-media_get_video_size(libvlc_media_t *media,
- unsigned int *width, unsigned int *height)
-{
- libvlc_media_track_info_t *tracks = NULL;
- int num_tracks;
-
- *width = *height = 0;
-
- libvlc_media_parse(media);
-
- num_tracks = libvlc_media_get_tracks_info(media, &tracks);
- for (int i = 0; i < num_tracks; i++) {
- if (tracks[i].i_type == libvlc_track_video) {
- *width = tracks[i].u.video.i_width;
- *height = tracks[i].u.video.i_height;
- break;
- }
- }
-
- free(tracks);
-
- assert(*width && *height);
-}
-
-#endif
-
-static void
-layer_video_url(struct layer_video *ctx, const char *url)
-{
- libvlc_media_t *m;
- unsigned int width, height;
-
- SDL_FREESURFACE_SAFE(ctx->surf);
-
- if (ctx->mp) {
- libvlc_media_player_release(ctx->mp);
- ctx->mp = NULL;
- }
-
- if (!url || !*url)
- return;
-
- m = libvlc_media_new_location(ctx->vlcinst, url);
- ctx->mp = libvlc_media_player_new_from_media(m);
- media_get_video_size(m, &width, &height);
- libvlc_media_release(m);
-
- /*
- * Cannot change buffer dimensions on the fly, so we let
- * libVLC render into a statically sized buffer and do the resizing
- * on our own.
- * We use the original video size so libVLC does not have to do
- * unnecessary scaling.
- */
- ctx->surf = SDL_CreateRGBSurface(SDL_HWSURFACE, width, height,
- 16, 0x001f, 0x07e0, 0xf800, 0);
-
- libvlc_video_set_callbacks(ctx->mp,
- layer_video_lock_cb, layer_video_unlock_cb,
- layer_video_display_cb,
- ctx);
- libvlc_video_set_format(ctx->mp, "RV16",
- ctx->surf->w, ctx->surf->h,
- ctx->surf->pitch);
-
- layer_video_rate(ctx, ctx->rate);
- layer_video_paused(ctx, ctx->paused);
-}
-
-static void
-layer_video_alpha(struct layer_video *ctx, float opacity)
-{
- ctx->alpha = opacity;
-}
-
-static void
-layer_video_rate(struct layer_video *ctx, float rate)
-{
- ctx->rate = rate;
-
- if (ctx->mp)
- libvlc_media_player_set_rate(ctx->mp, rate);
-}
-
-static void
-layer_video_position(struct layer_video *ctx, float position)
-{
- if (ctx->mp)
- libvlc_media_player_set_position(ctx->mp, position);
-}
-
-static void
-layer_video_paused(struct layer_video *ctx, int paused)
-{
- ctx->paused = paused;
-
- if (!ctx->mp)
- return;
-
-#if 0
- libvlc_media_player_set_pause(ctx->mp, paused);
-#else
- int playing = libvlc_media_player_is_playing(ctx->mp);
- if (playing && paused)
- libvlc_media_player_pause(ctx->mp);
- else if (!playing && !paused)
- libvlc_media_player_play(ctx->mp);
-#endif
-}
-
-static void
-layer_video_frame_cb(void *data, SDL_Surface *target)
-{
- struct layer_video *ctx = data;
- Uint8 alpha = (Uint8)ceilf(ctx->alpha*SDL_ALPHA_OPAQUE);
-
- if (!ctx->surf)
- return;
-
- if (ctx->surf->w != ctx->geo.w || ctx->surf->h != ctx->geo.h) {
- SDL_Surface *surf_scaled;
-
- SDL_LockMutex(ctx->mutex);
- surf_scaled = zoomSurface(ctx->surf,
- (double)ctx->geo.w/ctx->surf->w,
- (double)ctx->geo.h/ctx->surf->h,
- SMOOTHING_ON);
- SDL_UnlockMutex(ctx->mutex);
-
- if (alpha < SDL_ALPHA_OPAQUE)
- SDL_SetAlpha(surf_scaled, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
-
- SDL_BlitSurface(surf_scaled, NULL, target, &ctx->geo);
- SDL_FreeSurface(surf_scaled);
- } else {
- if (alpha == SDL_ALPHA_OPAQUE)
- SDL_SetAlpha(ctx->surf, 0, 0);
- else
- SDL_SetAlpha(ctx->surf, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
-
- SDL_LockMutex(ctx->mutex);
- SDL_BlitSurface(ctx->surf, NULL, target, &ctx->geo);
- SDL_UnlockMutex(ctx->mutex);
- }
-}
-
-static void
-layer_video_free_cb(void *data)
-{
- struct layer_video *ctx = data;
-
- if (ctx->mp)
- libvlc_media_player_release(ctx->mp);
- libvlc_release(ctx->vlcinst);
- SDL_DestroyMutex(ctx->mutex);
- if (ctx->surf)
- SDL_FreeSurface(ctx->surf);
-
- free(ctx);
-}
-
-/*
- * Box layer
- */
-struct layer_box {
- Sint16 x1, y1, x2, y2;
- Uint8 r, g, b, a;
-};
-
-static struct layer_box *
-layer_box_new(SDL_Rect geo, float opacity, SDL_Color color)
-{
- struct layer_box *ctx = malloc(sizeof(struct layer_box));
-
- if (ctx) {
- layer_box_geo(ctx, geo);
- layer_box_color(ctx, color);
- layer_box_alpha(ctx, opacity);
- }
-
- return ctx;
-}
-
-static void
-layer_box_geo(struct layer_box *ctx, SDL_Rect geo)
-{
- ctx->x1 = geo.x;
- ctx->y1 = geo.y;
- ctx->x2 = geo.x + geo.w;
- ctx->y2 = geo.y + geo.h;
-}
-
-static void
-layer_box_color(struct layer_box *ctx, SDL_Color color)
-{
- ctx->r = color.r;
- ctx->g = color.g;
- ctx->b = color.b;
-}
-
-static void
-layer_box_alpha(struct layer_box *ctx, float opacity)
-{
- ctx->a = (Uint8)ceilf(opacity*SDL_ALPHA_OPAQUE);
-}
-
-static void
-layer_box_frame_cb(void *data, SDL_Surface *target)
-{
- struct layer_box *ctx = data;
-
- boxRGBA(target, ctx->x1, ctx->y1,
- ctx->x2 ? : target->w, ctx->y2 ? : target->h,
- ctx->r, ctx->g, ctx->b, ctx->a);
-}
-
-static void
-layer_box_free_cb(void *data)
-{
- struct layer_box *ctx = data;
-
- free(ctx);
-}
-
static inline void
sdl_process_events(void)
{
@@ -1083,66 +477,6 @@ sdl_process_events(void)
}
}
-struct layer {
- struct layer *next;
-
- char *name;
-
- void *data;
- layer_frame_cb_t frame_cb;
- layer_free_cb_t free_cb;
-};
-static struct layer layers_head = {NULL};
-
-#define FOREACH_LAYER(VAR) \
- for (struct layer *VAR = layers_head.next; VAR; VAR = VAR->next)
-
-static int
-layer_insert(int pos, const char *name, void *data,
- layer_frame_cb_t frame_cb, layer_free_cb_t free_cb)
-{
- struct layer *new, *cur;
-
- new = malloc(sizeof(struct layer));
- if (!new)
- return -1;
-
- new->name = strdup(name);
- if (!new->name) {
- free(new);
- return -1;
- }
- new->data = data;
- new->frame_cb = frame_cb;
- new->free_cb = free_cb;
-
- for (cur = &layers_head; cur->next && pos; cur = cur->next, pos--);
- new->next = cur->next;
- cur->next = new;
-
- return 0;
-}
-
-static int
-layer_delete_by_name(const char *name)
-{
- for (struct layer *cur = &layers_head; cur->next; cur = cur->next) {
- if (!strcmp(cur->next->name, name)) {
- struct layer *l = cur->next;
-
- cur->next = l->next;
-
- l->free_cb(l->data);
- free(l->name);
- free(l);
-
- return 0;
- }
- }
-
- return -1;
-}
-
int
main(int argc, char **argv)
{
@@ -1168,7 +502,6 @@ main(int argc, char **argv)
return EXIT_FAILURE;
}
- render_mutex = SDL_CreateMutex();
lo_server_thread_start(osc_server);
SDL_initFramerate(&fpsm);
@@ -1177,12 +510,7 @@ main(int argc, char **argv)
for (;;) {
sdl_process_events();
- SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
-
- SDL_LockMutex(render_mutex);
- FOREACH_LAYER(cur)
- cur->frame_cb(cur->data, screen);
- SDL_UnlockMutex(render_mutex);
+ layers.render(screen);
SDL_Flip(screen);
SDL_framerateDelay(&fpsm);
diff --git a/osc_graphics.h b/osc_graphics.h
new file mode 100644
index 0000000..ab40fb5
--- /dev/null
+++ b/osc_graphics.h
@@ -0,0 +1,41 @@
+#ifndef __HAVE_OSC_GRAPHICS_H
+#define __HAVE_OSC_GRAPHICS_H
+
+#include <stdio.h>
+
+#include <SDL.h>
+
+/*
+ * Macros
+ */
+#define NARRAY(ARRAY) \
+ (sizeof(ARRAY) / sizeof((ARRAY)[0]))
+
+#define SDL_MAYBE_LOCK(SURFACE) do { \
+ if (SDL_MUSTLOCK(SURFACE)) \
+ SDL_LockSurface(SURFACE); \
+} while (0)
+
+#define SDL_MAYBE_UNLOCK(SURFACE) do { \
+ if (SDL_MUSTLOCK(SURFACE)) \
+ SDL_UnlockSurface(SURFACE); \
+} while (0)
+
+#define SDL_FREESURFACE_SAFE(SURFACE) do { \
+ if (SURFACE) { \
+ SDL_FreeSurface(SURFACE); \
+ SURFACE = NULL; \
+ } \
+} while (0)
+
+#define SDL_ERROR(FMT, ...) do { \
+ fprintf(stderr, "%s(%d): " FMT ": %s\n", \
+ __FILE__, __LINE__, ##__VA_ARGS__, SDL_GetError()); \
+} while (0)
+
+/*
+ * Declarations
+ */
+extern SDL_Surface *screen;
+
+#endif \ No newline at end of file