X-Git-Url: http://git.cinelerra-gg.org/git/?p=goodguy%2Fhistory.git;a=blobdiff_plain;f=cinelerra-5.1%2Fplugins%2Ftitler%2Ftitler.C;h=5086fea00d029d6101dae87de2b60ae5229449ed;hp=2a11a98e90374ddbdbdf2c814afb5e42c9c30da6;hb=7e5a0760f40ff787cc3d93cb7768a901ebe52809;hpb=25bafacda1fe9d8a9520cad451547a75d934c1bb diff --git a/cinelerra-5.1/plugins/titler/titler.C b/cinelerra-5.1/plugins/titler/titler.C index 2a11a98e..5086fea0 100644 --- a/cinelerra-5.1/plugins/titler/titler.C +++ b/cinelerra-5.1/plugins/titler/titler.C @@ -25,7 +25,6 @@ // Additional support for UTF-8 by // Paolo Rampino aka Akirad - #include "asset.h" #include "bccmodels.h" #include "bcsignals.h" @@ -46,12 +45,13 @@ #include "language.h" #include "mwindow.inc" #include "overlayframe.h" +#include "plugin.h" #include "renderengine.h" #include "titler.h" #include "titlerwindow.h" #include "transportque.h" #include "vrender.h" - +#include "workarounds.h" #include #include @@ -60,10 +60,10 @@ #include #include #include -#include #include #include +#define FIXED_FONT "bitstream vera sans mono (bitstream)" #define SMALL (1.0 / 64.0) #define MAX_FLT 3.40282347e+38 @@ -78,40 +78,42 @@ REGISTER_PLUGIN(TitleMain) #endif #define DEFAULT_TIMECODEFORMAT TIME_HMS +static inline int kw_strcmp(const char *ap, const char *bp) { + return !strcmp(ap, bp) ? 0 : strcmp(ap,_(bp)); +} + TitleConfig::TitleConfig() { - style = 0; + strcpy(font, "fixed"); + strcpy(encoding, DEFAULT_ENCODING); + style = FONT_ALIAS; + size = 24; color = BLACK; alpha = 0xff; + outline_size = 0.; + outline_color = WHITE; outline_alpha = 0xff; - size = 24; + color_stroke = 0xff0000; + stroke_width = 0.0; motion_strategy = NO_MOTION; - loop = 0; line_pitch = 0; + loop = 0; hjustification = JUSTIFY_CENTER; vjustification = JUSTIFY_MID; - fade_in = 0.0; - fade_out = 0.0; + fade_in = 0.0; fade_out = 0.0; + pixels_per_second = 100.0; + wtext[0] = 0; wlen = 0; title_x = title_y = 0.0; title_w = title_h = 0; - dropshadow = 2; - strcpy(font, "fixed"); - strcpy(encoding, DEFAULT_ENCODING); - timecode_format = DEFAULT_TIMECODEFORMAT; - pixels_per_second = 1.0; - timecode = 0; - stroke_width = 1.0; - wtext[0] = 0; wlen = 0; - color_stroke = 0xff0000; - outline_color = WHITE; - background = 0; - strcpy(background_path, ""); - - outline_size = 0; - window_w = 720; + window_w = 860; window_h = 460; next_keyframe_position = 0; prev_keyframe_position = 0; + timecode = 0; + dropshadow = 2; + background = 0; + strcpy(background_path, ""); + timecode_format = DEFAULT_TIMECODEFORMAT; drag = 0; loop_playback = 0; } @@ -123,102 +125,118 @@ TitleConfig::~TitleConfig() int TitleConfig::equivalent(TitleConfig &that) { return !strcasecmp(font, that.font) && + !strcasecmp(encoding, that.encoding) && style == that.style && size == that.size && color == that.color && - color_stroke == that.color_stroke && - stroke_width == that.stroke_width && - outline_color == that.outline_color && alpha == that.alpha && + outline_size == that.outline_size && + outline_color == that.outline_color && outline_alpha == that.outline_alpha && - EQUIV(pixels_per_second, that.pixels_per_second) && - motion_strategy == that.motion_strategy && - loop == that.loop && + color_stroke == that.color_stroke && + stroke_width == that.stroke_width && +// dont require redraw for these +// motion_strategy == that.motion_strategy && line_pitch == that.line_pitch && +// loop == that.loop && hjustification == that.hjustification && vjustification == that.vjustification && - fade_in == that.fade_in && fade_out == that.fade_out && - title_x == that.title_x && title_y == that.title_y && +// fade_in == that.fade_in && fade_out == that.fade_out && +// EQUIV(pixels_per_second, that.pixels_per_second) && + wlen == that.wlen && + !memcmp(wtext, that.wtext, wlen * sizeof(wchar_t)) && +// title_x == that.title_x && title_y == that.title_y && title_w == that.title_w && title_h == that.title_h && - dropshadow == that.dropshadow && +// window_w == that.window_w && window_h == that.window_h && timecode == that.timecode && + dropshadow == that.dropshadow && + background == that.background && + !strcmp(background_path, that.background_path) && timecode_format == that.timecode_format && - outline_size == that.outline_size && - !strcasecmp(encoding, that.encoding) && - wlen == that.wlen && - !memcmp(wtext, that.wtext, wlen * sizeof(wchar_t)); +// drag == that.drag && + loop_playback == that.loop_playback; } void TitleConfig::copy_from(TitleConfig &that) { strcpy(font, that.font); + strcpy(encoding, that.encoding); style = that.style; size = that.size; color = that.color; - color_stroke = that.color_stroke; - stroke_width = that.stroke_width; - outline_color = that.outline_color; alpha = that.alpha; + outline_size = that.outline_size; + outline_color = that.outline_color; outline_alpha = that.outline_alpha; - pixels_per_second = that.pixels_per_second; + color_stroke = that.color_stroke; + stroke_width = that.stroke_width; motion_strategy = that.motion_strategy; - loop = that.loop; line_pitch = that.line_pitch; + loop = that.loop; hjustification = that.hjustification; vjustification = that.vjustification; fade_in = that.fade_in; fade_out = that.fade_out; - title_x = that.title_x; - title_y = that.title_y; - title_w = that.title_w; - title_h = that.title_h; - dropshadow = that.dropshadow; + pixels_per_second = that.pixels_per_second; + wlen = that.wlen; + memcpy(wtext, that.wtext, that.wlen * sizeof(wchar_t)); + title_x = that.title_x; title_y = that.title_y; + title_w = that.title_w; title_h = that.title_h; + window_w = that.window_w; window_h = that.window_h; timecode = that.timecode; + dropshadow = that.dropshadow; + background = that.background; + strcpy(background_path, that.background_path); timecode_format = that.timecode_format; - outline_size = that.outline_size; - strcpy(encoding, that.encoding); - memcpy(wtext, that.wtext, that.wlen * sizeof(wchar_t)); - wlen = that.wlen; - window_w = that.window_w; - window_h = that.window_h; + drag = that.drag; + loop_playback = that.loop_playback; } void TitleConfig::interpolate(TitleConfig &prev, TitleConfig &next, int64_t prev_frame, int64_t next_frame, int64_t current_frame) { + double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame); + double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame); strcpy(font, prev.font); strcpy(encoding, prev.encoding); style = prev.style; size = prev.size; color = prev.color; - color_stroke = prev.color_stroke; - stroke_width = prev.stroke_width; - outline_color = prev.outline_color; alpha = prev.alpha; + outline_size = prev.outline_size; + outline_color = prev.outline_color; outline_alpha = prev.outline_alpha; + color_stroke = prev.color_stroke; + stroke_width = prev.stroke_width; motion_strategy = prev.motion_strategy; - loop = prev.loop; line_pitch = prev.line_pitch; + loop = prev.loop; hjustification = prev.hjustification; vjustification = prev.vjustification; fade_in = prev.fade_in; fade_out = prev.fade_out; - outline_size = prev.outline_size; pixels_per_second = prev.pixels_per_second; - memcpy(wtext, prev.wtext, prev.wlen * sizeof(wchar_t)); wlen = prev.wlen; + memcpy(wtext, prev.wtext, prev.wlen * sizeof(wchar_t)); wtext[wlen] = 0; - - double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame); - double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame); - this->title_x = prev.title_x * prev_scale + next.title_x * next_scale; - this->title_y = prev.title_y * prev_scale + next.title_y * next_scale; -// this->title_x = prev.title_x; -// this->title_y = prev.title_y; + this->title_x = prev.title_x == next.title_x ? prev.title_x : + prev.title_x * prev_scale + next.title_x * next_scale; + this->title_y = prev.title_y == next.title_y ? prev.title_y : + prev.title_y * prev_scale + next.title_y * next_scale; + this->title_w = prev.title_w == next.title_w ? prev.title_w : + prev.title_w * prev_scale + next.title_w * next_scale; + this->title_h = prev.title_h == next.title_h ? prev.title_h : + prev.title_h * prev_scale + next.title_h * next_scale; + window_w = prev.window_w; + window_h = prev.window_h; timecode = prev.timecode; + this->dropshadow = prev.dropshadow == next.dropshadow ? prev.dropshadow : + prev.dropshadow * prev_scale + next.dropshadow * next_scale; + background = prev.background; + strcpy(background_path, prev.background_path); timecode_format = prev.timecode_format; - this->dropshadow = prev.dropshadow * prev_scale + next.dropshadow * next_scale; -// this->dropshadow = prev.dropshadow; + drag = prev.drag; + loop_playback = prev.loop_playback; } void TitleConfig::to_wtext(const char *from_enc, const char *text, int tlen) @@ -272,13 +290,28 @@ GlyphUnit::GlyphUnit(TitleMain *plugin, GlyphEngine *server) GlyphUnit::~GlyphUnit() { if( freetype_library ) - FT_Done_FreeType(freetype_library); + ft_Done_FreeType(freetype_library); +} + +static inline void to_mono(VFrame *data) +{ + if( !data ) return; + int w = data->get_w(), h = data->get_h(); + uint8_t **rows = data->get_rows(); + for( int y=0; y= 0x80 ? 0xff : 0; + } } void GlyphUnit::process_package(LoadPackage *package) { GlyphPackage *pkg = (GlyphPackage*)package; TitleGlyph *glyph = pkg->glyph; + BC_Resources *resources = BC_WindowBase::get_resources(); + if( resources->font_debug ) + printf("GlyphUnit load glyph (%s) %04x, '%c'\n", glyph->font->displayname, + (unsigned)glyph->char_code, (unsigned)glyph->char_code); int result = 0; char new_path[BCTEXTLEN]; if( plugin->load_freetype_face(freetype_library, freetype_face, glyph->font->path) ) { @@ -286,22 +319,24 @@ void GlyphUnit::process_package(LoadPackage *package) glyph->font->path); result = 1; } - if( !result ) { - int gindex = FT_Get_Char_Index(freetype_face, glyph->char_code); - -//printf("GlyphUnit::process_package 1 %c\n", glyph->char_code); -// Char not found + int gindex = ft_Get_Char_Index(freetype_face, glyph->char_code); + if( !gindex && !freetype_face->charmap && // if no default charmap + freetype_face->charmaps && freetype_face->charmaps[0] && + !ft_Select_Charmap(freetype_face, freetype_face->charmaps[0]->encoding) ) { + gindex = ft_Get_Char_Index(freetype_face, glyph->char_code); + } if( gindex == 0 ) { - BC_Resources *resources = BC_WindowBase::get_resources(); +printf("GlyphUnit::process_package 1 glyph not found (%s) %04x, '%c'\n", + glyph->font->displayname, (unsigned)glyph->char_code, (unsigned)glyph->char_code); // Search replacement font if( resources->find_font_by_char(glyph->char_code, new_path, freetype_face) ) { plugin->load_freetype_face(freetype_library, freetype_face, new_path); - gindex = FT_Get_Char_Index(freetype_face, glyph->char_code); + gindex = ft_Get_Char_Index(freetype_face, glyph->char_code); } } - FT_Set_Pixel_Sizes(freetype_face, glyph->size, 0); + ft_Set_Pixel_Sizes(freetype_face, glyph->size, 0); if( gindex == 0 ) { // carrige return @@ -331,9 +366,9 @@ void GlyphUnit::process_package(LoadPackage *package) FT_Glyph glyph_image; FT_BBox bbox; FT_Bitmap bm; - FT_Load_Glyph(freetype_face, gindex, FT_LOAD_DEFAULT); - FT_Get_Glyph(freetype_face->glyph, &glyph_image); - FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph_image)->outline, &bbox); + ft_Load_Glyph(freetype_face, gindex, FT_LOAD_DEFAULT); + ft_Get_Glyph(freetype_face->glyph, &glyph_image); + ft_Outline_Get_BBox(&((FT_OutlineGlyph) glyph_image)->outline, &bbox); // printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n", // bbox.xMin,bbox.xMax, bbox.yMin, bbox.yMax); @@ -354,12 +389,12 @@ void GlyphUnit::process_package(LoadPackage *package) glyph->data = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); glyph->data->clear_frame(); bm.buffer = glyph->data->get_data(); - FT_Outline_Translate(&((FT_OutlineGlyph) glyph_image)->outline, + ft_Outline_Translate(&((FT_OutlineGlyph) glyph_image)->outline, - bbox.xMin, - bbox.yMin); - FT_Outline_Get_Bitmap( freetype_library, + ft_Outline_Get_Bitmap( freetype_library, &((FT_OutlineGlyph) glyph_image)->outline, &bm); - FT_Done_Glyph(glyph_image); + ft_Done_Glyph(glyph_image); } else { // Outline desired and glyph found @@ -370,14 +405,14 @@ void GlyphUnit::process_package(LoadPackage *package) FT_BBox bbox; FT_UInt npoints, ncontours; - FT_Load_Glyph(freetype_face, gindex, FT_LOAD_DEFAULT); - FT_Get_Glyph(freetype_face->glyph, &glyph_image); + ft_Load_Glyph(freetype_face, gindex, FT_LOAD_DEFAULT); + ft_Get_Glyph(freetype_face->glyph, &glyph_image); // check if the outline is ok (non-empty); - FT_Outline_Get_BBox(&((FT_OutlineGlyph) glyph_image)->outline, &bbox); + ft_Outline_Get_BBox(&((FT_OutlineGlyph) glyph_image)->outline, &bbox); if( bbox.xMin == 0 && bbox.xMax == 0 && bbox.yMin == 0 && bbox.yMax == 0 ) { - FT_Done_Glyph(glyph_image); + ft_Done_Glyph(glyph_image); glyph->width = 0; glyph->height = 0; glyph->left = 0; glyph->top = 0; glyph->right = 0; glyph->bottom = 0; @@ -391,18 +426,18 @@ void GlyphUnit::process_package(LoadPackage *package) return; } #if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 2) - FT_Stroker_New(freetype_library, &stroker); + ft_Stroker_New(freetype_library, &stroker); #else - FT_Stroker_New(((FT_LibraryRec *)freetype_library)->memory, &stroker); + ft_Stroker_New(((FT_LibraryRec *)freetype_library)->memory, &stroker); #endif - FT_Stroker_Set(stroker, (int)(plugin->config.stroke_width * 64), + ft_Stroker_Set(stroker, (int)(plugin->config.stroke_width * 64), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); - FT_Stroker_ParseOutline(stroker, &((FT_OutlineGlyph) glyph_image)->outline,1); - FT_Stroker_GetCounts(stroker,&npoints, &ncontours); + ft_Stroker_ParseOutline(stroker, &((FT_OutlineGlyph) glyph_image)->outline,1); + ft_Stroker_GetCounts(stroker,&npoints, &ncontours); if( npoints == 0 && ncontours == 0 ) { // this never happens, but FreeType has a bug regarding Linotype's Palatino font - FT_Stroker_Done(stroker); - FT_Done_Glyph(glyph_image); + ft_Stroker_Done(stroker); + ft_Done_Glyph(glyph_image); glyph->width = 0; glyph->height = 0; glyph->left = 0; glyph->top = 0; glyph->right = 0; glyph->bottom = 0; @@ -416,13 +451,13 @@ void GlyphUnit::process_package(LoadPackage *package) return; }; - FT_Outline_New(freetype_library, npoints, ncontours, &outline); + ft_Outline_New(freetype_library, npoints, ncontours, &outline); outline.n_points=0; outline.n_contours=0; - FT_Stroker_Export (stroker, &outline); - FT_Outline_Get_BBox(&outline, &bbox); - FT_Outline_Translate(&outline, - bbox.xMin, - bbox.yMin); - FT_Outline_Translate(&((FT_OutlineGlyph) glyph_image)->outline, + ft_Stroker_Export(stroker, &outline); + ft_Outline_Get_BBox(&outline, &bbox); + ft_Outline_Translate(&outline, - bbox.xMin, - bbox.yMin); + ft_Outline_Translate(&((FT_OutlineGlyph) glyph_image)->outline, - bbox.xMin, - bbox.yMin + (int)(plugin->config.stroke_width*32)); // printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n" @@ -458,19 +493,24 @@ void GlyphUnit::process_package(LoadPackage *package) glyph->data_stroke->clear_frame(); // for debugging memset( glyph->data_stroke->get_data(), 60, glyph->pitch * glyph->height); bm.buffer=glyph->data->get_data(); - FT_Outline_Get_Bitmap( freetype_library, + ft_Outline_Get_Bitmap( freetype_library, &((FT_OutlineGlyph) glyph_image)->outline, &bm); bm.buffer=glyph->data_stroke->get_data(); - FT_Outline_Get_Bitmap( freetype_library, + ft_Outline_Get_Bitmap( freetype_library, &outline, &bm); - FT_Outline_Done(freetype_library,&outline); - FT_Stroker_Done(stroker); - FT_Done_Glyph(glyph_image); + ft_Outline_Done(freetype_library,&outline); + ft_Stroker_Done(stroker); + ft_Done_Glyph(glyph_image); //printf("GlyphUnit::process_package 2\n"); } + + if( !(glyph->style & FONT_ALIAS) ) { + to_mono(glyph->data); + to_mono(glyph->data_stroke); + } } } @@ -523,10 +563,7 @@ TitleUnit::TitleUnit(TitleMain *plugin, TitleEngine *server) static void get_mask_colors(int rgb, int color_model, int &rr, int &gg, int &bb) { int r = 0xff & (rgb>>16), g = 0xff & (rgb>>8), b = 0xff & (rgb>>0); - if( BC_CModels::is_yuv(color_model) ) { - bc_rgb2yuv(r,g,b, r,g,b); - bclamp(r,0,255); bclamp(g,0,255); bclamp(b,0,255); - } + if( BC_CModels::is_yuv(color_model) ) YUV::yuv.rgb_to_yuv_8(r,g,b); rr = r; gg = g; bb = b; } @@ -555,7 +592,7 @@ void TitleUnit::draw_frame(int mode, VFrame *dst, VFrame *src, int x, int y) while( y_inp < inp_h && y_out < out_h ) { uint8_t *inp = inp_rows[y_inp], *out = out_rows[y_out]; for( int xin=x_inp,xout=x_out*4+3; xin= out_a ) { // crayola for top draw + out[xout+0] = r; out[xout+1] = g; out[xout+2] = b; + out[xout+3] = alpha * in_a / max; + } + else { + int i_r = r, i_g = g-ofs, i_b = b-ofs; + int o_r = out[xout+0], o_g = out[xout+1]-ofs, o_b = out[xout+2]-ofs; + out[xout+0] = COLOR_NORMAL(max, i_r, in_a, o_r, out_a); + out[xout+1] = COLOR_NORMAL(max, i_g, in_a, o_g, out_a) + ofs; + out[xout+2] = COLOR_NORMAL(max, i_b, in_a, o_b, out_a) + ofs; + out[xout+3] = alpha * STD_ALPHA(max, in_a, out_a) / max; + } } ++y_inp; ++y_out; } @@ -581,13 +625,22 @@ void TitleUnit::draw_frame(int mode, VFrame *dst, VFrame *src, int x, int y) while( y_inp < inp_h && y_out < out_h ) { uint8_t *inp = inp_rows[y_inp], *out = out_rows[y_out]; for( int xin=x_inp,xout=x_out*4+0; xin= out_a ) { + int i_r = inp[xinp+0], i_g = inp[xinp+1], i_b = inp[xinp+2]; + out[xout+0] = i_r; out[xout+1] = i_g; out[xout+2] = i_b; + out[xout+3] = alpha * in_a / max; + } + else { + int i_r = inp[xinp+0], i_g = inp[xinp+1]-ofs, i_b = inp[xinp+2]-ofs; + int o_r = out[xout+0], o_g = out[xout+1]-ofs, o_b = out[xout+2]-ofs; + out[xout+0] = COLOR_NORMAL(max, i_r, in_a, o_r, out_a); + out[xout+1] = COLOR_NORMAL(max, i_g, in_a, o_g, out_a) + ofs; + out[xout+2] = COLOR_NORMAL(max, i_b, in_a, o_b, out_a) + ofs; + out[xout+3] = alpha * STD_ALPHA(max, in_a, out_a) / max; + } } ++y_inp; ++y_out; } @@ -657,69 +710,6 @@ LoadPackage* TitleEngine::new_package() return new TitlePackage; } -void TitleTranslateUnit::translation_array_f(transfer_table_f* &table, - float in_x1, float in_x2, int in_total, - float out_x1, float out_x2, int out_total, - int &x1_out, int &x2_out) -{ - int out_w; - //float offset = out_x1 - in_x1; - - x1_out = (int)out_x1; - x2_out = MIN((int)ceil(out_x2), out_total); - if( x1_out >= x2_out ) return; - - out_w = x2_out - x1_out; - table = new transfer_table_f[out_w]; - bzero(table, sizeof(transfer_table_f) * out_w); - - float in_x = in_x1; - for( int out_x=x1_out; out_xin_x1 = (int)in_x; - entry->in_x2 = (int)in_x + 1; - -// Get fraction of output pixel to fill - entry->output_fraction = 1; - - if( out_x1 > out_x ) { - entry->output_fraction -= out_x1 - out_x; - } - - if( out_x2 < out_x + 1 ) { - entry->output_fraction = (out_x2 - out_x); - } - -// Advance in_x until out_x_fraction is filled - float out_x_fraction = entry->output_fraction; - float in_x_fraction = floor(in_x + 1) - in_x; - - if( out_x_fraction <= in_x_fraction ) { - entry->in_fraction1 = out_x_fraction; - entry->in_fraction2 = 0.0; - in_x += out_x_fraction; - } - else { - entry->in_fraction1 = in_x_fraction; - in_x += out_x_fraction; - entry->in_fraction2 = in_x - floor(in_x); - } - -// Clip in_x and zero out fraction. This doesn't work for YUV. - if( entry->in_x2 >= in_total ) { - entry->in_x2 = in_total - 1; - entry->in_fraction2 = 0.0; - } - - if( entry->in_x1 >= in_total ) { - entry->in_x1 = in_total - 1; - entry->in_fraction1 = 0.0; - } - } -} - - // Copy a single character to the text mask TitleOutlinePackage::TitleOutlinePackage() @@ -745,16 +735,16 @@ void TitleOutlineUnit::process_package(LoadPackage *package) unsigned char **text_rows = plugin->text_mask->get_rows(); int mask_w1 = plugin->text_mask->get_w()-1; int mask_h1 = plugin->text_mask->get_h()-1; - int ofs = plugin->config.outline_size; + int oln_sz = plugin->config.outline_size; if( engine->pass == 0 ) { // get max alpha under outline size macropixel for( int y=pkg->y1, my=pkg->y2; ytext_mask->get_w(); xplugin = plugin; -} - -void TitleTranslate::run_packages() -{ -// Generate scaling tables - delete [] x_table; x_table = 0; - delete [] y_table; y_table = 0; - - float in_w = xlat_mask->get_w(); - float in_h = xlat_mask->get_h(); - float ix1 = 0, ix2 = ix1 + in_w; - float iy1 = 0, iy2 = iy1 + in_h; - - float out_w = plugin->output->get_w(); - float out_h = plugin->output->get_h(); - float x1 = plugin->title_x, x2 = x1 + plugin->title_w; - float y1 = plugin->title_y, y2 = y1 + plugin->title_h; - bclamp(x1, 0, out_w); bclamp(y1, 0, out_h); - bclamp(x2, 0, out_w); bclamp(y2, 0, out_h); - - float ox1 = plugin->title_x + plugin->text_x - plugin->text_x1 + plugin->mask_x1, ox2 = ox1 + in_w; - float oy1 = plugin->title_y + plugin->text_y - plugin->text_y1 + plugin->mask_y1, oy2 = oy1 + in_h; - if( ox1 < x1 ) { ix1 -= (ox1-x1); ox1 = x1; } - if( oy1 < y1 ) { iy1 -= (oy1-y1); oy1 = y1; } - if( ox2 > x2 ) { ix2 -= (ox2-x2); ox2 = x2; } - if( oy2 > y2 ) { iy2 -= (oy2-x2); oy2 = y2; } -#if 0 -printf("TitleTranslate text txy=%7.2f,%-7.2f\n" - " mxy1=%7d,%-7d mxy2=%7d,%-7d\n" - " xy1=%7.2f,%-7.2f xy2=%7.2f,%-7.2f\n" - " ixy1=%7.2f,%-7.2f ixy2=%7.2f,%-7.2f\n" - " oxy1=%7.2f,%-7.2f oxy2=%7.2f,%-7.2f\n", - plugin->text_x, plugin->text_y, - plugin->mask_x1, plugin->mask_y1, plugin->mask_x2, plugin->mask_y2, - x1,y1, x2,y2, ix1,iy1, ix2,iy2, ox1,oy1, ox2,oy2); -#endif - out_x1 = out_x2 = out_y1 = out_y2 = 0; - TitleTranslateUnit::translation_array_f(x_table, - ix1, ix2, in_w, ox1, ox2, out_w, out_x1, out_x2); - TitleTranslateUnit::translation_array_f(y_table, - iy1, iy2, in_h, oy1, oy2, out_h, out_y1, out_y2); - - process_packages(); -} - - - -#define TRANSLATE(type, max, components, ofs) { \ - unsigned char **in_rows = server->xlat_mask->get_rows(); \ - type **out_rows = (type**)plugin->output->get_rows(); \ - \ - for( int y=pkg->y1; yy2; ++y ) { \ - int in_y1 = server->y_table[y].in_x1; \ - int in_y2 = server->y_table[y].in_x2; \ - float y_f1 = server->y_table[y].in_fraction1; \ - float y_f2 = server->y_table[y].in_fraction2; \ - unsigned char *in_row1 = in_rows[in_y1]; \ - unsigned char *in_row2 = in_rows[in_y2]; \ - type *out_row = out_rows[y + server->out_y1]; \ - for( int i=0,x=server->out_x1; xout_x2; ++i,++x ) { \ - int in_x1 = 4*server->x_table[i].in_x1; \ - int in_x2 = 4*server->x_table[i].in_x2; \ - float x_f1 = server->x_table[i].in_fraction1; \ - float x_f2 = server->x_table[i].in_fraction2; \ - float f11 = x_f1 * y_f1 / (256.f-max); \ - float f12 = x_f2 * y_f1 / (256.f-max); \ - float f21 = x_f1 * y_f2 / (256.f-max); \ - float f22 = x_f2 * y_f2 / (256.f-max); \ - type input_r = (type)( \ - in_row1[in_x1 + 0] * f11 + in_row1[in_x2 + 0] * f12 + \ - in_row2[in_x1 + 0] * f21 + in_row2[in_x2 + 0] * f22 ); \ - type input_g = (type)( \ - in_row1[in_x1 + 1] * f11 + in_row1[in_x2 + 1] * f12 + \ - in_row2[in_x1 + 1] * f21 + in_row2[in_x2 + 1] * f22 ); \ - type input_b = (type)( \ - in_row1[in_x1 + 2] * f11 + in_row1[in_x2 + 2] * f12 + \ - in_row2[in_x1 + 2] * f21 + in_row2[in_x2 + 2] * f22 ); \ - type input_a = (type)( \ - in_row1[in_x1 + 3] * f11 + in_row1[in_x2 + 3] * f12 + \ - in_row2[in_x1 + 3] * f21 + in_row2[in_x2 + 3] * f22 ); \ - input_a = input_a * plugin->fade; \ - if( components == 4 ) { \ - type transparency = out_row[x * components + 3] * (max - input_a) / max; \ - out_row[x * components + 0] = (input_r * input_a + \ - out_row[x * components + 0] * transparency) / max; \ - out_row[x * components + 1] = ((input_g-ofs) * input_a + \ - (out_row[x * components + 1]-ofs) * transparency) / max + ofs; \ - out_row[x * components + 2] = ((input_b-ofs) * input_a + \ - (out_row[x * components + 2]-ofs) * transparency) / max + ofs; \ - out_row[x * components + 3] = MAX(input_a, out_row[x * components + 3]); \ - } \ - else { \ - type transparency = max - input_a; \ - out_row[x * components + 0] = (input_r * input_a + \ - out_row[x * components + 0] * transparency) / max; \ - out_row[x * components + 1] = ((input_g-ofs) * input_a + \ - (out_row[x * components + 1]-ofs) * transparency) / max + ofs; \ - out_row[x * components + 2] = ((input_b-ofs) * input_a + \ - (out_row[x * components + 2]-ofs) * transparency) / max + ofs; \ - } \ - } \ - } \ -} - - -void TitleTranslateUnit::process_package(LoadPackage *package) -{ - TitleTranslatePackage *pkg = (TitleTranslatePackage*)package; - TitleTranslate *server = (TitleTranslate*)this->server; - - switch( plugin->output->get_color_model() ) { - case BC_RGB888: TRANSLATE(unsigned char, 0xff, 3, 0); break; - case BC_RGB_FLOAT: TRANSLATE(float, 1.0, 3, 0); break; - case BC_YUV888: TRANSLATE(unsigned char, 0xff, 3, 0x80); break; - case BC_RGBA_FLOAT: TRANSLATE(float, 1.0, 4, 0); break; - case BC_RGBA8888: TRANSLATE(unsigned char, 0xff, 4, 0); break; - case BC_YUVA8888: TRANSLATE(unsigned char, 0xff, 4, 0x80); break; - } -//printf("TitleTranslateUnit::process_package 5\n"); -} - - -TitleTranslate::TitleTranslate(TitleMain *plugin, int cpus) - : LoadServer(cpus, cpus) -{ - this->plugin = plugin; - x_table = 0; - y_table = 0; - out_x1 = out_x2 = 0; - out_y1 = out_y2 = 0; -} - -TitleTranslate::~TitleTranslate() -{ - delete [] x_table; - delete [] y_table; -} - -void TitleTranslate::init_packages() -{ - int out_h = out_y2 - out_y1; - int py1 = 0, py2 = 0; - int pkgs = get_total_packages(); - for( int i=0; iy1 = py1; pkg->y2 = py2; - } -//printf("TitleTranslate::init_packages 2\n"); -} - -LoadClient* TitleTranslate::new_client() -{ - return new TitleTranslateUnit(plugin, this); -} - -LoadPackage* TitleTranslate::new_package() -{ - return new TitleTranslatePackage; -} - TitleCurNudge::TitleCurNudge(TitleParser *parser, TitleMain *plugin) : TitleStack(parser, 0) { @@ -1044,6 +861,10 @@ TitleCurFixed::TitleCurFixed(TitleParser *parser, TitleMain *plugin) : TitleStack(parser, 0) { } +TitleCurAlias::TitleCurAlias(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, (plugin->config.style & FONT_ALIAS) ? 1 : 0) +{ +} TitleCurSuper::TitleCurSuper(TitleParser *parser, TitleMain *plugin) : TitleStack(parser, 0) { @@ -1062,6 +883,7 @@ TitleParser::TitleParser(TitleMain *plugin) cur_under(this, plugin), cur_blink(this, plugin), cur_fixed(this, plugin), + cur_alias(this, plugin), cur_super(this, plugin) { bfr = out = plugin->config.wtext; @@ -1120,14 +942,14 @@ TitleMain::~TitleMain() delete glyph_engine; delete title_engine; if( freetype_face ) - FT_Done_Face(freetype_face); + ft_Done_Face(freetype_face); if( freetype_library ) - FT_Done_FreeType(freetype_library); + ft_Done_FreeType(freetype_library); delete translate; delete outline_engine; } -const char* TitleMain::plugin_title() { return _("Title"); } +const char* TitleMain::plugin_title() { return N_("Title"); } int TitleMain::is_realtime() { return 1; } int TitleMain::is_synthesis() { return 1; } @@ -1136,7 +958,8 @@ NEW_WINDOW_MACRO(TitleMain, TitleWindow); void TitleMain::build_previews(TitleWindow *gui) { - ArrayList&fonts = *gui->get_resources()->fontlist; + BC_Resources *resources = BC_WindowBase::get_resources(); + ArrayList&fonts = *resources->fontlist; for( int font_number=0; font_numberget_text_height(LARGEFONT); - int text_color = BC_WindowBase::get_resources()->default_text_color; + int max_height = 3*text_height/2, max_width = 2 * max_height; + int text_color = resources->default_text_color; int r = (text_color >> 16) & 0xff; int g = (text_color >> 8) & 0xff; int b = text_color & 0xff; @@ -1163,6 +987,8 @@ void TitleMain::build_previews(TitleWindow *gui) int total_w = 0; int total_h = 0; for( int pass=0; pass<2; ++pass ) { + if( resources->font_debug ) + printf("Titler: build previews pass %d\n",pass); //printf("TitleMain::build_previews %d %d %d\n", //__LINE__, text_height, total_h); for( int font_number=0; font_numberdisplayname, font->displayname) ) { if( pass == 1 ) { - font->image = fonts[i]->image; + font->image = new VFrame(*fonts[i]->image); } skip = 1; break; @@ -1180,9 +1006,9 @@ void TitleMain::build_previews(TitleWindow *gui) } if( skip ) continue; - - int current_x = 0, current_w = 0, current_h = 0, current_ascent = 0; - if( pass == 1 ) { + if( resources->font_debug ) + printf("Titler: preview %s = %s\n",font->displayname, font->path); + if( pass > 0 ) { font->image = new VFrame; font->image->set_use_shm(0); font->image->reallocate(0, -1, 0, 0, 0, @@ -1190,7 +1016,10 @@ void TitleMain::build_previews(TitleWindow *gui) font->image->clear_frame(); } + int current_w = 1, current_h = 1; + int current_x = 0, current_ascent = 0; int len = strlen(test_string); + for( int j=0; jpath); if( load_freetype_face(freetype_library, freetype_face, new_path)) continue; - FT_Set_Pixel_Sizes(freetype_face, text_height, 0); - if( FT_Load_Char(freetype_face, c, FT_LOAD_RENDER) ) continue; + ft_Set_Pixel_Sizes(freetype_face, text_height, 0); + if( ft_Load_Char(freetype_face, c, FT_LOAD_RENDER) ) continue; + int glyph_w = freetype_face->glyph->bitmap.width; + int glyph_h = freetype_face->glyph->bitmap.rows; + if( glyph_h > max_height ) glyph_h = max_height; + int glyph_a = freetype_face->glyph->advance.x >> 6; + int glyph_t = freetype_face->glyph->bitmap_top; if( pass == 0 ) { - current_w = current_x + freetype_face->glyph->bitmap.width; - if( (int)freetype_face->glyph->bitmap_top > current_ascent ) - current_ascent = freetype_face->glyph->bitmap_top; - if( (int)freetype_face->glyph->bitmap.rows > total_h ) - total_h = freetype_face->glyph->bitmap.rows; - if( (int)freetype_face->glyph->bitmap.rows > current_h ) - current_h = freetype_face->glyph->bitmap.rows; + current_w = current_x + glyph_w; + if( current_w > max_width ) current_w = max_width; + if( total_w < current_w ) total_w = current_w; + if( current_ascent < glyph_t ) current_ascent = glyph_t; + if( current_h < glyph_h ) current_h = glyph_h; + if( total_h < glyph_h ) total_h = glyph_h; } else { // copy 1 row at a time, center vertically - int out_y = (total_h - height[font_number]) / 2 + - ascent[font_number] - freetype_face->glyph->bitmap_top; - for( int in_y = 0; - in_y < (int)freetype_face->glyph->bitmap.rows && out_y < total_h; - ++in_y, ++out_y ) { - unsigned char *out_row = font->image->get_rows()[out_y] + - current_x * 4; + int out_y = (total_h-height[font_number])/2 + ascent[font_number]-glyph_t; + if( out_y < 0 ) out_y = 0; + for( int in_y = 0; in_y < glyph_h && out_y < total_h; ++in_y, ++out_y ) { unsigned char *in_row = freetype_face->glyph->bitmap.buffer + freetype_face->glyph->bitmap.pitch * in_y; + int out_x = current_x; + unsigned char *out_row = font->image->get_rows()[out_y] + + out_x * 4; - for( int out_x = 0; - out_x < (int)freetype_face->glyph->bitmap.width && out_x < total_w; - ++out_x ) { + for( int in_x = 0; in_x < glyph_w && out_x < total_w; ++in_x, ++out_x ) { *out_row = (*in_row * r + (0xff - *in_row) * *out_row) / 0xff; ++out_row; *out_row = (*in_row * g + @@ -1236,17 +1066,15 @@ void TitleMain::build_previews(TitleWindow *gui) in_row++; } } - current_x += freetype_face->glyph->advance.x >> 6; } + current_x += glyph_a; } - height[font_number] = current_h; ascent[font_number] = current_ascent; - if( pass == 0 && current_w > total_w ) total_w = current_w; } } - if( freetype_library ) FT_Done_FreeType(freetype_library); + if( freetype_library ) ft_Done_FreeType(freetype_library); } @@ -1262,20 +1090,20 @@ int TitleMain::check_char_code_path(FT_Library &freetype_library, FcConfig *config; FcPattern *font; - FcInit(); - config = FcConfigGetCurrent(); - FcConfigSetRescanInterval(config, 0); + fcInit(); + config = fcConfigGetCurrent(); + fcConfigSetRescanInterval(config, 0); - pat = FcPatternCreate(); - os = FcObjectSetBuild ( FC_FILE, FC_FONTFORMAT, (char *) 0); - fs = FcFontList(config, pat, os); + pat = fcPatternCreate(); + os = fcObjectSetBuild( FC_FILE, FC_FONTFORMAT, (char *) 0); + fs = fcFontList(config, pat, os); int found = 0; char tmpstring[BCTEXTLEN]; int limit_to_truetype = 0; //if you want to limit search to truetype put 1 - if( !freetype_library ) FT_Init_FreeType(&freetype_library); - if( !FT_New_Face(freetype_library, path_old, 0, &temp_freetype_face) ) { - FT_Set_Pixel_Sizes(temp_freetype_face, 128, 0); - int gindex = FT_Get_Char_Index(temp_freetype_face, char_code); + if( !freetype_library ) ft_Init_FreeType(&freetype_library); + if( !ft_New_Face(freetype_library, path_old, 0, &temp_freetype_face) ) { + ft_Set_Pixel_Sizes(temp_freetype_face, 128, 0); + int gindex = ft_Get_Char_Index(temp_freetype_face, char_code); if( gindex != 0 && char_code == 10 ) { strcpy(path_new, path_old); found = 1; @@ -1285,13 +1113,13 @@ int TitleMain::check_char_code_path(FT_Library &freetype_library, if( !found ) { for( int i=0; fs && infont; ++i ) { font = fs->fonts[i]; - FcPatternGetString(font, FC_FONTFORMAT, 0, &format); + fcPatternGetString(font, FC_FONTFORMAT, 0, &format); if( strcmp((char *)format, "TrueType") && !limit_to_truetype ) continue; - if( FcPatternGetString(font, FC_FILE, 0, &file) != FcResultMatch ) continue; + if( fcPatternGetString(font, FC_FILE, 0, &file) != FcResultMatch ) continue; sprintf(tmpstring, "%s", file); - if( !FT_New_Face(freetype_library, tmpstring, 0, &temp_freetype_face) ) continue; - FT_Set_Pixel_Sizes(temp_freetype_face, 128, 0); - int gindex = FT_Get_Char_Index(temp_freetype_face, char_code); + if( !ft_New_Face(freetype_library, tmpstring, 0, &temp_freetype_face) ) continue; + ft_Set_Pixel_Sizes(temp_freetype_face, 128, 0); + int gindex = ft_Get_Char_Index(temp_freetype_face, char_code); if( gindex != 0 && char_code == 10 ) { sprintf(path_new, "%s", tmpstring); found = 1; @@ -1301,8 +1129,8 @@ int TitleMain::check_char_code_path(FT_Library &freetype_library, } done: - if( fs ) FcFontSetDestroy(fs); - if( temp_freetype_face ) FT_Done_Face(temp_freetype_face); + if( fs ) fcFontSetDestroy(fs); + if( temp_freetype_face ) ft_Done_Face(temp_freetype_face); temp_freetype_face = 0; if( !found ) { @@ -1319,14 +1147,14 @@ int TitleMain::load_freetype_face(FT_Library &freetype_library, { //printf("TitleMain::load_freetype_face 1\n"); if( !freetype_library ) - FT_Init_FreeType(&freetype_library); + ft_Init_FreeType(&freetype_library); if( freetype_face ) - FT_Done_Face(freetype_face); + ft_Done_Face(freetype_face); freetype_face = 0; //printf("TitleMain::load_freetype_face 2\n"); // Use freetype's internal function for loading font - if( FT_New_Face(freetype_library, path, 0, &freetype_face) ) { + if( ft_New_Face(freetype_library, path, 0, &freetype_face) ) { fprintf(stderr, _("TitleMain::load_freetype_face %s failed.\n"), path); freetype_face = 0; freetype_library = 0; @@ -1337,7 +1165,7 @@ int TitleMain::load_freetype_face(FT_Library &freetype_library, int TitleMain::load_font(BC_FontEntry *font) { - if( load_freetype_face(freetype_library,freetype_face, font->path) ) return 1; + if( !font || load_freetype_face(freetype_library,freetype_face, font->path) ) return 1; strcpy(text_font, font->displayname); return 0; } @@ -1441,7 +1269,7 @@ void TitleMain::draw_background() delete bg_frame; bg_frame = 0; } if( !bg_frame ) - bg_frame = new VFrame(0, -1, bw, bh, output_model, -1); + bg_frame = new VFrame(bw, bh, output_model); int64_t position = get_source_position() - get_source_start(); if( !read_background(bg_frame, position, output_model) ) { if( !overlay_frame ) @@ -1460,36 +1288,43 @@ void TitleMain::draw_background() BC_FontEntry* TitleMain::get_font(const char *font_name, int style) { - int flavor = + if( !strcmp("fixed", font_name) ) + font_name = FIXED_FONT; + int flavor = FL_WIDTH_MASK | ((style & BC_FONT_ITALIC) != 0 ? FL_SLANT_ITALIC | FL_SLANT_OBLIQUE : FL_SLANT_ROMAN) | ((style & BC_FONT_BOLD) != 0 ? FL_WEIGHT_BOLD | FL_WEIGHT_DEMIBOLD | FL_WEIGHT_EXTRABOLD| FL_WEIGHT_BLACK | FL_WEIGHT_EXTRABLACK : FL_WEIGHT_BOOK | FL_WEIGHT_NORMAL | FL_WEIGHT_MEDIUM | FL_WEIGHT_LIGHT | FL_WEIGHT_EXTRALIGHT | FL_WEIGHT_THIN); - int mask = FL_WEIGHT_MASK | FL_SLANT_MASK; + int mask = FL_WEIGHT_MASK | FL_SLANT_MASK | FL_WIDTH_MASK; BC_Resources *resources = BC_WindowBase::get_resources(); - return resources->find_fontentry(font_name, flavor, mask, style); + BC_FontEntry *font = resources->find_fontentry(font_name, flavor, mask, style); + if( font && strcmp(font_name, font->displayname) ) font = 0; + return font; } BC_FontEntry* TitleMain::config_font() { BC_FontEntry *font = get_font(config.font, config.style); - if( font && load_font(font) ) font = 0; + if( !font || load_font(font) ) + load_font(font = get_font(FIXED_FONT,0)); return font; } -static inline bool is_ltr(wchar_t wch) { return (wch>='a' && wch<='z') || (wch>='A' && wch<='Z'); } -static inline bool is_nbr(wchar_t wch) { return (wch>='0' && wch<='9'); } +static inline bool is_ltr(wchar_t wch) { return iswalpha(wch); } +static inline bool is_nbr(wchar_t wch) { return iswdigit(wch); } static inline bool is_ws(wchar_t wch) { return wch==' ' || wch=='\t'; } static inline bool is_idch(wchar_t wch) { return is_ltr(wch) || is_nbr(wch) || wch=='_'; } // return eof=-1, chr=0, opener=1, closer=2 int TitleParser::wget(wchar_t &wch) { - char *ip = id, *tp = text; *ip = 0; *tp = 0; - int ilen = sizeof(id), tlen = sizeof(text), ich; + wchar_t *wip = wid, *wtp = wtxt; *wip = 0; *wtp = 0; + int ilen = sizeof(wid)/sizeof(wid[0]); + int tlen = sizeof(wtxt)/sizeof(wtxt[0]); + int ich; while( (ich=wnext()) >= 0 ) { if( ich == '\\' ) { if( (ich=wnext()) == '\n' ) continue; @@ -1505,23 +1340,38 @@ int TitleParser::wget(wchar_t &wch) int ret = 1; long pos = tell(); if( (ich=wnext()) == '/' ) { ret = 2; ich = wnext(); } if( is_ltr(ich) ) { - *ip++ = ich; + *wip++ = ich; while( is_idch(ich=wnext()) ) - if( --ilen > 0 ) *ip++ = ich; + if( --ilen > 0 ) *wip++ = ich; } - *ip = 0; + *wip = 0; while( is_ws(ich) ) ich = wnext(); while( ich >= 0 && ich != '>' ) { if( ich == '\n' || ich == '<' ) { ich = -1; break; } if( ich == '\\' && (ich=wnext()) < 0 ) break; - if( --tlen > 0 ) *tp++ = ich; + if( --tlen > 0 ) *wtp++ = ich; ich = wnext(); } - *tp = 0; + *wtp = 0; if( ich < 0 ) { ich = '<'; seek(pos); ret = 0; } wch = ich; return ret; } +int TitleParser::tget(wchar_t &wch) +{ + int ret = wget(wch); + if( ret > 0 ) { + int wid_len = wcslen(wid)+1; + BC_Resources::encode( + BC_Resources::wide_encoding, plugin->config.encoding, + (char*)wid,wid_len*sizeof(wid[0]), (char *)id,sizeof(id)); + int wtxt_len = wcslen(wtxt)+1; + BC_Resources::encode( + BC_Resources::wide_encoding, plugin->config.encoding, + (char*)wtxt,wtxt_len*sizeof(wtxt[0]), (char *)text,sizeof(text)); + } + return ret; +} TitleGlyph *TitleMain::get_glyph(FT_ULong char_code, BC_FontEntry *font, int size, int style) { @@ -1540,10 +1390,11 @@ int TitleMain::get_width(TitleGlyph *cur, TitleGlyph *nxt) int result = cur->advance_x; if( !nxt ) return result; FT_Vector kerning; - FT_Get_Kerning(freetype_face, - cur->freetype_index, nxt->freetype_index, - ft_kerning_default, &kerning); - return result + (kerning.x >> 6); + if( !ft_Get_Kerning(freetype_face, + cur->freetype_index, nxt->freetype_index, + ft_kerning_default, &kerning) ) + result += (kerning.x >> 6); + return result; } @@ -1561,7 +1412,8 @@ VFrame *TitleMain::add_image(const char *path) VFrame *vframe = get_image(path); if( !vframe && (vframe=VFramePng::vframe_png(path)) != 0 ) { if( vframe->get_color_model() != text_model ) { - VFrame *frame = new VFrame(vframe->get_w(), vframe->get_h(), text_model); + VFrame *frame = new VFrame(vframe->get_w(), vframe->get_h(), + text_model, 0); frame->transfer_from(vframe); delete vframe; vframe = frame; } @@ -1751,6 +1603,14 @@ int TitleCurFixed::set(const char *txt) return 0; } +int TitleCurAlias::set(const char *txt) +{ + int alias = !*txt ? 1 : strtol(txt,(char **)&txt,0); + if( *txt ) return 1; + push(alias); + return 0; +} + int TitleCurSuper::set(const char *txt) { int super = !*txt ? 1 : strtol(txt,(char **)&txt,0); @@ -1773,18 +1633,19 @@ int TitleCurNudge::set(const char *txt) int TitleParser::set_attributes(int ret) { - if( !strcmp(id,_("nudge")) ) return ret>1 ? cur_nudge.unset(text) : cur_nudge.set(text); - if( !strcmp(id,_("color")) ) return ret>1 ? cur_color.unset(text) : cur_color.set(text); - if( !strcmp(id,_("alpha")) ) return ret>1 ? cur_alpha.unset(text) : cur_alpha.set(text); - if( !strcmp(id,_("font")) ) return ret>1 ? cur_font.unset(text) : cur_font.set(text); - if( !strcmp(id,_("size")) ) return ret>1 ? cur_size.unset(text) : cur_size.set(text); - if( !strcmp(id,_("bold")) ) return ret>1 ? cur_bold.unset(text) : cur_bold.set(text); - if( !strcmp(id,_("italic")) ) return ret>1 ? cur_italic.unset(text) : cur_italic.set(text); - if( !strcmp(id,_("caps")) ) return ret>1 ? cur_caps.unset(text) : cur_caps.set(text); - if( !strcmp(id,_("ul")) ) return ret>1 ? cur_under.unset(text) : cur_under.set(text); - if( !strcmp(id,_("blink")) ) return ret>1 ? cur_blink.unset(text) : cur_blink.set(text); - if( !strcmp(id,_("fixed")) ) return ret>1 ? cur_fixed.unset(text) : cur_fixed.set(text); - if( !strcmp(id,_("sup")) ) return ret>1 ? cur_super.unset(text) : cur_super.set(text); + if( !kw_strcmp(id,KW_NUDGE) ) return ret>1 ? cur_nudge.unset(text) : cur_nudge.set(text); + if( !kw_strcmp(id,KW_COLOR) ) return ret>1 ? cur_color.unset(text) : cur_color.set(text); + if( !kw_strcmp(id,KW_ALPHA) ) return ret>1 ? cur_alpha.unset(text) : cur_alpha.set(text); + if( !kw_strcmp(id,KW_FONT) ) return ret>1 ? cur_font.unset(text) : cur_font.set(text); + if( !kw_strcmp(id,KW_SIZE) ) return ret>1 ? cur_size.unset(text) : cur_size.set(text); + if( !kw_strcmp(id,KW_BOLD) ) return ret>1 ? cur_bold.unset(text) : cur_bold.set(text); + if( !kw_strcmp(id,KW_ITALIC) ) return ret>1 ? cur_italic.unset(text) : cur_italic.set(text); + if( !kw_strcmp(id,KW_CAPS) ) return ret>1 ? cur_caps.unset(text) : cur_caps.set(text); + if( !kw_strcmp(id,KW_UL) ) return ret>1 ? cur_under.unset(text) : cur_under.set(text); + if( !kw_strcmp(id,KW_BLINK) ) return ret>1 ? cur_blink.unset(text) : cur_blink.set(text); + if( !kw_strcmp(id,KW_FIXED) ) return ret>1 ? cur_fixed.unset(text) : cur_fixed.set(text); + if( !kw_strcmp(id,KW_ALIAS) ) return ret>1 ? cur_alias.unset(text) : cur_alias.set(text); + if( !kw_strcmp(id,KW_SUP) ) return ret>1 ? cur_super.unset(text) : cur_super.set(text); return 1; } @@ -1798,45 +1659,47 @@ void TitleMain::load_glyphs() while( !wchrs.eof() ) { wchar_t wch1 = wchrs.wcur(), wch; long ipos = wchrs.tell(); - int ret = wchrs.wget(wch); + int ret = wchrs.tget(wch); if( ret > 0 ) { if( !wchrs.set_attributes(ret) ) continue; - if( !strcmp(wchrs.id,"png") && add_image(wchrs.text) ) continue; + if( !kw_strcmp(wchrs.id,KW_PNG) && add_image(wchrs.text) ) continue; wch = wch1; wchrs.seek(ipos+1); ret = 0; } - if( !ret ) { - int cur_caps = wchrs.cur_caps; - if( cur_caps > 0 ) wch = towupper(wch); - else if( cur_caps < 0 ) wch = towlower(wch); - BC_FontEntry *cur_font = wchrs.cur_font; - int cur_size = wchrs.cur_size; - int cur_style = 0; - int cur_bold = wchrs.cur_bold; - if( cur_bold ) cur_style |= BC_FONT_BOLD; - int cur_italic = wchrs.cur_italic; - if( cur_italic ) cur_style |= BC_FONT_ITALIC; - int cur_super = wchrs.cur_super; - if( cur_super ) cur_size /= 2; - int exists = 0; - for( int j=0; jchar_code == (FT_ULong)wch && glyph->font == cur_font && - glyph->size == cur_size && glyph->style == cur_style ) { - exists = 1; break; - } - } + if( ret || wch == '\n' ) continue; - if( !exists ) { - total_packages++; - TitleGlyph *glyph = new TitleGlyph; - glyph->char_code = (FT_ULong)wch; - glyph->font = cur_font; - glyph->size = cur_size; - glyph->style = cur_style; - title_glyphs.append(glyph); + int cur_caps = wchrs.cur_caps; + if( cur_caps > 0 ) wch = towupper(wch); + else if( cur_caps < 0 ) wch = towlower(wch); + BC_FontEntry *cur_font = wchrs.cur_font; + int cur_size = wchrs.cur_size; + int cur_style = 0; + int cur_bold = wchrs.cur_bold; + if( cur_bold ) cur_style |= BC_FONT_BOLD; + int cur_italic = wchrs.cur_italic; + if( cur_italic ) cur_style |= BC_FONT_ITALIC; + int cur_alias = wchrs.cur_alias; + if( cur_alias ) cur_style |= FONT_ALIAS; + int cur_super = wchrs.cur_super; + if( cur_super ) cur_size /= 2; + int exists = 0; + for( int j=0; jchar_code == (FT_ULong)wch && glyph->font == cur_font && + glyph->size == cur_size && glyph->style == cur_style ) { + exists = 1; break; } } + + if( !exists && cur_font ) { + total_packages++; + TitleGlyph *glyph = new TitleGlyph; + glyph->char_code = (FT_ULong)wch; + glyph->font = cur_font; + glyph->size = cur_size; + glyph->style = cur_style; + title_glyphs.append(glyph); + } } if( !glyph_engine ) @@ -1903,7 +1766,7 @@ int TitleMain::get_text() TitleChar *chr = 0; long ipos = wchrs.tell(); wchar_t wch1 = wchrs.wcur(), wch; - int ret = wchrs.wget(wch); + int ret = wchrs.tget(wch); if( ret < 0 || wch == '\n' ) { if( row->x1 > row->x2 ) row->x1 = row->x2 = 0; if( row->y2 > row->y1 ) row->y1 = row->y2 = 0; @@ -1931,6 +1794,8 @@ int TitleMain::get_text() int cur_style = 0; int cur_bold = wchrs.cur_bold; if( cur_bold ) cur_style |= BC_FONT_BOLD; + int cur_alias = wchrs.cur_alias; + if( cur_alias ) cur_style |= FONT_ALIAS; int cur_italic = wchrs.cur_italic; if( cur_italic ) cur_style |= BC_FONT_ITALIC; short nx = cur_nudge >> 16, ny = cur_nudge; @@ -1938,7 +1803,7 @@ int TitleMain::get_text() if( ret > 0 ) { if( !wchrs.set_attributes(ret) ) continue; ret = -1; - if( !strcmp(wchrs.id,"png") ) { + if( !kw_strcmp(wchrs.id,KW_PNG) ) { VFrame *png_image = get_image(wchrs.text); if( png_image ) { chr = title_chars.add(CHAR_IMAGE, png_image); @@ -2052,7 +1917,7 @@ int TitleMain::get_visible_text() case RIGHT_TO_LEFT: case LEFT_TO_RIGHT: { float magnitude = config.pixels_per_second * - (get_source_position() - config.prev_keyframe_position) / + (get_source_position() - get_source_start()) / PluginVClient::project_frame_rate; if( config.loop ) { int loop_size = text_w + title_w; @@ -2267,21 +2132,21 @@ int TitleMain::draw_underline(VFrame *mask, int alpha) void TitleMain::draw_overlay() { - //printf("TitleMain::draw_overlay 1\n"); fade = 1; if( !EQUIV(config.fade_in, 0) ) { - int fade_len = lroundf(config.fade_in * PluginVClient::project_frame_rate); - int fade_position = get_source_position() - config.prev_keyframe_position; + int64_t plugin_start = server->plugin->startproject; + int64_t fade_len = lroundf(config.fade_in * PluginVClient::project_frame_rate); + int64_t fade_position = get_source_position() - plugin_start; if( fade_position >= 0 && fade_position < fade_len ) { fade = (float)fade_position / fade_len; } } if( !EQUIV(config.fade_out, 0) ) { - int fade_len = lroundf(config.fade_out * PluginVClient::project_frame_rate); - int fade_position = config.next_keyframe_position - get_source_position(); - + int64_t plugin_end = server->plugin->startproject + server->plugin->length; + int64_t fade_len = lroundf(config.fade_out * PluginVClient::project_frame_rate); + int64_t fade_position = plugin_end - get_source_position(); if( fade_position >= 0 && fade_position < fade_len ) { fade = (float)fade_position / fade_len; @@ -2290,16 +2155,162 @@ void TitleMain::draw_overlay() if( !translate ) translate = new TitleTranslate(this, cpus); - if( text_x+mask_w > 0 && text_x < title_w ) { - translate->xlat_mask = text_mask; - translate->run_packages(); + + int tx = text_x - text_x1 + mask_x1; + if( tx < title_w && tx+mask_w > 0 ) { + translate->copy(text_mask); if( config.stroke_width >= SMALL && (config.style & BC_FONT_OUTLINE) ) { - translate->xlat_mask = stroke_mask; - translate->run_packages(); + translate->copy(stroke_mask); } } } + +TitleTranslate::TitleTranslate(TitleMain *plugin, int cpus) + : LoadServer(cpus, cpus) +{ + this->plugin = plugin; +} + +TitleTranslate::~TitleTranslate() +{ +} + +void TitleTranslate::copy(VFrame *input) +{ + this->input = input; + in_w = input->get_w(); + in_h = input->get_h(); + ix1 = 0, ix2 = ix1 + in_w; + iy1 = 0, iy2 = iy1 + in_h; + + out_w = plugin->output->get_w(); + out_h = plugin->output->get_h(); + float x1 = plugin->title_x, x2 = x1 + plugin->title_w; + float y1 = plugin->title_y, y2 = y1 + plugin->title_h; + bclamp(x1, 0, out_w); bclamp(y1, 0, out_h); + bclamp(x2, 0, out_w); bclamp(y2, 0, out_h); + + ox1 = plugin->title_x + plugin->text_x - plugin->text_x1 + plugin->mask_x1; + ox2 = ox1 + in_w; + oy1 = plugin->title_y + plugin->text_y - plugin->text_y1 + plugin->mask_y1; + oy2 = oy1 + in_h; + if( ox1 < x1 ) { ix1 -= (ox1-x1); ox1 = x1; } + if( oy1 < y1 ) { iy1 -= (oy1-y1); oy1 = y1; } + if( ox2 > x2 ) { ix2 -= (ox2-x2); ox2 = x2; } + if( oy2 > y2 ) { iy2 -= (oy2-x2); oy2 = y2; } +#if 0 +printf("TitleTranslate text txy=%7.2f,%-7.2f\n" + " mxy1=%7d,%-7d mxy2=%7d,%-7d\n" + " xy1=%7.2f,%-7.2f xy2=%7.2f,%-7.2f\n" + " ixy1=%7.2f,%-7.2f ixy2=%7.2f,%-7.2f\n" + " oxy1=%7.2f,%-7.2f oxy2=%7.2f,%-7.2f\n", + plugin->text_x, plugin->text_y, + plugin->mask_x1, plugin->mask_y1, plugin->mask_x2, plugin->mask_y2, + x1,y1, x2,y2, ix1,iy1, ix2,iy2, ox1,oy1, ox2,oy2); +#endif + process_packages(); +} + + +TitleTranslatePackage::TitleTranslatePackage() + : LoadPackage() +{ + y1 = y2 = 0; +} + +TitleTranslateUnit::TitleTranslateUnit(TitleMain *plugin, TitleTranslate *server) + : LoadClient(server) +{ +} + +#define TRANSLATE(type, max, comps, ofs) { \ + type **out_rows = (type**)output->get_rows(); \ + float fr = 1./(256.-max), fs = max/255.; \ + float r = max > 1 ? 0.5 : 0; \ + int ix1= x1, iy1 = y1, ix2= x2, iy2 = y2; \ + float fy = y1 + yofs; \ + for( int y=iy1; yfade, b = max - a, px; \ + /*if( comps == 4 ) { b = (b * op[3]) / max; }*/ \ + px = *op; *op++ = (a*in_r + b*px) / max; \ + px = *op; *op++ = (a*(in_g-ofs) + b*(px-ofs)) / max + ofs; \ + px = *op; *op++ = (a*(in_b-ofs) + b*(px-ofs)) / max + ofs; \ + if( comps == 4 ) { b = *op; *op++ = a + b - a*b / max; } \ + } \ + } \ +} + +void TitleTranslateUnit::process_package(LoadPackage *package) +{ + TitleTranslatePackage *pkg = (TitleTranslatePackage*)package; + TitleTranslate *server = (TitleTranslate*)this->server; + TitleMain *plugin = server->plugin; + VFrame *input = server->input, *output = plugin->output; + int iw = input->get_w(), ih = input->get_h(); + int iw1 = iw-1, ih1 = ih-1; + float x1 = server->ox1, x2 = server->ox2; + float y1 = pkg->y1, y2 = pkg->y2; + float xofs = server->ix1 - server->ox1; + float yofs = server->iy1 - server->oy1; + unsigned char **in_rows = input->get_rows(); + + switch( output->get_color_model() ) { + case BC_RGB888: TRANSLATE(unsigned char, 0xff, 3, 0); break; + case BC_RGB_FLOAT: TRANSLATE(float, 1.0, 3, 0); break; + case BC_YUV888: TRANSLATE(unsigned char, 0xff, 3, 0x80); break; + case BC_RGBA_FLOAT: TRANSLATE(float, 1.0, 4, 0); break; + case BC_RGBA8888: TRANSLATE(unsigned char, 0xff, 4, 0); break; + case BC_YUVA8888: TRANSLATE(unsigned char, 0xff, 4, 0x80); break; + } +} + +void TitleTranslate::init_packages() +{ + int oh = oy2 - oy1; + int py = oy1; + int i = 0, pkgs = get_total_packages(); + while( i < pkgs ) { + TitleTranslatePackage *pkg = (TitleTranslatePackage*)get_package(i++); + pkg->y1 = py; + py = oy1 + i*oh / pkgs; + pkg->y2 = py; + } +} + +LoadClient* TitleTranslate::new_client() +{ + return new TitleTranslateUnit(plugin, this); +} + +LoadPackage* TitleTranslate::new_package() +{ + return new TitleTranslatePackage; +} + + + const char* TitleMain::motion_to_text(int motion) { switch( motion ) { @@ -2331,7 +2342,7 @@ void TitleMain::reset_render() title_glyphs.clear(); title_images.clear(); if( freetype_face ) { - FT_Done_Face(freetype_face); + ft_Done_Face(freetype_face); freetype_face = 0; } } @@ -2339,52 +2350,15 @@ void TitleMain::reset_render() int TitleMain::init_freetype() { if( !freetype_library ) - FT_Init_FreeType(&freetype_library); + ft_Init_FreeType(&freetype_library); return 0; } void TitleMain::draw_boundry() { - VFrame &out = *output; - int iw = output->get_w(), ih = output->get_h(); - int mr = MIN(iw, ih)/200 + 2, rr = 2*mr; - int x = title_x, y = title_y, w = title_w, h = title_h; - int r2 = (rr+1)/2; - int x0 = x-r2, x1 = x+(w+1)/2, x2 = x+w+r2; - int y0 = y-r2, y1 = y+(h+1)/2, y2 = y+h+r2; - int st = 1; - for( int r=2; r=0; ) { // bbox - int lft = x+r, rgt = x+w-1-r; - int top = y+r, bot = y+h-1-r; - out.draw_line(lft,top, rgt,top); - out.draw_line(rgt,top, rgt,bot); - out.draw_line(rgt,bot, lft,bot); - out.draw_line(lft,bot, lft,top); - } - - for( int r=mr; r=0; ) { // edge arrows - out.draw_line(x1-r,y0+r, x1+r,y0+r); - out.draw_line(x2-r,y1-r, x2-r,y1+r); - out.draw_line(x1-r,y2-r, x1+r,y2-r); - out.draw_line(x0+r,y1+r, x0+r,y1-r); - } - x0 += r2; y0 += r2; x2 -= r2; y2 -= r2; - for( int r=2*mr; --r>=0; ) { // corner arrows - out.draw_line(x0,y0+r, x0+r,y0); - out.draw_line(x2,y0+r, x2-r,y0); - out.draw_line(x2,y2-r, x2-r,y2); - out.draw_line(x0,y2-r, x0+r,y2); - } + if( !gui_open() ) return; + DragCheckBox::draw_boundary(output, + title_x, title_y, title_w, title_h); } @@ -2565,11 +2539,19 @@ void TitleMain::save_data(KeyFrame *keyframe) output.tag.set_property("LOOP_PLAYBACK", config.loop_playback); output.append_tag(); output.append_newline(); - char text[BCTEXTLEN]; + char text[2*sizeof(config.wtext)]; int text_len = BC_Resources::encode( BC_Resources::wide_encoding, DEFAULT_ENCODING, (char*)config.wtext, config.wlen*sizeof(wchar_t), text, sizeof(text)); + int len = output.length(), avail = MESSAGESIZE-16 - len; + if( text_len >= avail ) { // back off last utf8 char + text_len = avail; + while( text_len > 0 && (text[text_len-1] & 0xc0) == 0x80 ) + text[--text_len] = 0; + if( text_len > 0 ) + text[--text_len] = 0; + } output.append_text(text, text_len); output.tag.set_title("/TITLE"); output.append_tag(); @@ -2635,25 +2617,25 @@ void TitleMain::read_data(KeyFrame *keyframe) } } -void TitleMain::insert_text(const char *txt, int pos) +void TitleMain::insert_text(const wchar_t *wtxt, int pos) { - int ilen = strlen(txt); + int len = wcslen(wtxt); wchar_t *wtext = config.wtext; int wsize = sizeof(config.wtext)-1; int wlen = config.wlen; if( pos < 0 ) pos = 0; if( pos > wlen ) pos = wlen; - for( int i=wlen-1, j=wlen+ilen-1; i>=pos; --i,--j ) { + for( int i=wlen-1, j=wlen+len-1; i>=pos; --i,--j ) { if( j >= wsize ) continue; wtext[j] = wtext[i]; } - for( int i=pos, j=0; j= wsize ) break; - wtext[i] = txt[j]; + wtext[i] = wtxt[j]; } - if( (wlen+=ilen) > wsize ) wlen = wsize; + if( (wlen+=len) > wsize ) wlen = wsize; wtext[wlen] = 0; config.wlen = wlen; }