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;