From 590644ec1b6cb5ff315aed4de3c22bae0cbada04 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 20 Jul 2018 00:47:05 +0100 Subject: [PATCH] basic titling function added #84 --- effects/effects.cpp | 2 + effects/effects.h | 30 +++++++- effects/texteffect.cpp | 151 +++++++++++++++++++++++++++++++++++++++++ olive.pro | 3 +- project/effect.cpp | 1 + project/effect.h | 1 + ui/viewerwidget.cpp | 10 ++- 7 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 effects/texteffect.cpp diff --git a/effects/effects.cpp b/effects/effects.cpp index 6daf18d74..e2bfd0f00 100644 --- a/effects/effects.cpp +++ b/effects/effects.cpp @@ -14,6 +14,7 @@ void init_effects() { video_effect_names[VIDEO_TRANSFORM_EFFECT] = "Transform"; video_effect_names[VIDEO_SHAKE_EFFECT] = "Shake"; + video_effect_names[VIDEO_TEXT_EFFECT] = "Text"; audio_effect_names[AUDIO_VOLUME_EFFECT] = "Volume"; audio_effect_names[AUDIO_PAN_EFFECT] = "Pan"; @@ -24,6 +25,7 @@ Effect* create_effect(int effect_id, Clip* c) { switch (effect_id) { case VIDEO_TRANSFORM_EFFECT: return new TransformEffect(c); case VIDEO_SHAKE_EFFECT: return new ShakeEffect(c); + case VIDEO_TEXT_EFFECT: return new TextEffect(c); } } else { switch (effect_id) { diff --git a/effects/effects.h b/effects/effects.h index 700700d65..e693a75cf 100644 --- a/effects/effects.h +++ b/effects/effects.h @@ -3,16 +3,22 @@ #include "project/effect.h" +#include +#include #include class QSpinBox; class QCheckBox; class QComboBox; class LabelSlider; +class QOpenGLTexture; +class QTextEdit; +class QPushButton; enum VideoEffects { VIDEO_TRANSFORM_EFFECT, VIDEO_SHAKE_EFFECT, - VIDEO_EFFECT_COUNT + VIDEO_TEXT_EFFECT, + VIDEO_EFFECT_COUNT }; enum AudioEffects { @@ -82,6 +88,28 @@ private: double t; }; +class TextEffect : public Effect { + Q_OBJECT +public: + TextEffect(Clip* c); + ~TextEffect(); + void post_gl(); + Effect* copy(Clip* c); + void load(QXmlStreamReader* stream); + void save(QXmlStreamWriter* stream); + QTextEdit* text_val; + LabelSlider* size_val; + QPushButton* set_color_button; + QColor color; +private slots: + void set_color(); + void update_texture(); +private: + void set_button_color(); + QPixmap pixmap; + QOpenGLTexture* texture; +}; + // audio effects class VolumeEffect : public Effect { public: diff --git a/effects/texteffect.cpp b/effects/texteffect.cpp new file mode 100644 index 000000000..51d5beee1 --- /dev/null +++ b/effects/texteffect.cpp @@ -0,0 +1,151 @@ +#include "effects.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ui/labelslider.h" +#include "ui/collapsiblewidget.h" +#include "project/clip.h" +#include "project/sequence.h" + +TextEffect::TextEffect(Clip *c) : Effect(c), texture(NULL) { + setup_effect(EFFECT_TYPE_VIDEO, VIDEO_TEXT_EFFECT); + + QGridLayout* ui_layout = new QGridLayout(); + + ui_layout->addWidget(new QLabel("Text:"), 0, 0); + text_val = new QTextEdit(); + ui_layout->addWidget(text_val, 0, 1); + + ui_layout->addWidget(new QLabel("Size:"), 1, 0); + size_val = new LabelSlider(); + size_val->set_minimum_value(0); + ui_layout->addWidget(size_val, 1, 1); + + ui_layout->addWidget(new QLabel("Color:"), 2, 0); + set_color_button = new QPushButton(); + ui_layout->addWidget(set_color_button, 2, 1); + + ui->setLayout(ui_layout); + + container->setContents(ui); + + color = Qt::white; + set_button_color(); + + connect(text_val, SIGNAL(textChanged()), this, SLOT(update_texture())); + connect(size_val, SIGNAL(valueChanged()), this, SLOT(update_texture())); + connect(set_color_button, SIGNAL(clicked(bool)), this, SLOT(set_color())); + + size_val->set_value(24); + text_val->setText("Sample Text"); +} + +TextEffect::~TextEffect() { + texture->destroy(); + delete texture; +} + +void TextEffect::set_button_color() { + QPalette pal = set_color_button->palette(); + pal.setColor(QPalette::Button, color); + set_color_button->setPalette(pal); +} + +void TextEffect::set_color() { + color = QColorDialog::getColor(color, NULL); + set_button_color(); + update_texture(); +} + +void TextEffect::update_texture() { + pixmap = QPixmap(parent_clip->sequence->width, parent_clip->sequence->height); + pixmap.fill(Qt::transparent); + + QPainter p(&pixmap); + p.setRenderHint(QPainter::TextAntialiasing, true); + + // set font + QFont font = p.font(); + font.setPointSize(size_val->value()); + p.setFont(font); + + p.setPen(color); + p.drawText(QRect(0, 0, pixmap.width(), pixmap.height()), Qt::AlignCenter | Qt::TextWordWrap, text_val->toPlainText()); + + if (texture == NULL) { + texture = new QOpenGLTexture(pixmap.toImage()); + } else { + texture->destroy(); + texture->setData(pixmap.toImage()); + } + + // queue a repaint of the canvas + field_changed(); +} + +void TextEffect::post_gl() { + if (texture != NULL) { + texture->bind(); + + int half_width = pixmap.width()/2; + int half_height = pixmap.height()/2; + + glBegin(GL_QUADS); + glTexCoord2f(0.0, 0.0); + glVertex2f(-half_width, -half_height); + glTexCoord2f(1.0, 0.0); + glVertex2f(half_width, -half_height); + glTexCoord2f(1.0, 1.0); + glVertex2f(half_width, half_height); + glTexCoord2f(0.0, 1.0); + glVertex2f(-half_width, half_height); + glEnd(); + + texture->release(); + } +} + +Effect* TextEffect::copy(Clip* c) { + TextEffect* e = new TextEffect(c); + e->text_val->setPlainText(text_val->toPlainText()); + e->size_val->set_value(size_val->value()); + e->color = color; + return e; +} + +void TextEffect::load(QXmlStreamReader* stream) { + const QXmlStreamAttributes& attr = stream->attributes(); + for (int i=0;iset_value(a.value().toDouble()); + } else if (a.name() == "r") { + color.setRed(a.value().toInt()); + } else if (a.name() == "g") { + color.setGreen(a.value().toInt()); + } else if (a.name() == "b") { + color.setBlue(a.value().toInt()); + } + } + while (!(stream->name() == "effect" && stream->isEndElement())) { + stream->readNext(); + if (stream->name() == "text" && stream->isStartElement()) { + text_val->setPlainText(stream->text().toString()); + } + } +} + +void TextEffect::save(QXmlStreamWriter* stream) { + stream->writeAttribute("size", QString::number(size_val->value())); + stream->writeAttribute("r", QString::number(color.red())); + stream->writeAttribute("g", QString::number(color.green())); + stream->writeAttribute("b", QString::number(color.blue())); + stream->writeTextElement("text", text_val->toPlainText()); +} diff --git a/olive.pro b/olive.pro index 6ce6dbcd4..767dfdfa8 100644 --- a/olive.pro +++ b/olive.pro @@ -61,7 +61,8 @@ SOURCES += \ ui/audiomonitor.cpp \ project/undo.cpp \ ui/scrollarea.cpp \ - effects/shakeeffect.cpp + effects/shakeeffect.cpp \ + effects/texteffect.cpp HEADERS += \ mainwindow.h \ diff --git a/project/effect.cpp b/project/effect.cpp index dd8575f8e..55a9aaa95 100644 --- a/project/effect.cpp +++ b/project/effect.cpp @@ -36,4 +36,5 @@ Effect* Effect::copy(Clip*) {return NULL;} void Effect::load(QXmlStreamReader*) {} void Effect::save(QXmlStreamWriter*) {} void Effect::process_gl(int*, int*) {} +void Effect::post_gl() {} void Effect::process_audio(uint8_t*, int) {} diff --git a/project/effect.h b/project/effect.h index 85d052879..320b6b5c1 100644 --- a/project/effect.h +++ b/project/effect.h @@ -32,6 +32,7 @@ public: virtual void save(QXmlStreamWriter* stream); virtual void process_gl(int* anchor_x, int* anchor_y); + virtual void post_gl(); virtual void process_audio(quint8* samples, int nb_bytes); public slots: diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 6fea28c4d..899cd58cf 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -116,8 +116,8 @@ void ViewerWidget::paintGL() { } else if (panel_timeline->playhead >= c->timeline_in) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(1.0, 1.0, 1.0, 1.0); - glLoadIdentity(); + int half_width = c->sequence->width/2; int half_height = c->sequence->height/2; if (flip) { @@ -151,6 +151,9 @@ void ViewerWidget::paintGL() { c->texture->bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2f(-anchor_x, -anchor_y); @@ -163,6 +166,11 @@ void ViewerWidget::paintGL() { glEnd(); c->texture->release(); + + // perform all transform effects + for (int j=0;jeffects.size();j++) { + c->effects.at(j)->post_gl(); + } } } else if (render_audio && c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&