Commit 717110af authored by Laurent Aimar's avatar Laurent Aimar

Added fully configurable shadow support (freetype).

The shadow is enabled by default.
parent 7b6b6bf8
...@@ -677,7 +677,7 @@ AC_SUBST(GNUGETOPT_LIBS) ...@@ -677,7 +677,7 @@ AC_SUBST(GNUGETOPT_LIBS)
if test "${SYS}" != "mingw32" -a "${SYS}" != "mingwce"; then if test "${SYS}" != "mingw32" -a "${SYS}" != "mingwce"; then
AC_CHECK_LIB(m,cos,[ AC_CHECK_LIB(m,cos,[
VLC_ADD_LIBS([adjust wave ripple psychedelic gradient a52tofloat32 dtstofloat32 x264 goom visual panoramix rotate noise grain scene kate flac lua chorus_flanger],[-lm]) VLC_ADD_LIBS([adjust wave ripple psychedelic gradient a52tofloat32 dtstofloat32 x264 goom visual panoramix rotate noise grain scene kate flac lua chorus_flanger freetype],[-lm])
]) ])
AC_CHECK_LIB(m,pow,[ AC_CHECK_LIB(m,pow,[
VLC_ADD_LIBS([avcodec avformat access_avio swscale postproc i420_rgb faad twolame equalizer spatializer param_eq libvlccore freetype mod mpc dmo quicktime realvideo qt4],[-lm]) VLC_ADD_LIBS([avcodec avformat access_avio swscale postproc i420_rgb faad twolame equalizer spatializer param_eq libvlccore freetype mod mpc dmo quicktime realvideo qt4],[-lm])
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif #endif
#include <math.h>
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_plugin.h> #include <vlc_plugin.h>
...@@ -128,6 +129,12 @@ static void Destroy( vlc_object_t * ); ...@@ -128,6 +129,12 @@ static void Destroy( vlc_object_t * );
#define OUTLINE_COLOR_TEXT N_("Outline color") #define OUTLINE_COLOR_TEXT N_("Outline color")
#define OUTLINE_THICKNESS_TEXT N_("Outline thickness") #define OUTLINE_THICKNESS_TEXT N_("Outline thickness")
#define SHADOW_OPACITY_TEXT N_("Shadow opacity")
#define SHADOW_COLOR_TEXT N_("Shadow color")
#define SHADOW_ANGLE_TEXT N_("Shadow angle")
#define SHADOW_DISTANCE_TEXT N_("Shadow distance")
static const int pi_sizes[] = { 20, 18, 16, 12, 6 }; static const int pi_sizes[] = { 20, 18, 16, 12, 6 };
static const char *const ppsz_sizes_text[] = { static const char *const ppsz_sizes_text[] = {
N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"), N_("Larger") }; N_("Smaller"), N_("Small"), N_("Normal"), N_("Large"), N_("Larger") };
...@@ -204,6 +211,20 @@ vlc_module_begin () ...@@ -204,6 +211,20 @@ vlc_module_begin ()
change_integer_list( pi_outline_thickness, ppsz_outline_thickness ) change_integer_list( pi_outline_thickness, ppsz_outline_thickness )
change_safe() change_safe()
add_integer_with_range( "freetype-shadow-opacity", 128, 0, 255,
SHADOW_OPACITY_TEXT, "", false )
change_safe()
add_integer( "freetype-shadow-color", 0x00000000, SHADOW_COLOR_TEXT,
"", false )
change_integer_list( pi_color_values, ppsz_color_descriptions )
change_safe()
add_float_with_range( "freetype-shadow-angle", -45, -360, 360,
SHADOW_ANGLE_TEXT, "", false )
change_safe()
add_float_with_range( "freetype-shadow-distance", 0.06, 0.0, 1.0,
SHADOW_DISTANCE_TEXT, "", false )
change_safe()
add_obsolete_integer( "freetype-effect" ); add_obsolete_integer( "freetype-effect" );
add_bool( "freetype-yuvp", false, YUVP_TEXT, add_bool( "freetype-yuvp", false, YUVP_TEXT,
...@@ -222,6 +243,7 @@ typedef struct ...@@ -222,6 +243,7 @@ typedef struct
{ {
FT_BitmapGlyph p_glyph; FT_BitmapGlyph p_glyph;
FT_BitmapGlyph p_outline; FT_BitmapGlyph p_outline;
FT_BitmapGlyph p_shadow;
uint32_t i_color; /* ARGB color */ uint32_t i_color; /* ARGB color */
int i_line_offset; /* underline/strikethrough offset */ int i_line_offset; /* underline/strikethrough offset */
int i_line_thickness; /* underline/strikethrough thickness */ int i_line_thickness; /* underline/strikethrough thickness */
...@@ -271,6 +293,11 @@ struct filter_sys_t ...@@ -271,6 +293,11 @@ struct filter_sys_t
uint8_t i_outline_opacity; uint8_t i_outline_opacity;
int i_outline_color; int i_outline_color;
float f_shadow_vector_x;
float f_shadow_vector_y;
uint8_t i_shadow_opacity;
int i_shadow_color;
int i_default_font_size; int i_default_font_size;
int i_display_height; int i_display_height;
char* psz_fontfamily; char* psz_fontfamily;
...@@ -820,8 +847,8 @@ static int RenderYUVA( filter_t *p_filter, ...@@ -820,8 +847,8 @@ static int RenderYUVA( filter_t *p_filter,
memset( p_picture->p[3].p_pixels, i_a, memset( p_picture->p[3].p_pixels, i_a,
p_picture->p[3].i_pitch * p_picture->p[3].i_lines ); p_picture->p[3].i_pitch * p_picture->p[3].i_lines );
/* Render outline glyphs in the first pass, and then the normal glyphs */ /* Render shadow then outline and then normal glyphs */
for( int g = 0; g < 2; g++ ) for( int g = 0; g < 3; g++ )
{ {
/* Render all lines */ /* Render all lines */
for( line_desc_t *p_line = p_line_head; p_line != NULL; p_line = p_line->p_next ) for( line_desc_t *p_line = p_line_head; p_line != NULL; p_line = p_line->p_next )
...@@ -841,16 +868,24 @@ static int RenderYUVA( filter_t *p_filter, ...@@ -841,16 +868,24 @@ static int RenderYUVA( filter_t *p_filter,
for( int i = 0; i < p_line->i_character_count; i++ ) for( int i = 0; i < p_line->i_character_count; i++ )
{ {
const line_character_t *ch = &p_line->p_character[i]; const line_character_t *ch = &p_line->p_character[i];
FT_BitmapGlyph p_glyph = g == 0 ? ch->p_outline : ch->p_glyph; FT_BitmapGlyph p_glyph = g == 0 ? ch->p_shadow : g == 1 ? ch->p_outline : ch->p_glyph;
if( !p_glyph ) if( !p_glyph )
continue; continue;
uint32_t i_color = ch->i_color; i_a = (ch->i_color >> 24) & 0xff;
i_a = (i_color >> 24) & 0xff; uint32_t i_color;
if( g == 0 ) switch (g) {
{ case 0:
i_a = i_a * p_sys->i_outline_opacity / 255; i_a = i_a * p_sys->i_shadow_opacity / 255;
i_color = p_sys->i_shadow_color;
break;
case 1:
i_a = i_a * p_sys->i_outline_opacity / 255;
i_color = p_sys->i_outline_color; i_color = p_sys->i_outline_color;
break;
default:
i_color = ch->i_color;
break;
} }
YUVFromRGB( i_color, &i_y, &i_u, &i_v ); YUVFromRGB( i_color, &i_y, &i_u, &i_v );
...@@ -863,7 +898,7 @@ static int RenderYUVA( filter_t *p_filter, ...@@ -863,7 +898,7 @@ static int RenderYUVA( filter_t *p_filter,
p_glyph ); p_glyph );
/* underline/strikethrough are only rendered for the normal glyph */ /* underline/strikethrough are only rendered for the normal glyph */
if( g == 1 && ch->i_line_thickness > 0 ) if( g == 2 && ch->i_line_thickness > 0 )
BlendYUVALine( p_picture, BlendYUVALine( p_picture,
i_glyph_x, i_glyph_y + p_glyph->top, i_glyph_x, i_glyph_y + p_glyph->top,
i_a, i_y, i_u, i_v, i_a, i_y, i_u, i_v,
...@@ -1467,6 +1502,8 @@ static void FreeLine( line_desc_t *p_line ) ...@@ -1467,6 +1502,8 @@ static void FreeLine( line_desc_t *p_line )
FT_Done_Glyph( (FT_Glyph)ch->p_glyph ); FT_Done_Glyph( (FT_Glyph)ch->p_glyph );
if( ch->p_outline ) if( ch->p_outline )
FT_Done_Glyph( (FT_Glyph)ch->p_outline ); FT_Done_Glyph( (FT_Glyph)ch->p_outline );
if( ch->p_shadow )
FT_Done_Glyph( (FT_Glyph)ch->p_shadow );
} }
free( p_line->p_character ); free( p_line->p_character );
...@@ -1614,11 +1651,13 @@ static bool FaceStyleEquals( const text_style_t *p_style1, ...@@ -1614,11 +1651,13 @@ static bool FaceStyleEquals( const text_style_t *p_style1,
static int GetGlyph( filter_t *p_filter, static int GetGlyph( filter_t *p_filter,
FT_Glyph *pp_glyph, FT_BBox *p_glyph_bbox, FT_Glyph *pp_glyph, FT_BBox *p_glyph_bbox,
FT_Glyph *pp_outline, FT_BBox *p_outline_bbox, FT_Glyph *pp_outline, FT_BBox *p_outline_bbox,
FT_Glyph *pp_shadow, FT_BBox *p_shadow_bbox,
FT_Face p_face, FT_Face p_face,
int i_glyph_index, int i_glyph_index,
int i_style_flags, int i_style_flags,
FT_Vector *p_pen ) FT_Vector *p_pen,
FT_Vector *p_pen_shadow )
{ {
if( FT_Load_Glyph( p_face, i_glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_DEFAULT ) && if( FT_Load_Glyph( p_face, i_glyph_index, FT_LOAD_NO_BITMAP | FT_LOAD_DEFAULT ) &&
FT_Load_Glyph( p_face, i_glyph_index, FT_LOAD_DEFAULT ) ) FT_Load_Glyph( p_face, i_glyph_index, FT_LOAD_DEFAULT ) )
...@@ -1648,21 +1687,36 @@ static int GetGlyph( filter_t *p_filter, ...@@ -1648,21 +1687,36 @@ static int GetGlyph( filter_t *p_filter,
{ {
outline = glyph; outline = glyph;
FT_Glyph_StrokeBorder( &outline, p_filter->p_sys->p_stroker, 0, 0 ); FT_Glyph_StrokeBorder( &outline, p_filter->p_sys->p_stroker, 0, 0 );
FT_Glyph_To_Bitmap( &outline, FT_RENDER_MODE_NORMAL, p_pen, 1 ); }
FT_Glyph_Get_CBox( outline, ft_glyph_bbox_pixels, p_outline_bbox ); FT_Glyph shadow = NULL;
if( p_filter->p_sys->i_shadow_opacity > 0 )
{
shadow = outline ? outline : glyph;
FT_Glyph_To_Bitmap( &shadow, FT_RENDER_MODE_NORMAL, p_pen_shadow, 0 );
FT_Glyph_Get_CBox( shadow, ft_glyph_bbox_pixels, p_shadow_bbox );
} }
*pp_outline = outline; *pp_shadow = shadow;
if( FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, p_pen, 1) ) if( FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, p_pen, 1) )
{ {
FT_Done_Glyph( glyph ); FT_Done_Glyph( glyph );
if( outline )
FT_Done_Glyph( outline );
if( shadow )
FT_Done_Glyph( shadow );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_pixels, p_glyph_bbox ); FT_Glyph_Get_CBox( glyph, ft_glyph_bbox_pixels, p_glyph_bbox );
*pp_glyph = glyph; *pp_glyph = glyph;
if( outline )
{
FT_Glyph_To_Bitmap( &outline, FT_RENDER_MODE_NORMAL, p_pen, 1 );
FT_Glyph_Get_CBox( outline, ft_glyph_bbox_pixels, p_outline_bbox );
}
*pp_outline = outline;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -1911,19 +1965,31 @@ static int ProcessLines( filter_t *p_filter, ...@@ -1911,19 +1965,31 @@ static int ProcessLines( filter_t *p_filter,
.x = pen.x + kerning.x, .x = pen.x + kerning.x,
.y = pen.y + kerning.y, .y = pen.y + kerning.y,
}; };
FT_Vector pen_shadow_new = {
.x = pen_new.x + p_sys->f_shadow_vector_x * (p_current_style->i_font_size << 6),
.y = pen_new.y + p_sys->f_shadow_vector_y * (p_current_style->i_font_size << 6),
};
FT_Glyph glyph; FT_Glyph glyph;
FT_BBox glyph_bbox; FT_BBox glyph_bbox;
FT_Glyph outline; FT_Glyph outline;
FT_BBox outline_bbox; FT_BBox outline_bbox;
FT_Glyph shadow;
FT_BBox shadow_bbox;
if( GetGlyph( p_filter, if( GetGlyph( p_filter,
&glyph, &glyph_bbox, &glyph, &glyph_bbox,
&outline, &outline_bbox, &outline, &outline_bbox,
p_current_face, i_glyph_index, p_glyph_style->i_style_flags, &pen_new ) ) &shadow, &shadow_bbox,
p_current_face, i_glyph_index, p_glyph_style->i_style_flags,
&pen_new, &pen_shadow_new ) )
goto next; goto next;
FixGlyph( glyph, &glyph_bbox, p_current_face, &pen_new ); FixGlyph( glyph, &glyph_bbox, p_current_face, &pen_new );
if( outline ) if( outline )
FixGlyph( outline, &outline_bbox, p_current_face, &pen_new ); FixGlyph( outline, &outline_bbox, p_current_face, &pen_new );
if( shadow )
FixGlyph( shadow, &shadow_bbox, p_current_face, &pen_shadow_new );
/* FIXME and what about outline */ /* FIXME and what about outline */
bool b_karaoke = pi_karaoke_bar && pi_karaoke_bar[i_index] != 0; bool b_karaoke = pi_karaoke_bar && pi_karaoke_bar[i_index] != 0;
...@@ -1964,6 +2030,8 @@ static int ProcessLines( filter_t *p_filter, ...@@ -1964,6 +2030,8 @@ static int ProcessLines( filter_t *p_filter,
BBoxEnlarge( &line_bbox_new, &glyph_bbox ); BBoxEnlarge( &line_bbox_new, &glyph_bbox );
if( outline ) if( outline )
BBoxEnlarge( &line_bbox_new, &outline_bbox ); BBoxEnlarge( &line_bbox_new, &outline_bbox );
if( shadow )
BBoxEnlarge( &line_bbox_new, &shadow_bbox );
b_break_line = i_index > i_start && b_break_line = i_index > i_start &&
line_bbox_new.xMax - line_bbox_new.xMin >= p_filter->fmt_out.video.i_visible_width; line_bbox_new.xMax - line_bbox_new.xMin >= p_filter->fmt_out.video.i_visible_width;
...@@ -1972,6 +2040,8 @@ static int ProcessLines( filter_t *p_filter, ...@@ -1972,6 +2040,8 @@ static int ProcessLines( filter_t *p_filter,
FT_Done_Glyph( glyph ); FT_Done_Glyph( glyph );
if( outline ) if( outline )
FT_Done_Glyph( outline ); FT_Done_Glyph( outline );
if( shadow )
FT_Done_Glyph( shadow );
break_point_t *p_bp = NULL; break_point_t *p_bp = NULL;
if( break_point.i_index > i_start ) if( break_point.i_index > i_start )
...@@ -1988,6 +2058,8 @@ static int ProcessLines( filter_t *p_filter, ...@@ -1988,6 +2058,8 @@ static int ProcessLines( filter_t *p_filter,
FT_Done_Glyph( (FT_Glyph)ch->p_glyph ); FT_Done_Glyph( (FT_Glyph)ch->p_glyph );
if( ch->p_outline ) if( ch->p_outline )
FT_Done_Glyph( (FT_Glyph)ch->p_outline ); FT_Done_Glyph( (FT_Glyph)ch->p_outline );
if( ch->p_shadow )
FT_Done_Glyph( (FT_Glyph)ch->p_shadow );
} }
p_line->i_character_count = p_bp->i_index - i_start; p_line->i_character_count = p_bp->i_index - i_start;
...@@ -2009,6 +2081,7 @@ static int ProcessLines( filter_t *p_filter, ...@@ -2009,6 +2081,7 @@ static int ProcessLines( filter_t *p_filter,
p_line->p_character[p_line->i_character_count++] = (line_character_t){ p_line->p_character[p_line->i_character_count++] = (line_character_t){
.p_glyph = (FT_BitmapGlyph)glyph, .p_glyph = (FT_BitmapGlyph)glyph,
.p_outline = (FT_BitmapGlyph)outline, .p_outline = (FT_BitmapGlyph)outline,
.p_shadow = (FT_BitmapGlyph)shadow,
.i_color = i_color, .i_color = i_color,
.i_line_offset = i_line_offset, .i_line_offset = i_line_offset,
.i_line_thickness = i_line_thickness, .i_line_thickness = i_line_thickness,
...@@ -2324,6 +2397,16 @@ static int Create( vlc_object_t *p_this ) ...@@ -2324,6 +2397,16 @@ static int Create( vlc_object_t *p_this )
p_sys->i_outline_color = var_InheritInteger( p_filter, "freetype-outline-color" ); p_sys->i_outline_color = var_InheritInteger( p_filter, "freetype-outline-color" );
p_sys->i_outline_color = __MAX( __MIN( p_sys->i_outline_color, 0xFFFFFF ), 0 ); p_sys->i_outline_color = __MAX( __MIN( p_sys->i_outline_color, 0xFFFFFF ), 0 );
p_sys->i_shadow_opacity = var_InheritInteger( p_filter, "freetype-shadow-opacity" );
p_sys->i_shadow_opacity = __MAX( __MIN( p_sys->i_shadow_opacity, 255 ), 0 );
p_sys->i_shadow_color = var_InheritInteger( p_filter, "freetype-shadow-color" );
p_sys->i_shadow_color = __MAX( __MIN( p_sys->i_shadow_color, 0xFFFFFF ), 0 );
float f_shadow_angle = var_InheritFloat( p_filter, "freetype-shadow-angle" );
float f_shadow_distance = var_InheritFloat( p_filter, "freetype-shadow-distance" );
f_shadow_distance = __MAX( __MIN( f_shadow_distance, 1 ), 0 );
p_sys->f_shadow_vector_x = f_shadow_distance * cos(2 * M_PI * f_shadow_angle / 360);
p_sys->f_shadow_vector_y = f_shadow_distance * sin(2 * M_PI * f_shadow_angle / 360);
#ifdef WIN32 #ifdef WIN32
/* Get Windows Font folder */ /* Get Windows Font folder */
wchar_t wdir[MAX_PATH]; wchar_t wdir[MAX_PATH];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment