4 * Copyright (C) 2008 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
23 #include "bcdisplayinfo.h"
29 #include "pluginvclient.h"
30 #include "rotateframe.h"
50 int equivalent(RotateConfig &that);
51 void copy_from(RotateConfig &that);
52 void interpolate(RotateConfig &prev,
65 class RotateToggle : public BC_Radial
68 RotateToggle(RotateWindow *window,
82 class RotateDrawPivot : public BC_CheckBox
85 RotateDrawPivot(RotateWindow *window,
95 class RotateInterpolate : public BC_CheckBox
98 RotateInterpolate(RotateEffect *plugin, int x, int y);
100 RotateEffect *plugin;
103 class RotateFine : public BC_FPot
106 RotateFine(RotateWindow *window,
107 RotateEffect *plugin,
112 RotateEffect *plugin;
113 RotateWindow *window;
116 class RotateX : public BC_FPot
119 RotateX(RotateWindow *window,
120 RotateEffect *plugin,
124 RotateEffect *plugin;
125 RotateWindow *window;
128 class RotateY : public BC_FPot
131 RotateY(RotateWindow *window,
132 RotateEffect *plugin,
136 RotateEffect *plugin;
137 RotateWindow *window;
141 class RotateText : public BC_TextBox
144 RotateText(RotateWindow *window,
145 RotateEffect *plugin,
150 RotateEffect *plugin;
151 RotateWindow *window;
154 class RotateWindow : public PluginClientWindow
157 RotateWindow(RotateEffect *plugin);
159 void create_objects();
164 int update_toggles();
166 RotateEffect *plugin;
167 RotateToggle *toggle0;
168 RotateToggle *toggle90;
169 RotateToggle *toggle180;
170 RotateToggle *toggle270;
171 RotateDrawPivot *draw_pivot;
176 // RotateInterpolate *bilinear;
182 class RotateEffect : public PluginVClient
185 RotateEffect(PluginServer *server);
188 PLUGIN_CLASS_MEMBERS(RotateConfig)
189 int process_buffer(VFrame *frame,
190 int64_t start_position,
194 void save_data(KeyFrame *keyframe);
195 void read_data(KeyFrame *keyframe);
198 AffineEngine *engine;
199 int need_reconfigure;
208 REGISTER_PLUGIN(RotateEffect)
227 RotateConfig::RotateConfig()
235 int RotateConfig::equivalent(RotateConfig &that)
237 return EQUIV(angle, that.angle) &&
238 EQUIV(pivot_x, that.pivot_y) &&
239 EQUIV(pivot_y, that.pivot_y) &&
240 draw_pivot == that.draw_pivot;
243 void RotateConfig::copy_from(RotateConfig &that)
246 pivot_x = that.pivot_x;
247 pivot_y = that.pivot_y;
248 draw_pivot = that.draw_pivot;
249 // bilinear = that.bilinear;
252 void RotateConfig::interpolate(RotateConfig &prev,
258 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
259 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
261 this->angle = prev.angle * prev_scale + next.angle * next_scale;
262 this->pivot_x = prev.pivot_x * prev_scale + next.pivot_x * next_scale;
263 this->pivot_y = prev.pivot_y * prev_scale + next.pivot_y * next_scale;
264 draw_pivot = prev.draw_pivot;
265 // bilinear = prev.bilinear;
278 RotateToggle::RotateToggle(RotateWindow *window,
279 RotateEffect *plugin,
285 : BC_Radial(x, y, init_value, string)
288 this->plugin = plugin;
289 this->window = window;
292 int RotateToggle::handle_event()
294 plugin->config.angle = (float)value;
296 plugin->send_configure_change();
306 RotateDrawPivot::RotateDrawPivot(RotateWindow *window,
307 RotateEffect *plugin,
310 : BC_CheckBox(x, y, plugin->config.draw_pivot, _("Draw pivot"))
312 this->plugin = plugin;
313 this->window = window;
316 int RotateDrawPivot::handle_event()
318 plugin->config.draw_pivot = get_value();
319 plugin->send_configure_change();
327 // RotateInterpolate::RotateInterpolate(RotateEffect *plugin, int x, int y)
328 // : BC_CheckBox(x, y, plugin->config.bilinear, _("Interpolate"))
330 // this->plugin = plugin;
332 // int RotateInterpolate::handle_event()
334 // plugin->config.bilinear = get_value();
335 // plugin->send_configure_change();
342 RotateFine::RotateFine(RotateWindow *window, RotateEffect *plugin, int x, int y)
345 (float)plugin->config.angle,
349 this->window = window;
350 this->plugin = plugin;
355 int RotateFine::handle_event()
357 plugin->config.angle = get_value();
358 window->update_toggles();
359 window->update_text();
360 plugin->send_configure_change();
366 RotateText::RotateText(RotateWindow *window,
367 RotateEffect *plugin,
374 (float)plugin->config.angle)
376 this->window = window;
377 this->plugin = plugin;
381 int RotateText::handle_event()
383 plugin->config.angle = atof(get_text());
384 window->update_toggles();
385 window->update_fine();
386 plugin->send_configure_change();
392 RotateX::RotateX(RotateWindow *window, RotateEffect *plugin, int x, int y)
395 (float)plugin->config.pivot_x,
399 this->window = window;
400 this->plugin = plugin;
405 int RotateX::handle_event()
407 plugin->config.pivot_x = get_value();
408 plugin->send_configure_change();
412 RotateY::RotateY(RotateWindow *window, RotateEffect *plugin, int x, int y)
415 (float)plugin->config.pivot_y,
419 this->window = window;
420 this->plugin = plugin;
425 int RotateY::handle_event()
427 plugin->config.pivot_y = get_value();
428 plugin->send_configure_change();
439 RotateWindow::RotateWindow(RotateEffect *plugin)
440 : PluginClientWindow(plugin,
447 this->plugin = plugin;
452 void RotateWindow::create_objects()
459 add_tool(new BC_Title(x, y, _("Rotate")));
462 add_tool(toggle0 = new RotateToggle(this,
464 plugin->config.angle == 0,
471 add_tool(toggle90 = new RotateToggle(this,
473 plugin->config.angle == 90,
480 add_tool(toggle180 = new RotateToggle(this,
482 plugin->config.angle == 180,
489 add_tool(toggle270 = new RotateToggle(this,
491 plugin->config.angle == 270,
496 // add_subwindow(bilinear = new RotateInterpolate(plugin, 10, y + 60));
499 add_tool(fine = new RotateFine(this, plugin, x, y));
500 y += fine->get_h() + 10;
501 add_tool(text = new RotateText(this, plugin, x, y));
503 add_tool(new BC_Title(x, y, _("Degrees")));
509 y += text->get_h() + 10;
510 add_subwindow(title = new BC_Title(x, y, _("Pivot (x,y):")));
511 y += title->get_h() + 10;
512 add_subwindow(this->x = new RotateX(this, plugin, x, y));
513 x += this->x->get_w() + 10;
514 add_subwindow(this->y = new RotateY(this, plugin, x, y));
517 y += this->y->get_h() + 10;
518 add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
528 int RotateWindow::update()
533 // bilinear->update(plugin->config.bilinear);
537 int RotateWindow::update_fine()
539 fine->update(plugin->config.angle);
540 x->update(plugin->config.pivot_x);
541 y->update(plugin->config.pivot_y);
545 int RotateWindow::update_text()
547 text->update(plugin->config.angle);
551 int RotateWindow::update_toggles()
553 toggle0->update(EQUIV(plugin->config.angle, 0));
554 toggle90->update(EQUIV(plugin->config.angle, 90));
555 toggle180->update(EQUIV(plugin->config.angle, 180));
556 toggle270->update(EQUIV(plugin->config.angle, 270));
557 draw_pivot->update(plugin->config.draw_pivot);
594 RotateEffect::RotateEffect(PluginServer *server)
595 : PluginVClient(server)
598 need_reconfigure = 1;
602 RotateEffect::~RotateEffect()
605 if(engine) delete engine;
610 const char* RotateEffect::plugin_title() { return N_("Rotate"); }
611 int RotateEffect::is_realtime() { return 1; }
614 NEW_WINDOW_MACRO(RotateEffect, RotateWindow)
617 void RotateEffect::update_gui()
621 load_configuration();
622 thread->window->lock_window();
623 ((RotateWindow*)thread->window)->update();
624 thread->window->unlock_window();
628 LOAD_CONFIGURATION_MACRO(RotateEffect, RotateConfig)
633 void RotateEffect::save_data(KeyFrame *keyframe)
637 // cause data to be stored directly in text
638 output.set_shared_output(keyframe->xbuf);
639 output.tag.set_title("ROTATE");
640 output.tag.set_property("ANGLE", (float)config.angle);
641 output.tag.set_property("PIVOT_X", (float)config.pivot_x);
642 output.tag.set_property("PIVOT_Y", (float)config.pivot_y);
643 output.tag.set_property("DRAW_PIVOT", (int)config.draw_pivot);
644 // output.tag.set_property("INTERPOLATE", (int)config.bilinear);
646 output.tag.set_title("/ROTATE");
648 output.append_newline();
649 output.terminate_string();
650 // data is now in *text
653 void RotateEffect::read_data(KeyFrame *keyframe)
657 input.set_shared_input(keyframe->xbuf);
663 result = input.read_tag();
667 if(input.tag.title_is("ROTATE"))
669 config.angle = input.tag.get_property("ANGLE", (float)config.angle);
670 config.pivot_x = input.tag.get_property("PIVOT_X", (float)config.pivot_x);
671 config.pivot_y = input.tag.get_property("PIVOT_Y", (float)config.pivot_y);
672 config.draw_pivot = input.tag.get_property("DRAW_PIVOT", (int)config.draw_pivot);
673 // config.bilinear = input.tag.get_property("INTERPOLATE", (int)config.bilinear);
679 int RotateEffect::process_buffer(VFrame *frame,
680 int64_t start_position,
683 load_configuration();
684 int w = frame->get_w();
685 int h = frame->get_h();
686 //printf("RotateEffect::process_buffer %d\n", __LINE__);
689 if(config.angle == 0)
698 //printf("RotateEffect::process_buffer %d\n", __LINE__);
700 if(!engine) engine = new AffineEngine(PluginClient::smp + 1,
701 PluginClient::smp + 1);
702 int pivot_x = (int)(config.pivot_x * get_input()->get_w() / 100);
703 int pivot_y = (int)(config.pivot_y * get_input()->get_h() / 100);
704 engine->set_in_pivot(pivot_x, pivot_y);
705 engine->set_out_pivot(pivot_x, pivot_y);
709 // engine->set_out_viewport(0, 0, 320, 240);
710 // engine->set_out_pivot(160, 120);
721 //printf("RotateEffect::process_buffer %d\n", __LINE__);
724 // engine->set_viewport(50,
728 // engine->set_pivot(100, 100);
731 VFrame *temp_frame = PluginVClient::new_temp(get_input()->get_w(),
732 get_input()->get_h(),
733 get_input()->get_color_model());
734 read_frame(temp_frame,
739 frame->clear_frame();
740 engine->rotate(frame,
744 //printf("RotateEffect::process_buffer %d draw_pivot=%d\n", __LINE__, config.draw_pivot);
749 #define DRAW_CENTER(components, type, max) \
751 type **rows = (type**)get_output()->get_rows(); \
752 if( (center_x >= 0 && center_x < w) || (center_y >= 0 && center_y < h) ) \
754 type *hrow = rows[center_y] + components * (center_x - CENTER_W / 2); \
755 for(int i = center_x - CENTER_W / 2; i <= center_x + CENTER_W / 2; i++) \
757 if(i >= 0 && i < w) \
759 hrow[0] = max - hrow[0]; \
760 hrow[1] = max - hrow[1]; \
761 hrow[2] = max - hrow[2]; \
762 hrow += components; \
766 for(int i = center_y - CENTER_W / 2; i <= center_y + CENTER_W / 2; i++) \
768 if(i >= 0 && i < h) \
770 type *vrow = rows[i] + center_x * components; \
771 vrow[0] = max - vrow[0]; \
772 vrow[1] = max - vrow[1]; \
773 vrow[2] = max - vrow[2]; \
779 if(config.draw_pivot)
781 int center_x = (int)(config.pivot_x * w / 100); \
782 int center_y = (int)(config.pivot_y * h / 100); \
784 //printf("RotateEffect::process_buffer %d %d %d\n", __LINE__, center_x, center_y);
785 switch(get_output()->get_color_model())
788 DRAW_CENTER(3, float, 1.0)
791 DRAW_CENTER(4, float, 1.0)
794 DRAW_CENTER(3, unsigned char, 0xff)
797 DRAW_CENTER(4, unsigned char, 0xff)
800 DRAW_CENTER(3, unsigned char, 0xff)
803 DRAW_CENTER(4, unsigned char, 0xff)
808 // Conserve memory by deleting large frames
809 if(get_input()->get_w() > PLUGIN_MAX_W &&
810 get_input()->get_h() > PLUGIN_MAX_H)
820 int RotateEffect::handle_opengl()
823 engine->set_opengl(1);
824 engine->rotate(get_output(),
827 engine->set_opengl(0);
829 if(config.draw_pivot)
831 int w = get_output()->get_w();
832 int h = get_output()->get_h();
833 int center_x = (int)(config.pivot_x * w / 100);
834 int center_y = (int)(config.pivot_y * h / 100);
836 glDisable(GL_TEXTURE_2D);
837 glColor4f(0.0, 0.0, 0.0, 1.0);
839 glVertex3f(center_x, -h + center_y - CENTER_H / 2, 0.0);
840 glVertex3f(center_x, -h + center_y + CENTER_H / 2, 0.0);
843 glVertex3f(center_x - CENTER_W / 2, -h + center_y, 0.0);
844 glVertex3f(center_x + CENTER_W / 2, -h + center_y, 0.0);
846 glColor4f(1.0, 1.0, 1.0, 1.0);
848 glVertex3f(center_x - 1, -h + center_y - CENTER_H / 2 - 1, 0.0);
849 glVertex3f(center_x - 1, -h + center_y + CENTER_H / 2 - 1, 0.0);
852 glVertex3f(center_x - CENTER_W / 2 - 1, -h + center_y - 1, 0.0);
853 glVertex3f(center_x + CENTER_W / 2 - 1, -h + center_y - 1, 0.0);