From 77815ec03df6a03ed75433e8cf8ae1e83fb76d6e Mon Sep 17 00:00:00 2001 From: Good Guy Date: Thu, 23 Feb 2017 17:24:59 -0700 Subject: [PATCH] titler rework, some code cleanup and fixes --- cinelerra-5.1/cinelerra/assetedit.C | 42 +- cinelerra-5.1/cinelerra/cicolors.C | 162 +- cinelerra-5.1/cinelerra/cicolors.h | 2 +- cinelerra-5.1/cinelerra/edl.C | 2 +- cinelerra-5.1/cinelerra/edl.h | 2 +- cinelerra-5.1/cinelerra/mwindow.C | 2 +- cinelerra-5.1/cinelerra/pluginserver.C | 70 +- cinelerra-5.1/cinelerra/renderengine.h | 1 + cinelerra-5.1/guicast/bctextbox.C | 53 +- cinelerra-5.1/guicast/bctextbox.h | 28 +- cinelerra-5.1/guicast/bcwindowbase.C | 20 +- cinelerra-5.1/guicast/bcwindowbase.h | 6 + cinelerra-5.1/guicast/clip.h | 15 + cinelerra-5.1/guicast/vframe.C | 212 +- cinelerra-5.1/guicast/vframe.h | 14 +- cinelerra-5.1/plugins/polar/polarwindow.C | 4 + cinelerra-5.1/plugins/rgbshift/rgbshift.C | 9 +- cinelerra-5.1/plugins/svg/svg.C | 32 +- cinelerra-5.1/plugins/titler/Makefile | 17 +- cinelerra-5.1/plugins/titler/title.C | 2203 -------------- cinelerra-5.1/plugins/titler/title.C.stroker | 2306 -------------- cinelerra-5.1/plugins/titler/title.h | 467 --- cinelerra-5.1/plugins/titler/title.h.stroker | 418 --- cinelerra-5.1/plugins/titler/titler.C | 2636 +++++++++++++++++ cinelerra-5.1/plugins/titler/titler.h | 657 ++++ .../titler/{titlewindow.C => titlerwindow.C} | 879 ++++-- .../titler/{titlewindow.h => titlerwindow.h} | 140 +- .../plugins/titler/titlewindow.C.stroker | 904 ------ .../plugins/titler/titlewindow.h.stroker | 358 --- cinelerra-5.1/plugins/whirl/whirlwindow.C | 4 + cinelerra-5.1/plugins/yuv/yuv.C | 14 +- cinelerra-5.1/plugins/yuv/yuvwindow.C | 5 + cinelerra-5.1/plugins/yuvshift/yuvshift.C | 8 +- 33 files changed, 4306 insertions(+), 7386 deletions(-) delete mode 100644 cinelerra-5.1/plugins/titler/title.C delete mode 100644 cinelerra-5.1/plugins/titler/title.C.stroker delete mode 100644 cinelerra-5.1/plugins/titler/title.h delete mode 100644 cinelerra-5.1/plugins/titler/title.h.stroker create mode 100644 cinelerra-5.1/plugins/titler/titler.C create mode 100644 cinelerra-5.1/plugins/titler/titler.h rename cinelerra-5.1/plugins/titler/{titlewindow.C => titlerwindow.C} (50%) rename cinelerra-5.1/plugins/titler/{titlewindow.h => titlerwindow.h} (74%) delete mode 100644 cinelerra-5.1/plugins/titler/titlewindow.C.stroker delete mode 100644 cinelerra-5.1/plugins/titler/titlewindow.h.stroker diff --git a/cinelerra-5.1/cinelerra/assetedit.C b/cinelerra-5.1/cinelerra/assetedit.C index 27a5a8db..26759748 100644 --- a/cinelerra-5.1/cinelerra/assetedit.C +++ b/cinelerra-5.1/cinelerra/assetedit.C @@ -121,46 +121,37 @@ void AssetEdit::handle_done_event(int result) void AssetEdit::handle_close_event(int result) { - if(!result) - { + if(!result) { int changed = 0; Asset *asset = 0; EDL *nested_edl = 0; - if(indexable->is_asset) - { + if(indexable->is_asset) { asset = (Asset*)indexable; - if(!changed_params->equivalent(*asset, 1, 1, mwindow->edl)) + if( changed_params->equivalent(*asset, 1, 1, mwindow->edl) ) changed = 1; } - else - { + else { nested_edl = (EDL*)indexable; - if(strcmp(changed_params->path, nested_edl->path) -// || -// changed_params->sample_rate != nested_edl->session->sample_rate || -// !EQUIV(changed_params->frame_rate, nested_edl->session->frame_rate) - ) + if( strcmp(changed_params->path, nested_edl->path) +// || changed_params->sample_rate != nested_edl->session->sample_rate +// || !EQUIV(changed_params->frame_rate, nested_edl->session->frame_rate + ) changed = 1; } -//printf("AssetEdit::handle_close_event %d\n", __LINE__); - - if(changed) - { + if(changed) { mwindow->gui->lock_window(); //printf("AssetEdit::handle_close_event %d\n", __LINE__); // Omit index status from copy since an index rebuild may have been // happening when new_asset was created but not be happening anymore. - if(asset) - { + if(asset) { mwindow->remove_asset_from_caches(asset); //printf("AssetEdit::handle_close_event %d %f\n", __LINE__, asset->get_frame_rate()); asset->copy_from(changed_params, 0); //printf("AssetEdit::handle_close_event %d %d %d\n", __LINE__, changed_params->bits, asset->bits); } - else - { + else { strcpy(nested_edl->path, changed_params->path); // Other parameters can't be changed because they're defined in the other EDL // nested_edl->session->frame_rate = changed_params->frame_rate; @@ -168,18 +159,11 @@ void AssetEdit::handle_close_event(int result) } //printf("AssetEdit::handle_close_event %d\n", __LINE__); - mwindow->gui->update(0, - 2, - 0, - 0, - 0, - 0, - 0); + mwindow->gui->update(0, 2, 0, 0, 0, 0, 0); //printf("AssetEdit::handle_close_event %d\n", __LINE__); // Start index rebuilding - if( (asset && asset->audio_data) || nested_edl) - { + if( (asset && asset->audio_data) || nested_edl) { char source_filename[BCTEXTLEN]; char index_filename[BCTEXTLEN]; IndexFile::get_index_filename(source_filename, diff --git a/cinelerra-5.1/cinelerra/cicolors.C b/cinelerra-5.1/cinelerra/cicolors.C index 0d46ff06..8b99fb5c 100644 --- a/cinelerra-5.1/cinelerra/cicolors.C +++ b/cinelerra-5.1/cinelerra/cicolors.C @@ -32,38 +32,23 @@ HSV::~HSV() { } -YUV HSV::yuv_static; +YUV YUV::yuv; int HSV::rgb_to_hsv(float r, float g, float b, float &h, float &s, float &v) { - float min, max, delta; - min = ((r < g) ? r : g) < b ? ((r < g) ? r : g) : b; - max = ((r > g) ? r : g) > b ? ((r > g) ? r : g) : b; - v = max; - - delta = max - min; - - if(max != 0 && delta != 0) - { - s = delta / max; // s - - if(r == max) - h = (g - b) / delta; // between yellow & magenta - else - if(g == max) - h = 2 + (b - r) / delta; // between cyan & yellow - else - h = 4 + (r - g) / delta; // between magenta & cyan - - h *= 60; // degrees - if(h < 0) - h += 360; + float min = ((r < g) ? r : g) < b ? ((r < g) ? r : g) : b; + float max = ((r > g) ? r : g) > b ? ((r > g) ? r : g) : b; + float delta = max - min; + if( max != 0 && delta != 0 ) { + v = max; + s = delta / max; + h = r == max ? (g - b) / delta : // between yellow & magenta + g == max ? 2 + (b - r) / delta : // between cyan & yellow + 4 + (r - g) / delta; // between magenta & cyan + if( (h*=60) < 0 ) h += 360; // degrees } - else - { - // r = g = b = 0 // s = 0, v is undefined - s = 0; - h = -1; + else { // r = g = b = 0 + h = -1; s = 0; v = 0; // s = 0, v is undefined } return 0; @@ -71,55 +56,26 @@ int HSV::rgb_to_hsv(float r, float g, float b, float &h, float &s, float &v) int HSV::hsv_to_rgb(float &r, float &g, float &b, float h, float s, float v) { - int i; - float f, p, q, t; - if(s == 0) - { - // achromatic (grey) - r = g = b = v; - return 0; - } - - h /= 60; // sector 0 to 5 - i = (int)h; - f = h - i; // factorial part of h - p = v * (1 - s); - q = v * (1 - s * f); - t = v * (1 - s * (1 - f)); - - switch(i) - { - case 0: - r = v; - g = t; - b = p; - break; - case 1: - r = q; - g = v; - b = p; - break; - case 2: - r = p; - g = v; - b = t; - break; - case 3: - r = p; - g = q; - b = v; - break; - case 4: - r = t; - g = p; - b = v; - break; - default: // case 5: - r = v; - g = p; - b = q; - break; - } + if( s == 0 ) { // achromatic (grey) + r = g = b = v; + return 0; + } + + h /= 60; // sector 0 to 5 + int i = (int)h; + float f = h - i; // factorial part of h + float p = v * (1 - s); + float q = v * (1 - s * f); + float t = v * (1 - s * (1 - f)); + + switch(i) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + default: r = v; g = p; b = q; break; + } return 0; } @@ -130,11 +86,11 @@ int HSV::yuv_to_hsv(int y, int u, int v, float &h, float &s, float &va, int max) // if(max == 0xffff) // { -// yuv_static.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v); +// YUV::yuv.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v); // } // else { - yuv_static.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v); + YUV::yuv.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v); } r = (float)r_i / max; g = (float)g_i / max; @@ -142,10 +98,8 @@ int HSV::yuv_to_hsv(int y, int u, int v, float &h, float &s, float &va, int max) float h2, s2, v2; HSV::rgb_to_hsv(r, g, b, h2, s2, v2); - h = h2; - s = s2; - va = v2; + h = h2; s = s2; va = v2; return 0; } @@ -163,43 +117,17 @@ int HSV::hsv_to_yuv(int &y, int &u, int &v, float h, float s, float va, int max) int y2, u2, v2; // if(max == 0xffff) -// yuv_static.rgb_to_yuv_16(r_i, g_i, b_i, y2, u2, v2); +// YUV::yuv.rgb_to_yuv_16(r_i, g_i, b_i, y2, u2, v2); // else - yuv_static.rgb_to_yuv_8(r_i, g_i, b_i, y2, u2, v2); - y = y2; - u = u2; - v = v2; + YUV::yuv.rgb_to_yuv_8(r_i, g_i, b_i, y2, u2, v2); + y = y2; u = u2; v = v2; return 0; } - - - - - - - - - - - - - - - - - - - - - - - YUV::YUV() { - for(int i = 0; i < 0x100; i++) - { + for(int i = 0; i < 0x100; i++) { // compression rtoy_tab_8[i] = (int)(R_TO_Y * 0x100 * i); rtou_tab_8[i] = (int)(R_TO_U * 0x100 * i); @@ -219,8 +147,7 @@ YUV::YUV() utog_8 = &(utog_tab_8[(0x100) / 2]); utob_8 = &(utob_tab_8[(0x100) / 2]); - for(int i = (-0x100) / 2; i < (0x100) / 2; i++) - { + for(int i = (-0x100) / 2; i < (0x100) / 2; i++) { // decompression vtor_8[i] = (int)(V_TO_R * 0x100 * i); vtog_8[i] = (int)(V_TO_G * 0x100 * i); @@ -229,8 +156,7 @@ YUV::YUV() utob_8[i] = (int)(U_TO_B * 0x100 * i); } - for(int i = 0; i < 0x10000; i++) - { + for(int i = 0; i < 0x10000; i++) { // compression rtoy_tab_16[i] = (int)(R_TO_Y * 0x100 * i); rtou_tab_16[i] = (int)(R_TO_U * 0x100 * i); @@ -250,8 +176,7 @@ YUV::YUV() utog_16 = &(utog_tab_16[(0x10000) / 2]); utob_16 = &(utob_tab_16[(0x10000) / 2]); - for(int i = (-0x10000) / 2; i < (0x10000) / 2; i++) - { + for(int i = (-0x10000) / 2; i < (0x10000) / 2; i++) { // decompression vtor_16[i] = (int)(V_TO_R * 0x100 * i); vtog_16[i] = (int)(V_TO_G * 0x100 * i); @@ -264,3 +189,4 @@ YUV::YUV() YUV::~YUV() { } + diff --git a/cinelerra-5.1/cinelerra/cicolors.h b/cinelerra-5.1/cinelerra/cicolors.h index e8fca408..1ab7ab45 100644 --- a/cinelerra-5.1/cinelerra/cicolors.h +++ b/cinelerra-5.1/cinelerra/cicolors.h @@ -55,6 +55,7 @@ class YUV public: YUV(); ~YUV(); + static YUV yuv; inline void rgb_to_yuv_8(int &y, int &u, int &v) { @@ -220,7 +221,6 @@ public: // Dummies for macros static int yuv_to_hsv(float y, float u, float v, float &h, float &s, float &va, float max) { return 0; }; static int hsv_to_yuv(float &y, float &u, float &v, float h, float s, float va, float max) { return 0; }; - static YUV yuv_static; }; diff --git a/cinelerra-5.1/cinelerra/edl.C b/cinelerra-5.1/cinelerra/edl.C index 1b00471b..41ee55b4 100644 --- a/cinelerra-5.1/cinelerra/edl.C +++ b/cinelerra-5.1/cinelerra/edl.C @@ -758,7 +758,7 @@ double EDL::equivalent_output(EDL *edl) } -void EDL::set_path(char *path) +void EDL::set_path(const char *path) { strcpy(this->path, path); } diff --git a/cinelerra-5.1/cinelerra/edl.h b/cinelerra-5.1/cinelerra/edl.h index 69494c25..dbafb41e 100644 --- a/cinelerra-5.1/cinelerra/edl.h +++ b/cinelerra-5.1/cinelerra/edl.h @@ -121,7 +121,7 @@ public: // This is used by BRender + BatchRender. double equivalent_output(EDL *edl); // Set project path for filename prefixes in the assets - void set_path(char *path); + void set_path(const char *path); // Set points and labels void set_inpoint(double position); void set_outpoint(double position); diff --git a/cinelerra-5.1/cinelerra/mwindow.C b/cinelerra-5.1/cinelerra/mwindow.C index 7b0a52fe..aee8aadb 100644 --- a/cinelerra-5.1/cinelerra/mwindow.C +++ b/cinelerra-5.1/cinelerra/mwindow.C @@ -2470,8 +2470,8 @@ SET_TRACE // Needs mwindow to do GUI gui->set_mwindow(this); gui->open_plugin(0, preferences, edl, plugin); - gui->show_gui(); plugin->show = 1; + gui->show_gui(); } } plugin_gui_lock->unlock(); diff --git a/cinelerra-5.1/cinelerra/pluginserver.C b/cinelerra-5.1/cinelerra/pluginserver.C index cd69dfe7..0c72a358 100644 --- a/cinelerra-5.1/cinelerra/pluginserver.C +++ b/cinelerra-5.1/cinelerra/pluginserver.C @@ -150,30 +150,45 @@ int PluginServer::reset_parameters() keyframe = 0; prompt = 0; cleanup_plugin(); - autos = 0; - edl = 0; - preferences = 0; - title = 0; - path = 0; + + lad_index = -1; + lad_descriptor_function = 0; + lad_descriptor = 0; + + plugin_obj = 0; + client = 0; + new_plugin = 0; + lad_index = -1; + lad_descriptor_function = 0; + lad_descriptor = 0; + use_opengl = 0; ff_name = 0; - audio = video = theme = 0; - fileio = 0; - uses_gui = 0; + vdevice = 0; + plugin_type = 0; + start_auto = end_auto = 0; + autos = 0; + reverse = 0; + plugin_open = 0; realtime = multichannel = fileio = 0; synthesis = 0; - start_auto = end_auto = 0; + audio = video = theme = 0; + uses_gui = 0; transition = 0; - new_plugin = 0; - client = 0; - use_opengl = 0; - vdevice = 0; + title = 0; + path = 0; + data_text = 0; + for( int i=sizeof(args)/sizeof(args[0]); --i>=0; ) args[i] = 0; + total_args = 0; + dir_idx = 0; modules = 0; nodes = 0; + attachmentpoint = 0; + edl = 0; + preferences = 0; + prompt = 0; + temp_frame = 0; picon = 0; - lad_index = -1; - lad_descriptor_function = 0; - lad_descriptor = 0; return 0; } @@ -1243,27 +1258,8 @@ int PluginServer::get_plugin_png_path(char *png_path) VFrame *PluginServer::get_plugin_images() { char png_path[BCTEXTLEN]; - int len = get_plugin_png_path(png_path); - if( !len ) return 0; - int ret = 0, w = 0, h = 0; - unsigned char *bfr = 0; - int fd = ::open(png_path, O_RDONLY); - if( fd < 0 ) ret = 1; - if( !ret ) { - bfr = (unsigned char *) ::mmap (NULL, len, PROT_READ, MAP_SHARED, fd, 0); - if( bfr == MAP_FAILED ) ret = 1; - } - VFrame *vframe = 0; - if( !ret ) { - double scale = BC_WindowBase::get_resources()->icon_scale; - vframe = new VFramePng(bfr, len, scale, scale); - if( (w=vframe->get_w()) <= 0 || (h=vframe->get_h()) <= 0 || - vframe->get_data() == 0 ) ret = 1; - } - if( bfr && bfr != MAP_FAILED ) ::munmap(bfr, len); - if( fd >= 0 ) ::close(fd); - if( ret ) { delete vframe; vframe = 0; } - return vframe; + if( !get_plugin_png_path(png_path) ) return 0; + return VFramePng::vframe_png(png_path,0,0); } VFrame *PluginServer::get_picon() diff --git a/cinelerra-5.1/cinelerra/renderengine.h b/cinelerra-5.1/cinelerra/renderengine.h index f8968ff4..fd400c2d 100644 --- a/cinelerra-5.1/cinelerra/renderengine.h +++ b/cinelerra-5.1/cinelerra/renderengine.h @@ -27,6 +27,7 @@ class RenderEngine; #include "arender.inc" #include "audiodevice.inc" +#include "bctimer.h" #include "cache.inc" #include "canvas.inc" #include "channel.inc" diff --git a/cinelerra-5.1/guicast/bctextbox.C b/cinelerra-5.1/guicast/bctextbox.C index 4eef5347..e8cb09ce 100644 --- a/cinelerra-5.1/guicast/bctextbox.C +++ b/cinelerra-5.1/guicast/bctextbox.C @@ -2166,46 +2166,18 @@ void BC_ScrollTextBox::create_objects() set_text_row(0); } -int BC_ScrollTextBox::handle_event() -{ - return 1; -} - -int BC_ScrollTextBox::get_x() -{ - return x; -} - -int BC_ScrollTextBox::get_y() -{ - return y; -} - -int BC_ScrollTextBox::get_w() -{ - return w; -} - -int BC_ScrollTextBox::get_h() -{ - return this->text->get_h(); -} - -int BC_ScrollTextBox::get_rows() -{ - return rows; -} - - -const char* BC_ScrollTextBox::get_text() -{ - return text->get_text(); -} - -const wchar_t* BC_ScrollTextBox::get_wtext() -{ - return text->get_wtext(); -} +int BC_ScrollTextBox::handle_event() { return 1; } +int BC_ScrollTextBox::button_press_event() { return text->BC_TextBox::button_press_event(); } +int BC_ScrollTextBox::button_release_event() { return text->BC_TextBox::button_release_event(); } +int BC_ScrollTextBox::get_buttonpress() { return text->BC_TextBox::get_buttonpress(); }; +int BC_ScrollTextBox::get_x() { return x; } +int BC_ScrollTextBox::get_y() { return y; } +int BC_ScrollTextBox::get_w() { return w; } +int BC_ScrollTextBox::get_h() { return text->get_h(); } +int BC_ScrollTextBox::get_rows() { return rows; } + +const char* BC_ScrollTextBox::get_text() { return text->get_text(); } +const wchar_t* BC_ScrollTextBox::get_wtext() { return text->get_wtext(); } void BC_ScrollTextBox::set_text(char *text, int isz) { @@ -2326,7 +2298,6 @@ int BC_ScrollTextBoxText::motion_event() return 1; } - BC_ScrollTextBoxYScroll::BC_ScrollTextBoxYScroll(BC_ScrollTextBox *gui) : BC_ScrollBar(gui->x + gui->w - diff --git a/cinelerra-5.1/guicast/bctextbox.h b/cinelerra-5.1/guicast/bctextbox.h index 56514cad..bb79e689 100644 --- a/cinelerra-5.1/guicast/bctextbox.h +++ b/cinelerra-5.1/guicast/bctextbox.h @@ -231,6 +231,16 @@ class BC_ScrollTextBoxYScroll; class BC_ScrollTextBox { + BC_ScrollTextBoxText *text; + BC_ScrollTextBoxYScroll *yscroll; + BC_WindowBase *parent_window; + const char *default_text; + const wchar_t *default_wtext; + int default_size; + int x, y, w, rows; + + friend class BC_ScrollTextBoxText; + friend class BC_ScrollTextBoxYScroll; public: BC_ScrollTextBox(BC_WindowBase *parent_window, int x, int y, int w, int rows, @@ -241,6 +251,9 @@ public: virtual ~BC_ScrollTextBox(); void create_objects(); virtual int handle_event(); + virtual int button_press_event(); + virtual int button_release_event(); + int get_buttonpress(); const char* get_text(); const wchar_t* get_wtext(); @@ -251,6 +264,7 @@ public: void set_selection(int char1, int char2, int ibeam); void wset_selection(int char1, int char2, int ibeam); void reposition_window(int x, int y, int w, int rows); + int get_x(); int get_y(); int get_w(); @@ -258,18 +272,6 @@ public: // Visible rows for resizing int get_rows(); int get_ibeam_letter(); - - friend class BC_ScrollTextBoxText; - friend class BC_ScrollTextBoxYScroll; - -private: - BC_ScrollTextBoxText *text; - BC_ScrollTextBoxYScroll *yscroll; - BC_WindowBase *parent_window; - const char *default_text; - const wchar_t *default_wtext; - int default_size; - int x, y, w, rows; }; class BC_ScrollTextBoxText : public BC_TextBox @@ -281,6 +283,8 @@ public: int handle_event(); int motion_event(); BC_ScrollTextBox *gui; + int button_press_event() { return gui->button_press_event(); } + int button_release_event() { return gui->button_release_event(); } }; class BC_ScrollTextBoxYScroll : public BC_ScrollBar diff --git a/cinelerra-5.1/guicast/bcwindowbase.C b/cinelerra-5.1/guicast/bcwindowbase.C index 7d4fa2b5..366fbca6 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.C +++ b/cinelerra-5.1/guicast/bcwindowbase.C @@ -117,6 +117,7 @@ BC_WindowBase::~BC_WindowBase() #ifndef SINGLE_THREAD top_level->dequeue_events(win); #endif + if(top_level->active_grab == this) top_level->active_grab = 0; if(top_level->active_menubar == this) top_level->active_menubar = 0; if(top_level->active_popup_menu == this) top_level->active_popup_menu = 0; if(top_level->active_subwindow == this) top_level->active_subwindow = 0; @@ -284,6 +285,7 @@ int BC_WindowBase::initialize() event_win = 0; last_motion_win = 0; key_pressed = 0; + active_grab = 0; active_menubar = 0; active_popup_menu = 0; active_subwindow = 0; @@ -955,7 +957,10 @@ locking_message = event->xclient.message_type; // event_names[event->type] : "Unknown"); //} - + if( active_grab && active_grab->grab_event(event) ) { + unlock_window(); + return 0; + } switch(event->type) { @@ -3300,6 +3305,19 @@ void BC_WindowBase::close(int return_value) set_done(return_value); } +int BC_WindowBase::grab(BC_WindowBase *window) +{ + if( window->active_grab && this != window->active_grab ) return 0; + window->active_grab = this; + return 1; +} +int BC_WindowBase::ungrab(BC_WindowBase *window) +{ + if( window->active_grab && this != window->active_grab ) return 0; + window->active_grab = 0; + return 1; +} + int BC_WindowBase::get_w() { return w; diff --git a/cinelerra-5.1/guicast/bcwindowbase.h b/cinelerra-5.1/guicast/bcwindowbase.h index 4136b110..4ba5d8fc 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.h +++ b/cinelerra-5.1/guicast/bcwindowbase.h @@ -195,6 +195,7 @@ public: virtual int uses_text() { return 0; }; // Only if opengl is enabled virtual int expose_event() { return 0; }; + virtual int grab_event(XEvent *event) { return 0; }; virtual void create_objects() { return; }; int get_window_type() { return window_type; } @@ -453,6 +454,9 @@ public: int get_id(); void set_done(int return_value); void close(int return_value); +// Reroute toplevel events + int grab(BC_WindowBase *window); + int ungrab(BC_WindowBase *window); // Get a bitmap to draw on the window with BC_Bitmap* new_bitmap(int w, int h, int color_model = -1); // Draw a bitmap on the window @@ -629,6 +633,8 @@ private: int light1, light2, medium, dark1, dark2, bg_color; // Type of window defined above int window_type; +// keypress/pointer active grab + BC_WindowBase* active_grab; // Pointer to the active menubar in the window. BC_MenuBar* active_menubar; // pointer to the active popup menu in the window diff --git a/cinelerra-5.1/guicast/clip.h b/cinelerra-5.1/guicast/clip.h index 3b51b601..4246f2ec 100644 --- a/cinelerra-5.1/guicast/clip.h +++ b/cinelerra-5.1/guicast/clip.h @@ -61,5 +61,20 @@ static inline void bclamp(float &fv, float fmn, float fmx) { static inline void bclamp(double &dv, double dmn, double dmx) { if( dv < dmn ) dv = dmn; else if( dv > dmx ) dv = dmx; } +static inline void bc_rgb2yuv(int r, int g, int b, int &y, int &u, int &v, int max=255) +{ //bt601, jpeg, unclipped + double mx = max, rr = r/mx, gg = g/mx, bb = b/mx; + y = (int)(( 0.29900*rr + 0.58700*gg + 0.11400*bb) * mx + 0.5); + u = (int)((-0.16874*rr - 0.33126*gg + 0.50000*bb + 0.5) * mx + 0.5); + v = (int)(( 0.50000*rr - 0.41869*gg - 0.08131*bb + 0.5) * mx + 0.5); +} +static inline void bc_yuv2rgb(int y, int u, int v, int &r, int &g, int &b, int max=255) +{ + int ofs = (max + 1) / 2; + double mx = max, yy = y/mx, uu = (u-ofs)/mx, vv = (v-ofs)/mx; + r = (int)((yy + 1.40200*vv) * mx + 0.5); + g = (int)((yy - 0.34414*uu - 0.71414*vv) * mx + 0.5); + b = (int)((yy + 1.77200*uu) * mx + 0.5); +} #endif diff --git a/cinelerra-5.1/guicast/vframe.C b/cinelerra-5.1/guicast/vframe.C index 941ec09e..0ae65a66 100644 --- a/cinelerra-5.1/guicast/vframe.C +++ b/cinelerra-5.1/guicast/vframe.C @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include "bcbitmap.h" #include "bchash.h" @@ -78,27 +80,53 @@ VFrameScene::~VFrameScene() //static BCCounter counter; - -VFramePng::VFramePng(unsigned char *png_data, double scale) +VFramePng::VFramePng(unsigned char *png_data, double s) { long image_size = ((long)png_data[0] << 24) | ((long)png_data[1] << 16) | ((long)png_data[2] << 8) | (long)png_data[3]; - if( !scale ) scale = BC_WindowBase::get_resources()->icon_scale; - read_png(png_data+4, image_size, scale, scale); + if( !s ) s = BC_WindowBase::get_resources()->icon_scale; + read_png(png_data+4, image_size, s, s); } -VFramePng::VFramePng(unsigned char *png_data, long image_size, double xscale, double yscale) +VFramePng::VFramePng(unsigned char *png_data, long image_size, double xs, double ys) { - if( !xscale ) xscale = BC_WindowBase::get_resources()->icon_scale; - if( !yscale ) yscale = BC_WindowBase::get_resources()->icon_scale; - read_png(png_data, image_size, xscale, yscale); + if( !xs ) xs = BC_WindowBase::get_resources()->icon_scale; + if( !ys ) ys = BC_WindowBase::get_resources()->icon_scale; + read_png(png_data, image_size, xs, ys); } VFramePng::~VFramePng() { } +VFrame *VFramePng::vframe_png(int fd, double xs, double ys) +{ + struct stat st; + if( fstat(fd, &st) ) return 0; + long len = st.st_size; + if( !len ) return 0; + int w = 0, h = 0; + unsigned char *bfr = (unsigned char *) + ::mmap (NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if( bfr == MAP_FAILED ) return 0; + VFrame *vframe = new VFramePng(bfr, len, xs, ys); + if( (w=vframe->get_w()) <= 0 || (h=vframe->get_h()) <= 0 || + vframe->get_data() == 0 ) { delete vframe; vframe = 0; } + ::munmap(bfr, len); + return vframe; +} +VFrame *VFramePng::vframe_png(const char *png_path, double xs, double ys) +{ + VFrame *vframe = 0; + int fd = ::open(png_path, O_RDONLY); + if( fd >= 0 ) { + vframe = vframe_png(fd, xs, ys); + ::close(fd); + } + return vframe; +} + VFrame::VFrame(VFrame &frame) { @@ -249,6 +277,9 @@ int VFrame::reset_parameters(int do_opengl) sequence_number = -1; timestamp = -1.; is_keyframe = 0; + draw_point = 0; + set_pixel_color(BLACK); + stipple = 0; if(do_opengl) { @@ -1104,58 +1135,6 @@ int VFrame::transfer_from(VFrame *that, int bg_color, int in_x, int in_y, int in } - - - - -#define OVERLAY(type, max, components) \ -{ \ - type **in_rows = (type**)src->get_rows(); \ - type **out_rows = (type**)get_rows(); \ - int in_w = src->get_w(); \ - int in_h = src->get_h(); \ - \ - for(int i = 0; i < in_h; i++) \ - { \ - if(i + out_y1 >= 0 && i + out_y1 < h) \ - { \ - type *src_row = in_rows[i]; \ - type *dst_row = out_rows[i + out_y1] + out_x1 * components; \ - \ - for(int j = 0; j < in_w; j++) \ - { \ - if(j + out_x1 >= 0 && j + out_x1 < w) \ - { \ - int opacity = src_row[3]; \ - int transparency = dst_row[3] * (max - src_row[3]) / max; \ - dst_row[0] = (transparency * dst_row[0] + opacity * src_row[0]) / max; \ - dst_row[1] = (transparency * dst_row[1] + opacity * src_row[1]) / max; \ - dst_row[2] = (transparency * dst_row[2] + opacity * src_row[2]) / max; \ - dst_row[3] = MAX(dst_row[3], src_row[3]); \ - } \ - \ - dst_row += components; \ - src_row += components; \ - } \ - } \ - } \ -} - - -void VFrame::overlay(VFrame *src, - int out_x1, - int out_y1) -{ - switch(get_color_model()) - { - case BC_RGBA8888: - OVERLAY(unsigned char, 0xff, 4); - break; - } -} - - - int VFrame::get_scale_tables(int *column_table, int *row_table, int in_x1, int in_y1, int in_x2, int in_y2, int out_x1, int out_y1, int out_x2, int out_y2) @@ -1312,62 +1291,75 @@ int VFrame::get_memory_usage() return get_h() * get_bytes_per_line(); } -void VFrame::draw_pixel(int x, int y) +void VFrame::set_pixel_color(int rgb) { - if(!(x >= 0 && y >= 0 && x < get_w() && y < get_h())) return; + pixel_rgb = rgb; + int ir = 0xff & (pixel_rgb >> 16); + int ig = 0xff & (pixel_rgb >> 8); + int ib = 0xff & (pixel_rgb >> 0); + bc_rgb2yuv(ir,ig,ib, ir,ig,ib); + bclamp(ir,0,255); + bclamp(ig,0,255); + bclamp(ib,0,255); + pixel_yuv = (ir<<16) | (ig<<8) | (ib<<0); +} -#define DRAW_PIXEL(x, y, components, do_yuv, max, type) \ -{ \ - type **rows = (type**)get_rows(); \ - rows[y][x * components] = max - rows[y][x * components]; \ - if(!do_yuv) \ - { \ - rows[y][x * components + 1] = max - rows[y][x * components + 1]; \ - rows[y][x * components + 2] = max - rows[y][x * components + 2]; \ - } \ - else \ - { \ - rows[y][x * components + 1] = (max / 2 + 1) - rows[y][x * components + 1]; \ - rows[y][x * components + 2] = (max / 2 + 1) - rows[y][x * components + 2]; \ - } \ - if(components == 4) \ - rows[y][x * components + 3] = max; \ +void VFrame::set_stiple(int mask) +{ + stipple = mask; } +int VFrame::draw_pixel(int x, int y) +{ + if( x < 0 || y < 0 || x >= get_w() || y >= get_h() ) return 1; + if( draw_point ) return (this->*draw_point)(x, y); - switch(get_color_model()) - { - case BC_RGB888: - DRAW_PIXEL(x, y, 3, 0, 0xff, unsigned char); - break; - case BC_RGBA8888: - DRAW_PIXEL(x, y, 4, 0, 0xff, unsigned char); - break; - case BC_RGB_FLOAT: - DRAW_PIXEL(x, y, 3, 0, 1.0, float); - break; - case BC_RGBA_FLOAT: - DRAW_PIXEL(x, y, 4, 0, 1.0, float); - break; - case BC_YUV888: - DRAW_PIXEL(x, y, 3, 1, 0xff, unsigned char); - break; - case BC_YUVA8888: - DRAW_PIXEL(x, y, 4, 1, 0xff, unsigned char); - break; - case BC_RGB161616: - DRAW_PIXEL(x, y, 3, 0, 0xffff, uint16_t); - break; - case BC_YUV161616: - DRAW_PIXEL(x, y, 3, 1, 0xffff, uint16_t); - break; - case BC_RGBA16161616: - DRAW_PIXEL(x, y, 4, 0, 0xffff, uint16_t); - break; - case BC_YUVA16161616: - DRAW_PIXEL(x, y, 4, 1, 0xffff, uint16_t); - break; +#define DRAW_PIXEL(type, r, g, b) { \ + type **rows = (type**)get_rows(); \ + rows[y][x * components + 0] = r; \ + rows[y][x * components + 1] = g; \ + rows[y][x * components + 2] = b; \ + if( components == 4 ) \ + rows[y][x * components + 3] = mx; \ +} + int components = BC_CModels::components(color_model); + int bch = BC_CModels::calculate_pixelsize(color_model) / components; + int sz = 8*bch, mx = BC_CModels::is_float(color_model) ? 1 : (1<> 16); float fr = 0; + int ig = 0xff & (pixel_color >> 8); float fg = 0; + int ib = 0xff & (pixel_color >> 0); float fb = 0; + if( (x+y) & stipple ) { + ir = 255 - ir; ig = 255 - ig; ib = 255 - ib; + } + if( BC_CModels::is_float(color_model) ) { + fr = ir / 255.; fg = ig / 255.; fb = ib / 255.; + mx = 1; + } + else if( (sz-=8) > 0 ) { + ir <<= sz; ig <<= sz; ib <<= sz; + } + + switch(get_color_model()) { + case BC_RGB888: + case BC_YUV888: + case BC_RGBA8888: + case BC_YUVA8888: + DRAW_PIXEL(uint8_t, ir, ig, ib); + break; + case BC_RGB161616: + case BC_YUV161616: + case BC_RGBA16161616: + case BC_YUVA16161616: + DRAW_PIXEL(uint16_t, ir, ig, ib); + break; + case BC_RGB_FLOAT: + case BC_RGBA_FLOAT: + DRAW_PIXEL(float, fr, fg, fb); + break; } + return 0; } diff --git a/cinelerra-5.1/guicast/vframe.h b/cinelerra-5.1/guicast/vframe.h index 73ec70da..44695ba7 100644 --- a/cinelerra-5.1/guicast/vframe.h +++ b/cinelerra-5.1/guicast/vframe.h @@ -200,9 +200,6 @@ public: // Set keyframe status void set_keyframe(int value); int get_keyframe(); -// Overlay src onto this with blending and translation of input. -// Source and this must have alpha - void overlay(VFrame *src, int out_x1, int out_y1); // If the opengl state is RAM, transfer image from RAM to the texture // referenced by this frame. @@ -344,7 +341,12 @@ public: // This clears the stacks and the param table void clear_stacks(); - void draw_pixel(int x, int y); + int (VFrame::*draw_point)(int x, int y); + int pixel_rgb, pixel_yuv, stipple; + + void set_pixel_color(int rgb); + void set_stiple(int mask); + int draw_pixel(int x, int y); void draw_line(int x1, int y1, int x2, int y2); void draw_smooth(int x1, int y1, int x2, int y2, int x3, int y3); void smooth_draw(int x1, int y1, int x2, int y2, int x3, int y3); @@ -459,9 +461,11 @@ class VFramePng : public VFrame { // Read a PNG into the frame with alpha int read_png(const unsigned char *data, long image_size, double xscale, double yscale); public: - VFramePng(unsigned char *png_data, double scale=0); + VFramePng(unsigned char *png_data, double s=0); VFramePng(unsigned char *png_data, long image_size, double xs=0, double ys=0); ~VFramePng(); + static VFrame *vframe_png(int fd, double xs=1, double ys=1); + static VFrame *vframe_png(const char *png_path, double xs=1, double ys=1); }; #endif diff --git a/cinelerra-5.1/plugins/polar/polarwindow.C b/cinelerra-5.1/plugins/polar/polarwindow.C index f4bd9c0b..bf777450 100644 --- a/cinelerra-5.1/plugins/polar/polarwindow.C +++ b/cinelerra-5.1/plugins/polar/polarwindow.C @@ -72,6 +72,7 @@ int PolarWindow::close_event() client->save_defaults(); hide_window(); client->send_hide_gui(); + return 1; } DepthSlider::DepthSlider(PolarMain *client, int x, int y) @@ -86,6 +87,7 @@ int DepthSlider::handle_event() { client->depth = get_value(); client->send_configure_change(); + return 1; } AngleSlider::AngleSlider(PolarMain *client, int x, int y) @@ -100,6 +102,7 @@ int AngleSlider::handle_event() { client->angle = get_value(); client->send_configure_change(); + return 1; } AutomatedFn::AutomatedFn(PolarMain *client, PolarWindow *window, int x, int y, int number) @@ -123,5 +126,6 @@ int AutomatedFn::handle_event() update(1); client->automated_function = number; client->send_configure_change(); + return 1; } diff --git a/cinelerra-5.1/plugins/rgbshift/rgbshift.C b/cinelerra-5.1/plugins/rgbshift/rgbshift.C index d76f4d46..6cfb38b2 100644 --- a/cinelerra-5.1/plugins/rgbshift/rgbshift.C +++ b/cinelerra-5.1/plugins/rgbshift/rgbshift.C @@ -268,9 +268,6 @@ void RGBShiftEffect::read_data(KeyFrame *keyframe) } } - -static YUV yuv_static; - #define RGB_MACRO(type, temp_type, components) \ { \ for(int i = 0; i < h; i++) { \ @@ -310,11 +307,11 @@ static YUV yuv_static; temp_type g = gp ? gp[1] : 0; \ temp_type b = bp ? bp[2] : 0; \ if( sizeof(type) == 4 ) \ - yuv_static.rgb_to_yuv_f(r, g, b, y, u, v); \ + YUV::yuv.rgb_to_yuv_f(r, g, b, y, u, v); \ else if( sizeof(type) == 2 ) \ - yuv_static.rgb_to_yuv_16(r, g, b, y, u, v); \ + YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \ else \ - yuv_static.rgb_to_yuv_8(r, g, b, y, u, v); \ + YUV::yuv.rgb_to_yuv_8(r, g, b, y, u, v); \ out_row[0] = y; \ out_row[1] = u; \ out_row[2] = v; \ diff --git a/cinelerra-5.1/plugins/svg/svg.C b/cinelerra-5.1/plugins/svg/svg.C index c80bf199..842161ae 100644 --- a/cinelerra-5.1/plugins/svg/svg.C +++ b/cinelerra-5.1/plugins/svg/svg.C @@ -190,29 +190,17 @@ int SvgMain::process_realtime(VFrame *input, VFrame *output) printf(_("Export of %s to %s failed\n"), config.svg_file, filename_png); } if( fd >= 0 ) { - struct stat st_png; - fstat(fd, &st_png); - unsigned char *png_buffer = (unsigned char *) - mmap (NULL, st_png.st_size, PROT_READ, MAP_SHARED, fd, 0); - if( png_buffer != MAP_FAILED ) { - if( png_buffer[0] == 0x89 && png_buffer[1] == 0x50 && - png_buffer[2] == 0x4e && png_buffer[3] == 0x47 ) { - ofrm = new VFramePng(png_buffer, st_png.st_size, 1., 1.); - if( ofrm->get_color_model() != output->get_color_model() ) { - VFrame *vfrm = new VFrame(ofrm->get_w(), ofrm->get_h(), - output->get_color_model()); - vfrm->transfer_from(ofrm); - delete ofrm; ofrm = vfrm; - } - } - else - printf (_("The file %s that was generated from %s is not in PNG format." - " Try to delete all *.png files.\n"), filename_png, config.svg_file); - munmap(png_buffer, st_png.st_size); - } - else - printf(_("Access mmap to %s as %s failed.\n"), config.svg_file, filename_png); + ofrm = VFramePng::vframe_png(fd); close(fd); + if( ofrm && ofrm->get_color_model() != output->get_color_model() ) { + VFrame *vfrm = new VFrame(ofrm->get_w(), ofrm->get_h(), + output->get_color_model()); + vfrm->transfer_from(ofrm); + delete ofrm; ofrm = vfrm; + } + if( !ofrm ) + printf (_("The file %s that was generated from %s is not in PNG format." + " Try to delete all *.png files.\n"), filename_png, config.svg_file); } } if( ofrm ) { diff --git a/cinelerra-5.1/plugins/titler/Makefile b/cinelerra-5.1/plugins/titler/Makefile index 5bb84157..3e520ac7 100644 --- a/cinelerra-5.1/plugins/titler/Makefile +++ b/cinelerra-5.1/plugins/titler/Makefile @@ -1,24 +1,17 @@ include ../../plugin_defs -OBJS = $(OBJDIR)/title.o \ - $(OBJDIR)/titlewindow.o - - +OBJS = $(OBJDIR)/titler.o \ + $(OBJDIR)/titlerwindow.o PLUGIN = titler CFLAGS += -Wall -#CFLAGS += -I$(FREETYPE_DIR)/include -I../../thirdparty/ -#LFLAGS += $(FREETYPE_DIR)/$(OBJDIR)/libfreetype.a + ifneq ($(STATIC_LIBRARIES), y) LFLAGS += -lfreetype endif include ../../plugin_config - - -$(OBJDIR)/title.o: title.C -$(OBJDIR)/titlewindow.o: titlewindow.C - - +$(OBJDIR)/titler.o: titler.C +$(OBJDIR)/titlerwindow.o: titlerwindow.C diff --git a/cinelerra-5.1/plugins/titler/title.C b/cinelerra-5.1/plugins/titler/title.C deleted file mode 100644 index 0fbfec99..00000000 --- a/cinelerra-5.1/plugins/titler/title.C +++ /dev/null @@ -1,2203 +0,0 @@ - -/* - * CINELERRA - * Copyright (C) 1997-2014 Adam Williams - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -// Originally developed by Heroine Virtual Ltd. -// Support for multiple encodings, outline (stroke) by -// Andraz Tori -// Additional support for UTF-8 by -// Paolo Rampino aka Akirad - - - - -#include "bcsignals.h" -#include "clip.h" -#include "bccmodels.h" -#include "filexml.h" -#include "filesystem.h" -#include "transportque.inc" -#include "ft2build.h" -#include FT_GLYPH_H -#include FT_BBOX_H -#include FT_OUTLINE_H -#include FT_STROKER_H -#include "language.h" -#include "mwindow.inc" -#include "cicolors.h" -#include "title.h" -#include "titlewindow.h" -#include "transportque.inc" - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ZERO (1.0 / 64.0) - -REGISTER_PLUGIN(TitleMain) - -#ifdef X_HAVE_UTF8_STRING -#define DEFAULT_ENCODING "UTF-8" -#else -#define DEFAULT_ENCODING "ISO8859-1" -#endif -#define DEFAULT_TIMECODEFORMAT TIME_HMS - -static YUV yuv; - -TitleConfig::TitleConfig() -{ - style = 0; - color = BLACK; - alpha = 0xff; - outline_alpha = 0xff; - size = 24; - motion_strategy = NO_MOTION; - loop = 0; - line_pitch = 0; - hjustification = JUSTIFY_CENTER; - vjustification = JUSTIFY_MID; - fade_in = 0.0; - fade_out = 0.0; - x = 0.0; - y = 0.0; - dropshadow = 2; - sprintf(font, "fixed"); - sprintf(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; - - outline_size = 0; - window_w = 640; - window_h = 480; - next_keyframe_position = 0; - prev_keyframe_position = 0; -} - -TitleConfig::~TitleConfig() -{ -} - -// Does not test equivalency but determines if redrawing text is necessary. -int TitleConfig::equivalent(TitleConfig &that) -{ - return dropshadow == that.dropshadow && - 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_alpha == that.outline_alpha && - timecode == that.timecode && - timecode_format == that.timecode_format && - line_pitch == that.line_pitch && - outline_size == that.outline_size && - hjustification == that.hjustification && - vjustification == that.vjustification && - EQUIV(pixels_per_second, that.pixels_per_second) && - !strcasecmp(font, that.font) && - !strcasecmp(encoding, that.encoding) && - wlen == that.wlen && - !memcmp(wtext, that.wtext, wlen * sizeof(wchar_t)); -} - -void TitleConfig::copy_from(TitleConfig &that) -{ - strcpy(font, that.font); - 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_alpha = that.outline_alpha; - pixels_per_second = that.pixels_per_second; - motion_strategy = that.motion_strategy; - loop = that.loop; - line_pitch = that.line_pitch; - hjustification = that.hjustification; - vjustification = that.vjustification; - fade_in = that.fade_in; - fade_out = that.fade_out; - x = that.x; - y = that.y; - dropshadow = that.dropshadow; - timecode = that.timecode; - 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; - - limits(); -} - -void TitleConfig::interpolate(TitleConfig &prev, - TitleConfig &next, - int64_t prev_frame, - int64_t next_frame, - int64_t current_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_alpha = prev.outline_alpha; - motion_strategy = prev.motion_strategy; - loop = prev.loop; - line_pitch = prev.line_pitch; - 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; - 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->x = prev.x * prev_scale + next.x * next_scale; - this->y = prev.y * prev_scale + next.y * next_scale; -// this->x = prev.x; -// this->y = prev.y; - timecode = prev.timecode; - timecode_format = prev.timecode_format; - this->dropshadow = prev.dropshadow * prev_scale + next.dropshadow * next_scale; -// this->dropshadow = prev.dropshadow; -} - -void TitleConfig::limits() -{ - if(window_w < 100) window_w = 100; - if(window_h < 100) window_h = 100; -} - - - - -void TitleConfig::to_wtext(const char *from_enc, const char *text, int tlen) -{ - wlen = BC_Resources::encode(from_enc, BC_Resources::wide_encoding, - (char*)text,tlen, (char *)wtext,sizeof(wtext)) / sizeof(wchar_t); - while( wlen > 0 && !wtext[wlen-1] ) --wlen; -} - - -TitleGlyph::TitleGlyph() -{ - char_code = 0; - data = 0; - data_stroke = 0; - freetype_index = 0; - width = 0; - height = 0; - pitch = 0; - left = 0; - top = 0; - bottom = 0; - right = 0; - advance_x = 0; -} - - -TitleGlyph::~TitleGlyph() -{ -//printf("TitleGlyph::~TitleGlyph 1\n"); - if(data) delete data; - if(data_stroke) delete data_stroke; -} - - - - - - - - - - - -GlyphPackage::GlyphPackage() : LoadPackage() -{ - glyph = 0; -} - -GlyphUnit::GlyphUnit(TitleMain *plugin, GlyphEngine *server) - : LoadClient(server) -{ - this->plugin = plugin; - current_font = 0; - freetype_library = 0; - freetype_face = 0; -} - -GlyphUnit::~GlyphUnit() -{ - if(freetype_library) - FT_Done_FreeType(freetype_library); -} - -void GlyphUnit::process_package(LoadPackage *package) -{ - GlyphPackage *pkg = (GlyphPackage*)package; - TitleGlyph *glyph = pkg->glyph; - int result = 0; - char new_path[BCTEXTLEN]; - - current_font = plugin->get_font(); - - if(plugin->load_freetype_face(freetype_library, freetype_face, - current_font->path)) { - printf(_("GlyphUnit::process_package FT_New_Face failed.\n")); - 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 == 0) { - BC_Resources *resources = BC_WindowBase::get_resources(); - // 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); - } - } - FT_Set_Pixel_Sizes(freetype_face, plugin->config.size, 0); - - if (gindex == 0) { -// carrige return - if (glyph->char_code != 10) - printf(_("GlyphUnit::process_package FT_Load_Char failed - char: %li.\n"), - glyph->char_code); -// Prevent a crash here - glyph->width = 8; glyph->height = 8; - glyph->pitch = 8; glyph->advance_x = 8; - glyph->left = 9; glyph->top = 9; - glyph->right = 0; glyph->bottom = 0; - glyph->freetype_index = 0; - glyph->data = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); - glyph->data->clear_frame(); - glyph->data_stroke = 0; - -// create outline glyph - if (plugin->config.stroke_width >= ZERO && - (plugin->config.style & BC_FONT_OUTLINE)) { - glyph->data_stroke = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); - glyph->data_stroke->clear_frame(); - } - } -// char found and no outline desired - else if (plugin->config.stroke_width < ZERO || - !(plugin->config.style & BC_FONT_OUTLINE)) { - 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); -// printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n", -// bbox.xMin,bbox.xMax, bbox.yMin, bbox.yMax); - - glyph->width = bm.width = ((bbox.xMax - bbox.xMin + 63) >> 6); - glyph->height = bm.rows = ((bbox.yMax - bbox.yMin + 63) >> 6); - glyph->pitch = bm.pitch = bm.width; - bm.pixel_mode = FT_PIXEL_MODE_GRAY; - bm.num_grays = 256; - glyph->left = (bbox.xMin + 31) >> 6; - glyph->top = (bbox.yMax + 31) >> 6; - glyph->right = (bbox.xMax + 31) >> 6; - glyph->bottom = (bbox.yMin + 31) >> 6; - glyph->freetype_index = gindex; - glyph->advance_x = ((freetype_face->glyph->advance.x + 31) >> 6); -//printf("GlyphUnit::process_package 1 width=%d height=%d pitch=%d left=%d top=%d advance_x=%d freetype_index=%d\n", -//glyph->width, glyph->height, glyph->pitch, glyph->left, glyph->top, glyph->advance_x, glyph->freetype_index); - - 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, - - bbox.xMin, - bbox.yMin); - FT_Outline_Get_Bitmap( freetype_library, - &((FT_OutlineGlyph) glyph_image)->outline, - &bm); - FT_Done_Glyph(glyph_image); - } - else { -// Outline desired and glyph found - FT_Glyph glyph_image; - FT_Stroker stroker; - FT_Outline outline; - FT_Bitmap bm; - FT_BBox bbox; - FT_UInt npoints, ncontours; - - 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); - if( bbox.xMin == 0 && bbox.xMax == 0 && - bbox.yMin == 0 && bbox.yMax == 0 ) { - FT_Done_Glyph(glyph_image); - glyph->width = 0; glyph->height = 0; - glyph->left = 0; glyph->top = 0; - glyph->right = 0; glyph->bottom = 0; - glyph->pitch = 0; - glyph->data = - new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); - glyph->data_stroke = - new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); - glyph->advance_x =((int)(freetype_face->glyph->advance.x + - plugin->config.stroke_width * 64)) >> 6; - return; - } -#if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 2) - FT_Stroker_New(freetype_library, &stroker); -#else - FT_Stroker_New(((FT_LibraryRec *)freetype_library)->memory, &stroker); -#endif - 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); - 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); - glyph->width = 0; glyph->height = 0; - glyph->left = 0; glyph->top = 0; - glyph->right = 0; glyph->bottom = 0; - glyph->pitch = 0; - glyph->data = - new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); - glyph->data_stroke = - new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); - glyph->advance_x =((int)(freetype_face->glyph->advance.x + - plugin->config.stroke_width * 64)) >> 6; - return; - }; - - 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, - - bbox.xMin, - - bbox.yMin + (int)(plugin->config.stroke_width*32)); -// printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n" -// "Fill Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n", -// bbox.xMin,bbox.xMax, bbox.yMin, bbox.yMax, -// bbox_fill.xMin,bbox_fill.xMax, bbox_fill.yMin, bbox_fill.yMax); - - glyph->width = bm.width = ((bbox.xMax - bbox.xMin) >> 6)+1; - glyph->height = bm.rows = ((bbox.yMax - bbox.yMin) >> 6) +1; - glyph->pitch = bm.pitch = bm.width; - bm.pixel_mode = FT_PIXEL_MODE_GRAY; - bm.num_grays = 256; - glyph->left = (bbox.xMin + 31) >> 6; - glyph->top = (bbox.yMax + 31) >> 6; - glyph->right = (bbox.xMax + 31) >> 6; - glyph->bottom = (bbox.yMin + 31) >> 6; - glyph->freetype_index = gindex; - int real_advance = ((int)ceil((float)freetype_face->glyph->advance.x + - plugin->config.stroke_width * 64) >> 6); - glyph->advance_x = glyph->width + glyph->left; - if (real_advance > glyph->advance_x) - glyph->advance_x = real_advance; -//printf("GlyphUnit::process_package 1 width=%d height=%d " -// "pitch=%d left=%d top=%d advance_x=%d freetype_index=%d\n", -// glyph->width, glyph->height, glyph->pitch, glyph->left, -// glyph->top, glyph->advance_x, glyph->freetype_index); - - -//printf("GlyphUnit::process_package 1\n"); - glyph->data = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); - glyph->data->clear_frame(); - glyph->data_stroke = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); - 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_OutlineGlyph) glyph_image)->outline, - &bm); - bm.buffer=glyph->data_stroke->get_data(); - FT_Outline_Get_Bitmap( freetype_library, - &outline, - &bm); - FT_Outline_Done(freetype_library,&outline); - FT_Stroker_Done(stroker); - FT_Done_Glyph(glyph_image); - -//printf("GlyphUnit::process_package 2\n"); - } - } -} - - - -GlyphEngine::GlyphEngine(TitleMain *plugin, int cpus) - : LoadServer(cpus, cpus) -{ - this->plugin = plugin; -} - -void GlyphEngine::init_packages() -{ - int current_package = 0; - for(int i = 0; i < plugin->glyphs.total; i++) { - if(!plugin->glyphs.values[i]->data) { - GlyphPackage *pkg = (GlyphPackage*)get_package(current_package++); - pkg->glyph = plugin->glyphs.values[i]; - } - } -} - -LoadClient* GlyphEngine::new_client() -{ - return new GlyphUnit(plugin, this); -} - -LoadPackage* GlyphEngine::new_package() -{ - return new GlyphPackage; -} - - - - - -// Copy a single character to the text mask -TitlePackage::TitlePackage() - : LoadPackage() -{ - x = y = 0; - char_code = 0; -} - - -TitleUnit::TitleUnit(TitleMain *plugin, TitleEngine *server) - : LoadClient(server) -{ - this->plugin = plugin; - this->engine = server; -} - -void TitleUnit::draw_glyph(VFrame *output, VFrame *data, TitleGlyph *glyph, int x, int y) -{ - int glyph_w = data->get_w(), glyph_h = data->get_h(); - int output_w = output->get_w(), output_h = output->get_h(); - unsigned char **in_rows = data->get_rows(); - unsigned char **out_rows = output->get_rows(); - - int baseline = plugin->get_char_height(); - if( engine->do_dropshadow ) { - x += plugin->config.dropshadow; - y += plugin->config.dropshadow; - } - else if( plugin->config.dropshadow < 0 ) { - x -= plugin->config.dropshadow; - y -= plugin->config.dropshadow; - } - - int x_in = 0, y_in = 0; - int x_out = x + glyph->left; - if( x_out < 0 ) { x_in = -x_out; x_out = 0; } - if( x_out+glyph_w > output_w ) glyph_w = output_w-x_out; - if( x_in >= glyph_w || x_out >= output_w ) return; - int y_out = y + baseline - glyph->top; - if( y_out < 0 ) { y_in = -y_out; y_out = 0; } - if( y_out+glyph_h > output_h ) glyph_h = output_h-y_out; - if( y_in >= glyph_h || y_out >= output_h ) return; - - if(engine->do_dropshadow) { - while( y_in < glyph_h && y_out < output_h ) { - unsigned char *in_row = in_rows[y_in]; - unsigned char *out_row = out_rows[y_out]; - for( int xin=x_in,xout=x_out*4+3; xinget_color_components(&r, &g, &b, &a, 0); - //int outline = plugin->config.outline_size; - //if(outline) a = 0xff; - - while( y_in < glyph_h && y_out < output_h ) { - unsigned char *in_row = in_rows[y_in]; - unsigned char *out_row = out_rows[y_out]; - for( int xin=x_in,xout=x_out*4+0; xinchar_code == 0 || pkg->char_code == '\n') return; - TitleGlyph *glyph = plugin->get_glyph(pkg->char_code); - if( !glyph ) return; - draw_glyph(plugin->text_mask, glyph->data, glyph, pkg->x, pkg->y); - if(plugin->config.stroke_width >= ZERO && (plugin->config.style & BC_FONT_OUTLINE)) - draw_glyph(plugin->text_mask_stroke, glyph->data_stroke, glyph, pkg->x, pkg->y); -} - -TitleEngine::TitleEngine(TitleMain *plugin, int cpus) - : LoadServer(cpus, cpus) -{ - this->plugin = plugin; -} - -void TitleEngine::init_packages() -{ - int current_package = 0; - int dx = plugin->config.outline_size - plugin->extent.x1; - int dy = plugin->config.outline_size - plugin->extent.y1; - for(int i = plugin->visible_char1; i < plugin->visible_char2; i++) { - TitlePackage *pkg = (TitlePackage*)get_package(current_package++); - char_pos_t *pos = plugin->char_pos + i; - pkg->x = pos->x + dx; - pkg->y = pos->y + dy; - pkg->char_code = plugin->config.wtext[i]; -//printf("draw '%c' at %d,%d\n",(int)pkg->char_code, pkg->x, pkg->y); - } -} - -LoadClient* TitleEngine::new_client() -{ - return new TitleUnit(plugin, this); -} - -LoadPackage* TitleEngine::new_package() -{ - return new TitlePackage; -} - -void TitleTranslateUnit::translation_array_f(transfer_table_f* &table, - float out_x1, - float out_x2, - float in_x1, - float in_x2, - int in_total, - int out_total, - int &out_x1_int, - int &out_x2_int) -{ - int out_w_int; - //float offset = out_x1 - in_x1; - - out_x1_int = (int)out_x1; - out_x2_int = MIN((int)ceil(out_x2), out_total); - out_w_int = out_x2_int - out_x1_int; - - table = new transfer_table_f[out_w_int]; - bzero(table, sizeof(transfer_table_f) * out_w_int); - - float in_x = in_x1; - for(int out_x = out_x1_int; out_x < out_x2_int; out_x++) - { - transfer_table_f *entry = &table[out_x - out_x1_int]; - - 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() - : LoadPackage() -{ -} - - -TitleOutlineUnit::TitleOutlineUnit(TitleMain *plugin, TitleOutlineEngine *server) - : LoadClient(server) -{ - this->plugin = plugin; - this->engine = server; -} - -void TitleOutlineUnit::process_package(LoadPackage *package) -{ - TitleOutlinePackage *pkg = (TitleOutlinePackage*)package; - int r, g, b, outline_a; - plugin->get_color_components(&r, &g, &b, &outline_a, 1); - unsigned char **outline_rows = plugin->outline_mask->get_rows(); - 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; - - if(engine->pass == 0) { -// get max alpha under outline size macropixel - for(int y = pkg->y1; y < pkg->y2; y++) { - unsigned char *out_row = outline_rows[y]; - int y1 = y - ofs, y2 = y + ofs; - CLAMP(y1, 0, mask_h1); CLAMP(y2, 0, mask_h1); - for(int x = 0; x < plugin->text_mask->get_w(); x++) { - int x1 = x - ofs, x2 = x + ofs; - CLAMP(x1, 0, mask_w1); CLAMP(x2, 0, mask_w1); - - int max_a = 0; - for(int yy = y1; yy <= y2; yy++) { - unsigned char *text_row = text_rows[yy]; - for(int xx = x1; xx <= x2; ++xx) { - unsigned char *pixel = text_row + xx*4; - if(pixel[3] > max_a) max_a = pixel[3]; - } - } - - unsigned char *out = out_row + x*4; - out[0] = r; out[1] = g; out[2] = b; - out[3] = (max_a * outline_a) / 0xff; - } - } - return; - } - else { -// Overlay text mask on top of outline mask - int ofs = BC_CModels::is_yuv(plugin->output->get_color_model()) ? 0x80 : 0; - for(int y = pkg->y1; y < pkg->y2; y++) { - unsigned char *outline_row = outline_rows[y]; - unsigned char *text_row = text_rows[y]; - for(int x = 0; x < plugin->text_mask->get_w(); x++) { - unsigned char *out = text_row + x * 4; - unsigned char *inp = outline_row + x * 4; - int out_a = out[3], in_a = inp[3]; - int transparency = in_a * (0xff - out_a) / 0xff; - out[0] = (out[0] * out_a + inp[0] * transparency) / 0xff; - out[1] = ((out[1]-ofs) * out_a + (inp[1]-ofs) * transparency) / 0xff + ofs; - out[2] = ((out[2]-ofs) * out_a + (inp[2]-ofs) * transparency) / 0xff + ofs; - out[3] = in_a + out_a - in_a*out_a / 0xff; - } - } - } -} - -TitleOutlineEngine::TitleOutlineEngine(TitleMain *plugin, int cpus) - : LoadServer(cpus, cpus) -{ - this->plugin = plugin; -} - -void TitleOutlineEngine::init_packages() -{ - int mask_h = plugin->text_mask->get_h(); - if( !mask_h ) return; - int py1 = 0, py2 = 0; - int pkgs = get_total_packages(); - for( int i=0; iy1 = py1; pkg->y2 = py2; - } -} - -void TitleOutlineEngine::do_outline() -{ - pass = 0; process_packages(); - pass = 1; process_packages(); -} - -LoadClient* TitleOutlineEngine::new_client() -{ - return new TitleOutlineUnit(plugin, this); -} - -LoadPackage* TitleOutlineEngine::new_package() -{ - return new TitleOutlinePackage; -} - - - -TitleTranslatePackage::TitleTranslatePackage() - : LoadPackage() -{ - y1 = y2 = 0; -} - - -TitleTranslateUnit::TitleTranslateUnit(TitleMain *plugin, TitleTranslate *server) - : LoadClient(server) -{ - this->plugin = plugin; -} - -void TitleTranslate::run_packages() -{ - output_w = plugin->output->get_w(); - output_h = plugin->output->get_h(); - - float x1 = plugin->text_x1 + plugin->extent.x1; - float x2 = plugin->text_x1 + plugin->extent.x2; - if (x2 <= 0 || x1 >= x2 || x1 >= output_w) return; - - float y1 = plugin->text_y1 + plugin->extent.y1; - float y2 = plugin->text_y1 + plugin->extent.y2; - if (y2 <= 0 || y1 >= y2 || y1 >= output_h) return; - - process_packages(); -} - - - -#define TRANSLATE(type, max, components, ofs) \ -{ \ - unsigned char **in_rows = plugin->text_mask->get_rows(); \ - type **out_rows = (type**)plugin->output->get_rows(); \ - \ - for(int i = pkg->y1; i < pkg->y2; i++) \ - { \ - if(i + server->out_y1_int >= 0 && \ - i + server->out_y1_int < server->output_h) \ - { \ - int in_y1, in_y2; \ - float y_fraction1, y_fraction2; \ - in_y1 = server->y_table[i].in_x1; \ - in_y2 = server->y_table[i].in_x2; \ - y_fraction1 = server->y_table[i].in_fraction1; \ - y_fraction2 = server->y_table[i].in_fraction2; \ - unsigned char *in_row1 = in_rows[in_y1]; \ - unsigned char *in_row2 = in_rows[in_y2]; \ - type *out_row = out_rows[i + server->out_y1_int]; \ - \ - for(int j = server->out_x1_int; j < server->out_x2_int; j++) \ - { \ - if(j >= 0 && j < server->output_w) \ - { \ - int in_x1; \ - int in_x2; \ - float x_fraction1; \ - float x_fraction2; \ - in_x1 = \ - server->x_table[j - server->out_x1_int].in_x1; \ - in_x2 = \ - server->x_table[j - server->out_x1_int].in_x2; \ - x_fraction1 = \ - server->x_table[j - server->out_x1_int].in_fraction1; \ - x_fraction2 = \ - server->x_table[j - server->out_x1_int].in_fraction2; \ - \ - float fraction1 = x_fraction1 * y_fraction1 / (256.f-max); \ - float fraction2 = x_fraction2 * y_fraction1 / (256.f-max); \ - float fraction3 = x_fraction1 * y_fraction2 / (256.f-max); \ - float fraction4 = x_fraction2 * y_fraction2 / (256.f-max); \ - type input_r = (type)(in_row1[in_x1 * 4 + 0] * fraction1 + \ - in_row1[in_x2 * 4 + 0] * fraction2 + \ - in_row2[in_x1 * 4 + 0] * fraction3 + \ - in_row2[in_x2 * 4 + 0] * fraction4); \ - type input_g = (type)(in_row1[in_x1 * 4 + 1] * fraction1 + \ - in_row1[in_x2 * 4 + 1] * fraction2 + \ - in_row2[in_x1 * 4 + 1] * fraction3 + \ - in_row2[in_x2 * 4 + 1] * fraction4); \ - type input_b = (type)(in_row1[in_x1 * 4 + 2] * fraction1 + \ - in_row1[in_x2 * 4 + 2] * fraction2 + \ - in_row2[in_x1 * 4 + 2] * fraction3 + \ - in_row2[in_x2 * 4 + 2] * fraction4); \ - type input_a = (type)(in_row1[in_x1 * 4 + 3] * fraction1 + \ - in_row1[in_x2 * 4 + 3] * fraction2 + \ - in_row2[in_x1 * 4 + 3] * fraction3 + \ - in_row2[in_x2 * 4 + 3] * fraction4); \ -/* Plugin alpha is actually 0 - 0x100 */ \ - input_a = input_a * plugin->alpha / 0x100; \ - type transparency; \ - \ - \ - if(components == 4) \ - { \ - transparency = out_row[j * components + 3] * (max - input_a) / max; \ - out_row[j * components + 0] = \ - (input_r * input_a + out_row[j * components + 0] * transparency) / max; \ - out_row[j * components + 1] = \ - ((input_g-ofs) * input_a + (out_row[j * components + 1]-ofs) * transparency) / max + ofs; \ - out_row[j * components + 2] = \ - ((input_b-ofs) * input_a + (out_row[j * components + 2]-ofs) * transparency) / max + ofs; \ - out_row[j * components + 3] = \ - MAX(input_a, out_row[j * components + 3]); \ - } \ - else \ - { \ - transparency = max - input_a; \ - out_row[j * components + 0] = \ - (input_r * input_a + out_row[j * components + 0] * transparency) / max; \ - out_row[j * components + 1] = \ - ((input_g-ofs) * input_a + (out_row[j * components + 1]-ofs) * transparency) / max + ofs; \ - out_row[j * components + 2] = \ - ((input_b-ofs) * input_a + (out_row[j * components + 2]-ofs) * transparency) / max + ofs; \ - } \ - } \ - } \ - } \ - } \ -} - -#define TRANSLATEA(type, max, components, r, g, b) \ -{ \ - unsigned char **in_rows = plugin->text_mask->get_rows(); \ - type **out_rows = (type**)plugin->output->get_rows(); \ - \ - for(int i = pkg->y1; i < pkg->y2; i++) \ - { \ - if(i + server->out_y1_int >= 0 && \ - i + server->out_y1_int < server->output_h) \ - { \ - unsigned char *in_row = in_rows[i]; \ - type *out_row = out_rows[i + server->out_y1_int]; \ - \ - for(int j = server->out_x1; j < server->out_x2_int; j++) \ - { \ - if(j >= 0 && \ - j < server->output_w) \ - { \ - int input = (int)(in_row[j - server->out_x1]); \ - \ - input *= plugin->alpha; \ -/* Alpha is 0 - 256 */ \ - input >>= 8; \ - \ - int anti_input = 0xff - input; \ - if(components == 4) \ - { \ - out_row[j * components + 0] = \ - (r * input + out_row[j * components + 0] * anti_input) / 0xff; \ - out_row[j * components + 1] = \ - (g * input + out_row[j * components + 1] * anti_input) / 0xff; \ - out_row[j * components + 2] = \ - (b * input + out_row[j * components + 2] * anti_input) / 0xff; \ - if(max == 0xffff) \ - out_row[j * components + 3] = \ - MAX((input << 8) | input, out_row[j * components + 3]); \ - else \ - out_row[j * components + 3] = \ - MAX(input, out_row[j * components + 3]); \ - } \ - else \ - { \ - out_row[j * components + 0] = \ - (r * input + out_row[j * components + 0] * anti_input) / 0xff; \ - out_row[j * components + 1] = \ - (g * input + out_row[j * components + 1] * anti_input) / 0xff; \ - out_row[j * components + 2] = \ - (b * input + out_row[j * components + 2] * anti_input) / 0xff; \ - } \ - } \ - } \ - } \ - } \ -} - -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; - out_x1_int = out_x2_int = 0; - out_y1_int = out_y2_int = 0; - output_w = output_h = 0; -} - -TitleTranslate::~TitleTranslate() -{ - delete [] x_table; - delete [] y_table; -} - -void TitleTranslate::init_packages() -{ -// Generate scaling tables - delete [] x_table; x_table = 0; - delete [] y_table; y_table = 0; - - output_w = plugin->output->get_w(); - output_h = plugin->output->get_h(); - - float x1 = plugin->text_x1 + plugin->extent.x1; - float x2 = plugin->text_x1 + plugin->extent.x2; - TitleTranslateUnit::translation_array_f(x_table, x1, x2, 0, - plugin->mask_w, plugin->mask_w, - output_w, out_x1_int, out_x2_int); - - float y1 = plugin->text_y1 + plugin->extent.y1; - float y2 = plugin->text_y1 + plugin->extent.y2; - TitleTranslateUnit::translation_array_f(y_table, y1, y2, 0, - plugin->mask_h, plugin->mask_h, - output_h, out_y1_int, out_y2_int); - -//printf("TitleTranslate::init_packages 1\n"); - out_x1 = out_x1_int; out_x2 = out_x2_int; - out_y1 = out_y1_int; out_y2 = out_y2_int; - - 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; -} - - - -TitleMain::TitleMain(PluginServer *server) - : PluginVClient(server) -{ - text_mask = 0; - outline_mask = 0; - text_mask_stroke = 0; - glyph_engine = 0; - title_engine = 0; - freetype_face = 0; - freetype_library = 0; - char_pos = 0; - row_geom = 0; - row_geom_size = 0; - translate = 0; - outline_engine = 0; - visible_row1 = 0; visible_row2 = 0; - visible_char1 = 0; visible_char2 = 0; - text_y1 = text_y2 = text_x1 = 0; - alpha = 0x100; - text_rows = 0; - text_w = 0; text_h = 0; - input = 0; output = 0; - cpus = PluginClient::smp + 1; - if( cpus > 8 ) cpus = 8; - need_reconfigure = 1; -} - -TitleMain::~TitleMain() -{ - delete text_mask; - delete outline_mask; - delete text_mask_stroke; - delete [] char_pos; - delete [] row_geom; - clear_glyphs(); - delete glyph_engine; - delete title_engine; - if( freetype_face ) - FT_Done_Face(freetype_face); - if( freetype_library ) - FT_Done_FreeType(freetype_library); - delete translate; - delete outline_engine; -} - -const char* TitleMain::plugin_title() { return _("Title"); } -int TitleMain::is_realtime() { return 1; } -int TitleMain::is_synthesis() { return 1; } - -NEW_WINDOW_MACRO(TitleMain, TitleWindow); - - -void TitleMain::build_previews(TitleWindow *gui) -{ - ArrayList*fonts = gui->get_resources()->fontlist; - - for(int font_number = 0; font_number < fonts->size(); font_number++) - { - BC_FontEntry *font_entry = fonts->get(font_number); -// already have examples - if(font_entry->image) return; - } - -// create example bitmaps - FT_Library freetype_library = 0; // Freetype library - FT_Face freetype_face = 0; - const char *test_string = "Aa"; - char new_path[BCTEXTLEN]; - int text_height = gui->get_text_height(LARGEFONT); - int text_color = BC_WindowBase::get_resources()->default_text_color; - int r = (text_color >> 16) & 0xff; - int g = (text_color >> 8) & 0xff; - int b = text_color & 0xff; -// dimensions for each line - int height[fonts->size()]; - int ascent[fonts->size()]; - -// pass 1 gets the extents for all the fonts -// pass 2 draws the image - int total_w = 0; - int total_h = 0; - for(int pass = 0; pass < 2; 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++) - { - BC_FontEntry *font_entry = fonts->get(font_number); - -// test if font of same name has been processed - int skip = 0; - for(int i = 0; i < font_number; i++) { - if(!strcasecmp(fonts->get(i)->displayname, font_entry->displayname)) { - if(pass == 1) { - font_entry->image = fonts->get(i)->image; - } - skip = 1; - break; - } - } - - if(skip) continue; - - int current_x = 0; - int current_w = 0; - int current_ascent = 0; - int current_h = 0; - if(pass == 1) { - font_entry->image = new VFrame; - font_entry->image->set_use_shm(0); - font_entry->image->reallocate(0, -1, 0, 0, 0, - total_w, total_h, BC_RGBA8888, -1); - font_entry->image->clear_frame(); - } - - current_x = 0; - current_w = 0; - int len = strlen(test_string); - for(int j = 0; j < len; j++) - { - FT_ULong c = test_string[j]; -// memory leaks here are fatal -// check_char_code_path(freetype_library, -// font_entry->path, -// c, -// (char *)new_path); - strcpy(new_path, font_entry->path); - if( !load_freetype_face(freetype_library, - freetype_face, new_path)) { - FT_Set_Pixel_Sizes(freetype_face, text_height, 0); - - if(!FT_Load_Char(freetype_face, c, FT_LOAD_RENDER)) { - 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; - } - 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_entry->image->get_rows()[out_y] + - current_x * 4; - unsigned char *in_row = freetype_face->glyph->bitmap.buffer + - freetype_face->glyph->bitmap.pitch * in_y; - - for(int out_x = 0; out_x < (int)freetype_face->glyph->bitmap.width && - out_x < total_w; - out_x++) { - *out_row = (*in_row * r + - (0xff - *in_row) * *out_row) / 0xff; ++out_row; - *out_row = (*in_row * g + - (0xff - *in_row) * *out_row) / 0xff; ++out_row; - *out_row = (*in_row * b + - (0xff - *in_row) * *out_row) / 0xff; ++out_row; - *out_row = MAX(*in_row, *out_row); ++out_row; - in_row++; - } - } - } - - - current_x += freetype_face->glyph->advance.x >> 6; - } - } - } - - 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); -} - - - -//This checks if char_code is on the selected font, else it changes font to the first compatible //Akirad -int TitleMain::check_char_code_path(FT_Library &freetype_library, - char *path_old, - FT_ULong &char_code, - char *path_new) -{ - FT_Face temp_freetype_face; - FcPattern *pat; - FcFontSet *fs; - FcObjectSet *os; - FcChar8 *file, *format; - FcConfig *config; - int i; - - FcInit(); - config = FcConfigGetCurrent(); - FcConfigSetRescanInterval(config, 0); - - pat = FcPatternCreate(); - os = FcObjectSetBuild ( FC_FILE, FC_FONTFORMAT, (char *) 0); - fs = FcFontList(config, pat, os); - FcPattern *font; - int notfindit = 1; - 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( gindex != 0 && char_code == 10 ) - { - strcpy(path_new, path_old); - notfindit = 0; - } - } - - if(notfindit) - { - for (i=0; fs && i < fs->nfont; i++) - { - font = fs->fonts[i]; - FcPatternGetString(font, FC_FONTFORMAT, 0, &format); - if((!strcmp((char *)format, "TrueType")) || limit_to_truetype) - { - if(FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) - { - - sprintf(tmpstring, "%s", file); - if(!FT_New_Face(freetype_library, - tmpstring, - 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 ) - { - sprintf(path_new, "%s", tmpstring); - notfindit = 0; - goto done; - - } - } - } - } - } - } - -done: - if(fs) FcFontSetDestroy(fs); - if(temp_freetype_face) FT_Done_Face(temp_freetype_face); - temp_freetype_face = 0; - - if(notfindit) - { - strcpy(path_new, path_old); - return 1; - } - - return 0; -} - - - - -int TitleMain::load_freetype_face(FT_Library &freetype_library, - FT_Face &freetype_face, - const char *path) -{ -//printf("TitleMain::load_freetype_face 1\n"); - if(!freetype_library) - FT_Init_FreeType(&freetype_library); - if(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)) { - fprintf(stderr, _("TitleMain::load_freetype_face %s failed.\n"), path); - freetype_face = 0; - freetype_library = 0; - return 1; - } - return 0; -} - -BC_FontEntry* TitleMain::get_font() -{ - int style = 0; - int mask, pref; - - style |= (config.style & BC_FONT_ITALIC) ? - FL_SLANT_ITALIC | FL_SLANT_OBLIQUE : FL_SLANT_ROMAN; - style |= (config.style & BC_FONT_BOLD) ? - 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; - - pref = style & (FL_SLANT_ITALIC | FL_WEIGHT_BOLD | FL_WEIGHT_NORMAL); - - mask = FL_WEIGHT_MASK | FL_SLANT_MASK; - - BC_Resources *resources = BC_WindowBase::get_resources(); - return resources->find_fontentry(config.font, style, mask, pref); -} - -int TitleMain::get_char_height() -{ -// this is baseline to the baseline distance - int result = config.size; - if((config.style & BC_FONT_OUTLINE)) result += (int)ceil(config.stroke_width * 2); - return result; -} - -TitleGlyph *TitleMain::get_glyph(FT_ULong char_code) -{ - for(int i = 0; i < glyphs.size(); i++) { - if(glyphs.get(i)->char_code == char_code) - return glyphs.get(i); - } - return 0; -} - -int TitleMain::get_char_width(FT_ULong char_code) -{ - if(char_code == '\n') return 0; - TitleGlyph *glyph = get_glyph(char_code); - return !glyph ? 0 : glyph->width; -} - -int TitleMain::get_char_advance(FT_ULong current, FT_ULong next) -{ - FT_Vector kerning; - - if(current == '\n') return 0; - TitleGlyph *current_glyph = get_glyph(current); - int result = !current_glyph ? 0 : current_glyph->advance_x; - TitleGlyph *next_glyph = !next ? 0 : get_glyph(next); - if(next_glyph) - FT_Get_Kerning(freetype_face, - current_glyph->freetype_index, - next_glyph->freetype_index, - ft_kerning_default, - &kerning); - else - kerning.x = 0; - return result + (kerning.x >> 6); -} - -void TitleMain::load_glyphs() -{ -// Build table of all glyphs needed - int total_packages = 0; - - for(int i = 0; i < config.wlen; i++) - { - int exists = 0; - FT_ULong char_code = config.wtext[i]; - - for(int j = 0; j < glyphs.total; j++) { - if(glyphs.values[j]->char_code == char_code) { - exists = 1; - break; - } - } - - if(!exists && char_code != 0) { - total_packages++; - TitleGlyph *glyph = new TitleGlyph; - glyphs.append(glyph); - glyph->char_code = char_code; - } - } - - if(!glyph_engine) - glyph_engine = new GlyphEngine(this, cpus); - - glyph_engine->set_package_count(total_packages); - glyph_engine->process_packages(); -} - - -void TitleMain::get_total_extents() -{ -// Determine extents of total text - int wlen = config.wlen; - char_pos = new char_pos_t[wlen+1]; - - int pitch = config.line_pitch; - int font_h = get_char_height(); - int row = 0; - int row_w = 0, row_h = 0; - int max_char_w = 0, max_char_h = 0; - text_h = text_w = 0; - - // unjustified positions, initial bbox - for(int i = 0; i < wlen; i++) { - char_pos[i].x = row_w; - char_pos[i].y = text_h; - char_pos[i].row = row; - wchar_t wchar = config.wtext[i]; - if( wchar == '\n' ) { - text_h += pitch ? pitch : row_h > font_h ? row_h : font_h; - if(row_w > text_w) text_w = row_w; - row_w = row_h = 0; ++row; - continue; - } - TitleGlyph *glyph = get_glyph(wchar); - int char_w = i+1>=wlen ? glyph->width : - get_char_advance(wchar, config.wtext[i+1]); - char_pos[i].w = char_w; - row_w += char_w; - if( char_w > max_char_w ) max_char_w = char_w; - int char_h = glyph->top - glyph->bottom; - if( char_h > max_char_h ) max_char_h = char_h; - if( char_h > row_h ) row_h = char_h; -//printf("charcode '%c' %d,%d glyph bbox %d,%d %d,%d\n", -// (int)wchar, char_pos[i].x, char_pos[i].y, -// glyph->left, glyph->top, glyph->right, glyph->bottom); - } - if( wlen > 0 && config.wtext[wlen-1] != '\n' ) { - text_h += pitch ? pitch : row_h > font_h ? row_h : font_h; - if(row_w > text_w) text_w = row_w; - ++row; - } - char_pos[wlen].x = row_w; - char_pos[wlen].y = text_h; - char_pos[wlen].row = row; - char_pos[wlen].w = 0; - text_rows = row; - - // justify positions - int row_start = 0, pos = 0; - switch(config.hjustification) { - case JUSTIFY_MID: - while( row_start < wlen ) { - while( posx0 = geom->y0 = 0; - geom->x1 = geom->y1 = 0; - geom->x2 = geom->y2 = 0; - - // x0,y0 row origin in without kern - // x1,y1 - x2,y2 left baseline relative bbox with kerns - for(int i = 0; i < wlen; i++) { - int x = char_pos[i].x; - int y = char_pos[i].y; - wchar_t wchar = config.wtext[i]; - if( wchar == '\n' ) { - glyph = 0; ++geom; - geom->x0 = geom->y0 = 0; - geom->x1 = geom->y1 = 0; - geom->x2 = geom->y2 = 0; - continue; - } - TitleGlyph *gp = get_glyph(wchar); - if( !gp ) continue; - if( !glyph ) { - geom->x0 = x; geom->y0 = y; - int dx = x-geom->x0, dy = y-geom->y0 + config.size; - geom->x1 = dx + gp->left; geom->y1 = dy - gp->top; - geom->x2 = dx + gp->right; geom->y2 = dy - gp->bottom; - } - glyph = gp; - int dx = x-geom->x0, dy = y-geom->y0 + config.size; - int dx1 = dx + glyph->left; - int dx2 = dx + glyph->right; - if( dx1 < geom->x1 ) geom->x1 = dx1; - if( dx2 > geom->x2 ) geom->x2 = dx2; - int dy1 = dy - glyph->top; - int dy2 = dy - glyph->bottom; - if( dy1 < geom->y1 ) geom->y1 = dy1; - if( dy2 > geom->y2 ) geom->y2 = dy2; -//printf("charcode '%c' %d,%d row bbox %d,%d %d,%d %d,%d\n", -// (int)wchar, x,y, geom->x0,geom->y0, geom->x1,geom->y1, geom->x2,geom->y2); - } - if( wlen > 0 && config.wtext[wlen-1] != '\n' ) { - ++geom; - geom->x0 = 0; - geom->y0 = text_h; - geom->x1 = geom->y1 = 0; - geom->x2 = geom->y2 = 0; - } -} - -int TitleMain::draw_mask() -{ - int old_visible_row1 = visible_row1; - int old_visible_row2 = visible_row2; - -// Determine y of visible text - if(config.motion_strategy == BOTTOM_TO_TOP) { -// printf("TitleMain::draw_mask 1 %d %lld %lld %lld\n", -// config.motion_strategy, -// get_source_position(), -// get_source_start(), -// config.prev_keyframe_position); - float magnitude = config.pixels_per_second * - (get_source_position() - config.prev_keyframe_position) / - PluginVClient::project_frame_rate; - if(config.loop) { - int loop_size = text_h + input->get_h(); - magnitude -= (int)(magnitude / loop_size) * loop_size; - } - text_y1 = config.y + input->get_h() - magnitude; - } - else - if(config.motion_strategy == TOP_TO_BOTTOM) { - float magnitude = config.pixels_per_second * - (get_source_position() - config.prev_keyframe_position) / - PluginVClient::project_frame_rate; - if(config.loop) - { - int loop_size = text_h + input->get_h(); - magnitude -= (int)(magnitude / loop_size) * loop_size; - } - text_y1 = config.y + magnitude; - text_y1 -= text_h; - } - else if(config.vjustification == JUSTIFY_TOP) { - text_y1 = config.y; - } - else if(config.vjustification == JUSTIFY_MID) { - text_y1 = config.y + input->get_h() / 2 - text_h / 2; - } - else if(config.vjustification == JUSTIFY_BOTTOM) { - text_y1 = config.y + input->get_h() - text_h; - } - - text_y2 = text_y1 + text_h + 0.5; - -// Determine x of visible text - if(config.motion_strategy == RIGHT_TO_LEFT) { - float magnitude = config.pixels_per_second * - (get_source_position() - config.prev_keyframe_position) / - PluginVClient::project_frame_rate; - if(config.loop) { - int loop_size = text_w + input->get_w(); - magnitude -= (int)(magnitude / loop_size) * loop_size; - } - text_x1 = config.x + (float)input->get_w() - magnitude; - } - else if(config.motion_strategy == LEFT_TO_RIGHT) { - float magnitude = config.pixels_per_second * - (get_source_position() - config.prev_keyframe_position) / - PluginVClient::project_frame_rate; - if(config.loop) { - int loop_size = text_w + input->get_w(); - magnitude -= (int)(magnitude / loop_size) * loop_size; - } - text_x1 = config.x + -(float)text_w + magnitude; - } - else if(config.hjustification == JUSTIFY_LEFT) { - text_x1 = config.x; - } - else if(config.hjustification == JUSTIFY_MID) { - text_x1 = config.x + input->get_w() / 2 - text_w / 2; - } - else if(config.hjustification == JUSTIFY_RIGHT) { - text_x1 = config.x + input->get_w() - text_w; - } - text_x2 = text_x1 + text_w; - - // bottom of this row is visible - visible_row1 = 0; - RowGeom *geom = 0; - while( visible_row1 < text_rows ) { - geom = &row_geom[visible_row1]; - int y0 = text_y1 + geom->bottom(); - if( y0 > 0 ) break; - ++visible_row1; - } - - // top of next row is not visible - visible_row2 = visible_row1; - while( visible_row2 < text_rows ) { - geom = &row_geom[visible_row2]; - int y0 = text_y1 + geom->top(); - if( y0 >= input->get_h() ) break; - ++visible_row2; - } - - if( visible_row1 == visible_row2 ) return 1; - -//printf("visible rows %d to %d\n", visible_row1, visible_row2); - // Only use visible rows, get bbox including kerns - // text origin, no kerning - geom = &row_geom[visible_row1]; - extent.x0 = geom->x0; extent.y0 = geom->y0; - extent.x1 = geom->left(); extent.y1 = geom->top(); - extent.x2 = geom->right(); extent.y2 = geom->bottom(); - - for( int i=visible_row1; ileft()) < extent.x1 ) extent.x1 = v; - if( (v=geom->top()) < extent.y1 ) extent.y1 = v; - if( (v=geom->right()) > extent.x2 ) extent.x2 = v; - if( (v=geom->bottom()) > extent.y2 ) extent.y2 = v; - } - -//printf("exts x0,y0=%d,%d x1,y1=%d,%d x2,y2=%d,%d text %f,%f %dx%d\n", -// extent.x0,extent.y0, extent.x1,extent.y1, extent.x2,extent.y2, -// text_x1,text_y1, text_w,text_h); - // Only draw visible chars - visible_char1 = visible_char2 = -1; - int wlen = config.wlen; - for(int i = 0; i < wlen; i++) { - char_pos_t *pos = char_pos + i; - if( pos->row < visible_row1 ) continue; - if( pos->row >= visible_row2 ) continue; - if(visible_char1 < 0) visible_char1 = i; - visible_char2 = i; - } - visible_char2++; - - extent.x1 -= config.outline_size*2; - extent.y1 -= config.outline_size*2; - extent.x2 += abs(config.dropshadow) + config.outline_size*2; - extent.y2 += abs(config.dropshadow) + config.outline_size*2; - - // Determine mask geometry - mask_w = extent.x2 - extent.x1; - if( mask_w <= 0 ) return 1; - mask_h = extent.y2 - extent.y1; - if( mask_h <= 0 ) return 1; - -//printf("TitleMain::draw_mask %d-%d frame %dx%d\n", -// visible_row1, visible_row2, mask_w,mask_h) - int need_redraw = 0; - if(text_mask && (text_mask->get_w() != mask_w || text_mask->get_h() != mask_h)) { - delete text_mask; text_mask = 0; - delete text_mask_stroke; text_mask_stroke = 0; - } - - if(!text_mask) { -// Always use 8 bit because the glyphs are 8 bit -// Need to set YUV to get clear_frame to set the right chroma. - int output_model = get_output()->get_color_model(); - int color_model = BC_CModels::is_yuv(output_model) ? BC_YUVA8888 : BC_RGBA8888; - text_mask = new VFrame; - text_mask->set_use_shm(0); - text_mask->reallocate(0, -1, 0, 0, 0, mask_w, mask_h, color_model, -1); - float drop = abs(config.dropshadow); - int drop_w = mask_w + drop; - int drop_h = mask_h + drop; - text_mask_stroke = new VFrame; - text_mask_stroke->set_use_shm(0); - text_mask_stroke->reallocate(0, -1, 0, 0, 0, drop_w, drop_h, color_model, -1); - need_redraw = 1; - } - -// Draw on text mask if it has changed - if( need_redraw || - old_visible_row1 != visible_row1 || - old_visible_row2 != visible_row2 ) { -//printf("redraw %d to %d %d,%d %d,%d - %d,%d\n", visible_char1,visible_char2, -// extent.x0, extent.y0, extent.x1,extent.y1, extent.x2,extent.y2); - - text_mask->clear_frame(); - text_mask_stroke->clear_frame(); -#if 0 - unsigned char *data = text_mask->get_data(); // draw bbox on text_mask - for( int x=0; xdo_dropshadow = 1; - title_engine->set_package_count(visible_char2 - visible_char1); - title_engine->process_packages(); - } - -// Then draw foreground - title_engine->do_dropshadow = 0; - title_engine->set_package_count(visible_char2 - visible_char1); - title_engine->process_packages(); - -// Convert to text outlines - if(config.outline_size > 0) { - if(outline_mask && - (text_mask->get_w() != outline_mask->get_w() || - text_mask->get_h() != outline_mask->get_h())) { - delete outline_mask; outline_mask = 0; - } - - if(!outline_mask) { - outline_mask = new VFrame; - outline_mask->set_use_shm(0); - outline_mask->reallocate(0, -1, 0, 0, 0, - text_mask->get_w(), text_mask->get_h(), - text_mask->get_color_model(), -1); - } - if(!outline_engine) outline_engine = - new TitleOutlineEngine(this, cpus); - outline_engine->do_outline(); - } - } - - return 0; -} - -void TitleMain::overlay_mask() -{ - -//printf("TitleMain::overlay_mask 1\n"); - alpha = 0x100; - 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; - - if(fade_position >= 0 && fade_position < fade_len) - { - alpha = lroundf(256.0f * 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(); - - - if(fade_position >= 0 && fade_position < fade_len) - { - alpha = lroundf(256.0f * fade_position / fade_len); - } - } - - if(!translate) - translate = new TitleTranslate(this, cpus); - - if(config.dropshadow) - { - text_x1 += config.dropshadow; - if(text_x1 < input->get_w() && text_x1 + text_w > 0) - { -// Do 2 passes if dropshadow. - int temp_color = config.color; - config.color = 0x0; - translate->run_packages(); - config.color = temp_color; - } - text_x1 -= config.dropshadow; - } -//printf("TitleMain::overlay_mask 1\n"); - - if(text_x1 < input->get_w() && text_x1 + text_w > 0) { - translate->run_packages(); - if (config.stroke_width >= ZERO && (config.style & BC_FONT_OUTLINE)) { - int temp_color = config.color; - VFrame *tmp_text_mask = this->text_mask; - config.color = config.color_stroke; - this->text_mask = this->text_mask_stroke; - - translate->run_packages(); - config.color = temp_color; - this->text_mask = tmp_text_mask; - } - } -//printf("TitleMain::overlay_mask 200\n"); -} - -void TitleMain::get_color_components(int *r, int *g, int *b, int *a, int is_outline) -{ - int color = is_outline ? config.outline_color : config.color; - unsigned char r_in = color >> 16; - unsigned char g_in = color >> 8; - unsigned char b_in = color; - *a = is_outline ? config.outline_alpha : config.alpha; - - switch(output->get_color_model()) { - case BC_YUV888: - yuv.rgb_to_yuv_8(r_in, g_in, b_in, *r, *g, *b); - break; - case BC_YUVA8888: - yuv.rgb_to_yuv_8(r_in, g_in, b_in, *r, *g, *b); - break; - default: - *r = r_in; *g = g_in; *b = b_in; - break; - } -} - -void TitleMain::clear_glyphs() -{ -//printf("TitleMain::clear_glyphs 1\n"); - glyphs.remove_all_objects(); -} - -const char* TitleMain::motion_to_text(int motion) -{ - switch(motion) - { - case NO_MOTION: return _("No motion"); break; - case BOTTOM_TO_TOP: return _("Bottom to top"); break; - case TOP_TO_BOTTOM: return _("Top to bottom"); break; - case RIGHT_TO_LEFT: return _("Right to left"); break; - case LEFT_TO_RIGHT: return _("Left to right"); break; - } - return ""; -} - -int TitleMain::text_to_motion(const char *text) -{ - for(int i = 0; i < TOTAL_PATHS; i++) - { - if(!strcasecmp(motion_to_text(i), text)) return i; - } - return 0; -} - -void TitleMain::reset_render() -{ - delete text_mask; text_mask = 0; - delete glyph_engine; glyph_engine = 0; - delete [] char_pos; char_pos = 0; - delete text_mask_stroke; text_mask_stroke = 0; - delete [] row_geom; row_geom = 0; - row_geom_size = 0; - visible_row1 = 0; visible_row2 = 0; - visible_char1 = 0; visible_char2 = 0; - text_rows = 0; - clear_glyphs(); - if(freetype_face) { - FT_Done_Face(freetype_face); - freetype_face = 0; - } -} - -int TitleMain::init_freetype() -{ - if(!freetype_library) - FT_Init_FreeType(&freetype_library); - if(!freetype_face) { - BC_FontEntry *font = get_font(); - if(load_freetype_face(freetype_library, freetype_face, font->path)) { - printf("TitleMain::process_realtime %s: FT_New_Face failed.\n", - font->displayname); - return 1; - } - FT_Set_Pixel_Sizes(freetype_face, config.size, 0); - } - return 0; -} - -int TitleMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr) -{ - int result = 0; - input = input_ptr; - output = output_ptr; - - need_reconfigure |= load_configuration(); - -// Check boundaries - if(config.size <= 0 || config.size >= 2048) - config.size = 72; - if(config.stroke_width < 0 || config.stroke_width >= 512) - config.stroke_width = 0.0; - if(!config.wlen && !config.timecode) - return 0; - if(!strlen(config.encoding)) - strcpy(config.encoding, DEFAULT_ENCODING); - -// Always synthesize text and redraw it for timecode - if(config.timecode) - { - int64_t rendered_frame = get_source_position(); - if (get_direction() == PLAY_REVERSE) - rendered_frame -= 1; - - char text[BCTEXTLEN]; - Units::totext(text, - (double)rendered_frame / PluginVClient::project_frame_rate, - config.timecode_format, - PluginVClient::get_project_samplerate(), - PluginVClient::get_project_framerate(), - 16); - config.to_wtext(config.encoding, text, strlen(text)+1); - need_reconfigure = 1; - } - -// printf("TitleMain::process_realtime %d need_reconfigure=%d\n", -// __LINE__, -// need_reconfigure); - -// Handle reconfiguration - if(need_reconfigure) { - reset_render(); - result = init_freetype(); - if(!result) { -//PRINT_TRACE - load_glyphs(); - get_total_extents(); - need_reconfigure = 0; - } - } - - if(!result) { -//PRINT_TRACE -// Determine region of text visible on the output and draw mask - result = draw_mask(); - } - - -// Overlay mask on output - if(!result) { -//PRINT_TRACE - overlay_mask(); - } - - return 0; -} - -void TitleMain::update_gui() -{ - if(thread) - { - int reconfigure = load_configuration(); - if(reconfigure) - { - TitleWindow *window = (TitleWindow*)thread->window; - window->lock_window("TitleMain::update_gui"); - window->update(); - window->unlock_window(); - window->color_thread->update_gui(config.color, 0); - window->unlock_window(); - } - } -} - -int TitleMain::load_configuration() -{ - KeyFrame *prev_keyframe, *next_keyframe; - prev_keyframe = get_prev_keyframe(get_source_position()); - next_keyframe = get_next_keyframe(get_source_position()); - - TitleConfig old_config, prev_config, next_config; - old_config.copy_from(config); - read_data(prev_keyframe); - prev_config.copy_from(config); - read_data(next_keyframe); - next_config.copy_from(config); - - config.prev_keyframe_position = prev_keyframe->position; - config.next_keyframe_position = next_keyframe->position; - - // if no previous keyframe exists, it should be start of the plugin, not start of the track - if(config.next_keyframe_position == config.prev_keyframe_position) - config.next_keyframe_position = get_source_start() + get_total_len(); - if (config.prev_keyframe_position == 0) - config.prev_keyframe_position = get_source_start(); -// printf("TitleMain::load_configuration 10 %d %d\n", -// config.prev_keyframe_position, -// config.next_keyframe_position); - - config.interpolate(prev_config, - next_config, - (next_keyframe->position == prev_keyframe->position) ? - get_source_position() : - prev_keyframe->position, - (next_keyframe->position == prev_keyframe->position) ? - get_source_position() + 1 : - next_keyframe->position, - get_source_position()); - - if(!config.equivalent(old_config)) - return 1; - return 0; -} - - -void TitleMain::save_data(KeyFrame *keyframe) -{ - FileXML output; - - output.set_shared_output(keyframe->get_data(), MESSAGESIZE); - output.tag.set_title("TITLE"); - output.tag.set_property("FONT", config.font); - output.tag.set_property("ENCODING", config.encoding); - output.tag.set_property("STYLE", (int64_t)config.style); - output.tag.set_property("SIZE", config.size); - output.tag.set_property("COLOR", config.color); - output.tag.set_property("COLOR_STROKE", config.color_stroke); - output.tag.set_property("STROKE_WIDTH", config.stroke_width); - output.tag.set_property("OUTLINE_COLOR", config.outline_color); - output.tag.set_property("ALPHA", config.alpha); - output.tag.set_property("OUTLINE_ALPHA", config.outline_alpha); - output.tag.set_property("MOTION_STRATEGY", config.motion_strategy); - output.tag.set_property("LOOP", config.loop); - output.tag.set_property("LINE_PITCH", config.line_pitch); - output.tag.set_property("PIXELS_PER_SECOND", config.pixels_per_second); - output.tag.set_property("HJUSTIFICATION", config.hjustification); - output.tag.set_property("VJUSTIFICATION", config.vjustification); - output.tag.set_property("FADE_IN", config.fade_in); - output.tag.set_property("FADE_OUT", config.fade_out); - output.tag.set_property("TITLE_X", config.x); - output.tag.set_property("TITLE_Y", config.y); - output.tag.set_property("DROPSHADOW", config.dropshadow); - output.tag.set_property("OUTLINE_SIZE", config.outline_size); - output.tag.set_property("TIMECODE", config.timecode); - output.tag.set_property("TIMECODEFORMAT", config.timecode_format); - output.tag.set_property("WINDOW_W", config.window_w); - output.tag.set_property("WINDOW_H", config.window_h); - output.append_tag(); - output.append_newline(); - char text[BCTEXTLEN]; - int text_len = BC_Resources::encode( - BC_Resources::wide_encoding, DEFAULT_ENCODING, - (char*)config.wtext, config.wlen*sizeof(wchar_t), - text, sizeof(text)); - output.append_text(text, text_len); - output.tag.set_title("/TITLE"); - output.append_tag(); - output.append_newline(); - output.terminate_string(); -//printf("TitleMain::save_data 1\n%s\n", output.string); -//printf("TitleMain::save_data 2\n%s\n", config.text); -} - -void TitleMain::read_data(KeyFrame *keyframe) -{ - FileXML input; - - input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data())); - - int result = 0; - - config.prev_keyframe_position = keyframe->position; - while(!result) - { - result = input.read_tag(); - if( result ) break; - - if(input.tag.title_is("TITLE")) { - input.tag.get_property("FONT", config.font); - input.tag.get_property("ENCODING", config.encoding); - config.style = input.tag.get_property("STYLE", (int64_t)config.style); - config.size = input.tag.get_property("SIZE", config.size); - config.color = input.tag.get_property("COLOR", config.color); - config.color_stroke = input.tag.get_property("COLOR_STROKE", config.color_stroke); - config.stroke_width = input.tag.get_property("STROKE_WIDTH", config.stroke_width); - config.outline_color = input.tag.get_property("OUTLINE_COLOR", config.outline_color); - config.alpha = input.tag.get_property("ALPHA", config.alpha); - config.outline_alpha = input.tag.get_property("OUTLINE_ALPHA", config.outline_alpha); - config.motion_strategy = input.tag.get_property("MOTION_STRATEGY", config.motion_strategy); - config.loop = input.tag.get_property("LOOP", config.loop); - config.line_pitch = input.tag.get_property("LINE_PITCH", config.line_pitch); - config.pixels_per_second = input.tag.get_property("PIXELS_PER_SECOND", config.pixels_per_second); - config.hjustification = input.tag.get_property("HJUSTIFICATION", config.hjustification); - config.vjustification = input.tag.get_property("VJUSTIFICATION", config.vjustification); - config.fade_in = input.tag.get_property("FADE_IN", config.fade_in); - config.fade_out = input.tag.get_property("FADE_OUT", config.fade_out); - config.x = input.tag.get_property("TITLE_X", config.x); - config.y = input.tag.get_property("TITLE_Y", config.y); - config.dropshadow = input.tag.get_property("DROPSHADOW", config.dropshadow); - config.outline_size = input.tag.get_property("OUTLINE_SIZE", config.outline_size); - config.timecode = input.tag.get_property("TIMECODE", config.timecode); - config.timecode_format = input.tag.get_property("TIMECODEFORMAT", config.timecode_format); - config.window_w = input.tag.get_property("WINDOW_W", config.window_w); - config.window_h = input.tag.get_property("WINDOW_H", config.window_h); - const char *text = input.read_text(); - config.to_wtext(config.encoding, text, strlen(text)+1); - } - else if(input.tag.title_is("/TITLE")) { - result = 1; - } - } -} diff --git a/cinelerra-5.1/plugins/titler/title.C.stroker b/cinelerra-5.1/plugins/titler/title.C.stroker deleted file mode 100644 index b926c6da..00000000 --- a/cinelerra-5.1/plugins/titler/title.C.stroker +++ /dev/null @@ -1,2306 +0,0 @@ -// Originally developed by Heroine Virtual Ltd. -// Support for multiple encodings, outline (stroke) by -// Andraz Tori - - -#include "clip.h" -#include "bccmodels.h" -#include "file.h" -#include "filexml.h" -#include "filesystem.h" -#include "freetype/ftbbox.h" -#include "freetype/ftglyph.h" -#include "freetype/ftoutln.h" -#include "freetype/ftstroker.h" -#include "language.h" -#include "plugincolors.h" -#include "title.h" -#include "titlewindow.h" - - -#include -#include -#include -#include -#include -#include -#include -#include - - -#define ZERO (1.0 / 64.0) - -#define FONT_SEARCHPATH "fonts" -//#define FONT_SEARCHPATH "/usr/X11R6/lib/X11/fonts" - - -REGISTER_PLUGIN(TitleMain) - - -TitleConfig::TitleConfig() -{ - style = 0; - color = BLACK; - color_stroke = 0xff0000; - size = 24; - motion_strategy = NO_MOTION; - loop = 0; - hjustification = JUSTIFY_CENTER; - vjustification = JUSTIFY_MID; - fade_in = 0.0; - fade_out = 0.0; - x = 0.0; - y = 0.0; - dropshadow = 10; - sprintf(font, "fixed"); - sprintf(text, _("hello world")); -#define DEFAULT_ENCODING "ISO8859-1" - sprintf(encoding, DEFAULT_ENCODING); - pixels_per_second = 1.0; - timecode = 0; - stroke_width = 1.0; -} - -// Does not test equivalency but determines if redrawing text is necessary. -int TitleConfig::equivalent(TitleConfig &that) -{ - return dropshadow == that.dropshadow && - style == that.style && - size == that.size && - color == that.color && - color_stroke == that.color_stroke && - stroke_width == that.stroke_width && - timecode == that.timecode && - hjustification == that.hjustification && - vjustification == that.vjustification && - EQUIV(pixels_per_second, that.pixels_per_second) && - !strcasecmp(font, that.font) && - !strcasecmp(encoding, that.encoding) && - !strcmp(text, that.text); -} - -void TitleConfig::copy_from(TitleConfig &that) -{ - strcpy(font, that.font); - style = that.style; - size = that.size; - color = that.color; - color_stroke = that.color_stroke; - stroke_width = that.stroke_width; - pixels_per_second = that.pixels_per_second; - motion_strategy = that.motion_strategy; - loop = that.loop; - hjustification = that.hjustification; - vjustification = that.vjustification; - fade_in = that.fade_in; - fade_out = that.fade_out; - x = that.x; - y = that.y; - dropshadow = that.dropshadow; - timecode = that.timecode; - strcpy(text, that.text); - strcpy(encoding, that.encoding); -} - -void TitleConfig::interpolate(TitleConfig &prev, - TitleConfig &next, - int64_t prev_frame, - int64_t next_frame, - int64_t current_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; - motion_strategy = prev.motion_strategy; - loop = prev.loop; - hjustification = prev.hjustification; - vjustification = prev.vjustification; - fade_in = prev.fade_in; - fade_out = prev.fade_out; - pixels_per_second = prev.pixels_per_second; - strcpy(text, prev.text); - - 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->x = prev.x * prev_scale + next.x * next_scale; -// this->y = prev.y * prev_scale + next.y * next_scale; - this->x = prev.x; - this->y = prev.y; - timecode = prev.timecode; -// this->dropshadow = (int)(prev.dropshadow * prev_scale + next.dropshadow * next_scale); - this->dropshadow = prev.dropshadow; -} - - - - - - - - - - - - - - - - - -FontEntry::FontEntry() -{ - path = 0; - foundary = 0; - family = 0; - weight = 0; - slant = 0; - swidth = 0; - adstyle = 0; - spacing = 0; - registry = 0; - encoding = 0; - fixed_title = 0; - fixed_style = 0; -} - -FontEntry::~FontEntry() -{ - if(path) delete [] path; - if(foundary) delete [] foundary; - if(family) delete [] family; - if(weight) delete [] weight; - if(slant) delete [] slant; - if(swidth) delete [] swidth; - if(adstyle) delete [] adstyle; - if(spacing) delete [] spacing; - if(registry) delete [] registry; - if(encoding) delete [] encoding; - if(fixed_title) delete [] fixed_title; -} - -void FontEntry::dump() -{ - printf("%s: %s %s %s %s %s %s %d %d %d %d %s %d %s %s\n", - path, - foundary, - family, - weight, - slant, - swidth, - adstyle, - pixelsize, - pointsize, - xres, - yres, - spacing, - avg_width, - registry, - encoding); -} - -TitleGlyph::TitleGlyph() -{ - char_code = 0; - c=0; - data = 0; - data_stroke = 0; -} - - -TitleGlyph::~TitleGlyph() -{ -//printf("TitleGlyph::~TitleGlyph 1\n"); - if(data) delete data; - if(data_stroke) delete data_stroke; -} - - - - - - - - - - - -GlyphPackage::GlyphPackage() : LoadPackage() -{ -} - -GlyphUnit::GlyphUnit(TitleMain *plugin, GlyphEngine *server) - : LoadClient(server) -{ - this->plugin = plugin; - current_font = 0; - freetype_library = 0; - freetype_face = 0; -} - -GlyphUnit::~GlyphUnit() -{ - if(freetype_library) FT_Done_FreeType(freetype_library); -} - -void GlyphUnit::process_package(LoadPackage *package) -{ - GlyphPackage *pkg = (GlyphPackage*)package; - TitleGlyph *glyph = pkg->glyph; - int result = 0; - - if(!freetype_library) - { - current_font = plugin->get_font(); - - if(plugin->load_freetype_face(freetype_library, - freetype_face, - current_font->path)) - { - printf(_("GlyphUnit::process_package FT_New_Face failed.\n")); - result = 1; - } - else - { - FT_Set_Pixel_Sizes(freetype_face, plugin->config.size, 0); - } - } - - 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 == 0) - { -// carrige return - if (glyph->char_code != 10) - printf(_("GlyphUnit::process_package FT_Load_Char failed - char: %i.\n"), - glyph->char_code); -// Prevent a crash here - glyph->width = 8; - glyph->height = 8; - glyph->pitch = 8; - glyph->left = 9; - glyph->top = 9; - glyph->freetype_index = 0; - glyph->advance_w = 8; - glyph->data = new VFrame(0, - 8, - 8, - BC_A8, - 8); - glyph->data->clear_frame(); - glyph->data_stroke = 0; - - - -// create outline glyph - if (plugin->config.stroke_width >= ZERO && - (plugin->config.style & FONT_OUTLINE)) - { - glyph->data_stroke = new VFrame(0, - 8, - 8, - BC_A8, - 8); - glyph->data_stroke->clear_frame(); - } - - - - } - else -// char found and no outline desired - if (plugin->config.stroke_width < ZERO || - !(plugin->config.style & FONT_OUTLINE)) - { - 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); -// printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n", -// bbox.xMin,bbox.xMax, bbox.yMin, bbox.yMax); - - FT_Outline_Translate(&((FT_OutlineGlyph) glyph_image)->outline, - - bbox.xMin, - - bbox.yMin); - glyph->width = bm.width = ((bbox.xMax - bbox.xMin + 63) >> 6); - glyph->height = bm.rows = ((bbox.yMax - bbox.yMin + 63) >> 6); - glyph->pitch = bm.pitch = bm.width; - bm.pixel_mode = FT_PIXEL_MODE_GRAY; - bm.num_grays = 256; - glyph->left = (bbox.xMin + 31) >> 6; - if (glyph->left < 0) glyph->left = 0; - glyph->top = (bbox.yMax + 31) >> 6; - glyph->freetype_index = gindex; - glyph->advance_w = ((freetype_face->glyph->advance.x + 31) >> 6); -//printf("GlyphUnit::process_package 1 width=%d height=%d pitch=%d left=%d top=%d advance_w=%d freetype_index=%d\n", -//glyph->width, glyph->height, glyph->pitch, glyph->left, glyph->top, glyph->advance_w, glyph->freetype_index); - - glyph->data = new VFrame(0, - glyph->width, - glyph->height, - BC_A8, - glyph->pitch); - glyph->data->clear_frame(); - bm.buffer = glyph->data->get_data(); - FT_Outline_Get_Bitmap( freetype_library, - &((FT_OutlineGlyph) glyph_image)->outline, - &bm); - FT_Done_Glyph(glyph_image); - } - else -// Outline desired and glyph found - { - FT_Glyph glyph_image; - int no_outline = 0; - FT_Stroker stroker; - FT_Outline outline; - FT_Bitmap bm; - FT_BBox bbox; - FT_UInt npoints, ncontours; - - typedef struct FT_LibraryRec_ - { - FT_Memory memory; - } FT_LibraryRec; - - 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); - if (bbox.xMin == 0 && bbox.xMax == 0 && bbox.yMin ==0 && bbox.yMax == 0) - { - FT_Done_Glyph(glyph_image); - glyph->data = new VFrame(0, 0, BC_A8,0); - glyph->data_stroke = new VFrame(0, 0, BC_A8,0);; - glyph->width=0; - glyph->height=0; - glyph->top=0; - glyph->left=0; - glyph->advance_w =((int)(freetype_face->glyph->advance.x + - plugin->config.stroke_width * 64)) >> 6; - return; - } - FT_Stroker_New(((FT_LibraryRec *)freetype_library)->memory, &stroker); - 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); - 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); - glyph->data = new VFrame(0, 0, BC_A8,0); - glyph->data_stroke = new VFrame(0, 0, BC_A8,0);; - glyph->width=0; - glyph->height=0; - glyph->top=0; - glyph->left=0; - glyph->advance_w =((int)(freetype_face->glyph->advance.x + - plugin->config.stroke_width * 64)) >> 6; - return; - }; - - 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, - - bbox.xMin, - - bbox.yMin + (int)(plugin->config.stroke_width*32)); -// printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\nFill Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n", -// bbox.xMin,bbox.xMax, bbox.yMin, bbox.yMax, -// bbox_fill.xMin,bbox_fill.xMax, bbox_fill.yMin, bbox_fill.yMax); - - glyph->width = bm.width = ((bbox.xMax - bbox.xMin) >> 6)+1; - glyph->height = bm.rows = ((bbox.yMax - bbox.yMin) >> 6) +1; - glyph->pitch = bm.pitch = bm.width; - bm.pixel_mode = FT_PIXEL_MODE_GRAY; - bm.num_grays = 256; - glyph->left = (bbox.xMin + 31) >> 6; - if (glyph->left < 0) glyph->left = 0; - glyph->top = (bbox.yMax + 31) >> 6; - glyph->freetype_index = gindex; - int real_advance = ((int)ceil((float)freetype_face->glyph->advance.x + - plugin->config.stroke_width * 64) >> 6); - glyph->advance_w = glyph->width + glyph->left; - if (real_advance > glyph->advance_w) - glyph->advance_w = real_advance; -//printf("GlyphUnit::process_package 1 width=%d height=%d pitch=%d left=%d top=%d advance_w=%d freetype_index=%d\n", -//glyph->width, glyph->height, glyph->pitch, glyph->left, glyph->top, glyph->advance_w, glyph->freetype_index); - - -//printf("GlyphUnit::process_package 1\n"); - glyph->data = new VFrame(0, - glyph->width, - glyph->height, - BC_A8, - glyph->pitch); - glyph->data_stroke = new VFrame(0, - glyph->width, - glyph->height, - BC_A8, - glyph->pitch); - glyph->data->clear_frame(); - 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_OutlineGlyph) glyph_image)->outline, - &bm); - bm.buffer=glyph->data_stroke->get_data(); - FT_Outline_Get_Bitmap( freetype_library, - &outline, - &bm); - FT_Outline_Done(freetype_library,&outline); - FT_Stroker_Done(stroker); - FT_Done_Glyph(glyph_image); - -//printf("GlyphUnit::process_package 2\n"); - } - } -} - -GlyphEngine::GlyphEngine(TitleMain *plugin, int cpus) - : LoadServer(cpus, cpus) -{ - this->plugin = plugin; -} -void GlyphEngine::init_packages() -{ - int current_package = 0; - for(int i = 0; i < plugin->glyphs.total; i++) - { - if(!plugin->glyphs.values[i]->data) - { - GlyphPackage *pkg = (GlyphPackage*)packages[current_package++]; - pkg->glyph = plugin->glyphs.values[i]; - } - } -} -LoadClient* GlyphEngine::new_client() -{ - return new GlyphUnit(plugin, this); -} -LoadPackage* GlyphEngine::new_package() -{ - return new GlyphPackage; -} - - - - - - - - - - - - - -// Copy a single character to the text mask -TitlePackage::TitlePackage() - : LoadPackage() -{ -} - - -TitleUnit::TitleUnit(TitleMain *plugin, TitleEngine *server) - : LoadClient(server) -{ - this->plugin = plugin; -} - -void TitleUnit::draw_glyph(VFrame *output, TitleGlyph *glyph, int x, int y) -{ - int glyph_w = glyph->data->get_w(); - int glyph_h = glyph->data->get_h(); - int output_w = output->get_w(); - int output_h = output->get_h(); - unsigned char **in_rows = glyph->data->get_rows(); - unsigned char **out_rows = output->get_rows(); - -//printf("TitleUnit::draw_glyph 1 %c %d %d\n", glyph->c, x, y); - for(int in_y = 0; in_y < glyph_h; in_y++) - { -// int y_out = y + plugin->ascent + in_y - glyph->top; - int y_out = y + plugin->get_char_height() + in_y - glyph->top; - -//printf("TitleUnit::draw_glyph 1 %d\n", y_out); - if(y_out >= 0 && y_out < output_h) - { - unsigned char *out_row = out_rows[y_out]; - unsigned char *in_row = in_rows[in_y]; - for(int in_x = 0; in_x < glyph_w; in_x++) - { - int x_out = x + glyph->left + in_x; - if(x_out >= 0 && x_out < output_w) - { - if(in_row[in_x] > 0) - out_row[x_out] = in_row[in_x]; -//out_row[x_out] = 0xff; - } - } - } - } -} - - -void TitleUnit::process_package(LoadPackage *package) -{ - TitlePackage *pkg = (TitlePackage*)package; - - if(pkg->c != 0xa) - { - for(int i = 0; i < plugin->glyphs.total; i++) - { - TitleGlyph *glyph = plugin->glyphs.values[i]; - if(glyph->c == pkg->c) - { - draw_glyph(plugin->text_mask, glyph, pkg->x, pkg->y); - if(plugin->config.stroke_width >= ZERO && - (plugin->config.style & FONT_OUTLINE)) - { - VFrame *tmp = glyph->data; - glyph->data = glyph->data_stroke; - draw_glyph(plugin->text_mask_stroke, glyph, pkg->x, pkg->y); - glyph->data = tmp; - } - break; - } - } - } -} - -TitleEngine::TitleEngine(TitleMain *plugin, int cpus) - : LoadServer(cpus, cpus) -{ - this->plugin = plugin; -} - -void TitleEngine::init_packages() -{ - int visible_y1 = plugin->visible_row1 * plugin->get_char_height(); - int current_package = 0; - for(int i = plugin->visible_char1; i < plugin->visible_char2; i++) - { - title_char_position_t *char_position = plugin->char_positions + i; - TitlePackage *pkg = (TitlePackage*)get_package(current_package); - pkg->x = char_position->x; - pkg->y = char_position->y - visible_y1; - pkg->c = plugin->config.text[i]; - current_package++; - } -} - -LoadClient* TitleEngine::new_client() -{ - return new TitleUnit(plugin, this); -} - -LoadPackage* TitleEngine::new_package() -{ - return new TitlePackage; -} - - - - - - - - - - - -TitleTranslatePackage::TitleTranslatePackage() - : LoadPackage() -{ -} - - -TitleTranslateUnit::TitleTranslateUnit(TitleMain *plugin, TitleTranslate *server) - : LoadClient(server) -{ - this->plugin = plugin; -} - - - -#define TRANSLATE(type, max, components, r, g, b) \ -{ \ - unsigned char **in_rows = plugin->text_mask->get_rows(); \ - type **out_rows = (type**)plugin->output->get_rows(); \ - \ - for(int i = pkg->y1; i < pkg->y2; i++) \ - { \ - if(i + server->out_y1_int >= 0 && \ - i + server->out_y1_int < server->output_h) \ - { \ - int in_y1, in_y2; \ - float y_fraction1, y_fraction2; \ - float y_output_fraction; \ - in_y1 = server->y_table[i].in_x1; \ - in_y2 = server->y_table[i].in_x2; \ - y_fraction1 = server->y_table[i].in_fraction1; \ - y_fraction2 = server->y_table[i].in_fraction2; \ - y_output_fraction = server->y_table[i].output_fraction; \ - unsigned char *in_row1 = in_rows[in_y1]; \ - unsigned char *in_row2 = in_rows[in_y2]; \ - type *out_row = out_rows[i + server->out_y1_int]; \ - \ - for(int j = server->out_x1_int; j < server->out_x2_int; j++) \ - { \ - if(j >= 0 && j < server->output_w) \ - { \ - int in_x1; \ - int in_x2; \ - float x_fraction1; \ - float x_fraction2; \ - float x_output_fraction; \ - in_x1 = \ - server->x_table[j - server->out_x1_int].in_x1; \ - in_x2 = \ - server->x_table[j - server->out_x1_int].in_x2; \ - x_fraction1 = \ - server->x_table[j - server->out_x1_int].in_fraction1; \ - x_fraction2 = \ - server->x_table[j - server->out_x1_int].in_fraction2; \ - x_output_fraction = \ - server->x_table[j - server->out_x1_int].output_fraction; \ - \ - float fraction1 = x_fraction1 * y_fraction1; \ - float fraction2 = x_fraction2 * y_fraction1; \ - float fraction3 = x_fraction1 * y_fraction2; \ - float fraction4 = x_fraction2 * y_fraction2; \ - int input = (int)(in_row1[in_x1] * fraction1 + \ - in_row1[in_x2] * fraction2 + \ - in_row2[in_x1] * fraction3 + \ - in_row2[in_x2] * fraction4 + 0.5); \ - input *= plugin->alpha; \ -/* Alpha is 0 - 256 */ \ - input >>= 8; \ - \ - int anti_input = 0xff - input; \ - if(components == 4) \ - { \ - out_row[j * components + 0] = \ - (r * input + out_row[j * components + 0] * anti_input) / 0xff; \ - out_row[j * components + 1] = \ - (g * input + out_row[j * components + 1] * anti_input) / 0xff; \ - out_row[j * components + 2] = \ - (b * input + out_row[j * components + 2] * anti_input) / 0xff; \ - if(max == 0xffff) \ - out_row[j * components + 3] = \ - MAX((input << 8) | input, out_row[j * components + 3]); \ - else \ - out_row[j * components + 3] = \ - MAX(input, out_row[j * components + 3]); \ - } \ - else \ - { \ - out_row[j * components + 0] = \ - (r * input + out_row[j * components + 0] * anti_input) / 0xff; \ - out_row[j * components + 1] = \ - (g * input + out_row[j * components + 1] * anti_input) / 0xff; \ - out_row[j * components + 2] = \ - (b * input + out_row[j * components + 2] * anti_input) / 0xff; \ - } \ - } \ - } \ - } \ - } \ -} - - -#define TRANSLATEA(type, max, components, r, g, b) \ -{ \ - unsigned char **in_rows = plugin->text_mask->get_rows(); \ - type **out_rows = (type**)plugin->output->get_rows(); \ - \ - for(int i = pkg->y1; i < pkg->y2; i++) \ - { \ - if(i + server->out_y1_int >= 0 && \ - i + server->out_y1_int < server->output_h) \ - { \ - unsigned char *in_row = in_rows[i]; \ - type *out_row = out_rows[i + server->out_y1_int]; \ - \ - for(int j = server->out_x1; j < server->out_x2_int; j++) \ - { \ - if(j >= 0 && \ - j < server->output_w) \ - { \ - int input = (int)(in_row[j - server->out_x1]); \ - \ - input *= plugin->alpha; \ -/* Alpha is 0 - 256 */ \ - input >>= 8; \ - \ - int anti_input = 0xff - input; \ - if(components == 4) \ - { \ - out_row[j * components + 0] = \ - (r * input + out_row[j * components + 0] * anti_input) / 0xff; \ - out_row[j * components + 1] = \ - (g * input + out_row[j * components + 1] * anti_input) / 0xff; \ - out_row[j * components + 2] = \ - (b * input + out_row[j * components + 2] * anti_input) / 0xff; \ - if(max == 0xffff) \ - out_row[j * components + 3] = \ - MAX((input << 8) | input, out_row[j * components + 3]); \ - else \ - out_row[j * components + 3] = \ - MAX(input, out_row[j * components + 3]); \ - } \ - else \ - { \ - out_row[j * components + 0] = \ - (r * input + out_row[j * components + 0] * anti_input) / 0xff; \ - out_row[j * components + 1] = \ - (g * input + out_row[j * components + 1] * anti_input) / 0xff; \ - out_row[j * components + 2] = \ - (b * input + out_row[j * components + 2] * anti_input) / 0xff; \ - } \ - } \ - } \ - } \ - } \ -} - -static YUV yuv; - -void TitleTranslateUnit::process_package(LoadPackage *package) -{ - TitleTranslatePackage *pkg = (TitleTranslatePackage*)package; - TitleTranslate *server = (TitleTranslate*)this->server; - int r_in, g_in, b_in; - -//printf("TitleTranslateUnit::process_package 1 %d %d\n", pkg->y1, pkg->y2); - - r_in = (plugin->config.color & 0xff0000) >> 16; - g_in = (plugin->config.color & 0xff00) >> 8; - b_in = plugin->config.color & 0xff; - - switch(plugin->output->get_color_model()) - { - case BC_RGB888: - { - TRANSLATE(unsigned char, 0xff, 3, r_in, g_in, b_in); - break; - } - case BC_YUV888: - { - unsigned char y, u, v; - yuv.rgb_to_yuv_8(r_in, g_in, b_in, y, u, v); - TRANSLATE(unsigned char, 0xff, 3, y, u, v); - break; - } - case BC_RGB161616: - { - uint16_t r, g, b; - r = (r_in << 8) | r_in; - g = (g_in << 8) | g_in; - b = (b_in << 8) | b_in; - TRANSLATE(uint16_t, 0xffff, 3, r, g, b); - break; - } - case BC_YUV161616: - { - uint16_t y, u, v; - yuv.rgb_to_yuv_16( - (r_in << 8) | r_in, - (g_in << 8) | g_in, - (b_in << 8) | b_in, - y, - u, - v); - TRANSLATE(uint16_t, 0xffff, 3, y, u, v); - break; - } - case BC_RGBA8888: - { - TRANSLATE(unsigned char, 0xff, 4, r_in, g_in, b_in); - break; - } - case BC_YUVA8888: - { - unsigned char y, u, v; - yuv.rgb_to_yuv_8(r_in, g_in, b_in, y, u, v); - TRANSLATE(unsigned char, 0xff, 4, y, u, v); - break; - } - case BC_RGBA16161616: - { - uint16_t r, g, b; - r = (r_in << 8) | r_in; - g = (g_in << 8) | g_in; - b = (b_in << 8) | b_in; - TRANSLATE(uint16_t, 0xffff, 4, r, g, b); - break; - } - case BC_YUVA16161616: - { - uint16_t y, u, v; - yuv.rgb_to_yuv_16( - (r_in << 8) | r_in, - (g_in << 8) | g_in, - (b_in << 8) | b_in, - y, - u, - v); - TRANSLATE(uint16_t, 0xffff, 4, y, u, v); - break; - } - } - -//printf("TitleTranslateUnit::process_package 5\n"); -} - - - - -TitleTranslate::TitleTranslate(TitleMain *plugin, int cpus) - : LoadServer(1, 1) -{ - this->plugin = plugin; - x_table = y_table = 0; -} - -TitleTranslate::~TitleTranslate() -{ - if(x_table) delete [] x_table; - if(y_table) delete [] y_table; -} - -void TitleTranslate::init_packages() -{ -//printf("TitleTranslate::init_packages 1\n"); -// Generate scaling tables - if(x_table) delete [] x_table; - if(y_table) delete [] y_table; -//printf("TitleTranslate::init_packages 1\n"); - - output_w = plugin->output->get_w(); - output_h = plugin->output->get_h(); -//printf("TitleTranslate::init_packages 1 %f %d\n", plugin->text_x1, plugin->text_w); - - - TranslateUnit::translation_array_f(x_table, - plugin->text_x1, - plugin->text_x1 + plugin->text_w, - 0, - plugin->text_w, - plugin->text_w, - output_w, - out_x1_int, - out_x2_int); -//printf("TitleTranslate::init_packages 1 %f %f\n", plugin->mask_y1, plugin->mask_y2); - - TranslateUnit::translation_array_f(y_table, - plugin->mask_y1, - plugin->mask_y1 + plugin->text_mask->get_h(), - 0, - plugin->text_mask->get_h(), - plugin->text_mask->get_h(), - output_h, - out_y1_int, - out_y2_int); - -//printf("TitleTranslate::init_packages 1\n"); - - - out_y1 = out_y1_int; - out_y2 = out_y2_int; - out_x1 = out_x1_int; - out_x2 = out_x2_int; - int increment = (out_y2 - out_y1) / get_total_packages() + 1; - -//printf("TitleTranslate::init_packages 1 %d %d %d %d\n", -// out_y1, out_y2, out_y1_int, out_y2_int); - for(int i = 0; i < get_total_packages(); i++) - { - TitleTranslatePackage *pkg = (TitleTranslatePackage*)get_package(i); - pkg->y1 = i * increment; - pkg->y2 = i * increment + increment; - if(pkg->y1 > out_y2 - out_y1) - pkg->y1 = out_y2 - out_y1; - if(pkg->y2 > out_y2 - out_y1) - pkg->y2 = out_y2 - out_y1; - } -//printf("TitleTranslate::init_packages 2\n"); -} - -LoadClient* TitleTranslate::new_client() -{ - return new TitleTranslateUnit(plugin, this); -} - -LoadPackage* TitleTranslate::new_package() -{ - return new TitleTranslatePackage; -} - - - - - - - - - - - - - - - -ArrayList* TitleMain::fonts = 0; - - - -TitleMain::TitleMain(PluginServer *server) - : PluginVClient(server) -{ - PLUGIN_CONSTRUCTOR_MACRO - -// Build font database - build_fonts(); - text_mask = 0; - text_mask_stroke = 0; - glyph_engine = 0; - title_engine = 0; - freetype_library = 0; - freetype_face = 0; - char_positions = 0; - rows_bottom = 0; - translate = 0; - need_reconfigure = 1; -} - -TitleMain::~TitleMain() -{ - PLUGIN_DESTRUCTOR_MACRO - if(text_mask) delete text_mask; - if(text_mask_stroke) delete text_mask_stroke; - if(char_positions) delete [] char_positions; - if(rows_bottom) delete [] rows_bottom; - clear_glyphs(); - if(glyph_engine) delete glyph_engine; - if(title_engine) delete title_engine; - if(freetype_library) FT_Done_FreeType(freetype_library); - if(translate) delete translate; -} - -char* TitleMain::plugin_title() { return _("Title"); } -int TitleMain::is_realtime() { return 1; } -int TitleMain::is_synthesis() { return 1; } - -void TitleMain::build_fonts() -{ - if(!fonts) - { - fonts = new ArrayList; -// Construct path from location of the plugin - char search_path[BCTEXTLEN]; - strcpy(search_path, PluginClient::get_path()); - char *ptr = strrchr(search_path, '/'); - strcpy(ptr + 1, FONT_SEARCHPATH); - char command_line[BCTEXTLEN]; - - sprintf(command_line, - "find %s -name 'fonts.dir' -print -exec cat {} \\;", - search_path); -//printf("TitleMain::build_fonts %s\n", command_line); - - FILE *in = popen(command_line, "r"); - - - char current_dir[BCTEXTLEN]; - FT_Library freetype_library = 0; // Freetype library - FT_Face freetype_face = 0; - -// FT_Init_FreeType(&freetype_library); - current_dir[0] = 0; - - while(!feof(in)) - { - char string[BCTEXTLEN], string2[BCTEXTLEN]; - fgets(string, BCTEXTLEN, in); - if(!strlen(string)) break; - - char *in_ptr = string; - char *out_ptr; - -// Get current directory - - if(string[0] == '/') - { - out_ptr = current_dir; - while(*in_ptr != 0 && *in_ptr != 0xa) - *out_ptr++ = *in_ptr++; - out_ptr--; - while(*out_ptr != '/') - *out_ptr-- = 0; - } - else - { - - -//printf("TitleMain::build_fonts %s\n", string); - FontEntry *entry = new FontEntry; - int result = 0; - -// Path - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != ' ' && *in_ptr != 0xa) - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - if(string2[0] == '/') - { - entry->path = new char[strlen(string2) + 1]; - sprintf(entry->path, "%s", string2); - } - else - { - entry->path = new char[strlen(current_dir) + strlen(string2) + 1]; - sprintf(entry->path, "%s%s", current_dir, string2); - } - - -// Test path existence - struct stat test_stat; - if(stat(entry->path, &test_stat)) - { - result = 1; - } -//printf("TitleMain::build_fonts 1 %s\n", entry->path); - -// Foundary - while(*in_ptr != 0 && *in_ptr != 0xa && (*in_ptr == ' ' || *in_ptr == '-')) - in_ptr++; - - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != ' ' && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->foundary = new char[strlen(string2) + 1]; - strcpy(entry->foundary, string2); - if(*in_ptr == '-') in_ptr++; - - -// Family - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->family = new char[strlen(string2) + 1]; - strcpy(entry->family, string2); - if(*in_ptr == '-') in_ptr++; - -// Weight - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->weight = new char[strlen(string2) + 1]; - strcpy(entry->weight, string2); - if(*in_ptr == '-') in_ptr++; - -// Slant - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->slant = new char[strlen(string2) + 1]; - strcpy(entry->slant, string2); - if(*in_ptr == '-') in_ptr++; - -// SWidth - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->swidth = new char[strlen(string2) + 1]; - strcpy(entry->swidth, string2); - if(*in_ptr == '-') in_ptr++; - -// Adstyle - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->adstyle = new char[strlen(string2) + 1]; - strcpy(entry->adstyle, string2); - if(*in_ptr == '-') in_ptr++; - -// pixelsize - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->pixelsize = atol(string2); - if(*in_ptr == '-') in_ptr++; - -// pointsize - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->pointsize = atol(string2); - if(*in_ptr == '-') in_ptr++; - -// xres - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->xres = atol(string2); - if(*in_ptr == '-') in_ptr++; - -// yres - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->yres = atol(string2); - if(*in_ptr == '-') in_ptr++; - -// spacing - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->spacing = new char[strlen(string2) + 1]; - strcpy(entry->spacing, string2); - if(*in_ptr == '-') in_ptr++; - -// avg_width - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->avg_width = atol(string2); - if(*in_ptr == '-') in_ptr++; - -// registry - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa && *in_ptr != '-') - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->registry = new char[strlen(string2) + 1]; - strcpy(entry->registry, string2); - if(*in_ptr == '-') in_ptr++; - -// encoding - out_ptr = string2; - while(*in_ptr != 0 && *in_ptr != 0xa) - { - *out_ptr++ = *in_ptr++; - } - *out_ptr = 0; - entry->encoding = new char[strlen(string2) + 1]; - strcpy(entry->encoding, string2); - - - -// Add to list - if(strlen(entry->foundary) && !result) - { -//printf("TitleMain::build_fonts 1 %s\n", entry->path); -// This takes a real long time to do. Instead just take all fonts -// if(!load_freetype_face(freetype_library, -// freetype_face, -// entry->path)) -// if(1) - if(entry->family[0]) - { -// Fix parameters - sprintf(string, "%s (%s)", entry->family, entry->foundary); - entry->fixed_title = new char[strlen(string) + 1]; - strcpy(entry->fixed_title, string); - - if(!strcasecmp(entry->weight, "demibold") || - !strcasecmp(entry->weight, "bold")) - entry->fixed_style |= FONT_BOLD; - if(!strcasecmp(entry->slant, "i") || - !strcasecmp(entry->slant, "o")) - entry->fixed_style |= FONT_ITALIC; - fonts->append(entry); -// printf("TitleMain::build_fonts %s: success\n", -// entry->path); -//printf("TitleMain::build_fonts 2\n"); - } - else - { -// printf("TitleMain::build_fonts %s: FT_New_Face failed\n", -// entry->path); -//printf("TitleMain::build_fonts 3\n"); - delete entry; - } - } - else - { - delete entry; - } - } - } - pclose(in); - - if(freetype_library) FT_Done_FreeType(freetype_library); - } - - -// for(int i = 0; i < fonts->total; i++) -// fonts->values[i]->dump(); - - -} - -int TitleMain::load_freetype_face(FT_Library &freetype_library, - FT_Face &freetype_face, - char *path) -{ -//printf("TitleMain::load_freetype_face 1\n"); - if(!freetype_library) FT_Init_FreeType(&freetype_library); - if(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)) - { - fprintf(stderr, _("TitleMain::load_freetype_face %s failed.\n")); - FT_Done_FreeType(freetype_library); - freetype_face = 0; - freetype_library = 0; - return 1; - } else - { - return 0; - } - -//printf("TitleMain::load_freetype_face 4\n"); -} - -FontEntry* TitleMain::get_font_entry(char *title, - int style, - int size) -{ -//printf("TitleMain::get_font_entry %s %d %d\n", title, style, size); - FontEntry *result = 0; - int got_title = 0; - - for(int i = 0; i < fonts->total; i++) - { - FontEntry *entry = fonts->values[i]; - - if(!result) result = entry; - - if(!strcmp(title, entry->fixed_title)) - { - if(!got_title) result = entry; - got_title = 1; - -// Not every font has a size but every font has a style - if(entry->fixed_style == style) - result = entry; - - if(entry->fixed_style == style && entry->pointsize == size) - result = entry; - - } - } - - return result; -} - - -FontEntry* TitleMain::get_font() -{ - return get_font_entry(config.font, - config.style, - config.size); -} - - - - - - -int TitleMain::get_char_height() -{ -// this is height above the zero line, but does not include characters that go below - int result = config.size; - if((config.style & FONT_OUTLINE)) result += (int)ceil(config.stroke_width * 2); - return result; -} - -int TitleMain::get_char_advance(int current, int next) -{ - FT_Vector kerning; - int result = 0; - TitleGlyph *current_glyph = 0; - TitleGlyph *next_glyph = 0; - - if(current == 0xa) return 0; - - for(int i = 0; i < glyphs.total; i++) - { - if(glyphs.values[i]->c == current) - { - current_glyph = glyphs.values[i]; - break; - } - } - - for(int i = 0; i < glyphs.total; i++) - { - if(glyphs.values[i]->c == next) - { - next_glyph = glyphs.values[i]; - break; - } - } - - if(current_glyph) - result = current_glyph->advance_w; - -//printf("TitleMain::get_char_advance 1 %c %c %p %p\n", current, next, current_glyph, next_glyph); - if(next_glyph) - FT_Get_Kerning(freetype_face, - current_glyph->freetype_index, - next_glyph->freetype_index, - ft_kerning_default, - &kerning); - else - kerning.x = 0; -//printf("TitleMain::get_char_advance 2 %d %d\n", result, kerning.x); - - return result + (kerning.x >> 6); -} - - -void TitleMain::draw_glyphs() -{ -// Build table of all glyphs needed - int text_len = strlen(config.text); - int total_packages = 0; - iconv_t cd; - cd = iconv_open ("UCS-4", config.encoding); - - - if (cd == (iconv_t) -1) - { -/* Something went wrong. */ - fprintf (stderr, _("Iconv conversion from %s to Unicode UCS-4 not available\n"),config.encoding); - }; - - for(int i = 0; i < text_len; i++) - { - FT_ULong char_code; - int c = config.text[i]; - int exists = 0; - -/* if iconv is working ok for current encoding */ - if (cd != (iconv_t) -1) - { - - size_t inbytes,outbytes; - char inbuf; - char *inp = (char*)&inbuf, *outp = (char *)&char_code; - - inbuf = (char)c; - inbytes = 1; - outbytes = 4; - - iconv (cd, &inp, &inbytes, &outp, &outbytes); -#if __BYTE_ORDER == __LITTLE_ENDIAN - char_code = bswap_32(char_code); -#endif /* Big endian. */ - - } - else - { - char_code = c; - } - - for(int j = 0; j < glyphs.total; j++) - { - if(glyphs.values[j]->char_code == char_code) - { - exists = 1; - break; - } - } - - if(!exists) - { - total_packages++; -//printf("TitleMain::draw_glyphs 1\n"); - TitleGlyph *glyph = new TitleGlyph; -//printf("TitleMain::draw_glyphs 2\n"); - glyphs.append(glyph); - glyph->c = c; - glyph->char_code = char_code; - } - } - iconv_close(cd); - - if(!glyph_engine) - glyph_engine = new GlyphEngine(this, PluginClient::smp + 1); - - glyph_engine->set_package_count(total_packages); -//printf("TitleMain::draw_glyphs 3 %d\n", glyphs.total); - glyph_engine->process_packages(); -//printf("TitleMain::draw_glyphs 4\n"); -} - -void TitleMain::get_total_extents() -{ -// Determine extents of total text - int current_w = 0; - int row_start = 0; - text_len = strlen(config.text); - if(!char_positions) char_positions = new title_char_position_t[text_len]; - - text_rows = 0; - text_w = 0; - ascent = 0; - - for(int i = 0; i < glyphs.total; i++) - if(glyphs.values[i]->top > ascent) ascent = glyphs.values[i]->top; -//printf("TitleMain::get_total_extents %d\n", ascent); - - // get the number of rows first - for(int i = 0; i < text_len; i++) - { - if(config.text[i] == 0xa || i == text_len - 1) - { - text_rows++; - } - } - if (!rows_bottom) rows_bottom = new int[text_rows+1]; - text_rows = 0; - rows_bottom[0] = 0; - - for(int i = 0; i < text_len; i++) - { - char_positions[i].x = current_w; - char_positions[i].y = text_rows * get_char_height(); - char_positions[i].w = get_char_advance(config.text[i], config.text[i + 1]); - TitleGlyph *current_glyph = 0; - for(int j = 0; j < glyphs.total; j++) - { - if(glyphs.values[j]->c == config.text[i]) - { - current_glyph = glyphs.values[j]; - break; - } - } - int current_bottom = current_glyph->top - current_glyph->height; - if (current_bottom < rows_bottom[text_rows]) - rows_bottom[text_rows] = current_bottom ; - -// printf("TitleMain::get_total_extents 1 %c %d %d %d\n", -// config.text[i], -// char_positions[i].x, -// char_positions[i].y, -// char_positions[i].w); - current_w += char_positions[i].w; - - if(config.text[i] == 0xa || i == text_len - 1) - { - text_rows++; - rows_bottom[text_rows] = 0; - if(current_w > text_w) text_w = current_w; - current_w = 0; - } - } - text_w += config.dropshadow; - text_h = text_rows * get_char_height(); - text_h += config.dropshadow; - -// Now that text_w is known -// Justify rows based on configuration - row_start = 0; - for(int i = 0; i < text_len; i++) - { - if(config.text[i] == 0xa || i == text_len - 1) - { - for(int j = row_start; j <= i; j++) - { - switch(config.hjustification) - { - case JUSTIFY_LEFT: - break; - - case JUSTIFY_MID: - char_positions[j].x += (text_w - - char_positions[i].x - - char_positions[i].w) / - 2; - break; - - case JUSTIFY_RIGHT: - char_positions[j].x += (text_w - - char_positions[i].x - - char_positions[i].w); - break; - } - } - row_start = i + 1; - } - } - - -//printf("TitleMain::get_total_extents 2 %d %d\n", text_w, text_h); -} - -int TitleMain::draw_mask() -{ - int old_visible_row1 = visible_row1; - int old_visible_row2 = visible_row2; - - -// Determine y of visible text - if(config.motion_strategy == BOTTOM_TO_TOP) - { -// printf("TitleMain::draw_mask 1 %d %d %d %d\n", -// config.motion_strategy, -// get_source_position(), -// get_source_start(), -// config.prev_keyframe_position); - float magnitude = config.pixels_per_second * - ((get_source_position() - get_source_start()) - - (config.prev_keyframe_position - get_source_start())) / - PluginVClient::project_frame_rate; - if(config.loop) - { - int loop_size = text_h + input->get_h(); - magnitude -= (int)(magnitude / loop_size) * loop_size; - } - text_y1 = config.y + input->get_h() - magnitude; - } - else - if(config.motion_strategy == TOP_TO_BOTTOM) - { - float magnitude = config.pixels_per_second * - (get_source_position() - - get_source_start() - - config.prev_keyframe_position) / - PluginVClient::project_frame_rate; - if(config.loop) - { - int loop_size = text_h + input->get_h(); - magnitude -= (int)(magnitude / loop_size) * loop_size; - } - text_y1 = config.y + magnitude; - text_y1 -= text_h; - } - else - if(config.vjustification == JUSTIFY_TOP) - { - text_y1 = config.y; - } - else - if(config.vjustification == JUSTIFY_MID) - { - text_y1 = config.y + input->get_h() / 2 - text_h / 2; - } - else - if(config.vjustification == JUSTIFY_BOTTOM) - { - text_y1 = config.y + input->get_h() - text_h; - } - - text_y2 = text_y1 + text_h + 0.5; - -// Determine x of visible text - if(config.motion_strategy == RIGHT_TO_LEFT) - { - float magnitude = config.pixels_per_second * - (get_source_position() - - get_source_start() - - config.prev_keyframe_position) / - PluginVClient::project_frame_rate; - if(config.loop) - { - int loop_size = text_w + input->get_w(); - magnitude -= (int)(magnitude / loop_size) * loop_size; - } - text_x1 = config.x + (float)input->get_w() - magnitude; - } - else - if(config.motion_strategy == LEFT_TO_RIGHT) - { - float magnitude = config.pixels_per_second * - (get_source_position() - - get_source_start() - - config.prev_keyframe_position) / - PluginVClient::project_frame_rate; - if(config.loop) - { - int loop_size = text_w + input->get_w(); - magnitude -= (int)(magnitude / loop_size) * loop_size; - } - text_x1 = config.x + -(float)text_w + magnitude; - } - else - if(config.hjustification == JUSTIFY_LEFT) - { - text_x1 = config.x; - } - else - if(config.hjustification == JUSTIFY_MID) - { - text_x1 = config.x + input->get_w() / 2 - text_w / 2; - } - else - if(config.hjustification == JUSTIFY_RIGHT) - { - text_x1 = config.x + input->get_w() - text_w; - } - - - - - -// Determine y extents just of visible text - visible_row1 = (int)(-text_y1 / get_char_height()); - if(visible_row1 < 0) visible_row1 = 0; - - visible_row2 = (int)((float)text_rows - (text_y2 - input->get_h()) / get_char_height() + 1); - if(visible_row2 > text_rows) visible_row2 = text_rows; - - - if(visible_row2 <= visible_row1) return 1; - - - mask_y1 = text_y1 + visible_row1 * get_char_height(); - mask_y2 = text_y1 + visible_row2 * get_char_height(); - text_x1 += config.x; - - - visible_char1 = visible_char2 = 0; - int got_char1 = 0; - for(int i = 0; i < text_len; i++) - { - title_char_position_t *char_position = char_positions + i; - int char_row = char_position->y / get_char_height(); - if(char_row >= visible_row1 && - char_row < visible_row2) - - { - if(!got_char1) - { - visible_char1 = i; - got_char1 = 1; - } - visible_char2 = i; - } - } - visible_char2++; - - - - int visible_rows = visible_row2 - visible_row1; - int need_redraw = 0; - if(text_mask && - (text_mask->get_w() != text_w || - text_mask->get_h() != visible_rows * get_char_height() - rows_bottom[visible_row2 - 1])) - { - delete text_mask; - delete text_mask_stroke; - text_mask = 0; - text_mask_stroke = 0; - } - - if(!text_mask) - { - text_mask = new VFrame(0, - text_w, - visible_rows * get_char_height() - rows_bottom[visible_row2-1], - BC_A8); - text_mask_stroke = new VFrame(0, - text_w, - visible_rows * get_char_height() - rows_bottom[visible_row2-1], - BC_A8); - - need_redraw = 1; - } - - - -// Draw on text mask if different - if(old_visible_row1 != visible_row1 || - old_visible_row2 != visible_row2 || - need_redraw) - { - text_mask->clear_frame(); - text_mask_stroke->clear_frame(); - - - if(!title_engine) - title_engine = new TitleEngine(this, PluginClient::smp + 1); - - title_engine->set_package_count(visible_char2 - visible_char1); - title_engine->process_packages(); - } - - return 0; -} - - -void TitleMain::overlay_mask() -{ - - alpha = 0x100; -// printf("TitleMain::overlay_mask %lld %lld %lld\n", -// get_source_position(), -// config.prev_keyframe_position, -// config.next_keyframe_position); - if(!EQUIV(config.fade_in, 0)) - { - int fade_len = (int)(config.fade_in * PluginVClient::project_frame_rate); - int fade_position = get_source_position() - -/* get_source_start() - */ - config.prev_keyframe_position; - - - if(fade_position >= 0 && fade_position < fade_len) - { - alpha = (int)((float)0x100 * - fade_position / - fade_len + 0.5); - } - } - - if(!EQUIV(config.fade_out, 0)) - { - int fade_len = (int)(config.fade_out * - PluginVClient::project_frame_rate); - int fade_position = config.next_keyframe_position - - get_source_position(); - - - if(fade_position >= 0 && fade_position < fade_len) - { - alpha = (int)((float)0x100 * - fade_position / - fade_len + 0.5); - } - } - - if(config.dropshadow) - { - text_x1 += config.dropshadow; - text_x2 += config.dropshadow; - mask_y1 += config.dropshadow; - mask_y2 += config.dropshadow; - if(text_x1 < input->get_w() && text_x1 + text_w > 0 && - mask_y1 < input->get_h() && mask_y2 > 0) - { - if(!translate) translate = new TitleTranslate(this, PluginClient::smp + 1); -// Do 2 passes if dropshadow. - int temp_color = config.color; - config.color = 0x0; - translate->process_packages(); - config.color = temp_color; - } - text_x1 -= config.dropshadow; - text_x2 -= config.dropshadow; - mask_y1 -= config.dropshadow; - mask_y2 -= config.dropshadow; - } - - if(text_x1 < input->get_w() && text_x1 + text_w > 0 && - mask_y1 < input->get_h() && mask_y2 > 0) - { - if(!translate) translate = new TitleTranslate(this, PluginClient::smp + 1); - translate->process_packages(); - if (config.stroke_width >= ZERO && - (config.style & FONT_OUTLINE)) - { - int temp_color = config.color; - VFrame *tmp_text_mask = this->text_mask; - config.color = config.color_stroke; - this->text_mask = this->text_mask_stroke; - - translate->process_packages(); - config.color = temp_color; - this->text_mask = tmp_text_mask; - } - } -} - -void TitleMain::clear_glyphs() -{ -//printf("TitleMain::clear_glyphs 1\n"); - glyphs.remove_all_objects(); -} - -char* TitleMain::motion_to_text(int motion) -{ - switch(motion) - { - case NO_MOTION: return _("No motion"); break; - case BOTTOM_TO_TOP: return _("Bottom to top"); break; - case TOP_TO_BOTTOM: return _("Top to bottom"); break; - case RIGHT_TO_LEFT: return _("Right to left"); break; - case LEFT_TO_RIGHT: return _("Left to right"); break; - } -} - -int TitleMain::text_to_motion(char *text) -{ - for(int i = 0; i < TOTAL_PATHS; i++) - { - if(!strcasecmp(motion_to_text(i), text)) return i; - } - return 0; -} - - - - - - - -int TitleMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr) -{ - int result = 0; - input = input_ptr; - output = output_ptr; - - - need_reconfigure |= load_configuration(); - - -// Always synthesize text and redraw it for timecode - if(config.timecode) - { - Units::totext(config.text, - (double)get_source_position() / PluginVClient::project_frame_rate, - TIME_HMSF, - 0, - PluginVClient::project_frame_rate, - 0); - need_reconfigure = 1; - } - -// Check boundaries - if(config.size <= 0 || config.size >= 2048) config.size = 72; - if(config.stroke_width < 0 || - config.stroke_width >= 512) config.stroke_width = 0.0; - if(!strlen(config.text)) return 0; - if(!strlen(config.encoding)) strcpy(config.encoding, DEFAULT_ENCODING); - -//printf("TitleMain::process_realtime 4\n"); - -// Handle reconfiguration - if(need_reconfigure) - { -//printf("TitleMain::process_realtime 2\n"); - if(text_mask) delete text_mask; - if(text_mask_stroke) delete text_mask_stroke; - text_mask = 0; - text_mask_stroke = 0; -//printf("TitleMain::process_realtime 2\n"); - if(freetype_face) FT_Done_Face(freetype_face); - freetype_face = 0; -//printf("TitleMain::process_realtime 2\n"); - if(glyph_engine) delete glyph_engine; - glyph_engine = 0; -//printf("TitleMain::process_realtime 2\n"); - if(char_positions) delete [] char_positions; - char_positions = 0; - if(rows_bottom) delete [] rows_bottom; - rows_bottom = 0; -//printf("TitleMain::process_realtime 2\n"); - clear_glyphs(); -//printf("TitleMain::process_realtime 2\n"); - visible_row1 = 0; - visible_row2 = 0; - ascent = 0; - - if(!freetype_library) - FT_Init_FreeType(&freetype_library); - -//printf("TitleMain::process_realtime 2\n"); - if(!freetype_face) - { - FontEntry *font = get_font(); -//printf("TitleMain::process_realtime 2.1 %s\n", font->path); - if(load_freetype_face(freetype_library, - freetype_face, - font->path)) - { - printf("TitleMain::process_realtime %s: FT_New_Face failed.\n", - font->fixed_title); - result = 1; - } -//printf("TitleMain::process_realtime 2.2\n"); - - if(!result) FT_Set_Pixel_Sizes(freetype_face, config.size, 0); -//printf("TitleMain::process_realtime 2.3\n"); - } - -//printf("TitleMain::process_realtime 3\n"); - - if(!result) - { - draw_glyphs(); -//printf("TitleMain::process_realtime 4\n"); - get_total_extents(); -//printf("TitleMain::process_realtime 5\n"); - need_reconfigure = 0; - } - } - - if(!result) - { -//printf("TitleMain::process_realtime 4\n"); -// Determine region of text visible on the output and draw mask - result = draw_mask(); - } -//printf("TitleMain::process_realtime 50\n"); - - -// Overlay mask on output - if(!result) - { - overlay_mask(); - } -//printf("TitleMain::process_realtime 60 %d\n", glyphs.total); - - return 0; -} - -int TitleMain::show_gui() -{ - load_configuration(); - thread = new TitleThread(this); - thread->start(); - return 0; -} - -int TitleMain::set_string() -{ - if(thread) thread->window->set_title(gui_string); - return 0; -} - -void TitleMain::raise_window() -{ - if(thread) - { - thread->window->raise_window(); - thread->window->flush(); - } -} - -void TitleMain::update_gui() -{ - if(thread) - { - int reconfigure = load_configuration(); - if(reconfigure) - { - thread->window->lock_window(); - thread->window->update(); - thread->window->unlock_window(); - } - } -} - - -int TitleMain::load_defaults() -{ - char directory[1024], text_path[1024]; -// set the default directory - sprintf(directory, "%s/title.rc", File::get_config_path()); - -// load the defaults - defaults = new Defaults(directory); - defaults->load(); - - defaults->get("FONT", config.font); - defaults->get("ENCODING", config.encoding); - config.style = defaults->get("STYLE", (int64_t)config.style); - config.size = defaults->get("SIZE", config.size); - config.color = defaults->get("COLOR", config.color); - config.color_stroke = defaults->get("COLOR_STROKE", config.color_stroke); - config.stroke_width = defaults->get("STROKE_WIDTH", config.stroke_width); - config.motion_strategy = defaults->get("MOTION_STRATEGY", config.motion_strategy); - config.loop = defaults->get("LOOP", config.loop); - config.pixels_per_second = defaults->get("PIXELS_PER_SECOND", config.pixels_per_second); - config.hjustification = defaults->get("HJUSTIFICATION", config.hjustification); - config.vjustification = defaults->get("VJUSTIFICATION", config.vjustification); - config.fade_in = defaults->get("FADE_IN", config.fade_in); - config.fade_out = defaults->get("FADE_OUT", config.fade_out); - config.x = defaults->get("TITLE_X", config.x); - config.y = defaults->get("TITLE_Y", config.y); - config.dropshadow = defaults->get("DROPSHADOW", config.dropshadow); - config.timecode = defaults->get("TIMECODE", config.timecode); - window_w = defaults->get("WINDOW_W", 660); - window_h = defaults->get("WINDOW_H", 480); - -// Store text in separate path to isolate special characters - FileSystem fs; - sprintf(text_path, "%s/title_text.rc", File::get_config_path()); - fs.complete_path(text_path); - FILE *fd = fopen(text_path, "rb"); - if(fd) - { - fseek(fd, 0, SEEK_END); - int64_t len = ftell(fd); - fseek(fd, 0, SEEK_SET); - fread(config.text, len, 1, fd); - config.text[len] = 0; -//printf("TitleMain::load_defaults %s\n", config.text); - fclose(fd); - } - else - config.text[0] = 0; - return 0; -} - -int TitleMain::save_defaults() -{ - char text_path[1024]; - - defaults->update("FONT", config.font); - defaults->update("ENCODING", config.encoding); - defaults->update("STYLE", (int64_t)config.style); - defaults->update("SIZE", config.size); - defaults->update("COLOR", config.color); - defaults->update("COLOR_STROKE", config.color_stroke); - defaults->update("STROKE_WIDTH", config.stroke_width); - defaults->update("MOTION_STRATEGY", config.motion_strategy); - defaults->update("LOOP", config.loop); - defaults->update("PIXELS_PER_SECOND", config.pixels_per_second); - defaults->update("HJUSTIFICATION", config.hjustification); - defaults->update("VJUSTIFICATION", config.vjustification); - defaults->update("FADE_IN", config.fade_in); - defaults->update("FADE_OUT", config.fade_out); - defaults->update("TITLE_X", config.x); - defaults->update("TITLE_Y", config.y); - defaults->update("DROPSHADOW", config.dropshadow); - defaults->update("TIMECODE", config.timecode); - defaults->update("WINDOW_W", window_w); - defaults->update("WINDOW_H", window_h); - defaults->save(); - -// Store text in separate path to isolate special characters - FileSystem fs; - sprintf(text_path, "%s/title_text.rc", File::get_config_path()); - fs.complete_path(text_path); - FILE *fd = fopen(text_path, "wb"); - if(fd) - { - fwrite(config.text, strlen(config.text), 1, fd); - fclose(fd); - } -// else -// perror("TitleMain::save_defaults"); - return 0; -} - - - - -int TitleMain::load_configuration() -{ - KeyFrame *prev_keyframe, *next_keyframe; - prev_keyframe = get_prev_keyframe(get_source_position()); - next_keyframe = get_next_keyframe(get_source_position()); - int64_t prev_position = edl_to_local(prev_keyframe->position); - int64_t next_position = edl_to_local(next_keyframe->position); - - TitleConfig old_config, prev_config, next_config; - old_config.copy_from(config); - read_data(prev_keyframe); - prev_config.copy_from(config); - read_data(next_keyframe); - next_config.copy_from(config); - - config.prev_keyframe_position = prev_position; - config.next_keyframe_position = next_position; - if(config.next_keyframe_position == config.prev_keyframe_position) - config.next_keyframe_position = get_source_start() + get_total_len(); - if(config.prev_keyframe_position == 0) - config.prev_keyframe_position = get_source_start(); - - - - config.interpolate(prev_config, - next_config, - (next_position == prev_position) ? - get_source_position() : - prev_position, - (next_position == prev_position) ? - get_source_position() + 1 : - next_position, - get_source_position()); - - if(!config.equivalent(old_config)) - return 1; - else - return 0; -} - - - - - - - - - - - - -void TitleMain::save_data(KeyFrame *keyframe) -{ - FileXML output; - -// cause data to be stored directly in text - output.set_shared_string(keyframe->get_data(), -MESSAGESIZE); - output.tag.set_title("TITLE"); - output.tag.set_property("FONT", config.font); - output.tag.set_property("ENCODING", config.encoding); - output.tag.set_property("STYLE", (int64_t)config.style); - output.tag.set_property("SIZE", config.size); - output.tag.set_property("COLOR", config.color); - output.tag.set_property("COLOR_STROKE", config.color_stroke); - output.tag.set_property("STROKE_WIDTH", config.stroke_width); - output.tag.set_property("MOTION_STRATEGY", config.motion_strategy); - output.tag.set_property("LOOP", config.loop); - output.tag.set_property("PIXELS_PER_SECOND", config.pixels_per_second); - output.tag.set_property("HJUSTIFICATION", config.hjustification); - output.tag.set_property("VJUSTIFICATION", config.vjustification); - output.tag.set_property("FADE_IN", config.fade_in); - output.tag.set_property("FADE_OUT", config.fade_out); - output.tag.set_property("TITLE_X", config.x); - output.tag.set_property("TITLE_Y", config.y); - output.tag.set_property("DROPSHADOW", config.dropshadow); - output.tag.set_property("TIMECODE", config.timecode); - output.append_tag(); - output.append_newline(); - - output.append_text(config.text); - - output.tag.set_title("/TITLE"); - output.append_tag(); - output.append_newline(); - output.terminate_string(); -//printf("TitleMain::save_data 1\n%s\n", output.string); -//printf("TitleMain::save_data 2\n%s\n", config.text); -} - -void TitleMain::read_data(KeyFrame *keyframe) -{ - FileXML input; - - input.set_shared_string(keyframe->get_data(), strlen(keyframe->get_data())); - - int result = 0; - int new_interlace = 0; - int new_horizontal = 0; - int new_luminance = 0; - - config.prev_keyframe_position = edl_to_local(keyframe->position); - while(!result) - { - result = input.read_tag(); - - if(!result) - { - if(input.tag.title_is("TITLE")) - { - input.tag.get_property("FONT", config.font); - input.tag.get_property("ENCODING", config.encoding); - config.style = input.tag.get_property("STYLE", (int64_t)config.style); - config.size = input.tag.get_property("SIZE", config.size); - config.color = input.tag.get_property("COLOR", config.color); - config.color_stroke = input.tag.get_property("COLOR_STROKE", config.color_stroke); - config.stroke_width = input.tag.get_property("STROKE_WIDTH", config.stroke_width); - config.motion_strategy = input.tag.get_property("MOTION_STRATEGY", config.motion_strategy); - config.loop = input.tag.get_property("LOOP", config.loop); - config.pixels_per_second = input.tag.get_property("PIXELS_PER_SECOND", config.pixels_per_second); - config.hjustification = input.tag.get_property("HJUSTIFICATION", config.hjustification); - config.vjustification = input.tag.get_property("VJUSTIFICATION", config.vjustification); - config.fade_in = input.tag.get_property("FADE_IN", config.fade_in); - config.fade_out = input.tag.get_property("FADE_OUT", config.fade_out); - config.x = input.tag.get_property("TITLE_X", config.x); - config.y = input.tag.get_property("TITLE_Y", config.y); - config.dropshadow = input.tag.get_property("DROPSHADOW", config.dropshadow); - config.timecode = input.tag.get_property("TIMECODE", config.timecode); - strcpy(config.text, input.read_text()); -//printf("TitleMain::read_data 1\n%s\n", input.string); -//printf("TitleMain::read_data 2\n%s\n", config.text); - } - else - if(input.tag.title_is("/TITLE")) - { - result = 1; - } - } - } -} - - - - - - diff --git a/cinelerra-5.1/plugins/titler/title.h b/cinelerra-5.1/plugins/titler/title.h deleted file mode 100644 index f631e4fe..00000000 --- a/cinelerra-5.1/plugins/titler/title.h +++ /dev/null @@ -1,467 +0,0 @@ - -/* - * CINELERRA - * Copyright (C) 1997-2014 Adam Williams - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef TITLE_H -#define TITLE_H - - - -// Theory: - -// Stage 1: -// Only performed when text mask changes. -// Update glyph cache with every glyph used in the title. -// A parallel text renderer draws one character per CPU. -// The titler direct copies all the text currently visible onto the text mask. -// in integer coordinates. -// The text mask is in the same color space as the output but always has -// an alpha channel. - -// Stage 2: -// Performed every frame. -// The text mask is overlayed with fractional translation and fading on the output. - - - - - - -class TitleMain; -class TitleEngine; -class TitleOutlineEngine; -class GlyphEngine; -class TitleTranslate; - -#include "bchash.h" -#include "bcfontentry.h" -#include "loadbalance.h" -#include "mutex.h" -#include "pluginvclient.h" -#include "titlewindow.h" - -#include -#include FT_FREETYPE_H -#include - -// Motion strategy -#define TOTAL_PATHS 5 -#define NO_MOTION 0x0 -#define BOTTOM_TO_TOP 0x1 -#define TOP_TO_BOTTOM 0x2 -#define RIGHT_TO_LEFT 0x3 -#define LEFT_TO_RIGHT 0x4 - -// Horizontal justification -#define JUSTIFY_LEFT 0x0 -#define JUSTIFY_CENTER 0x1 -#define JUSTIFY_RIGHT 0x2 - -// Vertical justification -#define JUSTIFY_TOP 0x0 -#define JUSTIFY_MID 0x1 -#define JUSTIFY_BOTTOM 0x2 - -class TitleConfig -{ -public: - TitleConfig(); - ~TitleConfig(); - - void to_wtext(const char *from_enc, const char *text, int tlen); -// Only used to clear glyphs - int equivalent(TitleConfig &that); - void copy_from(TitleConfig &that); - void interpolate(TitleConfig &prev, - TitleConfig &next, - int64_t prev_frame, - int64_t next_frame, - int64_t current_frame); - void limits(); - -// Font information - char font[BCTEXTLEN]; - int64_t style; - int size; - int color; - int color_stroke; - int outline_color; - int alpha; - int outline_alpha; - int motion_strategy; // Motion of title across frame - int line_pitch; - int loop; // Loop motion path - float pixels_per_second; // Speed of motion - int hjustification; - int vjustification; -// Number of seconds the fade in and fade out of the title take - double fade_in, fade_out; -// Position in frame relative to top left - float x, y; -// Pixels down and right of dropshadow - int dropshadow; - int outline_size; -// Calculated during every frame for motion strategy - int64_t prev_keyframe_position; - int64_t next_keyframe_position; -// Stamp timecode - int timecode; - -// Text to display - wchar_t wtext[BCTEXTLEN]; - int wlen; - void convert_text(); - -// Encoding to convert from - char encoding[BCTEXTLEN]; -// Time Code Format - int timecode_format; -// Width of the stroke - double stroke_width; -// Size of window - int window_w, window_h; -}; - -class TitleGlyph -{ -public: - TitleGlyph(); - ~TitleGlyph(); - - FT_ULong char_code; - int width, height, pitch; - int advance_x; - int left, top, right, bottom; - int freetype_index; - VFrame *data; - VFrame *data_stroke; -}; - - - - - - - - - -// Draw a single character into the glyph cache -// -class GlyphPackage : public LoadPackage -{ -public: - GlyphPackage(); - TitleGlyph *glyph; -}; - - -class GlyphUnit : public LoadClient -{ -public: - GlyphUnit(TitleMain *plugin, GlyphEngine *server); - ~GlyphUnit(); - void process_package(LoadPackage *package); - - TitleMain *plugin; - BC_FontEntry *current_font; // Current font configured by freetype - FT_Library freetype_library; // Freetype library - FT_Face freetype_face; -}; - -class GlyphEngine : public LoadServer -{ -public: - GlyphEngine(TitleMain *plugin, int cpus); - void init_packages(); - LoadClient* new_client(); - LoadPackage* new_package(); - TitleMain *plugin; -}; - - - - - - - -// Copy a single character to the text mask -class TitlePackage : public LoadPackage -{ -public: - TitlePackage(); - int x, y; - wchar_t char_code; -}; - - -class TitleUnit : public LoadClient -{ -public: - TitleUnit(TitleMain *plugin, TitleEngine *server); - void process_package(LoadPackage *package); - void draw_glyph(VFrame *output, VFrame *data, TitleGlyph *glyph, int x, int y); - TitleMain *plugin; - TitleEngine *engine; -}; - -class TitleEngine : public LoadServer -{ -public: - TitleEngine(TitleMain *plugin, int cpus); - void init_packages(); - LoadClient* new_client(); - LoadPackage* new_package(); - TitleMain *plugin; - int do_dropshadow; -}; - - - - - -// Create outline -class TitleOutlinePackage : public LoadPackage -{ -public: - TitleOutlinePackage(); - int y1, y2; -}; - - -class TitleOutlineUnit : public LoadClient -{ -public: - TitleOutlineUnit(TitleMain *plugin, TitleOutlineEngine *server); - void process_package(LoadPackage *package); - TitleMain *plugin; - TitleOutlineEngine *engine; -}; - -class TitleOutlineEngine : public LoadServer -{ -public: - TitleOutlineEngine(TitleMain *plugin, int cpus); - void init_packages(); - void do_outline(); - LoadClient* new_client(); - LoadPackage* new_package(); - TitleMain *plugin; - int pass; -}; - - - - - - - - - -// Overlay text mask with fractional translation -// We don't use OverlayFrame to enable alpha blending on non alpha -// output. -class TitleTranslatePackage : public LoadPackage -{ -public: - TitleTranslatePackage(); - int y1, y2; -}; - -typedef struct -{ - int in_x1; - float in_fraction1; - int in_x2; // Might be same as in_x1 for boundary - float in_fraction2; - float output_fraction; -} transfer_table_f; - -class TitleTranslateUnit : public LoadClient -{ -public: - TitleTranslateUnit(TitleMain *plugin, TitleTranslate *server); - - static void translation_array_f(transfer_table_f* &table, - float out_x1, float out_x2, float in_x1, float in_x2, - int in_total, int out_total, int &out_x1_int, int &out_x2_int); - void process_package(LoadPackage *package); - TitleMain *plugin; -}; - -class TitleTranslate : public LoadServer -{ -public: - TitleTranslate(TitleMain *plugin, int cpus); - ~TitleTranslate(); - void init_packages(); - void run_packages(); - LoadClient* new_client(); - LoadPackage* new_package(); - TitleMain *plugin; - transfer_table_f *y_table; - transfer_table_f *x_table; - int output_w; - int output_h; -// Result of translation_array_f - int out_x1_int; - int out_x2_int; - int out_y1_int; - int out_y2_int; -// Values to process - int out_x1; - int out_x2; - int out_y1; - int out_y2; -}; - - - - - - - - - - - - - - -// Position of each character relative to total text extents -typedef struct -{ - int x, y, w, row; -} char_pos_t; - - - -class TitleMain : public PluginVClient -{ -public: - TitleMain(PluginServer *server); - ~TitleMain(); - -// required for all realtime plugins - PLUGIN_CLASS_MEMBERS(TitleConfig) - int process_realtime(VFrame *input_ptr, VFrame *output_ptr); - int is_realtime(); - int is_synthesis(); - void update_gui(); - void save_data(KeyFrame *keyframe); - void read_data(KeyFrame *keyframe); - - void build_previews(TitleWindow *gui); - void reset_render(); - int init_freetype(); - void load_glyphs(); - int draw_mask(); - void overlay_mask(); - TitleGlyph *get_glyph(FT_ULong char_code); - BC_FontEntry* get_font(); - int get_char_advance(FT_ULong current, FT_ULong next); - int get_char_height(); - int get_char_width(FT_ULong c); - void get_total_extents(); - void clear_glyphs(); - int check_char_code_path(FT_Library &freetype_library, - char *path_old, - FT_ULong &char_code, - char *path_new); - int load_freetype_face(FT_Library &freetype_library, - FT_Face &freetype_face, - const char *path); - void get_color_components(int *r, int *g, int *b, int *a, int is_outline); - - - - -// backward compatibility - void convert_encoding(); - static const char* motion_to_text(int motion); - static int text_to_motion(const char *text); - - ArrayList glyphs; - Mutex glyph_lock; - -// Stage 1 parameters must be compared to redraw the text mask - VFrame *text_mask; - VFrame *text_mask_stroke; - VFrame *outline_mask; - GlyphEngine *glyph_engine; - TitleEngine *title_engine; - TitleTranslate *translate; - TitleOutlineEngine *outline_engine; - -// Necessary to get character width - FT_Library freetype_library; // Freetype library - FT_Face freetype_face; - -// Visible area of all text present in the mask. -// Horizontal characters aren't clipped because column positions are -// proportional. - int visible_row1, visible_char1; - int visible_row2, visible_char2; -// Positions of the top pixels of the rows - class Geom { - public: // x1,y1 x2,y2 are abs - int x0, y0, x1, y1, x2, y2; - } extent; - class RowGeom : public Geom { - public: // x1,x2 y1,y2 are rel x0,y0 - int left() { return x0+x1; } - int top() { return y0+y1; } - int right() { return x0+x2; } - int bottom() { return y0+y2; } - } *row_geom; - int row_geom_size; - - int text_rows; -// relative position of all text to output - int text_w, text_h; - float text_x1, text_y1, text_x2, text_y2; -// Position of each character relative to total text extents - char_pos_t *char_pos; -// relative position of visible part of text to output - int mask_w, mask_h; - -// Fade value - int alpha; - -// Max dimensions for all characters. Not equal to config.size -// Must be calculated from rendering characters - int ascent; - int height; -// Relative position of mask to output is text_x1, mask_y1 -// We can either round it to nearest ints to speed up replication while the text -// itself is offset fractionally -// or replicate with fractional offsetting. Since fraction offsetting usually -// happens during motion and motion would require floating point offsetting -// for every frame we replicate with fractional offsetting. - - - - VFrame *input, *output; - - int need_reconfigure; - int cpus; -}; - - -#endif diff --git a/cinelerra-5.1/plugins/titler/title.h.stroker b/cinelerra-5.1/plugins/titler/title.h.stroker deleted file mode 100644 index 62b5be0c..00000000 --- a/cinelerra-5.1/plugins/titler/title.h.stroker +++ /dev/null @@ -1,418 +0,0 @@ -#ifndef TITLE_H -#define TITLE_H - - - - -// Theory: - -// Stage 1: -// Only performed when text mask changes. -// Update glyph cache with every glyph used in the title. -// A parallel text renderer draws one character per CPU. -// The titler direct copies all the text currently visible onto the text mask. -// in integer coordinates. -// The text mask is in the same color space as the output but always has -// an alpha channel. - -// Stage 2: -// Performed every frame. -// The text mask is overlayed with fractional translation and fading on the output. - - - - - - -class TitleMain; -class TitleEngine; -class GlyphEngine; -class TitleTranslate; - -#include "defaults.h" -#include "loadbalance.h" -#include "mutex.h" -#include "overlayframe.h" -#include "pluginvclient.h" -#include "titlewindow.h" - -#include -#include FT_FREETYPE_H -#include - -// Style bitwise ORed -#define FONT_ITALIC 0x1 -#define FONT_BOLD 0x2 -#define FONT_OUTLINE 0x4 - -// Motion strategy -#define TOTAL_PATHS 5 -#define NO_MOTION 0x0 -#define BOTTOM_TO_TOP 0x1 -#define TOP_TO_BOTTOM 0x2 -#define RIGHT_TO_LEFT 0x3 -#define LEFT_TO_RIGHT 0x4 - -// Horizontal justification -#define JUSTIFY_LEFT 0x0 -#define JUSTIFY_CENTER 0x1 -#define JUSTIFY_RIGHT 0x2 - -// Vertical justification -#define JUSTIFY_TOP 0x0 -#define JUSTIFY_MID 0x1 -#define JUSTIFY_BOTTOM 0x2 - - -class TitleConfig -{ -public: - TitleConfig(); - -// Only used to clear glyphs - int equivalent(TitleConfig &that); - void copy_from(TitleConfig &that); - void interpolate(TitleConfig &prev, - TitleConfig &next, - int64_t prev_frame, - int64_t next_frame, - int64_t current_frame); - - -// Font information - char font[BCTEXTLEN]; - int64_t style; - int size; - int color; - int color_stroke; -// Motion of title across frame - int motion_strategy; -// Loop motion path - int loop; -// Speed of motion - float pixels_per_second; - int hjustification; - int vjustification; -// Number of seconds the fade in and fade out of the title take - double fade_in, fade_out; -// Position in frame relative to top left - float x, y; -// Pixels down and right of dropshadow - int dropshadow; -// Calculated during every frame for motion strategy - int64_t prev_keyframe_position; - int64_t next_keyframe_position; -// Stamp timecode - int timecode; - -// Text to display - char text[BCTEXTLEN]; -// Encoding to convert from - char encoding[BCTEXTLEN]; -// Width of the stroke - double stroke_width; -}; - -class FontEntry -{ -public: - FontEntry(); - ~FontEntry(); - - void dump(); - - char *path; - char *foundary; - char *family; - char *weight; - char *slant; - char *swidth; - char *adstyle; - int pixelsize; - int pointsize; - int xres; - int yres; - char *spacing; - int avg_width; - char *registry; - char *encoding; - char *fixed_title; - int fixed_style; -}; - -class TitleGlyph -{ -public: - TitleGlyph(); - ~TitleGlyph(); - // character in 8 bit charset - int c; - // character in UCS-4 - FT_ULong char_code; - int width, height, pitch, advance_w, left, top, freetype_index; - VFrame *data; - VFrame *data_stroke; -}; - - - - - - - -// Draw a single character into the glyph cache -// -class GlyphPackage : public LoadPackage -{ -public: - GlyphPackage(); - TitleGlyph *glyph; -}; - - -class GlyphUnit : public LoadClient -{ -public: - GlyphUnit(TitleMain *plugin, GlyphEngine *server); - ~GlyphUnit(); - void process_package(LoadPackage *package); - - TitleMain *plugin; - FontEntry *current_font; // Current font configured by freetype - FT_Library freetype_library; // Freetype library - FT_Face freetype_face; -}; - -class GlyphEngine : public LoadServer -{ -public: - GlyphEngine(TitleMain *plugin, int cpus); - void init_packages(); - LoadClient* new_client(); - LoadPackage* new_package(); - TitleMain *plugin; -}; - - - - - - - -// Copy a single character to the text mask -class TitlePackage : public LoadPackage -{ -public: - TitlePackage(); - int x, y, c; -}; - - -class TitleUnit : public LoadClient -{ -public: - TitleUnit(TitleMain *plugin, TitleEngine *server); - void process_package(LoadPackage *package); - void draw_glyph(VFrame *output, TitleGlyph *glyph, int x, int y); - TitleMain *plugin; -}; - -class TitleEngine : public LoadServer -{ -public: - TitleEngine(TitleMain *plugin, int cpus); - void init_packages(); - LoadClient* new_client(); - LoadPackage* new_package(); - TitleMain *plugin; -}; - - - - - - - - - - -// Overlay text mask with fractional translation -// We don't use OverlayFrame to enable alpha blending on non alpha -// output. -class TitleTranslatePackage : public LoadPackage -{ -public: - TitleTranslatePackage(); - int y1, y2; -}; - - -class TitleTranslateUnit : public LoadClient -{ -public: - TitleTranslateUnit(TitleMain *plugin, TitleTranslate *server); - void process_package(LoadPackage *package); - TitleMain *plugin; -}; - -class TitleTranslate : public LoadServer -{ -public: - TitleTranslate(TitleMain *plugin, int cpus); - ~TitleTranslate(); - void init_packages(); - LoadClient* new_client(); - LoadPackage* new_package(); - TitleMain *plugin; - transfer_table_f *y_table; - transfer_table_f *x_table; - int output_w; - int output_h; -// Result of translation_array_f - int out_x1_int; - int out_x2_int; - int out_y1_int; - int out_y2_int; -// Values to process - int out_x1; - int out_x2; - int out_y1; - int out_y2; -}; - - - - - - - - - - - - - - -// Position of each character relative to total text extents -typedef struct -{ - int x, y, w; -} title_char_position_t; - - - -class TitleMain : public PluginVClient -{ -public: - TitleMain(PluginServer *server); - ~TitleMain(); - -// required for all realtime plugins - int process_realtime(VFrame *input_ptr, VFrame *output_ptr); - int is_realtime(); - int is_synthesis(); - char* plugin_title(); - int show_gui(); - void raise_window(); - void update_gui(); - int set_string(); - int load_configuration(); - void save_data(KeyFrame *keyframe); - void read_data(KeyFrame *keyframe); - int load_defaults(); - int save_defaults(); - - - - void build_fonts(); - void draw_glyphs(); - int draw_mask(); - void overlay_mask(); - FontEntry* get_font_entry(char *title, - int style, - int size); - FontEntry* get_font(); - int get_char_advance(int current, int next); - int get_char_height(); - void get_total_extents(); - void clear_glyphs(); - int load_freetype_face(FT_Library &freetype_library, - FT_Face &freetype_face, - char *path); - - - - - - static char* motion_to_text(int motion); - static int text_to_motion(char *text); -// a thread for the GUI - TitleThread *thread; -// Current configuration - TitleConfig config; -// Size of window - int window_w, window_h; - - static ArrayList *fonts; - - Defaults *defaults; - ArrayList glyphs; - Mutex glyph_lock; - -// Stage 1 parameters must be compared to redraw the text mask - VFrame *text_mask; - VFrame *text_mask_stroke; - GlyphEngine *glyph_engine; - TitleEngine *title_engine; - TitleTranslate *translate; - -// Necessary to get character width - FT_Library freetype_library; // Freetype library - FT_Face freetype_face; - -// Visible area of all text present in the mask. -// Horizontal characters aren't clipped because column positions are -// proportional. - int visible_row1; - int visible_row2; - int visible_char1; - int visible_char2; -// relative position of all text to output - float text_y1; - float text_y2; - float text_x1; - float text_x2; -// relative position of visible part of text to output - float mask_y1; - float mask_y2; - -// Fade value - int alpha; - -// Must be calculated from rendering characters - int ascent; -// Relative position of mask to output is text_x1, mask_y1 -// We can either round it to nearest ints to speed up replication while the text -// itself is offset fractionally -// or replicate with fractional offsetting. Since fraction offsetting usually -// happens during motion and motion would require floating point offsetting -// for every frame we replicate with fractional offsetting. - - - -// Text is always row aligned to mask boundaries. - int text_len; - int text_rows; - int text_w; - int text_h; -// Position of each character relative to total text extents - title_char_position_t *char_positions; -// Positions of the bottom pixels of the rows - int *rows_bottom; - VFrame *input, *output; - - int need_reconfigure; -}; - - -#endif diff --git a/cinelerra-5.1/plugins/titler/titler.C b/cinelerra-5.1/plugins/titler/titler.C new file mode 100644 index 00000000..bdde6b47 --- /dev/null +++ b/cinelerra-5.1/plugins/titler/titler.C @@ -0,0 +1,2636 @@ + +/* + * CINELERRA + * Copyright (C) 1997-2014 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +// Originally developed by Heroine Virtual Ltd. +// Support for multiple encodings, outline (stroke) by +// Andraz Tori +// Additional support for UTF-8 by +// Paolo Rampino aka Akirad + + +#include "asset.h" +#include "bccmodels.h" +#include "bcsignals.h" +#include "cache.h" +#include "clip.h" +#include "cstrdup.h" +#include "edl.h" +#include "edlsession.h" +#include "file.h" +#include "filexml.h" +#include "filesystem.h" +#include "indexable.h" +#include "ft2build.h" +#include FT_GLYPH_H +#include FT_BBOX_H +#include FT_OUTLINE_H +#include FT_STROKER_H +#include "language.h" +#include "mwindow.inc" +#include "overlayframe.h" +#include "renderengine.h" +#include "titler.h" +#include "titlerwindow.h" +#include "transportque.h" +#include "vrender.h" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SMALL (1.0 / 64.0) + +#define MAX_FLT 3.40282347e+38 +#define MIN_FLT -3.40282347e+38 + +REGISTER_PLUGIN(TitleMain) + +#ifdef X_HAVE_UTF8_STRING +#define DEFAULT_ENCODING "UTF-8" +#else +#define DEFAULT_ENCODING "ISO8859-1" +#endif +#define DEFAULT_TIMECODEFORMAT TIME_HMS + +TitleConfig::TitleConfig() +{ + style = 0; + color = BLACK; + alpha = 0xff; + outline_alpha = 0xff; + size = 24; + motion_strategy = NO_MOTION; + loop = 0; + line_pitch = 0; + hjustification = JUSTIFY_CENTER; + vjustification = JUSTIFY_MID; + fade_in = 0.0; + fade_out = 0.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_h = 460; + next_keyframe_position = 0; + prev_keyframe_position = 0; + drag = 0; + loop_playback = 0; +} + +TitleConfig::~TitleConfig() +{ +} + +int TitleConfig::equivalent(TitleConfig &that) +{ + return !strcasecmp(font, that.font) && + 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_alpha == that.outline_alpha && + EQUIV(pixels_per_second, that.pixels_per_second) && + motion_strategy == that.motion_strategy && + loop == that.loop && + line_pitch == that.line_pitch && + 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 && + timecode == that.timecode && + 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)); +} + +void TitleConfig::copy_from(TitleConfig &that) +{ + strcpy(font, that.font); + 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_alpha = that.outline_alpha; + pixels_per_second = that.pixels_per_second; + motion_strategy = that.motion_strategy; + loop = that.loop; + line_pitch = that.line_pitch; + 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; + timecode = that.timecode; + 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; +} + +void TitleConfig::interpolate(TitleConfig &prev, TitleConfig &next, + int64_t prev_frame, int64_t next_frame, int64_t current_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_alpha = prev.outline_alpha; + motion_strategy = prev.motion_strategy; + loop = prev.loop; + line_pitch = prev.line_pitch; + 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; + 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; + timecode = prev.timecode; + timecode_format = prev.timecode_format; + this->dropshadow = prev.dropshadow * prev_scale + next.dropshadow * next_scale; +// this->dropshadow = prev.dropshadow; +} + +void TitleConfig::to_wtext(const char *from_enc, const char *text, int tlen) +{ + wlen = BC_Resources::encode(from_enc, BC_Resources::wide_encoding, + (char*)text,tlen, (char *)wtext,sizeof(wtext)) / sizeof(wchar_t); + while( wlen > 0 && !wtext[wlen-1] ) --wlen; +} + + +TitleGlyph::TitleGlyph() +{ + char_code = 0; + size = 0; + data = 0; + data_stroke = 0; + freetype_index = 0; + width = 0; + height = 0; + style = 0; + pitch = 0; + left = 0; + top = 0; + bottom = 0; + right = 0; + advance_x = 0; +} + + +TitleGlyph::~TitleGlyph() +{ +//printf("TitleGlyph::~TitleGlyph 1\n"); + if( data ) delete data; + if( data_stroke ) delete data_stroke; +} + + +GlyphPackage::GlyphPackage() : LoadPackage() +{ + glyph = 0; +} + +GlyphUnit::GlyphUnit(TitleMain *plugin, GlyphEngine *server) + : LoadClient(server) +{ + this->plugin = plugin; + freetype_library = 0; + freetype_face = 0; +} + +GlyphUnit::~GlyphUnit() +{ + if( freetype_library ) + FT_Done_FreeType(freetype_library); +} + +void GlyphUnit::process_package(LoadPackage *package) +{ + GlyphPackage *pkg = (GlyphPackage*)package; + TitleGlyph *glyph = pkg->glyph; + int result = 0; + char new_path[BCTEXTLEN]; + if( plugin->load_freetype_face(freetype_library, freetype_face, glyph->font->path) ) { + printf(_("GlyphUnit::process_package FT_New_Face failed, path=%s\n"), + 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 == 0 ) { + BC_Resources *resources = BC_WindowBase::get_resources(); + // 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); + } + } + FT_Set_Pixel_Sizes(freetype_face, glyph->size, 0); + + if( gindex == 0 ) { +// carrige return + if( glyph->char_code != 10 ) + printf(_("GlyphUnit::process_package FT_Load_Char failed - char: %li.\n"), + glyph->char_code); +// Prevent a crash here + glyph->width = 8; glyph->height = 8; + glyph->pitch = 8; glyph->advance_x = 8; + glyph->left = 9; glyph->top = 9; + glyph->right = 0; glyph->bottom = 0; + glyph->freetype_index = 0; + glyph->data = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); + glyph->data->clear_frame(); + glyph->data_stroke = 0; + +// create outline glyph + if( plugin->config.stroke_width >= SMALL && + (plugin->config.style & BC_FONT_OUTLINE) ) { + glyph->data_stroke = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); + glyph->data_stroke->clear_frame(); + } + } +// char found and no outline desired + else if( plugin->config.stroke_width < SMALL || + !(plugin->config.style & BC_FONT_OUTLINE) ) { + 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); +// printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n", +// bbox.xMin,bbox.xMax, bbox.yMin, bbox.yMax); + + glyph->width = bm.width = ((bbox.xMax - bbox.xMin + 63) >> 6); + glyph->height = bm.rows = ((bbox.yMax - bbox.yMin + 63) >> 6); + glyph->pitch = bm.pitch = bm.width; + bm.pixel_mode = FT_PIXEL_MODE_GRAY; + bm.num_grays = 256; + glyph->left = (bbox.xMin + 31) >> 6; + glyph->top = (bbox.yMax + 31) >> 6; + glyph->right = (bbox.xMax + 31) >> 6; + glyph->bottom = (bbox.yMin + 31) >> 6; + glyph->freetype_index = gindex; + glyph->advance_x = ((freetype_face->glyph->advance.x + 31) >> 6); +//printf("GlyphUnit::process_package 1 width=%d height=%d pitch=%d left=%d top=%d advance_x=%d freetype_index=%d\n", +//glyph->width, glyph->height, glyph->pitch, glyph->left, glyph->top, glyph->advance_x, glyph->freetype_index); + + 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, + - bbox.xMin, - bbox.yMin); + FT_Outline_Get_Bitmap( freetype_library, + &((FT_OutlineGlyph) glyph_image)->outline, + &bm); + FT_Done_Glyph(glyph_image); + } + else { +// Outline desired and glyph found + FT_Glyph glyph_image; + FT_Stroker stroker; + FT_Outline outline; + FT_Bitmap bm; + FT_BBox bbox; + FT_UInt npoints, ncontours; + + 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); + if( bbox.xMin == 0 && bbox.xMax == 0 && + bbox.yMin == 0 && bbox.yMax == 0 ) { + FT_Done_Glyph(glyph_image); + glyph->width = 0; glyph->height = 0; + glyph->left = 0; glyph->top = 0; + glyph->right = 0; glyph->bottom = 0; + glyph->pitch = 0; + glyph->data = + new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); + glyph->data_stroke = + new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); + glyph->advance_x =((int)(freetype_face->glyph->advance.x + + plugin->config.stroke_width * 64)) >> 6; + return; + } +#if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 2) + FT_Stroker_New(freetype_library, &stroker); +#else + FT_Stroker_New(((FT_LibraryRec *)freetype_library)->memory, &stroker); +#endif + 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); + 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); + glyph->width = 0; glyph->height = 0; + glyph->left = 0; glyph->top = 0; + glyph->right = 0; glyph->bottom = 0; + glyph->pitch = 0; + glyph->data = + new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); + glyph->data_stroke = + new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); + glyph->advance_x =((int)(freetype_face->glyph->advance.x + + plugin->config.stroke_width * 64)) >> 6; + return; + }; + + 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, + - bbox.xMin, + - bbox.yMin + (int)(plugin->config.stroke_width*32)); +// printf("Stroke: Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n" +// "Fill Xmin: %ld, Xmax: %ld, Ymin: %ld, yMax: %ld\n", +// bbox.xMin,bbox.xMax, bbox.yMin, bbox.yMax, +// bbox_fill.xMin,bbox_fill.xMax, bbox_fill.yMin, bbox_fill.yMax); + + glyph->width = bm.width = ((bbox.xMax - bbox.xMin) >> 6)+1; + glyph->height = bm.rows = ((bbox.yMax - bbox.yMin) >> 6) +1; + glyph->pitch = bm.pitch = bm.width; + bm.pixel_mode = FT_PIXEL_MODE_GRAY; + bm.num_grays = 256; + glyph->left = (bbox.xMin + 31) >> 6; + glyph->top = (bbox.yMax + 31) >> 6; + glyph->right = (bbox.xMax + 31) >> 6; + glyph->bottom = (bbox.yMin + 31) >> 6; + glyph->freetype_index = gindex; + int real_advance = ((int)ceil((float)freetype_face->glyph->advance.x + + plugin->config.stroke_width * 64) >> 6); + glyph->advance_x = glyph->width + glyph->left; + if( real_advance > glyph->advance_x ) + glyph->advance_x = real_advance; +//printf("GlyphUnit::process_package 1 width=%d height=%d " +// "pitch=%d left=%d top=%d advance_x=%d freetype_index=%d\n", +// glyph->width, glyph->height, glyph->pitch, glyph->left, +// glyph->top, glyph->advance_x, glyph->freetype_index); + + +//printf("GlyphUnit::process_package 1\n"); + glyph->data = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); + glyph->data->clear_frame(); + glyph->data_stroke = new VFrame(glyph->width, glyph->height, BC_A8, glyph->pitch); + 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_OutlineGlyph) glyph_image)->outline, + &bm); + bm.buffer=glyph->data_stroke->get_data(); + FT_Outline_Get_Bitmap( freetype_library, + &outline, + &bm); + FT_Outline_Done(freetype_library,&outline); + FT_Stroker_Done(stroker); + FT_Done_Glyph(glyph_image); + +//printf("GlyphUnit::process_package 2\n"); + } + } +} + + +GlyphEngine::GlyphEngine(TitleMain *plugin, int cpus) + : LoadServer(cpus, cpus) +{ + this->plugin = plugin; +} + +void GlyphEngine::init_packages() +{ + int current_package = 0; + for( int i=0; ititle_glyphs.count(); ++i ) { + if( !plugin->title_glyphs[i]->data ) { + GlyphPackage *pkg = (GlyphPackage*)get_package(current_package++); + pkg->glyph = plugin->title_glyphs[i]; + } + } +} + +LoadClient* GlyphEngine::new_client() +{ + return new GlyphUnit(plugin, this); +} + +LoadPackage* GlyphEngine::new_package() +{ + return new GlyphPackage; +} + + +// Copy a single character to the text mask +TitlePackage::TitlePackage() + : LoadPackage() +{ + x = y = 0; + chr = 0; +} + + +TitleUnit::TitleUnit(TitleMain *plugin, TitleEngine *server) + : LoadClient(server) +{ + this->plugin = plugin; + this->engine = server; + this->chr = 0; +} + +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); + } + rr = r; gg = g; bb = b; +} + +void TitleUnit::draw_frame(int mode, VFrame *dst, VFrame *src, int x, int y) +{ + int inp_w = src->get_w(), inp_h = src->get_h(); + int out_w = dst->get_w(), out_h = dst->get_h(); + unsigned char **inp_rows = src->get_rows(); + unsigned char **out_rows = dst->get_rows(); + + int x_inp = 0, y_inp = 0; + int x_out = x; + if( x_out < 0 ) { x_inp = -x_out; x_out = 0; } + if( x_out+inp_w > out_w ) inp_w = out_w-x_out; + if( x_inp >= inp_w || x_out >= out_w ) return; + int y_out = y; + if( y_out < 0 ) { y_inp = -y_out; y_out = 0; } + if( y_out+inp_h > out_h ) inp_h = out_h-y_out; + if( y_inp >= inp_h || y_out >= out_h ) return; + int color = chr->color, max = 0xff; + int alpha = chr->alpha * chr->fade; + int ofs = BC_CModels::is_yuv(dst->get_color_model()) ? 0x80 : 0x00; + + switch( mode ) { + case DRAW_ALPHA: { + 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; xintext_model, r, g, 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+0; xinx, y = pkg->y; + chr = pkg->chr; + switch( chr->typ ) { + case CHAR_IMAGE: { + VFrame *vframe = (VFrame *)chr->vp; + if( !vframe ) return; + draw_frame(DRAW_IMAGE, plugin->text_mask, vframe, x, y); + break; } + case CHAR_GLYPH: { + if( chr->wch == 0 || chr->wch == '\n') return; + TitleGlyph *glyph = (TitleGlyph *)chr->vp; + if( !glyph ) return; + if( engine->do_dropshadow ) { + x += plugin->config.dropshadow; + y += plugin->config.dropshadow; + } + else if( plugin->config.dropshadow < 0 ) { + x -= plugin->config.dropshadow; + y -= plugin->config.dropshadow; + } + int mode = engine->do_dropshadow ? DRAW_ALPHA : DRAW_COLOR; + draw_frame(mode, plugin->text_mask, glyph->data, x, y); + if( plugin->config.stroke_width >= SMALL && (plugin->config.style & BC_FONT_OUTLINE) ) + draw_frame(mode, plugin->stroke_mask, glyph->data_stroke, x, y); + break; } + } +} + +TitleEngine::TitleEngine(TitleMain *plugin, int cpus) + : LoadServer(cpus, cpus) +{ + this->plugin = plugin; +} + +void TitleEngine::init_packages() +{ + int current_package = 0; + for( int i=plugin->visible_char1; ivisible_char2; ++i ) { + TitlePackage *pkg = (TitlePackage*)get_package(current_package++); + TitleChar *chr = plugin->title_chars[i]; + TitleRow *row = plugin->title_rows[chr->row]; + pkg->chr = chr; + pkg->x = row->x0 + chr->x - plugin->mask_x1; + pkg->y = row->y0 - chr->y - plugin->mask_y1; +//printf("draw '%c' at %d,%d\n",(int)pkg->chr->wch, pkg->x, pkg->y); + } +} + +LoadClient* TitleEngine::new_client() +{ + return new TitleUnit(plugin, this); +} + +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() + : LoadPackage() +{ +} + + +TitleOutlineUnit::TitleOutlineUnit(TitleMain *plugin, TitleOutlineEngine *server) + : LoadClient(server) +{ + this->plugin = plugin; + this->engine = server; +} + +void TitleOutlineUnit::process_package(LoadPackage *package) +{ + TitleOutlinePackage *pkg = (TitleOutlinePackage*)package; + int r = 0, g = 0, b = 0, outline_a = plugin->config.outline_alpha; + get_mask_colors(plugin->config.outline_color, plugin->mask_model, r, g, b); + + unsigned char **outline_rows = plugin->outline_mask->get_rows(); + 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; + + if( engine->pass == 0 ) { +// get max alpha under outline size macropixel + for( int y=pkg->y1, my=pkg->y2; ytext_mask->get_w(); x max_a ) max_a = pixel[3]; + } + } + unsigned char *out = out_row + x*4; + out[0] = r; out[1] = g; out[2] = b; + out[3] = (max_a * outline_a) / 0xff; + } + } + return; + } + else { +// Overlay text mask on top of outline mask + int ofs = BC_CModels::is_yuv(plugin->output->get_color_model()) ? 0x80 : 0; + for( int y=pkg->y1, my=pkg->y2; ytext_mask->get_w(); xplugin = plugin; +} + +void TitleOutlineEngine::init_packages() +{ + int mask_h = plugin->text_mask->get_h(); + if( !mask_h ) return; + int py1 = 0, py2 = 0; + int pkgs = get_total_packages(); + for( int i=0; iy1 = py1; pkg->y2 = py2; + } +} + +void TitleOutlineEngine::do_outline() +{ + pass = 0; process_packages(); + pass = 1; process_packages(); +} + +LoadClient* TitleOutlineEngine::new_client() +{ + return new TitleOutlineUnit(plugin, this); +} + +LoadPackage* TitleOutlineEngine::new_package() +{ + return new TitleOutlinePackage; +} + + + +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; 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) +{ +} +TitleCurColor::TitleCurColor(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, plugin->config.color) +{ +} +TitleCurAlpha::TitleCurAlpha(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, plugin->config.alpha) +{ +} +TitleCurSize::TitleCurSize(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, plugin->config.size) +{ +} +TitleCurBold::TitleCurBold(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, (plugin->config.style & BC_FONT_BOLD) ? 1 : 0) +{ +} +TitleCurItalic::TitleCurItalic(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, (plugin->config.style & BC_FONT_ITALIC) ? 1 : 0) +{ +} +TitleCurFont::TitleCurFont(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, plugin->config_font()) +{ +} +TitleCurCaps::TitleCurCaps(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, 0) +{ +} +TitleCurUnder::TitleCurUnder(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, 0) +{ +} +TitleCurBlink::TitleCurBlink(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, 0) +{ +} +TitleCurFixed::TitleCurFixed(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, 0) +{ +} +TitleCurSuper::TitleCurSuper(TitleParser *parser, TitleMain *plugin) + : TitleStack(parser, 0) +{ +} + +TitleParser::TitleParser(TitleMain *plugin) + : plugin(plugin), + cur_nudge(this, plugin), + cur_color(this, plugin), + cur_alpha(this, plugin), + cur_size(this, plugin), + cur_bold(this, plugin), + cur_italic(this, plugin), + cur_font(this, plugin), + cur_caps(this, plugin), + cur_under(this, plugin), + cur_blink(this, plugin), + cur_fixed(this, plugin), + cur_super(this, plugin) +{ + bfr = out = plugin->config.wtext; + lmt = bfr + plugin->config.wlen; +} + +TitleMain::TitleMain(PluginServer *server) + : PluginVClient(server) +{ + text_mask = 0; + stroke_mask = 0; + outline_mask = 0; + glyph_engine = 0; + title_engine = 0; + translate = 0; + outline_engine = 0; + freetype_library = 0; + freetype_face = 0; + text_font[0] = 0; + window_w = window_h = 0; + title_x = title_y = 0; + title_w = title_h = 0; + text_w = text_h = 0; + text_x = text_y = 0; mask_w = mask_h = 0; + mask_x1 = mask_y1 = mask_x2 = mask_y2 = 0; + text_rows = 0; + visible_row1 = visible_char1 = 0; + visible_row2 = visible_char2 = 0; + fade = 1; + input = 0; output = 0; + output_model = BC_RGBA8888; + mask_model = BC_RGBA8888; + background = 0; bg_file = 0; bg_frame = 0; + render_engine = 0; video_cache = 0; + overlay_frame = 0; + cpus = PluginClient::smp + 1; + if( cpus > 8 ) cpus = 8; + last_position = -1; + need_reconfigure = 1; +} + +TitleMain::~TitleMain() +{ + if( background ) { + background->Garbage::remove_user(); + background = 0; + } + delete render_engine; + delete video_cache; + delete overlay_frame; + delete bg_file; + delete bg_frame; + delete text_mask; + delete outline_mask; + delete stroke_mask; + delete glyph_engine; + delete title_engine; + if( freetype_face ) + FT_Done_Face(freetype_face); + if( freetype_library ) + FT_Done_FreeType(freetype_library); + delete translate; + delete outline_engine; +} + +const char* TitleMain::plugin_title() { return _("Title"); } +int TitleMain::is_realtime() { return 1; } +int TitleMain::is_synthesis() { return 1; } + +NEW_WINDOW_MACRO(TitleMain, TitleWindow); + + +void TitleMain::build_previews(TitleWindow *gui) +{ + ArrayList&fonts = *gui->get_resources()->fontlist; + + for( int font_number=0; font_numberimage ) return; + } + +// create example bitmaps + FT_Library freetype_library = 0; // Freetype library + FT_Face freetype_face = 0; + const char *test_string = "Aa"; + char new_path[BCTEXTLEN]; + int text_height = gui->get_text_height(LARGEFONT); + int text_color = BC_WindowBase::get_resources()->default_text_color; + int r = (text_color >> 16) & 0xff; + int g = (text_color >> 8) & 0xff; + int b = text_color & 0xff; +// dimensions for each line + int height[fonts.size()]; + int ascent[fonts.size()]; + +// pass 1 gets the extents for all the fonts +// pass 2 draws the image + int total_w = 0; + int total_h = 0; + for( int pass=0; pass<2; ++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; + } + skip = 1; + break; + } + } + + if( skip ) continue; + + int current_x = 0, current_w = 0, current_h = 0, current_ascent = 0; + if( pass == 1 ) { + font->image = new VFrame; + font->image->set_use_shm(0); + font->image->reallocate(0, -1, 0, 0, 0, + total_w, total_h, BC_RGBA8888, -1); + font->image->clear_frame(); + } + + int len = strlen(test_string); + for( int j=0; jpath, +// c, +// (char *)new_path); + strcpy(new_path, font->path); + 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; + 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; + } + 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; + unsigned char *in_row = freetype_face->glyph->bitmap.buffer + + freetype_face->glyph->bitmap.pitch * in_y; + + for( int out_x = 0; + out_x < (int)freetype_face->glyph->bitmap.width && out_x < total_w; + ++out_x ) { + *out_row = (*in_row * r + + (0xff - *in_row) * *out_row) / 0xff; ++out_row; + *out_row = (*in_row * g + + (0xff - *in_row) * *out_row) / 0xff; ++out_row; + *out_row = (*in_row * b + + (0xff - *in_row) * *out_row) / 0xff; ++out_row; + *out_row = MAX(*in_row, *out_row); ++out_row; + in_row++; + } + } + current_x += freetype_face->glyph->advance.x >> 6; + } + } + + 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); +} + + +//This checks if char_code is on the selected font, else it changes font to the first compatible //Akirad +int TitleMain::check_char_code_path(FT_Library &freetype_library, + char *path_old, FT_ULong &char_code, char *path_new) +{ + FT_Face temp_freetype_face; + FcPattern *pat; + FcFontSet *fs; + FcObjectSet *os; + FcChar8 *file, *format; + FcConfig *config; + FcPattern *font; + + FcInit(); + config = FcConfigGetCurrent(); + FcConfigSetRescanInterval(config, 0); + + 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( gindex != 0 && char_code == 10 ) { + strcpy(path_new, path_old); + found = 1; + } + } + + if( !found ) { + for( int i=0; fs && infont; ++i ) { + font = fs->fonts[i]; + FcPatternGetString(font, FC_FONTFORMAT, 0, &format); + if( strcmp((char *)format, "TrueType") && !limit_to_truetype ) 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( gindex != 0 && char_code == 10 ) { + sprintf(path_new, "%s", tmpstring); + found = 1; + goto done; + } + } + } + +done: + if( fs ) FcFontSetDestroy(fs); + if( temp_freetype_face ) FT_Done_Face(temp_freetype_face); + temp_freetype_face = 0; + + if( !found ) { + strcpy(path_new, path_old); + return 1; + } + + return 0; +} + + +int TitleMain::load_freetype_face(FT_Library &freetype_library, + FT_Face &freetype_face, const char *path) +{ +//printf("TitleMain::load_freetype_face 1\n"); + if( !freetype_library ) + FT_Init_FreeType(&freetype_library); + if( 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) ) { + fprintf(stderr, _("TitleMain::load_freetype_face %s failed.\n"), path); + freetype_face = 0; + freetype_library = 0; + return 1; + } + return 0; +} + +int TitleMain::load_font(BC_FontEntry *font) +{ + if( load_freetype_face(freetype_library,freetype_face, font->path) ) return 1; + strcpy(text_font, font->displayname); + return 0; +} + + +Indexable *TitleMain::open_background(const char *filename) +{ + delete render_engine; render_engine = 0; + delete video_cache; video_cache = 0; + delete bg_file; bg_file = new File; + + Asset *asset = new Asset(filename); + int result = bg_file->open_file(server->preferences, asset, 1, 0); + if( result == FILE_OK ) return (Indexable *)asset; +// not asset + asset->Garbage::remove_user(); + delete bg_file; bg_file = 0; + if( result != FILE_IS_XML ) return 0; +// nested edl + FileXML xml_file; + if( xml_file.read_from_file(filename) ) return 0; + EDL *nested_edl = new EDL; + nested_edl->create_objects(); + nested_edl->set_path(filename); + nested_edl->load_xml(&xml_file, LOAD_ALL); + TransportCommand command; + //command.command = audio_tracks ? NORMAL_FWD : CURRENT_FRAME; + command.command = CURRENT_FRAME; + command.get_edl()->copy_all(nested_edl); + command.change_type = CHANGE_ALL; + command.realtime = 0; + render_engine = new RenderEngine(0, server->preferences, 0, 0); + render_engine->set_vcache(video_cache = new CICache(server->preferences)); + render_engine->arm_command(&command); + return (Indexable *)nested_edl; +} + +int TitleMain::read_background(VFrame *frame, int64_t position, int color_model) +{ + int result = 1; + VFrame *iframe = frame; + int bw = background->get_w(), bh = background->get_h(); + if( background->is_asset ) { + Asset *asset = (Asset *)background; + if( bw != asset->width || bh != asset->height ) + iframe = new_temp(asset->width, asset->height, color_model); + int64_t source_position = (int64_t)(position * + asset->frame_rate / project_frame_rate); + if( config.loop_playback ) { + int64_t loop_size = asset->get_video_frames(); + source_position -= (int64_t)(source_position / loop_size) * loop_size; + } + if( bg_file ) { + bg_file->set_video_position(source_position, 0); + result = bg_file->read_frame(iframe); + } + } + else { + EDL *nested_edl = (EDL *)background; + if( color_model != nested_edl->session->color_model || + bw != nested_edl->session->output_w || + bh != nested_edl->session->output_h ) + iframe = new_temp( + nested_edl->session->output_w, + nested_edl->session->output_h, + nested_edl->session->color_model); + int64_t source_position = (int64_t)(position * + nested_edl->session->frame_rate / project_frame_rate); + if( config.loop_playback ) { + int64_t loop_size = nested_edl->get_video_frames(); + source_position -= (int64_t)(source_position / loop_size) * loop_size; + } + if( render_engine->vrender ) + result = render_engine->vrender->process_buffer(iframe, source_position, 0); + } + if( !result && iframe != frame ) + frame->transfer_from(iframe); + return result; +} + +void TitleMain::draw_background() +{ + if( background ) { + if( strcmp(background->path, config.background_path) ) { + if( background ) { + background->Garbage::remove_user(); + background = 0; + } + if( bg_file ) { + delete bg_file; + bg_file = 0; + } + } + } + if( !background && config.background_path[0] && !access(config.background_path,R_OK) ) + background = open_background(config.background_path); + if( background ) { + int bw = background->get_w(), bh = background->get_h(); + if( bg_frame && (bg_frame->get_w() != bw || bg_frame->get_h() != bh || + bg_frame->get_color_model() != output_model) ) { + delete bg_frame; bg_frame = 0; + } + if( !bg_frame ) + bg_frame = new VFrame(0, -1, bw, bh, output_model, -1); + int64_t position = get_source_position() - get_source_start(); + if( !read_background(bg_frame, position, output_model) ) { + if( !overlay_frame ) + overlay_frame = new OverlayFrame(cpus); + float in_x1 = 0, in_x2 = bg_frame->get_w(); + float in_y1 = 0, in_y2 = bg_frame->get_h(); + float out_x1 = config.title_x, out_x2 = out_x1 + title_w; + float out_y1 = config.title_y, out_y2 = out_y1 + title_h; + overlay_frame->overlay(output, bg_frame, + in_x1,in_y1, in_x2,in_y2, + out_x1,out_y1, out_x2,out_y2, + 1, TRANSFER_NORMAL, CUBIC_LINEAR); + } + } +} + +BC_FontEntry* TitleMain::get_font(const char *font_name, int style) +{ + int flavor = + ((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; + + BC_Resources *resources = BC_WindowBase::get_resources(); + return resources->find_fontentry(font_name, flavor, mask, style); +} +BC_FontEntry* TitleMain::config_font() +{ + BC_FontEntry *font = get_font(config.font, config.style); + if( font && load_font(font) ) 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_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; + while( (ich=wnext()) >= 0 ) { + if( ich == '\\' ) { + if( (ich=wnext()) == '\n' ) continue; + wch = ich; + return 0; + } + if( ich == '<' ) break; + if( ich != '#' ) { wch = ich; return 0; } + while( (ich=wnext()) >= 0 && ich != '\n' ); + if( ich < 0 ) break; + } + if( ich < 0 ) return -1; + int ret = 1; long pos = tell(); + if( (ich=wnext()) == '/' ) { ret = 2; ich = wnext(); } + if( is_ltr(ich) ) { + *ip++ = ich; + while( is_idch(ich=wnext()) ) + if( --ilen > 0 ) *ip++ = ich; + } + *ip = 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; + ich = wnext(); + } + *tp = 0; + if( ich < 0 ) { ich = '<'; seek(pos); ret = 0; } + wch = ich; + return ret; +} + +TitleGlyph *TitleMain::get_glyph(FT_ULong char_code, BC_FontEntry *font, int size, int style) +{ + for( int i=0, n=title_glyphs.count(); ichar_code == char_code && glyph->font == font && + glyph->size == size && glyph->style == style ) + return glyph; + } + return 0; +} + +int TitleMain::get_width(TitleGlyph *cur, TitleGlyph *nxt) +{ + if( !cur || cur->char_code == '\n' ) return 0; + 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); +} + + +VFrame *TitleMain::get_image(const char *path) +{ + for( int i=0; ipath) ) + return title_images[i]->vframe; + } + return 0; +} + +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); + frame->transfer_from(vframe); delete vframe; + vframe = frame; + } + title_images.append(new TitleImage(path, vframe)); + } + return vframe; +} + +int TitleCurColor::set(const char *txt) +{ +#define BCOLOR(NM) { #NM, NM } + static const struct { const char *name; int color; } colors[] = { + BCOLOR(MNBLUE), BCOLOR(ORANGE), BCOLOR(BLOND), + BCOLOR(MNGREY), BCOLOR(FGGREY), BCOLOR(FTGREY), BCOLOR(DKGREY), + BCOLOR(LTGREY), BCOLOR(MEGREY), BCOLOR(DMGREY), BCOLOR(MDGREY), + BCOLOR(LTPURPLE),BCOLOR(MEPURPLE),BCOLOR(MDPURPLE), BCOLOR(DKPURPLE), + BCOLOR(LTCYAN), BCOLOR(MECYAN), BCOLOR(MDCYAN), BCOLOR(DKCYAN), + BCOLOR(YELLOW), BCOLOR(LTYELLOW),BCOLOR(MEYELLOW), BCOLOR(MDYELLOW), + BCOLOR(LTGREEN), BCOLOR(DKGREEN), BCOLOR(DKYELLOW), BCOLOR(LTPINK), + BCOLOR(PINK), BCOLOR(LTBLUE), BCOLOR(DKBLUE), + BCOLOR(RED), BCOLOR(GREEN), BCOLOR(BLUE), + BCOLOR(BLACK), BCOLOR(WHITE), + }; + int color; + if( *txt ) { + if( txt[0] == '#' ) { + if( sscanf(&txt[1], "%x", &color) != 1 ) return 1; + } + else { + int i = sizeof(colors)/sizeof(colors[0]); + while( --i >= 0 && strcasecmp(txt, colors[i].name) ); + if( i < 0 ) return 1; + color = colors[i].color; + } + } + else + color = parser->plugin->config.color; + push(color); + return 0; +} + +int TitleCurAlpha::set(const char *txt) +{ + float a = !*txt ? + parser->plugin->config.alpha : + strtof(txt,(char**)&txt) * 255; + int alpha = a; + if( *txt || alpha < 0 || alpha > 255 ) return 1; + push(alpha); + return 0; +} + +int TitleCurSize::set(const char *txt) +{ + float size = 0; + if( !*txt ) { + size = parser->plugin->config.size; + } + else if( *txt == '+' || *txt == '-' ) { + size = *this; + for( int ch; (ch=*txt)!=0; ++txt ) { + if( ch == '+' ) { size *= 5./4.; continue; } + if( ch == '-' ) { size *= 4./5.; continue; } + return 1; + } + } + else { + size = strtof(txt,(char**)&txt); + } + if( *txt || size <= 0 || size > 2048 ) return 1; + int style = parser->cur_font.style(); + if( parser->cur_font.set(0,style) ) return 1; + push(size); + return 0; +} +int TitleCurSize::unset(const char *txt) +{ + if( pop() ) return 1; + int style = parser->cur_font.style(); + parser->cur_font.set(0,style); + return 0; +} + + +int TitleCurBold::set(const char *txt) +{ + int bold = !*txt ? 1 : + strtol(txt,(char**)&txt,0); + if( *txt || bold < 0 || bold > 1 ) return 1; + int style = parser->cur_font.style(); + if( bold ) style |= BC_FONT_BOLD; + else style &= ~BC_FONT_BOLD; + if( parser->cur_font.set(0,style) ) return 1; + push(bold); + return 0; +} +int TitleCurBold::unset(const char *txt) +{ + if( pop() ) return 1; + int style = parser->cur_font.style(); + parser->cur_font.set(0,style); + return 0; +} + +int TitleCurItalic::set(const char *txt) +{ + int italic = !*txt ? 1 : + strtol(txt,(char**)&txt,0); + if( *txt || italic < 0 || italic > 1 ) return 1; + int style = parser->cur_font.style(); + if( italic ) style |= BC_FONT_ITALIC; + else style &= ~BC_FONT_ITALIC; + if( parser->cur_font.set(0,style) ) return 1; + push(italic); + return 0; +} +int TitleCurItalic::unset(const char *txt) +{ + if( pop() ) return 1; + int style = parser->cur_font.style(); + parser->cur_font.set(0,style); + return 0; +} + + +int TitleCurFont::style() +{ + int style = 0; + if( parser->cur_bold ) style |= BC_FONT_BOLD; + if( parser->cur_italic ) style |= BC_FONT_ITALIC; + return style; +} +BC_FontEntry* TitleCurFont::get(const char *txt, int style) +{ + if( !txt ) txt = parser->plugin->text_font; + else if( !*txt ) txt = parser->plugin->config.font; + return parser->plugin->get_font(txt, style); +} +int TitleCurFont::set(const char *txt, int style) +{ + BC_FontEntry *font = get(txt, style); + if( !font || parser->plugin->load_font(font) ) return 1; + if( !txt ) (BC_FontEntry*&)*this = font; + return 0; +} +int TitleCurFont::set(const char *txt) +{ + BC_FontEntry *font = get(txt, style()); + if( !font ) return 1; + push(font); + return 0; +} +int TitleCurFont::unset(const char *txt) +{ + if( *txt || pop() ) return 1; + BC_FontEntry *font = *this; + if( !font ) return 1; + font = get(font->displayname, style()); + if( !font ) return 1; + (BC_FontEntry*&)*this = font; + return 0; +} + +int TitleCurCaps::set(const char *txt) +{ + int caps = !*txt ? 1 : strtol(txt,(char **)&txt,0); + if( *txt || caps < -1 || caps > 1 ) return 1; + push(caps); + return 0; +} + +int TitleCurBlink::set(const char *txt) +{ + float blink = !*txt ? 1 : strtof(txt,(char **)&txt); + if( *txt ) return 1; + push(blink); + return 0; +} + +int TitleCurFixed::set(const char *txt) +{ + int fixed = !*txt ? + parser->cur_size*3/4 : + strtol(txt,(char **)&txt,0); + if( *txt || fixed < 0 ) return 1; + push(fixed); + return 0; +} + +int TitleCurSuper::set(const char *txt) +{ + int super = !*txt ? 1 : strtol(txt,(char **)&txt,0); + if( *txt || super < -1 || super > 1 ) return 1; + push(super); + return 0; +} + +int TitleCurNudge::set(const char *txt) +{ + if( !*txt ) return 1; + short nx = strtol(txt,(char **)&txt,0); + if( *txt++ != ',' ) return 1; + short ny = strtol(txt,(char **)&txt,0); + if( *txt ) return 1; + int nudge = (nx << 16) | (ny & 0xffff); + push(nudge); + return 0; +} + +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); + return 1; +} + +void TitleMain::load_glyphs() +{ +// Build table of all glyphs needed + TitleParser wchrs(this); + int total_packages = 0; + + while( !wchrs.eof() ) { + wchar_t wch1 = wchrs.wcur(), wch; + long ipos = wchrs.tell(); + int ret = wchrs.wget(wch); + if( ret > 0 ) { + if( !wchrs.set_attributes(ret) ) continue; + if( !strcmp(wchrs.id,"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( !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); + } + } + } + + if( !glyph_engine ) + glyph_engine = new GlyphEngine(this, cpus); + + glyph_engine->set_package_count(total_packages); + glyph_engine->process_packages(); +} + + +TitleImage::TitleImage(const char *path, VFrame *vfrm) +{ + this->path = cstrdup(path); + this->vframe = vfrm; +} +TitleImage::~TitleImage() +{ + delete [] path; + delete vframe; +} + +TitleChar *TitleChar::init(int typ, void *vp) +{ + wch = 0; + flags = 0; + this->typ = typ; + this->vp = vp; + x = y = 0; + row = dx = 0; + blink = 0.; + size = 0.; + color = BLACK; + alpha = 0xff; + fade = 1; + return this; +} + +TitleRow *TitleRow::init() +{ + x0 = y0 = 0; + x1 = y2 = 0; //MAX_FLT; + y1 = x2 = 0; //MIN_FLT; + return this; +} + +int TitleMain::get_text() +{ +// Determine extents of total text + title_chars.reset(); + title_rows.reset(); + int pitch = config.line_pitch; + float font_h = config.size; + int descent = 0; + + TitleParser wchrs(this); + + TitleRow *row = 0; + float row_w = 0, row_h = 0; + float row_x = 0, row_y = 0; + text_rows = 0; + + for(;;) { + if( !row ) row = title_rows.add(); + TitleChar *chr = 0; + long ipos = wchrs.tell(); + wchar_t wch1 = wchrs.wcur(), wch; + int ret = wchrs.wget(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; + int dy = row->y1 - descent; + row_y += pitch ? pitch : dy > font_h ? dy : font_h; + row->y0 = row_y; + descent = row->y2; + if( row_x > row_w ) row_w = row_x; + if( row_y > row_h ) row_h = row_y; + text_rows = title_rows.count(); + row_x = 0; row = 0; + if( ret < 0 ) break; + continue; + } + BC_FontEntry *cur_font = wchrs.cur_font; + int cur_color = wchrs.cur_color; + int cur_alpha = wchrs.cur_alpha; + float cur_size = wchrs.cur_size; + int cur_caps = wchrs.cur_caps; + int cur_under = wchrs.cur_under; + float cur_blink = wchrs.cur_blink; + int cur_fixed = wchrs.cur_fixed; + int cur_super = wchrs.cur_super; + int cur_nudge = wchrs.cur_nudge; + 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; + short nx = cur_nudge >> 16, ny = cur_nudge; + int cx = nx, cy = ny, cw = 0, ch = 0, dx = 0; + if( ret > 0 ) { + if( !wchrs.set_attributes(ret) ) continue; + ret = -1; + if( !strcmp(wchrs.id,"png") ) { + VFrame *png_image = get_image(wchrs.text); + if( png_image ) { + chr = title_chars.add(CHAR_IMAGE, png_image); + cy += ch = png_image->get_h(); + cw = dx = png_image->get_w(); + wch = 0; ret = 0; + } + } + if( ret < 0 ) { + wch = wch1; wchrs.seek(ipos+1); + } + } + if( wch ) { + if( cur_caps > 0 ) wch = towupper(wch); + else if( cur_caps < 0 ) wch = towlower(wch); + int size = !cur_super ? cur_size : cur_size/2; + TitleGlyph *gp = get_glyph(wch, cur_font, size, cur_style); + if( !gp ) continue; + + if( cur_super > 0 ) cy += cur_size-4*size/3; + else if( cur_super < 0 ) cy -= size/3; + + dx = gp->advance_x; + + if( cur_fixed ) + dx = cur_fixed; + else if( !wchrs.eof() ) { + TitleGlyph *np = get_glyph(wchrs.wcur(), cur_font, cur_size, cur_style); + dx = get_width(gp, np); + } + + chr = title_chars.add(CHAR_GLYPH, gp); + cx += gp->left; + cy += gp->top; + cw = gp->right - gp->left; + ch = gp->top - gp->bottom; + } + + if( !chr ) continue; + chr->wch = wch; + chr->size = cur_size; + chr->blink = cur_blink; + chr->color = cur_color; + chr->alpha = cur_alpha; + chr->fade = 1; + if( cur_fixed ) chr->flags |= FLAG_FIXED; + if( cur_super > 0 ) chr->flags |= FLAG_SUPER; + if( cur_super < 0 ) chr->flags |= FLAG_SUBER; + if( cur_under ) chr->flags |= FLAG_UNDER; + if( cur_blink ) chr->flags |= FLAG_BLINK; + chr->x = (cx += row_x); + chr->y = cy; + chr->dx = dx; + row->bound(cx,cy, cx+cw,cy-ch); + chr->row = text_rows; + row_x += chr->dx; + } + + if( !row_w || !row_h ) return 1; + +// rows boundary, note: row->xy is y up (FT), row_xy is y down (X) + text_x1 = text_y1 = MAX_FLT; + text_x2 = text_y2 = MIN_FLT; + for( int i=0; ix0 = 0; break; + case JUSTIFY_CENTER: row->x0 = (row_w - (row->x2-row->x1)) / 2; break; + case JUSTIFY_RIGHT: row->x0 = row_w - (row->x2-row->x1); break; + } + float v; + if( text_x1 > (v=row->x0+row->x1) ) text_x1 = v; + if( text_y1 > (v=row->y0-row->y1) ) text_y1 = v; + if( text_x2 < (v=row->x0+row->x2) ) text_x2 = v; + if( text_y2 < (v=row->y0-row->y2) ) text_y2 = v; + } + if( text_x1 > text_x2 || text_y1 > text_y2 ) return 1; + text_x1 += fuzz1; text_y1 += fuzz1; + text_x2 += fuzz2; text_y2 += fuzz2; + text_w = text_x2 - text_x1; + text_h = text_y2 - text_y1; + return 0; +} + +int TitleMain::get_visible_text() +{ +// Determine y of visible text + switch( config.motion_strategy ) { + case BOTTOM_TO_TOP: + case TOP_TO_BOTTOM: { + float magnitude = config.pixels_per_second * + (get_source_position() - config.prev_keyframe_position) / + PluginVClient::project_frame_rate; + if( config.loop ) { + int loop_size = text_h + title_h; + magnitude -= (int)(magnitude / loop_size) * loop_size; + } + text_y = config.motion_strategy == BOTTOM_TO_TOP ? + title_h - magnitude : + magnitude - text_h; + break; } + default: switch( config.vjustification ) { + case JUSTIFY_TOP: text_y = 0; break; + case JUSTIFY_MID: text_y = (title_h - text_h) / 2; break; + case JUSTIFY_BOTTOM: text_y = title_h - text_h; break; + default: break; } + } + +// Determine x of visible text + switch( config.motion_strategy ) { + case RIGHT_TO_LEFT: + case LEFT_TO_RIGHT: { + float magnitude = config.pixels_per_second * + (get_source_position() - config.prev_keyframe_position) / + PluginVClient::project_frame_rate; + if( config.loop ) { + int loop_size = text_w + title_w; + magnitude -= (int)(magnitude / loop_size) * loop_size; + } + text_x = config.motion_strategy == RIGHT_TO_LEFT ? + title_w - magnitude : + magnitude - text_w; + break; } + default: switch ( config.hjustification ) { + case JUSTIFY_LEFT: text_x = 0; break; + case JUSTIFY_CENTER: text_x = (title_w - text_w) / 2; break; + case JUSTIFY_RIGHT: text_x = title_w - text_w; break; + default: break; } + } + + + // until bottom of this row is visible + int row1 = 0; + int y0 = text_y - text_y1; + while( row1 < text_rows ) { + TitleRow *row = title_rows[row1]; + if( y0 + row->y0-row->y2 > 0 ) break; + ++row1; + } + if( row1 >= text_rows ) return 0; + + // until top of next row is not visible + y0 -= title_h; + int row2 = row1; + while( row2 < text_rows ) { + TitleRow *row = title_rows[row2]; + if( y0 + row->y0-row->y1 >= 0 ) break; + ++row2; + } + if( row1 >= row2 ) return 0; + +//printf("get_visible_rows: visible_row1/2 = %d to %d\n",visible_row1,visible_row2); + // Only draw visible chars + double frame_rate = PluginVClient::get_project_framerate(); + int64_t units = get_source_position() - get_source_start(); + double position = units / frame_rate; + int blinking = 0; + int char1 = -1, char2 = -1, nchars = title_chars.count(); + for( int i=0; irow < row1 ) continue; + if( chr->row >= row2 ) break; + if( char1 < 0 ) char1 = i; + char2 = i; + if( (chr->flags & FLAG_BLINK) != 0 ) { + blinking = 1; + double rate = 1 / fabs(chr->blink), rate2 = 2 * rate; + double pos = position - ((int64_t)(position / rate2)) * rate2; + chr->fade = chr->blink > 0 ? + (pos > rate ? 0 : 1) : fabs(rate+pos) / rate; + } + } + if( char1 < 0 ) char1 = 0; + ++char2; + if( !blinking && visible_row1 == row1 && visible_row2 == row2 ) return 0; +// need redraw + visible_row1 = row1; visible_row2 = row2; + visible_char1 = char1; visible_char2 = char2; + return 1; +} + + +int TitleMain::draw_text(int need_redraw) +{ + // until top of next row is not visible + mask_x1 = mask_y1 = INT_MAX; + mask_x2 = mask_y2 = INT_MIN; + for( int i=visible_row1; i (v=row->x0+row->x1) ) mask_x1 = v; + if( mask_y1 > (v=row->y0-row->y1) ) mask_y1 = v; + if( mask_x2 < (v=row->x0+row->x2) ) mask_x2 = v; + if( mask_y2 < (v=row->y0-row->y2) ) mask_y2 = v; + } + if( mask_x1 >= mask_x2 || mask_y1 >= mask_y2 ) return 1; + + mask_x1 += fuzz1; mask_y1 += fuzz1; + mask_x2 += fuzz2; mask_y2 += fuzz2; + mask_w = mask_x2 - mask_x1; + mask_h = mask_y2 - mask_y1; + +//printf("TitleMain::draw_text %d-%d frame %dx%d\n", +// visible_row1, visible_row2, mask_w,mask_h); + if( text_mask && (text_mask->get_color_model() != text_model || + text_mask->get_w() != mask_w || text_mask->get_h() != mask_h) ) { + delete text_mask; text_mask = 0; + delete stroke_mask; stroke_mask = 0; + } + + if( !text_mask ) { +// Always use 8 bit because the glyphs are 8 bit +// Need to set YUV to get clear_frame to set the right chroma. + mask_model = text_model; + text_mask = new VFrame; + text_mask->set_use_shm(0); + text_mask->reallocate(0, -1, 0, 0, 0, mask_w, mask_h, mask_model, -1); + int drop = abs(config.dropshadow); + int drop_w = mask_w + drop; + int drop_h = mask_h + drop; + stroke_mask = new VFrame; + stroke_mask->set_use_shm(0); + stroke_mask->reallocate(0, -1, 0, 0, 0, drop_w, drop_h, mask_model, -1); + need_redraw = 1; + } + +// Draw on text mask if it has changed + if( need_redraw ) { +//printf("redraw %d to %d %d,%d %d,%d - %d,%d\n", visible_char1,visible_char2, +// ext_x0, ext_y0, ext_x1,ext_y1, ext_x2,ext_y2); + + text_mask->clear_frame(); + stroke_mask->clear_frame(); +#if 0 + unsigned char *data = text_mask->get_data(); // draw bbox on text + for( int x=0; xdo_dropshadow = 1; + title_engine->set_package_count(visible_char2 - visible_char1); + title_engine->process_packages(); + } + +// Then draw foreground + title_engine->do_dropshadow = 0; + title_engine->set_package_count(visible_char2 - visible_char1); + title_engine->process_packages(); + + draw_underline(text_mask, config.alpha); + +// Convert to text outlines + if( config.outline_size > 0 ) { + if( outline_mask && + (text_mask->get_w() != outline_mask->get_w() || + text_mask->get_h() != outline_mask->get_h()) ) { + delete outline_mask; outline_mask = 0; + } + + if( !outline_mask ) { + outline_mask = new VFrame; + outline_mask->set_use_shm(0); + outline_mask->reallocate(0, -1, 0, 0, 0, + text_mask->get_w(), text_mask->get_h(), + text_mask->get_color_model(), -1); + } + if( !outline_engine ) outline_engine = + new TitleOutlineEngine(this, cpus); + outline_engine->do_outline(); + } + + } + + return 0; +} + +int TitleMain::draw_underline(VFrame *mask, int alpha) +{ + int row = -1, sz = -1, color = -1, rgb = -1; + int bpp = mask->get_bytes_per_pixel(), bpp1 = bpp-1; + int x1 = 0, x2 = 0, y0 = 0; + for( int i=visible_char1; iflags & FLAG_UNDER) && row < 0 ) { + sz = chr->size; + rgb = chr->color; int rr, gg, bb; + get_mask_colors(rgb, mask_model, rr, gg, bb); + color = (rr<<16) | (gg<<8) | (bb<<0); + row = chr->row; + TitleRow *rp = title_rows[row]; + x1 = rp->x0 + chr->x; + y0 = rp->y0; + } + if( (chr->flags & FLAG_UNDER) && row == chr->row && chr->color == rgb ) { + TitleRow *rp = title_rows[row]; + x2 = rp->x0 + chr->x + chr->dx; + if( sz < chr->size ) sz = chr->size; + if( ++i < visible_char2 ) continue; + } + if( row < 0 ) { ++i; continue; } + x1 -= mask_x1; x2 -= mask_x1; y0 -= mask_y1; + if( x1 < 0 ) x1 = 0; + if( x2 > mask_w ) x2 = mask_w; + int sz1 = sz / 32 + 1, sz2 = sz1/2; + int y1 = y0 - sz2, y2 = y1 + sz1; + if( y1 < 0 ) y1 = 0; + if( y2 > mask_h ) y2 = mask_h; + unsigned char **rows = mask->get_rows(); + for( int y=y1; y=0; ) *bp++ = color>>(8*i); + *bp = alpha; + } + } + row = -1; + } + return 0; +} + +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; + + 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(); + + + if( fade_position >= 0 && fade_position < fade_len ) { + fade = (float)fade_position / fade_len; + } + } + + 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(); + if( config.stroke_width >= SMALL && (config.style & BC_FONT_OUTLINE) ) { + translate->xlat_mask = stroke_mask; + translate->run_packages(); + } + } +} + +const char* TitleMain::motion_to_text(int motion) +{ + switch( motion ) { + case NO_MOTION: return _("No motion"); break; + case BOTTOM_TO_TOP: return _("Bottom to top"); break; + case TOP_TO_BOTTOM: return _("Top to bottom"); break; + case RIGHT_TO_LEFT: return _("Right to left"); break; + case LEFT_TO_RIGHT: return _("Left to right"); break; + } + return _("Unknown"); +} + +int TitleMain::text_to_motion(const char *text) +{ + for( int i=0; iget_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); + } +} + + +int TitleMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr) +{ + int result = 0; + input = input_ptr; + output = output_ptr; + output_model = output->get_color_model(); + text_model = BC_CModels::is_yuv(output_model) ? BC_YUVA8888 : BC_RGBA8888; + + if( text_model != mask_model ) need_reconfigure = 1; + need_reconfigure |= load_configuration(); + int64_t cur_position = get_source_position(); + if( last_position < 0 || last_position+1 != cur_position ) + need_reconfigure = 1; + last_position = cur_position; + + title_x = config.title_x; title_y = config.title_y; + title_w = config.title_w ? config.title_w : input->get_w(); + title_h = config.title_h ? config.title_h : input->get_h(); + + fuzz1 = -config.outline_size; + fuzz2 = config.outline_size; + if( config.dropshadow < 0 ) + fuzz1 += config.dropshadow; + else + fuzz2 += config.dropshadow; + fuzz = fuzz2 - fuzz1; + +// Check boundaries + if( config.size <= 0 || config.size >= 2048 ) + config.size = 72; + if( config.stroke_width < 0 || config.stroke_width >= 512 ) + config.stroke_width = 0.0; + if( !config.wlen && !config.timecode ) + return 0; + if( !strlen(config.encoding) ) + strcpy(config.encoding, DEFAULT_ENCODING); + +// Always synthesize text and redraw it for timecode + if( config.timecode ) { + int64_t rendered_frame = get_source_position(); + if( get_direction() == PLAY_REVERSE ) + rendered_frame -= 1; + + char text[BCTEXTLEN]; + Units::totext(text, + (double)rendered_frame / PluginVClient::project_frame_rate, + config.timecode_format, + PluginVClient::get_project_samplerate(), + PluginVClient::get_project_framerate(), + 16); + config.to_wtext(config.encoding, text, strlen(text)+1); + need_reconfigure = 1; + } + + if( config.background ) + draw_background(); + +// Handle reconfiguration + if( need_reconfigure ) { + need_reconfigure = 0; + reset_render(); + result = init_freetype(); + if( !result ) { + load_glyphs(); + result = get_text(); + } + } + + if( !result ) + result = draw_text(get_visible_text()); + + +// Overlay mask on output + if( !result ) + draw_overlay(); + + if( config.drag ) + draw_boundry(); + + return 0; +} + +void TitleMain::update_gui() +{ + if( thread ) { + int reconfigure = load_configuration(); + if( reconfigure ) { + TitleWindow *window = (TitleWindow*)thread->window; + window->lock_window("TitleMain::update_gui"); + window->update(); + window->unlock_window(); + window->color_thread->update_gui(config.color, 0); + } + } +} + +int TitleMain::load_configuration() +{ + KeyFrame *prev_keyframe, *next_keyframe; + prev_keyframe = get_prev_keyframe(get_source_position()); + next_keyframe = get_next_keyframe(get_source_position()); + + TitleConfig old_config, prev_config, next_config; + old_config.copy_from(config); + read_data(prev_keyframe); + prev_config.copy_from(config); + read_data(next_keyframe); + next_config.copy_from(config); + + config.prev_keyframe_position = prev_keyframe->position; + config.next_keyframe_position = next_keyframe->position; + + // if no previous keyframe exists, it should be start of the plugin, not start of the track + if( config.next_keyframe_position == config.prev_keyframe_position ) + config.next_keyframe_position = get_source_start() + get_total_len(); + if( config.prev_keyframe_position == 0 ) + config.prev_keyframe_position = get_source_start(); +// printf("TitleMain::load_configuration 10 %d %d\n", +// config.prev_keyframe_position, +// config.next_keyframe_position); + + config.interpolate(prev_config, + next_config, + (next_keyframe->position == prev_keyframe->position) ? + get_source_position() : + prev_keyframe->position, + (next_keyframe->position == prev_keyframe->position) ? + get_source_position() + 1 : + next_keyframe->position, + get_source_position()); + + if( !config.equivalent(old_config) ) + return 1; + return 0; +} + + +void TitleMain::save_data(KeyFrame *keyframe) +{ + FileXML output; + + output.set_shared_output(keyframe->get_data(), MESSAGESIZE); + output.tag.set_title("TITLE"); + output.tag.set_property("FONT", config.font); + output.tag.set_property("ENCODING", config.encoding); + output.tag.set_property("STYLE", (int64_t)config.style); + output.tag.set_property("SIZE", config.size); + output.tag.set_property("COLOR", config.color); + output.tag.set_property("ALPHA", config.alpha); + output.tag.set_property("OUTLINE_SIZE", config.outline_size); + output.tag.set_property("OUTLINE_COLOR", config.outline_color); + output.tag.set_property("OUTLINE_ALPHA", config.outline_alpha); + output.tag.set_property("COLOR_STROKE", config.color_stroke); + output.tag.set_property("STROKE_WIDTH", config.stroke_width); + output.tag.set_property("MOTION_STRATEGY", config.motion_strategy); + output.tag.set_property("LOOP", config.loop); + output.tag.set_property("LINE_PITCH", config.line_pitch); + output.tag.set_property("PIXELS_PER_SECOND", config.pixels_per_second); + output.tag.set_property("HJUSTIFICATION", config.hjustification); + output.tag.set_property("VJUSTIFICATION", config.vjustification); + output.tag.set_property("FADE_IN", config.fade_in); + output.tag.set_property("FADE_OUT", config.fade_out); + output.tag.set_property("TITLE_X", config.title_x); + output.tag.set_property("TITLE_Y", config.title_y); + output.tag.set_property("TITLE_W", config.title_w); + output.tag.set_property("TITLE_H", config.title_h); + output.tag.set_property("DROPSHADOW", config.dropshadow); + output.tag.set_property("TIMECODE", config.timecode); + output.tag.set_property("TIMECODEFORMAT", config.timecode_format); + output.tag.set_property("WINDOW_W", config.window_w); + output.tag.set_property("WINDOW_H", config.window_h); + output.tag.set_property("DRAG", config.drag); + output.tag.set_property("BACKGROUND", config.background); + output.tag.set_property("BACKGROUND_PATH", config.background_path); + output.tag.set_property("LOOP_PLAYBACK", config.loop_playback); + output.append_tag(); + output.append_newline(); + char text[BCTEXTLEN]; + int text_len = BC_Resources::encode( + BC_Resources::wide_encoding, DEFAULT_ENCODING, + (char*)config.wtext, config.wlen*sizeof(wchar_t), + text, sizeof(text)); + output.append_text(text, text_len); + output.tag.set_title("/TITLE"); + output.append_tag(); + output.append_newline(); + output.terminate_string(); +//printf("TitleMain::save_data 1\n%s\n", output.string); +//printf("TitleMain::save_data 2\n%s\n", config.text); +} + +void TitleMain::read_data(KeyFrame *keyframe) +{ + FileXML input; + + input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data())); + + int result = 0; + + config.prev_keyframe_position = keyframe->position; + while(!result) + { + result = input.read_tag(); + if( result ) break; + + if( input.tag.title_is("TITLE") ) { + input.tag.get_property("FONT", config.font); + input.tag.get_property("ENCODING", config.encoding); + config.style = input.tag.get_property("STYLE", (int64_t)config.style); + config.size = input.tag.get_property("SIZE", config.size); + config.color = input.tag.get_property("COLOR", config.color); + config.alpha = input.tag.get_property("ALPHA", config.alpha); + config.outline_size = input.tag.get_property("OUTLINE_SIZE", config.outline_size); + config.outline_color = input.tag.get_property("OUTLINE_COLOR", config.outline_color); + config.outline_alpha = input.tag.get_property("OUTLINE_ALPHA", config.outline_alpha); + config.color_stroke = input.tag.get_property("COLOR_STROKE", config.color_stroke); + config.stroke_width = input.tag.get_property("STROKE_WIDTH", config.stroke_width); + config.motion_strategy = input.tag.get_property("MOTION_STRATEGY", config.motion_strategy); + config.loop = input.tag.get_property("LOOP", config.loop); + config.line_pitch = input.tag.get_property("LINE_PITCH", config.line_pitch); + config.pixels_per_second = input.tag.get_property("PIXELS_PER_SECOND", config.pixels_per_second); + config.hjustification = input.tag.get_property("HJUSTIFICATION", config.hjustification); + config.vjustification = input.tag.get_property("VJUSTIFICATION", config.vjustification); + config.fade_in = input.tag.get_property("FADE_IN", config.fade_in); + config.fade_out = input.tag.get_property("FADE_OUT", config.fade_out); + config.title_x = input.tag.get_property("TITLE_X", config.title_x); + config.title_y = input.tag.get_property("TITLE_Y", config.title_y); + config.title_w = input.tag.get_property("TITLE_W", config.title_w); + config.title_h = input.tag.get_property("TITLE_H", config.title_h); + config.dropshadow = input.tag.get_property("DROPSHADOW", config.dropshadow); + config.timecode = input.tag.get_property("TIMECODE", config.timecode); + config.timecode_format = input.tag.get_property("TIMECODEFORMAT", config.timecode_format); + config.window_w = input.tag.get_property("WINDOW_W", config.window_w); + config.window_h = input.tag.get_property("WINDOW_H", config.window_h); + config.drag = input.tag.get_property("DRAG", config.drag); + config.background = input.tag.get_property("BACKGROUND", config.background); + input.tag.get_property("BACKGROUND_PATH", config.background_path); + config.loop_playback = input.tag.get_property("LOOP_PLAYBACK", config.loop_playback); + const char *text = input.read_text(); + config.to_wtext(config.encoding, text, strlen(text)+1); + } + else if( input.tag.title_is("/TITLE") ) { + result = 1; + } + } +} + diff --git a/cinelerra-5.1/plugins/titler/titler.h b/cinelerra-5.1/plugins/titler/titler.h new file mode 100644 index 00000000..d24dbbbd --- /dev/null +++ b/cinelerra-5.1/plugins/titler/titler.h @@ -0,0 +1,657 @@ + +/* + * CINELERRA + * Copyright (C) 1997-2014 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef TITLE_H +#define TITLE_H + +class TitleConfig; +class TitleGlyph; +class TitleGlyphs; +class TitleImage; +class TitleImages; +class TitleChar; +class TitleChars; +class TitleRow; +class TitleRows; +class GlyphPackage; +class GlyphUnit; +class GlyphEngine; +class TitlePackage; +class TitleUnit; +class TitleEngine; +class TitleOutlinePackage; +class TitleOutlineUnit; +class TitleOutlineEngine; +class TitleTranslatePackage; +class TitleTranslateUnit; +class TitleTranslate; +class TitleCurFont; +class TitleCurSize; +class TitleCurColor; +class TitleCurAlpha; +class TitleCurBold; +class TitleCurItalic; +class TitleCurCaps; +class TitleCurUnder; +class TitleCurBlink; +class TitleCurFixed; +class TitleCurSuper; +class TitleCurNudge; +class TitleParser; +class TitleMain; + +#include "bchash.h" +#include "bcfontentry.h" +#include "file.inc" +#include "indexable.inc" +#include "loadbalance.h" +#include "mutex.h" +#include "overlayframe.inc" +#include "pluginvclient.h" +#include "renderengine.inc" +#include "titlerwindow.h" + +#include +#include FT_FREETYPE_H +#include + +// Motion strategy +#define TOTAL_PATHS 5 +#define NO_MOTION 0x0 +#define BOTTOM_TO_TOP 0x1 +#define TOP_TO_BOTTOM 0x2 +#define RIGHT_TO_LEFT 0x3 +#define LEFT_TO_RIGHT 0x4 + +// Horizontal justification +#define JUSTIFY_LEFT 0x0 +#define JUSTIFY_CENTER 0x1 +#define JUSTIFY_RIGHT 0x2 + +// Vertical justification +#define JUSTIFY_TOP 0x0 +#define JUSTIFY_MID 0x1 +#define JUSTIFY_BOTTOM 0x2 + +// char types +#define CHAR_GLYPH 0 +#define CHAR_IMAGE 1 +// flags +#define FLAG_UNDER 0x0001 +#define FLAG_FIXED 0x0002 +#define FLAG_SUPER 0x0004 +#define FLAG_SUBER 0x0008 +#define FLAG_BLINK 0x0010 + +class TitleConfig +{ +public: + TitleConfig(); + ~TitleConfig(); + + void to_wtext(const char *from_enc, const char *text, int tlen); +// Only used to clear glyphs + int equivalent(TitleConfig &that); + void copy_from(TitleConfig &that); + void interpolate(TitleConfig &prev, + TitleConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame); + +// Font information + char font[BCTEXTLEN]; +// Encoding to convert from + char encoding[BCTEXTLEN]; + int style; + float size; + int color; + int alpha; + float outline_size; + int outline_color; + int outline_alpha; + int color_stroke; + float stroke_width; + int motion_strategy; // Motion of title across frame + int line_pitch; + int loop; // Loop motion path + int hjustification; + int vjustification; +// Number of seconds the fade in and fade out of the title take + double fade_in, fade_out; + float pixels_per_second; // Speed of motion +// Text to display + wchar_t wtext[BCTEXTLEN]; + int wlen; +// Position in frame relative to top left + float title_x, title_y; + int title_w, title_h; +// Size of window + int window_w, window_h; +// Calculated during every frame for motion strategy + int64_t prev_keyframe_position; + int64_t next_keyframe_position; +// Stamp timecode + int timecode; + int dropshadow; + int background; + char background_path[BCTEXTLEN]; + + void convert_text(); + +// Time Code Format + int timecode_format; +// drag enable + int drag; +// loop background playback + int loop_playback; +}; + +class TitleGlyph +{ +public: + TitleGlyph(); + ~TitleGlyph(); + + FT_ULong char_code; + int freetype_index; + BC_FontEntry *font; + int width, height, style; + int size, pitch; + int advance_x; + int left, top, right, bottom; + VFrame *data, *data_stroke; +}; +class TitleGlyphs : public ArrayList { +public: + void clear() { remove_all_objects(); } + int count() { return size(); } + + TitleGlyphs() {} + ~TitleGlyphs() { clear(); } +}; + +class TitleImage { +public: + char *path; + VFrame *vframe; + + TitleImage(const char *path, VFrame *vfrm); + ~TitleImage(); +}; +class TitleImages : public ArrayList { +public: + void clear() { remove_all_objects(); } + int count() { return size(); } + + TitleImages() {} + ~TitleImages() { clear(); } +}; + + +// Position of each image box in a row +class TitleChar { +public: + wchar_t wch; + int typ, flags; + void *vp; + int x, y; + int row, dx; + int color, alpha; + float fade; + float blink, size; + + TitleChar *init(int typ, void *vp); +}; +class TitleChars : public ArrayList { + int next; +public: + void reset() { next = 0; } + void clear() { remove_all_objects(); reset(); } + int count() { return next; } + TitleChar *add(int typ, void *vp) { + TitleChar *ret = next < size() ? get(next++) : 0; + if( !ret ) { append(ret = new TitleChar()); next = size(); } + return ret->init(typ, vp); + } + TitleChars() { reset(); } + ~TitleChars() { clear(); } +}; + +class TitleRow { +public: + float x0, y0, x1, y1, x2, y2; + TitleRow *init(); + void bound(float lt, float tp, float rt, float bt) { + if( x1 > lt ) x1 = lt; + if( y1 < tp ) y1 = tp; + if( x2 < rt ) x2 = rt; + if( y2 > bt ) y2 = bt; + } +}; +class TitleRows : public ArrayList { + int next; +public: + void reset() { next = 0; } + void clear() { remove_all_objects(); reset(); } + int count() { return next; } + TitleRow *add() { + TitleRow *ret = next < size() ? get(next++) : 0; + if( !ret ) { append(ret = new TitleRow()); next = size(); } + return ret->init(); + } + TitleRows() { reset(); } + ~TitleRows() { clear(); } +}; + +// Draw a single character into the glyph cache +// +class GlyphPackage : public LoadPackage +{ +public: + GlyphPackage(); + TitleGlyph *glyph; +}; + + +class GlyphUnit : public LoadClient +{ +public: + GlyphUnit(TitleMain *plugin, GlyphEngine *server); + ~GlyphUnit(); + void process_package(LoadPackage *package); + + TitleMain *plugin; + FT_Library freetype_library; // Freetype library + FT_Face freetype_face; +}; + +class GlyphEngine : public LoadServer +{ +public: + GlyphEngine(TitleMain *plugin, int cpus); + void init_packages(); + LoadClient* new_client(); + LoadPackage* new_package(); + TitleMain *plugin; +}; + + +// Copy a single character to the text mask +class TitlePackage : public LoadPackage +{ +public: + TitlePackage(); + int x, y; + TitleChar *chr; +}; + +// overlay modes +#define DRAW_ALPHA 1 +#define DRAW_COLOR 2 +#define DRAW_IMAGE 3 + +class TitleUnit : public LoadClient +{ +public: + TitleUnit(TitleMain *plugin, TitleEngine *server); + void process_package(LoadPackage *package); + void draw_frame(int mode, VFrame *dst, VFrame *src, int x, int y); + + TitleMain *plugin; + TitleEngine *engine; + TitleChar *chr; +}; + +class TitleEngine : public LoadServer +{ +public: + TitleEngine(TitleMain *plugin, int cpus); + void init_packages(); + LoadClient* new_client(); + LoadPackage* new_package(); + TitleMain *plugin; + int do_dropshadow; +}; + + +// Create outline +class TitleOutlinePackage : public LoadPackage +{ +public: + TitleOutlinePackage(); + int y1, y2; +}; + + +class TitleOutlineUnit : public LoadClient +{ +public: + TitleOutlineUnit(TitleMain *plugin, TitleOutlineEngine *server); + void process_package(LoadPackage *package); + TitleMain *plugin; + TitleOutlineEngine *engine; +}; + +class TitleOutlineEngine : public LoadServer +{ +public: + TitleOutlineEngine(TitleMain *plugin, int cpus); + void init_packages(); + void do_outline(); + LoadClient* new_client(); + LoadPackage* new_package(); + TitleMain *plugin; + int pass; +}; + + +// Overlay text mask with fractional translation +// We don't use OverlayFrame to enable alpha blending on non alpha +// output. +class TitleTranslatePackage : public LoadPackage +{ +public: + TitleTranslatePackage(); + int y1, y2; +}; + +typedef struct { + int in_x1; + float in_fraction1; + int in_x2; // Might be same as in_x1 for boundary + float in_fraction2; + float output_fraction; +} transfer_table_f; + +class TitleTranslateUnit : public LoadClient +{ +public: + TitleTranslateUnit(TitleMain *plugin, TitleTranslate *server); + + static void translation_array_f(transfer_table_f* &table, + float out_x1, float out_x2, int out_total, + float in_x1, float in_x2, int in_total, + int &x1_out, int &x2_out); + void process_package(LoadPackage *package); + TitleMain *plugin; +}; + +class TitleTranslate : public LoadServer +{ +public: + TitleTranslate(TitleMain *plugin, int cpus); + ~TitleTranslate(); + void init_packages(); + void run_packages(); + LoadClient* new_client(); + LoadPackage* new_package(); + TitleMain *plugin; + transfer_table_f *y_table; + transfer_table_f *x_table; + VFrame *xlat_mask; + int out_x1, out_x2; + int out_y1, out_y2; +}; + +template class TitleStack : public ArrayList +{ + typ &last() { return ArrayList::last(); } + int size() { return ArrayList::size(); } + typ &append(typ &v) { return ArrayList::append(v); } + void remove() { return ArrayList::remove(); } +public: + TitleParser *parser; + TitleStack(TitleParser *p, typ v) : parser(p) { append(v); } + operator typ&() { return last(); } + typ &push(typ &v) { return append(v); } + int pop() { return size()>1 ? (remove(),0) : 1; } + int set(const char *txt); + int unset(const char *txt); +}; + +template int TitleStack::set(const char *txt) +{ + typ v = !*txt ? 1 : strtol(txt,(char **)&txt,0); + if( *txt || v < 0 || v > 1 ) return 1; + push(v); + return 0; +} +template int TitleStack::unset(const char *txt) +{ + return pop(); +} + +class TitleCurNudge : public TitleStack { +public: + TitleCurNudge(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); +}; + +class TitleCurColor : public TitleStack { +public: + TitleCurColor(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); +}; + +class TitleCurAlpha : public TitleStack { +public: + TitleCurAlpha(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); +}; + +class TitleCurSize : public TitleStack { +public: + TitleCurSize(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); + int unset(const char *txt); +}; + +class TitleCurBold : public TitleStack { +public: + TitleCurBold(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); + int unset(const char *txt); +}; + +class TitleCurItalic : public TitleStack { +public: + TitleCurItalic(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); + int unset(const char *txt); +}; + +class TitleCurFont : public TitleStack +{ +public: + BC_FontEntry* get(const char *txt, int style); + int set(const char *txt, int style); + int style(); + virtual int set(const char *txt=0); + virtual int unset(const char *txt); + TitleCurFont(TitleParser *parser, TitleMain *plugin); +}; + +class TitleCurCaps : public TitleStack { +public: + TitleCurCaps(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); +}; + +class TitleCurUnder : public TitleStack { +public: + TitleCurUnder(TitleParser *parser, TitleMain *plugin); +}; + +class TitleCurBlink : public TitleStack { +public: + TitleCurBlink(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); +}; + +class TitleCurFixed : public TitleStack { +public: + TitleCurFixed(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); +}; + +class TitleCurSuper : public TitleStack { +public: + TitleCurSuper(TitleParser *parser, TitleMain *plugin); + int set(const char *txt); +}; + + +class TitleParser +{ + const wchar_t *bfr, *out, *lmt; +public: + TitleMain *plugin; + + long tell() { return out - bfr; } + void seek(long pos) { out = bfr + pos; } + bool eof() { return out >= lmt; } + int wcur() { return eof() ? -1 : *out; } + int wnext() { return eof() ? -1 : *out++; } + int wget(wchar_t &wch); + char id[BCSTRLEN], text[BCTEXTLEN]; + int set_attributes(int ret); + + TitleCurNudge cur_nudge; + TitleCurColor cur_color; + TitleCurAlpha cur_alpha; + TitleCurSize cur_size; + TitleCurBold cur_bold; + TitleCurItalic cur_italic; + TitleCurFont cur_font; + TitleCurCaps cur_caps; + TitleCurUnder cur_under; + TitleCurBlink cur_blink; + TitleCurFixed cur_fixed; + TitleCurSuper cur_super; + + TitleParser(TitleMain *main); +}; + + +class TitleMain : public PluginVClient +{ +public: + TitleMain(PluginServer *server); + ~TitleMain(); + +// required for all realtime plugins + PLUGIN_CLASS_MEMBERS(TitleConfig) + int process_realtime(VFrame *input_ptr, VFrame *output_ptr); + int is_realtime(); + int is_synthesis(); + void update_gui(); + void save_data(KeyFrame *keyframe); + void read_data(KeyFrame *keyframe); + + void build_previews(TitleWindow *gui); + void reset_render(); + int init_freetype(); + int set_font(BC_FontEntry*&font, const char *txt); + int set_font(BC_FontEntry*&font, const char *txt, int style); + int set_size(int &size, const char *txt); + int set_color(int &color, const char *txt); + int set_bold(int &bold, const char *txt); + int set_italic(int &italic, const char *txt); + int set_caps(int &caps, const char *txt); + int set_under(int &under, const char *txt); + void load_glyphs(); + int draw_text(int need_redraw); + int draw_underline(VFrame *mask, int alpha); + void draw_overlay(); + void draw_boundry(); + int get_text(); + int get_visible_text(); + int check_char_code_path(FT_Library &freetype_library, + char *path_old, FT_ULong &char_code, char *path_new); + int load_freetype_face(FT_Library &freetype_library, + FT_Face &freetype_face, const char *path); + int load_font(BC_FontEntry *font); + Indexable *open_background(const char *filename); + int read_background(VFrame *frame, int64_t position, int color_model); + void draw_background(); + BC_FontEntry* get_font(const char *font_name, int style); + BC_FontEntry* config_font(); + TitleGlyph *get_glyph(FT_ULong char_code, BC_FontEntry *font, int size, int style); + int get_width(TitleGlyph *cur, TitleGlyph *nxt); + + VFrame *add_image(const char *path); + VFrame *get_image(const char *path); + +// backward compatibility + void convert_encoding(); + static const char* motion_to_text(int motion); + static int text_to_motion(const char *text); + + VFrame *text_mask; + VFrame *stroke_mask; + GlyphEngine *glyph_engine; + TitleEngine *title_engine; + VFrame *outline_mask; + TitleOutlineEngine *outline_engine; + TitleTranslate *translate; + + TitleChars title_chars; + TitleRows title_rows; + TitleGlyphs title_glyphs; + TitleImages title_images; + + FT_Library freetype_library; + FT_Face freetype_face; + char text_font[BCTEXTLEN]; + + int window_w, window_h; + int fuzz, fuzz1, fuzz2; + int title_x, title_y, title_w, title_h; + + float text_x, text_y, text_w, text_h; + float text_x1, text_y1, text_x2, text_y2; + + int mask_x, mask_y; int mask_w, mask_h; + int mask_x1, mask_y1, mask_x2, mask_y2; + + int text_rows; + int visible_row1, visible_char1; + int visible_row2, visible_char2; + float fade; + + VFrame *input, *output; + int output_model, text_model, mask_model; + + Indexable *background; + File *bg_file; + VFrame *bg_frame; + RenderEngine *render_engine; + CICache *video_cache; + OverlayFrame *overlay_frame; + + int64_t last_position; + int need_reconfigure; + int cpus; +}; + + +#endif diff --git a/cinelerra-5.1/plugins/titler/titlewindow.C b/cinelerra-5.1/plugins/titler/titlerwindow.C similarity index 50% rename from cinelerra-5.1/plugins/titler/titlewindow.C rename to cinelerra-5.1/plugins/titler/titlerwindow.C index 1a537ba6..ef89eb8d 100644 --- a/cinelerra-5.1/plugins/titler/titlewindow.C +++ b/cinelerra-5.1/plugins/titler/titlerwindow.C @@ -21,10 +21,20 @@ #include "bcdisplayinfo.h" #include "bcsignals.h" +#include "clip.h" #include "cstrdup.h" +#include "automation.h" +#include "cwindow.h" +#include "cwindowgui.h" +#include "edl.h" +#include "edlsession.h" #include "language.h" +#include "mwindow.h" +#include "plugin.h" +#include "pluginserver.h" #include "theme.h" -#include "titlewindow.h" +#include "track.h" +#include "titlerwindow.h" #include "bcfontentry.h" #include @@ -42,11 +52,7 @@ static const int timeunit_formats[] = TitleWindow::TitleWindow(TitleMain *client) : PluginClientWindow(client, - client->config.window_w, - client->config.window_h, - 100, - 100, - 1) + client->config.window_w, client->config.window_h, 100, 100, 1) { //printf("TitleWindow::TitleWindow %d %d %d\n", __LINE__, client->config.window_w, client->config.window_h); this->client = client; @@ -54,49 +60,42 @@ TitleWindow::TitleWindow(TitleMain *client) justify_title = 0; style_title = 0; size_title = 0; - title_y = 0; - bottom = 0; - size = 0; - loop = 0; - title_x = 0; - dropshadow = 0; - motion = 0; + motion_title = 0; + speed_title = 0; + font_title = 0; + fadeout_title = 0; + fadein_title = 0; dropshadow_title = 0; + text_title = 0; + + font = 0; size = 0; + title_x = 0; title_y = 0; + x_title = 0; y_title = 0; + title_w = 0; title_h = 0; + w_title = 0; h_title = 0; + top = 0; mid = 0; bottom = 0; + left = 0; center = 0; right = 0; + loop = 0; motion = 0; speed = 0; + dropshadow = 0; text = 0; timecode = 0; - fade_in = 0; - encoding_title = 0; - x_title = 0; bold = 0; - color_y = 0; - speed = 0; - center = 0; italic = 0; - text_title = 0; - motion_title = 0; - fadeout_title = 0; - font_title = 0; - fadein_title = 0; + dragging = 0; + fade_in = 0; fade_out = 0; color_button = 0; - left = 0; - speed_title = 0; - top = 0; - font = 0; - right = 0; - color_x = 0; - color_y = 0; - y_title = 0; + color_x = color_y = 0; color_thread = 0; - mid = 0; - encoding_title = 0; - encoding = 0; + background = 0; + background_path = 0; + cur_ibeam = -1; } TitleWindow::~TitleWindow() { - for(int j = 0; j < fonts.size(); j++) - { + ungrab(client->server->mwindow->cwindow->gui); + for( int j=0; jget_icon(); } @@ -104,9 +103,6 @@ TitleWindow::~TitleWindow() sizes.remove_all_objects(); delete timecode_format; delete color_thread; -#ifdef USE_OUTLINE - delete color_stroke_thread; -#endif delete title_x; delete title_y; } @@ -121,25 +117,6 @@ void TitleWindow::create_objects() #define COLOR_H 30 client->build_previews(this); - encodings.append(new BC_ListBoxItem("ISO8859-1")); - encodings.append(new BC_ListBoxItem("ISO8859-2")); - encodings.append(new BC_ListBoxItem("ISO8859-3")); - encodings.append(new BC_ListBoxItem("ISO8859-4")); - encodings.append(new BC_ListBoxItem("ISO8859-5")); - encodings.append(new BC_ListBoxItem("ISO8859-6")); - encodings.append(new BC_ListBoxItem("ISO8859-7")); - encodings.append(new BC_ListBoxItem("ISO8859-8")); - encodings.append(new BC_ListBoxItem("ISO8859-9")); - encodings.append(new BC_ListBoxItem("ISO8859-10")); - encodings.append(new BC_ListBoxItem("ISO8859-11")); - encodings.append(new BC_ListBoxItem("ISO8859-12")); - encodings.append(new BC_ListBoxItem("ISO8859-13")); - encodings.append(new BC_ListBoxItem("ISO8859-14")); - encodings.append(new BC_ListBoxItem("ISO8859-15")); - encodings.append(new BC_ListBoxItem("KOI8")); - encodings.append(new BC_ListBoxItem("UTF-8")); - - sizes.append(new BC_ListBoxItem("8")); sizes.append(new BC_ListBoxItem("9")); sizes.append(new BC_ListBoxItem("10")); @@ -178,24 +155,23 @@ void TitleWindow::create_objects() // Construct font list ArrayList *fontlist = get_resources()->fontlist; - for(int i = 0; i < fontlist->size(); i++) { + for( int i=0; isize(); ++i ) { int exists = 0; - for(int j = 0; j < fonts.size(); j++) { - if(!strcasecmp(fonts.get(j)->get_text(), - fontlist->get(i)->displayname)) { + for( int j=0; jget_text(), + fontlist->get(i)->displayname) ) { exists = 1; break; } } BC_ListBoxItem *item = 0; - if(!exists) { + if( !exists ) { fonts.append(item = new BC_ListBoxItem(fontlist->get(i)->displayname)); - if(!strcmp(client->config.font, item->get_text())) + if( !strcmp(client->config.font, item->get_text()) ) item->set_selected(1); - if(fontlist->values[i]->image) - { + if( fontlist->values[i]->image ) { VFrame *vframe = fontlist->get(i)->image; BC_Pixmap *icon = new BC_Pixmap(this, vframe, PIXMAP_ALPHA); item->set_icon(icon); @@ -208,9 +184,9 @@ void TitleWindow::create_objects() int done = 0; while(!done) { done = 1; - for(int i = 0; i < fonts.size() - 1; i++) { - if(strcmp(fonts.values[i]->get_text(), - fonts.values[i + 1]->get_text()) > 0) { + for( int i=0; iget_text(), + fonts.values[i + 1]->get_text()) > 0 ) { BC_ListBoxItem *temp = fonts.values[i + 1]; fonts.values[i + 1] = fonts.values[i]; fonts.values[i] = temp; @@ -223,34 +199,36 @@ void TitleWindow::create_objects() font = new TitleFont(client, this, x, y + font_title->get_h()); font->create_objects(); x += font->get_w(); - add_subwindow(font_tumbler = new TitleFontTumble(client, this, x, y+10)); + add_subwindow(font_tumbler = new TitleFontTumble(client, this, x, y+margin)); x += font_tumbler->get_w() + margin; int x1 = x, y1 = y; - add_tool(size_title = new BC_Title(x1, y1+10, _("Size:"))); - sprintf(string, "%d", client->config.size); + add_tool(size_title = new BC_Title(x1, y1+margin, _("Size:"))); + sprintf(string, "%.2f", client->config.size); x1 += size_title->get_w() + margin; - size = new TitleSize(client, this, x1, y1+10, string); + size = new TitleSize(client, this, x1, y1+margin, string); size->create_objects(); int x2 = x1 + size->get_w(), y2 = y1 + size->get_h() + margin; - add_subwindow(size_tumbler = new TitleSizeTumble(client, this, x2, y1+10)); + add_subwindow(size_tumbler = new TitleSizeTumble(client, this, x2, y1+margin)); - add_tool(pitch_title = new BC_Title(x-5, y2+10, _("Pitch:"))); - pitch = new TitlePitch(client, this, x1, y2+10, &client->config.line_pitch); + add_tool(pitch_title = new BC_Title(x-5, y2+margin, _("Pitch:"))); + pitch = new TitlePitch(client, this, x1, y2+margin, &client->config.line_pitch); pitch->create_objects(); - x = x2 + size_tumbler->get_w() + margin; + + int x3 = x2 + size_tumbler->get_w() + 50; int y3 = pitch->get_y() + pitch->get_h(); - add_tool(style_title = new BC_Title(x, y, _("Style:"))); + add_tool(style_title = new BC_Title(x=x3, y, _("Style:"))); add_tool(italic = new TitleItalic(client, this, x, y + 20)); int w1 = italic->get_w(); add_tool(bold = new TitleBold(client, this, x, y + 50)); if( bold->get_w() > w1 ) w1 = bold->get_w(); -#ifdef USE_OUTLINE - add_tool(stroke = new TitleStroke(client, this, x, y + 80)); - if( stroke->get_w() > w1 ) w1 = stroke->get_w(); -#endif - x += w1 + 10; + add_tool(drag = new TitleDrag(client, this, x, y + 80)); + if( drag->get_w() > w1 ) w1 = drag->get_w(); + if( client->config.drag ) + grab(client->server->mwindow->cwindow->gui); + + x += w1 + margin; add_tool(justify_title = new BC_Title(x, y, _("Justify:"))); add_tool(left = new TitleLeft(client, this, x, y + 20)); w1 = left->get_w(); @@ -259,109 +237,128 @@ void TitleWindow::create_objects() add_tool(right = new TitleRight(client, this, x, y + 80)); if( right->get_w() > w1 ) w1 = right->get_w(); - x += w1 + 10; + x += w1 + margin; add_tool(top = new TitleTop(client, this, x, y + 20)); add_tool(mid = new TitleMid(client, this, x, y + 50)); add_tool(bottom= new TitleBottom(client, this, x, y + 80)); - x = 10; - y = y3; + x = margin; + y = y3+10; - add_tool(x_title = new BC_Title(x, y, _("X:"))); - title_x = new TitleX(client, this, x, y + 20); + w1 = BC_Title::calculate_w(this, _("X:")); + if( (x1 = BC_Title::calculate_w(this, _("Y:"))) > w1 ) w1 = x1; + if( (x1 = BC_Title::calculate_w(this, _("W:"))) > w1 ) w1 = x1; + if( (x1 = BC_Title::calculate_w(this, _("H:"))) > w1 ) w1 = x1; + add_tool(x_title = new BC_Title(x1=x, y, _("X:"))); + x1 += w1; + title_x = new TitleX(client, this, x1, y); title_x->create_objects(); - x += 90; - - add_tool(y_title = new BC_Title(x, y, _("Y:"))); - title_y = new TitleY(client, this, x, y + 20); + x1 += title_x->get_w()+margin; + add_tool(y_title = new BC_Title(x1, y, _("Y:"))); + x1 += w1; + title_y = new TitleY(client, this, x1, y); title_y->create_objects(); - x += 90; - - add_tool(motion_title = new BC_Title(x, y, _("Motion type:"))); - - motion = new TitleMotion(client, this, x, y + 20); + x1 += title_y->get_w(); + y1 = y + title_y->get_h(); + + add_tool(w_title = new BC_Title(x1=x, y1, _("W:"))); + x1 += w1; + title_w = new TitleW(client, this, x1, y1); + title_w->create_objects(); + x1 += title_w->get_w()+margin; + add_tool(h_title = new BC_Title(x1, y1, _("H:"))); + x1 += w1; + title_h = new TitleH(client, this, x1, y1); + title_h->create_objects(); + x1 += title_h->get_w(); + + x = x1+2*margin; + add_tool(motion_title = new BC_Title(x1=x, y, _("Motion:"))); + x1 += motion_title->get_w()+margin; + motion = new TitleMotion(client, this, x1, y); motion->create_objects(); - x += 150; - - add_tool(loop = new TitleLoop(client, x, y + 20)); - - x = 10; - y += 50; + add_tool(loop = new TitleLoop(client, x, y1)); + x = margin; y = y1 + loop->get_h()+20; add_tool(dropshadow_title = new BC_Title(x, y, _("Drop shadow:"))); w1 = dropshadow_title->get_w(); dropshadow = new TitleDropShadow(client, this, x, y + 20); dropshadow->create_objects(); if( dropshadow->get_w() > w1 ) w1 = dropshadow->get_w(); - x += w1 + 10; + x += w1 + margin; add_tool(fadein_title = new BC_Title(x, y, _("Fade in (sec):"))); w1 = fadein_title->get_w(); add_tool(fade_in = new TitleFade(client, this, &client->config.fade_in, x, y + 20)); if( fade_in->get_w() > w1 ) w1 = fade_in->get_w(); - x += w1 + 10; + x += w1 + margin; add_tool(fadeout_title = new BC_Title(x, y, _("Fade out (sec):"))); w1 = fadeout_title->get_w(); add_tool(fade_out = new TitleFade(client, this, &client->config.fade_out, x, y + 20)); if( fade_out->get_w() > w1 ) w1 = fade_out->get_w(); - x += w1 + 10; + x += w1 + margin; - add_tool(speed_title = new BC_Title(x, y, _("Speed:"))); + add_tool(speed_title = new BC_Title(x, y1=y, _("Speed:"))); w1 = speed_title->get_w(); - speed = new TitleSpeed(client, this, x, y + 20); + y += speed_title->get_h() + 5; + speed = new TitleSpeed(client, this, x, y); speed->create_objects(); if( speed->get_w() > w1 ) w1 = speed->get_w(); - x += w1 + 10; + x += w1 + margin; + y2 = y + speed->get_h() + 10; - color_x = x; - color_y = y + 16; - x += COLOR_W + 5; - add_tool(color_button = new TitleColorButton(client, this, x, y + 16, 0)); - x += color_button->get_w() + 5; + color_x = x3; color_y = y = y1; color_thread = new TitleColorThread(client, this, 0); - - x = color_x; - y += 50; - - outline_color_x = x; - outline_color_y = y + 20; - x += COLOR_W + 5; - add_tool(outline_color_button = new TitleColorButton(client, this, x, y + 20, 1)); - x += outline_color_button->get_w(); + x1 = color_x + COLOR_W + 2*margin; + y1 = color_y + 5; + add_tool(color_button = new TitleColorButton(client, this, x1, y1)); + y += COLOR_H + 5; + outline_color_x = x3; outline_color_y = y; outline_color_thread = new TitleColorThread(client, this, 1); + y1 = outline_color_y + 5; + add_tool(outline_color_button = new TitleOutlineColorButton(client, this, x1, y1)); - x = 10; -// y += 50; - + x = 10; y = y2; add_tool(outline_title = new BC_Title(x, y, _("Outline:"))); - outline = new TitleOutline(client, this, x, y + outline_title->get_h() + margin); + y1 = y + outline_title->get_h() + margin; + outline = new TitleOutline(client, this, x, y1); outline->create_objects(); - x += outline->get_w() + margin; - -#ifndef X_HAVE_UTF8_STRING - add_tool(encoding_title = new BC_Title(x, y + 3, _("Encoding:"))); - encoding = new TitleEncoding(client, this, x, y + encoding_title->get_h() + margin); - encoding->create_objects(); - x += 100; + x += outline->get_w() + 2*margin; +#ifdef USE_STOKER +// to different to be used + add_tool(stroker_title = new BC_Title(x, y, _("Stroker:"))); + stroker = new TitleStroker(client, this, x, y1); + stroker->create_objects(); + x += stroker->get_w() + margin; #endif - y += outline_title->get_h() + margin; - add_tool(timecode = new TitleTimecode(client, x, y)); + add_tool(timecode = new TitleTimecode(client, x1=x, y)); x += timecode->get_w() + margin; - add_tool(timecode_format = new TitleTimecodeFormat(client, x, y, Units::print_time_format(client->config.timecode_format, string))); timecode_format->create_objects(); - x = 10; y += timecode_format->get_h() + margin; - add_tool(text_title = new BC_Title(x, y + 3, _("Text:"))); + x = 10; + add_tool(background = new TitleBackground(client, this, x, y)); + x += background->get_w() + margin; + add_tool(background_path = new TitleBackgroundPath(client, this, x, y)); + x += background_path->get_w() + 2*margin; + add_tool(loop_playback = new TitleLoopPlayback(client, x, y)); + y += loop_playback->get_h() + 10; + + x = 10; + add_tool(text_title = new BC_Title(x, y, _("Text:"))); y += text_title->get_h() + margin; - text = new TitleText(client, this, x, y, get_w() - x - 10, get_h() - y - 50); + x = margin; + text = new TitleText(client, this, x, y, get_w()-margin - x, get_h() - y - 10); text->create_objects(); - update(); + add_tool(cur_popup = new TitleCurPopup(client, this)); + cur_popup->create_objects(); + + update(); show_window(1); } @@ -378,26 +375,21 @@ int TitleWindow::resize_event(int w, int h) title_x->reposition_window(title_x->get_x(), title_x->get_y()); y_title->reposition_window(y_title->get_x(), y_title->get_y()); title_y->reposition_window(title_y->get_x(), title_y->get_y()); + w_title->reposition_window(w_title->get_x(), w_title->get_y()); + title_w->reposition_window(title_w->get_x(), title_w->get_y()); + h_title->reposition_window(h_title->get_x(), h_title->get_y()); + title_h->reposition_window(title_h->get_x(), title_h->get_y()); style_title->reposition_window(style_title->get_x(), style_title->get_y()); italic->reposition_window(italic->get_x(), italic->get_y()); bold->reposition_window(bold->get_x(), bold->get_y()); -#ifdef USE_OUTLINE - stroke->reposition_window(stroke->get_x(), stroke->get_y()); -#endif + drag->reposition_window(drag->get_x(), drag->get_y()); size_title->reposition_window(size_title->get_x(), size_title->get_y()); size->reposition_window(size->get_x(), size->get_y()); size_tumbler->reposition_window(size_tumbler->get_x(), size_tumbler->get_y()); pitch_title->reposition_window(pitch_title->get_x(), pitch_title->get_y()); pitch->reposition_window(pitch->get_x(), pitch->get_y()); -#ifndef X_HAVE_UTF8_STRING - encoding->reposition_window(encoding->get_x(), encoding->get_y()); -#endif - color_button->reposition_window(color_button->get_x(), color_button->get_y()); -#ifdef USE_OUTLINE - color_stroke_button->reposition_window(color_stroke_button->get_x(), color_stroke_button->get_y()); -#endif outline_color_button->reposition_window(outline_color_button->get_x(), outline_color_button->get_y()); motion_title->reposition_window(motion_title->get_x(), motion_title->get_y()); motion->reposition_window(motion->get_x(), motion->get_y()); @@ -409,19 +401,9 @@ int TitleWindow::resize_event(int w, int h) fadeout_title->reposition_window(fadeout_title->get_x(), fadeout_title->get_y()); fade_out->reposition_window(fade_out->get_x(), fade_out->get_y()); text_title->reposition_window(text_title->get_x(), text_title->get_y()); -#ifdef USE_OUTLINE - stroke_width->reposition_window(stroke_width->get_x(), stroke_width->get_y()); - strokewidth_title->reposition_window(strokewidth_title->get_x(), strokewidth_title->get_y()); -#endif timecode->reposition_window(timecode->get_x(), timecode->get_y()); - - text->reposition_window(text->get_x(), - text->get_y(), - w - text->get_x() - 10, + text->reposition_window(text->get_x(), text->get_y(), w - text->get_x() - 10, BC_TextBox::pixels_to_rows(this, MEDIUMFONT, h - text->get_y() - 10)); - - - justify_title->reposition_window(justify_title->get_x(), justify_title->get_y()); left->reposition_window(left->get_x(), left->get_y()); center->reposition_window(center->get_x(), center->get_y()); @@ -437,17 +419,152 @@ int TitleWindow::resize_event(int w, int h) return 1; } +int TitleWindow::grab_event(XEvent *event) +{ + switch( event->type ) { + case ButtonPress: + if( !dragging ) break; + return 1; + case ButtonRelease: + if( !dragging ) return 0; + dragging = 0; + return 1; + case MotionNotify: + if( dragging ) break; + default: + return 0; + } + MWindow *mwindow = client->server->mwindow; + CWindowGUI *cwindow_gui = mwindow->cwindow->gui; + CWindowCanvas *canvas = cwindow_gui->canvas; + float cursor_x = canvas->get_canvas()->get_relative_cursor_x(); + float cursor_y = canvas->get_canvas()->get_relative_cursor_y(); + canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y); + int64_t position = client->get_source_position(); + float projector_x, projector_y, projector_z; + Track *track = client->server->plugin->track; + int track_w = track->track_w, track_h = track->track_h; + track->automation->get_projector( + &projector_x, &projector_y, &projector_z, + position, PLAY_FORWARD); + projector_x += mwindow->edl->session->output_w / 2; + projector_y += mwindow->edl->session->output_h / 2; + cursor_x = (cursor_x - projector_x) / projector_z + track_w / 2; + cursor_y = (cursor_y - projector_y) / projector_z + track_h / 2; + int title_x = client->config.title_x, title_y = client->config.title_y; + int title_w = client->config.title_w, title_h = client->config.title_h; + if( !title_w ) title_w = track_w; + if( !title_h ) title_h = track_h; + int r = MIN(track_w, track_h)/100 + 2; + int x0 = title_x, x1 = title_x+(title_w+1)/2, x2 = title_x+title_w; + int y0 = title_y, y1 = title_y+(title_h+1)/2, y2 = title_y+title_h; + int drag_dx = 0, drag_dy = 0; + if( !dragging ) { // clockwise + if( abs(drag_dx = cursor_x-x0) < r && // x0,y0 + abs(drag_dy = cursor_y-y0) < r ) dragging = 1; + else if( abs(drag_dx = cursor_x-x1) < r && // x1,y0 + abs(drag_dy = cursor_y-y0) < r ) dragging = 2; + else if( abs(drag_dx = cursor_x-x2) < r && // x2,y0 + abs(drag_dy = cursor_y-y0) < r ) dragging = 3; + else if( abs(drag_dx = cursor_x-x2) < r && // x2,y1 + abs(drag_dy = cursor_y-y1) < r ) dragging = 4; + else if( abs(drag_dx = cursor_x-x2) < r && // x2,y2 + abs(drag_dy = cursor_y-y2) < r ) dragging = 5; + else if( abs(drag_dx = cursor_x-x1) < r && // x1,y2 + abs(drag_dy = cursor_y-y2) < r ) dragging = 6; + else if( abs(drag_dx = cursor_x-x0) < r && // x0,y2 + abs(drag_dy = cursor_y-y2) < r ) dragging = 7; + else if( abs(drag_dx = cursor_x-x0) < r && // x0,y1 + abs(drag_dy = cursor_y-y1) < r ) dragging = 8; + else if( abs(drag_dx = cursor_x-x1) < r && // x1,y1 + abs(drag_dy = cursor_y-y1) < r ) dragging = 9; + return 0; + } + switch( dragging ) { + case 1: { // x0,y0 + int cur_x = cursor_x - drag_dx, dx = cur_x - x0; + int cur_y = cursor_y - drag_dy, dy = cur_y - y0; + if( !dx && !dy ) return 1; + int cur_w = title_w - dx; if( cur_w < 1 ) cur_w = 1; + int cur_h = title_h - dy; if( cur_h < 1 ) cur_h = 1; + this->title_x->update((int64_t)(client->config.title_x = cur_x)); + this->title_y->update((int64_t)(client->config.title_y = cur_y)); + this->title_w->update((int64_t)(client->config.title_w = cur_w)); + this->title_h->update((int64_t)(client->config.title_h = cur_h)); + break; } + case 2: { // x1,y0 + int cur_y = cursor_y - drag_dy, dy = cur_y - y0; + if( !dy ) return 1; + int cur_h = title_h - dy; if( cur_h < 1 ) cur_h = 1; + this->title_y->update((int64_t)(client->config.title_y = cur_y)); + this->title_h->update((int64_t)(client->config.title_h = cur_h)); + break; } + case 3: { // x2,y0 + int cur_x = cursor_x - drag_dx, dx = cur_x - x2; + int cur_y = cursor_y - drag_dy, dy = cur_y - y0; + int cur_w = title_w + dx; if( cur_w < 1 ) cur_w = 1; + int cur_h = title_h - dy; if( cur_h < 1 ) cur_h = 1; + this->title_w->update((int64_t)(client->config.title_w = cur_w)); + this->title_y->update((int64_t)(client->config.title_y = cur_y)); + this->title_h->update((int64_t)(client->config.title_h = cur_h)); + break; } + case 4: { // x2,y1 + int cur_x = cursor_x - drag_dx, dx = cur_x - x2; + if( !dx ) return 1; + int cur_w = title_w + dx; if( cur_w < 1 ) cur_w = 1; + this->title_w->update((int64_t)(client->config.title_w = cur_w)); + break; } + case 5: { // x2,y2 + int cur_x = cursor_x - drag_dx, dx = cur_x - x2; + int cur_y = cursor_y - drag_dy, dy = cur_y - y2; + int cur_w = title_w + dx; if( cur_w < 1 ) cur_w = 1; + int cur_h = title_h + dy; if( cur_h < 1 ) cur_h = 1; + this->title_w->update((int64_t)(client->config.title_w = cur_w)); + this->title_h->update((int64_t)(client->config.title_h = cur_h)); + break; } + case 6: { // x1,y2 + int cur_y = cursor_y - drag_dy, dy = cur_y - y2; + if( client->config.title_h == cur_y ) return 1; + int cur_h = title_h + dy; if( cur_h < 1 ) cur_h = 1; + this->title_h->update((int64_t)(client->config.title_h = cur_h)); + break; } + case 7: { // x0,y2 + int cur_x = cursor_x - drag_dx, dx = cur_x - x0; + int cur_y = cursor_y - drag_dy, dy = cur_y - y2; + int cur_w = title_w - dx; if( cur_w < 1 ) cur_w = 1; + int cur_h = title_h + dy; if( cur_h < 1 ) cur_h = 1; + this->title_x->update((int64_t)(client->config.title_x = cur_x)); + this->title_w->update((int64_t)(client->config.title_w = cur_w)); + this->title_h->update((int64_t)(client->config.title_h = cur_h)); + break; } + case 8: { // x0,y1 + int cur_x = cursor_x - drag_dx, dx = cur_x - x0; + if( !dx ) return 1; + int cur_w = title_w - dx; if( cur_w < 1 ) cur_w = 1; + this->title_x->update((int64_t)(client->config.title_x = cur_x)); + this->title_w->update((int64_t)(client->config.title_w = cur_w)); + break; } + case 9: { // x1,y1 + int cur_x = cursor_x - drag_dx, dx = cur_x - x1; + int cur_y = cursor_y - drag_dy, dy = cur_y - y1; + if( title_x == cur_x && title_y == cur_y ) return 1; + this->title_x->update((int64_t)(client->config.title_x += dx)); + this->title_y->update((int64_t)(client->config.title_y += dy)); + } + } + client->send_configure_change(); + return 1; +} void TitleWindow::previous_font() { int current_font = font->get_number(); current_font--; - if(current_font < 0) current_font = fonts.total - 1; + if( current_font < 0 ) current_font = fonts.total - 1; - if(current_font < 0 || current_font >= fonts.total) return; + if( current_font < 0 || current_font >= fonts.total ) return; - for(int i = 0; i < fonts.total; i++) - { + for( int i=0; iset_selected(i == current_font); } @@ -460,12 +577,11 @@ void TitleWindow::next_font() { int current_font = font->get_number(); current_font++; - if(current_font >= fonts.total) current_font = 0; + if( current_font >= fonts.total ) current_font = 0; - if(current_font < 0 || current_font >= fonts.total) return; + if( current_font < 0 || current_font >= fonts.total ) return; - for(int i = 0; i < fonts.total; i++) - { + for( int i=0; iset_selected(i == current_font); } @@ -502,36 +618,34 @@ void TitleWindow::update_justification() void TitleWindow::update() { - title_x->update((int64_t)client->config.x); - title_y->update((int64_t)client->config.y); + title_x->update((int64_t)client->config.title_x); + title_y->update((int64_t)client->config.title_y); + title_w->update((int64_t)client->config.title_w); + title_h->update((int64_t)client->config.title_h); italic->update(client->config.style & BC_FONT_ITALIC); bold->update(client->config.style & BC_FONT_BOLD); -#ifdef USE_OUTLINE - stroke->update(client->config.style & BC_FONT_OUTLINE); -#endif size->update(client->config.size); -#ifndef X_HAVE_UTF8_STRING - encoding->update(client->config.encoding); -#endif motion->update(TitleMain::motion_to_text(client->config.motion_strategy)); loop->update(client->config.loop); - dropshadow->update((float)client->config.dropshadow); + dropshadow->update((int64_t)client->config.dropshadow); fade_in->update((float)client->config.fade_in); fade_out->update((float)client->config.fade_out); -#ifdef USE_OUTLINE - stroke_width->update((float)client->config.stroke_width); -#endif font->update(client->config.font); text->update(&client->config.wtext[0]); speed->update(client->config.pixels_per_second); outline->update((int64_t)client->config.outline_size); +#ifdef USE_STOKER + stroker->update((int64_t)client->config.stroke_width); +#endif timecode->update(client->config.timecode); timecode_format->update(client->config.timecode_format); + background->update(client->config.background); + background_path->update(client->config.background_path); + loop_playback->update((int64_t)client->config.loop_playback); char string[BCTEXTLEN]; - for(int i = 0; i < lengthof(timeunit_formats); i++) { - if(timeunit_formats[i] == client->config.timecode_format) - { + for( int i=0; iconfig.timecode_format ) { timecode_format->set_text( Units::print_time_format(timeunit_formats[i], string)); break; @@ -573,19 +687,17 @@ int TitleSizeTumble::handle_up_event() { int current_index = -1; int current_difference = -1; - for(int i = 0; i < window->sizes.size(); i++) - { + for( int i=0; isizes.size(); ++i ) { int size = atoi(window->sizes.get(i)->get_text()); - if(current_index < 0 || - abs(size - client->config.size) < current_difference) - { + if( current_index < 0 || + abs(size - client->config.size) < current_difference ) { current_index = i; current_difference = abs(size - client->config.size); } } current_index++; - if(current_index >= window->sizes.size()) current_index = 0; + if( current_index >= window->sizes.size() ) current_index = 0; client->config.size = atoi(window->sizes.get(current_index)->get_text()); @@ -598,19 +710,17 @@ int TitleSizeTumble::handle_down_event() { int current_index = -1; int current_difference = -1; - for(int i = 0; i < window->sizes.size(); i++) - { + for( int i=0; isizes.size(); ++i ) { int size = atoi(window->sizes.get(i)->get_text()); - if(current_index < 0 || - abs(size - client->config.size) < current_difference) - { + if( current_index < 0 || + abs(size - client->config.size) < current_difference ) { current_index = i; current_difference = abs(size - client->config.size); } } current_index--; - if(current_index < 0) current_index = window->sizes.size() - 1; + if( current_index < 0 ) current_index = window->sizes.size() - 1; client->config.size = atoi(window->sizes.get(current_index)->get_text()); @@ -684,7 +794,6 @@ void TitleSize::update(int size) TitlePitch:: TitlePitch(TitleMain *client, TitleWindow *window, int x, int y, int *value) : BC_TumbleTextBox(window, *value, 0, INT_MAX, x, y, 64) - { this->client = client; this->window = window; @@ -698,41 +807,41 @@ TitlePitch:: int TitlePitch::handle_event() { - *value = atof(get_text()); + *value = atol(get_text()); client->send_configure_change(); return 1; } -TitleColorButton::TitleColorButton(TitleMain *client, - TitleWindow *window, - int x, - int y, - int is_outline) - : BC_GenericButton(x, y, is_outline ? _("Outline color...") : _("Color...")) +TitleColorButton::TitleColorButton(TitleMain *client, TitleWindow *window, int x, int y) + : BC_GenericButton(x, y, _("Color...")) { this->client = client; this->window = window; - this->is_outline = is_outline; } int TitleColorButton::handle_event() { - if(is_outline) - window->outline_color_thread->start_window(client->config.outline_color, - client->config.outline_alpha); - else - window->color_thread->start_window(client->config.color, - client->config.alpha); + window->color_thread->start_window(client->config.color, + client->config.alpha); + return 1; +} +TitleOutlineColorButton::TitleOutlineColorButton(TitleMain *client, TitleWindow *window, int x, int y) + : BC_GenericButton(x, y, _("Outline color...")) +{ + this->client = client; + this->window = window; +} +int TitleOutlineColorButton::handle_event() +{ + window->outline_color_thread->start_window(client->config.outline_color, + client->config.outline_alpha); return 1; } + TitleMotion::TitleMotion(TitleMain *client, TitleWindow *window, int x, int y) - : BC_PopupTextBox(window, - &window->paths, + : BC_PopupTextBox(window, &window->paths, client->motion_to_text(client->config.motion_strategy), - x, - y, - 120, - 100) + x, y, 120, 100) { this->client = client; this->window = window; @@ -783,7 +892,7 @@ int TitleTimecodeFormat::handle_event() void TitleTimecodeFormat::create_objects() { char string[BCTEXTLEN]; - for(int i = 0; i < lengthof(timeunit_formats); i++) { + for( int i=0; iclient = client; this->window = window; this->value = value; + set_precision(2); } int TitleFade::handle_event() @@ -823,14 +929,8 @@ int TitleFade::handle_event() } TitleFont::TitleFont(TitleMain *client, TitleWindow *window, int x, int y) - : BC_PopupTextBox(window, - &window->fonts, - client->config.font, - x, - y, - 200, - 500, - LISTBOX_ICON_LIST) + : BC_PopupTextBox(window, &window->fonts, client->config.font, + x, y, 200, 500, LISTBOX_ICON_LIST) { this->client = client; this->window = window; @@ -842,8 +942,8 @@ int TitleFont::handle_event() return 1; } -TitleText::TitleText(TitleMain *client, - TitleWindow *window, int x, int y, int w, int h) +TitleText::TitleText(TitleMain *client, TitleWindow *window, + int x, int y, int w, int h) : BC_ScrollTextBox(window, x, y, w, BC_TextBox::pixels_to_rows(window, MEDIUMFONT, h), client->config.wtext, 8192) @@ -853,6 +953,16 @@ TitleText::TitleText(TitleMain *client, //printf("TitleText::TitleText %s\n", client->config.text); } +int TitleText::button_press_event() +{ + if( get_buttonpress() == 3 ) { + window->cur_ibeam = get_ibeam_letter(); + window->cur_popup->activate_menu(); + return 1; + } + return BC_ScrollTextBox::button_press_event(); +} + int TitleText::handle_event() { int len = sizeof(client->config.wtext) / sizeof(wchar_t); @@ -865,13 +975,8 @@ int TitleText::handle_event() TitleDropShadow::TitleDropShadow(TitleMain *client, TitleWindow *window, int x, int y) - : BC_TumbleTextBox(window, - (int64_t)client->config.dropshadow, - (int64_t)-1000, - (int64_t)1000, - x, - y, - 70) + : BC_TumbleTextBox(window, (int64_t)client->config.dropshadow, + (int64_t)-1000, (int64_t)1000, x, y, 70) { this->client = client; this->window = window; @@ -885,13 +990,8 @@ int TitleDropShadow::handle_event() TitleOutline::TitleOutline(TitleMain *client, TitleWindow *window, int x, int y) - : BC_TumbleTextBox(window, - (int64_t)client->config.outline_size, - (int64_t)0, - (int64_t)1000, - x, - y, - 70) + : BC_TumbleTextBox(window, (int64_t)client->config.outline_size, + (int64_t)0, (int64_t)1000, x, y, 70) { this->client = client; this->window = window; @@ -903,78 +1003,88 @@ int TitleOutline::handle_event() return 1; } +TitleStroker::TitleStroker(TitleMain *client, TitleWindow *window, int x, int y) + : BC_TumbleTextBox(window, (int64_t)client->config.stroke_width, + (int64_t)0, (int64_t)1000, x, y, 70) +{ + this->client = client; + this->window = window; +} +int TitleStroker::handle_event() +{ + client->config.stroke_width = atol(get_text()); + if( client->config.stroke_width > 1 ) + client->config.style |= BC_FONT_OUTLINE; + else + client->config.style &= ~BC_FONT_OUTLINE; + client->send_configure_change(); + return 1; +} + TitleX::TitleX(TitleMain *client, TitleWindow *window, int x, int y) - : BC_TumbleTextBox(window, - (int64_t)client->config.x, - (int64_t)-2048, - (int64_t)2048, - x, - y, - 60) + : BC_TumbleTextBox(window, (int64_t)client->config.title_x, + (int64_t)-32767, (int64_t)32767, x, y, 50) { this->client = client; this->window = window; } int TitleX::handle_event() { - client->config.x = atol(get_text()); + client->config.title_x = atol(get_text()); client->send_configure_change(); return 1; } TitleY::TitleY(TitleMain *client, TitleWindow *window, int x, int y) - : BC_TumbleTextBox(window, - (int64_t)client->config.y, - (int64_t)-2048, - (int64_t)2048, - x, - y, - 60) + : BC_TumbleTextBox(window, (int64_t)client->config.title_y, + (int64_t)-32767, (int64_t)32767, x, y, 50) { this->client = client; this->window = window; } int TitleY::handle_event() { - client->config.y = atol(get_text()); + client->config.title_y = atol(get_text()); client->send_configure_change(); return 1; } -TitleStrokeW::TitleStrokeW(TitleMain *client, - TitleWindow *window, - int x, - int y) - : BC_TumbleTextBox(window, - (float)client->config.stroke_width, - (float)-2048, - (float)2048, - x, - y, - 60) +TitleW::TitleW(TitleMain *client, TitleWindow *window, int x, int y) + : BC_TumbleTextBox(window, (int64_t)client->config.title_w, + (int64_t)0, (int64_t)32767, x, y, 50) { this->client = client; this->window = window; } -int TitleStrokeW::handle_event() +int TitleW::handle_event() { - client->config.stroke_width = atof(get_text()); + client->config.title_w = atol(get_text()); client->send_configure_change(); return 1; } +TitleH::TitleH(TitleMain *client, TitleWindow *window, int x, int y) + : BC_TumbleTextBox(window, (int64_t)client->config.title_h, + (int64_t)0, (int64_t)32767, x, y, 50) +{ + this->client = client; + this->window = window; +} +int TitleH::handle_event() +{ + client->config.title_h = atol(get_text()); + client->send_configure_change(); + return 1; +} TitleSpeed::TitleSpeed(TitleMain *client, TitleWindow *window, int x, int y) - : BC_TumbleTextBox(window, - (float)client->config.pixels_per_second, - (float)0, - (float)1000, - x, - y, - 70) + : BC_TumbleTextBox(window, (float)client->config.pixels_per_second, + (float)0, (float)1000, x, y, 100) { this->client = client; + set_precision(2); + set_increment(10); } @@ -986,11 +1096,6 @@ int TitleSpeed::handle_event() } - - - - - TitleLeft::TitleLeft(TitleMain *client, TitleWindow *window, int x, int y) : BC_Radial(x, y, client->config.hjustification == JUSTIFY_LEFT, _("Left")) { @@ -1089,13 +1194,11 @@ TitleColorThread::TitleColorThread(TitleMain *client, TitleWindow *window, int i int TitleColorThread::handle_new_color(int output, int alpha) { - if(is_outline) - { + if( is_outline ) { client->config.outline_color = output; client->config.outline_alpha = alpha; } - else - { + else { client->config.color = output; client->config.alpha = alpha; } @@ -1106,22 +1209,190 @@ int TitleColorThread::handle_new_color(int output, int alpha) window->unlock_window(); client->send_configure_change(); + return 1; +} +TitleDrag::TitleDrag(TitleMain *client, TitleWindow *window, int x, int y) + : BC_CheckBox(x, y, client->config.drag, _("Drag")) +{ + this->client = client; + this->window = window; +} +int TitleDrag::handle_event() +{ + int value = get_value(); + client->config.drag = value; + if( value ) + window->grab(client->server->mwindow->cwindow->gui); + else + window->ungrab(client->server->mwindow->cwindow->gui); + client->send_configure_change(); return 1; } -TitleColorStrokeThread::TitleColorStrokeThread(TitleMain *client, TitleWindow *window) - : ColorThread() + +TitleBackground::TitleBackground(TitleMain *client, TitleWindow *window, int x, int y) + : BC_CheckBox(x, y, client->config.background, _("Background:")) { this->client = client; this->window = window; } -int TitleColorStrokeThread::handle_event(int output) +int TitleBackground::handle_event() { - client->config.color_stroke = output; - window->update_color(); - window->flush(); + client->config.background = get_value(); + client->send_configure_change(); + return 1; +} + +TitleBackgroundPath::TitleBackgroundPath(TitleMain *client, TitleWindow *window, int x, int y) + : BC_TextBox(x, y, 240, 1, client->config.background_path) +{ + this->client = client; + this->window = window; +} + +int TitleBackgroundPath::handle_event() +{ + strncpy(client->config.background_path, get_text(), sizeof(client->config.background_path)); client->send_configure_change(); return 1; } + +TitleLoopPlayback::TitleLoopPlayback(TitleMain *client, int x, int y) + : BC_CheckBox(x, y, client->config.loop_playback, _("Loop playback")) +{ + this->client = client; +} +int TitleLoopPlayback::handle_event() +{ + client->config.loop_playback = get_value(); + client->send_configure_change(); + return 1; +} + + +TitleCurPopup::TitleCurPopup(TitleMain *client, TitleWindow *window) + : BC_PopupMenu(0, 0, 0, "", 0) +{ + this->client = client; + this->window = window; +} +int TitleCurPopup::handle_event() +{ +printf("cur popup\n"); + return 1; +} +void TitleCurPopup::create_objects() +{ + TitleCurItem *cur_item; + TitleCurSubMenu *sub_menu; + add_item(cur_item = new TitleCurItem(this, "nudge")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"nudge")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/nudge")); + add_item(cur_item = new TitleCurItem(this, "color")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"color")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/color")); + add_item(cur_item = new TitleCurItem(this, "alpha")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"alpha")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/alpha")); + add_item(cur_item = new TitleCurItem(this, "font")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"font")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/font")); + add_item(cur_item = new TitleCurItem(this, "size")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"size")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/size")); + add_item(cur_item = new TitleCurItem(this, "bold")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"bold")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/bold")); + add_item(cur_item = new TitleCurItem(this, "italic")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"italic")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/italic")); + add_item(cur_item = new TitleCurItem(this, "caps")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"caps")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/caps")); + add_item(cur_item = new TitleCurItem(this, "ul")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"ul")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/ul")); + add_item(cur_item = new TitleCurItem(this, "blink")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"blink")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/blink")); + add_item(cur_item = new TitleCurItem(this, "fixed")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"fixed")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/fixed")); + add_item(cur_item = new TitleCurItem(this, "sup")); + cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item)); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"sup")); + sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/sup")); +} + +TitleCurItem::TitleCurItem(TitleCurPopup *popup, const char *text) + : BC_MenuItem(text) +{ + this->popup = popup; +} +int TitleCurItem::handle_event() +{ + return 1; +} + +TitleCurSubMenu::TitleCurSubMenu(TitleCurItem *cur_item) +{ + this->cur_item = cur_item; +} +TitleCurSubMenu::~TitleCurSubMenu() +{ +} + +TitleCurSubMenuItem::TitleCurSubMenuItem(TitleCurSubMenu *submenu, const char *text) + : BC_MenuItem(text) +{ + this->submenu = submenu; +} +TitleCurSubMenuItem::~TitleCurSubMenuItem() +{ +} +int TitleCurSubMenuItem::handle_event() +{ + char id[BCSTRLEN]; + sprintf(id, "<%s>",get_text()); + int ilen = strlen(id); + TitleMain *client = submenu->cur_item->popup->client; + TitleWindow *window = submenu->cur_item->popup->window; + + wchar_t *wtext = client->config.wtext; + int wsize = sizeof(client->config.wtext)-1; + int wlen = client->config.wlen; + int ibeam_letter = window->cur_ibeam; + if( ibeam_letter < 0 ) ibeam_letter = 0; + if( ibeam_letter > wlen ) ibeam_letter = wlen; + + for( int i=wlen-1, j=wlen+ilen-1; i>=ibeam_letter; --i,--j ) { + if( j >= wsize ) continue; + wtext[j] = wtext[i]; + } + for( int i=ibeam_letter, j=0; j= wsize ) break; + wtext[i] = id[j]; + } + + if( (wlen+=ilen) > wsize ) wlen = wsize; + wtext[wlen] = 0; + window->text->update(wtext); + client->config.wlen = wlen; + client->send_configure_change(); + return 1; +} + + diff --git a/cinelerra-5.1/plugins/titler/titlewindow.h b/cinelerra-5.1/plugins/titler/titlerwindow.h similarity index 74% rename from cinelerra-5.1/plugins/titler/titlewindow.h rename to cinelerra-5.1/plugins/titler/titlerwindow.h index 3680b0ed..cc3734b4 100644 --- a/cinelerra-5.1/plugins/titler/titlewindow.h +++ b/cinelerra-5.1/plugins/titler/titlerwindow.h @@ -31,7 +31,7 @@ class TitleInterlace; #include "colorpicker.h" #include "filexml.h" #include "mutex.h" -#include "title.h" +#include "titler.h" @@ -41,10 +41,12 @@ class TitleFontTumble; class TitleSizeTumble; class TitleItalic; class TitleBold; +class TitleDrag; class TitleSize; class TitlePitch; class TitleEncoding; class TitleColorButton; +class TitleOutlineColorButton; class TitleDropShadow; class TitleMotion; class TitleLoop; @@ -54,6 +56,8 @@ class TitleFont; class TitleText; class TitleX; class TitleY; +class TitleW; +class TitleH; class TitleLeft; class TitleCenter; class TitleRight;class TitleTop; @@ -64,6 +68,14 @@ class TitleSpeed; class TitleTimecode; class TitleTimecodeFormat; class TitleOutline; +class TitleStroker; +class TitleBackground; +class TitleBackgroundPath; +class TitleLoopPlayback; +class TitleCurPopup; +class TitleCurItem; +class TitleCurSubMenu; +class TitleCurSubMenuItem; class TitleWindow : public PluginClientWindow { @@ -73,6 +85,7 @@ public: void create_objects(); int resize_event(int w, int h); + int grab_event(XEvent *event); void update_color(); void update_justification(); void update(); @@ -88,17 +101,26 @@ public: TitleX *title_x; BC_Title *y_title; TitleY *title_y; + BC_Title *w_title; + TitleW *title_w; + BC_Title *h_title; + TitleH *title_h; BC_Title *dropshadow_title; TitleDropShadow *dropshadow; BC_Title *outline_title; TitleOutline *outline; + BC_Title *stroker_title; + TitleStroker *stroker; BC_Title *style_title; TitleItalic *italic; TitleBold *bold; - + TitleDrag *drag; + TitleCurPopup *cur_popup; int color_x, color_y; int outline_color_x, outline_color_y; + int drag_dx, drag_dy, dragging; + BC_Title *size_title; TitleSize *size; TitleSizeTumble *size_tumbler; @@ -108,7 +130,7 @@ public: TitleEncoding *encoding; TitleColorButton *color_button; TitleColorThread *color_thread; - TitleColorButton *outline_color_button; + TitleOutlineColorButton *outline_color_button; TitleColorThread *outline_color_thread; BC_Title *motion_title; TitleMotion *motion; @@ -131,12 +153,16 @@ public: TitleSpeed *speed; TitleTimecode *timecode; TitleTimecodeFormat *timecode_format; + TitleBackground *background; + TitleBackgroundPath *background_path; + TitleLoopPlayback *loop_playback; // Color preview ArrayList sizes; ArrayList encodings; ArrayList paths; ArrayList fonts; + int cur_ibeam; }; @@ -183,6 +209,14 @@ public: TitleMain *client; TitleWindow *window; }; +class TitleDrag : public BC_CheckBox +{ +public: + TitleDrag(TitleMain *client, TitleWindow *window, int x, int y); + int handle_event(); + TitleMain *client; + TitleWindow *window; +}; class TitleSize : public BC_PopupTextBox @@ -221,15 +255,18 @@ public: class TitleColorButton : public BC_GenericButton { public: - TitleColorButton(TitleMain *client, - TitleWindow *window, - int x, - int y, - int is_outline); + TitleColorButton(TitleMain *client, TitleWindow *window, int x, int y); + int handle_event(); + TitleMain *client; + TitleWindow *window; +}; +class TitleOutlineColorButton : public BC_GenericButton +{ +public: + TitleOutlineColorButton(TitleMain *client, TitleWindow *window, int x, int y); int handle_event(); TitleMain *client; TitleWindow *window; - int is_outline; }; class TitleMotion : public BC_PopupTextBox @@ -302,6 +339,7 @@ public: int w, int h); int handle_event(); + int button_press_event(); TitleMain *client; TitleWindow *window; }; @@ -321,11 +359,18 @@ public: TitleMain *client; TitleWindow *window; }; - -class TitleStrokeW : public BC_TumbleTextBox +class TitleW : public BC_TumbleTextBox { public: - TitleStrokeW(TitleMain *client, TitleWindow *window, int x, int y); + TitleW(TitleMain *client, TitleWindow *window, int x, int y); + int handle_event(); + TitleMain *client; + TitleWindow *window; +}; +class TitleH : public BC_TumbleTextBox +{ +public: + TitleH(TitleMain *client, TitleWindow *window, int x, int y); int handle_event(); TitleMain *client; TitleWindow *window; @@ -349,6 +394,15 @@ public: TitleWindow *window; }; +class TitleStroker : public BC_TumbleTextBox +{ +public: + TitleStroker(TitleMain *client, TitleWindow *window, int x, int y); + int handle_event(); + TitleMain *client; + TitleWindow *window; +}; + class TitleSpeed : public BC_TumbleTextBox { public: @@ -406,7 +460,6 @@ public: TitleMain *client; TitleWindow *window; }; - class TitleColorThread : public ColorThread { public: @@ -416,15 +469,70 @@ public: TitleWindow *window; int is_outline; }; +class TitleBackground : public BC_CheckBox +{ +public: + TitleBackground(TitleMain *client, TitleWindow *window, int x, int y); + int handle_event(); + TitleMain *client; + TitleWindow *window; +}; +class TitleBackgroundPath : public BC_TextBox +{ +public: + TitleBackgroundPath(TitleMain *client, TitleWindow *window, int x, int y); + int handle_event(); + TitleMain *client; + TitleWindow *window; +}; +class TitleLoopPlayback : public BC_CheckBox +{ +public: + TitleLoopPlayback(TitleMain *client, int x, int y); + int handle_event(); + TitleMain *client; + TitleWindow *window; +}; -class TitleColorStrokeThread : public ColorThread +class TitleCurPopup : public BC_PopupMenu { public: - TitleColorStrokeThread(TitleMain *client, TitleWindow *window); - int handle_event(int output); + TitleCurPopup(TitleMain *client, TitleWindow *window); + + int handle_event(); + void create_objects(); + TitleMain *client; TitleWindow *window; }; +class TitleCurItem : public BC_MenuItem +{ +public: + TitleCurItem(TitleCurPopup *popup, const char *text); + + int handle_event(); + TitleCurPopup *popup; +}; + +class TitleCurSubMenu : public BC_SubMenu +{ +public: + TitleCurSubMenu(TitleCurItem *cur_item); + ~TitleCurSubMenu(); + + TitleCurItem *cur_item; +}; + +class TitleCurSubMenuItem : public BC_MenuItem +{ +public: + TitleCurSubMenuItem(TitleCurSubMenu *submenu, const char *text); + ~TitleCurSubMenuItem(); + + int handle_event(); + TitleCurSubMenu *submenu; +}; + #endif diff --git a/cinelerra-5.1/plugins/titler/titlewindow.C.stroker b/cinelerra-5.1/plugins/titler/titlewindow.C.stroker deleted file mode 100644 index 1b0d066f..00000000 --- a/cinelerra-5.1/plugins/titler/titlewindow.C.stroker +++ /dev/null @@ -1,904 +0,0 @@ -#include "bcdisplayinfo.h" -#include "language.h" -#include "titlewindow.h" - -#include - - -PLUGIN_THREAD_OBJECT(TitleMain, TitleThread, TitleWindow) - - -TitleWindow::TitleWindow(TitleMain *client, int x, int y) - : BC_Window(client->gui_string, - x, - y, - client->window_w, - client->window_h, - 100, - 100, - 1, - 0, - 1) -{ - this->client = client; -} - -TitleWindow::~TitleWindow() -{ - sizes.remove_all_objects(); - encodings.remove_all_objects(); - delete color_thread; -#ifdef USE_OUTLINE - delete color_stroke_thread; -#endif - delete title_x; - delete title_y; -} - -int TitleWindow::create_objects() -{ - int x = 10, y = 10; - - encodings.append(new BC_ListBoxItem("ISO8859-1")); - encodings.append(new BC_ListBoxItem("ISO8859-2")); - encodings.append(new BC_ListBoxItem("ISO8859-3")); - encodings.append(new BC_ListBoxItem("ISO8859-4")); - encodings.append(new BC_ListBoxItem("ISO8859-5")); - encodings.append(new BC_ListBoxItem("ISO8859-6")); - encodings.append(new BC_ListBoxItem("ISO8859-7")); - encodings.append(new BC_ListBoxItem("ISO8859-8")); - encodings.append(new BC_ListBoxItem("ISO8859-9")); - encodings.append(new BC_ListBoxItem("ISO8859-10")); - encodings.append(new BC_ListBoxItem("ISO8859-11")); - encodings.append(new BC_ListBoxItem("ISO8859-12")); - encodings.append(new BC_ListBoxItem("ISO8859-13")); - encodings.append(new BC_ListBoxItem("ISO8859-14")); - encodings.append(new BC_ListBoxItem("ISO8859-15")); - encodings.append(new BC_ListBoxItem("KOI8")); - - - - sizes.append(new BC_ListBoxItem("8")); - sizes.append(new BC_ListBoxItem("9")); - sizes.append(new BC_ListBoxItem("10")); - sizes.append(new BC_ListBoxItem("11")); - sizes.append(new BC_ListBoxItem("12")); - sizes.append(new BC_ListBoxItem("13")); - sizes.append(new BC_ListBoxItem("14")); - sizes.append(new BC_ListBoxItem("16")); - sizes.append(new BC_ListBoxItem("18")); - sizes.append(new BC_ListBoxItem("20")); - sizes.append(new BC_ListBoxItem("22")); - sizes.append(new BC_ListBoxItem("24")); - sizes.append(new BC_ListBoxItem("26")); - sizes.append(new BC_ListBoxItem("28")); - sizes.append(new BC_ListBoxItem("32")); - sizes.append(new BC_ListBoxItem("36")); - sizes.append(new BC_ListBoxItem("40")); - sizes.append(new BC_ListBoxItem("48")); - sizes.append(new BC_ListBoxItem("56")); - sizes.append(new BC_ListBoxItem("64")); - sizes.append(new BC_ListBoxItem("72")); - sizes.append(new BC_ListBoxItem("100")); - sizes.append(new BC_ListBoxItem("128")); - - paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(NO_MOTION))); - paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(BOTTOM_TO_TOP))); - paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(TOP_TO_BOTTOM))); - paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(RIGHT_TO_LEFT))); - paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(LEFT_TO_RIGHT))); - - - -// Construct font list - for(int i = 0; i < client->fonts->total; i++) - { - int exists = 0; - for(int j = 0; j < fonts.total; j++) - { - if(!strcasecmp(fonts.values[j]->get_text(), - client->fonts->values[i]->fixed_title)) - { - exists = 1; - break; - } - } - - if(!exists) fonts.append(new - BC_ListBoxItem(client->fonts->values[i]->fixed_title)); - } - -// Sort font list - int done = 0; - while(!done) - { - done = 1; - for(int i = 0; i < fonts.total - 1; i++) - { - if(strcmp(fonts.values[i]->get_text(), fonts.values[i + 1]->get_text()) > 0) - { - BC_ListBoxItem *temp = fonts.values[i + 1]; - fonts.values[i + 1] = fonts.values[i]; - fonts.values[i] = temp; - done = 0; - } - } - } - - - - - - - - - - - - - add_tool(font_title = new BC_Title(x, y, _("Font:"))); - font = new TitleFont(client, this, x, y + 20); - font->create_objects(); - x += 230; - add_subwindow(font_tumbler = new TitleFontTumble(client, this, x, y + 20)); - x += 30; - char string[BCTEXTLEN]; - add_tool(size_title = new BC_Title(x, y, _("Size:"))); - sprintf(string, "%d", client->config.size); - size = new TitleSize(client, this, x, y + 20, string); - size->create_objects(); - x += 140; - - add_tool(style_title = new BC_Title(x, y, _("Style:"))); - add_tool(italic = new TitleItalic(client, this, x, y + 20)); - add_tool(bold = new TitleBold(client, this, x, y + 50)); -#ifdef USE_OUTLINE - add_tool(stroke = new TitleStroke(client, this, x, y + 80)); -#endif - x += 90; - add_tool(justify_title = new BC_Title(x, y, _("Justify:"))); - add_tool(left = new TitleLeft(client, this, x, y + 20)); - add_tool(center = new TitleCenter(client, this, x, y + 50)); - add_tool(right = new TitleRight(client, this, x, y + 80)); - - x += 80; - add_tool(top = new TitleTop(client, this, x, y + 20)); - add_tool(mid = new TitleMid(client, this, x, y + 50)); - add_tool(bottom= new TitleBottom(client, this, x, y + 80)); - - - - y += 50; - x = 10; - - add_tool(x_title = new BC_Title(x, y, _("X:"))); - title_x = new TitleX(client, this, x, y + 20); - title_x->create_objects(); - x += 90; - - add_tool(y_title = new BC_Title(x, y, _("Y:"))); - title_y = new TitleY(client, this, x, y + 20); - title_y->create_objects(); - x += 90; - - add_tool(motion_title = new BC_Title(x, y, _("Motion type:"))); - - motion = new TitleMotion(client, this, x, y + 20); - motion->create_objects(); - x += 150; - - add_tool(loop = new TitleLoop(client, x, y + 20)); - x += 100; - - x = 10; - y += 50; - - add_tool(dropshadow_title = new BC_Title(x, y, _("Drop shadow:"))); - dropshadow = new TitleDropShadow(client, this, x, y + 20); - dropshadow->create_objects(); - x += 100; - - add_tool(fadein_title = new BC_Title(x, y, _("Fade in (sec):"))); - add_tool(fade_in = new TitleFade(client, this, &client->config.fade_in, x, y + 20)); - x += 100; - - add_tool(fadeout_title = new BC_Title(x, y, _("Fade out (sec):"))); - add_tool(fade_out = new TitleFade(client, this, &client->config.fade_out, x, y + 20)); - x += 110; - - add_tool(speed_title = new BC_Title(x, y, _("Speed:"))); - speed = new TitleSpeed(client, this, x, y + 20); - speed->create_objects(); - x += 110; - - add_tool(color_button = new TitleColorButton(client, this, x, y + 20)); - x += 90; - color_x = x; - color_y = y + 20; - color_thread = new TitleColorThread(client, this); - - x = 10; - y += 50; - add_tool(encoding_title = new BC_Title(x, y + 3, _("Encoding:"))); - encoding = new TitleEncoding(client, this, x, y + 20); - encoding->create_objects(); - -#ifdef USE_OUTLINE - x += 160; - add_tool(strokewidth_title = new BC_Title(x, y, _("Outline width:"))); - stroke_width = new TitleStrokeW(client, - this, - x, - y + 20); - stroke_width->create_objects(); - - x += 210; - add_tool(color_stroke_button = new TitleColorStrokeButton(client, - this, - x, - y + 20)); - color_stroke_x = color_x; - color_stroke_y = y + 20; - color_stroke_thread = new TitleColorStrokeThread(client, this); -#endif - - - x = 10; - y += 50; - - add_tool(text_title = new BC_Title(x, y + 3, _("Text:"))); - - x += 100; - add_tool(timecode = new TitleTimecode(client, x, y)); - - - - x = 10; - y += 30; - text = new TitleText(client, - this, - x, - y, - get_w() - x - 10, - get_h() - y - 20 - 10); - text->create_objects(); - - update_color(); - - show_window(); - flush(); - return 0; -} - -int TitleWindow::resize_event(int w, int h) -{ - client->window_w = w; - client->window_h = h; - - clear_box(0, 0, w, h); - font_title->reposition_window(font_title->get_x(), font_title->get_y()); - font->reposition_window(font->get_x(), font->get_y()); - font_tumbler->reposition_window(font_tumbler->get_x(), font_tumbler->get_y()); - x_title->reposition_window(x_title->get_x(), x_title->get_y()); - title_x->reposition_window(title_x->get_x(), title_x->get_y()); - y_title->reposition_window(y_title->get_x(), y_title->get_y()); - title_y->reposition_window(title_y->get_x(), title_y->get_y()); - style_title->reposition_window(style_title->get_x(), style_title->get_y()); - italic->reposition_window(italic->get_x(), italic->get_y()); - bold->reposition_window(bold->get_x(), bold->get_y()); -#ifdef USE_OUTLINE - stroke->reposition_window(stroke->get_x(), stroke->get_y()); -#endif - size_title->reposition_window(size_title->get_x(), size_title->get_y()); - size->reposition_window(size->get_x(), size->get_y()); - encoding_title->reposition_window(encoding_title->get_x(), encoding_title->get_y()); - encoding->reposition_window(encoding->get_x(), encoding->get_y()); - color_button->reposition_window(color_button->get_x(), color_button->get_y()); -#ifdef USE_OUTLINE - color_stroke_button->reposition_window(color_stroke_button->get_x(), color_stroke_button->get_y()); -#endif - motion_title->reposition_window(motion_title->get_x(), motion_title->get_y()); - motion->reposition_window(motion->get_x(), motion->get_y()); - loop->reposition_window(loop->get_x(), loop->get_y()); - dropshadow_title->reposition_window(dropshadow_title->get_x(), dropshadow_title->get_y()); - dropshadow->reposition_window(dropshadow->get_x(), dropshadow->get_y()); - fadein_title->reposition_window(fadein_title->get_x(), fadein_title->get_y()); - fade_in->reposition_window(fade_in->get_x(), fade_in->get_y()); - fadeout_title->reposition_window(fadeout_title->get_x(), fadeout_title->get_y()); - fade_out->reposition_window(fade_out->get_x(), fade_out->get_y()); - text_title->reposition_window(text_title->get_x(), text_title->get_y()); -#ifdef USE_OUTLINE - stroke_width->reposition_window(stroke_width->get_x(), stroke_width->get_y()); - strokewidth_title->reposition_window(strokewidth_title->get_x(), strokewidth_title->get_y()); -#endif - timecode->reposition_window(timecode->get_x(), timecode->get_y()); - - text->reposition_window(text->get_x(), - text->get_y(), - w - text->get_x() - 10, - BC_TextBox::pixels_to_rows(this, MEDIUMFONT, h - text->get_y() - 10)); - - - - justify_title->reposition_window(justify_title->get_x(), justify_title->get_y()); - left->reposition_window(left->get_x(), left->get_y()); - center->reposition_window(center->get_x(), center->get_y()); - right->reposition_window(right->get_x(), right->get_y()); - top->reposition_window(top->get_x(), top->get_y()); - mid->reposition_window(mid->get_x(), mid->get_y()); - bottom->reposition_window(bottom->get_x(), bottom->get_y()); - speed_title->reposition_window(speed_title->get_x(), speed_title->get_y()); - speed->reposition_window(speed->get_x(), speed->get_y()); - update_color(); - flash(); - - return 1; -} - - -void TitleWindow::previous_font() -{ - int current_font = font->get_number(); - current_font--; - if(current_font < 0) current_font = fonts.total - 1; - - if(current_font < 0 || current_font >= fonts.total) return; - - for(int i = 0; i < fonts.total; i++) - { - fonts.values[i]->set_selected(i == current_font); - } - - font->update(fonts.values[current_font]->get_text()); - strcpy(client->config.font, fonts.values[current_font]->get_text()); - client->send_configure_change(); -} - -void TitleWindow::next_font() -{ - int current_font = font->get_number(); - current_font++; - if(current_font >= fonts.total) current_font = 0; - - if(current_font < 0 || current_font >= fonts.total) return; - - for(int i = 0; i < fonts.total; i++) - { - fonts.values[i]->set_selected(i == current_font); - } - - font->update(fonts.values[current_font]->get_text()); - strcpy(client->config.font, fonts.values[current_font]->get_text()); - client->send_configure_change(); -} - - -int TitleWindow::close_event() -{ -// Set result to 1 to indicate a client side close - set_done(1); - return 1; -} - -void TitleWindow::update_color() -{ -//printf("TitleWindow::update_color %x\n", client->config.color); - set_color(client->config.color); - draw_box(color_x, color_y, 100, 30); - flash(color_x, color_y, 100, 30); -#ifdef USE_OUTLINE - set_color(client->config.color_stroke); - draw_box(color_stroke_x, color_stroke_y, 100, 30); - flash(color_stroke_x, color_stroke_y, 100, 30); -#endif -} - -void TitleWindow::update_justification() -{ - left->update(client->config.hjustification == JUSTIFY_LEFT); - center->update(client->config.hjustification == JUSTIFY_CENTER); - right->update(client->config.hjustification == JUSTIFY_RIGHT); - top->update(client->config.vjustification == JUSTIFY_TOP); - mid->update(client->config.vjustification == JUSTIFY_MID); - bottom->update(client->config.vjustification == JUSTIFY_BOTTOM); -} - -void TitleWindow::update() -{ - title_x->update((int64_t)client->config.x); - title_y->update((int64_t)client->config.y); - italic->update(client->config.style & FONT_ITALIC); - bold->update(client->config.style & FONT_BOLD); -#ifdef USE_OUTLINE - stroke->update(client->config.style & FONT_OUTLINE); -#endif - size->update(client->config.size); - encoding->update(client->config.encoding); - motion->update(TitleMain::motion_to_text(client->config.motion_strategy)); - loop->update(client->config.loop); - dropshadow->update((float)client->config.dropshadow); - fade_in->update((float)client->config.fade_in); - fade_out->update((float)client->config.fade_out); -#ifdef USE_OUTLINE - stroke_width->update((float)client->config.stroke_width); -#endif - font->update(client->config.font); - text->update(client->config.text); - speed->update(client->config.pixels_per_second); - update_justification(); - update_color(); -} - - -TitleFontTumble::TitleFontTumble(TitleMain *client, TitleWindow *window, int x, int y) - : BC_Tumbler(x, y) -{ - this->client = client; - this->window = window; -} -int TitleFontTumble::handle_up_event() -{ - window->previous_font(); - return 1; -} - -int TitleFontTumble::handle_down_event() -{ - window->next_font(); - return 1; -} - -TitleBold::TitleBold(TitleMain *client, TitleWindow *window, int x, int y) - : BC_CheckBox(x, y, client->config.style & FONT_BOLD, _("Bold")) -{ - this->client = client; - this->window = window; -} - -int TitleBold::handle_event() -{ - client->config.style = (client->config.style & ~FONT_BOLD) | (get_value() ? FONT_BOLD : 0); - client->send_configure_change(); - return 1; -} - -TitleItalic::TitleItalic(TitleMain *client, TitleWindow *window, int x, int y) - : BC_CheckBox(x, y, client->config.style & FONT_ITALIC, _("Italic")) -{ - this->client = client; - this->window = window; -} -int TitleItalic::handle_event() -{ - client->config.style = (client->config.style & ~FONT_ITALIC) | (get_value() ? FONT_ITALIC : 0); - client->send_configure_change(); - return 1; -} - -TitleStroke::TitleStroke(TitleMain *client, TitleWindow *window, int x, int y) - : BC_CheckBox(x, y, client->config.style & FONT_OUTLINE, _("Outline")) -{ - this->client = client; - this->window = window; -} - -int TitleStroke::handle_event() -{ - client->config.style = - (client->config.style & ~FONT_OUTLINE) | - (get_value() ? FONT_OUTLINE : 0); - client->send_configure_change(); - return 1; -} - - - -TitleSize::TitleSize(TitleMain *client, TitleWindow *window, int x, int y, char *text) - : BC_PopupTextBox(window, - &window->sizes, - text, - x, - y, - 100, - 300) -{ - this->client = client; - this->window = window; -} -TitleSize::~TitleSize() -{ -} -int TitleSize::handle_event() -{ - client->config.size = atol(get_text()); -//printf("TitleSize::handle_event 1 %s\n", get_text()); - client->send_configure_change(); - return 1; -} -void TitleSize::update(int size) -{ - char string[BCTEXTLEN]; - sprintf(string, "%d", size); - BC_PopupTextBox::update(string); -} -TitleEncoding::TitleEncoding(TitleMain *client, TitleWindow *window, int x, int y) - : BC_PopupTextBox(window, - &window->encodings, - client->config.encoding, - x, - y, - 100, - 300) -{ - this->client = client; - this->window = window; -} - -TitleEncoding::~TitleEncoding() -{ -} -int TitleEncoding::handle_event() -{ - strcpy(client->config.encoding, get_text()); - client->send_configure_change(); - return 1; -} - -TitleColorButton::TitleColorButton(TitleMain *client, TitleWindow *window, int x, int y) - : BC_GenericButton(x, y, _("Color...")) -{ - this->client = client; - this->window = window; -} -int TitleColorButton::handle_event() -{ - window->color_thread->start_window(client->config.color, 0); - return 1; -} - -TitleColorStrokeButton::TitleColorStrokeButton(TitleMain *client, TitleWindow *window, int x, int y) - : BC_GenericButton(x, y, _("Outline color...")) -{ - this->client = client; - this->window = window; -} -int TitleColorStrokeButton::handle_event() -{ -#ifdef USE_OUTLINE - window->color_stroke_thread->start_window(client->config.color_stroke, 0); -#endif - return 1; -} - -TitleMotion::TitleMotion(TitleMain *client, TitleWindow *window, int x, int y) - : BC_PopupTextBox(window, - &window->paths, - client->motion_to_text(client->config.motion_strategy), - x, - y, - 120, - 100) -{ - this->client = client; - this->window = window; -} -int TitleMotion::handle_event() -{ - client->config.motion_strategy = client->text_to_motion(get_text()); - client->send_configure_change(); - return 1; -} - -TitleLoop::TitleLoop(TitleMain *client, int x, int y) - : BC_CheckBox(x, y, client->config.loop, _("Loop")) -{ - this->client = client; -} -int TitleLoop::handle_event() -{ - client->config.loop = get_value(); - client->send_configure_change(); - return 1; -} - -TitleTimecode::TitleTimecode(TitleMain *client, int x, int y) - : BC_CheckBox(x, y, client->config.timecode, _("Stamp timecode")) -{ - this->client = client; -} -int TitleTimecode::handle_event() -{ - client->config.timecode = get_value(); - client->send_configure_change(); - return 1; -} - -TitleFade::TitleFade(TitleMain *client, - TitleWindow *window, - double *value, - int x, - int y) - : BC_TextBox(x, y, 90, 1, (float)*value) -{ - this->client = client; - this->window = window; - this->value = value; -} - -int TitleFade::handle_event() -{ - *value = atof(get_text()); - client->send_configure_change(); - return 1; -} - -TitleFont::TitleFont(TitleMain *client, TitleWindow *window, int x, int y) - : BC_PopupTextBox(window, - &window->fonts, - client->config.font, - x, - y, - 200, - 500) -{ - this->client = client; - this->window = window; -} -int TitleFont::handle_event() -{ - strcpy(client->config.font, get_text()); - client->send_configure_change(); - return 1; -} - -TitleText::TitleText(TitleMain *client, - TitleWindow *window, - int x, - int y, - int w, - int h) - : BC_ScrollTextBox(window, - x, - y, - w, - BC_TextBox::pixels_to_rows(window, MEDIUMFONT, h), - client->config.text) -{ - this->client = client; - this->window = window; -//printf("TitleText::TitleText %s\n", client->config.text); -} - -int TitleText::handle_event() -{ - strcpy(client->config.text, get_text()); - client->send_configure_change(); - return 1; -} - - -TitleDropShadow::TitleDropShadow(TitleMain *client, TitleWindow *window, int x, int y) - : BC_TumbleTextBox(window, - (int64_t)client->config.dropshadow, - (int64_t)0, - (int64_t)1000, - x, - y, - 70) -{ - this->client = client; - this->window = window; -} -int TitleDropShadow::handle_event() -{ - client->config.dropshadow = atol(get_text()); - client->send_configure_change(); - return 1; -} - - -TitleX::TitleX(TitleMain *client, TitleWindow *window, int x, int y) - : BC_TumbleTextBox(window, - (int64_t)client->config.x, - (int64_t)-2048, - (int64_t)2048, - x, - y, - 60) -{ - this->client = client; - this->window = window; -} -int TitleX::handle_event() -{ - client->config.x = atol(get_text()); - client->send_configure_change(); - return 1; -} - -TitleY::TitleY(TitleMain *client, TitleWindow *window, int x, int y) - : BC_TumbleTextBox(window, - (int64_t)client->config.y, - (int64_t)-2048, - (int64_t)2048, - x, - y, - 60) -{ - this->client = client; - this->window = window; -} -int TitleY::handle_event() -{ - client->config.y = atol(get_text()); - client->send_configure_change(); - return 1; -} - -TitleStrokeW::TitleStrokeW(TitleMain *client, - TitleWindow *window, - int x, - int y) - : BC_TumbleTextBox(window, - (float)client->config.stroke_width, - (float)-2048, - (float)2048, - x, - y, - 60) -{ - this->client = client; - this->window = window; -} -int TitleStrokeW::handle_event() -{ - client->config.stroke_width = atof(get_text()); - client->send_configure_change(); - return 1; -} - - -TitleSpeed::TitleSpeed(TitleMain *client, TitleWindow *window, int x, int y) - : BC_TumbleTextBox(window, - (float)client->config.pixels_per_second, - (float)0, - (float)1000, - x, - y, - 70) -{ - this->client = client; -} - - -int TitleSpeed::handle_event() -{ - client->config.pixels_per_second = atof(get_text()); - client->send_configure_change(); - return 1; -} - - - - - - - -TitleLeft::TitleLeft(TitleMain *client, TitleWindow *window, int x, int y) - : BC_Radial(x, y, client->config.hjustification == JUSTIFY_LEFT, _("Left")) -{ - this->client = client; - this->window = window; -} -int TitleLeft::handle_event() -{ - client->config.hjustification = JUSTIFY_LEFT; - window->update_justification(); - client->send_configure_change(); - return 1; -} - -TitleCenter::TitleCenter(TitleMain *client, TitleWindow *window, int x, int y) - : BC_Radial(x, y, client->config.hjustification == JUSTIFY_CENTER, _("Center")) -{ - this->client = client; - this->window = window; -} -int TitleCenter::handle_event() -{ - client->config.hjustification = JUSTIFY_CENTER; - window->update_justification(); - client->send_configure_change(); - return 1; -} - -TitleRight::TitleRight(TitleMain *client, TitleWindow *window, int x, int y) - : BC_Radial(x, y, client->config.hjustification == JUSTIFY_RIGHT, _("Right")) -{ - this->client = client; - this->window = window; -} -int TitleRight::handle_event() -{ - client->config.hjustification = JUSTIFY_RIGHT; - window->update_justification(); - client->send_configure_change(); - return 1; -} - - - -TitleTop::TitleTop(TitleMain *client, TitleWindow *window, int x, int y) - : BC_Radial(x, y, client->config.vjustification == JUSTIFY_TOP, _("Top")) -{ - this->client = client; - this->window = window; -} -int TitleTop::handle_event() -{ - client->config.vjustification = JUSTIFY_TOP; - window->update_justification(); - client->send_configure_change(); - return 1; -} - -TitleMid::TitleMid(TitleMain *client, TitleWindow *window, int x, int y) - : BC_Radial(x, y, client->config.vjustification == JUSTIFY_MID, _("Mid")) -{ - this->client = client; - this->window = window; -} -int TitleMid::handle_event() -{ - client->config.vjustification = JUSTIFY_MID; - window->update_justification(); - client->send_configure_change(); - return 1; -} - -TitleBottom::TitleBottom(TitleMain *client, TitleWindow *window, int x, int y) - : BC_Radial(x, y, client->config.vjustification == JUSTIFY_BOTTOM, _("Bottom")) -{ - this->client = client; - this->window = window; -} -int TitleBottom::handle_event() -{ - client->config.vjustification = JUSTIFY_BOTTOM; - window->update_justification(); - client->send_configure_change(); - return 1; -} - - - -TitleColorThread::TitleColorThread(TitleMain *client, TitleWindow *window) - : ColorThread() -{ - this->client = client; - this->window = window; -} - -int TitleColorThread::handle_event(int output) -{ - client->config.color = output; - window->update_color(); - window->flush(); - client->send_configure_change(); - return 1; -} -TitleColorStrokeThread::TitleColorStrokeThread(TitleMain *client, TitleWindow *window) - : ColorThread() -{ - this->client = client; - this->window = window; -} - -int TitleColorStrokeThread::handle_event(int output) -{ - client->config.color_stroke = output; - window->update_color(); - window->flush(); - client->send_configure_change(); - return 1; -} diff --git a/cinelerra-5.1/plugins/titler/titlewindow.h.stroker b/cinelerra-5.1/plugins/titler/titlewindow.h.stroker deleted file mode 100644 index 81eb07e4..00000000 --- a/cinelerra-5.1/plugins/titler/titlewindow.h.stroker +++ /dev/null @@ -1,358 +0,0 @@ -#ifndef TITLEWINDOW_H -#define TITLEWINDOW_H - -#include "guicast.h" - -class TitleThread; -class TitleWindow; -class TitleInterlace; - -#include "../colors/colorpicker.h" -#include "filexml.h" -#include "mutex.h" -#include "title.h" - - -PLUGIN_THREAD_HEADER(TitleMain, TitleThread, TitleWindow) - - - -class TitleFontTumble; -class TitleItalic; -class TitleBold; -class TitleSize; -class TitleEncoding; -class TitleColorButton; -class TitleColorStrokeButton; -class TitleStroke; -class TitleStrokeW; -class TitleDropShadow; -class TitleMotion; -class TitleLoop; -class TitleFade; -class TitleFont; -class TitleText; -class TitleX; -class TitleY; -class TitleLeft; -class TitleCenter; -class TitleRight;class TitleTop; -class TitleMid; -class TitleBottom; -class TitleColorThread; -class TitleColorStrokeThread; -class TitleSpeed; -class TitleTimecode; - -class TitleWindow : public BC_Window -{ -public: - TitleWindow(TitleMain *client, int x, int y); - ~TitleWindow(); - - void create_objects(); - int close_event(); - int resize_event(int w, int h); - void update_color(); - void update_justification(); - void update(); - void previous_font(); - void next_font(); - - TitleMain *client; - - BC_Title *font_title; - TitleFont *font; - TitleFontTumble *font_tumbler; - BC_Title *x_title; - TitleX *title_x; - BC_Title *y_title; - TitleY *title_y; - BC_Title *dropshadow_title; - TitleDropShadow *dropshadow; - BC_Title *style_title; - TitleItalic *italic; - TitleBold *bold; - -#ifdef USE_OUTLINE - TitleStroke *stroke; - TitleColorStrokeButton *color_stroke_button; - TitleColorStrokeThread *color_stroke_thread; - BC_Title *strokewidth_title; - TitleStrokeW *stroke_width; - int color_stroke_x, color_stroke_y; -#endif - - int color_x, color_y; - BC_Title *size_title; - BC_Title *encoding_title; - TitleSize *size; - TitleEncoding *encoding; - TitleColorButton *color_button; - TitleColorThread *color_thread; - BC_Title *motion_title; - TitleMotion *motion; - TitleLoop *loop; - BC_Title *fadein_title; - TitleFade *fade_in; - BC_Title *fadeout_title; - TitleFade *fade_out; - BC_Title *text_title; - TitleText *text; - BC_Title *justify_title; - TitleLeft *left; - TitleCenter *center; - TitleRight *right; - TitleTop *top; - TitleMid *mid; - TitleBottom *bottom; - BC_Title *speed_title; - TitleSpeed *speed; - TitleTimecode *timecode; - -// Color preview - ArrayList sizes; - ArrayList encodings; - ArrayList paths; - ArrayList fonts; -}; - - -class TitleFontTumble : public BC_Tumbler -{ -public: - TitleFontTumble(TitleMain *client, TitleWindow *window, int x, int y); - - int handle_up_event(); - int handle_down_event(); - - TitleMain *client; - TitleWindow *window; -}; - -class TitleItalic : public BC_CheckBox -{ -public: - TitleItalic(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleBold : public BC_CheckBox -{ -public: - TitleBold(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; - -class TitleStroke : public BC_CheckBox -{ -public: - TitleStroke(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; - - -class TitleSize : public BC_PopupTextBox -{ -public: - TitleSize(TitleMain *client, TitleWindow *window, int x, int y, char *text); - ~TitleSize(); - int handle_event(); - void update(int size); - TitleMain *client; - TitleWindow *window; -}; -class TitleEncoding : public BC_PopupTextBox -{ -public: - TitleEncoding(TitleMain *client, TitleWindow *window, int x, int y); - ~TitleEncoding(); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleColorButton : public BC_GenericButton -{ -public: - TitleColorButton(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleColorStrokeButton : public BC_GenericButton -{ -public: - TitleColorStrokeButton(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleMotion : public BC_PopupTextBox -{ -public: - TitleMotion(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleLoop : public BC_CheckBox -{ -public: - TitleLoop(TitleMain *client, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleTimecode : public BC_CheckBox -{ -public: - TitleTimecode(TitleMain *client, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleFade : public BC_TextBox -{ -public: - TitleFade(TitleMain *client, TitleWindow *window, double *value, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; - double *value; -}; -class TitleFont : public BC_PopupTextBox -{ -public: - TitleFont(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleText : public BC_ScrollTextBox -{ -public: - TitleText(TitleMain *client, - TitleWindow *window, - int x, - int y, - int w, - int h); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleX : public BC_TumbleTextBox -{ -public: - TitleX(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleY : public BC_TumbleTextBox -{ -public: - TitleY(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleStrokeW : public BC_TumbleTextBox -{ -public: - TitleStrokeW(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleDropShadow : public BC_TumbleTextBox -{ -public: - TitleDropShadow(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; - -class TitleSpeed : public BC_TumbleTextBox -{ -public: - TitleSpeed(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; -}; - -class TitleLeft : public BC_Radial -{ -public: - TitleLeft(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleCenter : public BC_Radial -{ -public: - TitleCenter(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleRight : public BC_Radial -{ -public: - TitleRight(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; - -class TitleTop : public BC_Radial -{ -public: - TitleTop(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleMid : public BC_Radial -{ -public: - TitleMid(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; -class TitleBottom : public BC_Radial -{ -public: - TitleBottom(TitleMain *client, TitleWindow *window, int x, int y); - int handle_event(); - TitleMain *client; - TitleWindow *window; -}; - -class TitleColorThread : public ColorThread -{ -public: - TitleColorThread(TitleMain *client, TitleWindow *window); - int handle_event(int output); - TitleMain *client; - TitleWindow *window; -}; - -class TitleColorStrokeThread : public ColorThread -{ -public: - TitleColorStrokeThread(TitleMain *client, TitleWindow *window); - int handle_event(int output); - TitleMain *client; - TitleWindow *window; -}; - -#endif diff --git a/cinelerra-5.1/plugins/whirl/whirlwindow.C b/cinelerra-5.1/plugins/whirl/whirlwindow.C index 0465acfe..3efb108d 100644 --- a/cinelerra-5.1/plugins/whirl/whirlwindow.C +++ b/cinelerra-5.1/plugins/whirl/whirlwindow.C @@ -76,6 +76,7 @@ int AngleSlider::handle_event() { client->angle = get_value(); client->send_configure_change(); + return 1; } PinchSlider::PinchSlider(WhirlMain *client, int x, int y) @@ -90,6 +91,7 @@ int PinchSlider::handle_event() { client->pinch = get_value(); client->send_configure_change(); + return 1; } RadiusSlider::RadiusSlider(WhirlMain *client, int x, int y) @@ -104,6 +106,7 @@ int RadiusSlider::handle_event() { client->radius = get_value(); client->send_configure_change(); + return 1; } AutomatedFn::AutomatedFn(WhirlMain *client, WhirlWindow *window, int x, int y, int number) @@ -127,5 +130,6 @@ int AutomatedFn::handle_event() update(1); client->automated_function = number; client->send_configure_change(); + return 1; } diff --git a/cinelerra-5.1/plugins/yuv/yuv.C b/cinelerra-5.1/plugins/yuv/yuv.C index 0e84d90b..28d9fc2a 100644 --- a/cinelerra-5.1/plugins/yuv/yuv.C +++ b/cinelerra-5.1/plugins/yuv/yuv.C @@ -257,8 +257,6 @@ void YUVEffect::read_data(KeyFrame *keyframe) } -static YUV yuv_static; - #define YUV_MACRO(type, temp_type, max, components, use_yuv) \ { \ for(int i = 0; i < input->get_h(); i++) \ @@ -283,16 +281,16 @@ static YUV yuv_static; temp_type y, u, v, r, g, b; \ if(sizeof(type) == 4) \ { \ - yuv_static.rgb_to_yuv_f(in_row[0], in_row[1], in_row[2], y, u, v); \ + YUV::yuv.rgb_to_yuv_f(in_row[0], in_row[1], in_row[2], y, u, v); \ } \ else \ if(sizeof(type) == 2) \ { \ - yuv_static.rgb_to_yuv_16(in_row[0], in_row[1], in_row[2], y, u, v); \ + YUV::yuv.rgb_to_yuv_16(in_row[0], in_row[1], in_row[2], y, u, v); \ } \ else \ { \ - yuv_static.rgb_to_yuv_8(in_row[0], in_row[1], in_row[2], y, u, v); \ + YUV::yuv.rgb_to_yuv_8(in_row[0], in_row[1], in_row[2], y, u, v); \ } \ \ if(sizeof(type) < 4) \ @@ -313,12 +311,12 @@ static YUV yuv_static; } \ \ if(sizeof(type) == 4) \ - yuv_static.yuv_to_rgb_f(r, g, b, y, u, v); \ + YUV::yuv.yuv_to_rgb_f(r, g, b, y, u, v); \ else \ if(sizeof(type) == 2) \ - yuv_static.yuv_to_rgb_16(r, g, b, y, u, v); \ + YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \ else \ - yuv_static.yuv_to_rgb_8(r, g, b, y, u, v); \ + YUV::yuv.yuv_to_rgb_8(r, g, b, y, u, v); \ \ out_row[0] = r; \ out_row[1] = g; \ diff --git a/cinelerra-5.1/plugins/yuv/yuvwindow.C b/cinelerra-5.1/plugins/yuv/yuvwindow.C index 3ca1a579..ae5bb5f0 100644 --- a/cinelerra-5.1/plugins/yuv/yuvwindow.C +++ b/cinelerra-5.1/plugins/yuv/yuvwindow.C @@ -61,6 +61,7 @@ int YUVWindow::close_event() client->save_defaults(); hide_window(); client->send_hide_gui(); + return 1; } YSlider::YSlider(YUVMain *client, int x, int y) @@ -75,6 +76,7 @@ int YSlider::handle_event() { client->y = get_value(); client->send_configure_change(); + return 1; } USlider::USlider(YUVMain *client, int x, int y) @@ -89,6 +91,7 @@ int USlider::handle_event() { client->u = get_value(); client->send_configure_change(); + return 1; } VSlider::VSlider(YUVMain *client, int x, int y) @@ -103,6 +106,7 @@ int VSlider::handle_event() { client->v = get_value(); client->send_configure_change(); + return 1; } AutomatedFn::AutomatedFn(YUVMain *client, YUVWindow *window, int x, int y, int number) @@ -126,5 +130,6 @@ int AutomatedFn::handle_event() update(1); client->automated_function = number; client->send_configure_change(); + return 1; } diff --git a/cinelerra-5.1/plugins/yuvshift/yuvshift.C b/cinelerra-5.1/plugins/yuvshift/yuvshift.C index c13381b0..2b814c03 100644 --- a/cinelerra-5.1/plugins/yuvshift/yuvshift.C +++ b/cinelerra-5.1/plugins/yuvshift/yuvshift.C @@ -269,8 +269,6 @@ void YUVShiftEffect::read_data(KeyFrame *keyframe) } -static YUV yuv_static; - #define YUV_MACRO(type, temp_type, components) \ { \ for(int i = 0; i < h; i++) { \ @@ -310,11 +308,11 @@ static YUV yuv_static; temp_type u = up ? up[1] : 0x80; \ temp_type v = vp ? vp[2] : 0x80; \ if( sizeof(type) == 4 ) \ - yuv_static.yuv_to_rgb_f(r, g, b, y/255., (u-128.)/255., (v-128.)/255.); \ + YUV::yuv.yuv_to_rgb_f(r, g, b, y/255., (u-128.)/255., (v-128.)/255.); \ else if( sizeof(type) == 2 ) \ - yuv_static.yuv_to_rgb_16(r, g, b, y, u, v); \ + YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \ else \ - yuv_static.yuv_to_rgb_8(r, g, b, y, u, v); \ + YUV::yuv.yuv_to_rgb_8(r, g, b, y, u, v); \ out_row[0] = r; \ out_row[1] = g; \ out_row[2] = b; \ -- 2.26.2