//NetTalk
/*------------------------------------------------------------------------------*\
 =============================
   模块名称: RippleWnd.cpp
 =============================
 
 [版权]
 
                                                 
\*------------------------------------------------------------------------------*/
//借鉴来的水波特效，作者不详，在此谢过
#include "WndX.h"

#include "RippleWnd.h"
#include <Stdio.h>
#include <Windowsx.h>
#pragma comment(lib,"ddraw")


/*------------------------------------------------------------------------------*/
CRippleWnd::CRippleWnd()
{
	m_iCount=0;
	m_dwFps=0;
	
}

/*------------------------------------------------------------------------------*/
CRippleWnd::~CRippleWnd()
{
	
}
/*------------------------------------------------------------------------------*/
BOOL CRippleWnd::Create(RECT &rc, HWND hParent,UINT uBmpID,int iWidth,int iHeight)
{
	BOOL bRet=FALSE;
	m_iWidth=iWidth;
	m_iHeight=iHeight;
	if(!CWndX::Create(0,0,0,WS_CHILD|WS_VISIBLE,rc,hParent,0,0))
		goto RET;
	SetClassLong(m_hWnd,GCL_HBRBACKGROUND,0);
	if(!InitDDraw(uBmpID,iWidth,iHeight))
		goto RET;
	SetTimer(m_hWnd,1,30,0);
	m_dwTime=GetTickCount();
	bRet=TRUE;
RET:
	return bRet;
}
/*------------------------------------------------------------------------------*/
LRESULT CRippleWnd::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_DESTROY:
		KillTimer(m_hWnd,1);
		FreeObject();
		break;
	case WM_TIMER:
		{
			if(IsWindowVisible(m_hWnd))
			{
				UpdateFrame();
			}
		}
		break;
	case WM_LBUTTONDOWN:
		
		DropStone(LOWORD(lParam),HIWORD(lParam),3,128);
		break;
	
	case WM_MOUSEMOVE:
		if (wParam==MK_LBUTTON )
		{
			
			DropStone(LOWORD(lParam),HIWORD(lParam),3,128);
		}
		break;
			
	}
	return CWndX::WndProc(uMsg,wParam,lParam);
}
/*------------------------------------------------------------------------------*/
BOOL CRippleWnd::InitDDraw(UINT uBmpID,int iWidth,int iHeight)
{
	DDSURFACEDESC       ddsd;
    HRESULT             ddrval;

    //创建DirectDraw对象
	ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
    if( ddrval != DD_OK )
        return FALSE;

    ddrval = lpDD->SetCooperativeLevel(NULL, DDSCL_NORMAL);
    if( ddrval != DD_OK )
        return FALSE;

    ddsd.dwSize = sizeof( ddsd );
    ddsd.dwFlags = DDSD_CAPS ;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

    ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
    if( ddrval != DD_OK )
        return FALSE;

	ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN |DDSCAPS_SYSTEMMEMORY ;
	ddsd.dwWidth = iWidth;
    ddsd.dwHeight = iHeight;

    if (lpDD->CreateSurface(&ddsd, &lpDDSPic1, NULL) != DD_OK)
		return FALSE;
    if (lpDD->CreateSurface(&ddsd, &lpDDSPic2, NULL) != DD_OK)
		return FALSE;

	lpDD->CreateClipper(0, &lpClipper, NULL);
	lpClipper->SetHWnd(0, m_hWnd);
	lpDDSPrimary->SetClipper(lpClipper);

	
	DDReLoadBitmap(lpDDSPic1, MAKEINTRESOURCE(uBmpID));

    buf1 = new short[iWidth*iHeight];
	buf2 = new short[iWidth*iHeight];
	ZeroMemory(buf1, iWidth*iHeight*sizeof(short));
	ZeroMemory(buf2, iWidth*iHeight*sizeof(short));

	
    return TRUE;
}
/*------------------------------------------------------------------------------*/
void CRippleWnd::FreeObject()
{
	if( lpDD != NULL )//释放DirectDraw对象
    {
        if( lpDDSPrimary != NULL )//释放主页面。
        {
            lpDDSPrimary->Release();
            lpDDSPrimary = NULL;
        }
        if( lpDDSPic1 != NULL )//释放离屏页面。
        {
            lpDDSPic1->Release();
            lpDDSPic1 = NULL;
        }
        if( lpDDSPic2 != NULL )
        {
            lpDDSPic2->Release();
            lpDDSPic2 = NULL;
        }
		if (lpClipper!=NULL)
		{
			lpClipper->Release();
			lpClipper=NULL;
		}
        lpDD->Release();
        lpDD = NULL;
    }
	if(buf1)
		delete buf1;
	if(buf2)
		delete buf2;
}
/*------------------------------------------------------------------------------*/
void CRippleWnd::DropStone(int x,int y,int stonesize,int stoneweight)
{
	
	//判断坐标是否在屏幕范围内
	if ((x+stonesize)>m_iWidth || 
		(y+stonesize)>m_iHeight||
		(x-stonesize)<0||
		(y-stonesize)<0)
		return;

	for (int posx=x-stonesize; posx<x+stonesize; posx++)
		for (int posy=y-stonesize; posy<y+stonesize; posy++)
			if ((posx-x)*(posx-x) + (posy-y)*(posy-y) < stonesize*stonesize)
				buf1[m_iWidth*posy+posx] = -stoneweight;
}
/*------------------------------------------------------------------------------*/

void CRippleWnd::RenderRipple()
{
	//锁定两个离屏页面
	DDSURFACEDESC ddsd1, ddsd2;
	ddsd1.dwSize = sizeof (DDSURFACEDESC);
	ddsd2.dwSize = sizeof(DDSURFACEDESC);
	
	lpDDSPic1->Lock(NULL, &ddsd1, DDLOCK_WAIT, NULL);
	lpDDSPic2->Lock(NULL, &ddsd2, DDLOCK_WAIT, NULL);
	
	//取得页面象素位深度，和页面内存指针
	int depth=ddsd1.ddpfPixelFormat.dwRGBBitCount/8;
	BYTE *Bitmap1 = (BYTE*)ddsd1.lpSurface;
	BYTE *Bitmap2 = (BYTE*)ddsd2.lpSurface;
	
	//下面进行页面渲染
	int xoff, yoff;
	int k = m_iWidth;
	for (int i=1; i<m_iHeight-1; i++)
	{
		for (int j=0; j<m_iWidth; j++)
		{
			//计算偏移量
			xoff = buf1[k-1]-buf1[k+1];
			yoff = buf1[k-m_iWidth]-buf1[k+m_iWidth];

			//判断坐标是否在窗口范围内
			if ((i+yoff )< 0 ) {k++; continue;}
			if ((i+yoff )> m_iHeight) {k++; continue;}
			if ((j+xoff )< 0 ) {k++; continue;}
			if ((j+xoff )> m_iWidth ) {k++; continue;}

			//计算出偏移象素和原始象素的内存地址偏移量
			int pos1, pos2;
			pos1=ddsd1.lPitch*(i+yoff)+ depth*(j+xoff);
			pos2=ddsd2.lPitch*i+ depth*j;

			//复制象素
			for (int d=0; d<depth; d++)
				Bitmap2[pos2++]=Bitmap1[pos1++];
			k++;
		}
	}
	//解锁页面
	lpDDSPic1->Unlock(&ddsd1);
	lpDDSPic2->Unlock(&ddsd2);
	HDC hdc;
	lpDDSPic2->GetDC(&hdc);
	char szFps[10];
	
	sprintf(szFps,"%dFPS",m_dwFps);
	
	SetBkMode(hdc,TRANSPARENT);
	SetTextColor(hdc,0x00ffaaaa);
	DrawText(hdc,szFps,strlen(szFps),&CRectX(200,5,280,20),DT_RIGHT);
	
	lpDDSPic2->ReleaseDC(hdc);
}


/*------------------------------------------------------------------------------*/
void CRippleWnd::UpdateFrame()
{
	m_iCount++;
	if(m_iCount>=20)
	{
	DropStone(
			(int)(m_iWidth*((short)rand()/32767.0)),
			(int)(m_iHeight*((short)rand()/32767.0)),
			3,
			128
			);
	DWORD temp=GetTickCount();
	m_dwFps=20000/(temp-m_dwTime);
	m_dwTime=temp;


	m_iCount=0;
	}

	
	RippleSpread();
			
	RenderRipple();//页面渲染

	//将离屏页面图象Blit到主页面
	RECT Window;
	POINT pt;
	GetClientRect(m_hWnd, &Window);
	pt.x=pt.y=0;
	ClientToScreen(m_hWnd, &pt);
	OffsetRect(&Window, pt.x, pt.y);
	lpDDSPrimary->Blt(&Window, lpDDSPic2, NULL, DDBLT_WAIT, NULL);
}
/*------------------------------------------------------------------------------*/
void CRippleWnd::RippleSpread()
{
	for (int i=m_iWidth; i<m_iWidth*m_iHeight-m_iWidth; i++)
	{
		//波能扩散
		buf2[i] = ((buf1[i-1]+
					buf1[i+1]+
					buf1[i-m_iWidth]+
					buf1[i+m_iWidth])
					>>1)
					- buf2[i];
		//波能衰减
		buf2[i] -= buf2[i]>>5;
	}

	//交换波能数据缓冲区
	short *ptmp =buf1;
	buf1 = buf2;
	buf2 = ptmp;
}


