/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 3 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, see . ***/ #include "transformeffect.h" #include #include #include #include #include #include #include #include #include "ui/collapsiblewidget.h" #include "timeline/clip.h" #include "timeline/sequence.h" #include "project/footage.h" #include "global/math.h" #include "ui/labelslider.h" #include "ui/comboboxex.h" #include "panels/project.h" #include "global/debug.h" #include "panels/panels.h" #include "panels/viewer.h" #include "ui/viewerwidget.h" TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { SetFlags(Effect::CoordsFlag); EffectRow* position_row = new EffectRow(this, tr("Position")); position_x = new DoubleField(position_row, "posx"); // position X position_y = new DoubleField(position_row, "posy"); // position Y EffectRow* scale_row = new EffectRow(this, tr("Scale")); // scale X (and Y is uniform scale is selected) scale_x = new DoubleField(scale_row, "scalex"); scale_x->SetMinimum(0); // scale Y (disabled if uniform scale is selected) scale_y = new DoubleField(scale_row, "scaley"); scale_y->SetMinimum(0); EffectRow* uniform_scale_row = new EffectRow(this, tr("Uniform Scale")); uniform_scale_field = new BoolField(uniform_scale_row, "uniformscale"); // uniform scale option EffectRow* rotation_row = new EffectRow(this, tr("Rotation")); rotation = new DoubleField(rotation_row, "rotation"); EffectRow* anchor_point_row = new EffectRow(this, tr("Anchor Point")); anchor_x_box = new DoubleField(anchor_point_row, "anchorx"); // anchor point X anchor_y_box = new DoubleField(anchor_point_row, "anchory"); // anchor point Y EffectRow* opacity_row = new EffectRow(this, tr("Opacity")); // opacity opacity = new DoubleField(opacity_row, "opacity"); opacity->SetMinimum(0); opacity->SetMaximum(100); EffectRow* blend_mode_row = new EffectRow(this, tr("Blend Mode")); // blend mode blend_mode_box = new ComboField(blend_mode_row, "blendmode"); blend_mode_box->SetColumnSpan(2); blend_mode_box->AddItem(tr("Normal"), ""); // set up gizmos top_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); top_left_gizmo->set_cursor(Qt::SizeFDiagCursor); top_left_gizmo->x_field1 = scale_x; top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); top_center_gizmo->set_cursor(Qt::SizeVerCursor); top_center_gizmo->y_field1 = scale_x; top_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); top_right_gizmo->set_cursor(Qt::SizeBDiagCursor); top_right_gizmo->x_field1 = scale_x; bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor); bottom_left_gizmo->x_field1 = scale_x; bottom_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); bottom_center_gizmo->set_cursor(Qt::SizeVerCursor); bottom_center_gizmo->y_field1 = scale_x; bottom_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor); bottom_right_gizmo->x_field1 = scale_x; left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); left_center_gizmo->set_cursor(Qt::SizeHorCursor); left_center_gizmo->x_field1 = scale_x; right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); right_center_gizmo->set_cursor(Qt::SizeHorCursor); right_center_gizmo->x_field1 = scale_x; anchor_gizmo = add_gizmo(GIZMO_TYPE_TARGET); anchor_gizmo->set_cursor(Qt::SizeAllCursor); anchor_gizmo->x_field1 = anchor_x_box; anchor_gizmo->y_field1 = anchor_y_box; anchor_gizmo->x_field2 = position_x; anchor_gizmo->y_field2 = position_y; rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT); rotate_gizmo->color = Qt::green; rotate_gizmo->set_cursor(Qt::SizeAllCursor); rotate_gizmo->x_field1 = rotation; rect_gizmo = add_gizmo(GIZMO_TYPE_POLY); rect_gizmo->x_field1 = position_x; rect_gizmo->y_field1 = position_y; connect(uniform_scale_field, SIGNAL(Toggled(bool)), this, SLOT(toggle_uniform_scale(bool))); // set defaults uniform_scale_field->SetValueAt(0, true); blend_mode_box->SetValueAt(0, ""); anchor_x_box->SetDefault(0); anchor_y_box->SetDefault(0); opacity->SetDefault(100); scale_x->SetDefault(100); scale_y->SetDefault(100); refresh(); } void TransformEffect::refresh() { if (parent_clip != nullptr && parent_clip->sequence != nullptr) { position_x->SetDefault(parent_clip->sequence->width/2); position_y->SetDefault(parent_clip->sequence->height/2); double x_percent_multipler = 200.0 / parent_clip->sequence->width; double y_percent_multipler = 200.0 / parent_clip->sequence->height; top_left_gizmo->x_field_multi1 = -x_percent_multipler; top_left_gizmo->y_field_multi1 = -y_percent_multipler; top_center_gizmo->y_field_multi1 = -y_percent_multipler; top_right_gizmo->x_field_multi1 = x_percent_multipler; top_right_gizmo->y_field_multi1 = -y_percent_multipler; bottom_left_gizmo->x_field_multi1 = -x_percent_multipler; bottom_left_gizmo->y_field_multi1 = y_percent_multipler; bottom_center_gizmo->y_field_multi1 = y_percent_multipler; bottom_right_gizmo->x_field_multi1 = x_percent_multipler; bottom_right_gizmo->y_field_multi1 = y_percent_multipler; left_center_gizmo->x_field_multi1 = -x_percent_multipler; right_center_gizmo->x_field_multi1 = x_percent_multipler; rotate_gizmo->x_field_multi1 = x_percent_multipler; } } void TransformEffect::toggle_uniform_scale(bool enabled) { scale_y->SetEnabled(!enabled); top_center_gizmo->y_field1 = enabled ? scale_x : scale_y; bottom_center_gizmo->y_field1 = enabled ? scale_x : scale_y; top_left_gizmo->y_field1 = enabled ? nullptr : scale_y; top_right_gizmo->y_field1 = enabled ? nullptr : scale_y; bottom_left_gizmo->y_field1 = enabled ? nullptr : scale_y; bottom_right_gizmo->y_field1 = enabled ? nullptr : scale_y; } void TransformEffect::process_coords(double timecode, GLTextureCoords& coords, int) { // position glTranslated(position_x->GetDoubleAt(timecode)-(parent_clip->sequence->width/2), position_y->GetDoubleAt(timecode)-(parent_clip->sequence->height/2), 0); // anchor point int anchor_x_offset = qRound(anchor_x_box->GetDoubleAt(timecode)); int anchor_y_offset = qRound(anchor_y_box->GetDoubleAt(timecode)); coords.vertexTopLeftX -= anchor_x_offset; coords.vertexTopRightX -= anchor_x_offset; coords.vertexBottomLeftX -= anchor_x_offset; coords.vertexBottomRightX -= anchor_x_offset; coords.vertexTopLeftY -= anchor_y_offset; coords.vertexTopRightY -= anchor_y_offset; coords.vertexBottomLeftY -= anchor_y_offset; coords.vertexBottomRightY -= anchor_y_offset; // rotation glRotated(rotation->GetDoubleAt(timecode), 0, 0, 1); // scale double sx = scale_x->GetDoubleAt(timecode)*0.01; double sy = (uniform_scale_field->GetBoolAt(timecode)) ? sx : scale_y->GetDoubleAt(timecode)*0.01; glScaled(sx, sy, 1); // blend mode coords.blendmode = blend_mode_box->GetValueAt(timecode).toInt(); // opacity coords.opacity *= float(opacity->GetDoubleAt(timecode)*0.01); } void TransformEffect::gizmo_draw(double, GLTextureCoords& coords) { top_left_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); top_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopLeftX, coords.vertexTopRightX, 0.5), lerp(coords.vertexTopLeftY, coords.vertexTopRightY, 0.5)); top_right_gizmo->world_pos[0] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); right_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexTopRightX, coords.vertexBottomRightX, 0.5), lerp(coords.vertexTopRightY, coords.vertexBottomRightY, 0.5)); bottom_right_gizmo->world_pos[0] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); bottom_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomRightX, coords.vertexBottomLeftX, 0.5), lerp(coords.vertexBottomRightY, coords.vertexBottomLeftY, 0.5)); bottom_left_gizmo->world_pos[0] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); left_center_gizmo->world_pos[0] = QPoint(lerp(coords.vertexBottomLeftX, coords.vertexTopLeftX, 0.5), lerp(coords.vertexBottomLeftY, coords.vertexTopLeftY, 0.5)); rotate_gizmo->world_pos[0] = QPoint(lerp(top_center_gizmo->world_pos[0].x(), bottom_center_gizmo->world_pos[0].x(), -0.1), lerp(top_center_gizmo->world_pos[0].y(), bottom_center_gizmo->world_pos[0].y(), -0.1)); rect_gizmo->world_pos[0] = QPoint(coords.vertexTopLeftX, coords.vertexTopLeftY); rect_gizmo->world_pos[1] = QPoint(coords.vertexTopRightX, coords.vertexTopRightY); rect_gizmo->world_pos[2] = QPoint(coords.vertexBottomRightX, coords.vertexBottomRightY); rect_gizmo->world_pos[3] = QPoint(coords.vertexBottomLeftX, coords.vertexBottomLeftY); }