// Additional support for UTF-8 by
// Paolo Rampino aka Akirad <info at tuttoainternet.it>
-
#include "asset.h"
#include "bccmodels.h"
#include "bcsignals.h"
#include <endian.h>
#include <byteswap.h>
#include <iconv.h>
-#include <wctype.h>
#include <sys/stat.h>
#include <fontconfig/fontconfig.h>
-#define FIXED_FONT "Bitstream Vera Sans Mono (Bits)"
+#define FIXED_FONT "bitstream vera sans mono (bitstream)"
#define SMALL (1.0 / 64.0)
#define MAX_FLT 3.40282347e+38
outline_color = WHITE;
outline_alpha = 0xff;
color_stroke = 0xff0000;
- stroke_width = 1.0;
+ stroke_width = 0.0;
motion_strategy = NO_MOTION;
line_pitch = 0;
loop = 0;
wtext[0] = 0; wlen = 0;
title_x = title_y = 0.0;
title_w = title_h = 0;
- window_w = 800;
+ window_w = 860;
window_h = 460;
next_keyframe_position = 0;
prev_keyframe_position = 0;
{
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) ) {
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
+ 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,
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);
+ if( BC_CModels::is_yuv(color_model) ) YUV::yuv.rgb_to_yuv_8(r,g,b);
rr = r; gg = g; bb = b;
}
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<inp_w; ++xin,xout+=4 ) {
- out[xout] = inp[xin];
+ out[xout] = STD_ALPHA(max, inp[xin], out[xout]);
}
++y_inp; ++y_out;
}
for( int xin=x_inp,xout=x_out*4+0; xin<inp_w; ++xin,xout+=4 ) {
int in_a = inp[xin], out_a = out[xout+3];
if( in_a + out_a == 0 ) continue;
- int opacity = (in_a * alpha)/max, transp = out_a * (max - opacity)/max;
- out[xout+0] = (opacity * r + transp * out[xout+0]) / max;
- out[xout+1] = (opacity * (g-ofs) + transp * (out[xout+1]-ofs)) / max + ofs;
- out[xout+2] = (opacity * (b-ofs) + transp * (out[xout+2]-ofs)) / max + ofs;
- out[xout+3] = opacity + transp - (opacity * transp) / max;
+ if( in_a >= 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;
}
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<inp_w; ++xin,xout+=4 ) {
- int xinp = xin*4, in_a = inp[xinp+3], out_a = out[xout+3];
+ int xinp = xin*4;
+ int in_a = inp[xinp+3], out_a = out[xout+3];
if( in_a + out_a == 0 ) continue;
- int opacity = (in_a * alpha)/max, transp = out_a * (max - opacity)/max;
- out[xout+0] = (opacity * inp[xinp+0] + transp * out[xout+0]) / max;
- out[xout+1] = (opacity * (inp[xinp+1]-ofs) + transp * (out[xout+1]-ofs)) / max + ofs;
- out[xout+2] = (opacity * (inp[xinp+2]-ofs) + transp * (out[xout+2]-ofs)) / max + ofs;
- out[xout+3] = opacity + transp - (opacity * transp) / max;
+ if( in_a >= 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;
}
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_x<x2_out; ++out_x ) {
- transfer_table_f *entry = &table[out_x - x1_out];
-
- entry->in_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()
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; y<my; ++y ) {
unsigned char *out_row = outline_rows[y];
- int y1 = y - ofs, y2 = y + ofs;
+ int y1 = y - oln_sz, y2 = y + oln_sz;
CLAMP(y1, 0, mask_h1); CLAMP(y2, 0, mask_h1);
for( int x=0, mx=plugin->text_mask->get_w(); x<mx; ++x ) {
- int x1 = x - ofs, x2 = x + ofs;
+ int x1 = x - oln_sz, x2 = x + oln_sz;
CLAMP(x1, 0, mask_w1); CLAMP(x2, 0, mask_w1);
int max_a = 0;
for( int yy=y1; yy<=y2; ++yy ) {
}
-
-TitleTranslatePackage::TitleTranslatePackage()
- : LoadPackage()
-{
- y1 = y2 = 0;
-}
-
-
-TitleTranslateUnit::TitleTranslateUnit(TitleMain *plugin, TitleTranslate *server)
- : LoadClient(server)
-{
- this->plugin = 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; y<pkg->y2; ++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; x<server->out_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; i<pkgs; py1=py2 ) {
- TitleTranslatePackage *pkg = (TitleTranslatePackage*)get_package(i);
- py2 = (++i*out_h) / pkgs;
- pkg->y1 = 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<int>(parser, 0)
{
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; }
void TitleMain::build_previews(TitleWindow *gui)
{
- ArrayList<BC_FontEntry*>&fonts = *gui->get_resources()->fontlist;
+ BC_Resources *resources = BC_WindowBase::get_resources();
+ ArrayList<BC_FontEntry*>&fonts = *resources->fontlist;
for( int font_number=0; font_number<fonts.size(); ++font_number ) {
BC_FontEntry *font = fonts.get(font_number);
char new_path[BCTEXTLEN];
int text_height = gui->get_text_height(LARGEFONT);
int max_height = 3*text_height/2, max_width = 2 * max_height;
- int text_color = BC_WindowBase::get_resources()->default_text_color;
+ int text_color = resources->default_text_color;
int r = (text_color >> 16) & 0xff;
int g = (text_color >> 8) & 0xff;
int b = text_color & 0xff;
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_number<fonts.size(); ++font_number ) {
for( int i=0; i<font_number; ++i ) {
if( !strcasecmp(fonts[i]->displayname, font->displayname) ) {
if( pass == 1 ) {
- font->image = fonts[i]->image;
+ font->image = new VFrame(*fonts[i]->image);
}
skip = 1;
break;
}
if( skip ) continue;
+ 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);
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;
}
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 )
{
if( !strcmp("fixed", font_name) )
font_name = FIXED_FONT;
- int flavor =
+ 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();
BC_FontEntry *font = resources->find_fontentry(font_name, flavor, mask, style);
}
-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;
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)
{
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;
}
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( !strcmp(id,KW_NUDGE) ) return ret>1 ? cur_nudge.unset(text) : cur_nudge.set(text);
+ if( !strcmp(id,KW_COLOR) ) return ret>1 ? cur_color.unset(text) : cur_color.set(text);
+ if( !strcmp(id,KW_ALPHA) ) return ret>1 ? cur_alpha.unset(text) : cur_alpha.set(text);
+ if( !strcmp(id,KW_FONT) ) return ret>1 ? cur_font.unset(text) : cur_font.set(text);
+ if( !strcmp(id,KW_SIZE) ) return ret>1 ? cur_size.unset(text) : cur_size.set(text);
+ if( !strcmp(id,KW_BOLD) ) return ret>1 ? cur_bold.unset(text) : cur_bold.set(text);
+ if( !strcmp(id,KW_ITALIC) ) return ret>1 ? cur_italic.unset(text) : cur_italic.set(text);
+ if( !strcmp(id,KW_CAPS) ) return ret>1 ? cur_caps.unset(text) : cur_caps.set(text);
+ if( !strcmp(id,KW_UL) ) return ret>1 ? cur_under.unset(text) : cur_under.set(text);
+ if( !strcmp(id,KW_BLINK) ) return ret>1 ? cur_blink.unset(text) : cur_blink.set(text);
+ if( !strcmp(id,KW_FIXED) ) return ret>1 ? cur_fixed.unset(text) : cur_fixed.set(text);
+ if( !strcmp(id,KW_SUP) ) return ret>1 ? cur_super.unset(text) : cur_super.set(text);
return 1;
}
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( !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; j<title_glyphs.count(); ++j ) {
- TitleGlyph *glyph = title_glyphs[j];
- if( glyph->char_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 && 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);
+ 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; j<title_glyphs.count(); ++j ) {
+ TitleGlyph *glyph = title_glyphs[j];
+ if( glyph->char_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 )
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;
if( ret > 0 ) {
if( !wchrs.set_attributes(ret) ) continue;
ret = -1;
- if( !strcmp(wchrs.id,"png") ) {
+ if( !strcmp(wchrs.id,KW_PNG) ) {
VFrame *png_image = get_image(wchrs.text);
if( png_image ) {
chr = title_chars.add(CHAR_IMAGE, png_image);
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 fs = 1./(256.-max); \
+ float r = max > 1 ? 0.5 : 0; \
+ for( int y=y1; y<y2; ++y ) { \
+ float fy = y+yofs; int iy = fy; \
+ float yf1 = fy>=iy ? fy - iy : fy+1-iy; \
+ float yf0 = 1. - yf1; \
+ unsigned char *in_row0 = in_rows[iy<0 ? 0 : iy]; \
+ unsigned char *in_row1 = in_rows[iy<ih1 ? iy+1 : ih1]; \
+ for( int x=x1; x<x2; ++x ) { \
+ type *op = out_rows[y] + x*comps; \
+ float fx = x+xofs; int ix = fx; \
+ float xf1 = fx - ix, xf0 = 1. - xf1; \
+ int i0 = (ix<0 ? 0 : ix)*4, i1 = (ix<iw1 ? ix+1 : iw1)*4; \
+ uint8_t *cp00 = in_row0 + i0, *cp01 = in_row0 + i1; \
+ uint8_t *cp10 = in_row1 + i0, *cp11 = in_row1 + i1; \
+ float a00 = yf0 * xf0 * cp00[3], a01 = yf0 * xf1 * cp01[3]; \
+ float a10 = yf1 * xf0 * cp10[3], a11 = yf1 * xf1 * cp11[3]; \
+ float fa = a00 + a01 + a10 + a11; if( !fa ) continue; fa *= fs; \
+ type in_a = fa + r; float s = 1./fa; \
+ type in_r = (cp00[0]*a00 + cp01[0]*a01 + cp10[0]*a10 + cp11[0]*a11)*s + r; \
+ type in_g = (cp00[1]*a00 + cp01[1]*a01 + cp10[1]*a10 + cp11[1]*a11)*s + r; \
+ type in_b = (cp00[2]*a00 + cp01[2]*a01 + cp10[2]*a10 + cp11[2]*a11)*s + r; \
+ type a = in_a*plugin->fade, 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 ) {
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();
}
}
-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<ilen; ++i,++j ) {
+ for( int i=pos, j=0; j<len; ++i,++j ) {
if( i >= 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;
}