Environment: Visual C++
To start with, the program is a small-time animation in VC++. What does an image look like when it is dipped in a tub of water when the tub is subjected to a constant vibration? The more difficult part is to produce the ripple effect, as when a pebble is thrown in the tub. So, I will tell at least this much.
The difference I make is that I am going to explain how to produce this effect, not simply copy and paste code form somewhere. Much of the code that I saw over the Net regarding small-time animation carries no explanation at all.
Some Theory
Let p(x,y) be a pixel at the x,y coordinate in an image. Imagine the pixel p(x,y) moving randomly around its four m-neighbourhoods, namely p(x-m,y-m),p(x+m,y+m), p(x-m,y),p(x,y-m) randomly, where m is a natural number {1,2,3,4,5,6,…}. Think what will happen if all the pixels in the image move in such a manner; you get the effect.
The Practice
When someone clicks the Ok button, I do the following:
CDC me1; CBitmap ma1; BITMAP info1; CDC me3; CBitmap ma3; BITMAP info3;
All the above all globals.
ma1.LoadBitmap(IDB_BITMAP1); me1.CreateCompatibleDC(dc); ma1.GetBitmap(&info1); me1.SelectObject(ma1); me3.CreateCompatibleDC(dc); ma3.CreateCompatibleBitmap(dc,1000,1000); me3.SelectObject(ma3); me3.BitBlt(0,0,1000,1000,dc,0,0,SRCCOPY);
I have one more copy of the DC just in case you need it for more animation tricks; it is not required here, though.
me3.BitBlt(0,0,info1.bmWidth,info1.bmHeight,&me1,0,0,SRCCOPY); HBITMAP hbm=NULL; HDC DeskHdc=::GetDC(NULL); HDC hdc=::CreateCompatibleDC(DeskHdc); BitmapInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); BitmapInfo.bmiHeader.biWidth=info1.bmWidth; BitmapInfo.bmiHeader.biHeight=info1.bmHeight; BitmapInfo.bmiHeader.biSizeImage=(((info1.bmWidth * 32 + 31) & ~31) >> 3) * info1.bmHeight; BitmapInfo.bmiHeader.biCompression=BI_RGB ; BitmapInfo.bmiHeader.biXPelsPerMeter=0; BitmapInfo.bmiHeader.biYPelsPerMeter =0; BitmapInfo.bmiHeader.biClrImportant = 0; BitmapInfo.bmiHeader.biClrUsed = 0; // we are not using palette BitmapInfo.bmiHeader.biPlanes = 1; // has to be 1 BitmapInfo.bmiHeader.biBitCount = 32; // as we want true-color hbm=::CreateDIBSection(GetDesktopWindow()->GetWindowDC() ->m_hDC, &BitmapInfo,DIB_RGB_COLORS,(void**)&imageData,NULL,0); HBITMAP m_hbmOld; if (hbm) { m_hbmOld = (HBITMAP)::SelectObject(hdc,hbm); } ::BitBlt(hdc,0,0,info1.bmWidth,info1.bmHeight,me3.m_hDC,0,0, SRCCOPY);
The above is a standard piece of code that would be given in any good VC++ books.
It is done so that I get access to the image’s bits that are now in the imageData member; the trick is to manipulate the bits directly and use SetDIBitsToDevice(–) to plot the image quickly and finally to repeat the process in a timer.
So, let us look at the OnTimer function: When we enter the timer for the first time, I want to copy the image bits array into another pointer, namely p, and a two-dimensional array, namely imgArr.
if(r= =0)
{
memcpy(p,imageData,BitmapInfo.bmiHeader.biSizeImage);
for(intj=0;j<=info1.bmHeight;j++)
for(intk=0;k<=info1.bmWidth;k++)
{
imgArr[j][k]=p[j*info1.bmWidth+k]; // See note below for this
// calculation
}
r= 1;
}
I want to stop this timer until I finish the following processing:
KillTimer(0);
Run through the whole image:
for(intk=0;k<=info1.bmHeight;k++)
for(intf=0;f<=info1.bmWidth;f++)
{
int R,G,B;
int Rx,Gx;
//Rx=rand()%(int)m+k;
//Gx=rand()%(int)m+f;
Then, I pick up a random 3-neighbouring pixel from the place (k,f):
Rx=rand()%(int)3+k; Gx=rand()%(int)3+f;
Put the current pixel (the k,f guy) = the so-selected 3-neighbouring pixel:
p[k*info1.bmWidth+f]=imgArr[Rx][Gx]; // For more explanation
// of this calculation,
// see the note at the end
}
Now, all the pixels in the image have been replaced by their 3-neighbouring guys, that too randomly:
m-=.5;
if(m<1)
m=20;
if(r>info1.bmWidth)
r=0;
SetDIBitsToDevice(::GetDC(NULL),
0,
0,
info1.bmWidth,
info1.bmHeight,
0,
0,
0,
info1.bmHeight,
p,
//imageData,
&BitmapInfo,
DIB_RGB_COLORS);
Now, resume the timer for the next round of random replacement:
SetTimer(0,30,0);
Note: One item worth mentioning will be how the bits are stored in one single array. From p[0] to p[info1.bmWidth], we have a single row of the image, then from p[info1.bmWidth+1] to p[info1.bmWidth+ info1.bmWidth] is the second row of the image and so on until p[info1.bmWidth*info1.bmHeight].