4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcdisplayinfo.h"
24 #include "bcsignals.h"
25 #include "attachmentpoint.h"
27 #include "condition.h"
31 #include "edlsession.h"
33 #include "filesystem.h"
35 #include "indexable.h"
37 #include "localsession.h"
41 #include "pluginclient.h"
42 #include "pluginserver.h"
43 #include "preferences.h"
44 #include "renderengine.h"
46 #include "transportque.h"
56 PluginClientFrame::PluginClientFrame()
61 PluginClientFrame::~PluginClientFrame()
66 PluginClientThread::PluginClientThread(PluginClient *client)
69 this->client = client;
71 init_complete = new Condition(0, "PluginClientThread::init_complete");
74 PluginClientThread::~PluginClientThread()
81 void PluginClientThread::run()
85 if(client->window_x < 0) client->window_x = info.get_abs_cursor_x();
86 if(client->window_y < 0) client->window_y = info.get_abs_cursor_y();
88 window = (PluginClientWindow*)client->new_window();
91 window->lock_window("PluginClientThread::run");
92 window->create_objects();
93 VFrame *picon = client->server->get_picon();
94 if( picon ) window->set_icon(picon);
95 window->unlock_window();
97 /* Only set it here so tracking doesn't update it until everything is created. */
98 client->thread = this;
99 init_complete->unlock();
101 result = window->run_window();
102 window->lock_window("PluginClientThread::run");
103 //printf("PluginClientThread::run %p %d\n", this, __LINE__);
104 window->hide_window(1);
105 window->unlock_window();
106 window->done_event(result);
107 // Can't save defaults in the destructor because it's not called immediately
109 /* if(client->defaults) */ client->save_defaults_xml();
110 /* This is needed when the GUI is closed from itself */
111 if(result) client->client_side_close();
116 client->thread = this;
117 init_complete->unlock();
121 BC_WindowBase* PluginClientThread::get_window()
126 PluginClient* PluginClientThread::get_client()
132 PluginClientWindow::PluginClientWindow(PluginClient *client,
133 int w, int h, int min_w, int min_h, int allow_resize)
134 : BC_Window(client->gui_string,
135 client->window_x /* - w / 2 */, client->window_y /* - h / 2 */,
136 w, h, min_w, min_h, allow_resize, 0, 1)
138 this->client = client;
141 PluginClientWindow::PluginClientWindow(const char *title,
142 int x, int y, int w, int h, int min_w, int min_h, int allow_resize)
143 : BC_Window(title, x, y, w, h, min_w, min_h, allow_resize, 0, 1)
148 PluginClientWindow::~PluginClientWindow()
153 int PluginClientWindow::translation_event()
157 client->window_x = get_x();
158 client->window_y = get_y();
164 int PluginClientWindow::close_event()
166 /* Set result to 1 to indicate a client side close */
171 void PluginClientWindow::param_updated()
173 printf("PluginClientWindow::param_updated %d undefined\n", __LINE__);
177 PluginParam::PluginParam(PluginClient *plugin, PluginClientWindow *gui,
178 int x1, int x2, int x3, int y, int text_w,
179 int *output_i, float *output_f, int *output_q,
180 const char *title, float min, float max)
182 this->output_i = output_i;
183 this->output_f = output_f;
184 this->output_q = output_q;
185 this->title = cstrdup(title);
186 this->plugin = plugin;
191 this->text_w = text_w;
201 PluginParam::~PluginParam()
211 void PluginParam::initialize()
215 (BC_Pot::calculate_h() -
216 BC_Title::calculate_h(gui, _(title), MEDIUMFONT)) / 2;
217 gui->add_tool(title_ = new BC_Title(x1, y2, _(title)));
221 gui->add_tool(fpot = new PluginFPot(this, x2, y));
226 gui->add_tool(ipot = new PluginIPot(this, x2, y));
231 gui->add_tool(qpot = new PluginQPot(this, x2, y));
235 (BC_Pot::calculate_h() -
236 BC_TextBox::calculate_h(gui, MEDIUMFONT, 1, 1)) / 2;
239 gui->add_tool(text = new PluginText(this, x3, y3, *output_i));
243 gui->add_tool(text = new PluginText(this, x3, y3, *output_f));
247 gui->add_tool(text = new PluginText(this, x3, y3, *output_q));
250 set_precision(precision);
253 void PluginParam::update(int skip_text, int skip_pot)
259 text->update((int64_t)*output_i);
263 text->update((int64_t)*output_q);
267 text->update((float)*output_f);
275 ipot->update((int64_t)*output_i);
279 qpot->update((int64_t)*output_q);
283 fpot->update((float)*output_f);
288 void PluginParam::set_precision(int digits)
290 this->precision = digits;
295 text->set_precision(digits);
298 fpot->set_precision(1.0f / pow(10, digits));
303 PluginFPot::PluginFPot(PluginParam *param, int x, int y)
314 int PluginFPot::handle_event()
316 *param->output_f = get_value();
318 param->plugin->send_configure_change();
319 param->gui->param_updated();
323 PluginIPot::PluginIPot(PluginParam *param, int x, int y)
334 int PluginIPot::handle_event()
336 *param->output_i = get_value();
338 param->plugin->send_configure_change();
339 param->gui->param_updated();
344 PluginQPot::PluginQPot(PluginParam *param, int x, int y)
353 int PluginQPot::handle_event()
355 *param->output_q = get_value();
357 param->plugin->send_configure_change();
358 param->gui->param_updated();
362 PluginText::PluginText(PluginParam *param, int x, int y, int value)
374 PluginText::PluginText(PluginParam *param, int x, int y, float value)
387 int PluginText::handle_event()
391 *param->output_i = atoi(get_text());
396 *param->output_f = atof(get_text());
401 *param->output_q = atoi(get_text());
404 param->plugin->send_configure_change();
405 param->gui->param_updated();
410 PluginClient::PluginClient(PluginServer *server)
413 this->server = server;
414 smp = server->preferences->project_smp;
416 update_timer = new Timer;
417 // Virtual functions don't work here.
420 PluginClient::~PluginClient()
428 // Virtual functions don't work here.
429 if(defaults) delete defaults;
433 int PluginClient::reset()
442 realtime_priority = 0;
444 total_in_buffers = 0;
445 total_out_buffers = 0;
449 direction = PLAY_FORWARD;
456 void PluginClient::hide_gui()
458 if(thread && thread->window)
460 //printf("PluginClient::delete_thread %d\n", __LINE__);
461 /* This is needed when the GUI is closed from elsewhere than itself */
462 /* Since we now use autodelete, this is all that has to be done, thread will take care of itself ... */
463 /* Thread join will wait if this was not called from the thread itself or go on if it was */
464 thread->window->lock_window("PluginClient::hide_gui");
465 thread->window->set_done(0);
466 //printf("PluginClient::hide_gui %d thread->window=%p\n", __LINE__, thread->window);
467 thread->window->unlock_window();
471 // For realtime plugins initialize buffers
472 int PluginClient::plugin_init_realtime(int realtime_priority,
473 int total_in_buffers,
477 // Get parameters for all
478 master_gui_on = get_gui_status();
482 // get parameters depending on video or audio
483 init_realtime_parameters();
485 this->realtime_priority = realtime_priority;
486 this->total_in_buffers = this->total_out_buffers = total_in_buffers;
487 this->out_buffer_size = this->in_buffer_size = buffer_size;
491 int PluginClient::plugin_start_loop(int64_t start,
496 //printf("PluginClient::plugin_start_loop %d %ld %ld %ld %d\n",
497 // __LINE__, start, end, buffer_size, total_buffers);
498 this->source_start = start;
499 this->total_len = end - start;
502 this->in_buffer_size = this->out_buffer_size = buffer_size;
503 this->total_in_buffers = this->total_out_buffers = total_buffers;
508 int PluginClient::plugin_process_loop()
510 return process_loop();
513 int PluginClient::plugin_stop_loop()
518 MainProgressBar* PluginClient::start_progress(char *string, int64_t length)
520 return server->start_progress(string, length);
524 // Non realtime parameters
525 int PluginClient::plugin_get_parameters()
527 int result = get_parameters();
528 if(defaults) save_defaults();
532 // ========================= main loop
534 int PluginClient::is_multichannel() { return 0; }
535 int PluginClient::is_synthesis() { return 0; }
536 int PluginClient::is_realtime() { return 0; }
537 int PluginClient::is_fileio() { return 0; }
538 const char* PluginClient::plugin_title() { return _("Untitled"); }
540 Theme* PluginClient::new_theme() { return 0; }
542 int PluginClient::load_configuration()
547 Theme* PluginClient::get_theme()
549 return server->get_theme();
552 int PluginClient::show_gui()
554 load_configuration();
555 thread = new PluginClientThread(this);
557 thread->init_complete->lock("PluginClient::show_gui");
558 // Must wait before sending any hide_gui
559 if( !thread->window ) return 1;
560 thread->window->init_wait();
564 void PluginClient::raise_window()
566 if(thread && thread->window)
568 thread->window->lock_window("PluginClient::raise_window");
569 thread->window->raise_window();
570 thread->window->flush();
571 thread->window->unlock_window();
575 int PluginClient::set_string()
579 thread->window->lock_window("PluginClient::set_string");
580 thread->window->put_title(gui_string);
581 thread->window->unlock_window();
590 PluginClientFrames::PluginClientFrames()
594 PluginClientFrames::~PluginClientFrames()
598 int PluginClientFrames::fwd_cmpr(PluginClientFrame *a, PluginClientFrame *b)
600 double d = a->position - b->position;
601 return d < 0 ? -1 : !d ? 0 : 1;
604 int PluginClientFrames::rev_cmpr(PluginClientFrame *a, PluginClientFrame *b)
606 double d = b->position - a->position;
607 return d < 0 ? -1 : !d ? 0 : 1;
610 void PluginClientFrames::reset()
616 void PluginClientFrames::add_gui_frame(PluginClientFrame *frame)
622 void PluginClientFrames::concatenate(PluginClientFrames *frames)
625 count += frames->count;
629 void PluginClientFrames::sort_position(int dir)
632 if( dir == PLAY_REVERSE )
638 // pop frames until buffer passes position=pos in direction=dir
639 // dir==0, pop frame; pos<0, pop all frames
640 // delete past frames, return last popped frame
641 PluginClientFrame* PluginClientFrames::get_gui_frame(double pos, int dir)
644 while( first != last ) {
645 if( pos >= 0 && dir*(first->next->position - pos) > 0 ) break;
646 delete first; --count;
649 PluginClientFrame *frame = first;
650 if( frame ) { remove_pointer(frame); --count; }
654 PluginClientFrame* PluginClient::get_gui_frame(double pos, int dir)
656 return frame_buffer.get_gui_frame(pos, dir);
658 PluginClientFrame* PluginClient::next_gui_frame()
660 return frame_buffer.first;
664 void PluginClient::plugin_update_gui()
669 void PluginClient::update_gui()
673 int PluginClient::pending_gui_frames()
675 PluginClientFrame *frame = frame_buffer.first;
676 if( !frame ) return 0;
677 double tracking_position = get_tracking_position();
678 int direction = get_tracking_direction();
679 int ret = !(direction == PLAY_REVERSE ?
680 frame->position < tracking_position :
681 frame->position > tracking_position);
685 void PluginClient::add_gui_frame(PluginClientFrame *frame)
687 frame_buffer.add_gui_frame(frame);
690 double PluginClient::get_tracking_position()
692 return server->mwindow->get_tracking_position();
695 int PluginClient::get_tracking_direction()
697 return server->mwindow->get_tracking_direction();
700 void PluginClient::send_render_gui()
702 server->send_render_gui(&frame_buffer);
705 void PluginClient::send_render_gui(void *data)
707 server->send_render_gui(data);
710 void PluginClient::send_render_gui(void *data, int size)
712 server->send_render_gui(data, size);
716 void PluginClient::plugin_reset_gui_frames()
718 if( !thread ) return;
719 BC_WindowBase *window = thread->get_window();
720 if( !window ) return;
721 window->lock_window("PluginClient::plugin_reset_gui_frames");
722 frame_buffer.reset();
723 window->unlock_window();
726 void PluginClient::plugin_render_gui_frames(PluginClientFrames *frames)
728 if( !thread ) return;
729 BC_WindowBase *window = thread->get_window();
730 if( !window ) return;
731 window->lock_window("PluginClient::render_gui");
732 while( frame_buffer.count > MAX_FRAME_BUFFER )
733 delete get_gui_frame(0, 0);
734 // append client frames to gui frame_buffer, consumes frames
735 frame_buffer.concatenate(frames);
736 frame_buffer.sort_position(get_tracking_direction());
737 update_timer->update();
738 window->unlock_window();
741 void PluginClient::plugin_render_gui(void *data)
746 void PluginClient::plugin_render_gui(void *data, int size)
748 render_gui(data, size);
751 void PluginClient::render_gui(void *data)
753 printf("PluginClient::render_gui %d\n", __LINE__);
756 void PluginClient::render_gui(void *data, int size)
758 printf("PluginClient::render_gui %d\n", __LINE__);
761 void PluginClient::reset_gui_frames()
763 server->reset_gui_frames();
766 int PluginClient::is_audio() { return 0; }
767 int PluginClient::is_video() { return 0; }
768 int PluginClient::is_theme() { return 0; }
769 int PluginClient::uses_gui() { return 1; }
770 int PluginClient::is_transition() { return 0; }
771 int PluginClient::load_defaults()
773 // printf("PluginClient::load_defaults undefined in %s.\n", plugin_title());
777 int PluginClient::save_defaults()
780 // printf("PluginClient::save_defaults undefined in %s.\n", plugin_title());
784 void PluginClient::load_defaults_xml()
786 char path[BCTEXTLEN];
787 server->get_defaults_path(path);
789 fs.complete_path(path);
791 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
796 int fd = open(path, O_RDONLY);
797 if( fd >= 0 && !fstat(fd, &st) ) {
798 int64_t sz = st.st_size;
799 data = new char[sz+1];
800 len = read(fd, data, sz);
803 if( data && len >= 0 ) {
805 // Get window extents
807 for( int state=0; i<len && state>=0; ++i ) {
808 if( !data[i] || data[i] == '<' ) break;
809 if( !isdigit(data[i]) ) continue;
811 window_x = atoi(data+i);
815 window_y = atoi(data+i);
818 while( i<len && isdigit(data[i]) ) ++i;
820 KeyFrame keyframe(data+i, len-i);
821 read_data(&keyframe);
826 //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path);
829 void PluginClient::save_defaults_xml()
831 char path[BCTEXTLEN];
832 server->get_defaults_path(path);
834 fs.complete_path(path);
837 KeyFrame temp_keyframe;
838 save_data(&temp_keyframe);
840 const char *data = temp_keyframe.get_data();
841 int len = strlen(data);
842 FILE *fp = fopen(path, "w");
845 fprintf(fp, "%d\n%d\n", window_x, window_y);
846 if( len > 0 && !fwrite(data, len, 1, fp) ) {
847 fprintf(stderr, "PluginClient::save_defaults_xml %d \"%s\" %d bytes: %s\n",
848 __LINE__, path, len, strerror(errno));
856 int PluginClient::is_defaults()
858 return using_defaults;
861 BC_Hash* PluginClient::get_defaults()
865 PluginClientThread* PluginClient::get_thread()
870 BC_WindowBase* PluginClient::new_window()
872 printf("PluginClient::new_window undefined in %s.\n", plugin_title());
875 int PluginClient::get_parameters() { return 0; }
876 int PluginClient::get_samplerate() { return get_project_samplerate(); }
877 double PluginClient::get_framerate() { return get_project_framerate(); }
878 int PluginClient::init_realtime_parameters() { return 0; }
879 int PluginClient::delete_nonrealtime_parameters() { return 0; }
880 int PluginClient::start_loop() { return 0; };
881 int PluginClient::process_loop() { return 0; };
882 int PluginClient::stop_loop() { return 0; };
884 void PluginClient::set_interactive()
889 int64_t PluginClient::get_in_buffers(int64_t recommended_size)
891 return recommended_size;
894 int64_t PluginClient::get_out_buffers(int64_t recommended_size)
896 return recommended_size;
899 int PluginClient::get_gui_status()
901 return server->get_gui_status();
904 // close event from client side
905 void PluginClient::client_side_close()
907 // Last command executed
908 server->client_side_close();
911 int PluginClient::stop_gui_client()
913 if(!client_gui_on) return 0;
918 int PluginClient::get_project_samplerate()
920 return server->get_project_samplerate();
923 double PluginClient::get_project_framerate()
925 return server->get_project_framerate();
928 const char *PluginClient::get_source_path()
930 if( server->plugin ) return 0;
931 int64_t source_position = server->plugin->startproject;
932 Edit *edit = server->plugin->track->edits->editof(source_position,PLAY_FORWARD,0);
933 Indexable *indexable = edit ? edit->get_source() : 0;
934 return indexable ? indexable->path : 0;
938 void PluginClient::update_display_title()
940 server->generate_display_title(gui_string);
944 char* PluginClient::get_gui_string()
950 char* PluginClient::get_path()
955 char* PluginClient::get_plugin_dir()
957 return server->preferences->plugin_dir;
960 int PluginClient::set_string_client(char *string)
962 strcpy(gui_string, string);
968 int PluginClient::get_interpolation_type()
970 return server->get_interpolation_type();
974 float PluginClient::get_red()
976 EDL *edl = get_edl();
977 return edl->local_session->use_max ?
978 edl->local_session->red_max :
979 edl->local_session->red;
982 float PluginClient::get_green()
984 EDL *edl = get_edl();
985 return edl->local_session->use_max ?
986 edl->local_session->green_max :
987 edl->local_session->green;
990 float PluginClient::get_blue()
992 EDL *edl = get_edl();
993 return edl->local_session->use_max ?
994 edl->local_session->blue_max :
995 edl->local_session->blue;
999 int64_t PluginClient::get_source_position()
1001 return source_position;
1004 int64_t PluginClient::get_source_start()
1006 return source_start;
1009 int64_t PluginClient::get_total_len()
1014 int PluginClient::get_direction()
1019 int64_t PluginClient::local_to_edl(int64_t position)
1024 int64_t PluginClient::edl_to_local(int64_t position)
1029 int PluginClient::get_use_opengl()
1031 return server->get_use_opengl();
1034 int PluginClient::get_total_buffers()
1036 return total_in_buffers;
1039 int PluginClient::get_buffer_size()
1041 return in_buffer_size;
1044 int PluginClient::get_project_smp()
1046 //printf("PluginClient::get_project_smp %d %d\n", __LINE__, smp);
1050 const char* PluginClient::get_defaultdir()
1052 return File::get_plugin_path();
1056 int PluginClient::send_hide_gui()
1058 // Stop the GUI server and delete GUI messages
1063 int PluginClient::send_configure_change()
1066 server->mwindow->undo->update_undo_before(_("tweek"), this);
1067 #ifdef USE_KEYFRAME_SPANNING
1069 save_data(&keyframe);
1070 server->apply_keyframe(&keyframe);
1072 KeyFrame* keyframe = server->get_keyframe();
1073 // Call save routine in plugin
1074 save_data(keyframe);
1077 server->mwindow->undo->update_undo_after(_("tweek"), LOAD_AUTOMATION);
1078 server->sync_parameters();
1083 KeyFrame* PluginClient::get_prev_keyframe(int64_t position, int is_local)
1085 if(is_local) position = local_to_edl(position);
1086 return server->get_prev_keyframe(position);
1089 KeyFrame* PluginClient::get_next_keyframe(int64_t position, int is_local)
1091 if(is_local) position = local_to_edl(position);
1092 return server->get_next_keyframe(position);
1095 void PluginClient::get_camera(float *x, float *y, float *z, int64_t position)
1097 server->get_camera(x, y, z, position, direction);
1100 void PluginClient::get_projector(float *x, float *y, float *z, int64_t position)
1102 server->get_projector(x, y, z, position, direction);
1106 void PluginClient::output_to_track(float ox, float oy, float &tx, float &ty)
1108 float projector_x, projector_y, projector_z;
1109 int64_t position = get_source_position();
1110 get_projector(&projector_x, &projector_y, &projector_z, position);
1111 EDL *edl = get_edl();
1112 projector_x += edl->session->output_w / 2;
1113 projector_y += edl->session->output_h / 2;
1114 Track *track = server->plugin ? server->plugin->track : 0;
1115 int track_w = track ? track->track_w : edl->session->output_w;
1116 int track_h = track ? track->track_h : edl->session->output_h;
1117 tx = (ox - projector_x) / projector_z + track_w / 2;
1118 ty = (oy - projector_y) / projector_z + track_h / 2;
1121 void PluginClient::track_to_output(float tx, float ty, float &ox, float &oy)
1123 float projector_x, projector_y, projector_z;
1124 int64_t position = get_source_position();
1125 get_projector(&projector_x, &projector_y, &projector_z, position);
1126 EDL *edl = get_edl();
1127 projector_x += edl->session->output_w / 2;
1128 projector_y += edl->session->output_h / 2;
1129 Track *track = server->plugin ? server->plugin->track : 0;
1130 int track_w = track ? track->track_w : edl->session->output_w;
1131 int track_h = track ? track->track_h : edl->session->output_h;
1132 ox = (tx - track_w / 2) * projector_z + projector_x;
1133 oy = (ty - track_h / 2) * projector_z + projector_y;
1137 EDL *PluginClient::get_edl()
1139 return server->mwindow ? server->mwindow->edl : server->edl;
1142 int PluginClient::gui_open()
1144 return server->gui_open();