diff --git a/debug.cpp b/debug.cpp index e948b5e51..b64e38ecd 100644 --- a/debug.cpp +++ b/debug.cpp @@ -34,79 +34,79 @@ QFile debug_file; QTextStream debug_stream; void open_debug_file() { - QDir debug_dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); - debug_dir.mkpath("."); - if (debug_dir.exists()) { - debug_file.setFileName(debug_dir.path() + "/debug_log"); - if (debug_file.open(QFile::WriteOnly)) { - debug_stream.setDevice(&debug_file); - } else { - qWarning() << "Couldn't open debug log file, debug log will not be saved"; - } + QDir debug_dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); + debug_dir.mkpath("."); + if (debug_dir.exists()) { + debug_file.setFileName(debug_dir.path() + "/debug_log"); + if (debug_file.open(QFile::WriteOnly)) { + debug_stream.setDevice(&debug_file); + } else { + qWarning() << "Couldn't open debug log file, debug log will not be saved"; } + } } void close_debug_file() { - if (debug_file.isOpen()) { - debug_file.close(); - } + if (debug_file.isOpen()) { + debug_file.close(); + } } void debug_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { - debug_mutex.lock(); - const QByteArray localMsg = msg.toLocal8Bit(); - const QDateTime now = QDateTime::currentDateTime(); - const QByteArray timeRepr(now.toString(Qt::ISODate).toLocal8Bit()); - QString msgTag; - QString fontColor; - switch (type) { - case QtDebugMsg: - msgTag = "DEBUG"; - fontColor = "grey"; - break; - case QtInfoMsg: - msgTag = "INFO"; - fontColor = "blue"; - break; - case QtWarningMsg: - msgTag = "WARNING"; - fontColor = "yellow"; - break; - case QtCriticalMsg: - msgTag = "ERROR"; - fontColor = "red"; - break; - case QtFatalMsg: - msgTag = "FATAL"; - fontColor = "red"; - break; - default: - fprintf(stderr, "Unknown debug msg type"); - fflush(stderr); - break; - }//switch + debug_mutex.lock(); + const QByteArray localMsg = msg.toLocal8Bit(); + const QDateTime now = QDateTime::currentDateTime(); + const QByteArray timeRepr(now.toString(Qt::ISODate).toLocal8Bit()); + QString msgTag; + QString fontColor; + switch (type) { + case QtDebugMsg: + msgTag = "DEBUG"; + fontColor = "grey"; + break; + case QtInfoMsg: + msgTag = "INFO"; + fontColor = "blue"; + break; + case QtWarningMsg: + msgTag = "WARNING"; + fontColor = "yellow"; + break; + case QtCriticalMsg: + msgTag = "ERROR"; + fontColor = "red"; + break; + case QtFatalMsg: + msgTag = "FATAL"; + fontColor = "red"; + break; + default: + fprintf(stderr, "Unknown debug msg type"); + fflush(stderr); + break; + }//switch - /*fprintf(stderr, "%s [%s] %s (%s:%u, %s)\n", timeRepr.data(), msgTag.toLocal8Bit().constData(), localMsg.data(), + /*fprintf(stderr, "%s [%s] %s (%s:%u, %s)\n", timeRepr.data(), msgTag.toLocal8Bit().constData(), localMsg.data(), context.file, context.line, context.function);*/ - fprintf(stderr, "%s [%s] %s\n", timeRepr.data(), msgTag.toLocal8Bit().constData(), localMsg.data()); + fprintf(stderr, "%s [%s] %s\n", timeRepr.data(), msgTag.toLocal8Bit().constData(), localMsg.data()); - if (debug_file.isOpen()) { - debug_stream << QString("[%1] %2 (%3:%4, %5)\n") - .arg(msgTag, localMsg, context.file, QString::number(context.line), context.function); - } - debug_info.prepend(QString("[%2] %3 (%4:%5, %6)
") - .arg(fontColor, msgTag, localMsg, context.file, QString::number(context.line), context.function)); - fflush(stderr); - if (olive::DebugDialog != nullptr && olive::DebugDialog->isVisible()) { - QMetaObject::invokeMethod(olive::DebugDialog, "update_log", Qt::QueuedConnection); - } - debug_mutex.unlock(); + if (debug_file.isOpen()) { + debug_stream << QString("[%1] %2 (%3:%4, %5)\n") + .arg(msgTag, localMsg, context.file, QString::number(context.line), context.function); + } + debug_info.prepend(QString("[%2] %3 (%4:%5, %6)
") + .arg(fontColor, msgTag, localMsg, context.file, QString::number(context.line), context.function)); + fflush(stderr); + if (olive::DebugDialog != nullptr && olive::DebugDialog->isVisible()) { + QMetaObject::invokeMethod(olive::DebugDialog, "update_log", Qt::QueuedConnection); + } + debug_mutex.unlock(); } const QString &get_debug_str() { - return debug_info; + return debug_info; } diff --git a/effects/internal/blending.frag b/effects/internal/blending.frag index c8d14d593..8f4dd3201 100644 --- a/effects/internal/blending.frag +++ b/effects/internal/blending.frag @@ -1,176 +1,13 @@ #version 110 -const int BLEND_MODE_ADD = 0; -const int BLEND_MODE_AVERAGE = 1; -const int BLEND_MODE_COLORBURN = 2; -const int BLEND_MODE_COLORDODGE = 3; -const int BLEND_MODE_DARKEN = 4; -const int BLEND_MODE_DIFFERENCE = 5; -const int BLEND_MODE_EXCLUSION = 6; -const int BLEND_MODE_GLOW = 7; -const int BLEND_MODE_HARDLIGHT = 8; -const int BLEND_MODE_HARDMIX = 9; -const int BLEND_MODE_LIGHTEN = 10; -const int BLEND_MODE_LINEARBURN = 11; -const int BLEND_MODE_LINEARDODGE = 12; -const int BLEND_MODE_LINEARLIGHT = 13; -const int BLEND_MODE_MULTIPLY = 14; -const int BLEND_MODE_NEGATION = 15; -const int BLEND_MODE_NORMAL = 16; -const int BLEND_MODE_OVERLAY = 17; -const int BLEND_MODE_PHOENIX = 18; -const int BLEND_MODE_PINLIGHT = 19; -const int BLEND_MODE_REFLECT = 20; -const int BLEND_MODE_SCREEN = 21; -const int BLEND_MODE_SOFTLIGHT = 22; -const int BLEND_MODE_SUBSTRACT = 23; -const int BLEND_MODE_SUBTRACT = 24; -const int BLEND_MODE_VIVIDLIGHT = 25; +/* + This main stump is combined with another shader loaded externally to produce a blending mode. -uniform sampler2D background; -uniform sampler2D foreground; + For a custom blend mode, the function blend() MUST be available, and use the following syntax: -uniform int blendmode; -uniform float opacity; + blend(vec3 base_color, vec3 blend_color, float opacity) -varying vec2 vTexCoord; - -// adapted from https://github.com/jamieowen/glsl-blend -// and http://www.deepskycolors.com/archivo/2010/04/21/formulas-for-Photoshop-blending-modes.html - -// float blending functions -float blend_color_burn(float base, float blend) { - return (blend==0.0)?blend:max((1.0-((1.0-base)/blend)),0.0); -} - -float blend_color_dodge(float base, float blend) { - return (blend==1.0)?blend:min(base/(1.0-blend),1.0); -} - -float blend_vivid_light(float base, float blend) { - return (blend<0.5)?blend_color_burn(base,(2.0*blend)):blend_color_dodge(base,(2.0*(blend-0.5))); -} - -vec3 blend_vivid_light(vec3 base, vec3 blend) { - return vec3(blend_vivid_light(base.r,blend.r),blend_vivid_light(base.g,blend.g),blend_vivid_light(base.b,blend.b)); -} - -float blend_hard_mix(float base, float blend) { - return (blend_vivid_light(base,blend)<0.5)?0.0:1.0; -} - -float blend_lighten(float base, float blend) { - return max(blend,base); -} - -float blend_overlay(float base, float blend) { - return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend)); -} - -vec3 blend_overlay(vec3 base, vec3 blend) { - return vec3(blend_overlay(base.r,blend.r),blend_overlay(base.g,blend.g),blend_overlay(base.b,blend.b)); -} - -float blend_darken(float base, float blend) { - return min(blend, base); -} - -float blend_linear_burn(float base, float blend) { - return max(base+blend-1.0,0.0); -} - -vec3 blend_linear_burn(vec3 base, vec3 blend) { - return max(base+blend-vec3(1.0),vec3(0.0)); -} - -float blend_linear_dodge(float base, float blend) { - return min(base+blend,1.0); -} - -vec3 blend_linear_dodge(vec3 base, vec3 blend) { - return min(base+blend,vec3(1.0)); -} - -float blend_linear_light(float base, float blend) { - return blend<0.5?blend_linear_burn(base,(2.0*blend)):blend_linear_dodge(base,(2.0*(blend-0.5))); -} - -float blend_pin_light(float base, float blend) { - return (blend<0.5)?blend_darken(base,(2.0*blend)):blend_lighten(base,(2.0*(blend-0.5))); -} - -float blend_reflect(float base, float blend) { - return (blend==1.0)?blend:min(base*base/(1.0-blend),1.0); -} - -vec3 blend_reflect(vec3 base, vec3 blend) { - return vec3(blend_reflect(base.r,blend.r),blend_reflect(base.g,blend.g),blend_reflect(base.b,blend.b)); -} - -float blend_screen(float base, float blend) { - return 1.0-((1.0-base)*(1.0-blend)); -} - -float blend_substract(float base, float blend) { - return max(base+blend-1.0,0.0); -} - -float blend_soft_light(float base, float blend) { - return (blend<0.5)?(2.0*base*blend+base*base*(1.0-2.0*blend)):(sqrt(base)*(2.0*blend-1.0)+2.0*base*(1.0-blend)); -} - -// RGB blending function, alpha is handled below -vec3 blend(vec3 base, vec3 blend) { - if (blendmode == BLEND_MODE_AVERAGE) { - return (base+blend)/2.0; - } else if (blendmode == BLEND_MODE_COLORBURN) { - return vec3(blend_color_burn(base.r, blend.r), blend_color_burn(base.g, blend.g), blend_color_burn(base.b, blend.b)); - } else if (blendmode == BLEND_MODE_COLORDODGE) { - return vec3(blend_color_dodge(base.r, blend.r), blend_color_dodge(base.g, blend.g), blend_color_dodge(base.b, blend.b)); - } else if (blendmode == BLEND_MODE_DARKEN) { - return vec3(blend_darken(base.r, blend.r), blend_darken(base.g, blend.g), blend_darken(base.b, blend.b)); - } else if (blendmode == BLEND_MODE_DIFFERENCE) { - return abs(base-blend); - } else if (blendmode == BLEND_MODE_EXCLUSION) { - return base+blend-2.0*base*blend; - } else if (blendmode == BLEND_MODE_GLOW) { - return blend_reflect(blend, base); - } else if (blendmode == BLEND_MODE_HARDLIGHT) { - return blend_overlay(blend,base); - } else if (blendmode == BLEND_MODE_HARDMIX) { - return vec3(blend_hard_mix(base.r,blend.r),blend_hard_mix(base.g,blend.g),blend_hard_mix(base.b,blend.b)); - } else if (blendmode == BLEND_MODE_LIGHTEN) { - return vec3(blend_lighten(base.r,blend.r),blend_lighten(base.g,blend.g),blend_lighten(base.b,blend.b)); - } else if (blendmode == BLEND_MODE_LINEARBURN || blendmode == BLEND_MODE_SUBTRACT) { - return blend_linear_burn(base, blend); - } else if (blendmode == BLEND_MODE_LINEARDODGE || blendmode == BLEND_MODE_ADD) { - return blend_linear_dodge(base, blend); - } else if (blendmode == BLEND_MODE_LINEARLIGHT) { - return vec3(blend_linear_light(base.r,blend.r),blend_linear_light(base.g,blend.g),blend_linear_light(base.b,blend.b)); - } else if (blendmode == BLEND_MODE_MULTIPLY) { - return (base * blend); - } else if (blendmode == BLEND_MODE_NEGATION) { - return vec3(1.0)-abs(vec3(1.0)-base-blend); - } else if (blendmode == BLEND_MODE_OVERLAY) { - return blend_overlay(base, blend); - } else if (blendmode == BLEND_MODE_PHOENIX) { - return min(base,blend)-max(base,blend)+vec3(1.0); - } else if (blendmode == BLEND_MODE_PINLIGHT) { - return vec3(blend_pin_light(base.r,blend.r),blend_pin_light(base.g,blend.g),blend_pin_light(base.b,blend.b)); - } else if (blendmode == BLEND_MODE_REFLECT) { - return blend_reflect(base, blend); - } else if (blendmode == BLEND_MODE_SCREEN) { - return vec3(blend_screen(base.r,blend.r),blend_screen(base.g,blend.g),blend_screen(base.b,blend.b)); - } else if (blendmode == BLEND_MODE_SUBSTRACT) { - return max(base+blend-vec3(1.0),vec3(0.0)); - } else if (blendmode == BLEND_MODE_SOFTLIGHT) { - return vec3(blend_soft_light(base.r,blend.r),blend_soft_light(base.g,blend.g),blend_soft_light(base.b,blend.b)); - } else if (blendmode == BLEND_MODE_VIVIDLIGHT) { - return vec3(blend_vivid_light(base.r,blend.r),blend_vivid_light(base.g,blend.g),blend_vivid_light(base.b,blend.b)); - } else { - return blend; - } -} +*/ void main(void) { vec4 bg_color = texture2D(background, vTexCoord); @@ -179,9 +16,6 @@ void main(void) { // blend textures together vec3 composite = blend(bg_color.rgb, fg_color.rgb); - // add foreground and background alpha's together - // float alpha_opac = fg_color.a*opacity; - if (blendmode == BLEND_MODE_OVERLAY || blendmode == BLEND_MODE_LIGHTEN || blendmode == BLEND_MODE_SCREEN @@ -198,7 +32,6 @@ void main(void) { } vec4 full_composite = vec4(composite + bg_color.rgb*(1.0-fg_color.a), bg_color.a + fg_color.a); - // vec4 full_composite = vec4(mix(bg_color.rgb, composite, alpha_opac), bg_color.a + alpha_opac); full_composite = mix(bg_color, full_composite, opacity); diff --git a/effects/internal/transformeffect.cpp b/effects/internal/transformeffect.cpp index 07dd08d3f..f4065ba1e 100644 --- a/effects/internal/transformeffect.cpp +++ b/effects/internal/transformeffect.cpp @@ -44,230 +44,210 @@ #include "ui/viewerwidget.h" TransformEffect::TransformEffect(Clip* c, const EffectMeta* em) : Effect(c, em) { - enable_coords = true; + enable_coords = true; - EffectRow* position_row = add_row(tr("Position")); - position_x = position_row->add_field(EFFECT_FIELD_DOUBLE, "posx"); // position X - position_y = position_row->add_field(EFFECT_FIELD_DOUBLE, "posy"); // position Y + EffectRow* position_row = add_row(tr("Position")); + position_x = position_row->add_field(EFFECT_FIELD_DOUBLE, "posx"); // position X + position_y = position_row->add_field(EFFECT_FIELD_DOUBLE, "posy"); // position Y - EffectRow* scale_row = add_row(tr("Scale")); - scale_x = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scalex"); // scale X (and Y is uniform scale is selected) - scale_x->set_double_minimum_value(0); - scale_x->set_double_maximum_value(3000); - scale_y = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scaley"); // scale Y (disabled if uniform scale is selected) - scale_y->set_double_minimum_value(0); - scale_y->set_double_maximum_value(3000); + EffectRow* scale_row = add_row(tr("Scale")); + scale_x = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scalex"); // scale X (and Y is uniform scale is selected) + scale_x->set_double_minimum_value(0); + scale_x->set_double_maximum_value(3000); + scale_y = scale_row->add_field(EFFECT_FIELD_DOUBLE, "scaley"); // scale Y (disabled if uniform scale is selected) + scale_y->set_double_minimum_value(0); + scale_y->set_double_maximum_value(3000); - EffectRow* uniform_scale_row = add_row(tr("Uniform Scale")); - uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL, "uniformscale"); // uniform scale option + EffectRow* uniform_scale_row = add_row(tr("Uniform Scale")); + uniform_scale_field = uniform_scale_row->add_field(EFFECT_FIELD_BOOL, "uniformscale"); // uniform scale option - EffectRow* rotation_row = add_row(tr("Rotation")); - rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation"); + EffectRow* rotation_row = add_row(tr("Rotation")); + rotation = rotation_row->add_field(EFFECT_FIELD_DOUBLE, "rotation"); - EffectRow* anchor_point_row = add_row(tr("Anchor Point")); - anchor_x_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchorx"); // anchor point X - anchor_y_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchory"); // anchor point Y + EffectRow* anchor_point_row = add_row(tr("Anchor Point")); + anchor_x_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchorx"); // anchor point X + anchor_y_box = anchor_point_row->add_field(EFFECT_FIELD_DOUBLE, "anchory"); // anchor point Y - EffectRow* opacity_row = add_row(tr("Opacity")); - opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE, "opacity"); // opacity - opacity->set_double_minimum_value(0); - opacity->set_double_maximum_value(100); + EffectRow* opacity_row = add_row(tr("Opacity")); + opacity = opacity_row->add_field(EFFECT_FIELD_DOUBLE, "opacity"); // opacity + opacity->set_double_minimum_value(0); + opacity->set_double_maximum_value(100); - EffectRow* blend_mode_row = add_row(tr("Blend Mode")); - blend_mode_box = blend_mode_row->add_field(EFFECT_FIELD_COMBO, "blendmode", 2); // blend mode - blend_mode_box->add_combo_item(tr("Normal"), BLEND_MODE_NORMAL); - blend_mode_box->add_combo_item(tr("Darken"), BLEND_MODE_DARKEN); - blend_mode_box->add_combo_item(tr("Multiply"), BLEND_MODE_MULTIPLY); - blend_mode_box->add_combo_item(tr("Color Burn"), BLEND_MODE_COLORBURN); - blend_mode_box->add_combo_item(tr("Linear Burn"), BLEND_MODE_LINEARBURN); - blend_mode_box->add_combo_item(tr("Lighten"), BLEND_MODE_LIGHTEN); - blend_mode_box->add_combo_item(tr("Screen"), BLEND_MODE_SCREEN); - blend_mode_box->add_combo_item(tr("Color Dodge"), BLEND_MODE_COLORDODGE); - blend_mode_box->add_combo_item(tr("Linear Dodge (Add)"), BLEND_MODE_LINEARDODGE); - blend_mode_box->add_combo_item(tr("Overlay"), BLEND_MODE_OVERLAY); - blend_mode_box->add_combo_item(tr("Soft Light"), BLEND_MODE_SOFTLIGHT); - blend_mode_box->add_combo_item(tr("Hard Light"), BLEND_MODE_HARDLIGHT); - blend_mode_box->add_combo_item(tr("Vivid Light"), BLEND_MODE_VIVIDLIGHT); - blend_mode_box->add_combo_item(tr("Linear Light"), BLEND_MODE_LINEARLIGHT); - blend_mode_box->add_combo_item(tr("Pin Light"), BLEND_MODE_PINLIGHT); - blend_mode_box->add_combo_item(tr("Hard Mix"), BLEND_MODE_HARDMIX); - blend_mode_box->add_combo_item(tr("Difference"), BLEND_MODE_DIFFERENCE); - blend_mode_box->add_combo_item(tr("Exclusion"), BLEND_MODE_EXCLUSION); - blend_mode_box->add_combo_item(tr("Reflect"), BLEND_MODE_REFLECT); -// blend_mode_box->add_combo_item(tr("Subtract"), BLEND_MODE_SUBTRACT); - blend_mode_box->add_combo_item(tr("Substract"), BLEND_MODE_SUBSTRACT); -// blend_mode_box->add_combo_item(tr("Add"), BLEND_MODE_ADD); - blend_mode_box->add_combo_item(tr("Average"), BLEND_MODE_AVERAGE); - blend_mode_box->add_combo_item(tr("Glow"), BLEND_MODE_GLOW); - blend_mode_box->add_combo_item(tr("Negation"), BLEND_MODE_NEGATION); - blend_mode_box->add_combo_item(tr("Phoenix"), BLEND_MODE_PHOENIX); + EffectRow* blend_mode_row = add_row(tr("Blend Mode")); + blend_mode_box = blend_mode_row->add_field(EFFECT_FIELD_COMBO, "blendmode", 2); // blend mode + blend_mode_box->add_combo_item(tr("Normal"), -1); - // 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; + // add loaded blending modes + for (int i=0;iadd_combo_item(olive::blend_modes.at(i).name, i); + } - top_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_center_gizmo->set_cursor(Qt::SizeVerCursor); - top_center_gizmo->y_field1 = scale_x; + // 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_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - top_right_gizmo->set_cursor(Qt::SizeBDiagCursor); - top_right_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; - bottom_left_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_left_gizmo->set_cursor(Qt::SizeBDiagCursor); - bottom_left_gizmo->x_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_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_center_gizmo->set_cursor(Qt::SizeVerCursor); - bottom_center_gizmo->y_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_right_gizmo = add_gizmo(GIZMO_TYPE_DOT); - bottom_right_gizmo->set_cursor(Qt::SizeFDiagCursor); - bottom_right_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; - left_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - left_center_gizmo->set_cursor(Qt::SizeHorCursor); - left_center_gizmo->x_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; - right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); - right_center_gizmo->set_cursor(Qt::SizeHorCursor); - right_center_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; - 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; + right_center_gizmo = add_gizmo(GIZMO_TYPE_DOT); + right_center_gizmo->set_cursor(Qt::SizeHorCursor); + right_center_gizmo->x_field1 = scale_x; - rotate_gizmo = add_gizmo(GIZMO_TYPE_DOT); - rotate_gizmo->color = Qt::green; - rotate_gizmo->set_cursor(Qt::SizeAllCursor); - rotate_gizmo->x_field1 = rotation; + 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; - rect_gizmo = add_gizmo(GIZMO_TYPE_POLY); - rect_gizmo->x_field1 = position_x; - rect_gizmo->y_field1 = 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; - connect(uniform_scale_field, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool))); + rect_gizmo = add_gizmo(GIZMO_TYPE_POLY); + rect_gizmo->x_field1 = position_x; + rect_gizmo->y_field1 = position_y; - // set defaults - uniform_scale_field->set_bool_value(true); - blend_mode_box->set_combo_index(0); - set = false; - refresh(); + connect(uniform_scale_field, SIGNAL(toggled(bool)), this, SLOT(toggle_uniform_scale(bool))); + + // set defaults + uniform_scale_field->set_bool_value(true); + blend_mode_box->set_combo_index(0); + set = false; + refresh(); } void adjust_field(EffectField* field, double old_offset, double new_offset) { - if (field->keyframes.size() > 0) { - for (int i=0;ikeyframes.size();i++) { - field->keyframes[i].data = field->keyframes.at(i).data.toDouble() - old_offset + new_offset; - } - } else { - field->set_current_data(field->get_current_data().toDouble() - old_offset + new_offset); - } + if (field->keyframes.size() > 0) { + for (int i=0;ikeyframes.size();i++) { + field->keyframes[i].data = field->keyframes.at(i).data.toDouble() - old_offset + new_offset; + } + } else { + field->set_current_data(field->get_current_data().toDouble() - old_offset + new_offset); + } } void TransformEffect::refresh() { - if (parent_clip != nullptr && parent_clip->sequence != nullptr) { - double new_default_pos_x = parent_clip->sequence->width/2; - double new_default_pos_y = parent_clip->sequence->height/2; + if (parent_clip != nullptr && parent_clip->sequence != nullptr) { + double new_default_pos_x = parent_clip->sequence->width/2; + double new_default_pos_y = parent_clip->sequence->height/2; - /*if (set) { - adjust_field(position_x, default_pos_x, new_default_pos_x); - adjust_field(position_y, default_pos_y, new_default_pos_y); - }*/ + /*if (set) { + adjust_field(position_x, default_pos_x, new_default_pos_x); + adjust_field(position_y, default_pos_y, new_default_pos_y); + }*/ - double default_pos_x = new_default_pos_x; - double default_pos_y = new_default_pos_y; + double default_pos_x = new_default_pos_x; + double default_pos_y = new_default_pos_y; - position_x->set_double_default_value(default_pos_x); - position_y->set_double_default_value(default_pos_y); - scale_x->set_double_default_value(100); - scale_y->set_double_default_value(100); + position_x->set_double_default_value(default_pos_x); + position_y->set_double_default_value(default_pos_y); + scale_x->set_double_default_value(100); + scale_y->set_double_default_value(100); - anchor_x_box->set_double_default_value(0); - anchor_y_box->set_double_default_value(0); - opacity->set_double_default_value(100); + anchor_x_box->set_double_default_value(0); + anchor_y_box->set_double_default_value(0); + opacity->set_double_default_value(100); - 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; + 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; - set = true; - } + set = true; + } } void TransformEffect::toggle_uniform_scale(bool enabled) { - scale_y->set_enabled(!enabled); + scale_y->set_enabled(!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; + 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->get_double_value(timecode)-(parent_clip->sequence->width/2), position_y->get_double_value(timecode)-(parent_clip->sequence->height/2), 0); + // position + glTranslated(position_x->get_double_value(timecode)-(parent_clip->sequence->width/2), position_y->get_double_value(timecode)-(parent_clip->sequence->height/2), 0); - // anchor point - int anchor_x_offset = qRound(anchor_x_box->get_double_value(timecode)); - int anchor_y_offset = qRound(anchor_y_box->get_double_value(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; + // anchor point + int anchor_x_offset = qRound(anchor_x_box->get_double_value(timecode)); + int anchor_y_offset = qRound(anchor_y_box->get_double_value(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->get_double_value(timecode), 0, 0, 1); + // rotation + glRotated(rotation->get_double_value(timecode), 0, 0, 1); - // scale - double sx = scale_x->get_double_value(timecode)*0.01; - double sy = (uniform_scale_field->get_bool_value(timecode)) ? sx : scale_y->get_double_value(timecode)*0.01; - glScaled(sx, sy, 1); + // scale + double sx = scale_x->get_double_value(timecode)*0.01; + double sy = (uniform_scale_field->get_bool_value(timecode)) ? sx : scale_y->get_double_value(timecode)*0.01; + glScaled(sx, sy, 1); - // blend mode - coords.blendmode = blend_mode_box->get_combo_data(timecode).toInt(); + // blend mode + coords.blendmode = blend_mode_box->get_combo_data(timecode).toInt(); - // opacity - coords.opacity *= float(opacity->get_double_value(timecode)*0.01); + // opacity + coords.opacity *= float(opacity->get_double_value(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)); + 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)); + 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); + 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); } diff --git a/effects/multiply.blend b/effects/multiply.blend new file mode 100644 index 000000000..0da71e49d --- /dev/null +++ b/effects/multiply.blend @@ -0,0 +1,9 @@ +vec3 blendMultiply(vec3 base, vec3 blend) { + return base*blend; +} + +vec3 blendMultiply(vec3 base, vec3 blend, float opacity) { + return (blendMultiply(base, blend) * opacity + base * (1.0 - opacity)); +} + +#pragma glslify: export(blendMultiply) \ No newline at end of file diff --git a/io/config.cpp b/io/config.cpp index 5b09d877b..1490ddcbd 100644 --- a/io/config.cpp +++ b/io/config.cpp @@ -285,6 +285,5 @@ void Config::save(QString path) { } RuntimeConfig::RuntimeConfig() : - shaders_are_enabled(true), - disable_blending(false) + shaders_are_enabled(true) {} diff --git a/io/config.h b/io/config.h index a83eb30d7..c9fc41d92 100644 --- a/io/config.h +++ b/io/config.h @@ -561,14 +561,6 @@ struct RuntimeConfig { */ bool shaders_are_enabled; - /** - * @brief Disable blending modes - * - * Some users had difficulty utilizing blending modes (provided by shaders). Set this to **TRUE** to bypass - * shader-based blending modes and utilize standard (less versatile) OpenGL blending instead. - */ - bool disable_blending; - /** * @brief Load an external translation file * diff --git a/main.cpp b/main.cpp index 69f99ee5e..e36f50fe0 100644 --- a/main.cpp +++ b/main.cpp @@ -34,7 +34,7 @@ extern "C" { #include } -int main(int argc, char *argv[]) { +int main(int argc, char *argv[]) { olive::Global = std::unique_ptr(new OliveGlobal); bool launch_fullscreen = false; @@ -60,7 +60,6 @@ int main(int argc, char *argv[]) { "\t-f, --fullscreen\tStart in full screen mode\n" "\t--disable-shaders\tDisable OpenGL shaders (for debugging)\n" "\t--no-debug\t\tDisable internal debug log and output directly to console\n" - "\t--disable-blend-modes\tDisable shader-based blending for older GPUs\n" "\t--translation \tSet an external language file to use\n" "\n" "Environment Variables:\n" @@ -75,8 +74,6 @@ int main(int argc, char *argv[]) { olive::CurrentRuntimeConfig.shaders_are_enabled = false; } else if (!strcmp(argv[i], "--no-debug")) { use_internal_logger = false; - } else if (!strcmp(argv[i], "--disable-blend-modes")) { - olive::CurrentRuntimeConfig.disable_blending = true; } else if (!strcmp(argv[i], "--translation")) { if (i + 1 < argc && argv[i + 1][0] != '-') { // load translation file diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 174baa795..1f0088ed1 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -199,8 +199,8 @@ void EffectControls::show_effect_menu(int type, int subtype) { QMenu effects_menu(this); effects_menu.setToolTipsVisible(true); - for (int i=0;isetObjectName("v"); @@ -1803,8 +1803,8 @@ void Timeline::transition_tool_click() { transition_menu.addSeparator(); - for (int i=0;isetObjectName("a"); diff --git a/project/effect.cpp b/project/effect.cpp index a49ae6977..4cf2bdc22 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -67,12 +67,13 @@ #include #include -QVector effects; +QVector olive::effects; +QVector olive::blend_modes; EffectPtr Effect::Create(Clip* c, const EffectMeta* em) { - if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) { - // must be an internal effect - switch (em->internal) { + if (em->internal >= 0 && em->internal < EFFECT_INTERNAL_COUNT) { + // must be an internal effect + switch (em->internal) { case EFFECT_INTERNAL_TRANSFORM: return EffectPtr(new TransformEffect(c, em)); case EFFECT_INTERNAL_TEXT: return EffectPtr(new TextEffect(c, em)); case EFFECT_INTERNAL_TIMECODE: return EffectPtr(new TimecodeEffect(c, em)); @@ -90,851 +91,851 @@ EffectPtr Effect::Create(Clip* c, const EffectMeta* em) { #ifndef NOFREI0R case EFFECT_INTERNAL_FREI0R: return EffectPtr(new Frei0rEffect(c, em)); #endif - } - } else if (!em->filename.isEmpty()) { - // load effect from file + } + } else if (!em->filename.isEmpty()) { + // load effect from file return EffectPtr(new Effect(c, em)); - } else { - qCritical() << "Invalid effect data"; + } else { + qCritical() << "Invalid effect data"; QMessageBox::critical(olive::MainWindow, - QCoreApplication::translate("Effect", "Invalid effect"), - QCoreApplication::translate("Effect", "No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive.").arg(em->name)); - } - return nullptr; + QCoreApplication::translate("Effect", "Invalid effect"), + QCoreApplication::translate("Effect", "No candidate for effect '%1'. This effect may be corrupt. Try reinstalling it or Olive.").arg(em->name)); + } + return nullptr; } const EffectMeta* Effect::GetInternalMeta(int internal_id, int type) { - for (int i=0;ienabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); - ui = new QWidget(container); - ui_layout = new QGridLayout(ui); - ui_layout->setSpacing(4); - container->setContents(ui); + // set up base UI + container = new CollapsibleWidget(); + connect(container->enabled_check, SIGNAL(clicked(bool)), this, SLOT(field_changed())); + ui = new QWidget(container); + ui_layout = new QGridLayout(ui); + ui_layout->setSpacing(4); + container->setContents(ui); - connect(container->title_bar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); + connect(container->title_bar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu(const QPoint&))); - if (em != nullptr) { - // set up UI from effect file - container->setText(em->name); + if (em != nullptr) { + // set up UI from effect file + container->setText(em->name); - if (!em->filename.isEmpty() && em->internal == -1) { - QFile effect_file(em->filename); - if (effect_file.open(QFile::ReadOnly)) { - QXmlStreamReader reader(&effect_file); + if (!em->filename.isEmpty() && em->internal == -1) { + QFile effect_file(em->filename); + if (effect_file.open(QFile::ReadOnly)) { + QXmlStreamReader reader(&effect_file); - while (!reader.atEnd()) { - if (reader.name() == "row" && reader.isStartElement()) { - QString row_name; - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;ifilename << "- ID cannot be empty."; - } else if (type > -1) { - EffectField* field = row->add_field(type, id); - connect(field, SIGNAL(changed()), this, SLOT(field_changed())); - switch (type) { - case EFFECT_FIELD_DOUBLE: - for (int i=0;iset_double_default_value(attr.value().toDouble()); - } else if (attr.name() == "min") { - field->set_double_minimum_value(attr.value().toDouble()); - } else if (attr.name() == "max") { - field->set_double_maximum_value(attr.value().toDouble()); - } - } - break; - case EFFECT_FIELD_COLOR: - { - QColor color; - for (int i=0;iset_color_value(color); - } - break; - case EFFECT_FIELD_STRING: - for (int i=0;iset_string_value(attr.value().toString()); - } - } - break; - case EFFECT_FIELD_BOOL: - for (int i=0;iset_bool_value(attr.value() == "1"); - } - } - break; - case EFFECT_FIELD_COMBO: - { - int combo_index = 0; - for (int i=0;iadd_combo_item(reader.text().toString(), 0); - } - } - field->set_combo_index(combo_index); - } - break; - case EFFECT_FIELD_FONT: - for (int i=0;iset_font_name(attr.value().toString()); - } - } - break; - case EFFECT_FIELD_FILE: - for (int i=0;iset_filename(attr.value().toString()); - } - } - break; - } - } - } - } - } - } else if (reader.name() == "shader" && reader.isStartElement()) { - enable_shader = true; - const QXmlStreamAttributes& attributes = reader.attributes(); - for (int i=0;ifilename; - enable_superimpose = false; - } - break; - } - } - }*/ - reader.readNext(); - } + if (id.isEmpty()) { + qCritical() << "Couldn't load field from" << em->filename << "- ID cannot be empty."; + } else if (type > -1) { + EffectField* field = row->add_field(type, id); + connect(field, SIGNAL(changed()), this, SLOT(field_changed())); + switch (type) { + case EFFECT_FIELD_DOUBLE: + for (int i=0;iset_double_default_value(attr.value().toDouble()); + } else if (attr.name() == "min") { + field->set_double_minimum_value(attr.value().toDouble()); + } else if (attr.name() == "max") { + field->set_double_maximum_value(attr.value().toDouble()); + } + } + break; + case EFFECT_FIELD_COLOR: + { + QColor color; + for (int i=0;iset_color_value(color); + } + break; + case EFFECT_FIELD_STRING: + for (int i=0;iset_string_value(attr.value().toString()); + } + } + break; + case EFFECT_FIELD_BOOL: + for (int i=0;iset_bool_value(attr.value() == "1"); + } + } + break; + case EFFECT_FIELD_COMBO: + { + int combo_index = 0; + for (int i=0;iadd_combo_item(reader.text().toString(), 0); + } + } + field->set_combo_index(combo_index); + } + break; + case EFFECT_FIELD_FONT: + for (int i=0;iset_font_name(attr.value().toString()); + } + } + break; + case EFFECT_FIELD_FILE: + for (int i=0;iset_filename(attr.value().toString()); + } + } + break; + } + } + } + } + } + } else if (reader.name() == "shader" && reader.isStartElement()) { + enable_shader = true; + const QXmlStreamAttributes& attributes = reader.attributes(); + for (int i=0;ifilename; + enable_superimpose = false; + } + break; + } + } + }*/ + reader.readNext(); + } - effect_file.close(); - } else { - qCritical() << "Failed to open effect file" << em->filename; - } - } - } + effect_file.close(); + } else { + qCritical() << "Failed to open effect file" << em->filename; + } + } + } } Effect::~Effect() { - if (isOpen) { - close(); - } + if (isOpen) { + close(); + } - delete container; + delete container; - for (int i=0;irows.at(i); - copy_row->setKeyframing(row->isKeyframing()); - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - EffectField* copy_field = copy_row->field(j); - copy_field->keyframes = field->keyframes; - copy_field->set_current_data(field->get_current_data()); - } - } + for (int i=0;irows.at(i); + copy_row->setKeyframing(row->isKeyframing()); + for (int j=0;jfieldCount();j++) { + EffectField* field = row->field(j); + EffectField* copy_field = copy_row->field(j); + copy_field->keyframes = field->keyframes; + copy_field->set_current_data(field->get_current_data()); + } + } } EffectRow* Effect::add_row(const QString& name, bool savable, bool keyframable) { - EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size(), keyframable); - rows.append(row); - return row; + EffectRow* row = new EffectRow(this, savable, ui_layout, name, rows.size(), keyframable); + rows.append(row); + return row; } EffectRow* Effect::row(int i) { - return rows.at(i); + return rows.at(i); } int Effect::row_count() { - return rows.size(); + return rows.size(); } EffectGizmo *Effect::add_gizmo(int type) { - EffectGizmo* gizmo = new EffectGizmo(type); - gizmos.append(gizmo); - return gizmo; + EffectGizmo* gizmo = new EffectGizmo(type); + gizmos.append(gizmo); + return gizmo; } EffectGizmo *Effect::gizmo(int i) { - return gizmos.at(i); + return gizmos.at(i); } int Effect::gizmo_count() { - return gizmos.size(); + return gizmos.size(); } void Effect::refresh() {} void Effect::field_changed() { - panel_sequence_viewer->viewer_widget->frame_update(); - panel_graph_editor->update_panel(); + panel_sequence_viewer->viewer_widget->frame_update(); + panel_graph_editor->update_panel(); } void Effect::show_context_menu(const QPoint& pos) { - if (meta->type == EFFECT_TYPE_EFFECT) { + if (meta->type == EFFECT_TYPE_EFFECT) { QMenu menu(olive::MainWindow); - int index = get_index_in_clip(); + int index = get_index_in_clip(); - menu.addAction(tr("Cu&t"), panel_effect_controls, SLOT(cut())); - menu.addAction(tr("&Copy"), panel_effect_controls, SLOT(copy(bool))); + menu.addAction(tr("Cu&t"), panel_effect_controls, SLOT(cut())); + menu.addAction(tr("&Copy"), panel_effect_controls, SLOT(copy(bool))); - panel_effect_controls->add_effect_paste_action(&menu); + panel_effect_controls->add_effect_paste_action(&menu); - menu.addSeparator(); + menu.addSeparator(); - if (index > 0) { - menu.addAction(tr("Move &Up"), this, SLOT(move_up())); - } + if (index > 0) { + menu.addAction(tr("Move &Up"), this, SLOT(move_up())); + } - if (index < parent_clip->effects.size() - 1) { - menu.addAction(tr("Move &Down"), this, SLOT(move_down())); - } + if (index < parent_clip->effects.size() - 1) { + menu.addAction(tr("Move &Down"), this, SLOT(move_down())); + } - menu.addSeparator(); + menu.addSeparator(); - menu.addAction(tr("D&elete"), this, SLOT(delete_self())); + menu.addAction(tr("D&elete"), this, SLOT(delete_self())); - menu.addSeparator(); + menu.addSeparator(); - menu.addAction(tr("Load Settings From File"), this, SLOT(load_from_file())); + menu.addAction(tr("Load Settings From File"), this, SLOT(load_from_file())); - menu.addAction(tr("Save Settings to File"), this, SLOT(save_to_file())); + menu.addAction(tr("Save Settings to File"), this, SLOT(save_to_file())); - menu.exec(container->title_bar->mapToGlobal(pos)); - } + menu.exec(container->title_bar->mapToGlobal(pos)); + } } void Effect::delete_self() { - EffectDeleteCommand* command = new EffectDeleteCommand(); - command->clips.append(parent_clip); - command->fx.append(get_index_in_clip()); - olive::UndoStack.push(command); - update_ui(true); + EffectDeleteCommand* command = new EffectDeleteCommand(); + command->clips.append(parent_clip); + command->fx.append(get_index_in_clip()); + olive::UndoStack.push(command); + update_ui(true); } void Effect::move_up() { - MoveEffectCommand* command = new MoveEffectCommand(); - command->clip = parent_clip; - command->from = get_index_in_clip(); - command->to = command->from - 1; - olive::UndoStack.push(command); - panel_effect_controls->reload_clips(); - panel_sequence_viewer->viewer_widget->frame_update(); + MoveEffectCommand* command = new MoveEffectCommand(); + command->clip = parent_clip; + command->from = get_index_in_clip(); + command->to = command->from - 1; + olive::UndoStack.push(command); + panel_effect_controls->reload_clips(); + panel_sequence_viewer->viewer_widget->frame_update(); } void Effect::move_down() { - MoveEffectCommand* command = new MoveEffectCommand(); - command->clip = parent_clip; - command->from = get_index_in_clip(); - command->to = command->from + 1; - olive::UndoStack.push(command); - panel_effect_controls->reload_clips(); - panel_sequence_viewer->viewer_widget->frame_update(); + MoveEffectCommand* command = new MoveEffectCommand(); + command->clip = parent_clip; + command->from = get_index_in_clip(); + command->to = command->from + 1; + olive::UndoStack.push(command); + panel_effect_controls->reload_clips(); + panel_sequence_viewer->viewer_widget->frame_update(); } void Effect::save_to_file() { - // save effect settings to file + // save effect settings to file QString file = QFileDialog::getSaveFileName(olive::MainWindow, - tr("Save Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); + tr("Save Effect Settings"), + QString(), + tr("Effect XML Settings %1").arg("(*.xml)")); - // if the user picked a file - if (!file.isEmpty()) { + // if the user picked a file + if (!file.isEmpty()) { // ensure file ends with .xml extension if (!file.endsWith(".xml", Qt::CaseInsensitive)) { file.append(".xml"); } - QFile file_handle(file); - if (file_handle.open(QFile::WriteOnly)) { + QFile file_handle(file); + if (file_handle.open(QFile::WriteOnly)) { - file_handle.write(save_to_string()); + file_handle.write(save_to_string()); - file_handle.close(); - } else { + file_handle.close(); + } else { QMessageBox::critical(olive::MainWindow, - tr("Save Settings Failed"), - tr("Failed to open \"%1\" for writing.").arg(file), - QMessageBox::Ok); - } - } + tr("Save Settings Failed"), + tr("Failed to open \"%1\" for writing.").arg(file), + QMessageBox::Ok); + } + } } void Effect::load_from_file() { - // load effect settings from file + // load effect settings from file QString file = QFileDialog::getOpenFileName(olive::MainWindow, - tr("Load Effect Settings"), - QString(), - tr("Effect XML Settings %1").arg("(*.xml)")); + tr("Load Effect Settings"), + QString(), + tr("Effect XML Settings %1").arg("(*.xml)")); - // if the user picked a file - if (!file.isEmpty()) { - QFile file_handle(file); - if (file_handle.open(QFile::ReadOnly)) { + // if the user picked a file + if (!file.isEmpty()) { + QFile file_handle(file); + if (file_handle.open(QFile::ReadOnly)) { olive::UndoStack.push(new SetEffectData(EffectPtr(this), file_handle.readAll())); - file_handle.close(); + file_handle.close(); - update_ui(false); - } else { + update_ui(false); + } else { QMessageBox::critical(olive::MainWindow, - tr("Load Settings Failed"), - tr("Failed to open \"%1\" for reading.").arg(file), - QMessageBox::Ok); - } - } + tr("Load Settings Failed"), + tr("Failed to open \"%1\" for reading.").arg(file), + QMessageBox::Ok); + } + } } int Effect::get_index_in_clip() { - if (parent_clip != nullptr) { - for (int i=0;ieffects.size();i++) { + if (parent_clip != nullptr) { + for (int i=0;ieffects.size();i++) { if (parent_clip->effects.at(i).get() == this) { - return i; - } - } - } - return -1; + return i; + } + } + } + return -1; } bool Effect::is_enabled() { - return container->enabled_check->isChecked(); + return container->enabled_check->isChecked(); } void Effect::set_enabled(bool b) { - container->enabled_check->setChecked(b); + container->enabled_check->setChecked(b); } QVariant load_data_from_string(int type, const QString& string) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return string.toDouble(); - case EFFECT_FIELD_COLOR: return QColor(string); - case EFFECT_FIELD_BOOL: return (string == "1"); - case EFFECT_FIELD_COMBO: return string.toInt(); - case EFFECT_FIELD_STRING: - case EFFECT_FIELD_FONT: - case EFFECT_FIELD_FILE: - return string; - } - return QVariant(); + switch (type) { + case EFFECT_FIELD_DOUBLE: return string.toDouble(); + case EFFECT_FIELD_COLOR: return QColor(string); + case EFFECT_FIELD_BOOL: return (string == "1"); + case EFFECT_FIELD_COMBO: return string.toInt(); + case EFFECT_FIELD_STRING: + case EFFECT_FIELD_FONT: + case EFFECT_FIELD_FILE: + return string; + } + return QVariant(); } QString save_data_to_string(int type, const QVariant& data) { - switch (type) { - case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble()); - case EFFECT_FIELD_COLOR: return data.value().name(); - case EFFECT_FIELD_BOOL: return QString::number(data.toBool()); - case EFFECT_FIELD_COMBO: return QString::number(data.toInt()); - case EFFECT_FIELD_STRING: - case EFFECT_FIELD_FONT: - case EFFECT_FIELD_FILE: - return data.toString(); - } - return QString(); + switch (type) { + case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble()); + case EFFECT_FIELD_COLOR: return data.value().name(); + case EFFECT_FIELD_BOOL: return QString::number(data.toBool()); + case EFFECT_FIELD_COMBO: return QString::number(data.toInt()); + case EFFECT_FIELD_STRING: + case EFFECT_FIELD_FONT: + case EFFECT_FIELD_FILE: + return data.toString(); + } + return QString(); } void Effect::load(QXmlStreamReader& stream) { - int row_count = 0; + int row_count = 0; - QString tag = stream.name().toString(); + QString tag = stream.name().toString(); - while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { - stream.readNext(); - if (stream.name() == "row" && stream.isStartElement()) { - if (row_count < rows.size()) { - EffectRow* row = rows.at(row_count); - int field_count = 0; + while (!stream.atEnd() && !(stream.name() == tag && stream.isEndElement())) { + stream.readNext(); + if (stream.name() == "row" && stream.isStartElement()) { + if (row_count < rows.size()) { + EffectRow* row = rows.at(row_count); + int field_count = 0; - while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) { - stream.readNext(); + while (!stream.atEnd() && !(stream.name() == "row" && stream.isEndElement())) { + stream.readNext(); - // read field - if (stream.name() == "field" && stream.isStartElement()) { - if (field_count < row->fieldCount()) { - // match field using ID - int field_number = field_count; - for (int k=0;kfieldCount();l++) { - if (row->field(l)->id == attr.value()) { - field_number = l; + // read field + if (stream.name() == "field" && stream.isStartElement()) { + if (field_count < row->fieldCount()) { + // match field using ID + int field_number = field_count; + for (int k=0;kfieldCount();l++) { + if (row->field(l)->id == attr.value()) { + field_number = l; // qInfo() << "Found field by ID"; - break; - } - } - break; - } - } + break; + } + } + break; + } + } - EffectField* field = row->field(field_number); + EffectField* field = row->field(field_number); - // get current field value - for (int k=0;kset_current_data(load_data_from_string(field->type, attr.value().toString())); - break; - } - } + // get current field value + for (int k=0;kset_current_data(load_data_from_string(field->type, attr.value().toString())); + break; + } + } - while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) { - stream.readNext(); + while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) { + stream.readNext(); - // read keyframes - if (stream.name() == "key" && stream.isStartElement()) { - row->setKeyframing(true); + // read keyframes + if (stream.name() == "key" && stream.isStartElement()) { + row->setKeyframing(true); - EffectKeyframe key; - for (int k=0;ktype, attr.value().toString()); - } else if (attr.name() == "frame") { - key.time = attr.value().toLong(); - } else if (attr.name() == "type") { - key.type = attr.value().toInt(); - } else if (attr.name() == "prehx") { - key.pre_handle_x = attr.value().toDouble(); - } else if (attr.name() == "prehy") { - key.pre_handle_y = attr.value().toDouble(); - } else if (attr.name() == "posthx") { - key.post_handle_x = attr.value().toDouble(); - } else if (attr.name() == "posthy") { - key.post_handle_y = attr.value().toDouble(); - } - } - field->keyframes.append(key); - } - } - } else { - qCritical() << "Too many fields for effect" << id << "row" << row_count << ". Project might be corrupt. (Got" << field_count << ", expected <" << row->fieldCount()-1 << ")"; - } - field_count++; - } - } + EffectKeyframe key; + for (int k=0;ktype, attr.value().toString()); + } else if (attr.name() == "frame") { + key.time = attr.value().toLong(); + } else if (attr.name() == "type") { + key.type = attr.value().toInt(); + } else if (attr.name() == "prehx") { + key.pre_handle_x = attr.value().toDouble(); + } else if (attr.name() == "prehy") { + key.pre_handle_y = attr.value().toDouble(); + } else if (attr.name() == "posthx") { + key.post_handle_x = attr.value().toDouble(); + } else if (attr.name() == "posthy") { + key.post_handle_y = attr.value().toDouble(); + } + } + field->keyframes.append(key); + } + } + } else { + qCritical() << "Too many fields for effect" << id << "row" << row_count << ". Project might be corrupt. (Got" << field_count << ", expected <" << row->fieldCount()-1 << ")"; + } + field_count++; + } + } - } else { - qCritical() << "Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")"; - } - row_count++; - } else if (stream.isStartElement()) { - custom_load(stream); - } - } + } else { + qCritical() << "Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")"; + } + row_count++; + } else if (stream.isStartElement()) { + custom_load(stream); + } + } } void Effect::custom_load(QXmlStreamReader &) {} void Effect::save(QXmlStreamWriter& stream) { - stream.writeAttribute("name", meta->category + "/" + meta->name); - stream.writeAttribute("enabled", QString::number(is_enabled())); + stream.writeAttribute("name", meta->category + "/" + meta->name); + stream.writeAttribute("enabled", QString::number(is_enabled())); - for (int i=0;isavable) { - stream.writeStartElement("row"); // row - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - stream.writeStartElement("field"); // field - stream.writeAttribute("id", field->id); - stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data())); - for (int k=0;kkeyframes.size();k++) { - const EffectKeyframe& key = field->keyframes.at(k); - stream.writeStartElement("key"); - stream.writeAttribute("value", save_data_to_string(field->type, key.data)); - stream.writeAttribute("frame", QString::number(key.time)); - stream.writeAttribute("type", QString::number(key.type)); - stream.writeAttribute("prehx", QString::number(key.pre_handle_x)); - stream.writeAttribute("prehy", QString::number(key.pre_handle_y)); - stream.writeAttribute("posthx", QString::number(key.post_handle_x)); - stream.writeAttribute("posthy", QString::number(key.post_handle_y)); - stream.writeEndElement(); // key - } - stream.writeEndElement(); // field - } - stream.writeEndElement(); // row - } - } + for (int i=0;isavable) { + stream.writeStartElement("row"); // row + for (int j=0;jfieldCount();j++) { + EffectField* field = row->field(j); + stream.writeStartElement("field"); // field + stream.writeAttribute("id", field->id); + stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data())); + for (int k=0;kkeyframes.size();k++) { + const EffectKeyframe& key = field->keyframes.at(k); + stream.writeStartElement("key"); + stream.writeAttribute("value", save_data_to_string(field->type, key.data)); + stream.writeAttribute("frame", QString::number(key.time)); + stream.writeAttribute("type", QString::number(key.type)); + stream.writeAttribute("prehx", QString::number(key.pre_handle_x)); + stream.writeAttribute("prehy", QString::number(key.pre_handle_y)); + stream.writeAttribute("posthx", QString::number(key.post_handle_x)); + stream.writeAttribute("posthy", QString::number(key.post_handle_y)); + stream.writeEndElement(); // key + } + stream.writeEndElement(); // field + } + stream.writeEndElement(); // row + } + } } void Effect::load_from_string(const QByteArray &s) { - // clear existing keyframe data - for (int i=0;isetKeyframing(false); - for (int j=0;jfieldCount();j++) { - EffectField* field = row->field(j); - field->keyframes.clear(); - } - } + // clear existing keyframe data + for (int i=0;isetKeyframing(false); + for (int j=0;jfieldCount();j++) { + EffectField* field = row->field(j); + field->keyframes.clear(); + } + } - // write settings with xml writer - QXmlStreamReader stream(s); + // write settings with xml writer + QXmlStreamReader stream(s); - while (!stream.atEnd()) { - stream.readNext(); + while (!stream.atEnd()) { + stream.readNext(); - // find the effect opening tag - if (stream.name() == "effect" && stream.isStartElement()) { + // find the effect opening tag + if (stream.name() == "effect" && stream.isStartElement()) { - // check the name to see if it matches this effect - const QXmlStreamAttributes& attributes = stream.attributes(); - for (int i=0;ipath.isEmpty() || (vertPath.isEmpty() && fragPath.isEmpty())) return; - QList effects_paths = get_effects_paths(); - const QString& test_fn = vertPath.isEmpty() ? fragPath : vertPath; - for (int i=0;ipath.isEmpty() || (vertPath.isEmpty() && fragPath.isEmpty())) return; + QList effects_paths = get_effects_paths(); + const QString& test_fn = vertPath.isEmpty() ? fragPath : vertPath; + for (int i=0;iaddShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + vertPath)) { - qInfo() << "Vertex shader added successfully"; - } else { - glsl_compiled = false; - qWarning() << "Vertex shader could not be added"; - } - } - if (!fragPath.isEmpty()) { - if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + fragPath)) { - qInfo() << "Fragment shader added successfully"; - } else { - glsl_compiled = false; - qWarning() << "Fragment shader could not be added"; - } - } - if (glsl_compiled) { - if (glslProgram->link()) { - qInfo() << "Shader program linked successfully"; - } else { - qWarning() << "Shader program failed to link"; - } - } - isOpen = true; - } - } else { - isOpen = true; - } + if (isOpen) { + qWarning() << "Tried to open an effect that was already open"; + close(); + } + if (olive::CurrentRuntimeConfig.shaders_are_enabled && enable_shader) { + if (QOpenGLContext::currentContext() == nullptr) { + qWarning() << "No current context to create a shader program for - will retry next repaint"; + } else { + glslProgram = new QOpenGLShaderProgram(); + validate_meta_path(); + bool glsl_compiled = true; + if (!vertPath.isEmpty()) { + if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, meta->path + "/" + vertPath)) { + qInfo() << "Vertex shader added successfully"; + } else { + glsl_compiled = false; + qWarning() << "Vertex shader could not be added"; + } + } + if (!fragPath.isEmpty()) { + if (glslProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, meta->path + "/" + fragPath)) { + qInfo() << "Fragment shader added successfully"; + } else { + glsl_compiled = false; + qWarning() << "Fragment shader could not be added"; + } + } + if (glsl_compiled) { + if (glslProgram->link()) { + qInfo() << "Shader program linked successfully"; + } else { + qWarning() << "Shader program failed to link"; + } + } + isOpen = true; + } + } else { + isOpen = true; + } } void Effect::close() { - if (!isOpen) { - qWarning() << "Tried to close an effect that was already closed"; - } - delete_texture(); - if (glslProgram != nullptr) { - delete glslProgram; - glslProgram = nullptr; - } - isOpen = false; + if (!isOpen) { + qWarning() << "Tried to close an effect that was already closed"; + } + delete_texture(); + if (glslProgram != nullptr) { + delete glslProgram; + glslProgram = nullptr; + } + isOpen = false; } bool Effect::is_glsl_linked() { - return glslProgram != nullptr && glslProgram->isLinked(); + return glslProgram != nullptr && glslProgram->isLinked(); } void Effect::startEffect() { - if (!isOpen) { - open(); - qWarning() << "Tried to start a closed effect - opening"; - } - if (olive::CurrentRuntimeConfig.shaders_are_enabled - && enable_shader - && glslProgram->isLinked()) { - bound = glslProgram->bind(); - } + if (!isOpen) { + open(); + qWarning() << "Tried to start a closed effect - opening"; + } + if (olive::CurrentRuntimeConfig.shaders_are_enabled + && enable_shader + && glslProgram->isLinked()) { + bound = glslProgram->bind(); + } } void Effect::endEffect() { - if (bound) glslProgram->release(); - bound = false; + if (bound) glslProgram->release(); + bound = false; } int Effect::getIterations() { - return iterations; + return iterations; } void Effect::setIterations(int i) { - iterations = i; + iterations = i; } void Effect::process_image(double, uint8_t *, uint8_t *, int){} EffectPtr Effect::copy(Clip *c) { EffectPtr copy = Effect::Create(c, meta); - copy->set_enabled(is_enabled()); - copy_field_keyframes(copy); - return copy; + copy->set_enabled(is_enabled()); + copy_field_keyframes(copy); + return copy; } void Effect::process_shader(double timecode, GLTextureCoords&, int iteration) { glslProgram->setUniformValue("resolution", parent_clip->media_width(), parent_clip->media_height()); - glslProgram->setUniformValue("time", GLfloat(timecode)); - glslProgram->setUniformValue("iteration", iteration); + glslProgram->setUniformValue("time", GLfloat(timecode)); + glslProgram->setUniformValue("iteration", iteration); - for (int i=0;ifieldCount();j++) { - EffectField* field = row->field(j); - if (!field->id.isEmpty()) { - switch (field->type) { - case EFFECT_FIELD_DOUBLE: - glslProgram->setUniformValue(field->id.toUtf8().constData(), GLfloat(field->get_double_value(timecode))); - break; - case EFFECT_FIELD_COLOR: - glslProgram->setUniformValue( - field->id.toUtf8().constData(), - GLfloat(field->get_color_value(timecode).redF()), - GLfloat(field->get_color_value(timecode).greenF()), - GLfloat(field->get_color_value(timecode).blueF()) - ); - break; - case EFFECT_FIELD_STRING: break; // can you even send a string to a uniform value? - case EFFECT_FIELD_BOOL: - glslProgram->setUniformValue(field->id.toUtf8().constData(), field->get_bool_value(timecode)); - break; - case EFFECT_FIELD_COMBO: - glslProgram->setUniformValue(field->id.toUtf8().constData(), field->get_combo_index(timecode)); - break; - case EFFECT_FIELD_FONT: break; // can you even send a string to a uniform value? - case EFFECT_FIELD_FILE: break; // can you even send a string to a uniform value? - } - } - } - } + for (int i=0;ifieldCount();j++) { + EffectField* field = row->field(j); + if (!field->id.isEmpty()) { + switch (field->type) { + case EFFECT_FIELD_DOUBLE: + glslProgram->setUniformValue(field->id.toUtf8().constData(), GLfloat(field->get_double_value(timecode))); + break; + case EFFECT_FIELD_COLOR: + glslProgram->setUniformValue( + field->id.toUtf8().constData(), + GLfloat(field->get_color_value(timecode).redF()), + GLfloat(field->get_color_value(timecode).greenF()), + GLfloat(field->get_color_value(timecode).blueF()) + ); + break; + case EFFECT_FIELD_STRING: break; // can you even send a string to a uniform value? + case EFFECT_FIELD_BOOL: + glslProgram->setUniformValue(field->id.toUtf8().constData(), field->get_bool_value(timecode)); + break; + case EFFECT_FIELD_COMBO: + glslProgram->setUniformValue(field->id.toUtf8().constData(), field->get_combo_index(timecode)); + break; + case EFFECT_FIELD_FONT: break; // can you even send a string to a uniform value? + case EFFECT_FIELD_FILE: break; // can you even send a string to a uniform value? + } + } + } + } } void Effect::process_coords(double, GLTextureCoords&, int) {} GLuint Effect::process_superimpose(double timecode) { - bool dimensions_changed = false; - bool redrew_image = false; + bool dimensions_changed = false; + bool redrew_image = false; int width = parent_clip->media_width(); int height = parent_clip->media_height(); - if (width != img.width() || height != img.height()) { - img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied); - dimensions_changed = true; - } + if (width != img.width() || height != img.height()) { + img = QImage(width, height, QImage::Format_RGBA8888_Premultiplied); + dimensions_changed = true; + } - if (valueHasChanged(timecode) || dimensions_changed || enable_always_update) { - redraw(timecode); - redrew_image = true; - } + if (valueHasChanged(timecode) || dimensions_changed || enable_always_update) { + redraw(timecode); + redrew_image = true; + } - if (texture == nullptr || texture->width() != img.width() || texture->height() != img.height()) { - delete_texture(); + if (texture == nullptr || texture->width() != img.width() || texture->height() != img.height()) { + delete_texture(); - texture = new QOpenGLTexture(QOpenGLTexture::Target2D); - texture->setSize(img.width(), img.height()); - texture->setFormat(QOpenGLTexture::RGBA8_UNorm); - texture->setMipLevels(texture->maximumMipLevels()); - texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); - texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); + texture = new QOpenGLTexture(QOpenGLTexture::Target2D); + texture->setSize(img.width(), img.height()); + texture->setFormat(QOpenGLTexture::RGBA8_UNorm); + texture->setMipLevels(texture->maximumMipLevels()); + texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); + texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); - redrew_image = true; - } + redrew_image = true; + } - if (redrew_image) { - texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, img.constBits()); - } + if (redrew_image) { + texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, img.constBits()); + } - return texture->textureId(); + return texture->textureId(); } void Effect::process_audio(double, double, quint8*, int, int) {} @@ -942,158 +943,158 @@ void Effect::process_audio(double, double, quint8*, int, int) {} void Effect::gizmo_draw(double, GLTextureCoords &) {} void Effect::gizmo_move(EffectGizmo* gizmo, int x_movement, int y_movement, double timecode, bool done) { - for (int i=0;ix_field1 != nullptr) { - gizmo->x_field1->set_double_value(gizmo->x_field1->get_double_value(timecode) + x_movement*gizmo->x_field_multi1); - gizmo->x_field1->make_key_from_change(ca); - } - if (gizmo->y_field1 != nullptr) { - gizmo->y_field1->set_double_value(gizmo->y_field1->get_double_value(timecode) + y_movement*gizmo->y_field_multi1); - gizmo->y_field1->make_key_from_change(ca); - } - if (gizmo->x_field2 != nullptr) { - gizmo->x_field2->set_double_value(gizmo->x_field2->get_double_value(timecode) + x_movement*gizmo->x_field_multi2); - gizmo->x_field2->make_key_from_change(ca); - } - if (gizmo->y_field2 != nullptr) { - gizmo->y_field2->set_double_value(gizmo->y_field2->get_double_value(timecode) + y_movement*gizmo->y_field_multi2); - gizmo->y_field2->make_key_from_change(ca); - } - if (done) olive::UndoStack.push(ca); - break; - } - } + for (int i=0;ix_field1 != nullptr) { + gizmo->x_field1->set_double_value(gizmo->x_field1->get_double_value(timecode) + x_movement*gizmo->x_field_multi1); + gizmo->x_field1->make_key_from_change(ca); + } + if (gizmo->y_field1 != nullptr) { + gizmo->y_field1->set_double_value(gizmo->y_field1->get_double_value(timecode) + y_movement*gizmo->y_field_multi1); + gizmo->y_field1->make_key_from_change(ca); + } + if (gizmo->x_field2 != nullptr) { + gizmo->x_field2->set_double_value(gizmo->x_field2->get_double_value(timecode) + x_movement*gizmo->x_field_multi2); + gizmo->x_field2->make_key_from_change(ca); + } + if (gizmo->y_field2 != nullptr) { + gizmo->y_field2->set_double_value(gizmo->y_field2->get_double_value(timecode) + y_movement*gizmo->y_field_multi2); + gizmo->y_field2->make_key_from_change(ca); + } + if (done) olive::UndoStack.push(ca); + break; + } + } } void Effect::gizmo_world_to_screen() { - GLfloat view_val[16]; - GLfloat projection_val[16]; - glGetFloatv(GL_MODELVIEW_MATRIX, view_val); - glGetFloatv(GL_PROJECTION_MATRIX, projection_val); + GLfloat view_val[16]; + GLfloat projection_val[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, view_val); + glGetFloatv(GL_PROJECTION_MATRIX, projection_val); - QMatrix4x4 view_matrix(view_val); - QMatrix4x4 projection_matrix(projection_val); + QMatrix4x4 view_matrix(view_val); + QMatrix4x4 projection_matrix(projection_val); - for (int i=0;iget_point_count();j++) { - QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (view_matrix * projection_matrix); + for (int j=0;jget_point_count();j++) { + QVector4D screen_pos = QVector4D(g->world_pos[j].x(), g->world_pos[j].y(), 0, 1.0) * (view_matrix * projection_matrix); - int adjusted_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width); - int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height); + int adjusted_sx1 = qRound(((screen_pos.x()*0.5f)+0.5f)*parent_clip->sequence->width); + int adjusted_sy1 = qRound((1.0f-((screen_pos.y()*0.5f)+0.5f))*parent_clip->sequence->height); - g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1); - } - } + g->screen_pos[j] = QPoint(adjusted_sx1, adjusted_sy1); + } + } } bool Effect::are_gizmos_enabled() { - return (gizmos.size() > 0); + return (gizmos.size() > 0); } void Effect::redraw(double) { - /* - // run javascript - QPainter p(&img); - painter_wrapper.img = &img; - painter_wrapper.painter = &p; + /* + // run javascript + QPainter p(&img); + painter_wrapper.img = &img; + painter_wrapper.painter = &p; - jsEngine.globalObject().setProperty("painter", wrapper_obj); + jsEngine.globalObject().setProperty("painter", wrapper_obj); jsEngine.globalObject().setProperty("width", parent_clip->media_width()); jsEngine.globalObject().setProperty("height", parent_clip->media_height()); - for (int i=0;ifieldCount();j++) { - EffectField* field = row->field(j); - if (!field->id.isEmpty()) { - switch (field->type) { - case EFFECT_FIELD_DOUBLE: - jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode)); - break; - case EFFECT_FIELD_COLOR: - jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name()); - break; - case EFFECT_FIELD_STRING: - jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode)); - break; - case EFFECT_FIELD_BOOL: - jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode)); - break; - case EFFECT_FIELD_COMBO: - jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode)); - break; - case EFFECT_FIELD_FONT: - jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode)); - break; - } - } - } - } + for (int i=0;ifieldCount();j++) { + EffectField* field = row->field(j); + if (!field->id.isEmpty()) { + switch (field->type) { + case EFFECT_FIELD_DOUBLE: + jsEngine.globalObject().setProperty(field->id, field->get_double_value(timecode)); + break; + case EFFECT_FIELD_COLOR: + jsEngine.globalObject().setProperty(field->id, field->get_color_value(timecode).name()); + break; + case EFFECT_FIELD_STRING: + jsEngine.globalObject().setProperty(field->id, field->get_string_value(timecode)); + break; + case EFFECT_FIELD_BOOL: + jsEngine.globalObject().setProperty(field->id, field->get_bool_value(timecode)); + break; + case EFFECT_FIELD_COMBO: + jsEngine.globalObject().setProperty(field->id, field->get_combo_index(timecode)); + break; + case EFFECT_FIELD_FONT: + jsEngine.globalObject().setProperty(field->id, field->get_font_name(timecode)); + break; + } + } + } + } - jsEngine.evaluate(script); - */ + jsEngine.evaluate(script); + */ } bool Effect::valueHasChanged(double timecode) { - if (cachedValues.size() == 0) { - for (int i=0;ifieldCount();j++) { - cachedValues.append(crow->field(j)->get_current_data()); - } - } - return true; - } else { - bool changed = false; - int index = 0; - for (int i=0;ifieldCount();j++) { - EffectField* field = crow->field(j); - field->validate_keyframe_data(timecode); - if (cachedValues.at(index) != field->get_current_data()) { - changed = true; - } - cachedValues[index] = field->get_current_data(); - index++; - } - } - return changed; - } + if (cachedValues.size() == 0) { + for (int i=0;ifieldCount();j++) { + cachedValues.append(crow->field(j)->get_current_data()); + } + } + return true; + } else { + bool changed = false; + int index = 0; + for (int i=0;ifieldCount();j++) { + EffectField* field = crow->field(j); + field->validate_keyframe_data(timecode); + if (cachedValues.at(index) != field->get_current_data()) { + changed = true; + } + cachedValues[index] = field->get_current_data(); + index++; + } + } + return changed; + } } void Effect::delete_texture() { - if (texture != nullptr) { - delete texture; - texture = nullptr; - } + if (texture != nullptr) { + delete texture; + texture = nullptr; + } } const EffectMeta* get_meta_from_name(const QString& input) { - int split_index = input.indexOf('/'); - QString category; - if (split_index > -1) { - category = input.left(split_index); - } - QString name = input.mid(split_index + 1); + int split_index = input.indexOf('/'); + QString category; + if (split_index > -1) { + category = input.left(split_index); + } + QString name = input.mid(split_index + 1); - for (int j=0;j(a) + static_cast(b); - mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); - return static_cast(mixed_sample); + qint32 mixed_sample = static_cast(a) + static_cast(b); + mixed_sample = qMax(qMin(mixed_sample, static_cast(INT16_MAX)), static_cast(INT16_MIN)); + return static_cast(mixed_sample); } diff --git a/project/effect.h b/project/effect.h index 64224ec97..91600f1d3 100644 --- a/project/effect.h +++ b/project/effect.h @@ -58,7 +58,16 @@ struct EffectMeta { int type; int subtype; }; -extern QVector effects; + +struct BlendMode { + QString name; + QString url; +}; + +namespace olive { + extern QVector effects; + extern QVector blend_modes; +} double log_volume(double linear); @@ -94,36 +103,6 @@ enum EffectInternal { EFFECT_INTERNAL_COUNT }; -enum EffectBlendMode { - BLEND_MODE_ADD, - BLEND_MODE_AVERAGE, - BLEND_MODE_COLORBURN, - BLEND_MODE_COLORDODGE, - BLEND_MODE_DARKEN, - BLEND_MODE_DIFFERENCE, - BLEND_MODE_EXCLUSION, - BLEND_MODE_GLOW, - BLEND_MODE_HARDLIGHT, - BLEND_MODE_HARDMIX, - BLEND_MODE_LIGHTEN, - BLEND_MODE_LINEARBURN, - BLEND_MODE_LINEARDODGE, - BLEND_MODE_LINEARLIGHT, - BLEND_MODE_MULTIPLY, - BLEND_MODE_NEGATION, - BLEND_MODE_NORMAL, - BLEND_MODE_OVERLAY, - BLEND_MODE_PHOENIX, - BLEND_MODE_PINLIGHT, - BLEND_MODE_REFLECT, - BLEND_MODE_SCREEN, - BLEND_MODE_SOFTLIGHT, - BLEND_MODE_SUBSTRACT, - BLEND_MODE_SUBTRACT, - BLEND_MODE_VIVIDLIGHT, - BLEND_MODE_COUNT -}; - struct GLTextureCoords { int grid_size; diff --git a/project/effectloaders.cpp b/project/effectloaders.cpp index 443caec1e..4162a2a6b 100644 --- a/project/effectloaders.cpp +++ b/project/effectloaders.cpp @@ -39,233 +39,233 @@ typedef void (*f0rGetPluginInfo)(f0r_plugin_info_t* info); #endif void load_internal_effects() { - if (!olive::CurrentRuntimeConfig.shaders_are_enabled) qWarning() << "Shaders are disabled, some effects may be nonfunctional"; + if (!olive::CurrentRuntimeConfig.shaders_are_enabled) qWarning() << "Shaders are disabled, some effects may be nonfunctional"; - EffectMeta em; + EffectMeta em; - // load internal effects - em.path = ":/internalshaders"; + // load internal effects + em.path = ":/internalshaders"; - em.type = EFFECT_TYPE_EFFECT; - em.subtype = EFFECT_TYPE_AUDIO; + em.type = EFFECT_TYPE_EFFECT; + em.subtype = EFFECT_TYPE_AUDIO; - em.name = "Volume"; - em.internal = EFFECT_INTERNAL_VOLUME; - effects.append(em); + em.name = "Volume"; + em.internal = EFFECT_INTERNAL_VOLUME; + olive::effects.append(em); - em.name = "Pan"; - em.internal = EFFECT_INTERNAL_PAN; - effects.append(em); + em.name = "Pan"; + em.internal = EFFECT_INTERNAL_PAN; + olive::effects.append(em); #ifndef NOVST - em.name = "VST Plugin 2.x"; - em.internal = EFFECT_INTERNAL_VST; - effects.append(em); + em.name = "VST Plugin 2.x"; + em.internal = EFFECT_INTERNAL_VST; + olive::effects.append(em); #endif - em.name = "Tone"; - em.internal = EFFECT_INTERNAL_TONE; - effects.append(em); + em.name = "Tone"; + em.internal = EFFECT_INTERNAL_TONE; + olive::effects.append(em); - em.name = "Noise"; - em.internal = EFFECT_INTERNAL_NOISE; - effects.append(em); + em.name = "Noise"; + em.internal = EFFECT_INTERNAL_NOISE; + olive::effects.append(em); - em.name = "Fill Left/Right"; - em.internal = EFFECT_INTERNAL_FILLLEFTRIGHT; - effects.append(em); + em.name = "Fill Left/Right"; + em.internal = EFFECT_INTERNAL_FILLLEFTRIGHT; + olive::effects.append(em); - em.subtype = EFFECT_TYPE_VIDEO; + em.subtype = EFFECT_TYPE_VIDEO; - em.name = "Transform"; - em.category = "Distort"; - em.internal = EFFECT_INTERNAL_TRANSFORM; - effects.append(em); + em.name = "Transform"; + em.category = "Distort"; + em.internal = EFFECT_INTERNAL_TRANSFORM; + olive::effects.append(em); - em.name = "Corner Pin"; - em.internal = EFFECT_INTERNAL_CORNERPIN; - effects.append(em); + em.name = "Corner Pin"; + em.internal = EFFECT_INTERNAL_CORNERPIN; + olive::effects.append(em); - /*em.name = "Mask"; - em.internal = EFFECT_INTERNAL_MASK; - effects.append(em);*/ + /*em.name = "Mask"; + em.internal = EFFECT_INTERNAL_MASK; + olive::effects.append(em);*/ - em.name = "Shake"; - em.internal = EFFECT_INTERNAL_SHAKE; - effects.append(em); + em.name = "Shake"; + em.internal = EFFECT_INTERNAL_SHAKE; + olive::effects.append(em); - em.name = "Text"; - em.category = "Render"; - em.internal = EFFECT_INTERNAL_TEXT; - effects.append(em); + em.name = "Text"; + em.category = "Render"; + em.internal = EFFECT_INTERNAL_TEXT; + olive::effects.append(em); - em.name = "Timecode"; - em.internal = EFFECT_INTERNAL_TIMECODE; - effects.append(em); + em.name = "Timecode"; + em.internal = EFFECT_INTERNAL_TIMECODE; + olive::effects.append(em); - em.name = "Solid"; - em.internal = EFFECT_INTERNAL_SOLID; - effects.append(em); + em.name = "Solid"; + em.internal = EFFECT_INTERNAL_SOLID; + olive::effects.append(em); - // internal transitions - em.type = EFFECT_TYPE_TRANSITION; - em.category = ""; + // internal transitions + em.type = EFFECT_TYPE_TRANSITION; + em.category = ""; - em.name = "Cross Dissolve"; - em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE; - effects.append(em); + em.name = "Cross Dissolve"; + em.internal = TRANSITION_INTERNAL_CROSSDISSOLVE; + olive::effects.append(em); - em.subtype = EFFECT_TYPE_AUDIO; + em.subtype = EFFECT_TYPE_AUDIO; - em.name = "Linear Fade"; - em.internal = TRANSITION_INTERNAL_LINEARFADE; - effects.append(em); + em.name = "Linear Fade"; + em.internal = TRANSITION_INTERNAL_LINEARFADE; + olive::effects.append(em); - em.name = "Exponential Fade"; - em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE; - effects.append(em); + em.name = "Exponential Fade"; + em.internal = TRANSITION_INTERNAL_EXPONENTIALFADE; + olive::effects.append(em); - em.name = "Logarithmic Fade"; - em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE; - effects.append(em); + em.name = "Logarithmic Fade"; + em.internal = TRANSITION_INTERNAL_LOGARITHMICFADE; + olive::effects.append(em); } void load_shader_effects() { - QList effects_paths = get_effects_paths(); + QList effects_paths = get_effects_paths(); - for (int h=0;h entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files); - for (int i=0;i entries = effects_dir.entryList(QStringList("*.xml"), QDir::Files); + for (int i=0;istart(); + EffectInit* init_thread = new EffectInit(); + QObject::connect(init_thread, SIGNAL(finished()), init_thread, SLOT(deleteLater())); + init_thread->start(); } #ifndef NOFREI0R void load_frei0r_effects_worker(const QString& dir, EffectMeta& em, QVector& loaded_names) { - QDir search_dir(dir); - if (search_dir.exists()) { - QList entry_list = search_dir.entryList(LibFilter(), QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); - for (int j=0;j(LibAddress(effect, "f0r_get_plugin_info")); - if (get_info_func != nullptr) { - f0r_plugin_info_t info; - get_info_func(&info); + QDir search_dir(dir); + if (search_dir.exists()) { + QList entry_list = search_dir.entryList(LibFilter(), QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); + for (int j=0;j(LibAddress(effect, "f0r_get_plugin_info")); + if (get_info_func != nullptr) { + f0r_plugin_info_t info; + get_info_func(&info); - if (!loaded_names.contains(info.name) - && info.plugin_type == F0R_PLUGIN_TYPE_FILTER - && info.color_model == F0R_COLOR_MODEL_RGBA8888) { - em.name = info.name; - em.path = dir; - em.filename = entry_list.at(j); - em.tooltip = QString("%1\n%2\n%3\n%4").arg(em.name, info.author, info.explanation, em.filename); + if (!loaded_names.contains(info.name) + && info.plugin_type == F0R_PLUGIN_TYPE_FILTER + && info.color_model == F0R_COLOR_MODEL_RGBA8888) { + em.name = info.name; + em.path = dir; + em.filename = entry_list.at(j); + em.tooltip = QString("%1\n%2\n%3\n%4").arg(em.name, info.author, info.explanation, em.filename); - loaded_names.append(em.name); + loaded_names.append(em.name); - effects.append(em); - } + olive::effects.append(em); + } // qDebug() << "Found:" << info.name << "by" << info.author; - } - LibClose(effect); - } + } + LibClose(effect); + } // qDebug() << search_dir.filePath(entry_list.at(j)); - } - } - } + } + } + } } void load_frei0r_effects() { - QList effect_dirs = get_effects_paths(); + QList effect_dirs = get_effects_paths(); - // add defined paths for frei0r plugins on unix + // add defined paths for frei0r plugins on unix #if defined(__APPLE__) || defined(__linux__) || defined(__HAIKU__) - effect_dirs.prepend("/usr/lib/frei0r-1"); - effect_dirs.prepend("/usr/local/lib/frei0r-1"); - effect_dirs.prepend(QDir::homePath() + "/.frei0r-1/lib"); + effect_dirs.prepend("/usr/lib/frei0r-1"); + effect_dirs.prepend("/usr/local/lib/frei0r-1"); + effect_dirs.prepend(QDir::homePath() + "/.frei0r-1/lib"); #endif - QString env_path(qgetenv("FREI0R_PATH")); - if (!env_path.isEmpty()) effect_dirs.append(env_path); + QString env_path(qgetenv("FREI0R_PATH")); + if (!env_path.isEmpty()) effect_dirs.append(env_path); - QVector loaded_names; + QVector loaded_names; - // search for paths - EffectMeta em; - em.category = "Frei0r"; - em.type = EFFECT_TYPE_EFFECT; - em.subtype = EFFECT_TYPE_VIDEO; - em.internal = EFFECT_INTERNAL_FREI0R; + // search for paths + EffectMeta em; + em.category = "Frei0r"; + em.type = EFFECT_TYPE_EFFECT; + em.subtype = EFFECT_TYPE_VIDEO; + em.internal = EFFECT_INTERNAL_FREI0R; - for (int i=0;ieffects_loaded.lock(); + panel_effect_controls->effects_loaded.lock(); } void EffectInit::run() { - qInfo() << "Initializing effects..."; - load_internal_effects(); - load_shader_effects(); + qInfo() << "Initializing effects..."; + load_internal_effects(); + load_shader_effects(); #ifndef NOFREI0R - load_frei0r_effects(); + load_frei0r_effects(); #endif - panel_effect_controls->effects_loaded.unlock(); - qInfo() << "Finished initializing effects"; + panel_effect_controls->effects_loaded.unlock(); + qInfo() << "Finished initializing effects"; } diff --git a/rendering/renderfunctions.cpp b/rendering/renderfunctions.cpp index 4f6a08990..681897895 100644 --- a/rendering/renderfunctions.cpp +++ b/rendering/renderfunctions.cpp @@ -399,7 +399,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { coords.textureTopLeftY = coords.textureTopRightY = coords.textureTopLeftX = coords.textureBottomLeftX = 0.0; coords.textureBottomLeftY = coords.textureBottomRightY = coords.textureTopRightX = coords.textureBottomRightX = 1.0; coords.textureTopLeftQ = coords.textureTopRightQ = coords.textureTopLeftQ = coords.textureBottomLeftQ = 1; - coords.blendmode = BLEND_MODE_NORMAL; + coords.blendmode = -1; coords.opacity = 1.0; // if auto-scale is enabled, auto-scale the clip @@ -514,8 +514,8 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { - // copy front buffer to back buffer (only if we're using blending modes - which we usually will be) - if (!olive::CurrentRuntimeConfig.disable_blending) { + // copy front buffer to back buffer (only if we're using a blending mode) + if (coords.blendmode >= 0) { if (params.nests.size() > 0) { draw_clip(params.ctx, params.nests.last()->fbo[2]->handle(), params.nests.last()->fbo[0]->texture(), true); } else { @@ -533,8 +533,8 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // bind front buffer as draw buffer params.ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, final_fbo); - if (olive::CurrentRuntimeConfig.disable_blending) { - // some GPUs don't like the blending shader, so we provide a pure GL fallback here + // Check if we're using a blend mode (< 0 means no blend mode) + if (coords.blendmode < 0) { params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, backend_tex_1); @@ -543,7 +543,9 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { full_blit(); params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); + } else { + // load background texture into texture unit 0 params.ctx->functions()->glActiveTexture(GL_TEXTURE0 + 0); // Texture unit 0 params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, backend_tex_2); @@ -572,6 +574,7 @@ GLuint compose_sequence(ComposeSequenceParams ¶ms) { // unbind texture from texture unit 0 params.ctx->functions()->glActiveTexture(GL_TEXTURE0 + 0); // Texture unit 0 params.ctx->functions()->glBindTexture(GL_TEXTURE_2D, 0); + } // unbind framebuffer