diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-09-21 18:24:57 +0200 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2012-09-21 18:24:57 +0200 |
commit | 75667b81215bdb3896599ec477a256c41fc90436 (patch) | |
tree | 44eb5919b596666997b972fc75fe5fdea60a633b | |
parent | 0e81cd9a89de9bdd6824bbe7265f91f3835dae97 (diff) | |
download | osc-graphics-75667b81215bdb3896599ec477a256c41fc90436.tar.gz |
split program into multiple files; switched to C++
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | layer.cpp | 70 | ||||
-rw-r--r-- | layer.h | 76 | ||||
-rw-r--r-- | layer_box.cpp | 29 | ||||
-rw-r--r-- | layer_box.h | 37 | ||||
-rw-r--r-- | layer_image.cpp | 157 | ||||
-rw-r--r-- | layer_image.h | 54 | ||||
-rw-r--r-- | layer_video.cpp | 232 | ||||
-rw-r--r-- | layer_video.h | 57 | ||||
-rw-r--r-- | main.cpp | 860 | ||||
-rw-r--r-- | osc_graphics.h | 41 |
11 files changed, 852 insertions, 769 deletions
@@ -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(); +} @@ -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 @@ -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 |