From 78169e6b06db136037b70c99ca46b82d4c311c3e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 19 Aug 2011 09:27:51 +0200 Subject: [PATCH] Remove qtessellator.* from QtGui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's now unused since the GL1 paintengine is gone. Change-Id: I1415b725dc05aab920670976a8eb8c3145464297 Reviewed-on: http://codereview.qt.nokia.com/3246 Reviewed-by: Qt Sanity Bot Reviewed-by: Samuel Rødal --- src/gui/painting/painting.pri | 2 - src/gui/painting/qtessellator.cpp | 1498 ----------------------------- src/gui/painting/qtessellator_p.h | 102 -- 3 files changed, 1602 deletions(-) delete mode 100644 src/gui/painting/qtessellator.cpp delete mode 100644 src/gui/painting/qtessellator_p.h diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index e033226dd8..1481cb8520 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -31,7 +31,6 @@ HEADERS += \ painting/qrasterizer_p.h \ painting/qregion.h \ painting/qstroker_p.h \ - painting/qtessellator_p.h \ painting/qtextureglyphcache_p.h \ painting/qtransform.h \ painting/qplatformbackingstore_qpa.h \ @@ -66,7 +65,6 @@ SOURCES += \ painting/qrasterizer.cpp \ painting/qregion.cpp \ painting/qstroker.cpp \ - painting/qtessellator.cpp \ painting/qtextureglyphcache.cpp \ painting/qtransform.cpp \ painting/qplatformbackingstore_qpa.cpp \ diff --git a/src/gui/painting/qtessellator.cpp b/src/gui/painting/qtessellator.cpp deleted file mode 100644 index c46943854d..0000000000 --- a/src/gui/painting/qtessellator.cpp +++ /dev/null @@ -1,1498 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtessellator_p.h" - -#include -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -//#define DEBUG -#ifdef DEBUG -#define QDEBUG qDebug -#else -#define QDEBUG if (1){} else qDebug -#endif - -static const bool emit_clever = true; -static const bool mark_clever = false; - -enum VertexFlags { - LineBeforeStarts = 0x1, - LineBeforeEnds = 0x2, - LineBeforeHorizontal = 0x4, - LineAfterStarts = 0x8, - LineAfterEnds = 0x10, - LineAfterHorizontal = 0x20 -}; - - - -class QTessellatorPrivate { -public: - struct Vertices; - - QTessellatorPrivate() {} - - QRectF collectAndSortVertices(const QPointF *points, int *maxActiveEdges); - void cancelCoincidingEdges(); - - void emitEdges(QTessellator *tessellator); - void processIntersections(); - void removeEdges(); - void addEdges(); - void addIntersections(); - - struct Vertex : public QTessellator::Vertex - { - int flags; - }; - - struct Intersection - { - Q27Dot5 y; - int edge; - bool operator <(const Intersection &other) const { - if (y != other.y) - return y < other.y; - return edge < other.edge; - } - }; - struct IntersectionLink - { - int next; - int prev; - }; - typedef QMap Intersections; - - struct Edge { - Edge(const Vertices &v, int _edge); - int edge; - const Vertex *v0; - const Vertex *v1; - Q27Dot5 y_left; - Q27Dot5 y_right; - signed int winding : 8; - bool mark; - bool free; - bool intersect_left; - bool intersect_right; - bool isLeftOf(const Edge &other, Q27Dot5 y) const; - Q27Dot5 positionAt(Q27Dot5 y) const; - bool intersect(const Edge &other, Q27Dot5 *y, bool *det_positive) const; - - }; - - class EdgeSorter - { - public: - EdgeSorter(int _y) : y(_y) {} - bool operator() (const Edge *e1, const Edge *e2); - int y; - }; - - class Scanline { - public: - Scanline(); - ~Scanline(); - - void init(int maxActiveEdges); - void done(); - - int findEdgePosition(Q27Dot5 x, Q27Dot5 y) const; - int findEdgePosition(const Edge &e) const; - int findEdge(int edge) const; - void clearMarks(); - - void swap(int p1, int p2) { - Edge *tmp = edges[p1]; - edges[p1] = edges[p2]; - edges[p2] = tmp; - } - void insert(int pos, const Edge &e); - void removeAt(int pos); - void markEdges(int pos1, int pos2); - - void prepareLine(); - void lineDone(); - - Edge **old; - int old_size; - - Edge **edges; - int size; - - private: - Edge *edge_table; - int first_unused; - int max_edges; - enum { default_alloc = 32 }; - }; - - struct Vertices { - enum { default_alloc = 128 }; - Vertices(); - ~Vertices(); - void init(int maxVertices); - void done(); - Vertex *storage; - Vertex **sorted; - - Vertex *operator[] (int i) { return storage + i; } - const Vertex *operator[] (int i) const { return storage + i; } - int position(const Vertex *v) const { - return v - storage; - } - Vertex *next(Vertex *v) { - ++v; - if (v == storage + nPoints) - v = storage; - return v; - } - const Vertex *next(const Vertex *v) const { - ++v; - if (v == storage + nPoints) - v = storage; - return v; - } - int nextPos(const Vertex *v) const { - ++v; - if (v == storage + nPoints) - return 0; - return v - storage; - } - Vertex *prev(Vertex *v) { - if (v == storage) - v = storage + nPoints; - --v; - return v; - } - const Vertex *prev(const Vertex *v) const { - if (v == storage) - v = storage + nPoints; - --v; - return v; - } - int prevPos(const Vertex *v) const { - if (v == storage) - v = storage + nPoints; - --v; - return v - storage; - } - int nPoints; - int allocated; - }; - Vertices vertices; - Intersections intersections; - Scanline scanline; - bool winding; - Q27Dot5 y; - int currentVertex; - -private: - void addIntersection(const Edge *e1, const Edge *e2); - bool edgeInChain(Intersection i, int edge); -}; - - -QTessellatorPrivate::Edge::Edge(const QTessellatorPrivate::Vertices &vertices, int edge) -{ - this->edge = edge; - intersect_left = intersect_right = true; - mark = false; - free = false; - - v0 = vertices[edge]; - v1 = vertices.next(v0); - - Q_ASSERT(v0->y != v1->y); - - if (v0->y > v1->y) { - qSwap(v0, v1); - winding = -1; - } else { - winding = 1; - } - y_left = y_right = v0->y; -} - -// This is basically the algorithm from graphics gems. The algorithm -// is cubic in the coordinates at one place. Since we use 64bit -// integers, this implies, that the allowed range for our coordinates -// is limited to 21 bits. With 5 bits behind the decimal, this -// implies that differences in coordaintes can range from 2*SHORT_MIN -// to 2*SHORT_MAX, giving us efficiently a coordinate system from -// SHORT_MIN to SHORT_MAX. -// - -// WARNING: It's absolutely critical that the intersect() and isLeftOf() methods use -// exactly the same algorithm to calulate yi. It's also important to be sure the algorithms -// are transitive (ie. the conditions below are true for all input data): -// -// a.intersect(b) == b.intersect(a) -// a.isLeftOf(b) != b.isLeftOf(a) -// -// This is tricky to get right, so be very careful when changing anything in here! - -static inline bool sameSign(qint64 a, qint64 b) { - return (((qint64) ((quint64) a ^ (quint64) b)) >= 0 ); -} - -bool QTessellatorPrivate::Edge::intersect(const Edge &other, Q27Dot5 *y, bool *det_positive) const -{ - qint64 a1 = v1->y - v0->y; - qint64 b1 = v0->x - v1->x; - - qint64 a2 = other.v1->y - other.v0->y; - qint64 b2 = other.v0->x - other.v1->x; - - qint64 det = a1 * b2 - a2 * b1; - if (det == 0) - return false; - - qint64 c1 = qint64(v1->x) * v0->y - qint64(v0->x) * v1->y; - - qint64 r3 = a1 * other.v0->x + b1 * other.v0->y + c1; - qint64 r4 = a1 * other.v1->x + b1 * other.v1->y + c1; - - // Check signs of r3 and r4. If both point 3 and point 4 lie on - // same side of line 1, the line segments do not intersect. - QDEBUG() << " " << r3 << r4; - if (r3 != 0 && r4 != 0 && sameSign( r3, r4 )) - return false; - - qint64 c2 = qint64(other.v1->x) * other.v0->y - qint64(other.v0->x) * other.v1->y; - - qint64 r1 = a2 * v0->x + b2 * v0->y + c2; - qint64 r2 = a2 * v1->x + b2 * v1->y + c2; - - // Check signs of r1 and r2. If both point 1 and point 2 lie - // on same side of second line segment, the line segments do not intersect. - QDEBUG() << " " << r1 << r2; - if (r1 != 0 && r2 != 0 && sameSign( r1, r2 )) - return false; - - // The det/2 is to get rounding instead of truncating. It - // is added or subtracted to the numerator, depending upon the - // sign of the numerator. - qint64 offset = det < 0 ? -det : det; - offset >>= 1; - - qint64 num = a2 * c1 - a1 * c2; - *y = ( num < 0 ? num - offset : num + offset ) / det; - - *det_positive = (det > 0); - - return true; -} - -#undef SAME_SIGNS - -bool QTessellatorPrivate::Edge::isLeftOf(const Edge &other, Q27Dot5 y) const -{ -// QDEBUG() << "isLeftOf" << edge << other.edge << y; - qint64 a1 = v1->y - v0->y; - qint64 b1 = v0->x - v1->x; - qint64 a2 = other.v1->y - other.v0->y; - qint64 b2 = other.v0->x - other.v1->x; - - qint64 c2 = qint64(other.v1->x) * other.v0->y - qint64(other.v0->x) * other.v1->y; - - qint64 det = a1 * b2 - a2 * b1; - if (det == 0) { - // lines are parallel. Only need to check side of one point - // fixed ordering for coincident edges - qint64 r1 = a2 * v0->x + b2 * v0->y + c2; -// QDEBUG() << "det = 0" << r1; - if (r1 == 0) - return edge < other.edge; - return (r1 < 0); - } - - // not parallel, need to find the y coordinate of the intersection point - qint64 c1 = qint64(v1->x) * v0->y - qint64(v0->x) * v1->y; - - qint64 offset = det < 0 ? -det : det; - offset >>= 1; - - qint64 num = a2 * c1 - a1 * c2; - qint64 yi = ( num < 0 ? num - offset : num + offset ) / det; -// QDEBUG() << " num=" << num << "offset=" << offset << "det=" << det; - - return ((yi > y) ^ (det < 0)); -} - -static inline bool compareVertex(const QTessellatorPrivate::Vertex *p1, - const QTessellatorPrivate::Vertex *p2) -{ - if (p1->y == p2->y) { - if (p1->x == p2->x) - return p1 < p2; - return p1->x < p2->x; - } - return p1->y < p2->y; -} - -Q27Dot5 QTessellatorPrivate::Edge::positionAt(Q27Dot5 y) const -{ - if (y == v0->y) - return v0->x; - else if (y == v1->y) - return v1->x; - - qint64 d = v1->x - v0->x; - return (v0->x + d*(y - v0->y)/(v1->y-v0->y)); -} - -bool QTessellatorPrivate::EdgeSorter::operator() (const Edge *e1, const Edge *e2) -{ - return e1->isLeftOf(*e2, y); -} - - -QTessellatorPrivate::Scanline::Scanline() -{ - edges = 0; - edge_table = 0; - old = 0; -} - -void QTessellatorPrivate::Scanline::init(int maxActiveEdges) -{ - maxActiveEdges *= 2; - if (!edges || maxActiveEdges > default_alloc) { - max_edges = maxActiveEdges; - int s = qMax(maxActiveEdges + 1, default_alloc + 1); - edges = q_check_ptr((Edge **)realloc(edges, s*sizeof(Edge *))); - edge_table = q_check_ptr((Edge *)realloc(edge_table, s*sizeof(Edge))); - old = q_check_ptr((Edge **)realloc(old, s*sizeof(Edge *))); - } - size = 0; - old_size = 0; - first_unused = 0; - for (int i = 0; i < maxActiveEdges; ++i) - edge_table[i].edge = i+1; - edge_table[maxActiveEdges].edge = -1; -} - -void QTessellatorPrivate::Scanline::done() -{ - if (max_edges > default_alloc) { - free(edges); - free(old); - free(edge_table); - edges = 0; - old = 0; - edge_table = 0; - } -} - -QTessellatorPrivate::Scanline::~Scanline() -{ - free(edges); - free(old); - free(edge_table); -} - -int QTessellatorPrivate::Scanline::findEdgePosition(Q27Dot5 x, Q27Dot5 y) const -{ - int min = 0; - int max = size - 1; - while (min < max) { - int pos = min + ((max - min + 1) >> 1); - Q27Dot5 ax = edges[pos]->positionAt(y); - if (ax > x) { - max = pos - 1; - } else { - min = pos; - } - } - return min; -} - -int QTessellatorPrivate::Scanline::findEdgePosition(const Edge &e) const -{ -// qDebug() << ">> findEdgePosition"; - int min = 0; - int max = size; - while (min < max) { - int pos = min + ((max - min) >> 1); -// qDebug() << " " << min << max << pos << edges[pos]->isLeftOf(e, e.y0); - if (edges[pos]->isLeftOf(e, e.v0->y)) { - min = pos + 1; - } else { - max = pos; - } - } -// qDebug() << "<< findEdgePosition got" << min; - return min; -} - -int QTessellatorPrivate::Scanline::findEdge(int edge) const -{ - for (int i = 0; i < size; ++i) { - int item_edge = edges[i]->edge; - if (item_edge == edge) - return i; - } - //Q_ASSERT(false); - return -1; -} - -void QTessellatorPrivate::Scanline::clearMarks() -{ - for (int i = 0; i < size; ++i) { - edges[i]->mark = false; - edges[i]->intersect_left = false; - edges[i]->intersect_right = false; - } -} - -void QTessellatorPrivate::Scanline::prepareLine() -{ - Edge **end = edges + size; - Edge **e = edges; - Edge **o = old; - while (e < end) { - *o = *e; - ++o; - ++e; - } - old_size = size; -} - -void QTessellatorPrivate::Scanline::lineDone() -{ - Edge **end = old + old_size; - Edge **e = old; - while (e < end) { - if ((*e)->free) { - (*e)->edge = first_unused; - first_unused = (*e - edge_table); - } - ++e; - } -} - -void QTessellatorPrivate::Scanline::insert(int pos, const Edge &e) -{ - Edge *edge = edge_table + first_unused; - first_unused = edge->edge; - Q_ASSERT(first_unused != -1); - *edge = e; - memmove(edges + pos + 1, edges + pos, (size - pos)*sizeof(Edge *)); - edges[pos] = edge; - ++size; -} - -void QTessellatorPrivate::Scanline::removeAt(int pos) -{ - Edge *e = edges[pos]; - e->free = true; - --size; - memmove(edges + pos, edges + pos + 1, (size - pos)*sizeof(Edge *)); -} - -void QTessellatorPrivate::Scanline::markEdges(int pos1, int pos2) -{ - if (pos2 < pos1) - return; - - for (int i = pos1; i <= pos2; ++i) - edges[i]->mark = true; -} - - -QTessellatorPrivate::Vertices::Vertices() -{ - storage = 0; - sorted = 0; - allocated = 0; - nPoints = 0; -} - -QTessellatorPrivate::Vertices::~Vertices() -{ - if (storage) { - free(storage); - free(sorted); - } -} - -void QTessellatorPrivate::Vertices::init(int maxVertices) -{ - if (!storage || maxVertices > allocated) { - int size = qMax((int)default_alloc, maxVertices); - storage = q_check_ptr((Vertex *)realloc(storage, size*sizeof(Vertex))); - sorted = q_check_ptr((Vertex **)realloc(sorted, size*sizeof(Vertex *))); - allocated = maxVertices; - } -} - -void QTessellatorPrivate::Vertices::done() -{ - if (allocated > default_alloc) { - free(storage); - free(sorted); - storage = 0; - sorted = 0; - allocated = 0; - } -} - - - -static inline void fillTrapezoid(Q27Dot5 y1, Q27Dot5 y2, int left, int right, - const QTessellatorPrivate::Vertices &vertices, - QTessellator::Trapezoid *trap) -{ - trap->top = y1; - trap->bottom = y2; - const QTessellatorPrivate::Vertex *v = vertices[left]; - trap->topLeft = v; - trap->bottomLeft = vertices.next(v); - if (trap->topLeft->y > trap->bottomLeft->y) - qSwap(trap->topLeft,trap->bottomLeft); - v = vertices[right]; - trap->topRight = v; - trap->bottomRight = vertices.next(v); - if (trap->topRight->y > trap->bottomRight->y) - qSwap(trap->topRight, trap->bottomRight); -} - -QRectF QTessellatorPrivate::collectAndSortVertices(const QPointF *points, int *maxActiveEdges) -{ - *maxActiveEdges = 0; - Vertex *v = vertices.storage; - Vertex **vv = vertices.sorted; - - qreal xmin(points[0].x()); - qreal xmax(points[0].x()); - qreal ymin(points[0].y()); - qreal ymax(points[0].y()); - - // collect vertex data - Q27Dot5 y_prev = FloatToQ27Dot5(points[vertices.nPoints-1].y()); - Q27Dot5 x_next = FloatToQ27Dot5(points[0].x()); - Q27Dot5 y_next = FloatToQ27Dot5(points[0].y()); - int j = 0; - int i = 0; - while (i < vertices.nPoints) { - Q27Dot5 y_curr = y_next; - - *vv = v; - - v->x = x_next; - v->y = y_next; - v->flags = 0; - - next_point: - - xmin = qMin(xmin, points[i+1].x()); - xmax = qMax(xmax, points[i+1].x()); - ymin = qMin(ymin, points[i+1].y()); - ymax = qMax(ymax, points[i+1].y()); - - y_next = FloatToQ27Dot5(points[i+1].y()); - x_next = FloatToQ27Dot5(points[i+1].x()); - - // skip vertices on top of each other - if (v->x == x_next && v->y == y_next) { - ++i; - if (i < vertices.nPoints) - goto next_point; - Vertex *v0 = vertices.storage; - v0->flags &= ~(LineBeforeStarts|LineBeforeEnds|LineBeforeHorizontal); - if (y_prev < y_curr) - v0->flags |= LineBeforeEnds; - else if (y_prev > y_curr) - v0->flags |= LineBeforeStarts; - else - v0->flags |= LineBeforeHorizontal; - if ((v0->flags & (LineBeforeStarts|LineAfterStarts)) - && !(v0->flags & (LineAfterEnds|LineBeforeEnds))) - *maxActiveEdges += 2; - break; - } - - if (y_prev < y_curr) - v->flags |= LineBeforeEnds; - else if (y_prev > y_curr) - v->flags |= LineBeforeStarts; - else - v->flags |= LineBeforeHorizontal; - - - if (y_curr < y_next) - v->flags |= LineAfterStarts; - else if (y_curr > y_next) - v->flags |= LineAfterEnds; - else - v->flags |= LineAfterHorizontal; - // ### could probably get better limit by looping over sorted list and counting down on ending edges - if ((v->flags & (LineBeforeStarts|LineAfterStarts)) - && !(v->flags & (LineAfterEnds|LineBeforeEnds))) - *maxActiveEdges += 2; - y_prev = y_curr; - ++v; - ++vv; - ++j; - ++i; - } - vertices.nPoints = j; - - QDEBUG() << "maxActiveEdges=" << *maxActiveEdges; - vv = vertices.sorted; - qSort(vv, vv + vertices.nPoints, compareVertex); - - return QRectF(xmin, ymin, xmax-xmin, ymax-ymin); -} - -struct QCoincidingEdge { - QTessellatorPrivate::Vertex *start; - QTessellatorPrivate::Vertex *end; - bool used; - bool before; - - inline bool operator<(const QCoincidingEdge &e2) const - { - return end->y == e2.end->y ? end->x < e2.end->x : end->y < e2.end->y; - } -}; - -static void cancelEdges(QCoincidingEdge &e1, QCoincidingEdge &e2) -{ - if (e1.before) { - e1.start->flags &= ~(LineBeforeStarts|LineBeforeHorizontal); - e1.end->flags &= ~(LineAfterEnds|LineAfterHorizontal); - } else { - e1.start->flags &= ~(LineAfterStarts|LineAfterHorizontal); - e1.end->flags &= ~(LineBeforeEnds|LineBeforeHorizontal); - } - if (e2.before) { - e2.start->flags &= ~(LineBeforeStarts|LineBeforeHorizontal); - e2.end->flags &= ~(LineAfterEnds|LineAfterHorizontal); - } else { - e2.start->flags &= ~(LineAfterStarts|LineAfterHorizontal); - e2.end->flags &= ~(LineBeforeEnds|LineBeforeHorizontal); - } - e1.used = e2.used = true; -} - -void QTessellatorPrivate::cancelCoincidingEdges() -{ - Vertex **vv = vertices.sorted; - - QCoincidingEdge *tl = 0; - int tlSize = 0; - - for (int i = 0; i < vertices.nPoints - 1; ++i) { - Vertex *v = vv[i]; - int testListSize = 0; - while (i < vertices.nPoints - 1) { - Vertex *n = vv[i]; - if (v->x != n->x || v->y != n->y) - break; - - if (testListSize > tlSize - 2) { - tlSize = qMax(tlSize*2, 16); - tl = q_check_ptr((QCoincidingEdge *)realloc(tl, tlSize*sizeof(QCoincidingEdge))); - } - if (n->flags & (LineBeforeStarts|LineBeforeHorizontal)) { - tl[testListSize].start = n; - tl[testListSize].end = vertices.prev(n); - tl[testListSize].used = false; - tl[testListSize].before = true; - ++testListSize; - } - if (n->flags & (LineAfterStarts|LineAfterHorizontal)) { - tl[testListSize].start = n; - tl[testListSize].end = vertices.next(n); - tl[testListSize].used = false; - tl[testListSize].before = false; - ++testListSize; - } - ++i; - } - if (!testListSize) - continue; - - qSort(tl, tl + testListSize); - - for (int j = 0; j < testListSize; ++j) { - if (tl[j].used) - continue; - - for (int k = j + 1; k < testListSize; ++k) { - if (tl[j].end->x != tl[k].end->x - || tl[j].end->y != tl[k].end->y - || tl[k].used) - break; - - if (!winding || tl[j].before != tl[k].before) { - cancelEdges(tl[j], tl[k]); - break; - } - ++k; - } - ++j; - } - } - free(tl); -} - - -void QTessellatorPrivate::emitEdges(QTessellator *tessellator) -{ - //QDEBUG() << "TRAPS:"; - if (!scanline.old_size) - return; - - // emit edges - if (winding) { - // winding fill rule - int w = 0; - - scanline.old[0]->y_left = y; - - for (int i = 0; i < scanline.old_size - 1; ++i) { - Edge *left = scanline.old[i]; - Edge *right = scanline.old[i+1]; - w += left->winding; -// qDebug() << "i=" << i << "edge->winding=" << left->winding << "winding=" << winding; - if (w == 0) { - left->y_right = y; - right->y_left = y; - } else if (!emit_clever || left->mark || right->mark) { - Q27Dot5 top = qMax(left->y_right, right->y_left); - if (top != y) { - QTessellator::Trapezoid trap; - fillTrapezoid(top, y, left->edge, right->edge, vertices, &trap); - tessellator->addTrap(trap); -// QDEBUG() << " top=" << Q27Dot5ToDouble(top) << "left=" << left->edge << "right=" << right->edge; - } - right->y_left = y; - left->y_right = y; - } - left->mark = false; - } - if (scanline.old[scanline.old_size - 1]->mark) { - scanline.old[scanline.old_size - 1]->y_right = y; - scanline.old[scanline.old_size - 1]->mark = false; - } - } else { - // odd-even fill rule - for (int i = 0; i < scanline.old_size; i += 2) { - Edge *left = scanline.old[i]; - Edge *right = scanline.old[i+1]; - if (!emit_clever || left->mark || right->mark) { - Q27Dot5 top = qMax(left->y_right, right->y_left); - if (top != y) { - QTessellator::Trapezoid trap; - fillTrapezoid(top, y, left->edge, right->edge, vertices, &trap); - tessellator->addTrap(trap); - } -// QDEBUG() << " top=" << Q27Dot5ToDouble(top) << "left=" << left->edge << "right=" << right->edge; - left->y_left = y; - left->y_right = y; - right->y_left = y; - right->y_right = y; - left->mark = right->mark = false; - } - } - } -} - - -void QTessellatorPrivate::processIntersections() -{ - QDEBUG() << "PROCESS INTERSECTIONS"; - // process intersections - while (!intersections.isEmpty()) { - Intersections::iterator it = intersections.begin(); - if (it.key().y != y) - break; - - // swap edges - QDEBUG() << " swapping intersecting edges "; - int min = scanline.size; - int max = 0; - Q27Dot5 xmin = INT_MAX; - Q27Dot5 xmax = INT_MIN; - int num = 0; - while (1) { - const Intersection &i = it.key(); - int next = it->next; - - int edgePos = scanline.findEdge(i.edge); - if (edgePos >= 0) { - ++num; - min = qMin(edgePos, min); - max = qMax(edgePos, max); - Edge *edge = scanline.edges[edgePos]; - xmin = qMin(xmin, edge->positionAt(y)); - xmax = qMax(xmax, edge->positionAt(y)); - } - Intersection key; - key.y = y; - key.edge = next; - it = intersections.find(key); - intersections.remove(i); - if (it == intersections.end()) - break; - } - if (num < 2) - continue; - - Q_ASSERT(min != max); - QDEBUG() << "sorting between" << min << "and" << max << "xpos=" << xmin << xmax; - while (min > 0 && scanline.edges[min - 1]->positionAt(y) >= xmin) { - QDEBUG() << " adding edge on left"; - --min; - } - while (max < scanline.size - 1 && scanline.edges[max + 1]->positionAt(y) <= xmax) { - QDEBUG() << " adding edge on right"; - ++max; - } - - qSort(scanline.edges + min, scanline.edges + max + 1, EdgeSorter(y)); -#ifdef DEBUG - for (int i = min; i <= max; ++i) - QDEBUG() << " " << scanline.edges[i]->edge << "at pos" << i; -#endif - for (int i = min; i <= max; ++i) { - Edge *edge = scanline.edges[i]; - edge->intersect_left = true; - edge->intersect_right = true; - edge->mark = true; - } - } -} - -void QTessellatorPrivate::removeEdges() -{ - int cv = currentVertex; - while (cv < vertices.nPoints) { - const Vertex *v = vertices.sorted[cv]; - if (v->y > y) - break; - if (v->flags & LineBeforeEnds) { - QDEBUG() << " removing edge" << vertices.prevPos(v); - int pos = scanline.findEdge(vertices.prevPos(v)); - if (pos == -1) - continue; - scanline.edges[pos]->mark = true; - if (pos > 0) - scanline.edges[pos - 1]->intersect_right = true; - if (pos < scanline.size - 1) - scanline.edges[pos + 1]->intersect_left = true; - scanline.removeAt(pos); - } - if (v->flags & LineAfterEnds) { - QDEBUG() << " removing edge" << vertices.position(v); - int pos = scanline.findEdge(vertices.position(v)); - if (pos == -1) - continue; - scanline.edges[pos]->mark = true; - if (pos > 0) - scanline.edges[pos - 1]->intersect_right = true; - if (pos < scanline.size - 1) - scanline.edges[pos + 1]->intersect_left = true; - scanline.removeAt(pos); - } - ++cv; - } -} - -void QTessellatorPrivate::addEdges() -{ - while (currentVertex < vertices.nPoints) { - const Vertex *v = vertices.sorted[currentVertex]; - if (v->y > y) - break; - if (v->flags & LineBeforeStarts) { - // add new edge - int start = vertices.prevPos(v); - Edge e(vertices, start); - int pos = scanline.findEdgePosition(e); - QDEBUG() << " adding edge" << start << "at position" << pos; - scanline.insert(pos, e); - if (!mark_clever || !(v->flags & LineAfterEnds)) { - if (pos > 0) - scanline.edges[pos - 1]->mark = true; - if (pos < scanline.size - 1) - scanline.edges[pos + 1]->mark = true; - } - } - if (v->flags & LineAfterStarts) { - Edge e(vertices, vertices.position(v)); - int pos = scanline.findEdgePosition(e); - QDEBUG() << " adding edge" << vertices.position(v) << "at position" << pos; - scanline.insert(pos, e); - if (!mark_clever || !(v->flags & LineBeforeEnds)) { - if (pos > 0) - scanline.edges[pos - 1]->mark = true; - if (pos < scanline.size - 1) - scanline.edges[pos + 1]->mark = true; - } - } - if (v->flags & LineAfterHorizontal) { - int pos1 = scanline.findEdgePosition(v->x, v->y); - const Vertex *next = vertices.next(v); - Q_ASSERT(v->y == next->y); - int pos2 = scanline.findEdgePosition(next->x, next->y); - if (pos2 < pos1) - qSwap(pos1, pos2); - if (pos1 > 0) - --pos1; - if (pos2 == scanline.size) - --pos2; - //QDEBUG() << "marking horizontal edge from " << pos1 << "to" << pos2; - scanline.markEdges(pos1, pos2); - } - ++currentVertex; - } -} - -#ifdef DEBUG -static void checkLinkChain(const QTessellatorPrivate::Intersections &intersections, - QTessellatorPrivate::Intersection i) -{ -// qDebug() << " Link chain: "; - int end = i.edge; - while (1) { - QTessellatorPrivate::IntersectionLink l = intersections.value(i); -// qDebug() << " " << i.edge << "next=" << l.next << "prev=" << l.prev; - if (l.next == end) - break; - Q_ASSERT(l.next != -1); - Q_ASSERT(l.prev != -1); - - QTessellatorPrivate::Intersection i2 = i; - i2.edge = l.next; - QTessellatorPrivate::IntersectionLink l2 = intersections.value(i2); - - Q_ASSERT(l2.next != -1); - Q_ASSERT(l2.prev != -1); - Q_ASSERT(l.next == i2.edge); - Q_ASSERT(l2.prev == i.edge); - i = i2; - } -} -#endif - -bool QTessellatorPrivate::edgeInChain(Intersection i, int edge) -{ - int end = i.edge; - while (1) { - if (i.edge == edge) - return true; - IntersectionLink l = intersections.value(i); - if (l.next == end) - break; - Q_ASSERT(l.next != -1); - Q_ASSERT(l.prev != -1); - - Intersection i2 = i; - i2.edge = l.next; - -#ifndef QT_NO_DEBUG - IntersectionLink l2 = intersections.value(i2); - Q_ASSERT(l2.next != -1); - Q_ASSERT(l2.prev != -1); - Q_ASSERT(l.next == i2.edge); - Q_ASSERT(l2.prev == i.edge); -#endif - i = i2; - } - return false; -} - - -void QTessellatorPrivate::addIntersection(const Edge *e1, const Edge *e2) -{ - const IntersectionLink emptyLink = {-1, -1}; - - int next = vertices.nextPos(vertices[e1->edge]); - if (e2->edge == next) - return; - int prev = vertices.prevPos(vertices[e1->edge]); - if (e2->edge == prev) - return; - - Q27Dot5 yi; - bool det_positive; - bool isect = e1->intersect(*e2, &yi, &det_positive); - QDEBUG("checking edges %d and %d", e1->edge, e2->edge); - if (!isect) { - QDEBUG() << " no intersection"; - return; - } - - // don't emit an intersection if it's at the start of a line segment or above us - if (yi <= y) { - if (!det_positive) - return; - QDEBUG() << " ----->>>>>> WRONG ORDER!"; - yi = y; - } - QDEBUG() << " between edges " << e1->edge << "and" << e2->edge << "at point (" - << Q27Dot5ToDouble(yi) << ')'; - - Intersection i1; - i1.y = yi; - i1.edge = e1->edge; - IntersectionLink link1 = intersections.value(i1, emptyLink); - Intersection i2; - i2.y = yi; - i2.edge = e2->edge; - IntersectionLink link2 = intersections.value(i2, emptyLink); - - // new pair of edges - if (link1.next == -1 && link2.next == -1) { - link1.next = link1.prev = i2.edge; - link2.next = link2.prev = i1.edge; - } else if (link1.next == i2.edge || link1.prev == i2.edge - || link2.next == i1.edge || link2.prev == i1.edge) { -#ifdef DEBUG - checkLinkChain(intersections, i1); - checkLinkChain(intersections, i2); - Q_ASSERT(edgeInChain(i1, i2.edge)); -#endif - return; - } else if (link1.next == -1 || link2.next == -1) { - if (link2.next == -1) { - qSwap(i1, i2); - qSwap(link1, link2); - } - Q_ASSERT(link1.next == -1); -#ifdef DEBUG - checkLinkChain(intersections, i2); -#endif - // only i2 in list - link1.next = i2.edge; - link1.prev = link2.prev; - link2.prev = i1.edge; - Intersection other; - other.y = yi; - other.edge = link1.prev; - IntersectionLink link = intersections.value(other, emptyLink); - Q_ASSERT(link.next == i2.edge); - Q_ASSERT(link.prev != -1); - link.next = i1.edge; - intersections.insert(other, link); - } else { - bool connected = edgeInChain(i1, i2.edge); - if (connected) - return; -#ifdef DEBUG - checkLinkChain(intersections, i1); - checkLinkChain(intersections, i2); -#endif - // both already in some list. Have to make sure they are connected - // this can be done by cutting open the ring(s) after the two eges and - // connecting them again - Intersection other1; - other1.y = yi; - other1.edge = link1.next; - IntersectionLink linko1 = intersections.value(other1, emptyLink); - Intersection other2; - other2.y = yi; - other2.edge = link2.next; - IntersectionLink linko2 = intersections.value(other2, emptyLink); - - linko1.prev = i2.edge; - link2.next = other1.edge; - - linko2.prev = i1.edge; - link1.next = other2.edge; - intersections.insert(other1, linko1); - intersections.insert(other2, linko2); - } - intersections.insert(i1, link1); - intersections.insert(i2, link2); -#ifdef DEBUG - checkLinkChain(intersections, i1); - checkLinkChain(intersections, i2); - Q_ASSERT(edgeInChain(i1, i2.edge)); -#endif - return; - -} - - -void QTessellatorPrivate::addIntersections() -{ - if (scanline.size) { - QDEBUG() << "INTERSECTIONS"; - // check marked edges for intersections -#ifdef DEBUG - for (int i = 0; i < scanline.size; ++i) { - Edge *e = scanline.edges[i]; - QDEBUG() << " " << i << e->edge << "isect=(" << e->intersect_left << e->intersect_right - << ')'; - } -#endif - - for (int i = 0; i < scanline.size - 1; ++i) { - Edge *e1 = scanline.edges[i]; - Edge *e2 = scanline.edges[i + 1]; - // check for intersection - if (e1->intersect_right || e2->intersect_left) - addIntersection(e1, e2); - } - } -#if 0 - if (intersections.constBegin().key().y == y) { - QDEBUG() << "----------------> intersection on same line"; - scanline.clearMarks(); - scanline.processIntersections(y, &intersections); - goto redo; - } -#endif -} - - -QTessellator::QTessellator() -{ - d = new QTessellatorPrivate; -} - -QTessellator::~QTessellator() -{ - delete d; -} - -void QTessellator::setWinding(bool w) -{ - d->winding = w; -} - - -QRectF QTessellator::tessellate(const QPointF *points, int nPoints) -{ - Q_ASSERT(points[0] == points[nPoints-1]); - --nPoints; - -#ifdef DEBUG - QDEBUG()<< "POINTS:"; - for (int i = 0; i < nPoints; ++i) { - QDEBUG() << points[i]; - } -#endif - - // collect edges and calculate bounds - d->vertices.nPoints = nPoints; - d->vertices.init(nPoints); - - int maxActiveEdges = 0; - QRectF br = d->collectAndSortVertices(points, &maxActiveEdges); - d->cancelCoincidingEdges(); - -#ifdef DEBUG - QDEBUG() << "nPoints = " << nPoints << "using " << d->vertices.nPoints; - QDEBUG()<< "VERTICES:"; - for (int i = 0; i < d->vertices.nPoints; ++i) { - QDEBUG() << " " << i << ": " - << "point=" << d->vertices.position(d->vertices.sorted[i]) - << "flags=" << d->vertices.sorted[i]->flags - << "pos=(" << Q27Dot5ToDouble(d->vertices.sorted[i]->x) << '/' - << Q27Dot5ToDouble(d->vertices.sorted[i]->y) << ')'; - } -#endif - - d->scanline.init(maxActiveEdges); - d->y = INT_MIN/256; - d->currentVertex = 0; - - while (d->currentVertex < d->vertices.nPoints) { - d->scanline.clearMarks(); - - d->y = d->vertices.sorted[d->currentVertex]->y; - if (!d->intersections.isEmpty()) - d->y = qMin(d->y, d->intersections.constBegin().key().y); - - QDEBUG()<< "===== SCANLINE: y =" << Q27Dot5ToDouble(d->y) << " ====="; - - d->scanline.prepareLine(); - d->processIntersections(); - d->removeEdges(); - d->addEdges(); - d->addIntersections(); - d->emitEdges(this); - d->scanline.lineDone(); - -#ifdef DEBUG - QDEBUG()<< "===== edges:"; - for (int i = 0; i < d->scanline.size; ++i) { - QDEBUG() << " " << d->scanline.edges[i]->edge - << "p0= (" << Q27Dot5ToDouble(d->scanline.edges[i]->v0->x) - << '/' << Q27Dot5ToDouble(d->scanline.edges[i]->v0->y) - << ") p1= (" << Q27Dot5ToDouble(d->scanline.edges[i]->v1->x) - << '/' << Q27Dot5ToDouble(d->scanline.edges[i]->v1->y) << ')' - << "x=" << Q27Dot5ToDouble(d->scanline.edges[i]->positionAt(d->y)) - << "isLeftOfNext=" - << ((i < d->scanline.size - 1) - ? d->scanline.edges[i]->isLeftOf(*d->scanline.edges[i+1], d->y) - : true); - } -#endif -} - - d->scanline.done(); - d->intersections.clear(); - return br; -} - -// tessellates the given convex polygon -void QTessellator::tessellateConvex(const QPointF *points, int nPoints) -{ - Q_ASSERT(points[0] == points[nPoints-1]); - --nPoints; - - d->vertices.nPoints = nPoints; - d->vertices.init(nPoints); - - for (int i = 0; i < nPoints; ++i) { - d->vertices[i]->x = FloatToQ27Dot5(points[i].x()); - d->vertices[i]->y = FloatToQ27Dot5(points[i].y()); - } - - int left = 0, right = 0; - - int top = 0; - for (int i = 1; i < nPoints; ++i) { - if (d->vertices[i]->y < d->vertices[top]->y) - top = i; - } - - left = (top + nPoints - 1) % nPoints; - right = (top + 1) % nPoints; - - while (d->vertices[left]->x == d->vertices[top]->x && d->vertices[left]->y == d->vertices[top]->y && left != right) - left = (left + nPoints - 1) % nPoints; - - while (d->vertices[right]->x == d->vertices[top]->x && d->vertices[right]->y == d->vertices[top]->y && left != right) - right = (right + 1) % nPoints; - - if (left == right) - return; - - int dir = 1; - - Vertex dLeft = { d->vertices[top]->x - d->vertices[left]->x, - d->vertices[top]->y - d->vertices[left]->y }; - - Vertex dRight = { d->vertices[right]->x - d->vertices[top]->x, - d->vertices[right]->y - d->vertices[top]->y }; - - Q27Dot5 cross = dLeft.x * dRight.y - dLeft.y * dRight.x; - - // flip direction if polygon is clockwise - if (cross < 0 || (cross == 0 && dLeft.x > 0)) { - qSwap(left, right); - dir = -1; - } - - Vertex *lastLeft = d->vertices[top]; - Vertex *lastRight = d->vertices[top]; - - QTessellator::Trapezoid trap; - - while (lastLeft->y == d->vertices[left]->y && left != right) { - lastLeft = d->vertices[left]; - left = (left + nPoints - dir) % nPoints; - } - - while (lastRight->y == d->vertices[right]->y && left != right) { - lastRight = d->vertices[right]; - right = (right + nPoints + dir) % nPoints; - } - - while (true) { - trap.top = qMax(lastRight->y, lastLeft->y); - trap.bottom = qMin(d->vertices[left]->y, d->vertices[right]->y); - trap.topLeft = lastLeft; - trap.topRight = lastRight; - trap.bottomLeft = d->vertices[left]; - trap.bottomRight = d->vertices[right]; - - if (trap.bottom > trap.top) - addTrap(trap); - - if (left == right) - break; - - if (d->vertices[right]->y < d->vertices[left]->y) { - do { - lastRight = d->vertices[right]; - right = (right + nPoints + dir) % nPoints; - } - while (lastRight->y == d->vertices[right]->y && left != right); - } else { - do { - lastLeft = d->vertices[left]; - left = (left + nPoints - dir) % nPoints; - } - while (lastLeft->y == d->vertices[left]->y && left != right); - } - } -} - -// tessellates the stroke of the line from a_ to b_ with the given width and a flat cap -void QTessellator::tessellateRect(const QPointF &a_, const QPointF &b_, qreal width) -{ - Vertex a = { FloatToQ27Dot5(a_.x()), FloatToQ27Dot5(a_.y()) }; - Vertex b = { FloatToQ27Dot5(b_.x()), FloatToQ27Dot5(b_.y()) }; - - QPointF pa = a_, pb = b_; - - if (a.y > b.y) { - qSwap(a, b); - qSwap(pa, pb); - } - - Vertex delta = { b.x - a.x, b.y - a.y }; - - if (delta.x == 0 && delta.y == 0) - return; - - qreal hw = 0.5 * width; - - if (delta.x == 0) { - Q27Dot5 halfWidth = FloatToQ27Dot5(hw); - - if (halfWidth == 0) - return; - - Vertex topLeft = { a.x - halfWidth, a.y }; - Vertex topRight = { a.x + halfWidth, a.y }; - Vertex bottomLeft = { a.x - halfWidth, b.y }; - Vertex bottomRight = { a.x + halfWidth, b.y }; - - QTessellator::Trapezoid trap = { topLeft.y, bottomLeft.y, &topLeft, &bottomLeft, &topRight, &bottomRight }; - addTrap(trap); - } else if (delta.y == 0) { - Q27Dot5 halfWidth = FloatToQ27Dot5(hw); - - if (halfWidth == 0) - return; - - if (a.x > b.x) - qSwap(a.x, b.x); - - Vertex topLeft = { a.x, a.y - halfWidth }; - Vertex topRight = { b.x, a.y - halfWidth }; - Vertex bottomLeft = { a.x, a.y + halfWidth }; - Vertex bottomRight = { b.x, a.y + halfWidth }; - - QTessellator::Trapezoid trap = { topLeft.y, bottomLeft.y, &topLeft, &bottomLeft, &topRight, &bottomRight }; - addTrap(trap); - } else { - QPointF perp(pb.y() - pa.y(), pa.x() - pb.x()); - qreal length = qSqrt(perp.x() * perp.x() + perp.y() * perp.y()); - - if (qFuzzyIsNull(length)) - return; - - // need the half of the width - perp *= hw / length; - - QPointF pta = pa + perp; - QPointF ptb = pa - perp; - QPointF ptc = pb - perp; - QPointF ptd = pb + perp; - - Vertex ta = { FloatToQ27Dot5(pta.x()), FloatToQ27Dot5(pta.y()) }; - Vertex tb = { FloatToQ27Dot5(ptb.x()), FloatToQ27Dot5(ptb.y()) }; - Vertex tc = { FloatToQ27Dot5(ptc.x()), FloatToQ27Dot5(ptc.y()) }; - Vertex td = { FloatToQ27Dot5(ptd.x()), FloatToQ27Dot5(ptd.y()) }; - - if (ta.y < tb.y) { - if (tb.y < td.y) { - QTessellator::Trapezoid top = { ta.y, tb.y, &ta, &tb, &ta, &td }; - QTessellator::Trapezoid bottom = { td.y, tc.y, &tb, &tc, &td, &tc }; - addTrap(top); - addTrap(bottom); - - QTessellator::Trapezoid middle = { tb.y, td.y, &tb, &tc, &ta, &td }; - addTrap(middle); - } else { - QTessellator::Trapezoid top = { ta.y, td.y, &ta, &tb, &ta, &td }; - QTessellator::Trapezoid bottom = { tb.y, tc.y, &tb, &tc, &td, &tc }; - addTrap(top); - addTrap(bottom); - - if (tb.y != td.y) { - QTessellator::Trapezoid middle = { td.y, tb.y, &ta, &tb, &td, &tc }; - addTrap(middle); - } - } - } else { - if (ta.y < tc.y) { - QTessellator::Trapezoid top = { tb.y, ta.y, &tb, &tc, &tb, &ta }; - QTessellator::Trapezoid bottom = { tc.y, td.y, &tc, &td, &ta, &td }; - addTrap(top); - addTrap(bottom); - - QTessellator::Trapezoid middle = { ta.y, tc.y, &tb, &tc, &ta, &td }; - addTrap(middle); - } else { - QTessellator::Trapezoid top = { tb.y, tc.y, &tb, &tc, &tb, &ta }; - QTessellator::Trapezoid bottom = { ta.y, td.y, &tc, &td, &ta, &td }; - addTrap(top); - addTrap(bottom); - - if (ta.y != tc.y) { - QTessellator::Trapezoid middle = { tc.y, ta.y, &tc, &td, &tb, &ta }; - addTrap(middle); - } - } - } - } -} - -QT_END_NAMESPACE diff --git a/src/gui/painting/qtessellator_p.h b/src/gui/painting/qtessellator_p.h deleted file mode 100644 index 9f598b6b2e..0000000000 --- a/src/gui/painting/qtessellator_p.h +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QTESSELATOR_P_H -#define QTESSELATOR_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -class QTessellatorPrivate; - -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 - -class Q_GUI_EXPORT QTessellator { -public: - QTessellator(); - virtual ~QTessellator(); - - QRectF tessellate(const QPointF *points, int nPoints); - void tessellateConvex(const QPointF *points, int nPoints); - void tessellateRect(const QPointF &a, const QPointF &b, qreal width); - - void setWinding(bool w); - - struct Vertex { - Q27Dot5 x; - Q27Dot5 y; - }; - struct Trapezoid { - Q27Dot5 top; - Q27Dot5 bottom; - const Vertex *topLeft; - const Vertex *bottomLeft; - const Vertex *topRight; - const Vertex *bottomRight; - }; - virtual void addTrap(const Trapezoid &trap) = 0; - -private: - friend class QTessellatorPrivate; - QTessellatorPrivate *d; -}; - -QT_END_NAMESPACE - -#endif