Example #1
0
void SprayBrush::paintDistanceMap(KisPaintDeviceSP dev, const KisPaintInformation &info, const KoColor &painterColor){
    KisRandomAccessor accessor = dev->createRandomAccessor(0, 0);
    KoColor color = painterColor;

    qreal posX = info.pos().x();
    qreal posY = info.pos().y();
    
    qreal opacity = 255;
    for (int y = -m_radius; y <= m_radius; y++){
        for (int x = -m_radius; x <= m_radius; x++){
            //opacity = sqrt(y*y + x*x) / m_radius;
            opacity = (y*y + x*x) / (m_radius * m_radius);
            opacity = 1.0 - opacity;
            opacity *= m_scale;

            if (opacity < 0) continue;
            if (opacity > 1.0) opacity = 1.0;

            if ( (y*y + x*x) <= (m_radius * m_radius) )
            {
                color.setOpacity( opacity * 255);
                accessor.moveTo(x + posX, y + posY);
                memcpy( accessor.rawData(), color.data(), dev->colorSpace()->pixelSize() );
            }

        }
    }
}
Example #2
0
void ChalkBrush::paint(KisPaintDeviceSP dev, qreal x, qreal y, const KoColor &color)
{

    m_inkColor = color;
    m_counter++;
    qreal decr = (m_counter * m_counter * m_counter) / 1000000.0f;

    Bristle *bristle;

    qint32 pixelSize = dev->colorSpace()->pixelSize();
    KisRandomAccessor accessor = dev->createRandomAccessor((int)x, (int)y);

    qreal dirt, result;

    //count decrementing of saturation and alpha
    result = log( ( qreal )m_counter);
    result = -(result * 10) / 100.0;

    QHash<QString, QVariant> params;
    params["h"] = 0.0;
    params["s"] = result;
    params["v"] = 0.0;

    KoColorTransformation* transfo = dev->colorSpace()->createColorTransformation("hsv_adjustment", params);
    transfo->transform(m_inkColor.data(), m_inkColor.data(), 1);

    int opacity = static_cast<int>((1.0f + result) * 255.0);
    m_inkColor.setOpacity(opacity);

    for (int i = 0;i < m_bristles.size();i++) {
        bristle = &m_bristles[i];

        // let's call that noise from ground to chalk :)
        dirt = drand48();
        if (bristle->distanceCenter() > m_radius || dirt < 0.5) {
            continue;
        }

        int dx, dy;
        dx = (int)(x + bristle->x());
        dy = (int)(y + bristle->y());

        accessor.moveTo(dx, dy);
        memcpy(accessor.rawData(), m_inkColor.data(), pixelSize);
        bristle->setInkAmount(1.0f - decr);
    }
}
Example #3
0
void SprayBrush::paint(KisPaintDeviceSP dev, const KisPaintInformation& info, const KoColor &color)
{
    qreal x = info.pos().x();
    qreal y = info.pos().y();

    // initializing painter
    KisPainter drawer(dev);
    drawer.setPaintColor(color);

    // jitter radius
    int tmpRadius = m_radius;
    if (m_jitterSize){
        m_radius = m_radius * drand48();
    }

    // jitter movement
    if (m_jitterMovement){
        x = x + (( 2 * m_radius * drand48() ) - m_radius) * m_amount;
        y = y + (( 2 * m_radius * drand48() ) - m_radius) * m_amount;
    }

    KisRandomAccessor accessor = dev->createRandomAccessor( qRound(x), qRound(y) );
    m_pixelSize = dev->colorSpace()->pixelSize();
    m_inkColor = color;
    m_counter++;

    // coverage: adaptively select how many objects are sprayed per paint
    if (m_useDensity){
        m_particlesCount = (m_coverage * (M_PI * m_radius * m_radius) );
    }

    // Metaballs are rendered little differently
    if (m_shape == 2 && m_object == 0){
        paintMetaballs(dev, info, color);
    }

    qreal nx, ny;
    int ix, iy;

    qreal angle;
    qreal lengthX;
    qreal lengthY;
    
    
    for (int i = 0; i < m_particlesCount; i++){
        // generate random angle
        angle = drand48() * M_PI * 2;
        // different X and Y length??
        lengthY = lengthX = drand48();
        // I hope we live the era where sin and cos is not slow for spray
        nx = (sin(angle) * m_radius * lengthX);
        ny = (cos(angle) * m_radius * lengthY);

        // transform
        nx *= m_scale;
        ny *= m_scale;

        // it is some shape (circle, ellipse, rectangle)
        if (m_object == 0)
        {
            // steps for single step in circle and ellipse
            int steps = 36;
            qreal random = drand48();       

            drawer.setFillColor(m_inkColor);
            drawer.setBackgroundColor(m_inkColor);
            drawer.setPaintColor(m_inkColor);
            // it is ellipse
            if (m_shape == 0){
                //  
                qreal ellipseA = m_width / 2.0;
                qreal ellipseB = m_height / 2.0;

                if (m_width == m_height)
                {
                    if (m_jitterShapeSize){
                        paintCircle(drawer, nx + x, ny + y, int((random * ellipseA) + 1.5) , steps);
                    } else{
                        paintCircle(drawer, nx + x, ny + y, qRound(ellipseA)  , steps);
                    }
                } else 
                {
                    if (m_jitterShapeSize){
                        paintEllipse(drawer, nx + x, ny + y,int((random * ellipseA) + 1.5) ,int((random * ellipseB) + 1.5), angle , steps);
                    } else{
                        paintEllipse(drawer, nx + x, ny + y, qRound(ellipseA), qRound(ellipseB), angle , steps);
                    }
                }
            } else if (m_shape == 1)
            {
                if (m_jitterShapeSize){
                    paintRectangle(drawer, nx + x, ny + y,int((random * m_width) + 1.5) ,int((random * m_height) + 1.5), angle , steps);
                } else{
                    paintRectangle(drawer, nx + x, ny + y, qRound(m_width), qRound(m_height), angle , steps);
                }
            }    
        // it is pixel particle
        }else if (m_object == 1){
            paintParticle(accessor,m_inkColor,nx + x, ny + y);
        }
        // it is pixel
        else if (m_object == 2)
        {
            ix = qRound(nx + x);
            iy = qRound(ny + y);
            accessor.moveTo(ix, iy);
            memcpy(accessor.rawData(), m_inkColor.data(), m_pixelSize);
        }
    }

    

    // hidden code for outline detection
    //m_inkColor.setOpacity(128);
    //paintOutline(dev,m_inkColor,x, y, m_radius * 2);

    // recover from jittering of color
    m_radius = tmpRadius;
}
Example #4
0
void SprayBrush::paintOutline(KisPaintDeviceSP dev ,const KoColor &outlineColor,qreal posX, qreal posY, qreal radius) {
    QList<QPointF> antiPixels;
    KisRandomAccessor accessor = dev->createRandomAccessor( qRound(posX), qRound(posY) );

    for (int y = -radius+posY; y <= radius+posY; y++){
        for (int x = -radius+posX; x <= radius+posX; x++){
            accessor.moveTo(x,y);
            qreal alpha = dev->colorSpace()->alpha(accessor.rawData());

            if (alpha != 0){
                // top left
                accessor.moveTo(x - 1,y - 1);
                if ( dev->colorSpace()->alpha(accessor.rawData()) == 0){
                    antiPixels.append( QPointF(x - 1,y - 1) );
                    //continue;
                }

                // top
                accessor.moveTo(x,y - 1);
                if ( dev->colorSpace()->alpha(accessor.rawData()) == 0){
                    antiPixels.append( QPointF(x,y - 1) );
                    //continue;
                }

                // top right
                accessor.moveTo(x + 1,y - 1);
                if ( dev->colorSpace()->alpha(accessor.rawData()) == 0){
                    antiPixels.append( QPointF(x + 1,y - 1) );
                    //continue;
                }

                //left 
                accessor.moveTo(x - 1,y);
                if ( dev->colorSpace()->alpha(accessor.rawData()) == 0){
                    antiPixels.append( QPointF(x - 1,y) );
                    //continue;
                }

                //right
                accessor.moveTo(x + 1,y);
                if ( dev->colorSpace()->alpha(accessor.rawData()) == 0){
                    antiPixels.append( QPointF(x + 1,y) );
                    //continue;
                }

                // bottom left
                accessor.moveTo(x - 1,y + 1);
                if ( dev->colorSpace()->alpha(accessor.rawData()) == 0){
                    antiPixels.append( QPointF(x - 1,y + 1) );
                    //continue;
                }

                // bottom
                accessor.moveTo(x,y + 1);
                if ( dev->colorSpace()->alpha(accessor.rawData()) == 0){
                    antiPixels.append( QPointF(x,y + 1) );
                    //continue;
                }

                // bottom right
                accessor.moveTo(x + 1,y + 1);
                if ( dev->colorSpace()->alpha(accessor.rawData()) == 0){
                    antiPixels.append( QPointF(x + 1,y + 1) );
                    //continue;
                }
            }

        }
    }

    // anti-alias it
    int size = antiPixels.size();
    for (int i = 0; i < size; i++)
    {
        accessor.moveTo( antiPixels[i].x(), antiPixels[i].y() );
        memcpy(accessor.rawData(), outlineColor.data(), dev->colorSpace()->pixelSize() );
    }
}
Example #5
0
void SprayBrush::paintMetaballs(KisPaintDeviceSP dev, const KisPaintInformation &info, const KoColor &painterColor) {
    // TODO: make adjustable?
    qreal MIN_TRESHOLD = m_mintresh;
    qreal MAX_TRESHOLD = m_maxtresh;

//    dbgPlugins << "MAX " << MAX_TRESHOLD;
//    dbgPlugins << "MIN " << MIN_TRESHOLD;

    KoColor color = painterColor;
    qreal posX = info.pos().x();
    qreal posY = info.pos().y();

    //int points = m_coverage * (m_radius * m_radius * M_PI);
    qreal ballRadius = m_width * 0.5;

    // generate metaballs
    QList<Metaball> list;
    for (int i = 0; i < m_particlesCount ; i++){
        qreal x = (2 * drand48() * m_radius) - m_radius;
        qreal y = (2 * drand48() * m_radius) - m_radius;
        list.append(
                    Metaball( x, 
                              y ,
                              drand48() *  ballRadius)
                    );
    }

 
    // paint it
    KisRandomAccessor accessor = dev->createRandomAccessor(0, 0);

    qreal sum = 0.0;
    m_computeArea.translate( -qRound(posX), -qRound(posY) );
    for (int y = m_computeArea.y(); y <= m_computeArea.height(); y++){
        for (int x = m_computeArea.x() ; x <= m_computeArea.width(); x++){

            sum = 0.0;        

            for (int i = 0; i < m_particlesCount; i++){
                sum += list[i].equation(x, y );
            }
           
            if (sum >= MIN_TRESHOLD && sum <= MAX_TRESHOLD){
                    if (sum < 0.0) sum = 0.0;
                    if (sum > 1.0) sum = 1.0;

                    color.setOpacity(OPACITY_OPAQUE * sum);
                    accessor.moveTo( x + posX ,y + posY );
                    memcpy(accessor.rawData(), color.data(), dev->colorSpace()->pixelSize() );
            }
        }
    }
    m_computeArea.translate( qRound(posX), qRound(posY) );

#if 0        
        KisPainter dabPainter(dev);
        dabPainter.setFillColor(color);
        dabPainter.setPaintColor(color);
        dabPainter.setFillStyle(KisPainter::FillStyleForegroundColor);

        for (int i = 0; i < m_particlesCount; i++){
                qreal x = list[i].x() + posX;
                qreal y = list[i].y() + posY;
                dabPainter.paintEllipse(x, y, list[i].radius() * 2,list[i].radius() * 2);
        }
#endif

}
void KisCubismFilter::cubism(KisPaintDeviceSP src,
                             const QPoint& srcTopLeft,
                             KisPaintDeviceSP dst,
                             const QPoint& dstTopLeft,
                             const QSize& size,
                             quint32 tileSize,
                             quint32 tileSaturation) const
{
    Q_ASSERT(src);
    Q_ASSERT(dst);

    //fill the destination image with the background color (black for now)
    KisRectIteratorPixel dstIt = dst->createRectIterator(dstTopLeft.x(), dstTopLeft.y(), size.width(), size.height());
    qint32 depth = src->colorSpace()->colorChannelCount();
    while (! dstIt.isDone()) {
        for (qint32 i = 0; i < depth; i++) {
            dstIt.rawData()[i] = 0;
        }
        ++dstIt;
    }

    //compute number of rows and columns
    qint32 cols = (size.width() + tileSize - 1) / tileSize;
    qint32 rows = (size.height() + tileSize - 1) / tileSize;
    qint32 numTiles = (rows + 1) * (cols + 1);

//         setProgressTotalSteps(numTiles);
//         setProgressStage(i18n("Applying cubism filter..."),0);

    qint32* randomIndices = new qint32[numTiles];
    for (qint32 i = 0; i < numTiles; i++) {
        randomIndices[i] = i;
    }
    randomizeIndices(numTiles, randomIndices);

    qint32 count = 0;
    qint32 i, j, ix, iy;
    double x, y, width, height, theta;
    KisPolygon *poly = new KisPolygon();
    qint32 pixelSize = src->pixelSize();
    const quint8 *srcPixel /*= new quint8[ pixelSize ]*/;
    quint8 *dstPixel = 0;
    KisRandomAccessor srcAccessor = src->createRandomAccessor(0, 0);
    while (count < numTiles) {
        i = randomIndices[count] / (cols + 1);
        j = randomIndices[count] % (cols + 1);
        x = j * tileSize + (tileSize / 4.0) - randomDoubleNumber(0, tileSize / 2.0) + dstTopLeft.x();
        y = i * tileSize + (tileSize / 4.0) - randomDoubleNumber(0, tileSize / 2.0) + dstTopLeft.y();
        width = (tileSize + randomDoubleNumber(0, tileSize / 4.0) - tileSize / 8.0) * tileSaturation;
        height = (tileSize + randomDoubleNumber(0, tileSize / 4.0) - tileSize / 8.0) * tileSaturation;
        theta = randomDoubleNumber(0, 2 * M_PI);
        poly->clear();
        poly->addPoint(-width / 2.0, -height / 2.0);
        poly->addPoint(width / 2.0, -height / 2.0);
        poly->addPoint(width / 2.0, height / 2.0);
        poly->addPoint(-width / 2.0, height / 2.0);
        poly->rotate(theta);
        poly->translate(x, y);
        //  bounds check on x, y
        ix = (qint32) CLAMP(x, dstTopLeft.x(), dstTopLeft.x() + size.width() - 1);
        iy = (qint32) CLAMP(y, dstTopLeft.y(), dstTopLeft.y() + size.height() - 1);

        //read the pixel at ix, iy
        srcAccessor.moveTo(ix, iy);
        srcPixel = srcAccessor.rawData();
        if (srcPixel[pixelSize - 1]) {
            fillPolyColor(src, srcTopLeft, dst, dstTopLeft, size, poly, srcPixel, dstPixel);
        }
        count++;
//                 if ((count % 5) == 0) setProgress(count);
    }

}
void KisCubismFilter::fillPolyColor(KisPaintDeviceSP src,
                                    const QPoint& srcTopLeft,
                                    KisPaintDeviceSP dst,
                                    const QPoint & dstTopLeft,
                                    const QSize& size,
                                    KisPolygon* poly,
                                    const quint8* col,
                                    quint8* dest) const
// void KisCubismFilter::fillPolyColor (KisPaintDeviceSP src, KisPaintDeviceSP dst, KisPolygon* poly, const quint8* col, quint8* /*s*/, QRect rect) const
{
    Q_UNUSED(srcTopLeft);
    Q_UNUSED(dest);

    qint32         val;
    double         alpha;
    qint32         x, y;
    double          xx, yy;
    double          vec[2];
    QRect rect(dstTopLeft, size);
    qint32         x1 = rect.left(), y1 = rect.top(), x2 = rect.right(), y2 = rect.bottom();
//         qint32         selWidth, selHeight;
    qint32         *vals, *valsIter, *valsEnd;
    qint32         xs, ys, xe, ye;


    qint32 sx = (qint32)(*poly)[0].x();
    qint32 sy = (qint32)(*poly)[0].y();
    qint32 ex = (qint32)(*poly)[1].x();
    qint32 ey = (qint32)(*poly)[1].y();

    double dist = sqrt((double)(SQR(ex - sx) + SQR(ey - sy)));
    double oneOverDist = 0.0;
    if (dist > 0.0) {
        double oneOverDist = 1 / dist;
        vec[0] = (ex - sx) * oneOverDist;
        vec[1] = (ey - sy) * oneOverDist;
    }

    qint32 pixelSize = src->pixelSize();
    //get the extents of the polygon
    double dMinX, dMinY, dMaxX, dMaxY;
    poly->extents(dMinX, dMinY, dMaxX, dMaxY);
    qint32 minX = static_cast<qint32>(dMinX);
    qint32 minY = static_cast<qint32>(dMinY);
    qint32 maxX = static_cast<qint32>(dMaxX);
    qint32 maxY = static_cast<qint32>(dMaxY);
    qint32 sizeX = (maxX - minX) * SUPERSAMPLE;
    qint32 sizeY = (maxY - minY) * SUPERSAMPLE;

    qint32 *minScanlines = new qint32[sizeY];
    qint32 *minScanlinesIter = minScanlines;
    qint32 *maxScanlines = new qint32[sizeY];
    qint32 *maxScanlinesIter = maxScanlines;

    for (qint32 i = 0; i < sizeY; i++) {
        minScanlines[i] = maxX * SUPERSAMPLE;
        maxScanlines[i] = minX * SUPERSAMPLE;
    }

    if (poly->numberOfPoints()) {
        qint32 polyNpts = poly->numberOfPoints();

        xs = static_cast<qint32>((*poly)[polyNpts-1].x());
        ys = static_cast<qint32>((*poly)[polyNpts-1].y());
        xe = static_cast<qint32>((*poly)[0].x());
        ye = static_cast<qint32>((*poly)[0].y());

        xs *= SUPERSAMPLE;
        ys *= SUPERSAMPLE;
        xe *= SUPERSAMPLE;
        ye *= SUPERSAMPLE;

        convertSegment(xs, ys, xe, ye, minY * SUPERSAMPLE, minScanlines, maxScanlines, minX* SUPERSAMPLE, maxX* SUPERSAMPLE);

        KisPolygon::iterator it;

        for (it = poly->begin(); it != poly->end();) {
            xs = static_cast<qint32>((*it).x());
            ys = static_cast<qint32>((*it).y());
            ++it;

            if (it != poly->end()) {
                xe = static_cast<qint32>((*it).x());
                ye = static_cast<qint32>((*it).y());

                xs *= SUPERSAMPLE;
                ys *= SUPERSAMPLE;
                xe *= SUPERSAMPLE;
                ye *= SUPERSAMPLE;

                convertSegment(xs, ys, xe, ye, minY * SUPERSAMPLE, minScanlines, maxScanlines, minX* SUPERSAMPLE, maxX* SUPERSAMPLE);
            }
        }
    }

    KisRandomAccessor dstAccessor = dst->createRandomAccessor(0, 0);

    KoMixColorsOp * mixOp = src->colorSpace()->mixColorsOp();
    quint8* buf = new quint8[pixelSize];

    vals = new qint32[sizeX];
//         x1 = minX; x2 = maxX; y1 = minY; y2 = maxY;
    for (qint32 i = 0; i < sizeY; i++, minScanlinesIter++, maxScanlinesIter++) {
        if (!(i % SUPERSAMPLE)) {
            memset(vals, 0, sizeof(qint32) * sizeX);
        }

        yy = static_cast<double>(i) / static_cast<double>(SUPERSAMPLE) + minY;

        for (qint32 j = *minScanlinesIter; j < *maxScanlinesIter; j++) {
            x = j - minX * SUPERSAMPLE;
            vals[x] += 255;
        }

        if (!((i + 1) % SUPERSAMPLE)) {
            y = (i / SUPERSAMPLE) + minY;
            if (y >= y1 && y <= y2) {
                for (qint32 j = 0; j < sizeX; j += SUPERSAMPLE) {
                    x = (j / SUPERSAMPLE) + minX;

                    if (x >= x1 && x <= x2) {
                        for (val = 0, valsIter = &vals[j], valsEnd = &valsIter[SUPERSAMPLE]; valsIter < valsEnd; valsIter++) {
                            val += *valsIter;
                        }
                        val /= SQR(SUPERSAMPLE);

                        if (val > 0) {
                            xx = static_cast<double>(j) / static_cast<double>(SUPERSAMPLE) + minX;
                            alpha = calcAlphaBlend(vec, oneOverDist, xx - sx, yy - sy);

                            qint16 weights[2];
                            weights[0] = static_cast<quint8>(alpha * 255);
                            weights[1] = 255 - weights[0];

                            dstAccessor.moveTo(x, y);
                            memcpy(buf, dstAccessor.rawData(), sizeof(quint8) * pixelSize);

                            const quint8* colors[2];
                            colors[0] = col;
                            colors[1] = buf;

                            mixOp->mixColors(colors, weights, 2, dstAccessor.rawData());
                        }
                    }
                }
            }
        }
    }
    delete[] buf;
    delete[] vals;
    delete[] minScanlines;
    delete[] maxScanlines;
}