culturered_client/ProjectorDisplay/DisplayMovieGLWidget.cpp
2024-09-07 11:34:44 +08:00

839 lines
28 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
// 顶点属性默认是禁用的启用顶点属性0location=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;
}