2025-04-27 07:49:33 -04:00

472 lines
13 KiB
C

/******************************Module*Header*******************************\
* Module Name: persp.c
*
* Code to do perspective tranform animations.
*
* Copyright (c) 1997 Microsoft Corporation
*
\**************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <commdlg.h>
#include <wndstuff.h>
#include <time.h>
#include <math.h>
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);
}