aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2012-09-15 22:04:28 +0200
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2012-09-15 22:04:28 +0200
commite4791c8a423dd7f981bd81775e8740a1da0f26fb (patch)
treef60cf43de96d39270b9a8a00600b5ad814f76a19
parentd6452189a87b5460e11aff3be19f8e31403e58c2 (diff)
downloadosc-graphics-e4791c8a423dd7f981bd81775e8740a1da0f26fb.tar.gz
allow setting alpha values for image and video layers
* for image layers, we must manually alpha blit if the image surface has an alpha channel (surf_alpha) * also, fill screen with black initially
-rw-r--r--Makefile3
-rw-r--r--main.c189
2 files changed, 176 insertions, 16 deletions
diff --git a/Makefile b/Makefile
index 19a0221..b71021d 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,8 @@ LIBLO_LDFLAGS := $(shell pkg-config liblo --libs)
CFLAGS := -std=c99 -Wall -g -O0 \
$(SDL_CFLAGS) $(SDL_IMAGE_CFLAGS) $(SDL_GFX_CFLAGS) \
$(LIBVLC_CFLAGS) $(LIBLO_CFLAGS)
-LDFLAGS := $(SDL_LDFLAGS) $(SDL_IMAGE_LDFLAGS) $(SDL_GFX_LDFLAGS) \
+LDFLAGS := -lm \
+ $(SDL_LDFLAGS) $(SDL_IMAGE_LDFLAGS) $(SDL_GFX_LDFLAGS) \
$(LIBVLC_LDFLAGS) $(LIBLO_LDFLAGS)
all : osc-graphics
diff --git a/main.c b/main.c
index d0ffe8e..9d245f5 100644
--- a/main.c
+++ b/main.c
@@ -3,6 +3,7 @@
#include <string.h>
#include <stdint.h>
#include <assert.h>
+#include <math.h>
#include <SDL.h>
#include <SDL_image.h>
@@ -59,12 +60,14 @@ static int layer_delete_by_name(const char *name);
static struct layer_image *layer_image_new(const char *file);
static void layer_image_change(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(const char *file, SDL_Color *key);
static void layer_video_change(struct layer_video *ctx,
const char *file, SDL_Color *key);
+static void layer_video_alpha(struct layer_video *ctx, float opacity);
static void layer_video_frame_cb(void *data, SDL_Surface *target);
static void layer_video_free_cb(void *data);
@@ -102,61 +105,133 @@ osc_generic_handler(const char *path, const char *types, lo_arg **argv,
return 1;
}
+static inline char *
+get_layer_name_from_path(const char *path)
+{
+ /* path is /layer/[name]/... */
+ char *name = strdup(path + 7);
+ *strchr(name, '/') = '\0';
+
+ return name;
+}
+
static int
osc_layer_delete(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
lo_server server = user_data;
+ char *name;
- /* path is /layer/[name]/delete */
- char *name = strdup(path + 7);
- *strchr(name, '/') = '\0';
-
+ name = get_layer_name_from_path(path);
layer_delete_by_name(name);
free(name);
lo_server_del_method(server, path, types);
- return 0;
+ return 1;
}
static inline void
-osc_add_layer_delete(lo_server server, const char *name)
+osc_add_layer_delete(lo_server server, const char *name,
+ lo_method_handler custom_delete)
{
char path[255];
snprintf(path, sizeof(path), "/layer/%s/delete", name);
+
+ if (custom_delete)
+ lo_server_add_method(server, path, "", custom_delete, server);
lo_server_add_method(server, path, "", osc_layer_delete, server);
}
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;
+
+ layer_image_alpha(ctx, argv[0]->f);
+ return 0;
+}
+
+static int
+osc_image_delete(const char *path, const char *types, lo_arg **argv,
+ int argc, void *data, void *user_data)
+{
+ lo_server server = user_data;
+ char buf[255], *name;
+
+ name = get_layer_name_from_path(path);
+ snprintf(buf, sizeof(buf), "/layer/%s/alpha", name);
+ lo_server_del_method(server, buf, "f");
+ free(name);
+
+ lo_server_del_method(server, path, types);
+
+ return 1;
+}
+
+static int
osc_image_new(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
lo_server server = user_data;
+ char buf[255];
struct layer_image *ctx = layer_image_new(&argv[2]->s);
if (layer_insert(argv[0]->i, &argv[1]->s, ctx,
layer_image_frame_cb, layer_image_free_cb))
return 0;
- osc_add_layer_delete(server, &argv[1]->s);
+ snprintf(buf, sizeof(buf), "/layer/%s/alpha", &argv[1]->s);
+ lo_server_add_method(server, buf, "f", osc_image_alpha, ctx);
+ osc_add_layer_delete(server, &argv[1]->s, osc_image_delete);
return 0;
}
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;
+
+ layer_video_alpha(ctx, argv[0]->f);
+ return 0;
+}
+
+static int
+osc_video_delete(const char *path, const char *types, lo_arg **argv,
+ int argc, void *data, void *user_data)
+{
+ lo_server server = user_data;
+ char buf[255], *name;
+
+ name = get_layer_name_from_path(path);
+ snprintf(buf, sizeof(buf), "/layer/%s/alpha", name);
+ lo_server_del_method(server, buf, "f");
+ free(name);
+
+ lo_server_del_method(server, path, types);
+
+ return 1;
+}
+
+static int
osc_video_new(const char *path, const char *types, lo_arg **argv,
int argc, void *data, void *user_data)
{
lo_server server = user_data;
+ char buf[255];
struct layer_video *ctx = layer_video_new(&argv[2]->s, NULL);
if (layer_insert(argv[0]->i, &argv[1]->s, ctx,
layer_video_frame_cb, layer_video_free_cb))
return 0;
- osc_add_layer_delete(server, &argv[1]->s);
+ snprintf(buf, sizeof(buf), "/layer/%s/alpha", &argv[1]->s);
+ lo_server_add_method(server, buf, "f", osc_video_alpha, ctx);
+ osc_add_layer_delete(server, &argv[1]->s, osc_video_delete);
return 0;
}
@@ -178,7 +253,7 @@ osc_rect_new(const char *path, const char *types, lo_arg **argv,
layer_rect_frame_cb, layer_rect_free_cb))
return 0;
- osc_add_layer_delete(server, &argv[1]->s);
+ osc_add_layer_delete(server, &argv[1]->s, NULL);
return 0;
}
@@ -210,7 +285,10 @@ osc_process_events(lo_server server)
* Image layers
*/
struct layer_image {
- SDL_Surface *surf;
+ SDL_Surface *surf_alpha; /* with per-surface alpha */
+ SDL_Surface *surf;
+
+ float alpha;
};
static struct layer_image *
@@ -220,6 +298,7 @@ layer_image_new(const char *file)
if (ctx) {
memset(ctx, 0, sizeof(*ctx));
+ ctx->alpha = 1.;
layer_image_change(ctx, file);
}
@@ -229,6 +308,11 @@ layer_image_new(const char *file)
static void
layer_image_change(struct layer_image *ctx, const char *file)
{
+ if (ctx->surf_alpha) {
+ SDL_FreeSurface(ctx->surf_alpha);
+ ctx->surf_alpha = NULL;
+ }
+
if (ctx->surf) {
SDL_FreeSurface(ctx->surf);
ctx->surf = NULL;
@@ -253,6 +337,65 @@ layer_image_change(struct layer_image *ctx, const char *file)
SDL_FreeSurface(ctx->surf);
ctx->surf = new;
}
+
+ layer_image_alpha(ctx, ctx->alpha);
+}
+
+static void
+layer_image_alpha(struct layer_image *ctx, float opacity)
+{
+ ctx->alpha = opacity;
+
+ if (!ctx->surf)
+ return;
+
+ if (!ctx->surf->format->Amask) {
+ Uint8 alpha = (Uint8)ceilf(opacity*SDL_ALPHA_OPAQUE);
+
+ if (alpha == SDL_ALPHA_OPAQUE)
+ SDL_SetAlpha(ctx->surf, 0, 0);
+ else
+ SDL_SetAlpha(ctx->surf, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
+
+ return;
+ }
+
+ if (opacity == 1.) {
+ if (ctx->surf_alpha) {
+ SDL_FreeSurface(ctx->surf_alpha);
+ ctx->surf_alpha = NULL;
+ }
+ return;
+ }
+
+ if (!ctx->surf_alpha)
+ ctx->surf_alpha = SDL_CreateRGBSurface(ctx->surf->flags,
+ ctx->surf->w, ctx->surf->h,
+ ctx->surf->format->BitsPerPixel,
+ ctx->surf->format->Rmask,
+ ctx->surf->format->Gmask,
+ ctx->surf->format->Bmask,
+ ctx->surf->format->Amask);
+
+ SDL_MAYBE_LOCK(ctx->surf_alpha);
+ SDL_MAYBE_LOCK(ctx->surf);
+
+ for (int i = 0; i < ctx->surf->w*ctx->surf->h; i++) {
+ Uint8 *src = ctx->surf->pixels;
+ Uint8 *dst = ctx->surf_alpha->pixels;
+ Uint8 r, g, b, a;
+ Uint32 v;
+
+ SDL_GetRGBA(*(Uint32 *)(src + i*ctx->surf->format->BytesPerPixel),
+ ctx->surf->format, &r, &g, &b, &a);
+ v = SDL_MapRGBA(ctx->surf_alpha->format,
+ r, g, b, (Uint8)ceilf(a*opacity));
+ memcpy(dst + i*ctx->surf_alpha->format->BytesPerPixel, &v,
+ ctx->surf_alpha->format->BytesPerPixel);
+ }
+
+ SDL_MAYBE_UNLOCK(ctx->surf);
+ SDL_MAYBE_UNLOCK(ctx->surf_alpha);
}
static void
@@ -261,7 +404,8 @@ layer_image_frame_cb(void *data, SDL_Surface *target)
struct layer_image *ctx = data;
if (ctx->surf)
- SDL_BlitSurface(ctx->surf, NULL, target, NULL);
+ SDL_BlitSurface(ctx->surf_alpha ? : ctx->surf,
+ NULL, target, NULL);
}
static void
@@ -269,6 +413,8 @@ layer_image_free_cb(void *data)
{
struct layer_image *ctx = data;
+ if (ctx->surf_alpha)
+ SDL_FreeSurface(ctx->surf_alpha);
if (ctx->surf)
SDL_FreeSurface(ctx->surf);
@@ -292,7 +438,7 @@ layer_video_lock_cb(void *data, void **p_pixels)
struct layer_video *ctx = data;
SDL_LockMutex(ctx->mutex);
- SDL_LockSurface(ctx->surf);
+ SDL_MAYBE_LOCK(ctx->surf);
*p_pixels = ctx->surf->pixels;
return NULL; /* picture identifier, not needed here */
@@ -305,7 +451,7 @@ layer_video_unlock_cb(void *data, void *id, void *const *p_pixels)
assert(id == NULL); /* picture identifier, not needed here */
- SDL_UnlockSurface(ctx->surf);
+ SDL_MAYBE_UNLOCK(ctx->surf);
SDL_UnlockMutex(ctx->mutex);
}
@@ -328,7 +474,7 @@ layer_video_new(const char *file, SDL_Color *key)
if (!ctx)
return NULL;
- ctx->surf = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h,
+ ctx->surf = SDL_CreateRGBSurface(SDL_HWSURFACE, screen->w, screen->h,
16, 0x001f, 0x07e0, 0xf800, 0);
ctx->mutex = SDL_CreateMutex();
@@ -371,12 +517,23 @@ layer_video_change(struct layer_video *ctx, const char *file, SDL_Color *key)
libvlc_video_set_format(ctx->mp, "RV16",
ctx->surf->w,
ctx->surf->h,
- ctx->surf->w*2);
+ ctx->surf->w*ctx->surf->format->BytesPerPixel);
libvlc_media_player_play(ctx->mp);
}
static void
+layer_video_alpha(struct layer_video *ctx, float opacity)
+{
+ Uint8 alpha = (Uint8)ceilf(opacity*SDL_ALPHA_OPAQUE);
+
+ if (alpha == SDL_ALPHA_OPAQUE)
+ SDL_SetAlpha(ctx->surf, 0, 0);
+ else
+ SDL_SetAlpha(ctx->surf, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
+}
+
+static void
layer_video_frame_cb(void *data, SDL_Surface *target)
{
struct layer_video *ctx = data;
@@ -579,6 +736,8 @@ main(int argc, char **argv)
sdl_process_events();
osc_process_events(osc_server);
+ SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
+
FOREACH_LAYER(cur)
cur->frame_cb(cur->data, screen);