ported ALL effects to opengl

This commit is contained in:
itsmattkc
2018-09-02 16:57:50 +10:00
parent cf35ea23bb
commit 0e8810109a
30 changed files with 485 additions and 168 deletions
+83 -4
View File
@@ -95,8 +95,9 @@ Effect::Effect(Clip* c, int t, int i) :
parent_clip(c),
type(t),
id(i),
enable_image(false),
enable_opengl(false),
enable_shader(false),
enable_coords(false),
enable_superimpose(false),
iterations(1),
isOpen(false),
glslProgram(NULL),
@@ -355,10 +356,88 @@ Effect* Effect::copy(Clip* c) {
return copy;
}
void Effect::process_image(double, uint8_t*, int, int) {}
void Effect::process_gl(double, GLTextureCoords&) {}
void Effect::process_shader(double) {}
void Effect::process_coords(double, GLTextureCoords&) {}
const GLuint Effect::process_superimpose(double) {return 0;}
void Effect::process_audio(double, double, quint8*, int, int) {}
SuperimposeEffect::SuperimposeEffect(Clip* c, int t, int i) : Effect(c, t, i), texture(NULL) {
enable_superimpose = true;
}
void SuperimposeEffect::open() {
Effect::open();
texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
}
void SuperimposeEffect::close() {
Effect::close();
deleteTexture();
}
const GLuint SuperimposeEffect::process_superimpose(double timecode) {
bool recreate_texture = false;
int width = parent_clip->getWidth();
int height = parent_clip->getHeight();
if (width != img.width() || height != img.height()) {
img = QImage(width, height, QImage::Format_RGBA8888);
recreate_texture = true;
}
if (valueHasChanged(timecode) || recreate_texture) {
redraw(timecode);
}
if (texture != NULL) {
if (recreate_texture || texture->width() != img.width() || texture->height() != img.height()) {
deleteTexture();
texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
texture->setData(img);
} else {
texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, img.constBits());
}
return texture->textureId();
}
return 0;
}
void SuperimposeEffect::redraw(double) {}
void SuperimposeEffect::deleteTexture() {
delete texture;
texture = NULL;
}
bool SuperimposeEffect::valueHasChanged(double timecode) {
if (cachedValues.size() == 0) {
for (int i=0;i<row_count();i++) {
EffectRow* crow = row(i);
for (int j=0;j<crow->fieldCount();j++) {
cachedValues.append(crow->field(j)->get_current_data());
}
}
return true;
} else {
bool changed = false;
int index = 0;
for (int i=0;i<row_count();i++) {
EffectRow* crow = row(i);
for (int j=0;j<crow->fieldCount();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;
}
}
/* Effect Row Definitions */
EffectRow::EffectRow(Effect *parent, QGridLayout *uilayout, const QString &n, int row) :
+28 -8
View File
@@ -5,7 +5,9 @@
#include <QString>
#include <QVector>
#include <QColor>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
class QLabel;
class QWidget;
class CollapsibleWidget;
@@ -193,21 +195,23 @@ public:
void save(QXmlStreamWriter& stream);
// glsl handling
void open();
void close();
void startEffect();
void endEffect();
virtual void open();
virtual void close();
virtual void startEffect();
virtual void endEffect();
bool enable_image;
bool enable_opengl;
bool enable_shader;
bool enable_coords;
bool enable_superimpose;
int getIterations();
void setIterations(int i);
const char* ffmpeg_filter;
virtual void process_image(double timecode, uint8_t* data, int width, int height);
virtual void process_gl(double timecode, GLTextureCoords& coords);
virtual void process_shader(double timecode);
virtual void process_coords(double timecode, GLTextureCoords& coords);
virtual const GLuint process_superimpose(double timecode);
virtual void process_audio(double timecode_start, double timecode_end, quint8* samples, int nb_bytes, int channel_count);
public slots:
void field_changed();
@@ -224,4 +228,20 @@ private:
bool bound;
};
class SuperimposeEffect : public Effect {
public:
SuperimposeEffect(Clip* c, int t, int i);
virtual void open();
virtual void close();
virtual const GLuint process_superimpose(double timecode);
virtual void redraw(double timecode);
protected:
QImage img;
QOpenGLTexture* texture;
void deleteTexture();
bool valueHasChanged(double timecode);
private:
QVector<QVariant> cachedValues;
};
#endif // EFFECT_H
+2 -2
View File
@@ -3,7 +3,7 @@
#include "project/clip.h"
BoxBlurEffect::BoxBlurEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_BOXBLUR_EFFECT) {
enable_opengl = true;
enable_shader = true;
radius_val = add_row("Radius:")->add_field(EFFECT_FIELD_DOUBLE);
// iteration_val = add_row("Iterations:")->add_field(EFFECT_FIELD_DOUBLE);
@@ -33,7 +33,7 @@ BoxBlurEffect::BoxBlurEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_BOXBL
connect(vert_val, SIGNAL(changed()), this, SLOT(field_changed()));
}
void BoxBlurEffect::process_gl(double timecode, GLTextureCoords&) {
void BoxBlurEffect::process_shader(double timecode) {
glslProgram->setUniformValue("resolution", parent_clip->getWidth(), parent_clip->getHeight());
glslProgram->setUniformValue("radius", (GLfloat) radius_val->get_double_value(timecode));
glslProgram->setUniformValue("horiz_blur", horiz_val->get_bool_value(timecode));
+1 -2
View File
@@ -7,8 +7,7 @@ class BoxBlurEffect : public Effect
{
public:
BoxBlurEffect(Clip* c);
void process_gl(double timecode, GLTextureCoords &coords);
void process_shader(double timecode);
private:
EffectField* radius_val;
EffectField* iteration_val;
+2 -2
View File
@@ -1,7 +1,7 @@
#include "chromakeyeffect.h"
ChromaKeyEffect::ChromaKeyEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_CHROMAKEY_EFFECT) {
enable_opengl = true;
enable_shader = true;
color_field = add_row("Color:")->add_field(EFFECT_FIELD_COLOR);
tolerance_field = add_row("Tolerance:")->add_field(EFFECT_FIELD_DOUBLE);
@@ -19,7 +19,7 @@ ChromaKeyEffect::ChromaKeyEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_C
connect(tolerance_field, SIGNAL(changed()), this, SLOT(field_changed()));
}
void ChromaKeyEffect::process_gl(double timecode, GLTextureCoords&) {
void ChromaKeyEffect::process_shader(double timecode) {
glslProgram->setUniformValue("keyColor", color_field->get_color_value(timecode));
glslProgram->setUniformValue("threshold", (GLfloat) (tolerance_field->get_double_value(timecode)*0.01));
}
+1 -1
View File
@@ -6,7 +6,7 @@
class ChromaKeyEffect : public Effect {
public:
ChromaKeyEffect(Clip* c);
void process_gl(double timecode, GLTextureCoords &coords);
void process_shader(double timecode);
private:
EffectField* color_field;
EffectField* tolerance_field;
+2 -2
View File
@@ -1,7 +1,7 @@
#include "cropeffect.h"
CropEffect::CropEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_CROP_EFFECT) {
enable_opengl = true;
enable_coords = true;
left_field = add_row("Left:")->add_field(EFFECT_FIELD_DOUBLE);
top_field = add_row("Top:")->add_field(EFFECT_FIELD_DOUBLE);
@@ -23,7 +23,7 @@ CropEffect::CropEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_CROP_EFFECT
connect(bottom_field, SIGNAL(changed()), this, SLOT(field_changed()));
}
void CropEffect::process_gl(double timecode, GLTextureCoords &coords) {
void CropEffect::process_coords(double timecode, GLTextureCoords &coords) {
// store initial coord data
int left = coords.vertexTopLeftX;
int top = coords.vertexTopLeftY;
+1 -1
View File
@@ -7,7 +7,7 @@ class CropEffect : public Effect
{
public:
CropEffect(Clip* c);
void process_gl(double timecode, GLTextureCoords &coords);
void process_coords(double timecode, GLTextureCoords &coords);
private:
EffectField* left_field;
EffectField* top_field;
+2 -2
View File
@@ -1,7 +1,7 @@
#include "flipeffect.h"
FlipEffect::FlipEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_FLIP_EFFECT) {
enable_opengl = true;
enable_coords = true;
horizontal_field = add_row("Horizontal:")->add_field(EFFECT_FIELD_BOOL);
vertical_field = add_row("Vertical:")->add_field(EFFECT_FIELD_BOOL);
@@ -10,7 +10,7 @@ FlipEffect::FlipEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_FLIP_EFFECT
connect(vertical_field, SIGNAL(changed()), this, SLOT(field_changed()));
}
void FlipEffect::process_gl(double timecode, GLTextureCoords &coords) {
void FlipEffect::process_coords(double timecode, GLTextureCoords &coords) {
if (horizontal_field->get_bool_value(timecode)) {
double tlX = coords.textureTopLeftX;
double blX = coords.textureBottomLeftX;
+1 -1
View File
@@ -7,7 +7,7 @@ class FlipEffect : public Effect
{
public:
FlipEffect(Clip* c);
void process_gl(double timecode, GLTextureCoords &coords);
void process_coords(double timecode, GLTextureCoords &coords);
private:
EffectField* horizontal_field;
EffectField* vertical_field;
+2 -2
View File
@@ -5,7 +5,7 @@
#include <QImage>
GaussianBlurEffect::GaussianBlurEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_GAUSSIANBLUR_EFFECT) {
enable_opengl = true;
enable_shader = true;
radius_val = add_row("Radius:")->add_field(EFFECT_FIELD_DOUBLE);
sigma_val = add_row("Sigma:")->add_field(EFFECT_FIELD_DOUBLE);
@@ -30,7 +30,7 @@ GaussianBlurEffect::GaussianBlurEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, V
connect(vert_val, SIGNAL(changed()), this, SLOT(field_changed()));
}
void GaussianBlurEffect::process_gl(double timecode, GLTextureCoords &coords) {
void GaussianBlurEffect::process_shader(double timecode) {
glslProgram->setUniformValue("resolution", parent_clip->getWidth(), parent_clip->getHeight());
glslProgram->setUniformValue("radius", (GLfloat) radius_val->get_double_value(timecode));
glslProgram->setUniformValue("sigma", (GLfloat) sigma_val->get_double_value(timecode));
+1 -1
View File
@@ -7,7 +7,7 @@ class GaussianBlurEffect : public Effect
{
public:
GaussianBlurEffect(Clip* c);
void process_gl(double timecode, GLTextureCoords &coords);
void process_shader(double timecode);
private:
EffectField* radius_val;
EffectField* sigma_val;
+2 -2
View File
@@ -10,7 +10,7 @@
#include <QXmlStreamAttributes>
InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_EFFECT) {
enable_opengl = true;
enable_shader = true;
EffectRow* amount_row = add_row("Amount:");
amount_val = amount_row->add_field(EFFECT_FIELD_DOUBLE);
@@ -26,6 +26,6 @@ InvertEffect::InvertEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_INVERT_
fragPath = ":/shaders/inverteffect.frag";
}
void InvertEffect::process_gl(double timecode, GLTextureCoords&) {
void InvertEffect::process_shader(double timecode) {
glslProgram->setUniformValue("amount_val", (GLfloat) (amount_val->get_double_value(timecode)*0.01));
}
+1 -1
View File
@@ -7,7 +7,7 @@ class InvertEffect : public Effect {
Q_OBJECT
public:
InvertEffect(Clip* c);
void process_gl(double timecode, GLTextureCoords& coords);
void process_shader(double timecode);
private:
EffectField* amount_val;
};
+2 -2
View File
@@ -13,7 +13,7 @@
#include "panels/timeline.h"
ShakeEffect::ShakeEffect(Clip *c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SHAKE_EFFECT), inside(false) {
enable_opengl = true;
enable_coords = true;
EffectRow* intensity_row = add_row("Intensity:");
intensity_val = intensity_row->add_field(EFFECT_FIELD_DOUBLE);
@@ -49,7 +49,7 @@ void ShakeEffect::refresh() {
}
}
void ShakeEffect::process_gl(double timecode, GLTextureCoords&) {
void ShakeEffect::process_coords(double timecode, GLTextureCoords&) {
if (shake_progress > shake_limit) {
double ival = intensity_val->get_double_value(timecode);
if ((int)ival > 0) {
+1 -1
View File
@@ -7,7 +7,7 @@ class ShakeEffect : public Effect {
Q_OBJECT
public:
ShakeEffect(Clip* c);
void process_gl(double timecode, GLTextureCoords& coords);
void process_coords(double timecode, GLTextureCoords& coords);
EffectField* intensity_val;
EffectField* rotation_val;
+105 -7
View File
@@ -4,6 +4,7 @@
#include <QPainter>
#include <QtMath>
#include <QVariant>
#include <QImage>
#include "project/clip.h"
#include "project/sequence.h"
@@ -15,9 +16,7 @@
#define SMPTE_STRIP_COUNT 3
#define SMPTE_LOWER_BARS 4
SolidEffect::SolidEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SOLID_EFFECT) {
enable_opengl = true;
SolidEffect::SolidEffect(Clip* c) : SuperimposeEffect(c, EFFECT_TYPE_VIDEO, VIDEO_SOLID_EFFECT) {
solid_type = add_row("Type:")->add_field(EFFECT_FIELD_COMBO);
solid_type->add_combo_item("Solid Color", SOLID_TYPE_COLOR);
solid_type->add_combo_item("SMPTE Bars", SOLID_TYPE_BARS);
@@ -38,14 +37,113 @@ SolidEffect::SolidEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_SOLID_EFF
fragPath = ":/shaders/solideffect.frag";
}
void SolidEffect::process_gl(double timecode, GLTextureCoords&) {
solid_color_field->set_enabled(solid_type->get_combo_data(timecode) == SOLID_TYPE_COLOR);
/*void SolidEffect::process_gl(double timecode, GLTextureCoords&) {
glslProgram->setUniformValue("solidColor", solid_color_field->get_color_value(timecode));
glslProgram->setUniformValue("amount_val", (GLfloat) (opacity_field->get_double_value(timecode)*0.01));
}*/
void SolidEffect::redraw(double timecode) {
int w = img.width();
int h = img.height();
int alpha = (opacity_field->get_double_value(timecode)*2.55);
switch (solid_type->get_combo_data(timecode).toInt()) {
case SOLID_TYPE_COLOR:
{
QColor solidColor = solid_color_field->get_color_value(timecode);
solidColor.setAlpha(alpha);
img.fill(solidColor);
}
break;
case SOLID_TYPE_BARS:
{
// draw smpte bars
QPainter p(&img);
img.fill(Qt::transparent);
int bar_width = qCeil((double) w / 7.0);
int first_bar_height = qCeil((double) h / 3.0 * 2.0);
int second_bar_height = qCeil((double) h / 12.5);
int third_bar_y = first_bar_height + second_bar_height;
int third_bar_height = h - third_bar_y;
int third_bar_width = 0;
int bar_x, strip_width;
QColor first_color, second_color, third_color;
for (int i=0;i<SMPTE_BARS;i++) {
bar_x = bar_width*i;
switch (i) {
case 0:
first_color = QColor(192, 192, 192);
second_color = QColor(0, 0, 192);
break;
case 1:
first_color = QColor(192, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 2:
first_color = QColor(0, 192, 192);
second_color = QColor(192, 0, 192);
break;
case 3:
first_color = QColor(0, 192, 0);
second_color = QColor(19, 19, 19);
break;
case 4:
first_color = QColor(192, 0, 192);
second_color = QColor(0, 192, 192);
break;
case 5:
third_bar_width = qRound((double) bar_x / (double) SMPTE_LOWER_BARS);
first_color = QColor(192, 0, 0);
second_color = QColor(19, 19, 19);
strip_width = qCeil(bar_width/SMPTE_STRIP_COUNT);
for (int j=0;j<SMPTE_STRIP_COUNT;j++) {
switch (j) {
case 0:
third_color = QColor(29, 29, 29, alpha);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), third_color);
break;
case 1:
third_color = QColor(19, 19, 19, alpha);
p.fillRect(QRect(bar_x + strip_width, third_bar_y, strip_width, third_bar_height), third_color);
break;
case 2:
third_color = QColor(9, 9, 9, alpha);
p.fillRect(QRect(bar_x, third_bar_y, strip_width, third_bar_height), third_color);
break;
}
}
break;
case 6:
first_color = QColor(0, 0, 192);
second_color = QColor(192, 192, 192);
p.fillRect(QRect(bar_x, third_bar_y, bar_width, third_bar_height), QColor(19, 19, 19, alpha));
break;
}
first_color.setAlpha(alpha);
second_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, 0, bar_width, first_bar_height), first_color);
p.fillRect(QRect(bar_x, first_bar_height, bar_width, second_bar_height), second_color);
}
for (int i=0;i<SMPTE_LOWER_BARS;i++) {
bar_x = third_bar_width*i;
switch (i) {
case 0: third_color = QColor(0, 33, 76); break;
case 1: third_color = QColor(255, 255, 255); break;
case 2: third_color = QColor(50, 0, 106); break;
case 3: third_color = QColor(19, 19, 19); break;
}
third_color.setAlpha(alpha);
p.fillRect(QRect(bar_x, third_bar_y, third_bar_width, third_bar_height), third_color);
}
}
break;
}
}
void SolidEffect::process_image(long frame, uint8_t* data, int w, int h) {
/*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();
@@ -136,4 +234,4 @@ void SolidEffect::process_image(long frame, uint8_t* data, int w, int h) {
}
break;
}
}
}*/
+5 -3
View File
@@ -3,15 +3,17 @@
#include "../effect.h"
class SolidEffect : public Effect {
class QOpenGLTexture;
#include <QImage>
class SolidEffect : public SuperimposeEffect {
Q_OBJECT
public:
SolidEffect(Clip* c);
EffectField* solid_type;
EffectField* solid_color_field;
EffectField* opacity_field;
void process_gl(double timecode, GLTextureCoords& coords);
void process_image(long p, uint8_t* data, int width, int height);
void redraw(double timecode);
};
#endif // SOLIDEFFECT_H
+186 -70
View File
@@ -21,9 +21,9 @@
#include "ui/fontcombobox.h"
TextEffect::TextEffect(Clip *c) :
Effect(c, EFFECT_TYPE_VIDEO, VIDEO_TEXT_EFFECT)
SuperimposeEffect(c, EFFECT_TYPE_VIDEO, VIDEO_TEXT_EFFECT)
{
enable_image = true;
enable_superimpose = true;
text_val = add_row("Text:")->add_field(EFFECT_FIELD_STRING, 2);
@@ -98,6 +98,186 @@ TextEffect::TextEffect(Clip *c) :
connect(outline_bool, SIGNAL(toggled(bool)), this, SLOT(outline_enable(bool)));
}
void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = false) {
int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
int r1 = rect.top();
int r2 = rect.bottom();
int c1 = rect.left();
int c2 = rect.right();
int bpl = result.bytesPerLine();
int rgba[4];
unsigned char* p;
int i1 = 0;
int i2 = 3;
if (alphaOnly)
i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r1) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += bpl;
for (int j = r1; j < r2; j++, p += bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c1 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += 4;
for (int j = c1; j < c2; j++, p += 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r2) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= bpl;
for (int j = r1; j < r2; j++, p -= bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c2 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= 4;
for (int j = c1; j < c2; j++, p -= 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
}
void TextEffect::redraw(double timecode) {
img.fill(Qt::transparent);
QPainter p(&img);
p.setRenderHint(QPainter::Antialiasing);
int width = img.width();
int height = img.height();
// set font
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
font.setFamily(set_font_combobox->get_font_name(timecode));
font.setPointSize(size_val->get_double_value(timecode));
p.setFont(font);
QFontMetrics fm(font);
QStringList lines = text_val->get_string_value(timecode).split('\n');
// word wrap function
if (word_wrap_field->get_bool_value(timecode)) {
for (int i=0;i<lines.size();i++) {
QString s(lines.at(i));
if (fm.width(s) > width) {
int last_space_index = 0;
for (int j=0;j<s.length();j++) {
if (s.at(j) == ' ') {
if (fm.width(s.left(j)) > width) {
break;
} else {
last_space_index = j;
}
}
}
if (last_space_index > 0) {
lines.insert(i+1, s.mid(last_space_index + 1));
lines[i] = s.left(last_space_index);
}
}
}
}
QPainterPath path;
int text_height = fm.height()*lines.size();
for (int i=0;i<lines.size();i++) {
int text_x, text_y;
switch (halign_field->get_combo_data(timecode).toInt()) {
case Qt::AlignLeft: text_x = 0; break;
case Qt::AlignHCenter: text_x = (width/2) - (fm.width(lines.at(i))/2); break;
case Qt::AlignRight: text_x = width - fm.width(lines.at(i)); break;
case Qt::AlignJustify:
// add spaces until the string is too big
text_x = 0;
while (fm.width(lines.at(i) < width)) {
bool space = false;
QString spaced(lines.at(i));
for (int i=0;i<spaced.length();i++) {
if (spaced.at(i) == ' ') {
// insert a space
spaced.insert(i, ' ');
space = true;
// scan to next non-space
while (i < spaced.length() && spaced.at(i) == ' ') i++;
}
}
if (fm.width(spaced) > width || !space) {
break;
} else {
lines[i] = spaced;
}
}
break;
}
switch (valign_field->get_combo_data(timecode).toInt()) {
case Qt::AlignTop: text_y = (fm.height()*i)+fm.ascent(); break;
case Qt::AlignVCenter: text_y = ((height/2) - (text_height/2) - fm.descent()) + (fm.height()*(i+1)); break;
case Qt::AlignBottom: text_y = (height - text_height - fm.descent()) + (fm.height()*(i+1)); break;
}
path.addText(text_x, text_y, font, lines.at(i));
}
p.setPen(Qt::NoPen);
// draw shadow
if (shadow_bool->get_bool_value(timecode)) {
int shadow_offset = shadow_distance->get_double_value(timecode);
QPainterPath shadow_path(path);
shadow_path.translate(shadow_offset, shadow_offset);
QColor col = shadow_color->get_color_value(timecode);
col.setAlphaF(shadow_opacity->get_double_value(timecode)*0.01);
p.setBrush(col);
p.drawPath(shadow_path);
int blurSoftness = shadow_softness->get_double_value(timecode);
if (blurSoftness > 0) blurred2(img, img.rect(), blurSoftness, false);
}
// draw outline
int outline_width_val = outline_width->get_double_value(timecode);
if (outline_bool->get_bool_value(timecode) && outline_width_val > 0) {
QPen outline(outline_color->get_color_value(timecode));
outline.setWidth(outline_width_val);
p.setPen(outline);
}
// draw "master" text
p.setBrush(set_color_button->get_color_value(timecode));
p.drawPath(path);
}
void TextEffect::shadow_enable(bool e) {
shadow_color->set_enabled(e);
shadow_distance->set_enabled(e);
@@ -110,7 +290,7 @@ void TextEffect::outline_enable(bool e) {
outline_width->set_enabled(e);
}
QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly = false)
/*QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly = false)
{
int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
@@ -176,73 +356,9 @@ QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnl
}
return result;
}
}*/
void blurred2(QImage& result, const QRect& rect, int radius, bool alphaOnly = false) {
int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
int r1 = rect.top();
int r2 = rect.bottom();
int c1 = rect.left();
int c2 = rect.right();
int bpl = result.bytesPerLine();
int rgba[4];
unsigned char* p;
int i1 = 0;
int i2 = 3;
if (alphaOnly)
i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r1) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += bpl;
for (int j = r1; j < r2; j++, p += bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c1 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += 4;
for (int j = c1; j < c2; j++, p += 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r2) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= bpl;
for (int j = r1; j < r2; j++, p -= bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c2 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= 4;
for (int j = c1; j < c2; j++, p -= 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
}
void TextEffect::process_image(double timecode, uint8_t* data, int w, int h) {
/*void TextEffect::process_image(double timecode, uint8_t* data, int w, int h) {
QImage img(data, w, h, QImage::Format_RGBA8888);
QPainter p(&img);
p.setRenderHint(QPainter::Antialiasing);
@@ -357,4 +473,4 @@ void TextEffect::process_image(double timecode, uint8_t* data, int w, int h) {
// draw "master" text
p.setBrush(set_color_button->get_color_value(timecode));
p.drawPath(path);
}
}*/
+4 -2
View File
@@ -4,12 +4,14 @@
#include "../effect.h"
#include <QFont>
#include <QImage>
class QOpenGLTexture;
class TextEffect : public Effect {
class TextEffect : public SuperimposeEffect {
Q_OBJECT
public:
TextEffect(Clip* c);
void process_image(double timecode, uint8_t* data, int width, int height);
void redraw(double timecode);
EffectField* text_val;
EffectField* size_val;
+2 -2
View File
@@ -23,7 +23,7 @@
#define BLEND_MODE_OVERLAY 3
TransformEffect::TransformEffect(Clip* c) : Effect(c, EFFECT_TYPE_VIDEO, VIDEO_TRANSFORM_EFFECT) {
enable_opengl = true;
enable_coords = true;
EffectRow* position_row = add_row("Position:");
position_x = position_row->add_field(EFFECT_FIELD_DOUBLE); // position X
@@ -104,7 +104,7 @@ void TransformEffect::toggle_uniform_scale(bool enabled) {
scale_y->set_enabled(!enabled);
}
void TransformEffect::process_gl(double timecode, GLTextureCoords& coords) {
void TransformEffect::process_coords(double timecode, GLTextureCoords& coords) {
// position
glTranslatef(position_x->get_double_value(timecode)-(parent_clip->sequence->width/2), position_y->get_double_value(timecode)-(parent_clip->sequence->height/2), 0);
+1 -1
View File
@@ -8,7 +8,7 @@ class TransformEffect : public Effect {
public:
TransformEffect(Clip* c);
void refresh();
void process_gl(double timecode, GLTextureCoords& coords);
void process_coords(double timecode, GLTextureCoords& coords);
EffectField* position_x;
EffectField* position_y;
+2 -2
View File
@@ -321,7 +321,7 @@ void ExportThread::run() {
fbo.bind();
panel_viewer->viewer_widget->rendering = true;
panel_viewer->viewer_widget->fbo = &fbo;
panel_viewer->viewer_widget->default_fbo = &fbo;
long file_audio_samples = 0;
@@ -371,7 +371,7 @@ void ExportThread::run() {
panel_timeline->playhead++;
}
panel_viewer->viewer_widget->fbo = NULL;
panel_viewer->viewer_widget->default_fbo = NULL;
panel_viewer->viewer_widget->rendering = false;
fbo.release();
+1 -1
View File
@@ -85,7 +85,7 @@ MainWindow::MainWindow(QWidget *parent) :
updateTitle("");
setWindowState(Qt::WindowMaximized);
statusBar()->showMessage("Welcome to Olive");
statusBar()->showMessage("Welcome to " + appName);
setDockNestingEnabled(true);
+1 -1
View File
@@ -1281,7 +1281,7 @@ void MediaThrobber::stop(int icon_type, bool replace) {
}
// redraw clips
// panel_timeline->redraw_all_clips(replace);
panel_timeline->redraw_all_clips(replace);
panel_project->source_table->viewport()->update();
deleteLater();
-9
View File
@@ -347,9 +347,6 @@ void open_clip_worker(Clip* clip) {
}
clip->cache_B.frames[i]->linesize[0] = dstW*4;
}
clip->comp_frame_size = dstW * dstH * 4;
clip->comp_frame = new uchar[clip->comp_frame_size];
} else if (clip->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
// if FFmpeg can't pick up the channel layout (usually WAV), assume
// based on channel count (doesn't support surround sound sources yet)
@@ -418,16 +415,10 @@ void cache_clip_worker(Clip* clip, long playhead, bool write_A, bool write_B, bo
}
void close_clip_worker(Clip* clip) {
for (int i=0;i<clip->effects.size();i++) {
clip->effects.at(i)->close();
}
// closes ffmpeg file handle and frees any memory used for caching
MediaStream* ms = static_cast<Media*>(clip->media)->get_stream_from_file_index(clip->track < 0, clip->media_stream);
if (clip->track < 0) {
sws_freeContext(clip->sws_ctx);
delete [] clip->comp_frame;
} else {
swr_free(&clip->swr_ctx);
}
+8 -9
View File
@@ -55,8 +55,14 @@ void close_clip(Clip* clip) {
clip->texture = NULL;
}
for (int i=0;i<clip->effects.size();i++) {
clip->effects.at(i)->close();
}
if (clip->fbo != NULL) {
delete clip->fbo;
delete clip->fbo[0];
delete clip->fbo[1];
delete [] clip->fbo;
clip->fbo = NULL;
}
@@ -178,14 +184,7 @@ bool get_clip_frame(Clip* c, long playhead) {
c->texture->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
}
memcpy(c->comp_frame, current_frame->data[0], c->comp_frame_size);
for (int i=0;i<c->effects.size();i++) {
if (c->effects.at(i)->is_enabled() && c->effects.at(i)->enable_image) {
c->effects.at(i)->process_image(sequence_clip_time, c->comp_frame, current_frame->width, current_frame->height);
}
}
c->texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, c->comp_frame);
c->texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, current_frame->data[0]);
c->texture_frame = clip_time;
return true;
+1 -3
View File
@@ -81,8 +81,6 @@ struct Clip
AVCodecContext* codecCtx;
AVPacket* pkt;
AVFrame* frame;
uchar* comp_frame;
int comp_frame_size;
bool pkt_written;
bool reached_end;
@@ -102,7 +100,7 @@ struct Clip
// video playback variables
SwsContext* sws_ctx;
QOpenGLFramebufferObject* fbo;
QOpenGLFramebufferObject** fbo;
QOpenGLTexture* texture;
long texture_frame;
+35 -22
View File
@@ -28,7 +28,7 @@ extern "C" {
ViewerWidget::ViewerWidget(QWidget *parent) :
QOpenGLWidget(parent),
rendering(false),
fbo(NULL)
default_fbo(NULL)
{
QSurfaceFormat format;
format.setDepthBufferSize(24);
@@ -67,12 +67,12 @@ void ViewerWidget::paintEvent(QPaintEvent *e) {
}
}
GLuint ViewerWidget::draw_clip(Clip* clip, GLuint texture) {
GLuint ViewerWidget::draw_clip(QOpenGLFramebufferObject* fbo, GLuint texture) {
glPushMatrix();
glLoadIdentity();
glOrtho(0, 1, 0, 1, -1, 1);
clip->fbo->bind();
fbo->bind();
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
@@ -87,11 +87,11 @@ GLuint ViewerWidget::draw_clip(Clip* clip, GLuint texture) {
glEnd();
glBindTexture(GL_TEXTURE_2D, NULL);
clip->fbo->release();
if (fbo != NULL) fbo->bind();
fbo->release();
if (default_fbo != NULL) default_fbo->bind();
glPopMatrix();
return clip->fbo->takeTexture();
return fbo->texture();
}
GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
@@ -198,12 +198,15 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
} else if (playhead >= c->timeline_in) {
// start preparing cache
if (c->fbo == NULL) {
c->fbo = new QOpenGLFramebufferObject(video_width, video_height);
c->fbo = new QOpenGLFramebufferObject* [2];
c->fbo[0] = new QOpenGLFramebufferObject(video_width, video_height);
c->fbo[1] = new QOpenGLFramebufferObject(video_width, video_height);
}
glViewport(0, 0, video_width, video_height);
GLuint composite_texture = draw_clip(c, textureID);
GLuint composite_texture = draw_clip(c->fbo[0], textureID);
bool fbo_switcher = true;
GLTextureCoords coords;
coords.vertexTopLeftX = coords.vertexBottomLeftX = -video_width/2;
@@ -215,11 +218,23 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
// EFFECT CODE START
for (int j=0;j<c->effects.size();j++) {
if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) {
c->effects.at(j)->startEffect();
for (int k=0;k<c->effects.at(j)->getIterations();k++) {
c->effects.at(j)->process_gl(((double)(panel_timeline->playhead-c->timeline_in+c->clip_in)/(double)sequence->frame_rate), coords);
composite_texture = draw_clip(c, composite_texture);
Effect* e = c->effects.at(j);
if (e->is_enabled()) {
double timecode = ((double)(panel_timeline->playhead-c->timeline_in+c->clip_in)/(double)sequence->frame_rate);
if (e->enable_coords) {
e->process_coords(timecode, coords);
}
if (e->enable_shader || e->enable_superimpose) {
e->startEffect();
for (int k=0;k<e->getIterations();k++) {
e->process_shader(timecode);
composite_texture = draw_clip(c->fbo[fbo_switcher], composite_texture);
if (e->enable_superimpose) {
GLuint superimpose_texture = e->process_superimpose(timecode);
if (superimpose_texture != 0) draw_clip(c->fbo[fbo_switcher], superimpose_texture);
}
fbo_switcher = !fbo_switcher;
}
}
}
}
@@ -237,17 +252,17 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
c->closing_transition->process_transition((double)transition_progress/(double)c->closing_transition->length);
}
}
// EFFECT CODE END
for (int j=0;j<c->effects.size();j++) {
if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) {
if ((c->effects.at(j)->enable_shader || c->effects.at(j)->enable_superimpose) && c->effects.at(j)->is_enabled()) {
c->effects.at(j)->endEffect();
}
}
// EFFECT CODE END
if (nest != NULL) {
if (nest->fbo == NULL) nest->fbo = new QOpenGLFramebufferObject(s->width, s->height);
nest->fbo->bind();
// if (nest->fbo == NULL) nest->fbo = new QOpenGLFramebufferObject(s->width, s->height);
nest->fbo[0]->bind();
glViewport(0, 0, s->width, s->height);
} else if (rendering) {
glViewport(0, 0, s->width, s->height);
@@ -271,11 +286,9 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
glVertex2f(coords.vertexBottomLeftX, coords.vertexBottomLeftY); // bottom left
glEnd();
glDeleteTextures(1, &composite_texture);
if (nest != NULL) {
nest->fbo->release();
if (fbo != NULL) fbo->bind();
nest->fbo[0]->release();
if (default_fbo != NULL) default_fbo->bind();
}
}
} else {
@@ -292,7 +305,7 @@ GLuint ViewerWidget::compose_sequence(Clip* nest, bool render_audio) {
}
}
return (nest != NULL && nest->fbo != NULL) ? nest->fbo->takeTexture() : 0;
return (nest != NULL && nest->fbo != NULL) ? nest->fbo[0]->texture() : 0;
}
void ViewerWidget::paintGL() {
+2 -2
View File
@@ -23,7 +23,7 @@ public:
void paintGL();
void initializeGL();
QOpenGLFramebufferObject* fbo;
QOpenGLFramebufferObject* default_fbo;
protected:
void paintEvent(QPaintEvent *e);
// void resizeGL(int w, int h);
@@ -33,7 +33,7 @@ private slots:
void retry();
void deleteFunction();
GLuint compose_sequence(Clip *nest, bool render_audio);
GLuint draw_clip(Clip *clip, GLuint texture);
GLuint draw_clip(QOpenGLFramebufferObject *clip, GLuint texture);
};
#endif // VIEWERWIDGET_H