// GrCard.cpp: implementation of the CGrCard class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Fantan.h" #include "GrCard.h" #include "ActionHandler.h" #include "MyBitmap.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CGrCard::CGrCard(Card card, CMyBitmap *bmpBack, CWnd *pView, bool faceDown) : m_suite(card.suite), m_face(card.face), m_pBmpBack(bmpBack), m_boundingRect(0,0,0,0), m_faceDown(faceDown), m_pRotatedBitmap(0), m_pRotatedBitmapMask(0), m_pRotatedBack(0), m_pView(pView) { CString filename; int iSuite; switch (card.suite) { case Spade: iSuite = 0; break; case Heart: iSuite = 1; break; case Diamond: iSuite = 2; break; case Club: iSuite = 3; break; } ASSERT((iSuite>=0)&&(iSuite<=3)&&(card.face>=1)&&(card.face<=13)); filename.Format("images/card%d.bmp", iSuite*13+card.face); if (m_bitmap.LoadBitmapFromFile(filename)) return; filename.Format("images/card%d.gif", iSuite*13+card.face); if (m_bitmap.LoadBitmapFromFile(filename)) return; filename.Format("images/card%d.jpg", iSuite*13+card.face); if (m_bitmap.LoadBitmapFromFile(filename)) return; m_bitmap.createBitmap(pView, card, 70, 100); } CGrCard::~CGrCard() { delete m_pRotatedBitmap; delete m_pRotatedBitmapMask; delete m_pRotatedBack; // no ownership over m_bmpBack } void CGrCard::draw(CDC *pDC) { if (m_faceDown && (m_pBmpBack==0)) { CBrush *pOldBr = (CBrush *)pDC->SelectStockObject(LTGRAY_BRUSH); pDC->Rectangle(&m_boundingRect); pDC->SelectObject(pOldBr); } else if (!m_faceDown && (m_bitmap.Width()==0)) pDC->Rectangle(&m_boundingRect); else if (!m_faceDown) { if (m_pRotatedBitmap) drawSprite(pDC, m_pRotatedBitmap); else m_bitmap.Draw(pDC, m_boundingRect.left, m_boundingRect.top); } else if (m_faceDown) { if (m_pRotatedBack) drawSprite(pDC, m_pRotatedBack); else m_pBmpBack->Draw(pDC, m_boundingRect.left, m_boundingRect.top); } return; } void CGrCard::drawSprite(CDC *pDC, CBitmap *pSprite) { CBitmap *pOldBitmap; CDC dcMem; dcMem.CreateCompatibleDC(pDC); // Step 1. cut a sprite shape from background pOldBitmap = (CBitmap *) dcMem.SelectObject(m_pRotatedBitmapMask); pDC->BitBlt(m_boundingRect.left, m_boundingRect.top, m_boundingRect.Width(), m_boundingRect.Height(), &dcMem, 0, 0, SRCAND); dcMem.SelectObject(pOldBitmap); // Step 2. OR the clean sprite to the background pOldBitmap = (CBitmap *) dcMem.SelectObject(pSprite); pDC->BitBlt(m_boundingRect.left, m_boundingRect.top, m_boundingRect.Width(), m_boundingRect.Height(), &dcMem, 0, 0, SRCPAINT); // OR dcMem.SelectObject(pOldBitmap); } bool CGrCard::is(Card card) { if ((m_suite == card.suite) && (m_face == card.face)) return true; else return false; } bool CGrCard::operator<(const CGrCard& y) const { return Card(m_suite, m_face) < Card(y.m_suite, y.m_face); } bool lessThan(const CGrCard *elem1, const CGrCard *elem2) { return *elem1 < *elem2; } bool CGrCard::hitTest(CPoint point) { if (m_boundingRect.PtInRect(point)) return true; else return false; } bool CGrCard::report(CActionHandler *controller) { return controller->userChoose(Card(m_suite, m_face)); } void CGrCard::setBoundsAndAngle(int left, int top, int angleRange, bool invalidateWindow) { // angle = 1000 ==> right 90 degree // angle = -1000 ==> left 90 degree int angle=0; if (angleRange > 1000) angleRange = 1000; if (angleRange < 0) angleRange = 0; if (angleRange == 0) angle = 0; else angle = (rand() % (angleRange*2+1)) - angleRange; delete m_pRotatedBack; m_pRotatedBack = 0; delete m_pRotatedBitmap; m_pRotatedBitmap = 0; delete m_pRotatedBitmapMask; m_pRotatedBitmapMask = 0; int width=70; int height=100; if (m_bitmap.Width()>0) { BITMAP bm; m_bitmap.GetBitmap(&bm); width = bm.bmWidth; height = bm.bmHeight; } if (invalidateWindow) invalidate(); if ((angle == 0) || (m_bitmap.Width()==0)) m_boundingRect = CRect(left, top, left+width, top+height); else { int dstX, dstY; double dAngle = (double)angle / 1000.0 * 3.14159265358979; prepareRotatedImages(dAngle, dstX, dstY); m_boundingRect = CRect(left, top, left+dstX, top+dstY); } if (invalidateWindow) invalidate(); // TRACE("suite=%d face=%d left=%d top=%d width=%d height=%d\n", // m_suite, m_face, left, top, dstX, dstY); } void CGrCard::faceDown(bool bFaceDown) { m_faceDown = bFaceDown; invalidate(); } void CGrCard::invalidate() { if (m_pView) m_pView->InvalidateRect(&m_boundingRect, FALSE); } #include // rotation matrix x' = cos(a) x - sin(a) y // y' = sin(a) x + cos(a) y void CGrCard::prepareRotatedImages(double angle, int &dstX, int &dstY) { // Start timing /* char s[40]; LARGE_INTEGER lStart, lEnd, lFreq; QueryPerformanceFrequency(&lFreq); QueryPerformanceCounter(&lStart); */ BITMAP bm; m_bitmap.GetBitmap(&bm); int SrcX = bm.bmWidth; int SrcY = bm.bmHeight; double cA, sA; int x[4], y[4]; int CtX, CtY, OfX, OfY; CtX = SrcX/2; CtY = SrcY/2; cA = cos(angle); sA = sin(angle); x[0] = int((0-CtX) * cA - (0-CtY) * sA + 1000.0) - 1000; y[0] = int((0-CtX) * sA + (0-CtY) * cA + 1000.0) - 1000; x[1] = int((SrcX-1 - CtX) * cA - (0-CtY) * sA + 1000.0) - 1000; y[1] = int((0-CtX) * sA + (SrcY-1 - CtY) * cA + 1000.0) - 1000; x[2] = int((SrcX-1 - CtX) * cA - (SrcY-1 - CtY) * sA + 1000.0) - 1000; y[2] = int((SrcX-1 - CtX) * sA + (SrcY-1 - CtY) * cA + 1000.0) - 1000; x[3] = int((0-CtX) * cA - (SrcY-1 - CtY) * sA + 1000.0) - 1000; y[3] = int((SrcX-1 - CtX) * sA + (0-CtY) * cA + 1000.0) - 1000; int i; OfX = x[0]; dstX = x[0]; OfY = y[0]; dstY = y[0]; for (i=1; i<4; i++) { if (x[i]dstX) dstX = x[i]; if (y[i]dstY) dstY = y[i]; } dstX = dstX - OfX + 1 + 2; dstY = dstY - OfY + 1 + 2; OfX += CtX; OfY += CtY; // Create the new memory DC HDC hdcClient = GetDC(m_pView->GetSafeHwnd()); // Set the new Bitmap BITMAPINFO bi; bi.bmiHeader.biSize = sizeof(bi.bmiHeader); bi.bmiHeader.biWidth = SrcX; bi.bmiHeader.biHeight = SrcY; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biSizeImage = 4 * SrcX * SrcY; bi.bmiHeader.biClrUsed = 0; bi.bmiHeader.biClrImportant = 0; HDC hdc = CreateCompatibleDC(hdcClient); HGDIOBJ hOldBmp = SelectObject(hdc, m_bitmap.GetSafeHandle()); HGDIOBJ hOldBr = SelectObject(hdc, GetStockObject(NULL_BRUSH)); Rectangle(hdc, 0, 0, SrcX, SrcY); SelectObject(hdc, hOldBmp); pBGR srcBitmap = (pBGR) malloc(4 * SrcX * SrcY); if (!srcBitmap) return; BOOL bRes = GetDIBits(hdcClient, (HBITMAP) m_bitmap.GetSafeHandle(), 0, SrcY, srcBitmap, &bi, DIB_RGB_COLORS); if (!bRes) {free(srcBitmap); return;} hOldBmp = SelectObject(hdc, m_pBmpBack->GetSafeHandle()); Rectangle(hdc, 0, 0, SrcX, SrcY); Rectangle(hdc, 2, 2, SrcX-2, SrcY-2); SelectObject(hdc, hOldBmp); SelectObject(hdc, hOldBr); DeleteDC(hdc); pBGR srcBack = (pBGR) malloc(4 * SrcX * SrcY); if (!srcBack) return; bRes = GetDIBits(hdcClient, (HBITMAP) m_pBmpBack->GetSafeHandle(), 0, SrcY, srcBack, &bi, DIB_RGB_COLORS); if (!bRes) {free(srcBack); free(srcBitmap); return;} pBGR bitmap = (pBGR) malloc(4*dstX*dstY); pBGR bitmapMask = (pBGR) malloc(4*dstX*dstY); pBGR bitmapBack = (pBGR) malloc(4*dstX*dstY); int stepX, stepY; int iorgX, iorgY; double tmpX, tmpY; int CtX1=CtX-1000, CtY1=CtY-1000; pBGR bitmapLine = bitmap; pBGR bitmapMaskLine = bitmapMask; pBGR bitmapBackLine = bitmapBack; pBGR *srcLine = (pBGR *) malloc(4*SrcY); pBGR *srcBackLine = (pBGR *) malloc(4*SrcY); if ((bitmap==0)||(bitmapMask==0)||(bitmapBack==0)|| (srcLine==0)||(srcBackLine==0)) { if (bitmap) free(bitmap); if (bitmapMask) free(bitmapMask); if (bitmapBack) free(bitmapBack); if (srcLine) free(srcLine); if (srcBackLine) free(srcBackLine); if (srcBitmap) free(srcBitmap); if (srcBack) free(srcBack); return; } for (i=0; i= 0) && (iorgY >= 0) && (iorgX < SrcX) && (iorgY < SrcY)) { bitmapLine[stepX] = srcLine[iorgY][iorgX]; *(int*)&bitmapMaskLine[stepX] = 0x00000000; bitmapBackLine[stepX] = srcBackLine[iorgY][iorgX]; } else { *(int *)&bitmapLine[stepX] = 0x00000000; *(int *)&bitmapMaskLine[stepX] = 0x00FFFFFF; *(int *)&bitmapBackLine[stepX] = 0x00000000; } } bitmapLine += dstX; bitmapMaskLine += dstX; bitmapBackLine += dstX; } free(srcLine); free(srcBackLine); free(srcBitmap); free(srcBack); /* SelectObject(hdcBitmap, hBitmap); SelectObject(hdcBitmapMask, hBitmapMask); SelectObject(hdcBack, hBitmapBack); */ bi.bmiHeader.biWidth = dstX; bi.bmiHeader.biHeight = dstY; bi.bmiHeader.biSizeImage = 4 * dstX * dstY; HBITMAP hBitmap = CreateCompatibleBitmap(hdcClient, dstX, dstY); SetDIBits(hdcClient, hBitmap, 0, dstY, bitmap, &bi, DIB_RGB_COLORS); m_pRotatedBitmap = new CBitmap; m_pRotatedBitmap->Attach(hBitmap); free(bitmap); HBITMAP hBitmapMask = CreateCompatibleBitmap(hdcClient, dstX, dstY); SetDIBits(hdcClient, hBitmapMask, 0, dstY, bitmapMask, &bi, DIB_RGB_COLORS); m_pRotatedBitmapMask = new CBitmap; m_pRotatedBitmapMask->Attach(hBitmapMask); free(bitmapMask); HBITMAP hBitmapBack = CreateCompatibleBitmap(hdcClient, dstX, dstY); SetDIBits(hdcClient, hBitmapBack, 0, dstY, bitmapBack, &bi, DIB_RGB_COLORS); m_pRotatedBack = new CBitmap; m_pRotatedBack->Attach(hBitmapBack); free(bitmapBack); // End timing and show Time taken in milliseconds /* QueryPerformanceCounter(&lEnd); sprintf(s, "%d ms", ((lEnd.QuadPart - lStart.QuadPart) * 1000) / lFreq.QuadPart); TextOut(hdcDst, 0, 0, s, strlen(s)); */ ReleaseDC(m_pView->GetSafeHwnd(), hdcClient); }