Add silhouette image generator
parent
86e2075142
commit
52252b70af
|
@ -538,6 +538,9 @@ HEADERS += src/motionbuilder.h
|
|||
SOURCES += src/statusbarlabel.cpp
|
||||
HEADERS += src/statusbarlabel.h
|
||||
|
||||
SOURCES += src/silhouetteimagegenerator.cpp
|
||||
HEADERS += src/silhouetteimagegenerator.h
|
||||
|
||||
SOURCES += src/main.cpp
|
||||
|
||||
HEADERS += src/version.h
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "objectxml.h"
|
||||
#include "rigxml.h"
|
||||
#include "statusbarlabel.h"
|
||||
#include "silhouetteimagegenerator.h"
|
||||
|
||||
int DocumentWindow::m_autoRecovered = false;
|
||||
|
||||
|
@ -80,6 +81,22 @@ const std::map<DocumentWindow *, QUuid> &DocumentWindow::documentWindows()
|
|||
return g_documentWindows;
|
||||
}
|
||||
|
||||
DocumentWindow::GraphicsViewEditTarget DocumentWindow::graphicsViewEditTarget()
|
||||
{
|
||||
return m_graphicsViewEditTarget;
|
||||
}
|
||||
|
||||
void DocumentWindow::updateGraphicsViewEditTarget(GraphicsViewEditTarget target)
|
||||
{
|
||||
if (m_graphicsViewEditTarget == target)
|
||||
return;
|
||||
|
||||
m_graphicsViewEditTarget = target;
|
||||
if (GraphicsViewEditTarget::Bone == m_graphicsViewEditTarget)
|
||||
generateSilhouetteImage();
|
||||
emit graphicsViewEditTargetChanged();
|
||||
}
|
||||
|
||||
Document *DocumentWindow::document()
|
||||
{
|
||||
return m_document;
|
||||
|
@ -520,12 +537,12 @@ DocumentWindow::DocumentWindow() :
|
|||
connect(boneLabel, &StatusBarLabel::clicked, this, [=]() {
|
||||
boneLabel->setSelected(true);
|
||||
shapeLabel->setSelected(false);
|
||||
// TODO:
|
||||
updateGraphicsViewEditTarget(GraphicsViewEditTarget::Bone);
|
||||
});
|
||||
connect(shapeLabel, &StatusBarLabel::clicked, this, [=]() {
|
||||
shapeLabel->setSelected(true);
|
||||
boneLabel->setSelected(false);
|
||||
// TODO:
|
||||
updateGraphicsViewEditTarget(GraphicsViewEditTarget::Shape);
|
||||
});
|
||||
|
||||
/////////////////////// Status Bar End ////////////////////////////
|
||||
|
@ -1354,6 +1371,9 @@ DocumentWindow::DocumentWindow() :
|
|||
connect(m_document, &Document::scriptChanged, m_document, &Document::runScript);
|
||||
connect(m_document, &Document::scriptModifiedFromExternal, m_document, &Document::runScript);
|
||||
|
||||
connect(m_document, &Document::skeletonChanged, this, &DocumentWindow::generateSilhouetteImage);
|
||||
connect(m_graphicsWidget, &SkeletonGraphicsWidget::loadedTurnaroundImageChanged, this, &DocumentWindow::generateSilhouetteImage);
|
||||
|
||||
initShortCuts(this, m_graphicsWidget);
|
||||
|
||||
connect(this, &DocumentWindow::initialized, m_document, &Document::uiReady);
|
||||
|
@ -2634,3 +2654,47 @@ ModelWidget *DocumentWindow::modelWidget()
|
|||
{
|
||||
return m_modelRenderWidget;
|
||||
}
|
||||
|
||||
void DocumentWindow::generateSilhouetteImage()
|
||||
{
|
||||
if (GraphicsViewEditTarget::Bone != m_graphicsViewEditTarget ||
|
||||
nullptr != m_silhouetteImageGenerator) {
|
||||
m_isSilhouetteImageObsolete = true;
|
||||
return;
|
||||
}
|
||||
|
||||
m_isSilhouetteImageObsolete = false;
|
||||
|
||||
const QImage *loadedTurnaroundImage = m_graphicsWidget->loadedTurnaroundImage();
|
||||
if (nullptr == loadedTurnaroundImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
QThread *thread = new QThread;
|
||||
|
||||
Snapshot *snapshot = new Snapshot;
|
||||
m_document->toSnapshot(snapshot);
|
||||
|
||||
m_silhouetteImageGenerator = new SilhouetteImageGenerator(loadedTurnaroundImage->width(),
|
||||
loadedTurnaroundImage->height(), snapshot);
|
||||
m_silhouetteImageGenerator->moveToThread(thread);
|
||||
connect(thread, &QThread::started, m_silhouetteImageGenerator, &SilhouetteImageGenerator::process);
|
||||
connect(m_silhouetteImageGenerator, &SilhouetteImageGenerator::finished, this, &DocumentWindow::silhouetteImageReady);
|
||||
connect(m_silhouetteImageGenerator, &SilhouetteImageGenerator::finished, thread, &QThread::quit);
|
||||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void DocumentWindow::silhouetteImageReady()
|
||||
{
|
||||
QImage *image = m_silhouetteImageGenerator->takeResultImage();
|
||||
if (nullptr != image)
|
||||
image->save("test.png");
|
||||
delete image;
|
||||
|
||||
delete m_silhouetteImageGenerator;
|
||||
m_silhouetteImageGenerator = nullptr;
|
||||
|
||||
if (m_isSilhouetteImageObsolete)
|
||||
generateSilhouetteImage();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
class SkeletonGraphicsWidget;
|
||||
class PartTreeWidget;
|
||||
class SpinnableAwesomeButton;
|
||||
class SilhouetteImageGenerator;
|
||||
|
||||
class DocumentWindow : public QMainWindow
|
||||
{
|
||||
|
@ -33,11 +34,19 @@ signals:
|
|||
void uninialized();
|
||||
void waitingExportFinished(const QString &filename, bool isSuccessful);
|
||||
void mouseTargetVertexPositionChanged(const QVector3D &position);
|
||||
void graphicsViewEditTargetChanged();
|
||||
public:
|
||||
enum class GraphicsViewEditTarget
|
||||
{
|
||||
Shape,
|
||||
Bone
|
||||
};
|
||||
|
||||
DocumentWindow();
|
||||
~DocumentWindow();
|
||||
Document *document();
|
||||
ModelWidget *modelWidget();
|
||||
GraphicsViewEditTarget graphicsViewEditTarget();
|
||||
static DocumentWindow *createDocumentWindow();
|
||||
static const std::map<DocumentWindow *, QUuid> &documentWindows();
|
||||
static void showAcknowlegements();
|
||||
|
@ -105,6 +114,9 @@ public slots:
|
|||
void generatePartPreviewImages();
|
||||
void partPreviewImagesReady();
|
||||
void updateRegenerateIcon();
|
||||
void updateGraphicsViewEditTarget(GraphicsViewEditTarget target);
|
||||
void generateSilhouetteImage();
|
||||
void silhouetteImageReady();
|
||||
private:
|
||||
void initLockButton(QPushButton *button);
|
||||
void setCurrentFilename(const QString &filename);
|
||||
|
@ -242,6 +254,10 @@ private:
|
|||
SpinnableAwesomeButton *m_regenerateButton = nullptr;
|
||||
|
||||
QWidget *m_paintWidget = nullptr;
|
||||
|
||||
GraphicsViewEditTarget m_graphicsViewEditTarget = GraphicsViewEditTarget::Shape;
|
||||
bool m_isSilhouetteImageObsolete = false;
|
||||
SilhouetteImageGenerator *m_silhouetteImageGenerator = nullptr;
|
||||
public:
|
||||
static int m_autoRecovered;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
#include <QPainter>
|
||||
#include <QBrush>
|
||||
#include "silhouetteimagegenerator.h"
|
||||
#include "util.h"
|
||||
|
||||
SilhouetteImageGenerator::SilhouetteImageGenerator(int width, int height, Snapshot *snapshot) :
|
||||
m_width(width),
|
||||
m_height(height),
|
||||
m_snapshot(snapshot)
|
||||
{
|
||||
}
|
||||
|
||||
SilhouetteImageGenerator::~SilhouetteImageGenerator()
|
||||
{
|
||||
delete m_snapshot;
|
||||
delete m_resultImage;
|
||||
}
|
||||
|
||||
QImage *SilhouetteImageGenerator::takeResultImage()
|
||||
{
|
||||
QImage *resultImage = m_resultImage;
|
||||
m_resultImage = nullptr;
|
||||
return resultImage;
|
||||
}
|
||||
|
||||
void SilhouetteImageGenerator::generate()
|
||||
{
|
||||
if (m_width <= 0 || m_height <= 0 || nullptr == m_snapshot)
|
||||
return;
|
||||
|
||||
//float originX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originX").toFloat();
|
||||
//float originY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat();
|
||||
//float originZ = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat();
|
||||
|
||||
delete m_resultImage;
|
||||
m_resultImage = new QImage(m_width, m_height, QImage::Format_ARGB32);
|
||||
m_resultImage->fill(QColor(0xE1, 0xD2, 0xBD));
|
||||
|
||||
struct NodeInfo
|
||||
{
|
||||
QVector3D position;
|
||||
float radius;
|
||||
};
|
||||
|
||||
std::map<QString, NodeInfo> nodePositionMap;
|
||||
for (const auto &node: m_snapshot->nodes) {
|
||||
NodeInfo nodeInfo;
|
||||
nodeInfo.position = QVector3D(valueOfKeyInMapOrEmpty(node.second, "x").toFloat(),
|
||||
valueOfKeyInMapOrEmpty(node.second, "y").toFloat(),
|
||||
valueOfKeyInMapOrEmpty(node.second, "z").toFloat());
|
||||
nodeInfo.radius = valueOfKeyInMapOrEmpty(node.second, "radius").toFloat();
|
||||
nodePositionMap.insert({node.first, nodeInfo});
|
||||
}
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(m_resultImage);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
|
||||
QBrush brush;
|
||||
brush.setColor(QColor(0x88, 0x80, 0x73));
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
|
||||
painter.setBrush(brush);
|
||||
|
||||
for (const auto &it: nodePositionMap) {
|
||||
const auto &nodeInfo = it.second;
|
||||
|
||||
painter.drawEllipse((nodeInfo.position.x() - nodeInfo.radius) * m_height,
|
||||
(nodeInfo.position.y() - nodeInfo.radius) * m_height,
|
||||
nodeInfo.radius * m_height * 2.0,
|
||||
nodeInfo.radius * m_height * 2.0);
|
||||
|
||||
painter.drawEllipse((nodeInfo.position.z() - nodeInfo.radius) * m_height,
|
||||
(nodeInfo.position.y() - nodeInfo.radius) * m_height,
|
||||
nodeInfo.radius * m_height * 2.0,
|
||||
nodeInfo.radius * m_height * 2.0);
|
||||
}
|
||||
|
||||
for (int round = 0; round < 2; ++round) {
|
||||
if (1 == round)
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Multiply);
|
||||
for (const auto &edge: m_snapshot->edges) {
|
||||
QString partId = valueOfKeyInMapOrEmpty(edge.second, "partId");
|
||||
QString fromNodeId = valueOfKeyInMapOrEmpty(edge.second, "from");
|
||||
QString toNodeId = valueOfKeyInMapOrEmpty(edge.second, "to");
|
||||
const auto &fromNodeInfo = nodePositionMap[fromNodeId];
|
||||
const auto &toNodeInfo = nodePositionMap[toNodeId];
|
||||
|
||||
{
|
||||
QVector3D pointerOut = QVector3D(0.0, 0.0, 1.0);
|
||||
QVector3D direction = (QVector3D(toNodeInfo.position.x(), toNodeInfo.position.y(), 0.0) -
|
||||
QVector3D(fromNodeInfo.position.x(), fromNodeInfo.position.y(), 0.0)).normalized();
|
||||
QVector3D fromBaseDirection = QVector3D::crossProduct(pointerOut, direction);
|
||||
QVector3D fromBaseRadius = fromBaseDirection * fromNodeInfo.radius;
|
||||
QVector3D fromBaseFirstPoint = QVector3D(fromNodeInfo.position.x(), fromNodeInfo.position.y(), 0.0) - fromBaseRadius;
|
||||
QVector3D fromBaseSecondPoint = QVector3D(fromNodeInfo.position.x(), fromNodeInfo.position.y(), 0.0) + fromBaseRadius;
|
||||
QVector3D tobaseDirection = -fromBaseDirection;
|
||||
QVector3D toBaseRadius = tobaseDirection * toNodeInfo.radius;
|
||||
QVector3D toBaseFirstPoint = QVector3D(toNodeInfo.position.x(), toNodeInfo.position.y(), 0.0) - toBaseRadius;
|
||||
QVector3D toBaseSecondPoint = QVector3D(toNodeInfo.position.x(), toNodeInfo.position.y(), 0.0) + toBaseRadius;
|
||||
QPolygon polygon;
|
||||
polygon.append(QPoint(fromBaseFirstPoint.x() * m_height, fromBaseFirstPoint.y() * m_height));
|
||||
polygon.append(QPoint(fromBaseSecondPoint.x() * m_height, fromBaseSecondPoint.y() * m_height));
|
||||
polygon.append(QPoint(toBaseFirstPoint.x() * m_height, toBaseFirstPoint.y() * m_height));
|
||||
polygon.append(QPoint(toBaseSecondPoint.x() * m_height, toBaseSecondPoint.y() * m_height));
|
||||
QPainterPath path;
|
||||
path.addPolygon(polygon);
|
||||
painter.fillPath(path, brush);
|
||||
}
|
||||
|
||||
{
|
||||
QVector3D pointerOut = QVector3D(0.0, 0.0, 1.0);
|
||||
QVector3D direction = (QVector3D(toNodeInfo.position.z(), toNodeInfo.position.y(), 0.0) -
|
||||
QVector3D(fromNodeInfo.position.z(), fromNodeInfo.position.y(), 0.0)).normalized();
|
||||
QVector3D fromBaseDirection = QVector3D::crossProduct(pointerOut, direction);
|
||||
QVector3D fromBaseRadius = fromBaseDirection * fromNodeInfo.radius;
|
||||
QVector3D fromBaseFirstPoint = QVector3D(fromNodeInfo.position.z(), fromNodeInfo.position.y(), 0.0) - fromBaseRadius;
|
||||
QVector3D fromBaseSecondPoint = QVector3D(fromNodeInfo.position.z(), fromNodeInfo.position.y(), 0.0) + fromBaseRadius;
|
||||
QVector3D tobaseDirection = -fromBaseDirection;
|
||||
QVector3D toBaseRadius = tobaseDirection * toNodeInfo.radius;
|
||||
QVector3D toBaseFirstPoint = QVector3D(toNodeInfo.position.z(), toNodeInfo.position.y(), 0.0) - toBaseRadius;
|
||||
QVector3D toBaseSecondPoint = QVector3D(toNodeInfo.position.z(), toNodeInfo.position.y(), 0.0) + toBaseRadius;
|
||||
QPolygon polygon;
|
||||
polygon.append(QPoint(fromBaseFirstPoint.x() * m_height, fromBaseFirstPoint.y() * m_height));
|
||||
polygon.append(QPoint(fromBaseSecondPoint.x() * m_height, fromBaseSecondPoint.y() * m_height));
|
||||
polygon.append(QPoint(toBaseFirstPoint.x() * m_height, toBaseFirstPoint.y() * m_height));
|
||||
polygon.append(QPoint(toBaseSecondPoint.x() * m_height, toBaseSecondPoint.y() * m_height));
|
||||
QPainterPath path;
|
||||
path.addPolygon(polygon);
|
||||
painter.fillPath(path, brush);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
painter.end();
|
||||
}
|
||||
|
||||
void SilhouetteImageGenerator::process()
|
||||
{
|
||||
generate();
|
||||
|
||||
emit finished();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef DUST3D_SILHOUETTE_IMAGE_GENERATOR_H
|
||||
#define DUST3D_SILHOUETTE_IMAGE_GENERATOR_H
|
||||
#include <QObject>
|
||||
#include <QImage>
|
||||
#include "snapshot.h"
|
||||
|
||||
class SilhouetteImageGenerator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SilhouetteImageGenerator(int width, int height, Snapshot *snapshot);
|
||||
~SilhouetteImageGenerator();
|
||||
QImage *takeResultImage();
|
||||
void generate();
|
||||
signals:
|
||||
void finished();
|
||||
public slots:
|
||||
void process();
|
||||
private:
|
||||
int m_width = 0;
|
||||
int m_height = 0;
|
||||
QImage *m_resultImage = nullptr;
|
||||
Snapshot *m_snapshot = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -761,11 +761,18 @@ void SkeletonGraphicsWidget::turnaroundImageReady()
|
|||
delete m_turnaroundLoader;
|
||||
m_turnaroundLoader = nullptr;
|
||||
|
||||
emit loadedTurnaroundImageChanged();
|
||||
|
||||
if (m_turnaroundChanged) {
|
||||
updateTurnaround();
|
||||
}
|
||||
}
|
||||
|
||||
const QImage *SkeletonGraphicsWidget::loadedTurnaroundImage() const
|
||||
{
|
||||
return m_backgroundImage;
|
||||
}
|
||||
|
||||
void SkeletonGraphicsWidget::updateCursor()
|
||||
{
|
||||
if (SkeletonDocumentEditMode::Add != m_document->editMode) {
|
||||
|
|
|
@ -516,6 +516,7 @@ signals:
|
|||
void shortcutToggleRotation();
|
||||
void createGriddedPartsFromNodes(const std::set<QUuid> &nodeIds);
|
||||
void addPartByPolygons(const QPolygonF &mainProfile, const QPolygonF &sideProfile, const QSizeF &canvasSize);
|
||||
void loadedTurnaroundImageChanged();
|
||||
public:
|
||||
SkeletonGraphicsWidget(const SkeletonDocument *document);
|
||||
std::map<QUuid, std::pair<SkeletonGraphicsNodeItem *, SkeletonGraphicsNodeItem *>> nodeItemMap;
|
||||
|
@ -547,6 +548,7 @@ public:
|
|||
void setMainProfileOnly(bool mainProfileOnly);
|
||||
bool inputWheelEventFromOtherWidget(QWheelEvent *event);
|
||||
bool rotated();
|
||||
const QImage *loadedTurnaroundImage() const;
|
||||
protected:
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
|
|
Loading…
Reference in New Issue