/******************************Module*Header*******************************\ * Module Name: persp.c * * Code to do perspective tranform animations. * * Copyright (c) 1997 Microsoft Corporation * \**************************************************************************/ #include #include #include #include #include #include BOOL bComputePerspectiveTransform( FLOAT eAngle, // z-rotation, in degrees LONG zDistance, // Distance from viewport, affects amount of perspective // warping POINTL* pptlLeft, // Defines the left and right edges, in screen POINTL* pptlRight, // coordinates, of the resulting bitmap at // the vertical center of the bitmap LONG cxSource, // Width of source LONG cySource, // Height of source POINTL* aptlResult) // Resulting points description { FLOAT cx = cxSource; FLOAT cy = cySource; FLOAT xA; FLOAT yA; FLOAT zA; FLOAT xB; FLOAT yB; FLOAT zB; FLOAT cxDst; FLOAT eScale; LONG dx; LONG dy; if ((pptlLeft->y != pptlRight->y) || (pptlLeft->x >= pptlRight->x)) { return(FALSE); } eAngle *= 3.1415926535897932384626433832795f / 180.0f; xA = cx / 2; yA = 0; zA = 0; xB = cx / 2; yB = (cy / 2) * cos(eAngle); zB = (cy / 2) * sin(eAngle); // Apply the perspective transform. Yes, this could be simplified: xA = (xA * zDistance) / (zA + zDistance); yA = (yA * zDistance) / (zA + zDistance); xB = (xB * zDistance) / (zB + zDistance); yB = (yB * zDistance) / (zB + zDistance); // Scale A and B appropriately: cxDst = pptlRight->x - pptlLeft->x; eScale = (cxDst / 2) / xA; dx = (xA - xB) * eScale; dy = yB * eScale; aptlResult[0].x = pptlLeft->x - dx; aptlResult[0].y = pptlLeft->y - dy; aptlResult[1].x = pptlRight->x + dx; aptlResult[1].y = pptlRight->y - dy; aptlResult[2].x = pptlLeft->x + dx; aptlResult[2].y = pptlLeft->y + dy; return(TRUE); } VOID vMinimize( HWND hwnd) { HDC hdcScreen; RECTL rclSrc; HDC hdcShape; HBITMAP hbmShape; BITMAP bmShape; BLENDFUNCTION blend; POINTL aptl[3]; POINTL ptlLeft; POINTL ptlRight; POINTL ptlStartLeft; POINTL ptlStartRight; POINTL ptlEndLeft; POINTL ptlEndRight; FLOAT eAngle; FLOAT eStartAngle; FLOAT eEndAngle; LONG cIterations; LONG i; hdcScreen = GetDC(hwnd); hdcShape = CreateCompatibleDC(hdcScreen); hbmShape = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(POPUP_BITMAP)); SelectObject(hdcShape, hbmShape); GetObject(hbmShape, sizeof(BITMAP), &bmShape); // Create a wider sprite up front to account for the expanding window: vCreateSprite(hdcScreen, (4 * bmShape.bmWidth) / 3, bmShape.bmHeight + 20); rclSrc.left = 0; rclSrc.top = 0; rclSrc.right = bmShape.bmWidth; rclSrc.bottom = bmShape.bmHeight; gcxPersp = bmShape.bmWidth; gcyPersp = bmShape.bmHeight; // This sets the number of frames: cIterations = 60; // This defines the start and end position: ptlStartLeft.x = gptlSprite.x; ptlStartLeft.y = gptlSprite.y + (bmShape.bmHeight / 2); ptlStartRight.x = gptlSprite.x + (bmShape.bmWidth); ptlStartRight.y = ptlStartLeft.y; ptlEndLeft.x = 200; ptlEndLeft.y = GetDeviceCaps(hdcScreen, VERTRES); ptlEndRight.x = 210; ptlEndRight.y = ptlEndLeft.y; // This defines the start and end angles: eStartAngle = 0.0f; eEndAngle = 360.0f; for (i = 0; i <= cIterations; i++) { // Linearly interpolate between the start and end positions and angles: ptlLeft.x = ptlStartLeft.x + (((ptlEndLeft.x - ptlStartLeft.x) * i) / cIterations); ptlLeft.y = ptlStartLeft.y + (((ptlEndLeft.y - ptlStartLeft.y) * i) / cIterations); ptlRight.x = ptlStartRight.x + (((ptlEndRight.x - ptlStartRight.x) * i) / cIterations); ptlRight.y = ptlLeft.y; eAngle = eStartAngle + (((eEndAngle - eStartAngle) * i) / cIterations); if (!bComputePerspectiveTransform(eAngle, 1000, &ptlLeft, &ptlRight, bmShape.bmWidth, bmShape.bmHeight, aptl)) { MessageBox(0, "Does not compute", "Does not compute", MB_OK); } else { #if 0 if (!UpdateSprite(ghSprite, dwShape | US_UPDATE_TRANSFORM, US_SHAPE_OPAQUE, hdcScreen, hdcShape, &rclSrc, 0, blend, US_TRANSFORM_PERSPECTIVE, &aptl[0], 0, NULL)) { MessageBox(0, "UpdateSprite failed", "Uh oh", MB_OK); } #endif } // It's faster not to set the shape again on subsequent calls: } #if 0 if (!UpdateSprite(ghSprite, US_UPDATE_TRANSFORM, US_SHAPE_OPAQUE, hdcScreen, hdcShape, &rclSrc, 0, blend, US_TRANSFORM_TRANSLATE, &gptlSprite, 0, NULL)) { MessageBox(0, "UpdateSprite failed", "Uh oh", MB_OK); } #endif ReleaseDC(hwnd, hdcScreen); DeleteObject(hdcShape); DeleteObject(hbmShape); } VOID vFlip( HWND hwnd) { HDC hdcScreen; RECTL rclSrc; HDC hdcShape; HBITMAP hbmShape; BITMAP bmShape; BLENDFUNCTION blend; POINTL aptl[3]; POINTL ptlLeft; POINTL ptlRight; DWORD dwShape; FLOAT eAngle; ULONG cIterations; ULONG i; hdcScreen = GetDC(hwnd); hdcShape = CreateCompatibleDC(hdcScreen); hbmShape = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(POPUP_BITMAP)); SelectObject(hdcShape, hbmShape); GetObject(hbmShape, sizeof(BITMAP), &bmShape); // Create a wider sprite up front to account for the expanding window: vCreateSprite(hdcScreen, (4 * bmShape.bmWidth) / 3, bmShape.bmHeight + 20); rclSrc.left = 0; rclSrc.top = 0; rclSrc.right = bmShape.bmWidth; rclSrc.bottom = bmShape.bmHeight; gcxPersp = bmShape.bmWidth; gcyPersp = bmShape.bmHeight; eAngle = 0.0f; cIterations = 30; for (i = cIterations; i != 0; i--) { ptlLeft.x = gptlSprite.x; ptlLeft.y = gptlSprite.y + (bmShape.bmHeight / 2); ptlRight.x = gptlSprite.x + (bmShape.bmWidth); ptlRight.y = gptlSprite.y + (bmShape.bmHeight / 2); eAngle += (360.0f / cIterations); bComputePerspectiveTransform(eAngle, 1000, &ptlLeft, &ptlRight, bmShape.bmWidth, bmShape.bmHeight, aptl); #if 0 if (!UpdateSprite(ghSprite, dwShape | US_UPDATE_TRANSFORM, US_SHAPE_OPAQUE, hdcScreen, hdcShape, &rclSrc, 0, blend, US_TRANSFORM_PERSPECTIVE, &aptl[0], 0, NULL)) { MessageBox(0, "UpdateSprite failed", "Uh oh", MB_OK); } #endif // It's faster not to set the shape again on subsequent calls: dwShape = 0; } ReleaseDC(hwnd, hdcScreen); DeleteObject(hdcShape); DeleteObject(hbmShape); } VOID vPerspectiveTimer( HWND hwnd, BOOL bPerspective) { HDC hdcScreen; RECTL rclSrc; HDC hdcShape; HBITMAP hbmShape; BITMAP bmShape; BLENDFUNCTION blend; POINTL aptl[3]; ULONG cIterations; ULONG i; LONG tStart; LONG tEnd; LONG tTotal; LONG cBitsPixel; ULONG cBytes; ULONG cBytesPerSecond; FLOAT eMegsPerSecond; CHAR achBuf[200]; hdcScreen = GetDC(hwnd); hdcShape = CreateCompatibleDC(hdcScreen); hbmShape = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(POPUP_BITMAP)); SelectObject(hdcShape, hbmShape); GetObject(hbmShape, sizeof(BITMAP), &bmShape); vDelete(hwnd); // Create a wider sprite up front to account for the expanding window: vCreateSprite(hdcScreen, (4 * bmShape.bmWidth) / 3, bmShape.bmHeight + 20); rclSrc.left = 0; rclSrc.top = 0; rclSrc.right = bmShape.bmWidth; rclSrc.bottom = bmShape.bmHeight; aptl[0].x = gptlSprite.x; aptl[0].y = gptlSprite.y; aptl[1].x = aptl[0].x + 256; aptl[1].y = aptl[0].y; aptl[2].x = aptl[0].x; aptl[2].y = aptl[0].y + 256; #if 0 if (!UpdateSprite(ghSprite, US_UPDATE_SHAPE | US_UPDATE_TRANSFORM, US_SHAPE_OPAQUE, hdcScreen, hdcShape, &rclSrc, 0, blend, (bPerspective) ? US_TRANSFORM_PERSPECTIVE : US_TRANSFORM_NONPERSPECTIVE, &aptl[0], 0, NULL)) { MessageBox(0, "UpdateSprite failed", "Uh oh", MB_OK); } #endif cIterations = 1000; tStart = GetTickCount(); #if 0 for (i = cIterations; i != 0; i--) { if (!UpdateSprite(ghSprite, US_UPDATE_TRANSFORM, US_SHAPE_OPAQUE, hdcScreen, hdcShape, &rclSrc, 0, blend, (bPerspective) ? US_TRANSFORM_PERSPECTIVE : US_TRANSFORM_NONPERSPECTIVE, &aptl[0], 0, NULL)) { MessageBox(0, "UpdateSprite failed", "Uh oh", MB_OK); break; } } #endif tEnd = GetTickCount(); tTotal = tEnd - tStart; cBitsPixel = GetDeviceCaps(hdcScreen, BITSPIXEL); cBytes = 256 * 256 * cIterations * ((cBitsPixel + 1) / 8); eMegsPerSecond = ((FLOAT) 1000 * (FLOAT) cBytes) / ((FLOAT) (1024 * 1024) * (FLOAT) (tTotal)); sprintf(achBuf, "%li 256x256 %libpp transforms in %li ms is %1.2f MB/s", cIterations, cBitsPixel, tTotal, eMegsPerSecond); MessageBox(0, achBuf, "Timing is done!", MB_OK); ReleaseDC(hwnd, hdcScreen); DeleteObject(hdcShape); DeleteObject(hbmShape); } #define ITERATIONS 100 VOID vTimeRefresh( HWND hwnd) { RECT rc; HDC hdcScreen; HBITMAP hbm; HDC hdc; DWORD dwStart; DWORD dwTime; ULONG i; LONG cx; LONG cy; LONG cjPixel; CHAR achBuf[100]; hdcScreen = GetDC(hwnd); cjPixel = (GetDeviceCaps(hdcScreen, BITSPIXEL) + 1) / 8; GetClientRect(hwnd, &rc); cx = rc.right - rc.left; cy = rc.bottom - rc.top; hbm = CreateCompatibleBitmap(hdcScreen, cx, cy | 0x01000000); hdc = CreateCompatibleDC(hdcScreen); SelectObject(hdc, hbm); dwStart = GetTickCount(); for (i = ITERATIONS; i != 0; i--) { BitBlt(hdcScreen, 0, 0, cx, cy, hdc, 0, 0, SRCCOPY); } dwTime = GetTickCount() - dwStart; sprintf(achBuf, "%.2f refreshes/s, %.2f MB/s", (1000.0f * ITERATIONS) / dwTime, (1000.0f * cx * cy * cjPixel * ITERATIONS) / (dwTime * 1024.0f * 1024.0f)); MessageBox(0, achBuf, "Timing is done!", MB_OK); ReleaseDC(hwnd, hdcScreen); DeleteObject(hdc); DeleteObject(hbm); }