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
27 REGISTER_PLUGIN(RotateEffect)
32 RotateConfig::RotateConfig()
37 void RotateConfig::reset()
45 int RotateConfig::equivalent(RotateConfig &that)
47 return EQUIV(angle, that.angle) &&
48 EQUIV(pivot_x, that.pivot_y) &&
49 EQUIV(pivot_y, that.pivot_y) &&
50 draw_pivot == that.draw_pivot;
53 void RotateConfig::copy_from(RotateConfig &that)
56 pivot_x = that.pivot_x;
57 pivot_y = that.pivot_y;
58 draw_pivot = that.draw_pivot;
59 // bilinear = that.bilinear;
62 void RotateConfig::interpolate(RotateConfig &prev,
68 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
69 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
71 this->angle = prev.angle * prev_scale + next.angle * next_scale;
72 this->pivot_x = prev.pivot_x * prev_scale + next.pivot_x * next_scale;
73 this->pivot_y = prev.pivot_y * prev_scale + next.pivot_y * next_scale;
74 draw_pivot = prev.draw_pivot;
75 // bilinear = prev.bilinear;
88 RotateToggle::RotateToggle(RotateWindow *window,
95 : BC_Radial(x, y, init_value, string)
98 this->plugin = plugin;
99 this->window = window;
102 int RotateToggle::handle_event()
104 plugin->config.angle = (float)value;
106 plugin->send_configure_change();
116 RotateDrawPivot::RotateDrawPivot(RotateWindow *window,
117 RotateEffect *plugin,
120 : BC_CheckBox(x, y, plugin->config.draw_pivot, _("Draw pivot"))
122 this->plugin = plugin;
123 this->window = window;
126 int RotateDrawPivot::handle_event()
128 plugin->config.draw_pivot = get_value();
129 plugin->send_configure_change();
137 // RotateInterpolate::RotateInterpolate(RotateEffect *plugin, int x, int y)
138 // : BC_CheckBox(x, y, plugin->config.bilinear, _("Interpolate"))
140 // this->plugin = plugin;
142 // int RotateInterpolate::handle_event()
144 // plugin->config.bilinear = get_value();
145 // plugin->send_configure_change();
152 RotateFine::RotateFine(RotateWindow *window, RotateEffect *plugin, int x, int y)
155 (float)plugin->config.angle,
159 this->window = window;
160 this->plugin = plugin;
165 int RotateFine::handle_event()
167 plugin->config.angle = get_value();
168 window->update_toggles();
169 window->update_text();
170 plugin->send_configure_change();
176 RotateText::RotateText(RotateWindow *window,
177 RotateEffect *plugin,
184 (float)plugin->config.angle)
186 this->window = window;
187 this->plugin = plugin;
191 int RotateText::handle_event()
193 plugin->config.angle = atof(get_text());
194 window->update_toggles();
195 window->update_fine();
196 plugin->send_configure_change();
202 RotateX::RotateX(RotateWindow *window, RotateEffect *plugin, int x, int y)
205 (float)plugin->config.pivot_x,
209 this->window = window;
210 this->plugin = plugin;
215 int RotateX::handle_event()
217 plugin->config.pivot_x = get_value();
218 plugin->send_configure_change();
222 RotateY::RotateY(RotateWindow *window, RotateEffect *plugin, int x, int y)
225 (float)plugin->config.pivot_y,
229 this->window = window;
230 this->plugin = plugin;
235 int RotateY::handle_event()
237 plugin->config.pivot_y = get_value();
238 plugin->send_configure_change();
243 RotateReset::RotateReset(RotateEffect *plugin, RotateWindow *window, int x, int y)
244 : BC_GenericButton(x, y, _("Reset"))
246 this->plugin = plugin;
247 this->window = window;
249 RotateReset::~RotateReset()
252 int RotateReset::handle_event()
254 plugin->config.reset();
256 plugin->send_configure_change();
265 RotateWindow::RotateWindow(RotateEffect *plugin)
266 : PluginClientWindow(plugin, xS(300), yS(230), xS(300), yS(230), 0)
268 this->plugin = plugin;
271 #define RADIUS xS(30)
273 void RotateWindow::create_objects()
275 int xs10 = xS(10), xs50 = xS(50), xs150 = xS(150);
276 int ys10 = yS(10), ys20 = yS(20), ys25 = yS(25), ys50 = yS(50), ys60 = yS(60);
277 int x = xs10, y = ys10;
279 add_tool(new BC_Title(x, y, _("Rotate")));
280 x += xs50; y += ys20;
281 add_tool(toggle0 = new RotateToggle(this, plugin,
282 plugin->config.angle == 0, x, y, 0, "0"));
283 x += RADIUS; y += RADIUS;
284 add_tool(toggle90 = new RotateToggle(this, plugin,
285 plugin->config.angle == 90, x, y, 90, "90"));
286 x -= RADIUS; y += RADIUS;
287 add_tool(toggle180 = new RotateToggle(this, plugin,
288 plugin->config.angle == 180, x, y, 180, "180"));
289 x -= RADIUS; y -= RADIUS;
290 add_tool(toggle270 = new RotateToggle(this, plugin,
291 plugin->config.angle == 270, x, y, 270, "270"));
292 // add_subwindow(bilinear = new RotateInterpolate(plugin, xs10, y + ys60));
293 x += xs150; y -= ys50;
294 add_tool(fine = new RotateFine(this, plugin, x, y));
295 y += fine->get_h() + ys10;
296 add_tool(text = new RotateText(this, plugin, x, y));
298 add_tool(new BC_Title(x, y, _("Degrees")));
300 y += text->get_h() + ys10;
301 add_subwindow(title = new BC_Title(x, y, _("Pivot (x,y):")));
302 y += title->get_h() + ys10;
303 add_subwindow(this->x = new RotateX(this, plugin, x, y));
304 x += this->x->get_w() + xs10;
305 add_subwindow(this->y = new RotateY(this, plugin, x, y));
307 // y += this->y->get_h() + ys10;
309 add_subwindow(draw_pivot = new RotateDrawPivot(this, plugin, x, y));
311 add_subwindow(reset = new RotateReset(plugin, this, x, y));
318 int RotateWindow::update()
323 // bilinear->update(plugin->config.bilinear);
327 int RotateWindow::update_fine()
329 fine->update(plugin->config.angle);
330 x->update(plugin->config.pivot_x);
331 y->update(plugin->config.pivot_y);
335 int RotateWindow::update_text()
337 text->update(plugin->config.angle);
341 int RotateWindow::update_toggles()
343 toggle0->update(EQUIV(plugin->config.angle, 0));
344 toggle90->update(EQUIV(plugin->config.angle, 90));
345 toggle180->update(EQUIV(plugin->config.angle, 180));
346 toggle270->update(EQUIV(plugin->config.angle, 270));
347 draw_pivot->update(plugin->config.draw_pivot);
384 RotateEffect::RotateEffect(PluginServer *server)
385 : PluginVClient(server)
388 need_reconfigure = 1;
392 RotateEffect::~RotateEffect()
395 if(engine) delete engine;
400 const char* RotateEffect::plugin_title() { return N_("Rotate"); }
401 int RotateEffect::is_realtime() { return 1; }
404 NEW_WINDOW_MACRO(RotateEffect, RotateWindow)
407 void RotateEffect::update_gui()
411 load_configuration();
412 thread->window->lock_window();
413 ((RotateWindow*)thread->window)->update();
414 thread->window->unlock_window();
418 LOAD_CONFIGURATION_MACRO(RotateEffect, RotateConfig)
423 void RotateEffect::save_data(KeyFrame *keyframe)
427 // cause data to be stored directly in text
428 output.set_shared_output(keyframe->xbuf);
429 output.tag.set_title("ROTATE");
430 output.tag.set_property("ANGLE", (float)config.angle);
431 output.tag.set_property("PIVOT_X", (float)config.pivot_x);
432 output.tag.set_property("PIVOT_Y", (float)config.pivot_y);
433 output.tag.set_property("DRAW_PIVOT", (int)config.draw_pivot);
434 // output.tag.set_property("INTERPOLATE", (int)config.bilinear);
436 output.tag.set_title("/ROTATE");
438 output.append_newline();
439 output.terminate_string();
440 // data is now in *text
443 void RotateEffect::read_data(KeyFrame *keyframe)
447 input.set_shared_input(keyframe->xbuf);
453 result = input.read_tag();
457 if(input.tag.title_is("ROTATE"))
459 config.angle = input.tag.get_property("ANGLE", (float)config.angle);
460 config.pivot_x = input.tag.get_property("PIVOT_X", (float)config.pivot_x);
461 config.pivot_y = input.tag.get_property("PIVOT_Y", (float)config.pivot_y);
462 config.draw_pivot = input.tag.get_property("DRAW_PIVOT", (int)config.draw_pivot);
463 // config.bilinear = input.tag.get_property("INTERPOLATE", (int)config.bilinear);
469 int RotateEffect::process_buffer(VFrame *frame,
470 int64_t start_position,
473 load_configuration();
474 //printf("RotateEffect::process_buffer %d\n", __LINE__);
477 if(config.angle == 0 && !config.draw_pivot)
486 //printf("RotateEffect::process_buffer %d\n", __LINE__);
488 if(!engine) engine = new AffineEngine(PluginClient::smp + 1,
489 PluginClient::smp + 1);
490 int pivot_x = (int)(config.pivot_x * get_input()->get_w() / 100);
491 int pivot_y = (int)(config.pivot_y * get_input()->get_h() / 100);
492 engine->set_in_pivot(pivot_x, pivot_y);
493 engine->set_out_pivot(pivot_x, pivot_y);
497 // engine->set_out_viewport(0, 0, 320, 240);
498 // engine->set_out_pivot(160, 120);
509 //printf("RotateEffect::process_buffer %d\n", __LINE__);
512 // engine->set_viewport(50,
516 // engine->set_pivot(100, 100);
519 VFrame *temp_frame = PluginVClient::new_temp(get_input()->get_w(),
520 get_input()->get_h(),
521 get_input()->get_color_model());
522 read_frame(temp_frame,
527 frame->clear_frame();
528 engine->rotate(frame,
532 //printf("RotateEffect::process_buffer %d draw_pivot=%d\n", __LINE__, config.draw_pivot);
535 if(config.draw_pivot) {
536 VFrame *vframe = get_output();
537 int w = vframe->get_w(), h = vframe->get_h();
538 int mx = w > h ? w : h;
539 int lw = mx/400 + 1, cxy = mx/80;
540 int center_x = (int)(config.pivot_x * w/100);
541 int center_y = (int)(config.pivot_y * h/100);
542 int x1 = center_x - cxy, x2 = center_x + cxy;
543 int y1 = center_y - cxy, y2 = center_y + cxy;
544 vframe->set_pixel_color(WHITE);
545 for( int i=0; i<lw; ++i )
546 frame->draw_line(x1-i,center_y-i, x2-i,center_y-i);
547 vframe->set_pixel_color(BLACK);
548 for( int i=1; i<=lw; ++i )
549 frame->draw_line(x1+i,center_y+i, x2+i,center_y+i);
550 vframe->set_pixel_color(WHITE);
551 for( int i=0; i<lw; ++i )
552 frame->draw_line(center_x-i,y1-i, center_x-i,y2-i);
553 vframe->set_pixel_color(BLACK);
554 for( int i=1; i<=lw; ++i )
555 frame->draw_line(center_x+i,y1+i, center_x+i,y2+i);
558 // Conserve memory by deleting large frames
559 if(get_input()->get_w() > PLUGIN_MAX_W &&
560 get_input()->get_h() > PLUGIN_MAX_H)
570 int RotateEffect::handle_opengl()
573 engine->set_opengl(1);
574 engine->rotate(get_output(),
577 engine->set_opengl(0);
579 if(config.draw_pivot)
581 VFrame *vframe = get_output();
582 int w = vframe->get_w(), h = vframe->get_h();
583 int mx = w > h ? w : h;
584 int lw = mx/400 + 1, cxy = mx/80;
585 int center_x = (int)(config.pivot_x * w/100);
586 int center_y = (int)(config.pivot_y * h/100);
587 int x1 = center_x - cxy, x2 = center_x + cxy;
588 int y1 = center_y - cxy, y2 = center_y + cxy;
589 glDisable(GL_TEXTURE_2D);
590 int is_yuv = BC_CModels::is_yuv(vframe->get_color_model());
591 float rwt = 1, gwt = is_yuv? 0.5 : 1, bwt = is_yuv? 0.5 : 1;
592 float rbk = 0, gbk = is_yuv? 0.5 : 0, bbk = is_yuv? 0.5 : 0;
594 glColor4f(rwt, gwt, bwt, 1.0);
595 for( int i=0; i<lw; ++i ) {
596 glVertex3f(x1-i, center_y-i - h, 0.0);
597 glVertex3f(x2-i, center_y-i - h, 0.0);
599 glColor4f(rbk, gbk, bbk, 1.0);
600 for( int i=1; i<=lw; ++i ) {
601 glVertex3f(x1+i, center_y+i - h, 0.0);
602 glVertex3f(x2+i, center_y+i - h, 0.0);
606 glColor4f(rwt, gwt, bwt, 1.0);
607 for( int i=0; i<lw; ++i ) {
608 glVertex3f(center_x-i, y1-i - h, 0.0);
609 glVertex3f(center_x-i, y2-i - h, 0.0);
611 glColor4f(rbk, gbk, bbk, 1.0);
612 for( int i=1; i<=lw; ++i ) {
613 glVertex3f(center_x+i, y1+i - h, 0.0);
614 glVertex3f(center_x+i, y2+i - h, 0.0);