summaryrefslogtreecommitdiffstats
path: root/tests/auto/qtessellator/oldtessellator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qtessellator/oldtessellator.cpp')
-rw-r--r--tests/auto/qtessellator/oldtessellator.cpp446
1 files changed, 446 insertions, 0 deletions
diff --git a/tests/auto/qtessellator/oldtessellator.cpp b/tests/auto/qtessellator/oldtessellator.cpp
new file mode 100644
index 0000000..edfc1aa
--- /dev/null
+++ b/tests/auto/qtessellator/oldtessellator.cpp
@@ -0,0 +1,446 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "oldtessellator.h"
+#include <QPointF>
+#include <QVector>
+#include <QList>
+#include <QVariant>
+#include <QVarLengthArray>
+#include <qdebug.h>
+
+#include "limits.h"
+#include "utils.h"
+
+#include "qnum.h"
+#include "XrenderFake.h"
+
+/*
+ * Polygon tesselator - can probably be optimized a bit more
+ */
+
+//#define QT_DEBUG_TESSELATOR
+#define FloatToXFixed(i) (int)((i) * 65536)
+#define IntToXFixed(i) ((i) << 16)
+
+//inline int qrealToXFixed(qreal f)
+//{ return f << 8; }
+
+struct QEdge {
+ inline QEdge()
+ {}
+ inline QEdge(const QPointF &pt1,
+ const QPointF &pt2)
+ {
+ p1.x = XDoubleToFixed(pt1.x());
+ p1.y = XDoubleToFixed(pt1.y());
+ p2.x = XDoubleToFixed(pt2.x());
+ p2.y = XDoubleToFixed(pt2.y());
+ m = (pt1.x() - pt2.x()) ? (pt1.y() - pt2.y()) / (pt1.x() - pt2.x()) : 0;
+ im = m ? 1/m : 0;
+ b = pt1.y() - m * pt1.x();
+ vertical = p1.x == p2.x;
+ horizontal = p1.y == p2.y;
+ }
+
+ inline qreal xAt(const qreal &y) const
+ {
+ Q_ASSERT(p1.y != p2.y);
+ XFixed yf = XDoubleToFixed(y);
+
+ if (yf == p1.y)
+ return XFixedToDouble(p1.x);
+ else if (yf == p2.y)
+ return XFixedToDouble(p2.x);
+
+ return (!vertical) ? (((y - b)*im)) : pf1.x();
+ }
+
+ QPointF pf1, pf2;
+ XPointFixed p1, p2;
+ qreal m;
+ qreal im;
+ qreal b;
+ qreal intersection;
+ signed short winding;
+ bool vertical;
+ bool horizontal;
+};
+
+struct QVrtx {
+ typedef QList<QEdge> Edges;
+ XPointFixed coords;
+ Edges startingEdges;
+ Edges endingEdges;
+ Edges intersectingEdges;
+};
+
+struct QIntersectionPoint {
+ qreal x;
+ const QEdge *edge;
+};
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(QEdge, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(QVrtx, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(QIntersectionPoint, Q_PRIMITIVE_TYPE);
+QT_END_NAMESPACE
+
+
+// used by the edge point sort algorithm
+static qreal currentY = 0.f;
+
+static inline bool compareEdges(const QEdge *e1, const QEdge *e2)
+{
+ return e1->p1.y < e2->p1.y;
+}
+
+static inline bool isEqual(const XPointFixed &p1, const XPointFixed &p2)
+{
+ return ((p1.x == p2.x) && (p1.y == p2.y));
+}
+
+static inline bool compareIntersections(const QIntersectionPoint &i1, const QIntersectionPoint &i2)
+{
+ if (qAbs(i1.x - i2.x) > 0.01) { // x != other.x in 99% of the cases
+ return i1.x < i2.x;
+ } else {
+ qreal x1 = (i1.edge->p1.x != i1.edge->p2.x) ?
+ ((currentY+1 - i1.edge->b)*i1.edge->m) : XFixedToDouble(i1.edge->p1.x);
+ qreal x2 = (i2.edge->p1.x != i2.edge->p2.x) ?
+ ((currentY+1 - i2.edge->b)*i2.edge->m) : XFixedToDouble(i2.edge->p1.x);
+// qDebug() << ">>>" << currentY << i1.edge << i2.edge << x1 << x2;
+ return x1 < x2;
+ }
+}
+
+#ifdef QT_USE_FIXED_POINT
+inline int qrealToXFixed(qreal f)
+{ return f.value() << 8; }
+#else
+#define qrealToXFixed FloatToXFixed
+#endif
+
+static XTrapezoid QT_FASTCALL toXTrapezoid(XFixed y1, XFixed y2, const QEdge &left, const QEdge &right)
+{
+ XTrapezoid trap;
+ trap.top = y1;
+ trap.bottom = y2;
+ trap.left.p1.y = left.p1.y;
+ trap.left.p2.y = left.p2.y;
+ trap.right.p1.y = right.p1.y;
+ trap.right.p2.y = right.p2.y;
+ trap.left.p1.x = left.p1.x;
+ trap.left.p2.x = left.p2.x;
+ trap.right.p1.x = right.p1.x;
+ trap.right.p2.x = right.p2.x;
+ return trap;
+}
+
+#ifdef QT_DEBUG_TESSELATOR
+static void dump_edges(const QList<const QEdge *> &et)
+{
+ for (int x = 0; x < et.size(); ++x) {
+ qDebug() << "edge#" << x << et.at(x) << "("
+ << XFixedToDouble(et.at(x)->p1.x)
+ << XFixedToDouble(et.at(x)->p1.y)
+ << ") ("
+ << XFixedToDouble(et.at(x)->p2.x)
+ << XFixedToDouble(et.at(x)->p2.y)
+ << ") b: " << et.at(x)->b << "m:" << et.at(x)->m;
+ }
+}
+
+static void dump_trap(const XTrapezoid &t)
+{
+ qDebug() << "trap# t=" << t.top/65536.0 << "b=" << t.bottom/65536.0 << "h="
+ << XFixedToDouble(t.bottom - t.top) << "\tleft p1: ("
+ << XFixedToDouble(t.left.p1.x) << ","<< XFixedToDouble(t.left.p1.y)
+ << ")" << "\tleft p2: (" << XFixedToDouble(t.left.p2.x) << ","
+ << XFixedToDouble(t.left.p2.y) << ")" << "\n\t\t\t\tright p1:("
+ << XFixedToDouble(t.right.p1.x) << "," << XFixedToDouble(t.right.p1.y) << ")"
+ << "\tright p2:(" << XFixedToDouble(t.right.p2.x) << ","
+ << XFixedToDouble(t.right.p2.y) << ")";
+}
+#endif
+
+
+typedef int Q27Dot5;
+#define Q27Dot5ToDouble(i) (i/32.)
+#define FloatToQ27Dot5(i) (int)((i) * 32)
+#define IntToQ27Dot5(i) ((i) << 5)
+#define Q27Dot5ToXFixed(i) ((i) << 11)
+#define Q27Dot5Factor 32
+
+void old_tesselate_polygon(QVector<XTrapezoid> *traps, const QPointF *pg, int pgSize,
+ bool winding)
+{
+ QVector<QEdge> edges;
+ edges.reserve(128);
+ qreal ymin(INT_MAX/256);
+ qreal ymax(INT_MIN/256);
+
+ //painter.begin(pg, pgSize);
+ Q_ASSERT(pg[0] == pg[pgSize-1]);
+ // generate edge table
+// qDebug() << "POINTS:";
+ for (int x = 0; x < pgSize-1; ++x) {
+ QEdge edge;
+ QPointF p1(Q27Dot5ToDouble(FloatToQ27Dot5(pg[x].x())),
+ Q27Dot5ToDouble(FloatToQ27Dot5(pg[x].y())));
+ QPointF p2(Q27Dot5ToDouble(FloatToQ27Dot5(pg[x+1].x())),
+ Q27Dot5ToDouble(FloatToQ27Dot5(pg[x+1].y())));
+
+// qDebug() << " "
+// << p1;
+ edge.winding = p1.y() > p2.y() ? 1 : -1;
+ if (edge.winding > 0)
+ qSwap(p1, p2);
+ edge.p1.x = XDoubleToFixed(p1.x());
+ edge.p1.y = XDoubleToFixed(p1.y());
+ edge.p2.x = XDoubleToFixed(p2.x());
+ edge.p2.y = XDoubleToFixed(p2.y());
+
+ edge.m = (p1.y() - p2.y()) / (p1.x() - p2.x()); // line derivative
+ edge.b = p1.y() - edge.m * p1.x(); // intersection with y axis
+ edge.m = edge.m != 0.0 ? 1.0 / edge.m : 0.0; // inverted derivative
+ edges.append(edge);
+ ymin = qMin(ymin, qreal(XFixedToDouble(edge.p1.y)));
+ ymax = qMax(ymax, qreal(XFixedToDouble(edge.p2.y)));
+ }
+
+ QList<const QEdge *> et; // edge list
+ for (int i = 0; i < edges.size(); ++i)
+ et.append(&edges.at(i));
+
+ // sort edge table by min y value
+ qSort(et.begin(), et.end(), compareEdges);
+
+ // eliminate shared edges
+ for (int i = 0; i < et.size(); ++i) {
+ for (int k = i+1; k < et.size(); ++k) {
+ const QEdge *edgeI = et.at(i);
+ const QEdge *edgeK = et.at(k);
+ if (edgeK->p1.y > edgeI->p1.y)
+ break;
+ if (edgeI->winding != edgeK->winding &&
+ isEqual(edgeI->p1, edgeK->p1) && isEqual(edgeI->p2, edgeK->p2)
+ ) {
+ et.removeAt(k);
+ et.removeAt(i);
+ --i;
+ break;
+ }
+ }
+ }
+
+ if (ymax <= ymin)
+ return;
+ QList<const QEdge *> aet; // edges that intersects the current scanline
+
+// if (ymin < 0)
+// ymin = 0;
+// if (paintEventClipRegion) // don't scan more lines than we have to
+// ymax = paintEventClipRegion->boundingRect().height();
+
+#ifdef QT_DEBUG_TESSELATOR
+ qDebug("==> ymin = %f, ymax = %f", ymin, ymax);
+#endif // QT_DEBUG_TESSELATOR
+
+ currentY = ymin; // used by the less than op
+ for (qreal y = ymin; y < ymax;) {
+ // fill active edge table with edges that intersect the current line
+ for (int i = 0; i < et.size(); ++i) {
+ const QEdge *edge = et.at(i);
+ if (edge->p1.y > XDoubleToFixed(y))
+ break;
+ aet.append(edge);
+ et.removeAt(i);
+ --i;
+ }
+
+ // remove processed edges from active edge table
+ for (int i = 0; i < aet.size(); ++i) {
+ if (aet.at(i)->p2.y <= XDoubleToFixed(y)) {
+ aet.removeAt(i);
+ --i;
+ }
+ }
+ if (aet.size()%2 != 0) {
+#ifndef QT_NO_DEBUG
+ qWarning("QX11PaintEngine: aet out of sync - this should not happen.");
+#endif
+ return;
+ }
+
+ // done?
+ if (!aet.size()) {
+ if (!et.size()) {
+ break;
+ } else {
+ y = currentY = XFixedToDouble(et.at(0)->p1.y);
+ continue;
+ }
+ }
+
+ // calculate the next y where we have to start a new set of trapezoids
+ qreal next_y(INT_MAX/256);
+ for (int i = 0; i < aet.size(); ++i) {
+ const QEdge *edge = aet.at(i);
+ if (XFixedToDouble(edge->p2.y) < next_y)
+ next_y = XFixedToDouble(edge->p2.y);
+ }
+
+ if (et.size() && next_y > XFixedToDouble(et.at(0)->p1.y))
+ next_y = XFixedToDouble(et.at(0)->p1.y);
+
+ int aetSize = aet.size();
+ for (int i = 0; i < aetSize; ++i) {
+ for (int k = i+1; k < aetSize; ++k) {
+ const QEdge *edgeI = aet.at(i);
+ const QEdge *edgeK = aet.at(k);
+ qreal m1 = edgeI->m;
+ qreal b1 = edgeI->b;
+ qreal m2 = edgeK->m;
+ qreal b2 = edgeK->b;
+
+ if (qAbs(m1 - m2) < 0.001)
+ continue;
+
+ // ### intersect is not calculated correctly when optimized with -O2 (gcc)
+ volatile qreal intersect = 0;
+ if (!qIsFinite(b1))
+ intersect = (1.f / m2) * XFixedToDouble(edgeI->p1.x) + b2;
+ else if (!qIsFinite(b2))
+ intersect = (1.f / m1) * XFixedToDouble(edgeK->p1.x) + b1;
+ else
+ intersect = (b1*m1 - b2*m2) / (m1 - m2);
+
+ if (intersect > y && intersect < next_y)
+ next_y = intersect;
+ }
+ }
+
+ XFixed yf, next_yf;
+ yf = qrealToXFixed(y);
+ next_yf = qrealToXFixed(next_y);
+
+ if (yf == next_yf) {
+ y = currentY = next_y;
+ continue;
+ }
+
+#ifdef QT_DEBUG_TESSELATOR
+ qDebug("###> y = %f, next_y = %f, %d active edges", y, next_y, aet.size());
+ qDebug("===> edges");
+ dump_edges(et);
+ qDebug("===> active edges");
+ dump_edges(aet);
+#endif
+ // calc intersection points
+ QVarLengthArray<QIntersectionPoint> isects(aet.size()+1);
+ for (int i = 0; i < isects.size()-1; ++i) {
+ const QEdge *edge = aet.at(i);
+ isects[i].x = (edge->p1.x != edge->p2.x) ?
+ ((y - edge->b)*edge->m) : XFixedToDouble(edge->p1.x);
+ isects[i].edge = edge;
+ }
+
+ Q_ASSERT(isects.size()%2 == 1);
+
+ // sort intersection points
+ qSort(&isects[0], &isects[isects.size()-1], compareIntersections);
+// qDebug() << "INTERSECTION_POINTS:";
+// for (int i = 0; i < isects.size(); ++i)
+// qDebug() << isects[i].edge << isects[i].x;
+
+ if (winding) {
+ // winding fill rule
+ for (int i = 0; i < isects.size()-1;) {
+ int winding = 0;
+ const QEdge *left = isects[i].edge;
+ const QEdge *right = 0;
+ winding += isects[i].edge->winding;
+ for (++i; i < isects.size()-1 && winding != 0; ++i) {
+ winding += isects[i].edge->winding;
+ right = isects[i].edge;
+ }
+ if (!left || !right)
+ break;
+ //painter.addTrapezoid(&toXTrapezoid(yf, next_yf, *left, *right));
+ traps->append(toXTrapezoid(yf, next_yf, *left, *right));
+ }
+ } else {
+ // odd-even fill rule
+ for (int i = 0; i < isects.size()-2; i += 2) {
+ //painter.addTrapezoid(&toXTrapezoid(yf, next_yf, *isects[i].edge, *isects[i+1].edge));
+ traps->append(toXTrapezoid(yf, next_yf, *isects[i].edge, *isects[i+1].edge));
+ }
+ }
+ y = currentY = next_y;
+ }
+
+#ifdef QT_DEBUG_TESSELATOR
+ qDebug("==> number of trapezoids: %d - edge table size: %d\n", traps->size(), et.size());
+
+ for (int i = 0; i < traps->size(); ++i)
+ dump_trap(traps->at(i));
+#endif
+
+ // optimize by unifying trapezoids that share left/right lines
+ // and have a common top/bottom edge
+// for (int i = 0; i < tps.size(); ++i) {
+// for (int k = i+1; k < tps.size(); ++k) {
+// if (i != k && tps.at(i).right == tps.at(k).right
+// && tps.at(i).left == tps.at(k).left
+// && (tps.at(i).top == tps.at(k).bottom
+// || tps.at(i).bottom == tps.at(k).top))
+// {
+// tps[i].bottom = tps.at(k).bottom;
+// tps.removeAt(k);
+// i = 0;
+// break;
+// }
+// }
+// }
+ //static int i = 0;
+ //QImage img = painter.end();
+ //img.save(QString("res%1.png").arg(i++), "PNG");
+}