void TopologyNode::updateShapeCache() { QPainterPath shapePath; QString imagePath; #ifdef PLUGIN_TARGET if(mNodeFlags & NF_ISCENTRALROUTER) { Q_ASSERT (m_paintStrategy); imagePath = m_paintStrategy->getImageName(); } else #endif { #ifdef POWERLINE_REVISION if(m_isPowerLine) { imagePath = GENIE2_RES("map/devices/PowerLineNormal.png"); } else #endif { imagePath = getDeviceTypeImagePath(m_deviceType,DTIR_NORMAL); } } QPixmap pixDetecter(imagePath); shapePath.addRegion(QRegion(pixDetecter.mask())); shapePath.translate(-pixDetecter.width() / 2,-pixDetecter.height() / 2); m_shapePath = shapePath; }
QPainterPath BubbleChatBox::shape() const { QRegion maskRegion(backgroundPixmap.mask().scaled(rect.size().toSize())); QPainterPath path; path.addRegion(maskRegion); return path; }
void GlPlottingCanvas::paintEvent(QPaintEvent *) { // QPainter painter(this); // painter.setCompositionMode(QPainter::CompositionMode_Source); // QPixmap& pix = PlottingThread::Instance()->GetCanvas(); //// qDebug() << ".... paint"; // painter.drawPixmap(0, 0, 800, 600, pix); static double s_plottingX = 0; double plottingY = 0; QPainter painter(this); QPen pen(Qt::green); painter.setPen(pen); painter.setCompositionMode(QPainter::CompositionMode_Source); painter.fillRect(s_plottingX, 0, 10, 600, Qt::transparent); QPainterPath path; path.addRegion(m_popUpRegion); painter.fillPath(path, Qt::transparent); QRegion region(rect()); region -= m_popUpRegion; painter.setClipRegion(region); for(int i = 0; i < 60; i++) { plottingY = 10 + i * 10; painter.drawLine(s_plottingX, plottingY, s_plottingX + 5, plottingY); } s_plottingX += 5; if(s_plottingX > 800) { s_plottingX = 0; } }
/*! \internal A static function for reading the sprite files containing pixmaps for displaying animated elements seen in the game. */ void KSprite::loadSprites() { QString sprites_prefix = IMG_BACKGROUND; int sep = sprites_prefix.lastIndexOf("/"); sprites_prefix.truncate(sep); int i = 0; QString file_name; QString base = sprites_prefix + '/'; while (animations_[i].id_) { QList<QPixmap> p; if (animations_[i].frames_) { for (int j=0; j<animations_[i].frames_; ++j) { QString s(animations_[i].path_); file_name = base + s.arg(j,4,10,QLatin1Char('0')); QPixmap pixmap(file_name); p.insert(j,pixmap); } } else { file_name = base + QString(animations_[i].path_); QPixmap pixmap(file_name); p.insert(0,pixmap); } QList<Frame> frameshape; for (int f = 0; f < p.size(); ++f) { QPixmap pixmap = p.at(f); Frame frame; frame.pixmap = pixmap; QPainterPath path; QBitmap m = pixmap.mask(); if (m.width()) path.addRegion(QRegion(m)); else path.addRegion(QRect(pixmap.rect())); frame.shape = path; frame.boundingRect = path.controlPointRect(); frameshape << frame; } shapemap_.insert(animations_[i].id_,frameshape); i++; } spritesLoaded_ = true; }
QPainterPath AnimatedPixmapItem::shape() const { const Frame &f = frames.at(currentFrame); if (f.shape.isEmpty()) { QPainterPath path; path.addRegion(f.pixmap.createHeuristicMask()); const_cast<Frame &>(f).shape = path; } return f.shape; }
void LaptopButton::drawButton(QPainter *p) { bool smallBtn = width() == btnWidth1; if(btnPix1){ if(decoration()->isActive()){ if(isDown()) p->drawPixmap(0, 0, smallBtn ? *btnDownPix1 : *btnDownPix2); else p->drawPixmap(0, 0, smallBtn ? *btnPix1 : *btnPix2); } else{ if(isDown()) p->drawPixmap(0, 0, smallBtn ? *iBtnDownPix1 : *iBtnDownPix2); else p->drawPixmap(0, 0, smallBtn ? *iBtnPix1 : *iBtnPix2); } } else{ QPalette g = options()->palette(KDecoration::ColorButtonBg, decoration()->isActive()); g.setCurrentColorGroup( QPalette::Active ); int w = width(); int h = height(); p->fillRect(1, 1, w-2, h-2, isDown() ? g.color(QPalette::Mid) : g.color(QPalette::Button) ); p->setPen(isDown() ? g.color( QPalette::Dark ) : g.color( QPalette::Light )); p->drawLine(0, 0, w-1, 0); p->drawLine(0, 0, 0, w-1); p->setPen(isDown() ? g.color( QPalette::Light ) : g.color( QPalette::Dark )); p->drawLine(w-1, 0, w-1, h-1); p->drawLine(0, h-1, w-1, h-1); } QPainterPath path; path.addRegion( deco ); QPoint offset( (width()-8)/2, (height()-8)/2 ); if( isDown() ) offset += QPoint( 1, 1 ); p->translate( offset ); p->setPen( Qt::NoPen ); p->setBrush( btnForeground ); p->drawPath( path ); }
QT_END_NAMESPACE #endif void tst_QRegion::regionToPath() { #ifdef QT_BUILD_INTERNAL QFETCH(QPainterPath, path); for (int i = 0; i < 360; i += 10) { QTransform transform; transform.scale(5, 5); transform.rotate(i); QPainterPath mapped = transform.map(path); QRegion region(mapped.toFillPolygon().toPolygon()); QPainterPath a; a.addRegion(region); QPainterPath b = qt_regionToPath(region); QRect r = a.boundingRect().toAlignedRect(); QImage ia(r.size(), QImage::Format_RGB32); ia.fill(0xffffffff); QImage ib = ia; QPainter p(&ia); p.translate(-r.x(), -r.y()); p.fillPath(a, Qt::red); p.end(); p.begin(&ib); p.translate(-r.x(), -r.y()); p.fillPath(b, Qt::red); p.end(); QCOMPARE(ia, ib); QCOMPARE(a.boundingRect(), b.boundingRect()); } #endif }
void GraphQtInteractiveRenderer::clipRegionAddRect(Rectangle *rect) { GraphQtRenderer *renderer = m_data->renderer; QRegion *clip = renderer->clipRegion(); QRect clipRect; clipRect.setX(rect->x()); clipRect.setY(rect->y()); clipRect.setWidth(rect->width()); clipRect.setHeight(rect->height()); *clip = clip->united(clipRect); QPainterPath path; path.addRegion(*clip); QPainter *painter = m_data->renderer->painter(); painter->setClipping(true); painter->setClipPath(path); }
void tst_QPainterPath::translate() { QPainterPath path; // Path with no elements. QCOMPARE(path.currentPosition(), QPointF()); path.translate(50.5, 50.5); QCOMPARE(path.currentPosition(), QPointF()); QCOMPARE(path.translated(50.5, 50.5).currentPosition(), QPointF()); // path.isEmpty(), but we have one MoveTo element that should be translated. path.moveTo(50, 50); QCOMPARE(path.currentPosition(), QPointF(50, 50)); path.translate(99.9, 99.9); QCOMPARE(path.currentPosition(), QPointF(149.9, 149.9)); path.translate(-99.9, -99.9); QCOMPARE(path.currentPosition(), QPointF(50, 50)); QCOMPARE(path.translated(-50, -50).currentPosition(), QPointF(0, 0)); // Complex path. QRegion shape(100, 100, 300, 200, QRegion::Ellipse); shape -= QRect(225, 175, 50, 50); QPainterPath complexPath; complexPath.addRegion(shape); QVector<QPointF> untranslatedElements; for (int i = 0; i < complexPath.elementCount(); ++i) untranslatedElements.append(QPointF(complexPath.elementAt(i))); const QPainterPath untranslatedComplexPath(complexPath); const QPointF offset(100, 100); complexPath.translate(offset); for (int i = 0; i < complexPath.elementCount(); ++i) QCOMPARE(QPointF(complexPath.elementAt(i)) - offset, untranslatedElements.at(i)); QCOMPARE(complexPath.translated(-offset), untranslatedComplexPath); }
void TextLayer::recreateTexture(VidgfxContext *gfx) { if(!m_isTexDirty) return; // Don't waste any time if it hasn't changed m_isTexDirty = false; // Delete existing texture if one exists if(m_texture != NULL) vidgfx_context_destroy_tex(gfx, m_texture); m_texture = NULL; // Determine texture size. We need to keep in mind that the text in the // document might extend outside of the layer's bounds. m_document.setTextWidth(m_rect.width()); QSize size( (int)ceilf(m_document.size().width()), (int)ceilf(m_document.size().height())); if(m_document.isEmpty() || size.isEmpty()) { // Nothing to display return; } // Create temporary canvas. We need to be careful here as text is rendered // differently on premultiplied vs non-premultiplied pixel formats. On a // premultiplied format text is rendered with subpixel rendering enabled // while on a non-premultiplied format it is not. As we don't want subpixel // rendering we use the standard ARGB32 format. QSize imgSize( size.width() + m_strokeSize * 2, size.height() + m_strokeSize * 2); QImage img(imgSize, QImage::Format_ARGB32); img.fill(Qt::transparent); QPainter p(&img); p.setRenderHint(QPainter::Antialiasing, true); // Render text //m_document.drawContents(&p); // Render stroke if(m_strokeSize > 0) { #define STROKE_TECHNIQUE 0 #if STROKE_TECHNIQUE == 0 // Technique 0: Use QTextDocument's built-in text outliner //quint64 timeStart = App->getUsecSinceExec(); QTextDocument *outlineDoc = m_document.clone(this); QTextCharFormat format; QPen pen(m_strokeColor, (double)(m_strokeSize * 2)); pen.setJoinStyle(Qt::RoundJoin); format.setTextOutline(pen); QTextCursor cursor(outlineDoc); cursor.select(QTextCursor::Document); cursor.mergeCharFormat(format); // Take into account the stroke offset p.translate(m_strokeSize, m_strokeSize); //quint64 timePath = App->getUsecSinceExec(); outlineDoc->drawContents(&p); delete outlineDoc; //quint64 timeEnd = App->getUsecSinceExec(); //appLog() << "Path time = " << (timePath - timeStart) << " usec"; //appLog() << "Render time = " << (timeEnd - timePath) << " usec"; //appLog() << "Full time = " << (timeEnd - timeStart) << " usec"; #elif STROKE_TECHNIQUE == 1 // Technique 1: Create a text QPainterPath and stroke it quint64 timeStart = App->getUsecSinceExec(); // Create the path for the text's stroke QPainterPath path; QTextBlock &block = m_document.firstBlock(); int numBlocks = m_document.blockCount(); for(int i = 0; i < numBlocks; i++) { QTextLayout *layout = block.layout(); for(int j = 0; j < layout->lineCount(); j++) { QTextLine &line = layout->lineAt(j); const QString text = block.text().mid( line.textStart(), line.textLength()); QPointF pos = layout->position() + line.position(); pos.ry() += line.ascent(); //appLog() << pos << ": " << text; path.addText(pos, block.charFormat().font(), text); } block = block.next(); } quint64 timePath = App->getUsecSinceExec(); path = path.simplified(); // Fixes gaps with large stroke sizes quint64 timeSimplify = App->getUsecSinceExec(); // Render the path //p.strokePath(path, QPen(m_strokeColor, m_strokeSize)); // Convert it to a stroke QPainterPathStroker stroker; stroker.setWidth(m_strokeSize); //stroker.setCurveThreshold(2.0); stroker.setJoinStyle(Qt::RoundJoin); path = stroker.createStroke(path); // Render the path p.fillPath(path, m_strokeColor); quint64 timeEnd = App->getUsecSinceExec(); appLog() << "Path time = " << (timePath - timeStart) << " usec"; appLog() << "Simplify time = " << (timeSimplify - timePath) << " usec"; appLog() << "Render time = " << (timeEnd - timeSimplify) << " usec"; appLog() << "Full time = " << (timeEnd - timeStart) << " usec"; #elif STROKE_TECHNIQUE == 2 // Technique 2: Similar to technique 1 but do each block separately quint64 timeStart = App->getUsecSinceExec(); quint64 timeTotalSimplify = 0; quint64 timeTotalRender = 0; // Create the path for the text's stroke QTextBlock &block = m_document.firstBlock(); int numBlocks = m_document.blockCount(); for(int i = 0; i < numBlocks; i++) { // Convert this block to a painter path QPainterPath path; QTextLayout *layout = block.layout(); for(int j = 0; j < layout->lineCount(); j++) { QTextLine &line = layout->lineAt(j); const QString text = block.text().mid( line.textStart(), line.textLength()); QPointF pos = layout->position() + line.position() + QPointF(m_strokeSize, m_strokeSize); pos.ry() += line.ascent(); //appLog() << pos << ": " << text; path.addText(pos, block.charFormat().font(), text); } // Prevent gaps appearing at larger stroke sizes quint64 timeA = App->getUsecSinceExec(); path = path.simplified(); quint64 timeB = App->getUsecSinceExec(); timeTotalSimplify += timeB - timeA; // Render the path QPen pen(m_strokeColor, m_strokeSize * 2); pen.setJoinStyle(Qt::RoundJoin); p.strokePath(path, pen); timeA = App->getUsecSinceExec(); timeTotalRender += timeA - timeB; // Iterate block = block.next(); } // Make the final draw take into account the stroke offset p.translate(m_strokeSize, m_strokeSize); quint64 timeEnd = App->getUsecSinceExec(); appLog() << "Simplify time = " << timeTotalSimplify << " usec"; appLog() << "Render time = " << timeTotalRender << " usec"; appLog() << "Full time = " << (timeEnd - timeStart) << " usec"; #elif STROKE_TECHNIQUE == 3 // Technique 3: Raster brute-force where for each destination pixel // we measure the distance to the closest opaque source pixel quint64 timeStart = App->getUsecSinceExec(); // Get bounding region based on text line bounding rects QRegion region; QTextBlock &block = m_document.firstBlock(); int numBlocks = m_document.blockCount(); for(int i = 0; i < numBlocks; i++) { QTextLayout *layout = block.layout(); for(int j = 0; j < layout->lineCount(); j++) { QTextLine &line = layout->lineAt(j); const QString text = block.text().mid( line.textStart(), line.textLength()); QRect rect = line.naturalTextRect() .translated(layout->position()).toAlignedRect(); if(rect.isEmpty()) continue; // Don't add empty rectangles rect.adjust(0, 0, 1, 0); // QTextLine is incorrect? rect.adjust( -m_strokeSize, -m_strokeSize, m_strokeSize, m_strokeSize); //appLog() << rect; region += rect; } // Iterate block = block.next(); } quint64 timeRegion = App->getUsecSinceExec(); #if 0 // Debug bounding region QPainterPath regionPath; regionPath.addRegion(region); regionPath.setFillRule(Qt::WindingFill); p.fillPath(regionPath, QColor(255, 0, 0, 128)); #endif // 0 // We cannot read and write to the same image at the same time so // create a second one. Note that this is not premultiplied. QImage imgOut(size, QImage::Format_ARGB32); imgOut.fill(Qt::transparent); // Do distance calculation. We assume that non-fully transparent // pixels are always next to a fully opaque one so if the closest // "covered" pixel is not fully opaque then we can use that pixel's // opacity to determine the distance to the shape's edge. for(int y = 0; y < img.height(); y++) { for(int x = 0; x < img.width(); x++) { if(!region.contains(QPoint(x, y))) continue; float dist = getDistance(img, x, y, m_strokeSize); // We fake antialiasing by blurring the edge by 1px float outEdge = (float)m_strokeSize; if(dist >= outEdge) continue; // Outside stroke completely float opacity = qMin(1.0f, outEdge - dist); QColor col = m_strokeColor; col.setAlphaF(col.alphaF() * opacity); // Blend the stroke so that it appears under the existing // pixel data QRgb origRgb = img.pixel(x, y); QColor origCol(origRgb); origCol.setAlpha(qAlpha(origRgb)); col = blendColors(col, origCol, 1.0f); imgOut.setPixel(x, y, col.rgba()); } } quint64 timeRender = App->getUsecSinceExec(); // Swap image data p.end(); img = imgOut; p.begin(&img); quint64 timeEnd = App->getUsecSinceExec(); appLog() << "Region time = " << (timeRegion - timeStart) << " usec"; appLog() << "Render time = " << (timeRender - timeRegion) << " usec"; appLog() << "Swap time = " << (timeEnd - timeRender) << " usec"; appLog() << "Full time = " << (timeEnd - timeStart) << " usec"; #endif // STROKE_TECHNIQUE } // Render text m_document.drawContents(&p); // Convert the image to a GPU texture m_texture = vidgfx_context_new_tex(gfx, img); // Preview texture for debugging //img.save(App->getDataDirectory().filePath("Preview.png")); }
QPainterPath CCJKShapeLinkNode::GetShape() const { QPainterPath path; path.addRegion(QRegion(BoundingRect().toRect(), QRegion::Rectangle)); return path; }