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
26 #define MAXANGLE 360.00
28 #define MAXPIVOT 100.00
31 REGISTER_PLUGIN(RotateEffect)
36 RotateConfig::RotateConfig()
38 reset(RESET_DEFAULT_SETTINGS);
41 void RotateConfig::reset(int clear)
54 case RESET_DEFAULT_SETTINGS :
64 int RotateConfig::equivalent(RotateConfig &that)
66 return EQUIV(angle, that.angle) &&
67 EQUIV(pivot_x, that.pivot_y) &&
68 EQUIV(pivot_y, that.pivot_y) &&
69 draw_pivot == that.draw_pivot;
72 void RotateConfig::copy_from(RotateConfig &that)
75 pivot_x = that.pivot_x;
76 pivot_y = that.pivot_y;
77 draw_pivot = that.draw_pivot;
78 // bilinear = that.bilinear;
81 void RotateConfig::interpolate(RotateConfig &prev,
87 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
88 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
90 this->angle = prev.angle * prev_scale + next.angle * next_scale;
91 this->pivot_x = prev.pivot_x * prev_scale + next.pivot_x * next_scale;
92 this->pivot_y = prev.pivot_y * prev_scale + next.pivot_y * next_scale;
93 draw_pivot = prev.draw_pivot;
94 // bilinear = prev.bilinear;
107 RotateToggle::RotateToggle(RotateWindow *window,
108 RotateEffect *plugin,
114 : BC_Radial(x, y, init_value, string)
117 this->plugin = plugin;
118 this->window = window;
121 int RotateToggle::handle_event()
123 plugin->config.angle = (float)value;
125 plugin->send_configure_change();
135 RotateDrawPivot::RotateDrawPivot(RotateWindow *window,
136 RotateEffect *plugin,
139 : BC_CheckBox(x, y, plugin->config.draw_pivot, _("Draw pivot"))
141 this->plugin = plugin;
142 this->window = window;
145 int RotateDrawPivot::handle_event()
147 plugin->config.draw_pivot = get_value();
148 plugin->send_configure_change();
156 // RotateInterpolate::RotateInterpolate(RotateEffect *plugin, int x, int y)
157 // : BC_CheckBox(x, y, plugin->config.bilinear, _("Interpolate"))
159 // this->plugin = plugin;
161 // int RotateInterpolate::handle_event()
163 // plugin->config.bilinear = get_value();
164 // plugin->send_configure_change();
171 RotateAngleText::RotateAngleText(RotateWindow *window, RotateEffect *plugin, int x, int y)
172 : BC_TumbleTextBox(window, (float)plugin->config.angle,
173 (float)-MAXANGLE, (float)MAXANGLE, x, y, xS(60), 2)
175 this->window = window;
176 this->plugin = plugin;
179 int RotateAngleText::handle_event()
181 plugin->config.angle = atof(get_text());
182 window->update_toggles();
183 window->update_sliders();
184 plugin->send_configure_change();
189 RotateAngleSlider::RotateAngleSlider(RotateWindow *window, RotateEffect *plugin, int x, int y, int w)
190 : BC_FSlider(x, y, 0, w, w, (float)-MAXANGLE, (float)MAXANGLE, (float)plugin->config.angle)
192 this->window = window;
193 this->plugin = plugin;
194 enable_show_value(0); // Hide caption
198 int RotateAngleSlider::handle_event()
200 plugin->config.angle = get_value();
201 window->update_toggles();
202 window->update_texts();
203 plugin->send_configure_change();
209 RotatePivotXText::RotatePivotXText(RotateWindow *window, RotateEffect *plugin, int x, int y)
210 : BC_TumbleTextBox(window, (float)plugin->config.pivot_x,
211 (float)MINPIVOT, (float)MAXPIVOT, x, y, xS(60), 2)
213 this->window = window;
214 this->plugin = plugin;
217 int RotatePivotXText::handle_event()
219 plugin->config.pivot_x = atof(get_text());
220 window->update_sliders();
221 plugin->send_configure_change();
226 RotatePivotXSlider::RotatePivotXSlider(RotateWindow *window, RotateEffect *plugin, int x, int y, int w)
227 : BC_FSlider(x, y, 0, w, w, (float)MINPIVOT, (float)MAXPIVOT, (float)plugin->config.pivot_x)
229 this->window = window;
230 this->plugin = plugin;
231 enable_show_value(0); // Hide caption
235 int RotatePivotXSlider::handle_event()
237 plugin->config.pivot_x = get_value();
238 window->update_toggles();
239 window->update_texts();
240 plugin->send_configure_change();
245 RotatePivotYText::RotatePivotYText(RotateWindow *window, RotateEffect *plugin, int x, int y)
246 : BC_TumbleTextBox(window, (float)plugin->config.pivot_y,
247 (float)MINPIVOT, (float)MAXPIVOT, x, y, xS(60), 2)
249 this->window = window;
250 this->plugin = plugin;
253 int RotatePivotYText::handle_event()
255 plugin->config.pivot_y = atof(get_text());
256 plugin->send_configure_change();
261 RotatePivotYSlider::RotatePivotYSlider(RotateWindow *window, RotateEffect *plugin, int x, int y, int w)
262 : BC_FSlider(x, y, 0, w, w, (float)MINPIVOT, (float)MAXPIVOT, (float)plugin->config.pivot_y)
264 this->window = window;
265 this->plugin = plugin;
266 enable_show_value(0); // Hide caption
270 int RotatePivotYSlider::handle_event()
272 plugin->config.pivot_y = get_value();
273 window->update_toggles();
274 window->update_texts();
275 plugin->send_configure_change();
281 RotateClr::RotateClr(RotateWindow *window, RotateEffect *plugin, int x, int y, int clear)
282 : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
284 this->window = window;
285 this->plugin = plugin;
289 RotateClr::~RotateClr()
293 int RotateClr::handle_event()
295 plugin->config.reset(clear);
297 plugin->send_configure_change();
303 RotateReset::RotateReset(RotateEffect *plugin, RotateWindow *window, int x, int y)
304 : BC_GenericButton(x, y, _("Reset"))
306 this->plugin = plugin;
307 this->window = window;
309 RotateReset::~RotateReset()
312 int RotateReset::handle_event()
314 plugin->config.reset(RESET_ALL);
316 plugin->send_configure_change();
325 RotateWindow::RotateWindow(RotateEffect *plugin)
326 : PluginClientWindow(plugin, xS(420), yS(260), xS(420), yS(260), 0)
328 this->plugin = plugin;
331 #define RADIUS xS(30)
333 void RotateWindow::create_objects()
335 int xs10 = xS(10), xs20 = xS(20), xs64 = xS(64), xs200 = xS(200);
336 int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(40);
337 int x2 = xS(80), x3 = xS(180);
338 int x = xs10, y = ys10;
339 int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
341 BC_TitleBar *title_bar;
345 add_subwindow(title_bar = new BC_TitleBar(x, y, get_w()-2*x, xs20, xs10, _("Rotation")));
347 add_tool(new BC_Title(x, y, _("Preset:")));
349 add_tool(toggle180neg = new RotateToggle(this, plugin,
350 plugin->config.angle == -180, x, y, -180, "-180°"));
352 add_tool(toggle90neg = new RotateToggle(this, plugin,
353 plugin->config.angle == -90, x, y, -90, "-90°"));
355 add_tool(toggle0 = new RotateToggle(this, plugin,
356 plugin->config.angle == 0, x, y, 0, "0°"));
358 add_tool(toggle90 = new RotateToggle(this, plugin,
359 plugin->config.angle == 90, x, y, 90, "+90°"));
361 add_tool(toggle180 = new RotateToggle(this, plugin,
362 plugin->config.angle == 180, x, y, 180, "+180°"));
363 // add_subwindow(bilinear = new RotateInterpolate(plugin, xs10, y + ys60));
365 add_tool(new BC_Title(x, y, _("Angle:")));
366 rotate_angle_text = new RotateAngleText(this, plugin, (x + x2), y);
367 rotate_angle_text->create_objects();
368 add_tool(rotate_angle_slider = new RotateAngleSlider(this, plugin, x3, y, xs200));
369 add_tool(rotate_angle_clr = new RotateClr(this, plugin,
370 clr_x, y, RESET_ANGLE));
374 add_subwindow(title_bar = new BC_TitleBar(x, y, get_w()-2*x, xs20, xs10, _("Pivot")));
376 add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
378 add_tool(new BC_Title(x, y, _("X:")));
379 add_tool(new BC_Title((x2-x), y, _("%")));
380 rotate_pivot_x_text = new RotatePivotXText(this, plugin, (x + x2), y);
381 rotate_pivot_x_text->create_objects();
382 add_tool(rotate_pivot_x_slider = new RotatePivotXSlider(this, plugin, x3, y, xs200));
383 add_tool(rotate_pivot_x_clr = new RotateClr(this, plugin,
384 clr_x, y, RESET_PIVOT_X));
386 add_tool(new BC_Title(x, y, _("Y:")));
387 add_tool(new BC_Title((x2-x), y, _("%")));
388 rotate_pivot_y_text = new RotatePivotYText(this, plugin, (x + x2), y);
389 rotate_pivot_y_text->create_objects();
390 add_tool(rotate_pivot_y_slider = new RotatePivotYSlider(this, plugin, x3, y, xs200));
391 add_tool(rotate_pivot_y_clr = new RotateClr(this, plugin,
392 clr_x, y, RESET_PIVOT_Y));
396 add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
398 add_subwindow(reset = new RotateReset(plugin, this, x, y));
405 int RotateWindow::update()
410 // bilinear->update(plugin->config.bilinear);
414 int RotateWindow::update_sliders()
416 rotate_angle_slider->update(plugin->config.angle);
417 rotate_pivot_x_slider->update(plugin->config.pivot_x);
418 rotate_pivot_y_slider->update(plugin->config.pivot_y);
422 int RotateWindow::update_texts()
424 rotate_angle_text->update(plugin->config.angle);
425 rotate_pivot_x_text->update(plugin->config.pivot_x);
426 rotate_pivot_y_text->update(plugin->config.pivot_y);
430 int RotateWindow::update_toggles()
432 toggle180neg->update(EQUIV(plugin->config.angle, -180));
433 toggle90neg->update(EQUIV(plugin->config.angle, -90));
434 toggle0->update(EQUIV(plugin->config.angle, 0));
435 toggle90->update(EQUIV(plugin->config.angle, 90));
436 toggle180->update(EQUIV(plugin->config.angle, 180));
437 draw_pivot->update(plugin->config.draw_pivot);
474 RotateEffect::RotateEffect(PluginServer *server)
475 : PluginVClient(server)
478 need_reconfigure = 1;
482 RotateEffect::~RotateEffect()
485 if(engine) delete engine;
490 const char* RotateEffect::plugin_title() { return N_("Rotate"); }
491 int RotateEffect::is_realtime() { return 1; }
494 NEW_WINDOW_MACRO(RotateEffect, RotateWindow)
497 void RotateEffect::update_gui()
501 load_configuration();
502 thread->window->lock_window();
503 ((RotateWindow*)thread->window)->update();
504 thread->window->unlock_window();
508 LOAD_CONFIGURATION_MACRO(RotateEffect, RotateConfig)
513 void RotateEffect::save_data(KeyFrame *keyframe)
517 // cause data to be stored directly in text
518 output.set_shared_output(keyframe->xbuf);
519 output.tag.set_title("ROTATE");
520 output.tag.set_property("ANGLE", (float)config.angle);
521 output.tag.set_property("PIVOT_X", (float)config.pivot_x);
522 output.tag.set_property("PIVOT_Y", (float)config.pivot_y);
523 output.tag.set_property("DRAW_PIVOT", (int)config.draw_pivot);
524 // output.tag.set_property("INTERPOLATE", (int)config.bilinear);
526 output.tag.set_title("/ROTATE");
528 output.append_newline();
529 output.terminate_string();
530 // data is now in *text
533 void RotateEffect::read_data(KeyFrame *keyframe)
537 input.set_shared_input(keyframe->xbuf);
543 result = input.read_tag();
547 if(input.tag.title_is("ROTATE"))
549 config.angle = input.tag.get_property("ANGLE", (float)config.angle);
550 config.pivot_x = input.tag.get_property("PIVOT_X", (float)config.pivot_x);
551 config.pivot_y = input.tag.get_property("PIVOT_Y", (float)config.pivot_y);
552 config.draw_pivot = input.tag.get_property("DRAW_PIVOT", (int)config.draw_pivot);
553 // config.bilinear = input.tag.get_property("INTERPOLATE", (int)config.bilinear);
559 int RotateEffect::process_buffer(VFrame *frame,
560 int64_t start_position,
563 load_configuration();
564 //printf("RotateEffect::process_buffer %d\n", __LINE__);
567 if(config.angle == 0 && !config.draw_pivot)
576 //printf("RotateEffect::process_buffer %d\n", __LINE__);
578 if(!engine) engine = new AffineEngine(PluginClient::smp + 1,
579 PluginClient::smp + 1);
580 int pivot_x = (int)(config.pivot_x * get_input()->get_w() / 100);
581 int pivot_y = (int)(config.pivot_y * get_input()->get_h() / 100);
582 engine->set_in_pivot(pivot_x, pivot_y);
583 engine->set_out_pivot(pivot_x, pivot_y);
587 // engine->set_out_viewport(0, 0, 320, 240);
588 // engine->set_out_pivot(160, 120);
599 //printf("RotateEffect::process_buffer %d\n", __LINE__);
602 // engine->set_viewport(50,
606 // engine->set_pivot(100, 100);
609 VFrame *temp_frame = PluginVClient::new_temp(get_input()->get_w(),
610 get_input()->get_h(),
611 get_input()->get_color_model());
612 read_frame(temp_frame,
617 frame->clear_frame();
618 engine->rotate(frame,
622 //printf("RotateEffect::process_buffer %d draw_pivot=%d\n", __LINE__, config.draw_pivot);
625 if(config.draw_pivot) {
626 VFrame *vframe = get_output();
627 int w = vframe->get_w(), h = vframe->get_h();
628 int mx = w > h ? w : h;
629 int lw = mx/400 + 1, cxy = mx/80;
630 int center_x = (int)(config.pivot_x * w/100);
631 int center_y = (int)(config.pivot_y * h/100);
632 int x1 = center_x - cxy, x2 = center_x + cxy;
633 int y1 = center_y - cxy, y2 = center_y + cxy;
634 vframe->set_pixel_color(WHITE);
635 for( int i=0; i<lw; ++i )
636 frame->draw_line(x1-i,center_y-i, x2-i,center_y-i);
637 vframe->set_pixel_color(BLACK);
638 for( int i=1; i<=lw; ++i )
639 frame->draw_line(x1+i,center_y+i, x2+i,center_y+i);
640 vframe->set_pixel_color(WHITE);
641 for( int i=0; i<lw; ++i )
642 frame->draw_line(center_x-i,y1-i, center_x-i,y2-i);
643 vframe->set_pixel_color(BLACK);
644 for( int i=1; i<=lw; ++i )
645 frame->draw_line(center_x+i,y1+i, center_x+i,y2+i);
648 // Conserve memory by deleting large frames
649 if(get_input()->get_w() > PLUGIN_MAX_W &&
650 get_input()->get_h() > PLUGIN_MAX_H)
660 int RotateEffect::handle_opengl()
663 engine->set_opengl(1);
664 engine->rotate(get_output(),
667 engine->set_opengl(0);
669 if(config.draw_pivot)
671 VFrame *vframe = get_output();
672 int w = vframe->get_w(), h = vframe->get_h();
673 int mx = w > h ? w : h;
674 int lw = mx/400 + 1, cxy = mx/80;
675 int center_x = (int)(config.pivot_x * w/100);
676 int center_y = (int)(config.pivot_y * h/100);
677 int x1 = center_x - cxy, x2 = center_x + cxy;
678 int y1 = center_y - cxy, y2 = center_y + cxy;
679 glDisable(GL_TEXTURE_2D);
680 int is_yuv = BC_CModels::is_yuv(vframe->get_color_model());
681 float rwt = 1, gwt = is_yuv? 0.5 : 1, bwt = is_yuv? 0.5 : 1;
682 float rbk = 0, gbk = is_yuv? 0.5 : 0, bbk = is_yuv? 0.5 : 0;
684 glColor4f(rwt, gwt, bwt, 1.0);
685 for( int i=0; i<lw; ++i ) {
686 glVertex3f(x1-i, center_y-i - h, 0.0);
687 glVertex3f(x2-i, center_y-i - h, 0.0);
689 glColor4f(rbk, gbk, bbk, 1.0);
690 for( int i=1; i<=lw; ++i ) {
691 glVertex3f(x1+i, center_y+i - h, 0.0);
692 glVertex3f(x2+i, center_y+i - h, 0.0);
696 glColor4f(rwt, gwt, bwt, 1.0);
697 for( int i=0; i<lw; ++i ) {
698 glVertex3f(center_x-i, y1-i - h, 0.0);
699 glVertex3f(center_x-i, y2-i - h, 0.0);
701 glColor4f(rbk, gbk, bbk, 1.0);
702 for( int i=1; i<=lw; ++i ) {
703 glVertex3f(center_x+i, y1+i - h, 0.0);
704 glVertex3f(center_x+i, y2+i - h, 0.0);