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

This commit is contained in:
2026-06-30 02:04:24 +02:00
parent fed9372b35
commit 467e44bb9f
85 changed files with 4139 additions and 3738 deletions
+18 -22
View File
@@ -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();
+33 -37
View File
@@ -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;
};
+29 -32
View File
@@ -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);
}
+40 -42
View File
@@ -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;
};
+19 -16
View File
@@ -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);
+26 -22
View File
@@ -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;
};
+69 -59
View File
@@ -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);
}
}
+101 -99
View File
@@ -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);
};
+132 -74
View File
@@ -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];
+57 -64
View File
@@ -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] = {};
};