tidy&format(all): all files formatted and relevant warnings resolved
C++ / build (pull_request) Failing after 15s
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 28s
Python / lint-format (pull_request) Successful in 45s
Python / test (pull_request) Successful in 38s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m45s
C++ / build (pull_request) Failing after 15s
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 28s
Python / lint-format (pull_request) Successful in 45s
Python / test (pull_request) Successful in 38s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m45s
This commit is contained in:
@@ -2,9 +2,7 @@
|
||||
#include "blobinvertedrect.hpp"
|
||||
#include "blobshape.hpp"
|
||||
|
||||
BlobGroup::BlobGroup(QObject* parent)
|
||||
: QObject(parent) {
|
||||
}
|
||||
BlobGroup::BlobGroup(QObject* parent) : QObject(parent) {}
|
||||
|
||||
BlobGroup::~BlobGroup() {
|
||||
for (auto* shape : std::as_const(m_shapes))
|
||||
@@ -14,24 +12,21 @@ BlobGroup::~BlobGroup() {
|
||||
}
|
||||
|
||||
void BlobGroup::setSmoothing(qreal s) {
|
||||
if (qFuzzyCompare(m_smoothing, s))
|
||||
return;
|
||||
if (qFuzzyCompare(m_smoothing, s)) return;
|
||||
m_smoothing = s;
|
||||
emit smoothingChanged();
|
||||
markDirty();
|
||||
}
|
||||
|
||||
void BlobGroup::setColor(const QColor& c) {
|
||||
if (m_color == c)
|
||||
return;
|
||||
if (m_color == c) return;
|
||||
m_color = c;
|
||||
emit colorChanged();
|
||||
markDirty();
|
||||
}
|
||||
|
||||
void BlobGroup::addShape(BlobShape* shape) {
|
||||
if (!shape || m_shapes.contains(shape))
|
||||
return;
|
||||
if (!shape || m_shapes.contains(shape)) return;
|
||||
m_shapes.append(shape);
|
||||
markDirty();
|
||||
}
|
||||
@@ -42,15 +37,13 @@ void BlobGroup::removeShape(BlobShape* shape) {
|
||||
}
|
||||
|
||||
void BlobGroup::setInvertedRect(BlobInvertedRect* rect) {
|
||||
if (m_invertedRect == rect)
|
||||
return;
|
||||
if (m_invertedRect == rect) return;
|
||||
m_invertedRect = rect;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
void BlobGroup::clearInvertedRect(BlobInvertedRect* rect) {
|
||||
if (m_invertedRect != rect)
|
||||
return;
|
||||
if (m_invertedRect != rect) return;
|
||||
m_invertedRect = nullptr;
|
||||
markDirty();
|
||||
}
|
||||
@@ -75,15 +68,19 @@ void BlobGroup::markShapeDirty(BlobShape* source) {
|
||||
|
||||
// Use cached padded rects to find spatial neighbors
|
||||
const float pad = static_cast<float>(m_smoothing) * 2.0f;
|
||||
const QRectF srcRect(static_cast<double>(source->m_cachedPaddedX - pad),
|
||||
static_cast<double>(source->m_cachedPaddedY - pad), static_cast<double>(source->m_cachedPaddedW + pad * 2.0f),
|
||||
static_cast<double>(source->m_cachedPaddedH + pad * 2.0f));
|
||||
const QRectF srcRect(
|
||||
static_cast<double>(source->m_cachedPaddedX - pad),
|
||||
static_cast<double>(source->m_cachedPaddedY - pad),
|
||||
static_cast<double>(source->m_cachedPaddedW + pad * 2.0f),
|
||||
static_cast<double>(source->m_cachedPaddedH + pad * 2.0f));
|
||||
|
||||
for (auto* shape : std::as_const(m_shapes)) {
|
||||
if (shape == source)
|
||||
continue;
|
||||
const QRectF otherRect(static_cast<double>(shape->m_cachedPaddedX), static_cast<double>(shape->m_cachedPaddedY),
|
||||
static_cast<double>(shape->m_cachedPaddedW), static_cast<double>(shape->m_cachedPaddedH));
|
||||
if (shape == source) continue;
|
||||
const QRectF otherRect(
|
||||
static_cast<double>(shape->m_cachedPaddedX),
|
||||
static_cast<double>(shape->m_cachedPaddedY),
|
||||
static_cast<double>(shape->m_cachedPaddedW),
|
||||
static_cast<double>(shape->m_cachedPaddedH));
|
||||
if (srcRect.intersects(otherRect)) {
|
||||
shape->polish();
|
||||
shape->update();
|
||||
@@ -97,8 +94,7 @@ void BlobGroup::markShapeDirty(BlobShape* source) {
|
||||
}
|
||||
|
||||
void BlobGroup::ensurePhysicsUpdated() {
|
||||
if (m_physicsUpdated)
|
||||
return;
|
||||
if (m_physicsUpdated) return;
|
||||
m_physicsUpdated = true;
|
||||
for (auto* shape : std::as_const(m_shapes))
|
||||
shape->updatePhysics();
|
||||
|
||||
@@ -9,53 +9,49 @@ class BlobShape;
|
||||
class BlobInvertedRect;
|
||||
|
||||
class BlobGroup : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_PROPERTY(qreal smoothing READ smoothing WRITE setSmoothing NOTIFY smoothingChanged)
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_PROPERTY(
|
||||
qreal smoothing READ smoothing WRITE setSmoothing NOTIFY
|
||||
smoothingChanged)
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
|
||||
|
||||
public:
|
||||
explicit BlobGroup(QObject* parent = nullptr);
|
||||
~BlobGroup() override;
|
||||
public:
|
||||
explicit BlobGroup(QObject* parent = nullptr);
|
||||
~BlobGroup() override;
|
||||
|
||||
[[nodiscard]] qreal smoothing() const {
|
||||
return m_smoothing;
|
||||
}
|
||||
[[nodiscard]] qreal smoothing() const { return m_smoothing; }
|
||||
|
||||
void setSmoothing(qreal s);
|
||||
void setSmoothing(qreal s);
|
||||
|
||||
[[nodiscard]] QColor color() const {
|
||||
return m_color;
|
||||
}
|
||||
[[nodiscard]] QColor color() const { return m_color; }
|
||||
|
||||
void setColor(const QColor& c);
|
||||
void setColor(const QColor& c);
|
||||
|
||||
void addShape(BlobShape* shape);
|
||||
void removeShape(BlobShape* shape);
|
||||
void addShape(BlobShape* shape);
|
||||
void removeShape(BlobShape* shape);
|
||||
|
||||
void setInvertedRect(BlobInvertedRect* rect);
|
||||
void clearInvertedRect(BlobInvertedRect* rect);
|
||||
void setInvertedRect(BlobInvertedRect* rect);
|
||||
void clearInvertedRect(BlobInvertedRect* rect);
|
||||
|
||||
[[nodiscard]] const QList<BlobShape*>& shapes() const {
|
||||
return m_shapes;
|
||||
}
|
||||
[[nodiscard]] const QList<BlobShape*>& shapes() const { return m_shapes; }
|
||||
|
||||
[[nodiscard]] BlobInvertedRect* invertedRect() const {
|
||||
return m_invertedRect;
|
||||
}
|
||||
[[nodiscard]] BlobInvertedRect* invertedRect() const {
|
||||
return m_invertedRect;
|
||||
}
|
||||
|
||||
void markDirty();
|
||||
void markShapeDirty(BlobShape* source);
|
||||
void ensurePhysicsUpdated();
|
||||
void markDirty();
|
||||
void markShapeDirty(BlobShape* source);
|
||||
void ensurePhysicsUpdated();
|
||||
|
||||
signals:
|
||||
void smoothingChanged();
|
||||
void colorChanged();
|
||||
signals:
|
||||
void smoothingChanged();
|
||||
void colorChanged();
|
||||
|
||||
private:
|
||||
qreal m_smoothing = 32.0;
|
||||
QColor m_color{ 0x44, 0x88, 0xff };
|
||||
QList<BlobShape*> m_shapes;
|
||||
BlobInvertedRect* m_invertedRect = nullptr;
|
||||
bool m_physicsUpdated = false;
|
||||
private:
|
||||
qreal m_smoothing = 32.0;
|
||||
QColor m_color{0x44, 0x88, 0xff};
|
||||
QList<BlobShape*> m_shapes;
|
||||
BlobInvertedRect* m_invertedRect = nullptr;
|
||||
bool m_physicsUpdated = false;
|
||||
};
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
#include <qsggeometry.h>
|
||||
#include <qsgnode.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
BlobInvertedRect::BlobInvertedRect(QQuickItem* parent)
|
||||
: BlobShape(parent) {
|
||||
}
|
||||
BlobInvertedRect::BlobInvertedRect(QQuickItem* parent) : BlobShape(parent) {}
|
||||
|
||||
static void setFrameIndices(quint16* idx) {
|
||||
// Top strip: 0-1-4, 1-5-4
|
||||
@@ -43,7 +40,8 @@ static void setFrameIndices(quint16* idx) {
|
||||
idx[23] = 7;
|
||||
}
|
||||
|
||||
QSGNode* BlobInvertedRect::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) {
|
||||
QSGNode* BlobInvertedRect::updatePaintNode(
|
||||
QSGNode* oldNode, UpdatePaintNodeData*) {
|
||||
if (!m_group) {
|
||||
delete oldNode;
|
||||
return nullptr;
|
||||
@@ -71,8 +69,11 @@ QSGNode* BlobInvertedRect::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData
|
||||
delete oldNode;
|
||||
node = new QSGGeometryNode;
|
||||
|
||||
auto* geometry =
|
||||
new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 8, 24, QSGGeometry::UnsignedShortType);
|
||||
auto* geometry = new QSGGeometry(
|
||||
QSGGeometry::defaultAttributes_TexturedPoint2D(),
|
||||
8,
|
||||
24,
|
||||
QSGGeometry::UnsignedShortType);
|
||||
geometry->setDrawingMode(QSGGeometry::DrawTriangles);
|
||||
node->setGeometry(geometry);
|
||||
node->setFlag(QSGNode::OwnsGeometry);
|
||||
@@ -120,10 +121,17 @@ QSGNode* BlobInvertedRect::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData
|
||||
material->m_color = m_group->color();
|
||||
material->m_hasInverted = m_cachedHasInverted ? 1 : 0;
|
||||
material->m_invertedRadius = m_cachedInvertedRadius;
|
||||
memcpy(material->m_invertedOuter, m_cachedInvertedOuter, sizeof(m_cachedInvertedOuter));
|
||||
memcpy(material->m_invertedInner, m_cachedInvertedInner, sizeof(m_cachedInvertedInner));
|
||||
memcpy(
|
||||
material->m_invertedOuter,
|
||||
m_cachedInvertedOuter,
|
||||
sizeof(m_cachedInvertedOuter));
|
||||
memcpy(
|
||||
material->m_invertedInner,
|
||||
m_cachedInvertedInner,
|
||||
sizeof(m_cachedInvertedInner));
|
||||
|
||||
const int count = static_cast<int>(qMin(m_cachedRects.size(), qsizetype(16)));
|
||||
const int count =
|
||||
static_cast<int>(qMin(m_cachedRects.size(), qsizetype(16)));
|
||||
material->m_rectCount = count;
|
||||
for (int i = 0; i < count; ++i)
|
||||
material->m_rects[i] = m_cachedRects[i];
|
||||
@@ -134,52 +142,41 @@ QSGNode* BlobInvertedRect::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData
|
||||
}
|
||||
|
||||
BlobInvertedRect::~BlobInvertedRect() {
|
||||
if (m_group)
|
||||
m_group->clearInvertedRect(this);
|
||||
if (m_group) m_group->clearInvertedRect(this);
|
||||
}
|
||||
|
||||
void BlobInvertedRect::setBorderLeft(qreal v) {
|
||||
if (qFuzzyCompare(m_borderLeft, v))
|
||||
return;
|
||||
if (qFuzzyCompare(m_borderLeft, v)) return;
|
||||
m_borderLeft = v;
|
||||
emit borderLeftChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::setBorderRight(qreal v) {
|
||||
if (qFuzzyCompare(m_borderRight, v))
|
||||
return;
|
||||
if (qFuzzyCompare(m_borderRight, v)) return;
|
||||
m_borderRight = v;
|
||||
emit borderRightChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::setBorderTop(qreal v) {
|
||||
if (qFuzzyCompare(m_borderTop, v))
|
||||
return;
|
||||
if (qFuzzyCompare(m_borderTop, v)) return;
|
||||
m_borderTop = v;
|
||||
emit borderTopChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::setBorderBottom(qreal v) {
|
||||
if (qFuzzyCompare(m_borderBottom, v))
|
||||
return;
|
||||
if (qFuzzyCompare(m_borderBottom, v)) return;
|
||||
m_borderBottom = v;
|
||||
emit borderBottomChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobInvertedRect::registerWithGroup() {
|
||||
if (m_group)
|
||||
m_group->setInvertedRect(this);
|
||||
if (m_group) m_group->setInvertedRect(this);
|
||||
}
|
||||
|
||||
void BlobInvertedRect::unregisterFromGroup() {
|
||||
if (m_group)
|
||||
m_group->clearInvertedRect(this);
|
||||
if (m_group) m_group->clearInvertedRect(this);
|
||||
}
|
||||
|
||||
@@ -5,60 +5,58 @@
|
||||
#include <qqmlengine.h>
|
||||
|
||||
class BlobInvertedRect : public BlobShape {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_PROPERTY(qreal borderLeft READ borderLeft WRITE setBorderLeft NOTIFY borderLeftChanged)
|
||||
Q_PROPERTY(qreal borderRight READ borderRight WRITE setBorderRight NOTIFY borderRightChanged)
|
||||
Q_PROPERTY(qreal borderTop READ borderTop WRITE setBorderTop NOTIFY borderTopChanged)
|
||||
Q_PROPERTY(qreal borderBottom READ borderBottom WRITE setBorderBottom NOTIFY borderBottomChanged)
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_PROPERTY(
|
||||
qreal borderLeft READ borderLeft WRITE setBorderLeft NOTIFY
|
||||
borderLeftChanged)
|
||||
Q_PROPERTY(
|
||||
qreal borderRight READ borderRight WRITE setBorderRight NOTIFY
|
||||
borderRightChanged)
|
||||
Q_PROPERTY(
|
||||
qreal borderTop READ borderTop WRITE setBorderTop NOTIFY
|
||||
borderTopChanged)
|
||||
Q_PROPERTY(
|
||||
qreal borderBottom READ borderBottom WRITE setBorderBottom NOTIFY
|
||||
borderBottomChanged)
|
||||
|
||||
public:
|
||||
explicit BlobInvertedRect(QQuickItem* parent = nullptr);
|
||||
~BlobInvertedRect() override;
|
||||
public:
|
||||
explicit BlobInvertedRect(QQuickItem* parent = nullptr);
|
||||
~BlobInvertedRect() override;
|
||||
|
||||
[[nodiscard]] qreal borderLeft() const {
|
||||
return m_borderLeft;
|
||||
}
|
||||
[[nodiscard]] qreal borderLeft() const { return m_borderLeft; }
|
||||
|
||||
void setBorderLeft(qreal v);
|
||||
void setBorderLeft(qreal v);
|
||||
|
||||
[[nodiscard]] qreal borderRight() const {
|
||||
return m_borderRight;
|
||||
}
|
||||
[[nodiscard]] qreal borderRight() const { return m_borderRight; }
|
||||
|
||||
void setBorderRight(qreal v);
|
||||
void setBorderRight(qreal v);
|
||||
|
||||
[[nodiscard]] qreal borderTop() const {
|
||||
return m_borderTop;
|
||||
}
|
||||
[[nodiscard]] qreal borderTop() const { return m_borderTop; }
|
||||
|
||||
void setBorderTop(qreal v);
|
||||
void setBorderTop(qreal v);
|
||||
|
||||
[[nodiscard]] qreal borderBottom() const {
|
||||
return m_borderBottom;
|
||||
}
|
||||
[[nodiscard]] qreal borderBottom() const { return m_borderBottom; }
|
||||
|
||||
void setBorderBottom(qreal v);
|
||||
void setBorderBottom(qreal v);
|
||||
|
||||
signals:
|
||||
void borderLeftChanged();
|
||||
void borderRightChanged();
|
||||
void borderTopChanged();
|
||||
void borderBottomChanged();
|
||||
signals:
|
||||
void borderLeftChanged();
|
||||
void borderRightChanged();
|
||||
void borderTopChanged();
|
||||
void borderBottomChanged();
|
||||
|
||||
protected:
|
||||
[[nodiscard]] bool isInvertedRect() const override {
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
[[nodiscard]] bool isInvertedRect() const override { return true; }
|
||||
|
||||
QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) override;
|
||||
QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) override;
|
||||
|
||||
void registerWithGroup() override;
|
||||
void unregisterFromGroup() override;
|
||||
void registerWithGroup() override;
|
||||
void unregisterFromGroup() override;
|
||||
|
||||
private:
|
||||
qreal m_borderLeft = 0;
|
||||
qreal m_borderRight = 0;
|
||||
qreal m_borderTop = 0;
|
||||
qreal m_borderBottom = 0;
|
||||
private:
|
||||
qreal m_borderLeft = 0;
|
||||
qreal m_borderRight = 0;
|
||||
qreal m_borderTop = 0;
|
||||
qreal m_borderBottom = 0;
|
||||
};
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
#include "blobmaterial.hpp"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
static_assert(sizeof(decltype(BlobRectData::excludeMask)) == sizeof(float),
|
||||
"BlobMaterial packs excludeMask into a float slot via memcpy");
|
||||
static_assert(
|
||||
sizeof(decltype(BlobRectData::excludeMask)) == sizeof(float),
|
||||
"BlobMaterial packs excludeMask into a float slot via memcpy");
|
||||
|
||||
QSGMaterialType* BlobMaterial::type() const {
|
||||
static QSGMaterialType s_type;
|
||||
return &s_type;
|
||||
}
|
||||
|
||||
QSGMaterialShader* BlobMaterial::createShader(QSGRendererInterface::RenderMode) const {
|
||||
QSGMaterialShader* BlobMaterial::createShader(
|
||||
QSGRendererInterface::RenderMode) const {
|
||||
return new BlobMaterialShader;
|
||||
}
|
||||
|
||||
int BlobMaterial::compare(const QSGMaterial* other) const {
|
||||
if (this < other)
|
||||
return -1;
|
||||
if (this > other)
|
||||
return 1;
|
||||
if (this < other) return -1;
|
||||
if (this > other) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,7 +29,8 @@ BlobMaterialShader::BlobMaterialShader() {
|
||||
setShaderFileName(FragmentStage, QStringLiteral(":/shaders/blob.frag.qsb"));
|
||||
}
|
||||
|
||||
bool BlobMaterialShader::updateUniformData(RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial) {
|
||||
bool BlobMaterialShader::updateUniformData(
|
||||
RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial) {
|
||||
Q_UNUSED(oldMaterial);
|
||||
auto* mat = static_cast<BlobMaterial*>(newMaterial);
|
||||
QByteArray* buf = state.uniformData();
|
||||
@@ -59,10 +62,10 @@ bool BlobMaterialShader::updateUniformData(RenderState& state, QSGMaterial* newM
|
||||
|
||||
// Color as vec4 (offset 96, 16 bytes)
|
||||
const float color[4] = {
|
||||
static_cast<float>(mat->m_color.redF()),
|
||||
static_cast<float>(mat->m_color.greenF()),
|
||||
static_cast<float>(mat->m_color.blueF()),
|
||||
static_cast<float>(mat->m_color.alphaF()),
|
||||
mat->m_color.redF(),
|
||||
mat->m_color.greenF(),
|
||||
mat->m_color.blueF(),
|
||||
mat->m_color.alphaF(),
|
||||
};
|
||||
memcpy(buf->data() + 96, color, 16);
|
||||
|
||||
@@ -86,11 +89,11 @@ bool BlobMaterialShader::updateUniformData(RenderState& state, QSGMaterial* newM
|
||||
const auto& r = mat->m_rects[i];
|
||||
const int base = 160 + i * 80;
|
||||
// Pack excludeMask into props.x via bit-cast (read in shader with floatBitsToInt)
|
||||
float maskAsFloat;
|
||||
float maskAsFloat = NAN;
|
||||
memcpy(&maskAsFloat, &r.excludeMask, sizeof(float));
|
||||
const float d0[4] = { r.cx, r.cy, r.hw, r.hh };
|
||||
const float d1[4] = { maskAsFloat, r.offsetX, r.offsetY, r.minEig };
|
||||
const float d3[4] = { r.screenHalfX, r.screenHalfY, 0.0f, 0.0f };
|
||||
const float d0[4] = {r.cx, r.cy, r.hw, r.hh};
|
||||
const float d1[4] = {maskAsFloat, r.offsetX, r.offsetY, r.minEig};
|
||||
const float d3[4] = {r.screenHalfX, r.screenHalfY, 0.0f, 0.0f};
|
||||
memcpy(buf->data() + base, d0, 16);
|
||||
memcpy(buf->data() + base + 16, d1, 16);
|
||||
memcpy(buf->data() + base + 32, r.invDeform, 16);
|
||||
|
||||
@@ -9,39 +9,43 @@ struct BlobRectData {
|
||||
float offsetX = 0, offsetY = 0;
|
||||
float minEig = 1.0f;
|
||||
// Inverse of 2x2 deformation matrix, column-major for GLSL
|
||||
float invDeform[4] = { 1, 0, 0, 1 };
|
||||
float invDeform[4] = {1, 0, 0, 1};
|
||||
// Screen-space AABB half-extents of the deformed rect
|
||||
float screenHalfX = 0, screenHalfY = 0;
|
||||
// Effective per-corner radii (tr, br, bl, tl), pre-computed on CPU
|
||||
float radius[4] = { 0, 0, 0, 0 };
|
||||
float radius[4] = {0, 0, 0, 0};
|
||||
// Bitmask of indices in this rect's m_cachedRects that mutually exclude (or are excluded by) this rect.
|
||||
// Used by the shader to skip smin between excluded pairs.
|
||||
int excludeMask = 0;
|
||||
};
|
||||
|
||||
class BlobMaterial : public QSGMaterial {
|
||||
public:
|
||||
[[nodiscard]] QSGMaterialType* type() const override;
|
||||
[[nodiscard]] QSGMaterialShader* createShader(QSGRendererInterface::RenderMode) const override;
|
||||
int compare(const QSGMaterial* other) const override;
|
||||
public:
|
||||
[[nodiscard]] QSGMaterialType* type() const override;
|
||||
[[nodiscard]] QSGMaterialShader* createShader(
|
||||
QSGRendererInterface::RenderMode) const override;
|
||||
int compare(const QSGMaterial* other) const override;
|
||||
|
||||
float m_paddedX = 0;
|
||||
float m_paddedY = 0;
|
||||
float m_paddedW = 0;
|
||||
float m_paddedH = 0;
|
||||
float m_smoothFactor = 32.0f;
|
||||
int m_rectCount = 0;
|
||||
int m_myIndex = -2;
|
||||
QColor m_color{ 0x44, 0x88, 0xff };
|
||||
int m_hasInverted = 0;
|
||||
float m_invertedRadius = 0;
|
||||
float m_invertedOuter[4] = {};
|
||||
float m_invertedInner[4] = {};
|
||||
BlobRectData m_rects[16] = {};
|
||||
float m_paddedX = 0;
|
||||
float m_paddedY = 0;
|
||||
float m_paddedW = 0;
|
||||
float m_paddedH = 0;
|
||||
float m_smoothFactor = 32.0f;
|
||||
int m_rectCount = 0;
|
||||
int m_myIndex = -2;
|
||||
QColor m_color{0x44, 0x88, 0xff};
|
||||
int m_hasInverted = 0;
|
||||
float m_invertedRadius = 0;
|
||||
float m_invertedOuter[4] = {};
|
||||
float m_invertedInner[4] = {};
|
||||
BlobRectData m_rects[16] = {};
|
||||
};
|
||||
|
||||
class BlobMaterialShader : public QSGMaterialShader {
|
||||
public:
|
||||
BlobMaterialShader();
|
||||
bool updateUniformData(RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial) override;
|
||||
public:
|
||||
BlobMaterialShader();
|
||||
bool updateUniformData(
|
||||
RenderState& state,
|
||||
QSGMaterial* newMaterial,
|
||||
QSGMaterial* oldMaterial) override;
|
||||
};
|
||||
|
||||
@@ -4,19 +4,18 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
BlobRect::BlobRect(QQuickItem* parent)
|
||||
: BlobShape(parent) {
|
||||
}
|
||||
BlobRect::BlobRect(QQuickItem* parent) : BlobShape(parent) {}
|
||||
|
||||
BlobRect::~BlobRect() {
|
||||
if (m_group)
|
||||
m_group->removeShape(this);
|
||||
if (m_group) m_group->removeShape(this);
|
||||
}
|
||||
|
||||
void BlobRect::updatePolish() {
|
||||
if (m_physicsActive) {
|
||||
float totalDelta = std::abs(m_dm00 - 1.0f) + std::abs(m_dm01) + std::abs(m_dm11 - 1.0f);
|
||||
float totalVel = std::abs(m_dmVel00) + std::abs(m_dmVel01) + std::abs(m_dmVel11);
|
||||
float totalDelta = std::abs(m_dm00 - 1.0f) + std::abs(m_dm01) +
|
||||
std::abs(m_dm11 - 1.0f);
|
||||
float totalVel =
|
||||
std::abs(m_dmVel00) + std::abs(m_dmVel01) + std::abs(m_dmVel11);
|
||||
|
||||
if (totalDelta < 0.004f && totalVel < 0.05f) {
|
||||
m_dm00 = 1.0f;
|
||||
@@ -32,18 +31,16 @@ void BlobRect::updatePolish() {
|
||||
QMetaObject::invokeMethod(
|
||||
this,
|
||||
[this]() {
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
},
|
||||
if (m_group) m_group->markDirty();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
} else {
|
||||
QMetaObject::invokeMethod(
|
||||
this,
|
||||
[this]() {
|
||||
if (m_physicsActive && m_group)
|
||||
m_group->markDirty();
|
||||
},
|
||||
if (m_physicsActive && m_group) m_group->markDirty();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
@@ -64,20 +61,20 @@ void BlobRect::updatePhysics() {
|
||||
const float dt = static_cast<float>(m_elapsed.restart()) / 1000.0f;
|
||||
if (dt > 0.1f || dt < 0.001f) {
|
||||
m_prevScenePos = scenePos;
|
||||
if (m_physicsActive)
|
||||
checkAtRest(0.0f);
|
||||
if (m_physicsActive) checkAtRest(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
const float velX = static_cast<float>(scenePos.x() - m_prevScenePos.x()) / dt;
|
||||
const float velY = static_cast<float>(scenePos.y() - m_prevScenePos.y()) / dt;
|
||||
const float velX =
|
||||
static_cast<float>(scenePos.x() - m_prevScenePos.x()) / dt;
|
||||
const float velY =
|
||||
static_cast<float>(scenePos.y() - m_prevScenePos.y()) / dt;
|
||||
m_prevScenePos = scenePos;
|
||||
|
||||
const float speed = std::sqrt(velX * velX + velY * velY);
|
||||
|
||||
if (!m_physicsActive) {
|
||||
if (speed < 5.0f)
|
||||
return;
|
||||
if (speed < 5.0f) return;
|
||||
m_physicsActive = true;
|
||||
}
|
||||
|
||||
@@ -89,7 +86,8 @@ void BlobRect::updatePhysics() {
|
||||
float target11 = 1.0f;
|
||||
|
||||
if (speed > 5.0f) {
|
||||
const float targetStretch = 1.0f + std::min(speed * kStretchFactor, kMaxStretch);
|
||||
const float targetStretch =
|
||||
1.0f + std::min(speed * kStretchFactor, kMaxStretch);
|
||||
const float targetCompress = 1.0f / targetStretch;
|
||||
|
||||
const float cosA = velX / speed;
|
||||
@@ -106,19 +104,23 @@ void BlobRect::updatePhysics() {
|
||||
const float kStiffness = static_cast<float>(m_stiffness);
|
||||
const float kDamping = static_cast<float>(m_damping);
|
||||
|
||||
const float accel00 = -kStiffness * (m_dm00 - target00) - kDamping * m_dmVel00;
|
||||
const float accel00 =
|
||||
-kStiffness * (m_dm00 - target00) - kDamping * m_dmVel00;
|
||||
m_dmVel00 += accel00 * dt;
|
||||
m_dm00 += m_dmVel00 * dt;
|
||||
|
||||
const float accel01 = -kStiffness * (m_dm01 - target01) - kDamping * m_dmVel01;
|
||||
const float accel01 =
|
||||
-kStiffness * (m_dm01 - target01) - kDamping * m_dmVel01;
|
||||
m_dmVel01 += accel01 * dt;
|
||||
m_dm01 += m_dmVel01 * dt;
|
||||
|
||||
const float accel11 = -kStiffness * (m_dm11 - target11) - kDamping * m_dmVel11;
|
||||
const float accel11 =
|
||||
-kStiffness * (m_dm11 - target11) - kDamping * m_dmVel11;
|
||||
m_dmVel11 += accel11 * dt;
|
||||
m_dm11 += m_dmVel11 * dt;
|
||||
|
||||
m_deformMatrix = QMatrix4x4(m_dm00, m_dm01, 0, 0, m_dm01, m_dm11, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
m_deformMatrix = QMatrix4x4(
|
||||
m_dm00, m_dm01, 0, 0, m_dm01, m_dm11, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
emit rawDeformMatrixChanged();
|
||||
updateCenteredDeformMatrix();
|
||||
|
||||
@@ -129,8 +131,7 @@ void BlobRect::setTopLeftRadius(qreal r) {
|
||||
if (!qFuzzyCompare(m_topLeftRadius, r)) {
|
||||
m_topLeftRadius = r;
|
||||
emit topLeftRadiusChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,8 +139,7 @@ void BlobRect::setTopRightRadius(qreal r) {
|
||||
if (!qFuzzyCompare(m_topRightRadius, r)) {
|
||||
m_topRightRadius = r;
|
||||
emit topRightRadiusChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +147,7 @@ void BlobRect::setBottomLeftRadius(qreal r) {
|
||||
if (!qFuzzyCompare(m_bottomLeftRadius, r)) {
|
||||
m_bottomLeftRadius = r;
|
||||
emit bottomLeftRadiusChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,38 +155,51 @@ void BlobRect::setBottomRightRadius(qreal r) {
|
||||
if (!qFuzzyCompare(m_bottomRightRadius, r)) {
|
||||
m_bottomRightRadius = r;
|
||||
emit bottomRightRadiusChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void BlobRect::cornerRadii(float out[4]) const {
|
||||
const auto maxR = static_cast<float>(std::min(width(), height())) * 0.5f;
|
||||
const auto base = std::min(static_cast<float>(m_radius), maxR);
|
||||
out[0] = std::min(m_topRightRadius >= 0 ? static_cast<float>(m_topRightRadius) : base, maxR);
|
||||
out[1] = std::min(m_bottomRightRadius >= 0 ? static_cast<float>(m_bottomRightRadius) : base, maxR);
|
||||
out[2] = std::min(m_bottomLeftRadius >= 0 ? static_cast<float>(m_bottomLeftRadius) : base, maxR);
|
||||
out[3] = std::min(m_topLeftRadius >= 0 ? static_cast<float>(m_topLeftRadius) : base, maxR);
|
||||
out[0] = std::min(
|
||||
m_topRightRadius >= 0 ? static_cast<float>(m_topRightRadius) : base,
|
||||
maxR);
|
||||
out[1] = std::min(
|
||||
m_bottomRightRadius >= 0 ? static_cast<float>(m_bottomRightRadius)
|
||||
: base,
|
||||
maxR);
|
||||
out[2] = std::min(
|
||||
m_bottomLeftRadius >= 0 ? static_cast<float>(m_bottomLeftRadius) : base,
|
||||
maxR);
|
||||
out[3] = std::min(
|
||||
m_topLeftRadius >= 0 ? static_cast<float>(m_topLeftRadius) : base,
|
||||
maxR);
|
||||
}
|
||||
|
||||
bool BlobRect::isExcluded(const BlobShape* other) const {
|
||||
for (const auto& ptr : m_exclude) {
|
||||
if (ptr == other)
|
||||
return true;
|
||||
if (ptr == other) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QQmlListProperty<BlobRect> BlobRect::exclude() {
|
||||
return QQmlListProperty<BlobRect>(
|
||||
this, nullptr, &excludeAppend, &excludeCount, &excludeAt, &excludeClear, &excludeReplace, &excludeRemoveLast);
|
||||
this,
|
||||
nullptr,
|
||||
&excludeAppend,
|
||||
&excludeCount,
|
||||
&excludeAt,
|
||||
&excludeClear,
|
||||
&excludeReplace,
|
||||
&excludeRemoveLast);
|
||||
}
|
||||
|
||||
void BlobRect::excludeAppend(QQmlListProperty<BlobRect>* prop, BlobRect* rect) {
|
||||
auto* self = static_cast<BlobRect*>(prop->object);
|
||||
self->m_exclude.append(rect);
|
||||
if (self->m_group)
|
||||
self->m_group->markDirty();
|
||||
if (self->m_group) self->m_group->markDirty();
|
||||
emit self->excludeChanged();
|
||||
}
|
||||
|
||||
@@ -196,44 +208,43 @@ qsizetype BlobRect::excludeCount(QQmlListProperty<BlobRect>* prop) {
|
||||
return self->m_exclude.size();
|
||||
}
|
||||
|
||||
BlobRect* BlobRect::excludeAt(QQmlListProperty<BlobRect>* prop, qsizetype index) {
|
||||
BlobRect* BlobRect::excludeAt(
|
||||
QQmlListProperty<BlobRect>* prop, qsizetype index) {
|
||||
auto* self = static_cast<BlobRect*>(prop->object);
|
||||
return self->m_exclude.at(index);
|
||||
}
|
||||
|
||||
void BlobRect::excludeClear(QQmlListProperty<BlobRect>* prop) {
|
||||
auto* self = static_cast<BlobRect*>(prop->object);
|
||||
if (self->m_exclude.isEmpty())
|
||||
return;
|
||||
if (self->m_exclude.isEmpty()) return;
|
||||
self->m_exclude.clear();
|
||||
if (self->m_group)
|
||||
self->m_group->markDirty();
|
||||
if (self->m_group) self->m_group->markDirty();
|
||||
emit self->excludeChanged();
|
||||
}
|
||||
|
||||
void BlobRect::excludeReplace(QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect) {
|
||||
void BlobRect::excludeReplace(
|
||||
QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect) {
|
||||
auto* self = static_cast<BlobRect*>(prop->object);
|
||||
self->m_exclude[index] = rect;
|
||||
if (self->m_group)
|
||||
self->m_group->markDirty();
|
||||
if (self->m_group) self->m_group->markDirty();
|
||||
emit self->excludeChanged();
|
||||
}
|
||||
|
||||
void BlobRect::excludeRemoveLast(QQmlListProperty<BlobRect>* prop) {
|
||||
auto* self = static_cast<BlobRect*>(prop->object);
|
||||
if (self->m_exclude.isEmpty())
|
||||
return;
|
||||
if (self->m_exclude.isEmpty()) return;
|
||||
self->m_exclude.removeLast();
|
||||
if (self->m_group)
|
||||
self->m_group->markDirty();
|
||||
if (self->m_group) self->m_group->markDirty();
|
||||
emit self->excludeChanged();
|
||||
}
|
||||
|
||||
void BlobRect::checkAtRest(float speed) {
|
||||
constexpr float kEpsilon = 0.002f;
|
||||
const bool atRest = std::abs(m_dm00 - 1.0f) < kEpsilon && std::abs(m_dm01) < kEpsilon &&
|
||||
std::abs(m_dm11 - 1.0f) < kEpsilon && std::abs(m_dmVel00) < kEpsilon &&
|
||||
std::abs(m_dmVel01) < kEpsilon && std::abs(m_dmVel11) < kEpsilon && speed < 5.0f;
|
||||
const bool atRest =
|
||||
std::abs(m_dm00 - 1.0f) < kEpsilon && std::abs(m_dm01) < kEpsilon &&
|
||||
std::abs(m_dm11 - 1.0f) < kEpsilon && std::abs(m_dmVel00) < kEpsilon &&
|
||||
std::abs(m_dmVel01) < kEpsilon && std::abs(m_dmVel11) < kEpsilon &&
|
||||
speed < 5.0f;
|
||||
|
||||
if (atRest) {
|
||||
m_dm00 = 1.0f;
|
||||
@@ -251,9 +262,8 @@ void BlobRect::checkAtRest(float speed) {
|
||||
QMetaObject::invokeMethod(
|
||||
this,
|
||||
[this]() {
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
},
|
||||
if (m_group) m_group->markDirty();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,133 +8,135 @@
|
||||
#include <qqmllist.h>
|
||||
|
||||
class BlobRect : public BlobShape {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_PROPERTY(qreal stiffness READ stiffness WRITE setStiffness NOTIFY stiffnessChanged)
|
||||
Q_PROPERTY(qreal damping READ damping WRITE setDamping NOTIFY dampingChanged)
|
||||
Q_PROPERTY(qreal deformScale READ deformScale WRITE setDeformScale NOTIFY deformScaleChanged)
|
||||
Q_PROPERTY(QQmlListProperty<BlobRect> exclude READ exclude NOTIFY excludeChanged)
|
||||
Q_PROPERTY(qreal topLeftRadius READ topLeftRadius WRITE setTopLeftRadius NOTIFY topLeftRadiusChanged)
|
||||
Q_PROPERTY(qreal topRightRadius READ topRightRadius WRITE setTopRightRadius NOTIFY topRightRadiusChanged)
|
||||
Q_PROPERTY(qreal bottomLeftRadius READ bottomLeftRadius WRITE setBottomLeftRadius NOTIFY bottomLeftRadiusChanged)
|
||||
Q_PROPERTY(
|
||||
qreal bottomRightRadius READ bottomRightRadius WRITE setBottomRightRadius NOTIFY bottomRightRadiusChanged)
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
Q_PROPERTY(
|
||||
qreal stiffness READ stiffness WRITE setStiffness NOTIFY
|
||||
stiffnessChanged)
|
||||
Q_PROPERTY(qreal damping READ damping WRITE setDamping NOTIFY dampingChanged)
|
||||
Q_PROPERTY(
|
||||
qreal deformScale READ deformScale WRITE setDeformScale NOTIFY
|
||||
deformScaleChanged)
|
||||
Q_PROPERTY(
|
||||
QQmlListProperty<BlobRect> exclude READ exclude NOTIFY excludeChanged)
|
||||
Q_PROPERTY(
|
||||
qreal topLeftRadius READ topLeftRadius WRITE setTopLeftRadius NOTIFY
|
||||
topLeftRadiusChanged)
|
||||
Q_PROPERTY(
|
||||
qreal topRightRadius READ topRightRadius WRITE setTopRightRadius NOTIFY
|
||||
topRightRadiusChanged)
|
||||
Q_PROPERTY(
|
||||
qreal bottomLeftRadius READ bottomLeftRadius WRITE setBottomLeftRadius
|
||||
NOTIFY bottomLeftRadiusChanged)
|
||||
Q_PROPERTY(
|
||||
qreal bottomRightRadius READ bottomRightRadius WRITE
|
||||
setBottomRightRadius NOTIFY bottomRightRadiusChanged)
|
||||
|
||||
public:
|
||||
explicit BlobRect(QQuickItem* parent = nullptr);
|
||||
~BlobRect() override;
|
||||
public:
|
||||
explicit BlobRect(QQuickItem* parent = nullptr);
|
||||
~BlobRect() override;
|
||||
|
||||
[[nodiscard]] qreal stiffness() const {
|
||||
return m_stiffness;
|
||||
}
|
||||
[[nodiscard]] qreal stiffness() const { return m_stiffness; }
|
||||
|
||||
void setStiffness(qreal s) {
|
||||
if (!qFuzzyCompare(m_stiffness, s)) {
|
||||
m_stiffness = s;
|
||||
emit stiffnessChanged();
|
||||
void setStiffness(qreal s) {
|
||||
if (!qFuzzyCompare(m_stiffness, s)) {
|
||||
m_stiffness = s;
|
||||
emit stiffnessChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] qreal damping() const {
|
||||
return m_damping;
|
||||
}
|
||||
[[nodiscard]] qreal damping() const { return m_damping; }
|
||||
|
||||
void setDamping(qreal d) {
|
||||
if (!qFuzzyCompare(m_damping, d)) {
|
||||
m_damping = d;
|
||||
emit dampingChanged();
|
||||
void setDamping(qreal d) {
|
||||
if (!qFuzzyCompare(m_damping, d)) {
|
||||
m_damping = d;
|
||||
emit dampingChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] qreal deformScale() const {
|
||||
return m_deformScale;
|
||||
}
|
||||
[[nodiscard]] qreal deformScale() const { return m_deformScale; }
|
||||
|
||||
void setDeformScale(qreal s) {
|
||||
if (!qFuzzyCompare(m_deformScale, s)) {
|
||||
m_deformScale = s;
|
||||
emit deformScaleChanged();
|
||||
void setDeformScale(qreal s) {
|
||||
if (!qFuzzyCompare(m_deformScale, s)) {
|
||||
m_deformScale = s;
|
||||
emit deformScaleChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QQmlListProperty<BlobRect> exclude();
|
||||
QQmlListProperty<BlobRect> exclude();
|
||||
|
||||
bool isExcluded(const BlobShape* other) const override;
|
||||
void cornerRadii(float out[4]) const override;
|
||||
bool isExcluded(const BlobShape* other) const override;
|
||||
void cornerRadii(float out[4]) const override;
|
||||
|
||||
[[nodiscard]] qreal topLeftRadius() const {
|
||||
return m_topLeftRadius;
|
||||
}
|
||||
[[nodiscard]] qreal topLeftRadius() const { return m_topLeftRadius; }
|
||||
|
||||
void setTopLeftRadius(qreal r);
|
||||
void setTopLeftRadius(qreal r);
|
||||
|
||||
[[nodiscard]] qreal topRightRadius() const {
|
||||
return m_topRightRadius;
|
||||
}
|
||||
[[nodiscard]] qreal topRightRadius() const { return m_topRightRadius; }
|
||||
|
||||
void setTopRightRadius(qreal r);
|
||||
void setTopRightRadius(qreal r);
|
||||
|
||||
[[nodiscard]] qreal bottomLeftRadius() const {
|
||||
return m_bottomLeftRadius;
|
||||
}
|
||||
[[nodiscard]] qreal bottomLeftRadius() const { return m_bottomLeftRadius; }
|
||||
|
||||
void setBottomLeftRadius(qreal r);
|
||||
void setBottomLeftRadius(qreal r);
|
||||
|
||||
[[nodiscard]] qreal bottomRightRadius() const {
|
||||
return m_bottomRightRadius;
|
||||
}
|
||||
[[nodiscard]] qreal bottomRightRadius() const {
|
||||
return m_bottomRightRadius;
|
||||
}
|
||||
|
||||
void setBottomRightRadius(qreal r);
|
||||
void setBottomRightRadius(qreal r);
|
||||
|
||||
signals:
|
||||
void stiffnessChanged();
|
||||
void dampingChanged();
|
||||
void deformScaleChanged();
|
||||
void excludeChanged();
|
||||
void topLeftRadiusChanged();
|
||||
void topRightRadiusChanged();
|
||||
void bottomLeftRadiusChanged();
|
||||
void bottomRightRadiusChanged();
|
||||
signals:
|
||||
void stiffnessChanged();
|
||||
void dampingChanged();
|
||||
void deformScaleChanged();
|
||||
void excludeChanged();
|
||||
void topLeftRadiusChanged();
|
||||
void topRightRadiusChanged();
|
||||
void bottomLeftRadiusChanged();
|
||||
void bottomRightRadiusChanged();
|
||||
|
||||
protected:
|
||||
void updatePolish() override;
|
||||
void updatePhysics() override;
|
||||
protected:
|
||||
void updatePolish() override;
|
||||
void updatePhysics() override;
|
||||
|
||||
private:
|
||||
void checkAtRest(float speed);
|
||||
private:
|
||||
void checkAtRest(float speed);
|
||||
|
||||
// Physics state
|
||||
QPointF m_prevScenePos;
|
||||
QElapsedTimer m_elapsed;
|
||||
bool m_physicsActive = false;
|
||||
bool m_hasPrevPos = false;
|
||||
// Physics state
|
||||
QPointF m_prevScenePos;
|
||||
QElapsedTimer m_elapsed;
|
||||
bool m_physicsActive = false;
|
||||
bool m_hasPrevPos = false;
|
||||
|
||||
// Symmetric 2x2 deformation matrix components (3 independent: m00, m01,
|
||||
// m11) Rest state is identity: m00=1, m01=0, m11=1
|
||||
float m_dm00 = 1.0f;
|
||||
float m_dm01 = 0.0f;
|
||||
float m_dm11 = 1.0f;
|
||||
// Symmetric 2x2 deformation matrix components (3 independent: m00, m01,
|
||||
// m11) Rest state is identity: m00=1, m01=0, m11=1
|
||||
float m_dm00 = 1.0f;
|
||||
float m_dm01 = 0.0f;
|
||||
float m_dm11 = 1.0f;
|
||||
|
||||
// Spring velocities for each component
|
||||
float m_dmVel00 = 0.0f;
|
||||
float m_dmVel01 = 0.0f;
|
||||
float m_dmVel11 = 0.0f;
|
||||
// Spring velocities for each component
|
||||
float m_dmVel00 = 0.0f;
|
||||
float m_dmVel01 = 0.0f;
|
||||
float m_dmVel11 = 0.0f;
|
||||
|
||||
qreal m_stiffness = 200.0;
|
||||
qreal m_damping = 16.0;
|
||||
qreal m_deformScale = 0.0005;
|
||||
qreal m_stiffness = 200.0;
|
||||
qreal m_damping = 16.0;
|
||||
qreal m_deformScale = 0.0005;
|
||||
|
||||
qreal m_topLeftRadius = -1;
|
||||
qreal m_topRightRadius = -1;
|
||||
qreal m_bottomLeftRadius = -1;
|
||||
qreal m_bottomRightRadius = -1;
|
||||
qreal m_topLeftRadius = -1;
|
||||
qreal m_topRightRadius = -1;
|
||||
qreal m_bottomLeftRadius = -1;
|
||||
qreal m_bottomRightRadius = -1;
|
||||
|
||||
QList<QPointer<BlobRect> > m_exclude;
|
||||
QList<QPointer<BlobRect>> m_exclude;
|
||||
|
||||
static void excludeAppend(QQmlListProperty<BlobRect>* prop, BlobRect* rect);
|
||||
static qsizetype excludeCount(QQmlListProperty<BlobRect>* prop);
|
||||
static BlobRect* excludeAt(QQmlListProperty<BlobRect>* prop, qsizetype index);
|
||||
static void excludeClear(QQmlListProperty<BlobRect>* prop);
|
||||
static void excludeReplace(QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect);
|
||||
static void excludeRemoveLast(QQmlListProperty<BlobRect>* prop);
|
||||
static void excludeAppend(QQmlListProperty<BlobRect>* prop, BlobRect* rect);
|
||||
static qsizetype excludeCount(QQmlListProperty<BlobRect>* prop);
|
||||
static BlobRect* excludeAt(
|
||||
QQmlListProperty<BlobRect>* prop, qsizetype index);
|
||||
static void excludeClear(QQmlListProperty<BlobRect>* prop);
|
||||
static void excludeReplace(
|
||||
QQmlListProperty<BlobRect>* prop, qsizetype index, BlobRect* rect);
|
||||
static void excludeRemoveLast(QQmlListProperty<BlobRect>* prop);
|
||||
};
|
||||
|
||||
@@ -18,7 +18,8 @@ static float deformPadding(const QMatrix4x4& dm, float hw, float hh) {
|
||||
return std::max(extraX, extraY);
|
||||
}
|
||||
|
||||
static float cpuSdBox(float px, float py, float cx, float cy, float hw, float hh) {
|
||||
static float cpuSdBox(
|
||||
float px, float py, float cx, float cy, float hw, float hh) {
|
||||
const float dx = std::abs(px - cx) - hw;
|
||||
const float dy = std::abs(py - cy) - hh;
|
||||
const float mdx = std::max(dx, 0.0f);
|
||||
@@ -31,54 +32,53 @@ static float cpuSmoothstep(float edge0, float edge1, float x) {
|
||||
return t * t * (3.0f - 2.0f * t);
|
||||
}
|
||||
|
||||
BlobShape::BlobShape(QQuickItem* parent)
|
||||
: QQuickItem(parent) {
|
||||
BlobShape::BlobShape(QQuickItem* parent) : QQuickItem(parent) {
|
||||
setFlag(ItemHasContents);
|
||||
}
|
||||
|
||||
void BlobShape::setGroup(BlobGroup* g) {
|
||||
if (m_group == g)
|
||||
return;
|
||||
if (m_group && isComponentComplete())
|
||||
unregisterFromGroup();
|
||||
if (m_group == g) return;
|
||||
if (m_group && isComponentComplete()) unregisterFromGroup();
|
||||
m_group = g;
|
||||
if (m_group && isComponentComplete())
|
||||
registerWithGroup();
|
||||
if (m_group && isComponentComplete()) registerWithGroup();
|
||||
emit groupChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobShape::setRadius(qreal r) {
|
||||
if (qFuzzyCompare(m_radius, r))
|
||||
return;
|
||||
if (qFuzzyCompare(m_radius, r)) return;
|
||||
m_radius = r;
|
||||
emit radiusChanged();
|
||||
if (m_group)
|
||||
m_group->markDirty();
|
||||
if (m_group) m_group->markDirty();
|
||||
}
|
||||
|
||||
void BlobShape::componentComplete() {
|
||||
QQuickItem::componentComplete();
|
||||
if (m_group)
|
||||
registerWithGroup();
|
||||
if (m_group) registerWithGroup();
|
||||
}
|
||||
|
||||
void BlobShape::geometryChange(const QRectF& newGeometry, const QRectF& oldGeometry) {
|
||||
void BlobShape::geometryChange(
|
||||
const QRectF& newGeometry, const QRectF& oldGeometry) {
|
||||
QQuickItem::geometryChange(newGeometry, oldGeometry);
|
||||
updateCenteredDeformMatrix();
|
||||
if (m_group) {
|
||||
m_pendingDx += static_cast<float>(newGeometry.x() - oldGeometry.x());
|
||||
m_pendingDy += static_cast<float>(newGeometry.y() - oldGeometry.y());
|
||||
m_pendingDw += static_cast<float>(newGeometry.width() - oldGeometry.width());
|
||||
m_pendingDh += static_cast<float>(newGeometry.height() - oldGeometry.height());
|
||||
m_pendingDw +=
|
||||
static_cast<float>(newGeometry.width() - oldGeometry.width());
|
||||
m_pendingDh +=
|
||||
static_cast<float>(newGeometry.height() - oldGeometry.height());
|
||||
|
||||
const float deformMag = std::abs(m_deformMatrix(0, 0) - 1.0f) + std::abs(m_deformMatrix(0, 1)) +
|
||||
std::abs(m_deformMatrix(1, 0)) + std::abs(m_deformMatrix(1, 1) - 1.0f);
|
||||
const float deformMag = std::abs(m_deformMatrix(0, 0) - 1.0f) +
|
||||
std::abs(m_deformMatrix(0, 1)) +
|
||||
std::abs(m_deformMatrix(1, 0)) +
|
||||
std::abs(m_deformMatrix(1, 1) - 1.0f);
|
||||
const float syncThreshold = deformMag > 0.001f ? 0.05f : 0.5f;
|
||||
|
||||
if (std::abs(m_pendingDx) > syncThreshold || std::abs(m_pendingDy) > syncThreshold ||
|
||||
std::abs(m_pendingDw) > syncThreshold || std::abs(m_pendingDh) > syncThreshold) {
|
||||
if (std::abs(m_pendingDx) > syncThreshold ||
|
||||
std::abs(m_pendingDy) > syncThreshold ||
|
||||
std::abs(m_pendingDw) > syncThreshold ||
|
||||
std::abs(m_pendingDh) > syncThreshold) {
|
||||
m_pendingDx = 0;
|
||||
m_pendingDy = 0;
|
||||
m_pendingDw = 0;
|
||||
@@ -111,18 +111,15 @@ void BlobShape::cornerRadii(float out[4]) const {
|
||||
}
|
||||
|
||||
void BlobShape::registerWithGroup() {
|
||||
if (m_group)
|
||||
m_group->addShape(this);
|
||||
if (m_group) m_group->addShape(this);
|
||||
}
|
||||
|
||||
void BlobShape::unregisterFromGroup() {
|
||||
if (m_group)
|
||||
m_group->removeShape(this);
|
||||
if (m_group) m_group->removeShape(this);
|
||||
}
|
||||
|
||||
void BlobShape::updatePolish() {
|
||||
if (!m_group)
|
||||
return;
|
||||
if (!m_group) return;
|
||||
|
||||
m_group->ensurePhysicsUpdated();
|
||||
|
||||
@@ -144,27 +141,30 @@ void BlobShape::updatePolish() {
|
||||
m_cachedPaddedY = static_cast<float>(scenePos.y()) - totalPad;
|
||||
m_cachedPaddedW = static_cast<float>(width()) + 2.0f * totalPad;
|
||||
m_cachedPaddedH = static_cast<float>(height()) + 2.0f * totalPad;
|
||||
m_localPaddedRect = QRectF(static_cast<double>(-totalPad), static_cast<double>(-totalPad),
|
||||
width() + 2.0 * static_cast<double>(totalPad), height() + 2.0 * static_cast<double>(totalPad));
|
||||
m_localPaddedRect = QRectF(
|
||||
static_cast<double>(-totalPad),
|
||||
static_cast<double>(-totalPad),
|
||||
width() + 2.0 * static_cast<double>(totalPad),
|
||||
height() + 2.0 * static_cast<double>(totalPad));
|
||||
}
|
||||
|
||||
m_cachedRects.clear();
|
||||
m_cachedMyIndex = -2;
|
||||
const QRectF myPadded(static_cast<double>(m_cachedPaddedX), static_cast<double>(m_cachedPaddedY),
|
||||
static_cast<double>(m_cachedPaddedW), static_cast<double>(m_cachedPaddedH));
|
||||
const QRectF myPadded(
|
||||
static_cast<double>(m_cachedPaddedX),
|
||||
static_cast<double>(m_cachedPaddedY),
|
||||
static_cast<double>(m_cachedPaddedW),
|
||||
static_cast<double>(m_cachedPaddedH));
|
||||
|
||||
QVector<BlobShape*> rectShapes;
|
||||
rectShapes.reserve(m_group->shapes().size());
|
||||
|
||||
for (BlobShape* other : m_group->shapes()) {
|
||||
if (other->isInvertedRect())
|
||||
continue;
|
||||
if (other->isInvertedRect()) continue;
|
||||
|
||||
if (other->width() <= 0 || other->height() <= 0)
|
||||
continue;
|
||||
if (other->width() <= 0 || other->height() <= 0) continue;
|
||||
|
||||
if (isExcluded(other))
|
||||
continue;
|
||||
if (isExcluded(other)) continue;
|
||||
|
||||
const QPointF otherScene = other->mapToScene(QPointF(0, 0));
|
||||
|
||||
@@ -174,10 +174,13 @@ void BlobShape::updatePolish() {
|
||||
} else {
|
||||
const float otherHW = static_cast<float>(other->width()) * 0.5f;
|
||||
const float otherHH = static_cast<float>(other->height()) * 0.5f;
|
||||
const float otherPad = pad + deformPadding(other->m_deformMatrix, otherHW, otherHH);
|
||||
const QRectF otherPadded(otherScene.x() - static_cast<double>(otherPad),
|
||||
otherScene.y() - static_cast<double>(otherPad), other->width() + 2.0 * static_cast<double>(otherPad),
|
||||
other->height() + 2.0 * static_cast<double>(otherPad));
|
||||
const float otherPad =
|
||||
pad + deformPadding(other->m_deformMatrix, otherHW, otherHH);
|
||||
const QRectF otherPadded(
|
||||
otherScene.x() - static_cast<double>(otherPad),
|
||||
otherScene.y() - static_cast<double>(otherPad),
|
||||
other->width() + 2.0 * static_cast<double>(otherPad),
|
||||
other->height() + 2.0 * static_cast<double>(otherPad));
|
||||
include = myPadded.intersects(otherPadded);
|
||||
}
|
||||
|
||||
@@ -217,19 +220,16 @@ void BlobShape::updatePolish() {
|
||||
}
|
||||
}
|
||||
|
||||
if (isInvertedRect())
|
||||
m_cachedMyIndex = -1;
|
||||
if (isInvertedRect()) m_cachedMyIndex = -1;
|
||||
|
||||
const auto cachedCount = m_cachedRects.size();
|
||||
for (qsizetype i = 0; i < cachedCount; ++i) {
|
||||
int mask = 0;
|
||||
BlobShape* si = rectShapes[i];
|
||||
for (qsizetype j = 0; j < cachedCount; ++j) {
|
||||
if (j == i)
|
||||
continue;
|
||||
if (j == i) continue;
|
||||
BlobShape* sj = rectShapes[j];
|
||||
if (si->isExcluded(sj) || sj->isExcluded(si))
|
||||
mask |= (1 << j);
|
||||
if (si->isExcluded(sj) || sj->isExcluded(si)) mask |= (1 << j);
|
||||
}
|
||||
m_cachedRects[i].excludeMask = mask;
|
||||
}
|
||||
@@ -242,15 +242,25 @@ void BlobShape::updatePolish() {
|
||||
auto* inv = m_group->invertedRect();
|
||||
if (inv) {
|
||||
const QPointF invScene = inv->mapToScene(QPointF(0, 0));
|
||||
const float outerCX = static_cast<float>(invScene.x() + inv->width() / 2.0);
|
||||
const float outerCY = static_cast<float>(invScene.y() + inv->height() / 2.0);
|
||||
const float outerCX =
|
||||
static_cast<float>(invScene.x() + inv->width() / 2.0);
|
||||
const float outerCY =
|
||||
static_cast<float>(invScene.y() + inv->height() / 2.0);
|
||||
const float outerHW = static_cast<float>(inv->width() / 2.0);
|
||||
const float outerHH = static_cast<float>(inv->height() / 2.0);
|
||||
|
||||
const float innerCX = outerCX + static_cast<float>((inv->borderLeft() - inv->borderRight()) / 2.0);
|
||||
const float innerCY = outerCY + static_cast<float>((inv->borderTop() - inv->borderBottom()) / 2.0);
|
||||
const float innerHW = outerHW - static_cast<float>((inv->borderLeft() + inv->borderRight()) / 2.0);
|
||||
const float innerHH = outerHH - static_cast<float>((inv->borderTop() + inv->borderBottom()) / 2.0);
|
||||
const float innerCX =
|
||||
outerCX +
|
||||
static_cast<float>((inv->borderLeft() - inv->borderRight()) / 2.0);
|
||||
const float innerCY =
|
||||
outerCY +
|
||||
static_cast<float>((inv->borderTop() - inv->borderBottom()) / 2.0);
|
||||
const float innerHW =
|
||||
outerHW -
|
||||
static_cast<float>((inv->borderLeft() + inv->borderRight()) / 2.0);
|
||||
const float innerHH =
|
||||
outerHH -
|
||||
static_cast<float>((inv->borderTop() + inv->borderBottom()) / 2.0);
|
||||
|
||||
bool nearBorder = isInvertedRect();
|
||||
if (!nearBorder) {
|
||||
@@ -259,8 +269,10 @@ void BlobShape::updatePolish() {
|
||||
const float myCY = m_cachedPaddedY + m_cachedPaddedH * 0.5f;
|
||||
const float myHW = m_cachedPaddedW * 0.5f;
|
||||
const float myHH = m_cachedPaddedH * 0.5f;
|
||||
nearBorder = (myCX - myHW < innerCX - innerHW + margin) || (myCX + myHW > innerCX + innerHW - margin) ||
|
||||
(myCY - myHH < innerCY - innerHH + margin) || (myCY + myHH > innerCY + innerHH - margin);
|
||||
nearBorder = (myCX - myHW < innerCX - innerHW + margin) ||
|
||||
(myCX + myHW > innerCX + innerHW - margin) ||
|
||||
(myCY - myHH < innerCY - innerHH + margin) ||
|
||||
(myCY + myHH > innerCY + innerHH - margin);
|
||||
}
|
||||
|
||||
if (nearBorder) {
|
||||
@@ -293,15 +305,33 @@ void BlobShape::updatePolish() {
|
||||
const float cTlX = ri.cx - ri.hw, cTlY = ri.cy - ri.hh;
|
||||
|
||||
for (qsizetype j = 0; j < rectCount; ++j) {
|
||||
if (j == i)
|
||||
continue;
|
||||
if (riExcludeMask & (1 << j))
|
||||
continue;
|
||||
if (j == i) continue;
|
||||
if (riExcludeMask & (1 << j)) continue;
|
||||
const auto& rj = m_cachedRects[j];
|
||||
fTr = std::min(fTr, cpuSmoothstep(0.0f, smoothFactor, cpuSdBox(cTrX, cTrY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||
fBr = std::min(fBr, cpuSmoothstep(0.0f, smoothFactor, cpuSdBox(cBrX, cBrY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||
fBl = std::min(fBl, cpuSmoothstep(0.0f, smoothFactor, cpuSdBox(cBlX, cBlY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||
fTl = std::min(fTl, cpuSmoothstep(0.0f, smoothFactor, cpuSdBox(cTlX, cTlY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||
fTr = std::min(
|
||||
fTr,
|
||||
cpuSmoothstep(
|
||||
0.0f,
|
||||
smoothFactor,
|
||||
cpuSdBox(cTrX, cTrY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||
fBr = std::min(
|
||||
fBr,
|
||||
cpuSmoothstep(
|
||||
0.0f,
|
||||
smoothFactor,
|
||||
cpuSdBox(cBrX, cBrY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||
fBl = std::min(
|
||||
fBl,
|
||||
cpuSmoothstep(
|
||||
0.0f,
|
||||
smoothFactor,
|
||||
cpuSdBox(cBlX, cBlY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||
fTl = std::min(
|
||||
fTl,
|
||||
cpuSmoothstep(
|
||||
0.0f,
|
||||
smoothFactor,
|
||||
cpuSdBox(cTlX, cTlY, rj.cx, rj.cy, rj.hw, rj.hh)));
|
||||
}
|
||||
|
||||
if (m_cachedHasInverted) {
|
||||
@@ -309,10 +339,30 @@ void BlobShape::updatePolish() {
|
||||
const float icy = m_cachedInvertedInner[1];
|
||||
const float ihw = m_cachedInvertedInner[2];
|
||||
const float ihh = m_cachedInvertedInner[3];
|
||||
fTr = std::min(fTr, cpuSmoothstep(0.0f, smoothFactor, -cpuSdBox(cTrX, cTrY, icx, icy, ihw, ihh)));
|
||||
fBr = std::min(fBr, cpuSmoothstep(0.0f, smoothFactor, -cpuSdBox(cBrX, cBrY, icx, icy, ihw, ihh)));
|
||||
fBl = std::min(fBl, cpuSmoothstep(0.0f, smoothFactor, -cpuSdBox(cBlX, cBlY, icx, icy, ihw, ihh)));
|
||||
fTl = std::min(fTl, cpuSmoothstep(0.0f, smoothFactor, -cpuSdBox(cTlX, cTlY, icx, icy, ihw, ihh)));
|
||||
fTr = std::min(
|
||||
fTr,
|
||||
cpuSmoothstep(
|
||||
0.0f,
|
||||
smoothFactor,
|
||||
-cpuSdBox(cTrX, cTrY, icx, icy, ihw, ihh)));
|
||||
fBr = std::min(
|
||||
fBr,
|
||||
cpuSmoothstep(
|
||||
0.0f,
|
||||
smoothFactor,
|
||||
-cpuSdBox(cBrX, cBrY, icx, icy, ihw, ihh)));
|
||||
fBl = std::min(
|
||||
fBl,
|
||||
cpuSmoothstep(
|
||||
0.0f,
|
||||
smoothFactor,
|
||||
-cpuSdBox(cBlX, cBlY, icx, icy, ihw, ihh)));
|
||||
fTl = std::min(
|
||||
fTl,
|
||||
cpuSmoothstep(
|
||||
0.0f,
|
||||
smoothFactor,
|
||||
-cpuSdBox(cTlX, cTlY, icx, icy, ihw, ihh)));
|
||||
}
|
||||
|
||||
ri.radius[0] = std::max(ri.radius[0] * fTr, minR);
|
||||
@@ -332,7 +382,8 @@ QSGNode* BlobShape::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) {
|
||||
if (!node) {
|
||||
node = new QSGGeometryNode;
|
||||
|
||||
auto* geometry = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
|
||||
auto* geometry =
|
||||
new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
|
||||
geometry->setDrawingMode(QSGGeometry::DrawTriangleStrip);
|
||||
node->setGeometry(geometry);
|
||||
node->setFlag(QSGNode::OwnsGeometry);
|
||||
@@ -368,10 +419,17 @@ QSGNode* BlobShape::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) {
|
||||
material->m_color = m_group->color();
|
||||
material->m_hasInverted = m_cachedHasInverted ? 1 : 0;
|
||||
material->m_invertedRadius = m_cachedInvertedRadius;
|
||||
memcpy(material->m_invertedOuter, m_cachedInvertedOuter, sizeof(m_cachedInvertedOuter));
|
||||
memcpy(material->m_invertedInner, m_cachedInvertedInner, sizeof(m_cachedInvertedInner));
|
||||
memcpy(
|
||||
material->m_invertedOuter,
|
||||
m_cachedInvertedOuter,
|
||||
sizeof(m_cachedInvertedOuter));
|
||||
memcpy(
|
||||
material->m_invertedInner,
|
||||
m_cachedInvertedInner,
|
||||
sizeof(m_cachedInvertedInner));
|
||||
|
||||
const int count = static_cast<int>(qMin(m_cachedRects.size(), qsizetype(16)));
|
||||
const int count =
|
||||
static_cast<int>(qMin(m_cachedRects.size(), qsizetype(16)));
|
||||
material->m_rectCount = count;
|
||||
for (int i = 0; i < count; ++i)
|
||||
material->m_rects[i] = m_cachedRects[i];
|
||||
|
||||
@@ -9,85 +9,78 @@
|
||||
class BlobGroup;
|
||||
|
||||
class BlobShape : public QQuickItem {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(BlobGroup* group READ group WRITE setGroup NOTIFY groupChanged)
|
||||
Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
|
||||
Q_PROPERTY(QMatrix4x4 deformMatrix READ deformMatrix NOTIFY deformMatrixChanged)
|
||||
Q_PROPERTY(QMatrix4x4 rawDeformMatrix READ rawDeformMatrix NOTIFY rawDeformMatrixChanged)
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(BlobGroup* group READ group WRITE setGroup NOTIFY groupChanged)
|
||||
Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
|
||||
Q_PROPERTY(
|
||||
QMatrix4x4 deformMatrix READ deformMatrix NOTIFY deformMatrixChanged)
|
||||
Q_PROPERTY(
|
||||
QMatrix4x4 rawDeformMatrix READ rawDeformMatrix NOTIFY
|
||||
rawDeformMatrixChanged)
|
||||
|
||||
friend class BlobGroup;
|
||||
friend class BlobGroup;
|
||||
|
||||
public:
|
||||
explicit BlobShape(QQuickItem* parent = nullptr);
|
||||
~BlobShape() override = default;
|
||||
public:
|
||||
explicit BlobShape(QQuickItem* parent = nullptr);
|
||||
~BlobShape() override = default;
|
||||
|
||||
[[nodiscard]] BlobGroup* group() const {
|
||||
return m_group;
|
||||
}
|
||||
[[nodiscard]] BlobGroup* group() const { return m_group; }
|
||||
|
||||
void setGroup(BlobGroup* g);
|
||||
void setGroup(BlobGroup* g);
|
||||
|
||||
[[nodiscard]] qreal radius() const {
|
||||
return m_radius;
|
||||
}
|
||||
[[nodiscard]] qreal radius() const { return m_radius; }
|
||||
|
||||
void setRadius(qreal r);
|
||||
void setRadius(qreal r);
|
||||
|
||||
[[nodiscard]] QMatrix4x4 deformMatrix() const {
|
||||
return m_centeredDeformMatrix;
|
||||
}
|
||||
[[nodiscard]] QMatrix4x4 deformMatrix() const {
|
||||
return m_centeredDeformMatrix;
|
||||
}
|
||||
|
||||
[[nodiscard]] QMatrix4x4 rawDeformMatrix() const {
|
||||
return m_deformMatrix;
|
||||
}
|
||||
[[nodiscard]] QMatrix4x4 rawDeformMatrix() const { return m_deformMatrix; }
|
||||
|
||||
signals:
|
||||
void groupChanged();
|
||||
void radiusChanged();
|
||||
void deformMatrixChanged();
|
||||
void rawDeformMatrixChanged();
|
||||
signals:
|
||||
void groupChanged();
|
||||
void radiusChanged();
|
||||
void deformMatrixChanged();
|
||||
void rawDeformMatrixChanged();
|
||||
|
||||
protected:
|
||||
void componentComplete() override;
|
||||
void geometryChange(const QRectF& newGeometry, const QRectF& oldGeometry) override;
|
||||
void updatePolish() override;
|
||||
QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) override;
|
||||
protected:
|
||||
void componentComplete() override;
|
||||
void geometryChange(
|
||||
const QRectF& newGeometry, const QRectF& oldGeometry) override;
|
||||
void updatePolish() override;
|
||||
QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData*) override;
|
||||
|
||||
[[nodiscard]] virtual bool isInvertedRect() const {
|
||||
return false;
|
||||
}
|
||||
[[nodiscard]] virtual bool isInvertedRect() const { return false; }
|
||||
|
||||
virtual bool isExcluded(const BlobShape* /*other*/) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool isExcluded(const BlobShape*) const { return false; }
|
||||
|
||||
virtual void cornerRadii(float out[4]) const;
|
||||
virtual void cornerRadii(float out[4]) const;
|
||||
|
||||
virtual void updatePhysics() {
|
||||
}
|
||||
virtual void updatePhysics() {}
|
||||
|
||||
virtual void registerWithGroup();
|
||||
virtual void unregisterFromGroup();
|
||||
void updateCenteredDeformMatrix();
|
||||
virtual void registerWithGroup();
|
||||
virtual void unregisterFromGroup();
|
||||
void updateCenteredDeformMatrix();
|
||||
|
||||
BlobGroup* m_group = nullptr;
|
||||
qreal m_radius = 0;
|
||||
QMatrix4x4 m_deformMatrix;
|
||||
QMatrix4x4 m_centeredDeformMatrix;
|
||||
BlobGroup* m_group = nullptr;
|
||||
qreal m_radius = 0;
|
||||
QMatrix4x4 m_deformMatrix;
|
||||
QMatrix4x4 m_centeredDeformMatrix;
|
||||
|
||||
float m_cachedPaddedX = 0;
|
||||
float m_cachedPaddedY = 0;
|
||||
float m_cachedPaddedW = 0;
|
||||
float m_cachedPaddedH = 0;
|
||||
QRectF m_localPaddedRect;
|
||||
QVector<BlobRectData> m_cachedRects;
|
||||
int m_cachedMyIndex = -2;
|
||||
float m_pendingDx = 0;
|
||||
float m_pendingDy = 0;
|
||||
float m_pendingDw = 0;
|
||||
float m_pendingDh = 0;
|
||||
bool m_cachedHasInverted = false;
|
||||
float m_cachedInvertedRadius = 0;
|
||||
float m_cachedInvertedOuter[4] = {};
|
||||
float m_cachedInvertedInner[4] = {};
|
||||
float m_cachedPaddedX = 0;
|
||||
float m_cachedPaddedY = 0;
|
||||
float m_cachedPaddedW = 0;
|
||||
float m_cachedPaddedH = 0;
|
||||
QRectF m_localPaddedRect;
|
||||
QVector<BlobRectData> m_cachedRects;
|
||||
int m_cachedMyIndex = -2;
|
||||
float m_pendingDx = 0;
|
||||
float m_pendingDy = 0;
|
||||
float m_pendingDw = 0;
|
||||
float m_pendingDh = 0;
|
||||
bool m_cachedHasInverted = false;
|
||||
float m_cachedInvertedRadius = 0;
|
||||
float m_cachedInvertedOuter[4] = {};
|
||||
float m_cachedInvertedInner[4] = {};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user