// CSweeper.cpp: implementation of the CSweeper class. // ////////////////////////////////////////////////////////////////////// #include "CSweeper.h" extern TextureBrush *g_paBrCleanBkg; extern Bitmap *g_paBmDirtyBkg; CSweeper::CSweeper() { ZeroMemory(&m_rDesktop,sizeof(m_rDesktop)); ZeroMemory(&m_vLastPos,sizeof(m_vLastPos)); m_flStepRadius=0.0f; m_flBroomWidth=0.0f; m_flSweepLength=0.0f; m_paBroomOn=NULL; m_paBroomOff=NULL; m_paBackground=NULL; m_bSweeping=false; m_flLastAngle=0.0f; m_flDist=0.0f; } CSweeper::~CSweeper() { Destroy(); } void CSweeper::Destroy() { if (m_paBroomOn!=NULL) { delete m_paBroomOn; m_paBroomOn=NULL; } if (m_paBroomOff!=NULL) { delete m_paBroomOff; m_paBroomOff=NULL; } if (m_paBackground!=NULL) { delete m_paBackground; m_paBackground=NULL; } } BOOL CSweeper::Init(HWND hWnd) { int nRand; float flWidth; float flHeight; Destroy(); // Get desktop dimensions (top/left can be negative on multimon) GetClientRect(hWnd,&m_rDesktop); flWidth=(float)m_rDesktop.right; flHeight=(float)m_rDesktop.bottom; m_rDesktop.top+=GetSystemMetrics(SM_YVIRTUALSCREEN); m_rDesktop.bottom+=GetSystemMetrics(SM_YVIRTUALSCREEN); m_rDesktop.left+=GetSystemMetrics(SM_XVIRTUALSCREEN); m_rDesktop.right+=GetSystemMetrics(SM_XVIRTUALSCREEN); m_flVelMax=((float)rand()/(float)RAND_MAX)*20.0f+20.0f; m_paBroomOn=LoadTGAResource(MAKEINTRESOURCE(IDR_BROOMON)); m_paBroomOff=LoadTGAResource(MAKEINTRESOURCE(IDR_BROOMOFF)); m_nSnapshotSize=(int)sqrt(m_paBroomOn->GetWidth()*m_paBroomOn->GetWidth()+(m_paBroomOn->GetHeight()+m_flVelMax*2.0f)*(m_paBroomOn->GetHeight()+m_flVelMax*2.0f)); m_paBackground=new Bitmap(m_nSnapshotSize,m_nSnapshotSize,PixelFormat32bppPARGB); nRand=rand(); if (nRandGetWidth()-6.0f; m_flSweepLength=((float)rand()/(float)RAND_MAX)*50.0f+200.0f; m_flStepRadius=m_flSweepLength; m_vVel=Normalize(m_vVel); m_vVel.X*=m_flVelMax; m_vVel.Y*=m_flVelMax; m_vLastPos=m_vPos; m_bSweeping=false; m_flDist=0.0f; m_flLastAngle=((float)atan2(m_vVel.Y,m_vVel.X)*180.0f/3.1415f); return true; } BOOL CSweeper::Move(Graphics *g) // Returns true if moved on screen, false if moved outside screen { float flAngle; float flAngleDist; if (m_bSweeping) { m_vPos=m_vPos+m_vVel; if ((m_vPos.X<(float)m_rDesktop.left-m_flSweepLength) || (m_vPos.X>(float)m_rDesktop.right+m_flSweepLength) || (m_vPos.Y<(float)m_rDesktop.top-m_flSweepLength) || (m_vPos.Y>(float)m_rDesktop.bottom+m_flSweepLength)) { // If sweeper is outside desktop, erase it and remove it NoSweep(g); return false; } Sweep(g); } else { NoSweep(g); } if (!m_bSweeping && (m_flDist==0.0f)) { // If not sweeping and broom is back at distance 0, start next sweep m_bSweeping=true; m_flLastAngle=((float)atan2(m_vVel.Y,m_vVel.X)*180.0f/3.1415f); m_vPos.X=m_vPos.X-m_vVel.X*(m_flSweepLength/m_flVelMax*0.75f); m_vPos.Y=m_vPos.Y-m_vVel.Y*(m_flSweepLength/m_flVelMax*0.75f); m_vLastPos=m_vPos; flAngle=((float)atan2(m_vVel.Y,m_vVel.X)*180.0f/3.1415f); flAngleDist=((float)rand()/(float)RAND_MAX)*40.0f-20.0f; flAngle+=flAngleDist; m_vVel.X=(float)cos(flAngle*3.1415f/180.0f)*m_flVelMax; m_vVel.Y=(float)sin(flAngle*3.1415f/180.0f)*m_flVelMax; } return true; } void CSweeper::Sweep(Graphics *g) { Graphics *gBackground; RectF rect(0.0f,0.0f,m_flBroomWidth,m_flVelMax); RectF rect2(0.0f,0.0f,(float)m_paBroomOn->GetWidth(),(float)m_paBroomOn->GetHeight()+m_flVelMax); Matrix mat; GraphicsPath Path; Pen pen(Color(10,0,0,0),2); Graphics *gDirty; if (m_flDist!=0.0f) { // If broom has moved already, erase a rect on dirty background // Set up the brush transform (opposite from original transform) g_paBrCleanBkg->ResetTransform(); mat.Reset(); mat.Translate(0.0f,-m_flDist); mat.Translate(-(float)m_paBroomOn->GetWidth()/2.0f,-(float)m_paBroomOn->GetHeight()+20.0f); mat.Rotate(-m_flLastAngle-270.0f); mat.Translate(-m_vLastPos.X+m_rDesktop.left,-m_vLastPos.Y+m_rDesktop.top); g_paBrCleanBkg->SetTransform(&mat); // Set up original transform and erase from DirtyBkg a rectangle where the broom moved gDirty=new Graphics(g_paBmDirtyBkg); gDirty->TranslateTransform(m_vLastPos.X-m_rDesktop.left,m_vLastPos.Y-m_rDesktop.top); gDirty->RotateTransform(m_flLastAngle+270.0f); gDirty->TranslateTransform((float)m_paBroomOn->GetWidth()/2.0f,(float)m_paBroomOn->GetHeight()-20.0f); gDirty->TranslateTransform(0.0f,m_flDist); gDirty->FillRectangle(g_paBrCleanBkg,rect); // Draw dirty lines around the broom, to simulate dirty that fell beside the broom gDirty->DrawLine(&pen,0.0f,0.0f,0.0f,m_flVelMax+2); gDirty->DrawLine(&pen,0.0f,m_flVelMax+2,m_flBroomWidth,m_flVelMax+2); gDirty->DrawLine(&pen,m_flBroomWidth,m_flVelMax+2,m_flBroomWidth,0.0f); delete gDirty; } // Get the bounds of the broom after rotations Path.AddRectangle(rect2); mat.Reset(); mat.Translate(m_vLastPos.X-m_rDesktop.left,m_vLastPos.Y-m_rDesktop.top); mat.Rotate(m_flLastAngle+270.0f); mat.Translate(m_flBroomWidth/2.0f,0.0); mat.Translate(0.0f,m_flDist); Path.GetBounds(&rect,&mat,&pen); // Draw on a temp surface whatever was on the dirty background where the broom is to be drawn gBackground=new Graphics(m_paBackground); gBackground->DrawImage(g_paBmDirtyBkg,0,0,(int)rect.X,(int)rect.Y,(int)rect.Width,(int)rect.Height,UnitPixel); // Draw broom on temp surface gBackground->ResetTransform(); gBackground->TranslateTransform(rect.Width/2.0f,rect.Height/2.0f); gBackground->RotateTransform(m_flLastAngle+270.0f); gBackground->TranslateTransform(-(float)m_paBroomOn->GetWidth()/2.0f,-(float)m_paBroomOn->GetHeight()/2.0f+m_flVelMax/2.0f); gBackground->DrawImage(m_paBroomOn,0,0,0,0,m_paBroomOn->GetWidth(),m_paBroomOn->GetHeight(),UnitPixel); delete gBackground; // Draw temp surface to screen g->ResetTransform(); g->DrawImage(m_paBackground,(int)rect.X,(int)rect.Y,0,0,(int)rect.Width,(int)rect.Height,UnitPixel); // Update distance, continue the sweep m_flDist+=m_flVelMax; if (m_flDist>m_flSweepLength) { // If sweep is at the end, start moving broom back m_flDist-=m_flVelMax; m_bSweeping=false; } } void CSweeper::NoSweep(Graphics *g) { Graphics *gBackground; RectF rect(0.0f,0.0f,m_flBroomWidth,m_flVelMax); RectF rect2(0.0f,0.0f,(float)m_paBroomOn->GetWidth(),(float)m_paBroomOn->GetHeight()+m_flVelMax); Matrix mat; GraphicsPath Path; Pen pen(Color(20,0,0,0),2); // Get the bounds of the broom after rotations Path.AddRectangle(rect2); mat.Reset(); mat.Translate(m_vLastPos.X,m_vLastPos.Y); mat.Rotate(m_flLastAngle+270.0f); mat.Translate(m_flBroomWidth/2.0f,0.0f); mat.Translate(0.0f,m_flDist); Path.GetBounds(&rect,&mat,&pen); // Draw on a temp surface whatever was on the dirty background where the broom is to be drawn gBackground=new Graphics(m_paBackground); gBackground->DrawImage(g_paBmDirtyBkg,0,0,(int)rect.X-m_rDesktop.left,(int)rect.Y-m_rDesktop.top,(int)rect.Width,(int)rect.Height,UnitPixel); // Draw broom on temp surface gBackground->ResetTransform(); gBackground->TranslateTransform(rect.Width/2.0f,rect.Height/2.0f); gBackground->RotateTransform(m_flLastAngle+270.0f); gBackground->TranslateTransform(-(float)m_paBroomOn->GetWidth()/2.0f,-(float)m_paBroomOn->GetHeight()/2.0f-m_flVelMax/2.0f); gBackground->DrawImage(m_paBroomOff,0,0,0,0,m_paBroomOn->GetWidth(),m_paBroomOn->GetHeight(),UnitPixel); delete gBackground; // Draw temp surface to screen g->ResetTransform(); g->DrawImage(m_paBackground,(int)rect.X-m_rDesktop.left,(int)rect.Y-m_rDesktop.top,0,0,(int)rect.Width,(int)rect.Height,UnitPixel); // Update distance, continue moving back to start of sweep m_flDist-=m_flVelMax; if (m_flDist<=(m_flSweepLength/m_flVelMax*0.25f)*Magnitude(m_vVel)) { // If all the way back, erase last broom, and get ready for next sweep g->DrawImage(g_paBmDirtyBkg,(int)rect.X-m_rDesktop.left,(int)rect.Y-m_rDesktop.top,(int)rect.X-m_rDesktop.left,(int)rect.Y-m_rDesktop.top,(int)rect.Width,(int)rect.Height,UnitPixel); m_flDist=0.0f; } }