From b224aef050b4f75b6325cb3b46b70e31d9116fa2 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Tue, 2 Oct 2012 20:33:35 +0200 Subject: added text layers based on SDL_ttf --- configure.ac | 7 +++ src/Makefile.am | 1 + src/layer_box.h | 2 - src/layer_image.cpp | 47 +------------- src/layer_text.cpp | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/layer_text.h | 101 ++++++++++++++++++++++++++++++ src/main.cpp | 48 +++++++++++++++ src/osc_graphics.h | 3 + src/osc_server.h | 2 + 9 files changed, 336 insertions(+), 48 deletions(-) create mode 100644 src/layer_text.cpp create mode 100644 src/layer_text.h diff --git a/configure.ac b/configure.ac index 5b728e0..3597213 100644 --- a/configure.ac +++ b/configure.ac @@ -71,6 +71,13 @@ PKG_CHECK_MODULES(SDL_GFX, [SDL_gfx], [ ]) ]) +AC_CHECK_LIB(SDL_ttf, TTF_Init, , [ + AC_MSG_ERROR([Required libSDL_ttf missing!]) +]) +AC_CHECK_HEADERS([SDL_ttf.h], , [ + AC_MSG_ERROR([Required libSDL_ttf header missing!]) +]) + PKG_CHECK_MODULES(LIBVLC, [libvlc >= 1.1.10], [ CFLAGS="$CFLAGS $LIBVLC_CFLAGS" CPPFLAGS="$CPPFLAGS $LIBVLC_CFLAGS" diff --git a/src/Makefile.am b/src/Makefile.am index bee1c2d..5c1a23c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,5 +13,6 @@ osc_graphics_SOURCES = main.cpp osc_graphics.h \ osc_server.cpp osc_server.h \ layer.cpp layer.h \ layer_box.cpp layer_box.h \ + layer_text.cpp layer_text.h \ layer_image.cpp layer_image.h \ layer_video.cpp layer_video.h diff --git a/src/layer_box.h b/src/layer_box.h index 1e4e5e3..157bb29 100644 --- a/src/layer_box.h +++ b/src/layer_box.h @@ -7,8 +7,6 @@ #include "osc_server.h" #include "layer.h" -#define COLOR_TYPES "iii" /* r, g, b */ - class LayerBox : public Layer { Sint16 x1, y1, x2, y2; Uint8 r, g, b, a; diff --git a/src/layer_image.cpp b/src/layer_image.cpp index 89eb795..7f338b2 100644 --- a/src/layer_image.cpp +++ b/src/layer_image.cpp @@ -8,50 +8,11 @@ #include #include -/* HACK: older SDL_gfx versions define GFX_ALPHA_ADJUST in the header */ -#define GFX_ALPHA_ADJUST \ - static __attribute__((unused)) GFX_ALPHA_ADJUST -#include -#undef GFX_ALPHA_ADJUST - #include "osc_graphics.h" #include "layer_image.h" Layer::CtorInfo LayerImage::ctor_info = {"image", "s" /* file */}; -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); -} - LayerImage::LayerImage(const char *name, SDL_Rect geo, float opacity, const char *file) : Layer(name), @@ -128,13 +89,7 @@ LayerImage::alpha(float opacity) 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); - } + rgba_blit_with_alpha(use_surf, surf_alpha, alpha); } void diff --git a/src/layer_text.cpp b/src/layer_text.cpp new file mode 100644 index 0000000..32b4963 --- /dev/null +++ b/src/layer_text.cpp @@ -0,0 +1,173 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include + +#include "osc_graphics.h" +#include "layer_text.h" + +Layer::CtorInfo LayerText::ctor_info = { + "text", + COLOR_TYPES "ss" /* r, g, b, text, font file */ +}; + +#define TTF_CLOSEFONT_SAFE(FONT) do { \ + if (FONT) { \ + TTF_CloseFont(FONT); \ + FONT = NULL; \ + } \ +} while (0) + +LayerText::LayerText(const char *name, SDL_Rect geo, float opacity, + SDL_Color color, const char *text, const char *file) + : Layer(name), ttf_font(NULL), surf_alpha(NULL), surf(NULL), + textv(NULL), filev(NULL) +{ + color_osc_id = register_method("color", COLOR_TYPES, + (OSCServer::MethodHandlerCb)color_osc); + text_osc_id = register_method("test", "s", + (OSCServer::MethodHandlerCb)text_osc); + font_osc_id = register_method("font", "s", + (OSCServer::MethodHandlerCb)font_osc); + style_osc_id = register_method("style", "s", + (OSCServer::MethodHandlerCb)style_osc); + + if (TTF_Init()) { + SDL_ERROR("TTF_Init"); + exit(EXIT_FAILURE); + } + + LayerText::geo(geo); + LayerText::alpha(opacity); + LayerText::color(color); + LayerText::text(text); + LayerText::font(file); +} + +void +LayerText::geo(SDL_Rect geo) +{ + int style = TTF_STYLE_NORMAL; + + geov = geo; + if (!geov.h) + geov.h = screen->h; + + if (!filev) + return; + + if (surf && (!geov.w || geov.w == surf->w) && geov.h == surf->h) + return; + + if (ttf_font) { + style = TTF_GetFontStyle(ttf_font); + TTF_CloseFont(ttf_font); + } + ttf_font = TTF_OpenFont(filev, geov.h); + + LayerText::style(style); +} + +void +LayerText::alpha(float opacity) +{ + Uint8 alpha = (Uint8)ceilf(opacity*SDL_ALPHA_OPAQUE); + + alphav = opacity; + + if (!surf) + return; + + if (alpha == SDL_ALPHA_OPAQUE) { + SDL_FREESURFACE_SAFE(surf_alpha); + return; + } + + if (!surf_alpha) { + 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); + } + + rgba_blit_with_alpha(surf, surf_alpha, alpha); +} + +void +LayerText::color(SDL_Color color) +{ + colorv = color; + + if (!ttf_font) + return; + + SDL_FREESURFACE_SAFE(surf_alpha); + SDL_FREESURFACE_SAFE(surf); + + surf = TTF_RenderText_Blended(ttf_font, textv, colorv); + + if (geov.w && surf->w != geov.w) { + SDL_Surface *new_surf; + + new_surf = zoomSurface(surf, (double)geov.w/surf->w, 1.0, + SMOOTHING_ON); + SDL_FreeSurface(surf); + surf = new_surf; + } + + alpha(alphav); +} + +void +LayerText::style_osc(LayerText *obj, lo_arg **argv) +{ + int style = TTF_STYLE_NORMAL; + + for (char *p = &argv[0]->s; *p; p++) { + switch (*p) { + case 'b': + style |= TTF_STYLE_BOLD; + break; + case 'i': + style |= TTF_STYLE_ITALIC; + break; + case 'u': + style |= TTF_STYLE_UNDERLINE; + break; + default: + break; + } + } + + obj->style(style); +} + +void +LayerText::frame(SDL_Surface *target) +{ + SDL_Surface *use_surf = surf_alpha ? : surf; + SDL_Rect dst_rect = {geov.x, geov.y, use_surf->w, use_surf->h}; + + SDL_BlitSurface(use_surf, NULL, target, &dst_rect); +} + +LayerText::~LayerText() +{ + unregister_method(style_osc_id); + unregister_method(font_osc_id); + unregister_method(text_osc_id); + unregister_method(color_osc_id); + + SDL_FREESURFACE_SAFE(surf); + SDL_FREESURFACE_SAFE(surf_alpha); + + TTF_CLOSEFONT_SAFE(ttf_font); +} diff --git a/src/layer_text.h b/src/layer_text.h new file mode 100644 index 0000000..745f54f --- /dev/null +++ b/src/layer_text.h @@ -0,0 +1,101 @@ +#ifndef __LAYER_TEXT_H +#define __LAYER_TEXT_H + +#include +#include + +#include +#include + +#include "osc_graphics.h" +#include "osc_server.h" +#include "layer.h" + +class LayerText : public Layer { + TTF_Font *ttf_font; + + SDL_Surface *surf_alpha; /* with per-surface alpha */ + SDL_Surface *surf; /* original text (possibly scaled) */ + + char *textv; + char *filev; + SDL_Color colorv; + SDL_Rect geov; + float alphav; + +public: + LayerText(const char *name, SDL_Rect geo, float opacity, + SDL_Color color, const char *text, const char *file); + + static CtorInfo ctor_info; + static Layer * + ctor_osc(const char *name, SDL_Rect geo, float opacity, lo_arg **argv) + { + SDL_Color color = { + (Uint8)argv[0]->i, (Uint8)argv[1]->i, (Uint8)argv[2]->i + }; + return new LayerText(name, geo, opacity, color, + &argv[3]->s, &argv[4]->s); + } + + ~LayerText(); + + void frame(SDL_Surface *target); + +private: + void geo(SDL_Rect geo); + void alpha(float opacity); + + void color(SDL_Color color); + OSCServer::MethodHandlerId *color_osc_id; + static void + color_osc(LayerText *obj, lo_arg **argv) + { + SDL_Color color = { + (Uint8)argv[0]->i, (Uint8)argv[1]->i, (Uint8)argv[2]->i + }; + obj->color(color); + } + + inline void + text(const char *text) + { + free(textv); + textv = strdup(text); + + color(colorv); + } + OSCServer::MethodHandlerId *text_osc_id; + static void + text_osc(LayerText *obj, lo_arg **argv) + { + obj->text(&argv[0]->s); + } + + inline void + font(const char *file) + { + free(filev); + filev = strdup(file); + + geo(geov); + } + OSCServer::MethodHandlerId *font_osc_id; + static void + font_osc(LayerText *obj, lo_arg **argv) + { + obj->font(&argv[0]->s); + } + + inline void + style(int style) + { + TTF_SetFontStyle(ttf_font, style); + + color(colorv); + } + OSCServer::MethodHandlerId *style_osc_id; + static void style_osc(LayerText *obj, lo_arg **argv); +}; + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index f055db5..f9c3eb8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,11 +9,18 @@ #include #include +/* HACK: older SDL_gfx versions define GFX_ALPHA_ADJUST in the header */ +#define GFX_ALPHA_ADJUST \ + static __attribute__((unused)) GFX_ALPHA_ADJUST +#include +#undef GFX_ALPHA_ADJUST + #include "osc_graphics.h" #include "osc_server.h" #include "layer.h" #include "layer_box.h" +#include "layer_text.h" #include "layer_image.h" #include "layer_video.h" @@ -48,6 +55,46 @@ LayerList layers; int config_dump_osc = 0; +void +rgba_blit_with_alpha(SDL_Surface *src_surf, SDL_Surface *dst_surf, Uint8 alpha) +{ + if (alpha == SDL_ALPHA_TRANSPARENT) { + SDL_FillRect(dst_surf, NULL, + SDL_MapRGBA(dst_surf->format, + 0, 0, 0, SDL_ALPHA_TRANSPARENT)); + return; + } + + 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); +} + static inline void sdl_process_events(void) { @@ -223,6 +270,7 @@ main(int argc, char **argv) REGISTER_LAYER(LayerImage); REGISTER_LAYER(LayerVideo); REGISTER_LAYER(LayerBox); + REGISTER_LAYER(LayerText); osc_server.start(); diff --git a/src/osc_graphics.h b/src/osc_graphics.h index 2a08678..c36ef54 100644 --- a/src/osc_graphics.h +++ b/src/osc_graphics.h @@ -43,4 +43,7 @@ extern SDL_Surface *screen; extern int config_dump_osc; +void rgba_blit_with_alpha(SDL_Surface *src_surf, SDL_Surface *dst_surf, + Uint8 alpha = SDL_ALPHA_TRANSPARENT); + #endif diff --git a/src/osc_server.h b/src/osc_server.h index f6d0c51..0687d1c 100644 --- a/src/osc_server.h +++ b/src/osc_server.h @@ -102,4 +102,6 @@ public: #define GEO_TYPES "iiii" /* x, y, width, height */ #define NEW_LAYER_TYPES "is" GEO_TYPES "f" /* position, name, GEO, alpha */ +#define COLOR_TYPES "iii" /* r, g, b */ + #endif -- cgit v1.2.3