// SquidDynamicPane.cpp: implementation of the SquidDynamicPane class. // ////////////////////////////////////////////////////////////////////// #include <qframe.h> #include <qlayout.h> #include <qpainter.h> #include "SquidPortrait.h" #include "SquidDynamicPane.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// SquidDynamicPane::SquidDynamicPane( QWidget* parent, QImage* f, QImage* g ) : QFrame( parent ), f1( f ), f2( g ), diffmask( NULL ), maskdiffs( false ), scroll( new QScrollView( this ) ) { QSize dsize = f1->size(); if ( f2->height() > f1->height() ) dsize.setHeight( f2->height() ); if ( f2->width() > f1->width() ) dsize.setWidth( f2->width() ); img = new QImage( dsize, 32 ); if ( f1->hasAlphaBuffer() || f2->hasAlphaBuffer() ) img->setAlphaBuffer( true ); scroll->setVScrollBarMode( QScrollView::AlwaysOff ); scroll->setHScrollBarMode( QScrollView::AlwaysOff ); pic = new SquidPortrait( scroll->viewport(), img ); scroll->addChild( pic ); slider = new QSlider( 0, 99, 10, 99, Horizontal, this ); QVBoxLayout* vlayout = new QVBoxLayout( this ); vlayout->addWidget( scroll ); vlayout->addSpacing( 4 ); vlayout->addWidget( slider ); setMaximumSize( pic->maximumWidth() + 4, pic->maximumHeight() + 24 ); setMinimumSize( 0, 0 ); } SquidDynamicPane::~SquidDynamicPane() { } void SquidDynamicPane::SetBlendSize( int size ) { blendsize = size; disconnect( slider, SIGNAL( valueChanged( int ) ), 0, 0 ); if ( img->width() * img->height() < blendsize ) { connect( slider, SIGNAL( valueChanged( int ) ), this, SLOT( Blend( int ) ) ); Blend( slider->value() ); } else { connect( slider, SIGNAL( valueChanged( int ) ), this, SLOT( Stipple( int ) ) ); oldslid = 0; Stipple( 99 ); Stipple( slider->value() ); } } void SquidDynamicPane::Blend( int bl ) { QRgb col1, col2; QRgb bkrd = scroll->viewport()->paletteBackgroundColor().rgb(); QRgb *s1, *s2, *sd; int r, g, b, a; float w1 = ( 99.0 - bl ) / 99.0 ; float w2 = bl / 99.0 ; for ( int y = 0 ; y < img->height() ; y++ ) { if ( y < f1->height() ) s1 = (QRgb*)f1->scanLine( y ); else s1 = NULL; if ( y < f2->height() ) s2 = (QRgb*)f2->scanLine( y ); else s2 = NULL; sd = (QRgb*)img->scanLine( y ); for ( int x = 0 ; x < img->width() ; x++ ) { if ( maskdiffs && !diffmask[x][y] ) { sd[x] = bkrd; continue; } if ( s1 && x < f1->width() ) col1 = s1[x]; else col1 = bkrd; if ( s2 && x < f2->width() ) col2 = s2[x]; else col2 = bkrd; r = qRed( col1 )*w1 + qRed( col2 )*w2; g = qGreen( col1 )*w1 + qGreen( col2 )*w2; b = qBlue( col1 )*w1 + qBlue( col2 )*w2; a = qAlpha( col1 )*w1 + qAlpha( col2 )*w2; sd[x] = qRgba( r, g, b, a ); } } QPainter p; pic->drawContents( &p ); } void SquidDynamicPane::Stipple( int s ) { if ( oldslid == s ) return; bool f2w = oldslid < s; if ( f2w ) { for ( int a = oldslid ; a <= s ; a++ ) { StippleStep( a, f2w ); } } else { for ( int a = s ; a <= oldslid ; a++ ) { StippleStep( a, f2w ); } } oldslid = s; QPainter p; pic->drawContents( &p ); } // Go and toggle 1% of the picture. Which 1% is given by "s", and which // direction to toggle is given by "f2ward". void SquidDynamicPane::StippleStep( int s, bool f2ward ) { int z = ( ( ( s%2 )*5 + s/2 ) + s/10 )%10; QImage* i; if ( f2ward ) i = f2; else i = f1; for ( int y = (s/2)%10 ; y < img->height() ; y += 10 ) { for ( int x = z ; x < img->width() ; x += 10 ) { if ( y >= i->height() || x >= i->width() || ( maskdiffs && !diffmask[x][y] ) ) img->setPixel( x, y, scroll->viewport()->paletteBackgroundColor().rgb() ); else img->setPixel( x, y, i->pixel( x, y ) ); } } } void SquidDynamicPane::resizeEvent( QResizeEvent* e ) { if ( e->size().width() < 20 ) slider->hide(); else slider->show(); QFrame::resizeEvent( e ); } void SquidDynamicPane::HScroll( int pct ) { int d = scroll->contentsWidth() - scroll->visibleWidth(); if ( !d ) return; d *= pct; d /= 100; scroll->setContentsPos( d, scroll->contentsY() ); } void SquidDynamicPane::VScroll( int pct ) { int d = scroll->contentsHeight() - scroll->visibleHeight(); if ( !d ) return; d *= pct; d /= 100; scroll->setContentsPos( scroll->contentsX(), d ); } void SquidDynamicPane::GenDiffMask( int tol ) { //The "tolerance" is the sum of RGBA differences allowed. if ( !diffmask ) { diffmask = new bool*[img->width()]; for ( int t = 0 ; t < img->width() ; t++ ) { diffmask[t] = new bool[img->height()]; } } QRgb col1, col2; QRgb bkrd = scroll->viewport()->paletteBackgroundColor().rgb(); QRgb *s1, *s2, *sd; int r, g, b, a; for ( int y = 0 ; y < img->height() ; y++ ) { if ( y < f1->height() ) s1 = (QRgb*)f1->scanLine( y ); else s1 = NULL; if ( y < f2->height() ) s2 = (QRgb*)f2->scanLine( y ); else s2 = NULL; sd = (QRgb*)img->scanLine( y ); for ( int x = 0 ; x < img->width() ; x++ ) { if ( s1 && x < f1->width() ) col1 = s1[x]; else col1 = bkrd; if ( s2 && x < f2->width() ) col2 = s2[x]; else col2 = bkrd; r = ( qRed( col1 ) - qRed( col2 ) ) * ( qRed( col1 ) - qRed( col2 ) ); g = ( qGreen( col1 ) - qGreen( col2 ) ) * ( qGreen( col1 ) - qGreen( col2 ) ); b = ( qBlue( col1 ) - qBlue( col2 ) ) * ( qBlue( col1 ) - qBlue( col2 ) ); a = ( qAlpha( col1 ) - qAlpha( col2 ) ) * ( qAlpha( col1 ) - qAlpha( col2 ) ); diffmask[x][y] = ( r + g + b + a > tol ); } } } void SquidDynamicPane::Redraw() { oldslid = 0; Stipple( 99 ); slider->setValue( 99 ); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 2401 | Sam Stafford |
Rename SID to SQUID - avoids conflicts with another program. Also lets me use cool squid icon. |
||
//guest/sam_stafford/sid/src/SidDynamicPane.cpp | |||||
#10 | 2050 | Sam Stafford | Settings. | ||
#9 | 2036 | Sam Stafford |
Uber-L33T "highlight" feature. Has to be seen to be believed. |
||
#8 | 2034 | Sam Stafford |
Working "subtraction" diff and zooming. Definitely need to make some decent toolbutton icons. |
||
#7 | 2032 | Sam Stafford |
Minor improvements to Blend() performance - use floating point math to average RGBA values, and circumvent the pixel() and setPixel() method calls by copying and pasting the parts relevant to 32-bit images. |
||
#6 | 2030 | Sam Stafford |
Scrolling. It's not perfect, but I'm happy enough with it to move on with my life. |
||
#5 | 2029 | Sam Stafford |
Give Blend() the same upgrade I gave Stipple() in terms of handling different-sized images. |
||
#4 | 2028 | Sam Stafford |
Make the "diff" image as large as need be to accomodate both images, in the event of different-sized images. |
||
#3 | 2025 | Sam Stafford | A slightly niftier way of doing the coarse blending. | ||
#2 | 2023 | Sam Stafford |
Improvements to the middle pane slider - if the image is over a certain size, use a more efficient (but less cool-looking) algorithm to blend between the two images. |
||
#1 | 2016 | Sam Stafford |
Barely-functional Sid (about three hours worth of code). "Sid" = "Sam's Image Differ", for those who were curious. |