839 lines
28 KiB
C++
839 lines
28 KiB
C++
|
#include "DisplayMovieGLWidget.h"
|
|||
|
|
|||
|
#include <QApplication>
|
|||
|
#include <QDir>
|
|||
|
#include <QImageReader>
|
|||
|
#include <QPainter>
|
|||
|
#include <QDateTime>
|
|||
|
#include <QThreadPool>
|
|||
|
#include <QStringList>
|
|||
|
#include <QOpenGLPixelTransferOptions>
|
|||
|
|
|||
|
#include "MainWindow.h"
|
|||
|
|
|||
|
class LoadImageTask : public QObject, public QRunnable {
|
|||
|
public:
|
|||
|
using HandleResoult = std::function<void(int index, QImage image)>;
|
|||
|
public:
|
|||
|
LoadImageTask(int index, const QVector<QString>& texturePaths, HandleResoult handle, QObject* parent = nullptr)
|
|||
|
: QObject(parent)
|
|||
|
, m_index(index)
|
|||
|
, m_texturePaths(texturePaths)
|
|||
|
, m_handle(std::move(handle)) {
|
|||
|
setAutoDelete(true);
|
|||
|
}
|
|||
|
|
|||
|
void run() override {
|
|||
|
const QString& path = m_texturePaths[m_index];
|
|||
|
QPixmap px(path);
|
|||
|
QImage image = px.toImage().mirrored();
|
|||
|
m_handle(m_index, std::move(image));
|
|||
|
}
|
|||
|
|
|||
|
private:
|
|||
|
int m_index{ 0 };
|
|||
|
const QVector<QString>& m_texturePaths;
|
|||
|
HandleResoult m_handle;
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
SourImasgeHandler::~SourImasgeHandler() {
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void SourImasgeHandler::run() {
|
|||
|
QImage dest(size_.width(), size_.height(), QImage::Format_RGBA8888);
|
|||
|
dest.fill(Qt::transparent);
|
|||
|
|
|||
|
QImage destAlpha(size_.width(), size_.height(), QImage::Format_RGBA8888);
|
|||
|
destAlpha.fill(Qt::transparent);
|
|||
|
|
|||
|
QPainter painter(&dest);
|
|||
|
QPainter painterAlpha(&destAlpha);
|
|||
|
|
|||
|
QPixmap px(path_);
|
|||
|
if (!px.isNull()) {
|
|||
|
const QSize& is = MainWindow::Get().GetImageShowSize();
|
|||
|
px = px.scaled(is, Qt::KeepAspectRatio);
|
|||
|
|
|||
|
QPoint sp(abs(size_.width() - px.width()) / 2, abs(size_.height() - px.height()) / 2 - 8);
|
|||
|
painter.drawPixmap(sp, px);
|
|||
|
|
|||
|
QLinearGradient gradient(sp.x(), sp.y(), sp.x() + 100, sp.y());
|
|||
|
gradient.setColorAt(0, QColor(255, 255, 255, 0));
|
|||
|
gradient.setColorAt(1, QColor(255, 255, 255, 255));
|
|||
|
painterAlpha.fillRect(QRect(sp.x(), sp.y(), 100, px.height()), gradient);
|
|||
|
|
|||
|
QLinearGradient gradientr(sp.x() + px.width() - 100, sp.y(), sp.x() + px.width(), sp.y());
|
|||
|
gradientr.setColorAt(0, QColor(255, 255, 225, 255));
|
|||
|
gradientr.setColorAt(1, QColor(255, 255, 225, 0));
|
|||
|
painterAlpha.fillRect(QRect(sp.x() + px.width() - 100, sp.y(), 100, px.height()), gradientr);
|
|||
|
|
|||
|
painterAlpha.fillRect(QRect(sp.x() + 100, sp.y(), px.width() - 200, px.height()), Qt::white);
|
|||
|
|
|||
|
|
|||
|
} else {
|
|||
|
// qWarning() << "DisplayMovieGLWidget::UpdateSourceImage load failed path:" << path_;
|
|||
|
}
|
|||
|
|
|||
|
dest.mirror();
|
|||
|
destAlpha.mirror();
|
|||
|
|
|||
|
emit Finish(dest, destAlpha);
|
|||
|
}
|
|||
|
|
|||
|
DisplayMovieGLWidget::DisplayMovieGLWidget(QWidget* parent /*= */)
|
|||
|
: QOpenGLWidget(parent) {
|
|||
|
makeCurrent();
|
|||
|
setAutoFillBackground(false);
|
|||
|
}
|
|||
|
|
|||
|
DisplayMovieGLWidget::~DisplayMovieGLWidget() {
|
|||
|
//m_vbo.destroy();
|
|||
|
if (m_program == nullptr) {
|
|||
|
return;
|
|||
|
}
|
|||
|
makeCurrent();
|
|||
|
delete m_background;
|
|||
|
delete m_mask;
|
|||
|
delete m_source;
|
|||
|
delete m_sourceAlpha;
|
|||
|
delete m_program;
|
|||
|
delete m_vshader;
|
|||
|
delete m_fshader;
|
|||
|
m_vbo->destroy();
|
|||
|
m_vao->destroy();
|
|||
|
doneCurrent();
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::initializeGL() {
|
|||
|
makeCurrent();
|
|||
|
initializeOpenGLFunctions();
|
|||
|
|
|||
|
static float vertices[] = {
|
|||
|
// 位置 // 颜色 // 纹理坐标
|
|||
|
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
|
|||
|
1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 右下
|
|||
|
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // 左下
|
|||
|
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上
|
|||
|
};
|
|||
|
static unsigned int indices[] = {
|
|||
|
// 注意索引从0开始!
|
|||
|
// 此例的索引(0,1,2,3)就是顶点数组vertices的下标,
|
|||
|
// 这样可以由下标代表顶点组合成矩形
|
|||
|
0, 1, 3, // 第一个三角形
|
|||
|
1, 2, 3 // 第二个三角形
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);// 设置清屏颜色
|
|||
|
glDisable(GL_DEPTH_TEST); // 启用深度测试
|
|||
|
glEnable(GL_COLOR_BUFFER_BIT); // 启用颜色缓冲区
|
|||
|
|
|||
|
const QString shaderDir = QApplication::applicationDirPath() + "/ProjectDisplay/shader/";
|
|||
|
|
|||
|
// 创建顶点着色器对象,并编译
|
|||
|
m_vshader = new QOpenGLShader(QOpenGLShader::Vertex);
|
|||
|
bool success = m_vshader->compileSourceFile(shaderDir + "vertex_shader.vs");
|
|||
|
if (!success) {
|
|||
|
const QString log = m_vshader->log();
|
|||
|
qDebug() << log;
|
|||
|
}
|
|||
|
// 创建片段着色器对象,并编译
|
|||
|
m_fshader = new QOpenGLShader(QOpenGLShader::Fragment);
|
|||
|
success = m_fshader->compileSourceFile(shaderDir + "fragment_shader.fs");
|
|||
|
if (!success) {
|
|||
|
const QString log = m_fshader->log();
|
|||
|
qDebug() << log;
|
|||
|
|
|||
|
}
|
|||
|
// 创建着色器程序对象,添加顶点着色器和片段着色器,并链接它们
|
|||
|
m_program = new QOpenGLShaderProgram;
|
|||
|
m_program->addShader(m_vshader);
|
|||
|
m_program->addShader(m_fshader);
|
|||
|
m_program->link();
|
|||
|
// 创建顶点数组对象,并绑定到当前上下文
|
|||
|
m_vao = new QOpenGLVertexArrayObject;
|
|||
|
m_vao->create();
|
|||
|
QOpenGLVertexArrayObject::Binder vaoBinder(m_vao);
|
|||
|
// 创建顶点缓冲对象,
|
|||
|
m_vbo = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
|
|||
|
m_vbo->create();
|
|||
|
m_vbo->bind();
|
|||
|
// 分配显存大小,并搬运至显存
|
|||
|
m_vbo->allocate(vertices, sizeof(vertices));
|
|||
|
|
|||
|
// 创建元素缓冲对象,
|
|||
|
m_ebo = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
|
|||
|
m_ebo->create();
|
|||
|
m_ebo->bind();
|
|||
|
// 分配显存大小,并搬运至显存
|
|||
|
m_ebo->allocate(indices, sizeof(indices));
|
|||
|
// 链接顶点属性
|
|||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), 0);
|
|||
|
// 顶点属性默认是禁用的,启用顶点属性0(location=0)
|
|||
|
m_program->enableAttributeArray(0);
|
|||
|
// 颜色属性
|
|||
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
|
|||
|
m_program->enableAttributeArray(1);
|
|||
|
// 纹理坐标属性
|
|||
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
|
|||
|
m_program->enableAttributeArray(2);
|
|||
|
|
|||
|
|
|||
|
m_vao->release();
|
|||
|
m_vbo->release();
|
|||
|
|
|||
|
QDateTime dt = QDateTime::currentDateTime();
|
|||
|
m_startTimestamp = dt.toUTC().toMSecsSinceEpoch();
|
|||
|
|
|||
|
#ifdef BG_VLC
|
|||
|
PlayBackgroundMovie();
|
|||
|
#else
|
|||
|
InitBackgroundImages();
|
|||
|
#endif
|
|||
|
|
|||
|
InitBackgroundTexture();
|
|||
|
|
|||
|
InitMaskImages();
|
|||
|
InitMaskTexture();
|
|||
|
InitForeMovieTextImage();
|
|||
|
|
|||
|
m_program->bind(); //在修改uniform值之前,一定要绑定着色器程序到当前激活的opengl上下文
|
|||
|
m_program->setUniformValue("bgMap", 0);
|
|||
|
m_program->setUniformValue("maskMap", 1);
|
|||
|
m_program->setUniformValue("sourceMap", 2);
|
|||
|
m_program->setUniformValue("textMap", 3);
|
|||
|
m_program->setUniformValue("movieTextMap", 4);
|
|||
|
m_program->setUniformValue("bgMapMask", 5);
|
|||
|
m_program->setUniformValue("sourceAlphaMap", 6);
|
|||
|
|
|||
|
//connect(&m_timer, &QTimer::timeout, this, &DisplayMovieGLWidget::OnTimeout);
|
|||
|
//m_timer.start(40);
|
|||
|
|
|||
|
QTimer::singleShot(3000, [this]() {
|
|||
|
m_showSource = true;
|
|||
|
|
|||
|
}
|
|||
|
);
|
|||
|
|
|||
|
//OnMessage("0|1|0");
|
|||
|
//OnMessage("");
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::paintGL() {
|
|||
|
makeCurrent();
|
|||
|
#ifdef BG_VLC
|
|||
|
if (!videoImage_.isNull()) {
|
|||
|
QOpenGLTexture::PixelFormat pf = QOpenGLTexture::BGRA;
|
|||
|
const void* data = reinterpret_cast<const void*>(videoImage_.constBits());
|
|||
|
#else
|
|||
|
if (m_backgroundFrameCount > 0 && !m_textureData.isEmpty()) {
|
|||
|
const QImage& image = m_textureData[m_backgroundCurrentFrame];
|
|||
|
QOpenGLTexture::PixelFormat pf = QOpenGLTexture::RGB;
|
|||
|
const void* data = reinterpret_cast<const void*>(image.constBits());
|
|||
|
#endif
|
|||
|
QOpenGLPixelTransferOptions uploadOptions;
|
|||
|
uploadOptions.setAlignment(8);
|
|||
|
m_background->setData(0, pf, QOpenGLTexture::UInt8, data, &uploadOptions);
|
|||
|
}
|
|||
|
if (!videoForeImage_.isNull()) {
|
|||
|
// const QImage& image = m_textureData[m_backgroundCurrentFrame];
|
|||
|
QOpenGLPixelTransferOptions uploadOptions;
|
|||
|
uploadOptions.setAlignment(8);
|
|||
|
m_movieSource->setData(0, QOpenGLTexture::BGRA, QOpenGLTexture::UInt8, videoForeImage_.constBits(), &uploadOptions);
|
|||
|
}
|
|||
|
|
|||
|
if (m_maskFrame < m_maskTextureData.size() && !m_maskTextureData.isEmpty()) {
|
|||
|
const QImage& image = m_maskTextureData[m_maskFrame];
|
|||
|
QOpenGLPixelTransferOptions uploadOptions;
|
|||
|
uploadOptions.setAlignment(1);
|
|||
|
m_mask->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.constBits(), &uploadOptions);
|
|||
|
//m_mask->setData(image);
|
|||
|
}
|
|||
|
|
|||
|
glClearColor(0.f, 0.f, 0.f, 1.0f);
|
|||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|||
|
|
|||
|
// 将纹理绑定到当前激活的纹理单元
|
|||
|
if (nullptr != m_background) {
|
|||
|
m_background->bind(0);
|
|||
|
}
|
|||
|
|
|||
|
if (nullptr != m_mask) {
|
|||
|
m_mask->bind(1);
|
|||
|
}
|
|||
|
|
|||
|
if (nullptr != m_source) {
|
|||
|
m_source->bind(2);
|
|||
|
}
|
|||
|
|
|||
|
if (nullptr != m_textSource) {
|
|||
|
m_textSource->bind(3);
|
|||
|
}
|
|||
|
|
|||
|
if (nullptr != m_movieSource) {
|
|||
|
m_movieSource->bind(4);
|
|||
|
}
|
|||
|
if (nullptr != m_backgroundMask) {
|
|||
|
m_backgroundMask->bind(5);
|
|||
|
}
|
|||
|
if (nullptr != m_sourceAlpha) {
|
|||
|
m_sourceAlpha->bind(6);
|
|||
|
}
|
|||
|
|
|||
|
QMatrix4x4 projection;
|
|||
|
|
|||
|
QMatrix4x4 view;
|
|||
|
view.translate(0.0f, 0.0f, -1.0000f);
|
|||
|
|
|||
|
QMatrix4x4 model;
|
|||
|
|
|||
|
// 绑定着色器程序至当前上下文,相当于调用glUseProgram()
|
|||
|
m_program->bind();
|
|||
|
m_program->setUniformValue("view", view);
|
|||
|
m_program->setUniformValue("projection", projection);
|
|||
|
m_program->setUniformValue("model", model);
|
|||
|
|
|||
|
QDateTime dt = QDateTime::currentDateTime();
|
|||
|
qint64 nowTimeStamp = dt.toUTC().toMSecsSinceEpoch();
|
|||
|
float timeStamp = nowTimeStamp - m_startTimestamp;
|
|||
|
m_program->setUniformValue("fusion", m_fusion);
|
|||
|
m_program->setUniformValue("alpha", m_alpha);
|
|||
|
m_program->setUniformValue("time", timeStamp * 0.001f);
|
|||
|
|
|||
|
// 绑定VAO,调用设置的一组状态
|
|||
|
QOpenGLVertexArrayObject::Binder vaoBinder(m_vao);
|
|||
|
// 绘制三角形
|
|||
|
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
|||
|
m_program->release();
|
|||
|
// 交换缓存
|
|||
|
auto* context = QOpenGLContext::currentContext();
|
|||
|
context->swapBuffers(context->surface());
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::resizeGL(int w, int h) {
|
|||
|
makeCurrent();
|
|||
|
glViewport(0, 0, w, h);
|
|||
|
|
|||
|
update();
|
|||
|
}
|
|||
|
#if FPS_DISPLAY
|
|||
|
|
|||
|
|
|||
|
int gettimeofday(struct timeval* tp, struct timezone* tzp) {
|
|||
|
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
|
|||
|
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
|
|||
|
// until 00:00:00 January 1, 1970
|
|||
|
static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
|
|||
|
|
|||
|
SYSTEMTIME system_time;
|
|||
|
FILETIME file_time;
|
|||
|
uint64_t time;
|
|||
|
|
|||
|
GetSystemTime(&system_time);
|
|||
|
SystemTimeToFileTime(&system_time, &file_time);
|
|||
|
time = ((uint64_t)file_time.dwLowDateTime);
|
|||
|
time += ((uint64_t)file_time.dwHighDateTime) << 32;
|
|||
|
|
|||
|
tp->tv_sec = (long)((time - EPOCH) / 10000000L);
|
|||
|
tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static double GetFPSAverageCount(int seconds) {
|
|||
|
static struct timeval timeStart;
|
|||
|
static struct timeval timeFinish;
|
|||
|
static bool init{ false };
|
|||
|
static int count{ 0 };
|
|||
|
|
|||
|
static double fps = 0.0;
|
|||
|
|
|||
|
if (!init) {
|
|||
|
gettimeofday(&timeStart, NULL);
|
|||
|
gettimeofday(&timeFinish, NULL);
|
|||
|
init = true;
|
|||
|
} else {
|
|||
|
int cycle = timeFinish.tv_sec - timeStart.tv_sec;
|
|||
|
gettimeofday(&timeFinish, NULL);
|
|||
|
|
|||
|
if (cycle >= seconds) {
|
|||
|
gettimeofday(&timeStart, NULL);
|
|||
|
fps = count / seconds;
|
|||
|
count = 0;
|
|||
|
printf("----------\n");
|
|||
|
printf("%d S average FPS value is: %f\n", seconds, fps);
|
|||
|
}
|
|||
|
count++;
|
|||
|
}
|
|||
|
|
|||
|
return fps;
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::paintEvent(QPaintEvent* event) {
|
|||
|
QPainter painter;
|
|||
|
painter.begin(this);
|
|||
|
painter.setRenderHint(QPainter::Antialiasing);
|
|||
|
painter.translate(100, 100);
|
|||
|
painter.fillRect(rect(), QBrush(QColor(64, 32, 64)));
|
|||
|
|
|||
|
|
|||
|
painter.setPen(Qt::red);
|
|||
|
|
|||
|
double fps = GetFPSAverageCount(1);
|
|||
|
painter.drawText(rect().topLeft() + QPoint(20, 100), QString("fps:%1").arg(QString::number(fps)));
|
|||
|
// painter.drawLine(rect().topLeft(), rect().bottomRight());
|
|||
|
|
|||
|
painter.end();
|
|||
|
|
|||
|
}
|
|||
|
#endif
|
|||
|
void DisplayMovieGLWidget::OnTimeout() {
|
|||
|
makeCurrent();
|
|||
|
|
|||
|
|
|||
|
#ifndef BG_VLC
|
|||
|
LoadBackgroundTexture();
|
|||
|
if (!m_textureData.isEmpty()) {
|
|||
|
m_backgroundCurrentFrame = (m_backgroundCurrentFrame + 1) % m_textureData.size();
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
LoadMaskTexture();
|
|||
|
|
|||
|
if (++m_maskFrame >= m_maskTextureData.size()) {
|
|||
|
m_maskFrame = m_maskTextureData.size() - 1;
|
|||
|
}
|
|||
|
|
|||
|
if (m_showSource && (++m_colorMaskFrame >= m_maskTextureData.size())) {
|
|||
|
m_colorMaskFrame = m_maskTextureData.size() - 1;
|
|||
|
}
|
|||
|
|
|||
|
if (m_delayTime > 0) {
|
|||
|
m_delayTime -= 40;
|
|||
|
|
|||
|
if (m_alpha >= 1.0f) {
|
|||
|
m_alpha = 1.0f;
|
|||
|
} else {
|
|||
|
m_alpha *= 1.05f;
|
|||
|
}
|
|||
|
} else {
|
|||
|
if (m_alpha == 0.0f) {
|
|||
|
update();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (m_alpha > 0.000001f) {
|
|||
|
m_alpha *= 0.95f;
|
|||
|
} else {
|
|||
|
m_alpha = 0.0f;
|
|||
|
m_maskFrame = 0;
|
|||
|
m_place = 0;
|
|||
|
m_showText = "";
|
|||
|
UpdateTextImage();
|
|||
|
m_fusion = false;
|
|||
|
}
|
|||
|
}
|
|||
|
emit AlphaChanged(m_alpha);
|
|||
|
|
|||
|
update();
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::OnMoveFrame(const QImage& movieImage) {
|
|||
|
videoForeImage_ = movieImage.mirrored();
|
|||
|
}
|
|||
|
|
|||
|
//void DisplayMovieGLWidget::LoadBackgroundTexture() {
|
|||
|
// if (m_textureData.count() >= m_backgroundFrameCount) {
|
|||
|
// return;
|
|||
|
// }
|
|||
|
//
|
|||
|
// QImageReader reader;
|
|||
|
// reader.setAutoTransform(true);
|
|||
|
//
|
|||
|
// reader.setFileName(m_backgourndTexturePaths[m_backgroundCurrentFrame]);
|
|||
|
// QImage image = reader.read();
|
|||
|
// image = image.mirrored().convertToFormat(QImage::Format_RGBA8888);
|
|||
|
// m_textureData.emplace_back(std::move(image));
|
|||
|
//}
|
|||
|
|
|||
|
|
|||
|
void DisplayMovieGLWidget::InitBackgroundImages() {
|
|||
|
#ifndef BG_VLC
|
|||
|
const QString imageDir = QApplication::applicationDirPath() + "/ProjectDisplay/background/out";
|
|||
|
QStringList jpgFiles;
|
|||
|
|
|||
|
QDir dir(imageDir);
|
|||
|
QStringList filters;
|
|||
|
filters << "*.jpg"; // 添加 JPG 的文件扩展名
|
|||
|
QFileInfoList fileInfoList = dir.entryInfoList(filters, QDir::Files); // 使用过滤器获取文件列表
|
|||
|
|
|||
|
m_backgroundFrameCount = fileInfoList.size();
|
|||
|
m_textureData.resize(m_backgroundFrameCount);
|
|||
|
|
|||
|
foreach(const QFileInfo & fileInfo, fileInfoList) {
|
|||
|
m_backgourndTexturePaths.append(fileInfo.absoluteFilePath());
|
|||
|
}
|
|||
|
|
|||
|
auto handle = [&](int index, QImage image) {
|
|||
|
image = image.convertToFormat(QImage::Format_RGB888);
|
|||
|
m_textureData[index] = std::move(image);
|
|||
|
};
|
|||
|
|
|||
|
QThreadPool pool;
|
|||
|
pool.setMaxThreadCount(std::thread::hardware_concurrency());
|
|||
|
for (int i = 0; i < m_backgourndTexturePaths.count(); ++i) {
|
|||
|
LoadImageTask* task = new LoadImageTask(i, m_backgourndTexturePaths, handle);
|
|||
|
pool.start(task);
|
|||
|
}
|
|||
|
|
|||
|
pool.waitForDone();
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::LoadMaskTexture() {
|
|||
|
if (m_maskTextureData.count() >= m_maskFrameCount) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
QImageReader reader;
|
|||
|
reader.setAutoTransform(true);
|
|||
|
|
|||
|
reader.setFileName(m_maskTexturePaths[m_maskFrame]);
|
|||
|
|
|||
|
QSize s = size();
|
|||
|
QImage image = reader.read();
|
|||
|
image = image.scaled(s, Qt::KeepAspectRatio);
|
|||
|
m_maskTextureData.emplace_back(std::move(image.mirrored()));
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::InitBackgroundTexture() {
|
|||
|
if (nullptr == m_background) {
|
|||
|
// QPixmap px(m_backgourndTexturePaths[m_backgroundCurrentFrame]);
|
|||
|
m_background = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
m_background->setAutoMipMapGenerationEnabled(false);
|
|||
|
m_background->setSize(3840, 1200);
|
|||
|
m_background->setMipLevels(1);
|
|||
|
#ifndef BG_VLC
|
|||
|
m_background->setFormat(QOpenGLTexture::RGB8_UNorm);
|
|||
|
/*m_background->setMinificationFilter(QOpenGLTexture::Nearest);
|
|||
|
m_background->setMagnificationFilter(QOpenGLTexture::Nearest);
|
|||
|
m_background->allocateStorage();*/
|
|||
|
|
|||
|
m_background->allocateStorage(QOpenGLTexture::RGB, QOpenGLTexture::UInt8);
|
|||
|
#else
|
|||
|
m_background->setFormat(QOpenGLTexture::RGBA8_UNorm);
|
|||
|
/*m_background->setMinificationFilter(QOpenGLTexture::Nearest);
|
|||
|
m_background->setMagnificationFilter(QOpenGLTexture::Nearest);
|
|||
|
m_background->allocateStorage();*/
|
|||
|
|
|||
|
m_background->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
|
|||
|
#endif
|
|||
|
//// 设置纹理环绕方式
|
|||
|
m_background->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
|
|||
|
m_background->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
|
|||
|
// 设置多级渐远纹理过滤方式
|
|||
|
//m_background->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
|
|||
|
}
|
|||
|
if (nullptr == m_backgroundMask) {
|
|||
|
m_backgroundMask = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
m_backgroundMask->setAutoMipMapGenerationEnabled(false);
|
|||
|
m_backgroundMask->setFormat(QOpenGLTexture::RGBA8_UNorm);
|
|||
|
m_backgroundMask->setSize(3840, 1200);
|
|||
|
m_backgroundMask->setMipLevels(1);
|
|||
|
m_backgroundMask->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
|
|||
|
m_backgroundMask->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
|
|||
|
m_backgroundMask->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
|
|||
|
|
|||
|
QImageReader reader;
|
|||
|
reader.setAutoTransform(true);
|
|||
|
|
|||
|
const QString filePath = QCoreApplication::applicationDirPath() + "/ProjectDisplay/background/bg.png";
|
|||
|
reader.setFileName(filePath);
|
|||
|
QImage image = reader.read();
|
|||
|
|
|||
|
QImage dest(3840, 1200, QImage::Format_RGBA8888);
|
|||
|
dest.fill(0);
|
|||
|
QPainter painter(&dest);
|
|||
|
painter.drawImage(0, 0, image);
|
|||
|
painter.end();
|
|||
|
|
|||
|
dest.mirror();
|
|||
|
|
|||
|
QOpenGLPixelTransferOptions uploadOptions;
|
|||
|
uploadOptions.setAlignment(1);
|
|||
|
m_backgroundMask->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, dest.constBits(), &uploadOptions);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::InitMaskTexture() {
|
|||
|
if (nullptr == m_mask) {
|
|||
|
QImageReader reader;
|
|||
|
reader.setAutoTransform(true);
|
|||
|
|
|||
|
reader.setFileName(m_maskTexturePaths[m_maskFrame]);
|
|||
|
QImage image = reader.read();
|
|||
|
m_mask = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
m_mask->setAutoMipMapGenerationEnabled(false);
|
|||
|
m_mask->setFormat(QOpenGLTexture::RGBA8_UNorm);
|
|||
|
int with = image.width();
|
|||
|
int height = image.height();
|
|||
|
m_mask->setSize(with, height);
|
|||
|
m_mask->setMipLevels(1);
|
|||
|
m_mask->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
|
|||
|
/*m_mask = new QOpenGLTexture(image.mirrored());
|
|||
|
m_mask->setAutoMipMapGenerationEnabled(false);*/
|
|||
|
// 设置纹理环绕方式
|
|||
|
m_mask->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
|
|||
|
m_mask->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::UpdateSourceImage(const QString& path) {
|
|||
|
|
|||
|
if (path.isEmpty()) {
|
|||
|
qWarning() << "DisplayMovieGLWidget::UpdateSourceImage source path is empty";
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
const QSize s = size();
|
|||
|
if (nullptr == m_source) {
|
|||
|
makeCurrent();
|
|||
|
m_source = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
m_source->setAutoMipMapGenerationEnabled(false);
|
|||
|
m_source->setFormat(QOpenGLTexture::RGBA8_UNorm);
|
|||
|
m_source->setSize(s.width(), s.height());
|
|||
|
m_source->setMipLevels(1);
|
|||
|
m_source->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
|
|||
|
// 设置纹理环绕方式
|
|||
|
m_source->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
|
|||
|
m_source->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
|
|||
|
}
|
|||
|
|
|||
|
if (nullptr == m_sourceAlpha) {
|
|||
|
makeCurrent();
|
|||
|
m_sourceAlpha = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
m_sourceAlpha->setAutoMipMapGenerationEnabled(false);
|
|||
|
m_sourceAlpha->setFormat(QOpenGLTexture::RGBA8_UNorm);
|
|||
|
m_sourceAlpha->setSize(s.width(), s.height());
|
|||
|
m_sourceAlpha->setMipLevels(1);
|
|||
|
m_sourceAlpha->allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8);
|
|||
|
// 设置纹理环绕方式
|
|||
|
m_sourceAlpha->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
|
|||
|
m_sourceAlpha->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
|
|||
|
}
|
|||
|
;
|
|||
|
SourImasgeHandler* handler = new SourImasgeHandler(path, s);
|
|||
|
connect(handler, &SourImasgeHandler::Finish, this, &DisplayMovieGLWidget::OnUpdateSourceImage, Qt::QueuedConnection);
|
|||
|
QThreadPool::globalInstance()->start(handler);
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::UpdateTextImage() {
|
|||
|
makeCurrent();
|
|||
|
const QSize s = size();
|
|||
|
QImage dest(s.width(), s.height(), QImage::Format_RGB888);
|
|||
|
dest.fill(Qt::transparent);
|
|||
|
QPainter painter(&dest);
|
|||
|
|
|||
|
//const QStringList& fontFamilies = MainWindow::Get().GetDefaultFontFamily();
|
|||
|
//QFont font(fontFamilies[0], 30, QFont::Black);
|
|||
|
QFont font("Microsoft YaHei", 30, QFont::Bold);
|
|||
|
painter.setPen(QColor(255, 255, 255));
|
|||
|
painter.setFont(font);
|
|||
|
QFontMetrics fm(font);
|
|||
|
const QSize textSize = fm.size(Qt::TextWordWrap, m_showText);
|
|||
|
QTextOption textOption(Qt::AlignHCenter);
|
|||
|
textOption.setWrapMode(QTextOption::NoWrap);
|
|||
|
painter.drawText(MainWindow::Get().GetTextRect(), m_showText, textOption);
|
|||
|
|
|||
|
|
|||
|
painter.end();
|
|||
|
|
|||
|
QImage image = dest.mirrored();
|
|||
|
if (nullptr == m_textSource) {
|
|||
|
//m_textSource = new QOpenGLTexture(image);
|
|||
|
m_textSource = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
m_textSource->setAutoMipMapGenerationEnabled(false);
|
|||
|
m_textSource->setFormat(QOpenGLTexture::RGB8_UNorm);
|
|||
|
m_textSource->setSize(image.width(), image.height());
|
|||
|
m_textSource->setMipLevels(1);
|
|||
|
m_textSource->allocateStorage(QOpenGLTexture::RGB, QOpenGLTexture::UInt8);
|
|||
|
// 设置纹理环绕方式
|
|||
|
m_textSource->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
|
|||
|
m_textSource->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
|
|||
|
}
|
|||
|
QOpenGLPixelTransferOptions uploadOptions;
|
|||
|
uploadOptions.setAlignment(1);
|
|||
|
m_textSource->setData(0, QOpenGLTexture::RGB, QOpenGLTexture::UInt8, image.constBits(), &uploadOptions);
|
|||
|
//m_textSource->setData(dest.mirrored());
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::InitForeMovieTextImage() {
|
|||
|
makeCurrent();
|
|||
|
QImage dest(3240, 1200, QImage::Format_RGBA8888);
|
|||
|
dest.fill(Qt::transparent);
|
|||
|
|
|||
|
videoForeImage_ = dest.mirrored();
|
|||
|
if (nullptr == m_movieSource) {
|
|||
|
//m_textSource = new QOpenGLTexture(image);
|
|||
|
m_movieSource = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
m_movieSource->setAutoMipMapGenerationEnabled(false);
|
|||
|
m_movieSource->setFormat(QOpenGLTexture::RGBA8_UNorm);
|
|||
|
m_movieSource->setSize(dest.width(), dest.height());
|
|||
|
m_movieSource->setMipLevels(1);
|
|||
|
m_movieSource->allocateStorage(QOpenGLTexture::RGB, QOpenGLTexture::UInt8);
|
|||
|
// 设置纹理环绕方式
|
|||
|
m_movieSource->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
|
|||
|
m_movieSource->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
|
|||
|
}
|
|||
|
QOpenGLPixelTransferOptions uploadOptions;
|
|||
|
uploadOptions.setAlignment(1);
|
|||
|
m_movieSource->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, videoForeImage_.constBits(), &uploadOptions);
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::PlayBackgroundMovie() {
|
|||
|
#ifdef BG_VLC
|
|||
|
videoImage_ = QImage(3840, 1200, QImage::Format_RGBA8888);
|
|||
|
connect(&vlcPlayer_, &VlcMediaListPlayer::VideoDataOutput, this, &DisplayMovieGLWidget::SlotSetOneFrame, Qt::QueuedConnection);
|
|||
|
|
|||
|
vlcPlayer_.SetPlayMode(VlcMediaListPlayer::Loop);
|
|||
|
|
|||
|
const QString filePath = QCoreApplication::applicationDirPath() + "/ProjectDisplay/background/bg.mp4";
|
|||
|
QStringList paths;
|
|||
|
paths.append(filePath);
|
|||
|
vlcPlayer_.SetResolution(3840, 1200);
|
|||
|
vlcPlayer_.SetMediaList(paths);
|
|||
|
vlcPlayer_.Play();
|
|||
|
#endif
|
|||
|
}
|
|||
|
void DisplayMovieGLWidget::SlotSetOneFrame(QImage image) {
|
|||
|
#ifdef BG_VLC
|
|||
|
videoImage_ = image.mirrored();
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::OnUpdateSourceImage(QImage source, QImage sourceAlpha) {
|
|||
|
makeCurrent();
|
|||
|
|
|||
|
QOpenGLPixelTransferOptions uploadOptions;
|
|||
|
uploadOptions.setAlignment(1);
|
|||
|
m_source->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, source.constBits(), &uploadOptions);
|
|||
|
m_sourceAlpha->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, sourceAlpha.constBits(), &uploadOptions);
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::LoadBackgroundTexture() {
|
|||
|
#ifndef BG_VLC
|
|||
|
if (m_textureData.count() >= m_backgroundFrameCount) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
QImageReader reader;
|
|||
|
reader.setAutoTransform(true);
|
|||
|
|
|||
|
reader.setFileName(m_backgourndTexturePaths[m_backgroundCurrentFrame]);
|
|||
|
QImage image = reader.read();
|
|||
|
image = image.mirrored().convertToFormat(QImage::Format_RGB888);
|
|||
|
m_textureData.emplace_back(std::move(image));
|
|||
|
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::InitMaskImages() {
|
|||
|
const QString imageDir = QApplication::applicationDirPath() + "/ProjectDisplay/mask";
|
|||
|
|
|||
|
QStringList jpgFiles;
|
|||
|
|
|||
|
QDir dir(imageDir);
|
|||
|
QStringList filters;
|
|||
|
filters << "*.jpg"; // 添加 JPG 的文件扩展名
|
|||
|
QFileInfoList fileInfoList = dir.entryInfoList(filters, QDir::Files); // 使用过滤器获取文件列表
|
|||
|
|
|||
|
m_maskFrameCount = fileInfoList.size();
|
|||
|
m_maskTextureData.resize(fileInfoList.size());
|
|||
|
|
|||
|
foreach(const QFileInfo & fileInfo, fileInfoList) {
|
|||
|
m_maskTexturePaths.append(fileInfo.absoluteFilePath());
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
auto handle = [&](int index, QImage image) {
|
|||
|
m_maskTextureData[index] = std::move(image);
|
|||
|
};
|
|||
|
|
|||
|
QThreadPool pool;
|
|||
|
pool.setMaxThreadCount(std::thread::hardware_concurrency());
|
|||
|
for (int i = 0; i < m_maskTexturePaths.count(); ++i) {
|
|||
|
LoadImageTask* task = new LoadImageTask(i, m_maskTexturePaths, handle);
|
|||
|
pool.start(task);
|
|||
|
}
|
|||
|
|
|||
|
pool.waitForDone();
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::ReInit() {
|
|||
|
// m_backgroundCurrentFrame = 0;
|
|||
|
m_maskFrame = 0;
|
|||
|
m_colorMaskFrame = 0;
|
|||
|
m_showSource = false;
|
|||
|
|
|||
|
QTimer::singleShot(5000, [this]() {
|
|||
|
m_showSource = true;
|
|||
|
}
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::SetNetConnectStatus(int connected) {
|
|||
|
m_connected = connected;
|
|||
|
//UpdateNetworkTextImage();
|
|||
|
}
|
|||
|
|
|||
|
void DisplayMovieGLWidget::OnMessage(const QString& cmd) {
|
|||
|
// cmd = "0/0/0"
|
|||
|
const QStringList params = cmd.split("|");
|
|||
|
if (params.count() < 3) {
|
|||
|
qWarning() << "invalid cmd:" << cmd;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
int32_t town = params[0].toInt();
|
|||
|
int32_t place = params[1].toInt();
|
|||
|
int32_t image = params[2].toInt();
|
|||
|
|
|||
|
if (/*m_place != place*/true) {
|
|||
|
m_place = place;
|
|||
|
m_maskFrame = 0;
|
|||
|
m_colorMaskFrame = 0;
|
|||
|
m_showSource = false;
|
|||
|
QDateTime dt = QDateTime::currentDateTime();
|
|||
|
m_startTimestamp = dt.toUTC().toMSecsSinceEpoch();
|
|||
|
|
|||
|
|
|||
|
QTimer::singleShot(5000, [this]() {
|
|||
|
m_showSource = true;
|
|||
|
});
|
|||
|
QTimer::singleShot(100, [this]() {
|
|||
|
MainWindow::Get().PlayWav();
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
m_alpha = 0.13f;
|
|||
|
|
|||
|
const QString townName = MainWindow::Get().GetTownName(town);
|
|||
|
const QString placeName = MainWindow::Get().GetPlaceName(town, place);
|
|||
|
const QString imageName = MainWindow::Get().GetImageName(town, place, image);
|
|||
|
/*if (imageName.isEmpty()) {
|
|||
|
qWarning() << "image name is empty";
|
|||
|
return;
|
|||
|
}*/
|
|||
|
|
|||
|
const QString& path = QString("%1/ProjectDisplay/images/%2/%3/%4").arg(QApplication::applicationDirPath(), townName, placeName, imageName);
|
|||
|
UpdateSourceImage(path);
|
|||
|
|
|||
|
m_showText = MainWindow::Get().GetTitleName(town, place);
|
|||
|
|
|||
|
UpdateTextImage();
|
|||
|
m_fusion = true;
|
|||
|
|
|||
|
m_delayTime = MainWindow::Get().GetDelayRetore() * 1000;
|
|||
|
}
|