restored swscale and updated opengl fx spec
This commit is contained in:
+117
-79
@@ -136,79 +136,111 @@ bool Effect::is_enabled() {
|
||||
return container->enabled_check->isChecked();
|
||||
}
|
||||
|
||||
void Effect::load(QXmlStreamReader& stream) {
|
||||
stream.readNext();
|
||||
/*for (int i=0;i<rows.size();i++) {
|
||||
EffectRow* row = rows.at(i);
|
||||
while (!stream->atEnd() && !(stream->name() == "effect" && stream->isEndElement())) {
|
||||
stream->readNext();
|
||||
if (stream->name() == "row" && stream->isStartElement()) {
|
||||
for (int j=0;j<row->fieldCount();j++) {
|
||||
EffectField* field = row->field(j);
|
||||
while (!stream->atEnd() && !(stream->name() == "effect" && stream->isEndElement())) {
|
||||
stream->readNext();
|
||||
if (stream->name() == "field" && stream->isStartElement()) {
|
||||
// read all keyframes
|
||||
QVector<EffectKeyframe> keys;
|
||||
while (!stream->atEnd() && (stream->name() == "field" && stream->isEndElement())) {
|
||||
stream->readNext();
|
||||
if (stream->name() == "key" && stream->isStartElement()) {
|
||||
EffectKeyframe kf;
|
||||
for (int k=0;k<stream->attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream->attributes().at(k);
|
||||
if (attr.name() == "frame") {
|
||||
kf.frame = attr.value().toLong();
|
||||
} else if (attr.name() == "type") {
|
||||
kf.type = attr.value().toInt();
|
||||
} else if (attr.name() == "value") {
|
||||
switch (field->type) {
|
||||
case EFFECT_FIELD_DOUBLE:
|
||||
kf.data = attr.value().toDouble();
|
||||
break;
|
||||
case EFFECT_FIELD_COLOR:
|
||||
{
|
||||
kf.data = QColor(attr.value().toString());
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_STRING:
|
||||
kf.data = attr.value().toString();
|
||||
break;
|
||||
case EFFECT_FIELD_BOOL:
|
||||
kf.data = (stream->text() == "1");
|
||||
break;
|
||||
case EFFECT_FIELD_COMBO:
|
||||
kf.data = (stream->text().toInt());
|
||||
break;
|
||||
case EFFECT_FIELD_FONT:
|
||||
kf.data = (stream->text().toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
keys.append(kf);
|
||||
}
|
||||
}
|
||||
field->keyframes = keys;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
QVariant load_data_from_string(int type, const QString& string) {
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return string.toDouble(); break;
|
||||
case EFFECT_FIELD_COLOR: return QColor(string); break;
|
||||
case EFFECT_FIELD_STRING: return string; break;
|
||||
case EFFECT_FIELD_BOOL: return (string == "1"); break;
|
||||
case EFFECT_FIELD_COMBO: return string.toInt(); break;
|
||||
case EFFECT_FIELD_FONT: return string; break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QString save_data(int type, const QVariant& data) {
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble()); break;
|
||||
case EFFECT_FIELD_COLOR: return data.value<QColor>().name(); break;
|
||||
case EFFECT_FIELD_STRING: return data.toString(); break;
|
||||
case EFFECT_FIELD_BOOL: return QString::number(data.toBool()); break;
|
||||
case EFFECT_FIELD_COMBO: return QString::number(data.toInt()); break;
|
||||
case EFFECT_FIELD_FONT: return data.toString(); break;
|
||||
}
|
||||
return QString();
|
||||
QString save_data_to_string(int type, const QVariant& data) {
|
||||
switch (type) {
|
||||
case EFFECT_FIELD_DOUBLE: return QString::number(data.toDouble()); break;
|
||||
case EFFECT_FIELD_COLOR: return data.value<QColor>().name(); break;
|
||||
case EFFECT_FIELD_STRING: return data.toString(); break;
|
||||
case EFFECT_FIELD_BOOL: return QString::number(data.toBool()); break;
|
||||
case EFFECT_FIELD_COMBO: return QString::number(data.toInt()); break;
|
||||
case EFFECT_FIELD_FONT: return data.toString(); break;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void Effect::load(QXmlStreamReader& stream) {
|
||||
int row_count = 0;
|
||||
|
||||
while (!stream.atEnd() && !(stream.name() == "effect" && 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();
|
||||
|
||||
// read keyframes
|
||||
if (stream.name() == "keyframes" && stream.isStartElement()) {
|
||||
for (int k=0;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||
if (attr.name() == "enabled") {
|
||||
row->keyframing = (attr.value() == "1");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (row->keyframing) {
|
||||
stream.readNext();
|
||||
while (!stream.atEnd() && !(stream.name() == "keyframes" && stream.isEndElement())) {
|
||||
if (stream.name() == "key" && stream.isStartElement()) {
|
||||
long keyframe_frame;
|
||||
int keyframe_type;
|
||||
for (int k=0;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||
if (attr.name() == "frame") {
|
||||
keyframe_frame = attr.value().toLong();
|
||||
} else if (attr.name() == "type") {
|
||||
keyframe_type = attr.value().toInt();
|
||||
}
|
||||
}
|
||||
row->keyframe_times.append(keyframe_frame);
|
||||
row->keyframe_types.append(keyframe_type);
|
||||
}
|
||||
stream.readNext();
|
||||
}
|
||||
}
|
||||
stream.readNext();
|
||||
}
|
||||
|
||||
// read field
|
||||
if (stream.name() == "field" && stream.isStartElement()) {
|
||||
if (field_count < row->fieldCount()) {
|
||||
EffectField* field = row->field(field_count);
|
||||
|
||||
for (int k=0;k<stream.attributes().size();k++) {
|
||||
const QXmlStreamAttribute& attr = stream.attributes().at(k);
|
||||
if (attr.name() == "value") {
|
||||
field->set_current_data(load_data_from_string(field->type, attr.value().toString()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (!stream.atEnd() && !(stream.name() == "field" && stream.isEndElement())) {
|
||||
stream.readNext();
|
||||
|
||||
// read all keyframes
|
||||
if (stream.name() == "key" && stream.isStartElement()) {
|
||||
stream.readNext();
|
||||
field->keyframe_data.append(load_data_from_string(field->type, stream.text().toString()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qDebug() << "[ERROR] Too many fields for effect" << id << "row" << row_count << ". Project might be corrupt. (Got" << field_count << ", expected <" << row->fieldCount()-1 << ")";
|
||||
}
|
||||
field_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
qDebug() << "[ERROR] Too many rows for effect" << id << ". Project might be corrupt. (Got" << row_count << ", expected <" << rows.size()-1 << ")";
|
||||
}
|
||||
row_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Effect::save(QXmlStreamWriter& stream) {
|
||||
@@ -227,9 +259,9 @@ void Effect::save(QXmlStreamWriter& stream) {
|
||||
for (int j=0;j<row->fieldCount();j++) {
|
||||
EffectField* field = row->field(j);
|
||||
stream.writeStartElement("field"); // field
|
||||
stream.writeAttribute("value", save_data(field->type, field->get_current_data()));
|
||||
stream.writeAttribute("value", save_data_to_string(field->type, field->get_current_data()));
|
||||
for (int k=0;k<field->keyframe_data.size();k++) {
|
||||
stream.writeTextElement("key", save_data(field->type, field->keyframe_data.at(k)));
|
||||
stream.writeTextElement("key", save_data_to_string(field->type, field->keyframe_data.at(k)));
|
||||
}
|
||||
stream.writeEndElement(); // field
|
||||
}
|
||||
@@ -243,8 +275,8 @@ Effect* Effect::copy(Clip* c) {
|
||||
return copy;
|
||||
}
|
||||
|
||||
void Effect::process_image(long, QImage&) {}
|
||||
void Effect::process_gl(long, QOpenGLShaderProgram&, int*, int*) {}
|
||||
void Effect::process_image(long, uint8_t*, int, int) {}
|
||||
void Effect::process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords) {}
|
||||
void Effect::process_audio(uint8_t*, int) {}
|
||||
|
||||
/* Effect Row Definitions */
|
||||
@@ -261,6 +293,7 @@ EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, in
|
||||
|
||||
// DEBUG STARTS
|
||||
QPushButton* nkf = new QPushButton();
|
||||
nkf->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
|
||||
connect(nkf, SIGNAL(clicked(bool)), this, SLOT(set_keyframe_now()));
|
||||
ui->addWidget(nkf, row, 5);
|
||||
// DEBUG ENDS
|
||||
@@ -337,7 +370,7 @@ EffectField::EffectField(EffectRow *parent, int t) : parent_row(parent), type(t)
|
||||
QTextEdit* edit = new QTextEdit();
|
||||
edit->setUndoRedoEnabled(true);
|
||||
ui_element = edit;
|
||||
connect(edit, SIGNAL(textChanged()), this, SLOT(uiElementChange()));
|
||||
connect(edit->document(), SIGNAL(contentsChanged()), this, SLOT(uiElementChange()));
|
||||
}
|
||||
break;
|
||||
case EFFECT_FIELD_BOOL:
|
||||
@@ -432,9 +465,14 @@ void EffectField::get_keyframe_data(long frame, int* before, int* after, double*
|
||||
*before = after_keyframe_index;
|
||||
*after = after_keyframe_index;
|
||||
}
|
||||
} else {
|
||||
*before = before_keyframe_index;
|
||||
*after = before_keyframe_index;
|
||||
} else {
|
||||
if (before_keyframe_index > -1) {
|
||||
*before = before_keyframe_index;
|
||||
*after = before_keyframe_index;
|
||||
} else {
|
||||
*before = after_keyframe_time;
|
||||
*after = after_keyframe_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-2
@@ -53,6 +53,26 @@ Effect* create_effect(int effect_id, Clip* c);
|
||||
#define EFFECT_KEYFRAME_HOLD 1
|
||||
#define EFFECT_KEYFRAME_BEZIER 2
|
||||
|
||||
struct GLTextureCoords {
|
||||
int vertexTopLeftX;
|
||||
int vertexTopLeftY;
|
||||
int vertexTopRightX;
|
||||
int vertexTopRightY;
|
||||
int vertexBottomLeftX;
|
||||
int vertexBottomLeftY;
|
||||
int vertexBottomRightX;
|
||||
int vertexBottomRightY;
|
||||
|
||||
double textureTopLeftX;
|
||||
double textureTopLeftY;
|
||||
double textureTopRightX;
|
||||
double textureTopRightY;
|
||||
double textureBottomRightX;
|
||||
double textureBottomRightY;
|
||||
double textureBottomLeftX;
|
||||
double textureBottomLeftY;
|
||||
};
|
||||
|
||||
class EffectField : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -163,8 +183,8 @@ public:
|
||||
|
||||
const char* ffmpeg_filter;
|
||||
|
||||
virtual void process_image(long frame, QImage& img);
|
||||
virtual void process_gl(long frame, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y);
|
||||
virtual void process_image(long frame, uint8_t* data, int width, int height);
|
||||
virtual void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
|
||||
virtual void process_audio(quint8* samples, int nb_bytes);
|
||||
public slots:
|
||||
void field_changed();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QXmlStreamAttributes>
|
||||
|
||||
InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_EFFECT), vert_shader(QOpenGLShader::Vertex), frag_shader(QOpenGLShader::Fragment) {
|
||||
InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_EFFECT) {
|
||||
enable_opengl = true;
|
||||
|
||||
EffectRow* amount_row = add_row("Amount:");
|
||||
@@ -22,12 +22,8 @@ InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_
|
||||
connect(amount_val, SIGNAL(changed()), this, SLOT(field_changed()));
|
||||
}
|
||||
|
||||
void InvertEffect::process_gl(long p, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y) {
|
||||
double value = amount_val->get_double_value(p)*0.01;
|
||||
|
||||
vert_shader.compileSourceCode("varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}");
|
||||
frag_shader.compileSourceCode("uniform sampler2D myTexture;\nvarying vec2 vTexCoord;\nvoid main(void) {\n\tvec4 textureColor = texture2D(myTexture, vTexCoord);\n\tgl_FragColor = vec4(textureColor.r+((1.0-textureColor.r-textureColor.r)*" + QString::number(value, 'f', 2) + "), textureColor.g+((1.0-textureColor.g-textureColor.g)*" + QString::number(value, 'f', 2) + "), textureColor.b+((1.0-textureColor.b-textureColor.b)*" + QString::number(value, 'f', 2) + "), 1);\n}");
|
||||
|
||||
shader_prog.addShader(&vert_shader);
|
||||
shader_prog.addShader(&frag_shader);
|
||||
void InvertEffect::process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords&) {
|
||||
double value = amount_val->get_double_value(frame)*0.01;
|
||||
shaders.addShaderFromSourceCode(QOpenGLShader::Vertex, "varying vec2 vTexCoord;\nvoid main() {\n\tvTexCoord = gl_MultiTexCoord0.xy;\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}");
|
||||
shaders.addShaderFromSourceCode(QOpenGLShader::Fragment, "uniform sampler2D myTexture;\nvarying vec2 vTexCoord;\nvoid main(void) {\n\tvec4 textureColor = texture2D(myTexture, vTexCoord);\n\tgl_FragColor = vec4(textureColor.r+((1.0-textureColor.r-textureColor.r)*" + QString::number(value, 'f', 2) + "), textureColor.g+((1.0-textureColor.g-textureColor.g)*" + QString::number(value, 'f', 2) + "), textureColor.b+((1.0-textureColor.b-textureColor.b)*" + QString::number(value, 'f', 2) + "), 1);\n}");
|
||||
}
|
||||
|
||||
@@ -9,12 +9,9 @@ class InvertEffect : public Effect {
|
||||
Q_OBJECT
|
||||
public:
|
||||
InvertEffect(Clip* c);
|
||||
void process_gl(long p, QOpenGLShaderProgram& shader_prog, int *anchor_x, int *anchor_y);
|
||||
|
||||
EffectField* amount_val;
|
||||
void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
|
||||
private:
|
||||
QOpenGLShader vert_shader;
|
||||
QOpenGLShader frag_shader;
|
||||
EffectField* amount_val;
|
||||
};
|
||||
|
||||
#endif // INVERTEFFECT_H
|
||||
|
||||
@@ -49,9 +49,9 @@ void ShakeEffect::refresh() {
|
||||
}
|
||||
}
|
||||
|
||||
void ShakeEffect::process_gl(long p, QOpenGLShaderProgram&, int*, int*) {
|
||||
void ShakeEffect::process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords) {
|
||||
if (shake_progress > shake_limit) {
|
||||
double ival = intensity_val->get_double_value(p);
|
||||
double ival = intensity_val->get_double_value(frame);
|
||||
if ((int)ival > 0) {
|
||||
prev_x = next_x;
|
||||
prev_y = next_y;
|
||||
@@ -81,7 +81,7 @@ void ShakeEffect::process_gl(long p, QOpenGLShaderProgram&, int*, int*) {
|
||||
offset_x = 0;
|
||||
offset_y = 0;
|
||||
}
|
||||
double rot_val = rotation_val->get_double_value(p);
|
||||
double rot_val = rotation_val->get_double_value(frame);
|
||||
if ((int)rot_val > 0) {
|
||||
prev_rot = next_rot;
|
||||
next_rot = (qrand() % (int) (rot_val * 2)) - rot_val;
|
||||
|
||||
@@ -7,7 +7,7 @@ class ShakeEffect : public Effect {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ShakeEffect(Clip* c);
|
||||
void process_gl(long p, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y);
|
||||
void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
|
||||
|
||||
EffectField* intensity_val;
|
||||
EffectField* rotation_val;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#define SMPTE_LOWER_BARS 4
|
||||
|
||||
SolidEffect::SolidEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SOLID_EFFECT) {
|
||||
enable_image = true;
|
||||
enable_opengl = true;
|
||||
|
||||
solid_type = add_row("Type:")->add_field(EFFECT_FIELD_COMBO);
|
||||
solid_type->add_combo_item("Solid Color", SOLID_TYPE_COLOR);
|
||||
@@ -40,7 +40,12 @@ void SolidEffect::enable_color() {
|
||||
solid_color_field->set_enabled(solid_type->get_combo_data(-1) == SOLID_TYPE_COLOR);
|
||||
}
|
||||
|
||||
void SolidEffect::process_image(long frame, QImage& img) {
|
||||
void SolidEffect::process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords) {
|
||||
|
||||
}
|
||||
|
||||
void SolidEffect::process_image(long frame, uint8_t* data, int w, int h) {
|
||||
QImage img(data, w, h, QImage::Format_RGBA8888); // create QImage wrapper
|
||||
QPainter p(&img);
|
||||
int width = img.width();
|
||||
int height = img.height();
|
||||
|
||||
@@ -10,7 +10,8 @@ public:
|
||||
EffectField* solid_type;
|
||||
EffectField* solid_color_field;
|
||||
EffectField* opacity_field;
|
||||
void process_image(long p, QImage &img);
|
||||
void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
|
||||
void process_image(long p, uint8_t* data, int width, int height);
|
||||
private slots:
|
||||
void enable_color();
|
||||
};
|
||||
|
||||
@@ -242,7 +242,8 @@ void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = fa
|
||||
}
|
||||
}
|
||||
|
||||
void TextEffect::process_image(long frame, QImage& img) {
|
||||
void TextEffect::process_image(long frame, uint8_t* data, int w, int h) {
|
||||
QImage img(data, w, h, QImage::Format_RGBA8888);
|
||||
QPainter p(&img);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
int width = img.width();
|
||||
|
||||
@@ -9,7 +9,7 @@ class TextEffect : public Effect {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TextEffect(Clip* c);
|
||||
void process_image(long frame, QImage& img);
|
||||
void process_image(long frame, uint8_t* data, int width, int height);
|
||||
|
||||
EffectField* text_val;
|
||||
EffectField* size_val;
|
||||
|
||||
@@ -121,13 +121,21 @@ void TransformEffect::toggle_uniform_scale(bool enabled) {
|
||||
scale_y->set_enabled(!enabled);
|
||||
}
|
||||
|
||||
void TransformEffect::process_gl(long frame, QOpenGLShaderProgram&, int* anchor_x, int* anchor_y) {
|
||||
void TransformEffect::process_gl(long frame, QOpenGLShaderProgram&, GLTextureCoords& coords) {
|
||||
// position
|
||||
glTranslatef(position_x->get_double_value(frame)-(parent_clip->sequence->width/2), position_y->get_double_value(frame)-(parent_clip->sequence->height/2), 0);
|
||||
|
||||
// anchor point
|
||||
*anchor_x += (anchor_x_box->get_double_value(frame)-default_anchor_x);
|
||||
*anchor_y += (anchor_y_box->get_double_value(frame)-default_anchor_y);
|
||||
int anchor_x_offset = (anchor_x_box->get_double_value(frame)-default_anchor_x);
|
||||
int anchor_y_offset = (anchor_y_box->get_double_value(frame)-default_anchor_y);
|
||||
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
|
||||
glRotatef(rotation->get_double_value(frame), 0, 0, 1);
|
||||
|
||||
@@ -8,7 +8,7 @@ class TransformEffect : public Effect {
|
||||
public:
|
||||
TransformEffect(Clip* c);
|
||||
void refresh();
|
||||
void process_gl(long p, QOpenGLShaderProgram& shader_prog, int* anchor_x, int* anchor_y);
|
||||
void process_gl(long frame, QOpenGLShaderProgram& shaders, GLTextureCoords& coords);
|
||||
|
||||
EffectField* position_x;
|
||||
EffectField* position_y;
|
||||
|
||||
Reference in New Issue
Block a user