double compute_area(XTrapezoid *trap) { double x1 = compute_x_at(trap->top, trap->left.p1, trap->left.p2); double x2 = compute_x_at(trap->top, trap->right.p1, trap->right.p2); double x3 = compute_x_at(trap->bottom, trap->left.p1, trap->left.p2); double x4 = compute_x_at(trap->bottom, trap->right.p1, trap->right.p2); double top = XFixedToDouble(trap->top); double bottom = XFixedToDouble(trap->bottom); double h = bottom - top; double top_base = x2 - x1; double bottom_base = x4 - x3; if ((top_base < 0 && bottom_base > 0) || (top_base > 0 && bottom_base < 0)) { double y0 = top_base*h/(top_base - bottom_base) + top; double area = qAbs(top_base * (y0 - top) / 2.); area += qAbs(bottom_base * (bottom - y0) /2.); return area; } return 0.5 * h * qAbs(top_base + bottom_base); }
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; } }
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(); }
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; } }
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) << ")"; }
static Bool transform_point (XTransform *transform, double *xp, double *yp) { double vector[3]; double result[3]; int i, j; double v; vector[0] = *xp; vector[1] = *yp; vector[2] = 1; for (j = 0; j < 3; j++) { v = 0; for (i = 0; i < 3; i++) { v += (XFixedToDouble (transform->matrix[j][i]) * vector[i]); } if (v > 32767 || v < -32767) { return False; } result[j] = v; } if (!result[2]) { return False; } for (j = 0; j < 2; j++) { vector[j] = result[j] / result[2]; } *xp = vector[0]; *yp = vector[1]; return True; }
static INLINE boolean matrix_from_pict_transform(PictTransform *trans, float *matrix) { if (!trans) return FALSE; matrix[0] = XFixedToDouble(trans->matrix[0][0]); matrix[3] = XFixedToDouble(trans->matrix[0][1]); matrix[6] = XFixedToDouble(trans->matrix[0][2]); matrix[1] = XFixedToDouble(trans->matrix[1][0]); matrix[4] = XFixedToDouble(trans->matrix[1][1]); matrix[7] = XFixedToDouble(trans->matrix[1][2]); matrix[2] = XFixedToDouble(trans->matrix[2][0]); matrix[5] = XFixedToDouble(trans->matrix[2][1]); matrix[8] = XFixedToDouble(trans->matrix[2][2]); return TRUE; }
static double compute_x_at(XFixed y, XPointFixed p1, XPointFixed p2) { double d = XFixedToDouble(p2.x - p1.x); return XFixedToDouble(p1.x) + d*XFixedToDouble(y - p1.y)/XFixedToDouble(p2.y - p1.y); }
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); if (pg[0] != pg[pgSize-1]) qWarning() << Q_FUNC_INFO << "Malformed polygon (first and last points must be identical)"; // 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; } if (isects.size()%2 != 1) qFatal("%s: number of intersection points must be odd", Q_FUNC_INFO); // 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"); }
static double XRenderComputeXIntercept (XLineFixed *l, double inverse_slope) { return XFixedToDouble (l->p1.x) - inverse_slope * XFixedToDouble (l->p1.y); }
static double XRenderComputeInverseSlope (XLineFixed *l) { return (XFixedToDouble (l->p2.x - l->p1.x) / XFixedToDouble (l->p2.y - l->p1.y)); }
int apply_transform (Display *display, Window root, RRCrtc crtcnum, const char *input_name) { int ret; ret = EXIT_SUCCESS; if (ret != EXIT_FAILURE) { XRRScreenConfiguration *sconf; XRRScreenResources *res; XRRCrtcInfo *crtc; XRRCrtcTransformAttributes *transform; Status status; double amx[3][3]; double sina, cosa; double hscale, vscale, hoffs, voffs; XRRScreenSize *ssize; int nsizes; Rotation srot; res = XRRGetScreenResourcesCurrent (display, root); sconf = XRRGetScreenInfo (display, root); ssize = XRRConfigSizes(sconf, &nsizes) + XRRConfigCurrentConfiguration (sconf, &srot); crtc = XRRGetCrtcInfo (display, res, crtcnum); if (verbose) { fprintf (stderr, "Screen: (%u, %u) 0x%02x\n", ssize->width, ssize->height, srot); fprintf (stderr, "CRTC: (%i, %i) (%u, %u) 0x%02x\n", crtc->x, crtc->y, crtc->width, crtc->height, crtc->rotation); } switch (srot) { case RR_Rotate_0: case RR_Rotate_180: hscale = (double)crtc->width/(double)ssize->width; vscale = (double)crtc->height/(double)ssize->height; break; case RR_Rotate_90: case RR_Rotate_270: hscale = (double)crtc->width/(double)ssize->height; vscale = (double)crtc->height/(double)ssize->width; break; default: ret = EXIT_FAILURE; fprintf (stderr, "The screen rotation/reflection 0x%02x is not supported yet. Sorry.\n", srot); } switch (crtc->rotation) { case RR_Rotate_0: sina = 0; cosa = 1; hoffs = 0; voffs = 0; break; case RR_Rotate_90: sina = 1; cosa = 0; hoffs = 1; voffs = 0; break; case RR_Rotate_180: sina = 0; cosa = -1; hoffs = 1; voffs = 1; break; case RR_Rotate_270: sina = -1; cosa = 0; hoffs = 0; voffs = 1; break; default: ret = EXIT_FAILURE; fprintf (stderr, "The rotation/reflection 0x%02x is not supported yet. Sorry.\n", crtc->rotation); } if (ret != EXIT_FAILURE) { amx[0][0] = cosa*hscale; amx[0][1] = -sina*hscale; amx[0][2] = hoffs*hscale + crtc->x/ssize->width; amx[1][0] = sina*vscale; amx[1][1] = cosa*vscale; amx[1][2] = voffs*vscale + crtc->y/ssize->height; amx[2][0] = 0; amx[2][1] = 0; amx[2][2] = 1; status = XRRGetCrtcTransform (display, crtcnum, &transform); if (!status) { fprintf (stderr, "Unable to get the current transformation\n"); ret = EXIT_FAILURE; } } if (ret != EXIT_FAILURE) { static char strmx[3][3][8]; static const char *args[11]; double mx[3][3]; int i, j; for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) { XFixed fv = transform->currentTransform.matrix[j][i]; mx[j][i] = XFixedToDouble (fv); } } args[0] = input_name; args[1] = "Coordinate Transformation Matrix"; for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) { double v = mx[0][i]*amx[j][0] + mx[1][i]*amx[j][1] + mx[2][i]*amx[j][2]; snprintf (strmx[j][i], 8, "%8.6f", v); args[2 + i + j*3] = strmx[j][i]; } } if (verbose) { fprintf (stderr, "Debug: set-float-prop"); for (i = 0; i < 11; i++) { fprintf (stderr, " %s", args[i]); } fprintf (stderr, "\n"); } ret = set_float_prop(display, 11, args, "set-float-prop", ": error calling function, please report a bug."); XFree (transform); } XRRFreeCrtcInfo (crtc); XRRFreeScreenResources (res); XRRFreeScreenConfigInfo (sconf); } return ret; }