Commit 9e2c0f55 authored by Ulf Hermann's avatar Ulf Hermann
Browse files

Timeline: Use the same shader for items and selections



This should once and for all rid us of artifacts resulting from
rounding errors that occur in one shader but not in the other.

Change-Id: I07decc8e24fb8f1a9b0a5a165fd8333540dc0443
Reviewed-by: default avatarJoerg Bornemann <joerg.bornemann@theqtcompany.com>
parent 987dccad
......@@ -36,26 +36,6 @@
namespace Timeline {
class TimelineItemsMaterial : public QSGMaterial {
public:
TimelineItemsMaterial();
QVector2D scale() const;
void setScale(QVector2D scale);
float selectedItem() const;
void setSelectedItem(float selectedItem);
QColor selectionColor() const;
void setSelectionColor(QColor selectionColor);
QSGMaterialType *type() const;
QSGMaterialShader *createShader() const;
private:
QVector2D m_scale;
float m_selectedItem;
QColor m_selectionColor;
};
class TimelineItemsRenderPassState : public TimelineRenderPass::State {
public:
TimelineItemsRenderPassState(const TimelineModel *model);
......@@ -82,18 +62,10 @@ private:
QVector<QSGNode *> m_collapsedRows;
};
struct OpaqueColoredPoint2DWithSize {
float x, y, w, h, id;
unsigned char r, g, b, a;
void set(float nx, float ny, float nw, float nh, float nid, uchar nr, uchar ng, uchar nb);
};
struct TimelineItemsGeometry {
// Alternating nodes with with 7 and 4 vertices; and vertex indices are 16bit
static const int maxEventsPerNode = 0xffff * 2 / (7 + 4);
static const QSGGeometry::AttributeSet &opaqueColoredPoint2DWithSize();
TimelineItemsGeometry() : allocatedVertices(0), usedVertices(0), node(0) {
prevNode.set(0, TimelineModel::defaultRowHeight(), 0, 0, 0, 0, 0, 0);
}
......@@ -104,7 +76,7 @@ struct TimelineItemsGeometry {
OpaqueColoredPoint2DWithSize prevNode;
QSGGeometryNode *node;
OpaqueColoredPoint2DWithSize *vertexData();
void allocate(QSGMaterial *material);
void addVertices(float itemTop);
......@@ -112,14 +84,31 @@ struct TimelineItemsGeometry {
uchar green, uchar blue);
};
void OpaqueColoredPoint2DWithSize::set(float nx, float ny, float nw, float nh, float nid,
uchar nr, uchar ng, uchar nb) {
x = nx; y = ny; w = nw; h = nh; id = nid;
r = nr; g = ng, b = nb; a = 255;
}
float OpaqueColoredPoint2DWithSize::top() const
{
return y;
}
void OpaqueColoredPoint2DWithSize::setTop(float top)
{
y = top;
}
void TimelineItemsGeometry::addEvent(float itemLeft, float itemTop, float itemWidth,
float selectionId, uchar red, uchar green,
uchar blue)
{
float rowHeight = TimelineModel::defaultRowHeight();
float itemHeight = rowHeight - itemTop;
OpaqueColoredPoint2DWithSize *v = vertexData();
if (prevNode.y == rowHeight) {
OpaqueColoredPoint2DWithSize *v = OpaqueColoredPoint2DWithSize::fromVertexData(
node->geometry());
if (prevNode.top() == rowHeight) {
// "Z" form, bottom to top
v[usedVertices++].set(itemLeft, rowHeight, -itemWidth, -itemHeight, selectionId, red, green,
blue);
......@@ -131,7 +120,7 @@ void TimelineItemsGeometry::addEvent(float itemLeft, float itemTop, float itemWi
red, green, blue);
prevNode = v[usedVertices - 1];
} else {
if (prevNode.y != itemTop) {
if (prevNode.top() != itemTop) {
// 2 extra vertices to degenerate the surplus triangles
v[usedVertices++] = prevNode;
v[usedVertices++].set(itemLeft, itemTop, -itemWidth, itemHeight, selectionId, red,
......@@ -152,9 +141,8 @@ void TimelineItemsGeometry::addEvent(float itemLeft, float itemTop, float itemWi
}
OpaqueColoredPoint2DWithSize *TimelineItemsGeometry::vertexData()
OpaqueColoredPoint2DWithSize *OpaqueColoredPoint2DWithSize::fromVertexData(QSGGeometry *geometry)
{
QSGGeometry *geometry = node->geometry();
Q_ASSERT(geometry->attributeCount() == 4);
Q_ASSERT(geometry->sizeOfVertex() == sizeof(OpaqueColoredPoint2DWithSize));
const QSGGeometry::Attribute *attributes = geometry->attributes();
......@@ -171,12 +159,13 @@ OpaqueColoredPoint2DWithSize *TimelineItemsGeometry::vertexData()
Q_ASSERT(attributes[3].tupleSize == 4);
Q_ASSERT(attributes[3].type == GL_UNSIGNED_BYTE);
Q_UNUSED(attributes);
return static_cast<OpaqueColoredPoint2DWithSize *>(node->geometry()->vertexData());
return static_cast<OpaqueColoredPoint2DWithSize *>(geometry->vertexData());
}
void TimelineItemsGeometry::allocate(QSGMaterial *material)
{
QSGGeometry *geometry = new QSGGeometry(opaqueColoredPoint2DWithSize(), usedVertices);
QSGGeometry *geometry = new QSGGeometry(OpaqueColoredPoint2DWithSize::attributes(),
usedVertices);
geometry->setIndexDataPattern(QSGGeometry::StaticPattern);
geometry->setVertexDataPattern(QSGGeometry::StaticPattern);
node = new QSGGeometryNode;
......@@ -190,12 +179,12 @@ void TimelineItemsGeometry::allocate(QSGMaterial *material)
void TimelineItemsGeometry::addVertices(float itemTop)
{
if (prevNode.y == TimelineModel::defaultRowHeight()) {
if (prevNode.top() == TimelineModel::defaultRowHeight()) {
usedVertices += 4;
prevNode.y = itemTop;
prevNode.setTop(itemTop);
} else {
usedVertices += (prevNode.y != itemTop ? 6 : 4);
prevNode.y = TimelineModel::defaultRowHeight();
usedVertices += (prevNode.top() != itemTop ? 6 : 4);
prevNode.setTop(TimelineModel::defaultRowHeight());
}
}
......@@ -267,7 +256,7 @@ static void updateNodes(int from, int to, const TimelineModel *model,
}
}
const QSGGeometry::AttributeSet &TimelineItemsGeometry::opaqueColoredPoint2DWithSize()
const QSGGeometry::AttributeSet &OpaqueColoredPoint2DWithSize::attributes()
{
static QSGGeometry::Attribute data[] = {
QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
......@@ -455,12 +444,6 @@ QSGMaterialShader *TimelineItemsMaterial::createShader() const
return new TimelineItemsMaterialShader;
}
void OpaqueColoredPoint2DWithSize::set(float nx, float ny, float nw, float nh, float nid,
uchar nr, uchar ng, uchar nb) {
x = nx; y = ny; w = nw; h = nh; id = nid;
r = nr; g = ng, b = nb; a = 255;
}
TimelineItemsRenderPassState::TimelineItemsRenderPassState(const TimelineModel *model) :
m_indexFrom(std::numeric_limits<int>::max()), m_indexTo(-1)
{
......
......@@ -37,6 +37,43 @@
namespace Timeline {
class TimelineItemsMaterial : public QSGMaterial
{
public:
TimelineItemsMaterial();
QVector2D scale() const;
void setScale(QVector2D scale);
float selectedItem() const;
void setSelectedItem(float selectedItem);
QColor selectionColor() const;
void setSelectionColor(QColor selectionColor);
QSGMaterialType *type() const;
QSGMaterialShader *createShader() const;
private:
QVector2D m_scale;
float m_selectedItem;
QColor m_selectionColor;
};
class OpaqueColoredPoint2DWithSize
{
public:
void set(float nx, float ny, float nw, float nh, float nid, uchar nr, uchar ng, uchar nb);
float top() const;
void setTop(float top);
static const QSGGeometry::AttributeSet &attributes();
static OpaqueColoredPoint2DWithSize *fromVertexData(QSGGeometry *geometry);
private:
float x, y, w, h, id;
unsigned char r, g, b, a;
};
class TIMELINE_EXPORT TimelineItemsRenderPass : public TimelineRenderPass
{
public:
......
......@@ -28,23 +28,26 @@
**
****************************************************************************/
#include "timelineselectionrenderpass.h"
#include "timelineitemsrenderpass.h"
#include <QtMath>
#include <QSGSimpleRectNode>
namespace Timeline {
QSGSimpleRectNode *createSelectionNode()
QSGGeometryNode *createSelectionNode(QSGMaterial *material)
{
QSGSimpleRectNode *selectionNode = new QSGSimpleRectNode;
selectionNode->material()->setFlag(QSGMaterial::Blending, false);
selectionNode->setRect(0, 0, 0, 0);
QSGGeometryNode *selectionNode = new QSGGeometryNode;
selectionNode->setMaterial(material);
selectionNode->setFlag(QSGNode::OwnsMaterial, false);
QSGGeometry *geometry = new QSGGeometry(OpaqueColoredPoint2DWithSize::attributes(), 4);
geometry->setDrawingMode(GL_TRIANGLE_STRIP);
OpaqueColoredPoint2DWithSize *v = OpaqueColoredPoint2DWithSize::fromVertexData(geometry);
for (int i = 0; i < 4; ++i)
v[i].set(0, 0, 0, 0, 0, 0, 0, 0);
selectionNode->setGeometry(geometry);
selectionNode->setFlag(QSGNode::OwnsGeometry, true);
selectionNode->setFlag(QSGNode::OwnedByParent, false);
QSGSimpleRectNode *selectionChild = new QSGSimpleRectNode;
selectionChild->material()->setFlag(QSGMaterial::Blending, false);
selectionChild->setRect(0, 0, 0, 0);
selectionNode->appendChildNode(selectionChild);
return selectionNode;
}
......@@ -55,9 +58,12 @@ public:
QSGNode *expandedOverlay() const { return m_expandedOverlay; }
QSGNode *collapsedOverlay() const { return m_collapsedOverlay; }
TimelineItemsMaterial *material() { return &m_material; }
private:
QSGSimpleRectNode *m_expandedOverlay;
QSGSimpleRectNode *m_collapsedOverlay;
QSGNode *m_expandedOverlay;
QSGNode *m_collapsedOverlay;
TimelineItemsMaterial m_material;
};
TimelineRenderPass::State *TimelineSelectionRenderPass::update(
......@@ -77,12 +83,11 @@ TimelineRenderPass::State *TimelineSelectionRenderPass::update(
else
state = static_cast<TimelineSelectionRenderPassState *>(oldState);
QSGSimpleRectNode *selectionNode = static_cast<QSGSimpleRectNode *>(model->expanded() ?
state->expandedOverlay() :
state->collapsedOverlay());
QSGSimpleRectNode *child = static_cast<QSGSimpleRectNode *>(selectionNode->firstChild());
int selectedItem = renderer->selectedItem();
QSGGeometryNode *node = static_cast<QSGGeometryNode *>(model->expanded() ?
state->expandedOverlay() :
state->collapsedOverlay());
if (selectedItem != -1 && selectedItem >= firstIndex && selectedItem < lastIndex) {
qreal top = 0;
qreal height = 0;
......@@ -105,36 +110,36 @@ TimelineRenderPass::State *TimelineSelectionRenderPass::update(
// left and width the error on the left border is inherited by the right border. Like this
// they're independent.
QRectF outer(QPointF(left * parentState->scale(), top),
QRectF position(QPointF(left * parentState->scale(), top),
QPointF(right * parentState->scale(), top + height));
float scaleConversion = parentState->scale() / spacing;
float missing = 3.0 - outer.width() / scaleConversion;
if (missing > 0.0) {
outer.setLeft(outer.left() - missing * scaleConversion / 2.0);
outer.setRight(outer.right() + missing * scaleConversion / 2.0);
}
missing = 3.0 - outer.height();
if (missing > 0.0)
outer.setTop(outer.top() - missing);
selectionNode->setRect(outer);
selectionNode->setColor(renderer->selectionLocked() ? QColor(96,0,255) : Qt::blue);
float childWidthThreshold = 6.0 * scaleConversion;
if (outer.width() > childWidthThreshold && outer.height() > 6.0) {
// Construct from upper left and lower right for better precision
child->setRect(QRectF(QPointF(outer.left() + childWidthThreshold / 2.0,
outer.top() + 3.0),
QPointF(outer.right() - childWidthThreshold / 2.0,
outer.bottom() - 3.0)));
child->setColor(model->color(selectedItem));
} else {
child->setRect(0, 0, 0, 0);
}
QColor itemColor = model->color(selectedItem);
uchar red = itemColor.red();
uchar green = itemColor.green();
uchar blue = itemColor.blue();
int selectionId = model->selectionId(selectedItem);
OpaqueColoredPoint2DWithSize *v = OpaqueColoredPoint2DWithSize::fromVertexData(
node->geometry());
v[0].set(position.left(), position.bottom(), -position.width(), -position.height(),
selectionId, red, green, blue);
v[1].set(position.right(), position.bottom(), position.width(), -position.height(),
selectionId, red, green, blue);
v[2].set(position.left(), position.top(), -position.width(), position.height(),
selectionId, red, green, blue);
v[3].set(position.right(), position.top(), position.width(), position.height(),
selectionId, red, green, blue);
state->material()->setSelectionColor(renderer->selectionLocked() ? QColor(96,0,255) :
Qt::blue);
state->material()->setSelectedItem(selectionId);
state->material()->setScale(QVector2D(spacing / parentState->scale(), 1));
node->markDirty(QSGNode::DirtyMaterial | QSGNode::DirtyGeometry);
} else {
selectionNode->setRect(0, 0, 0, 0);
child->setRect(0, 0, 0, 0);
OpaqueColoredPoint2DWithSize *v = OpaqueColoredPoint2DWithSize::fromVertexData(
node->geometry());
for (int i = 0; i < 4; ++i)
v[i].set(0, 0, 0, 0, 0, 0, 0, 0);
node->markDirty(QSGNode::DirtyGeometry);
}
return state;
}
......@@ -150,8 +155,10 @@ TimelineSelectionRenderPass::TimelineSelectionRenderPass()
}
TimelineSelectionRenderPassState::TimelineSelectionRenderPassState() :
m_expandedOverlay(createSelectionNode()), m_collapsedOverlay(createSelectionNode())
m_expandedOverlay(0), m_collapsedOverlay(0)
{
m_expandedOverlay = createSelectionNode(&m_material);
m_collapsedOverlay = createSelectionNode(&m_material);
}
TimelineSelectionRenderPassState::~TimelineSelectionRenderPassState()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment