windows-nt/Source/XPSP1/NT/multimedia/directx/gamectrl/gcdef/pov.cpp
2020-09-26 16:20:57 +08:00

334 lines
11 KiB
C++

/*~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=
**
** FILE: POV.CPP
** DATE: 3/31/97
** PROJ: ATLAS
** PROG: JKH
** COMMENTS:
**
** DESCRIPTION: Window class for a 360 degree Point Of View control
**
**
**
** NOTE: There are some issues with using extern "C" in this file.
** If you don't understand why they are there, you're not
** alone. For now, and probably for a while they will be
** here though, because I can't get this file and others
** that use these services to compile without them.
** Unfortunately the dynamics of this project don't really
** afford me the time at present to figure this out.
** TODO: figure this out
**
** HISTORY:
** DATE WHO WHAT
** ---- --- ----
** 3/31/97 a-kirkh Wrote it.
**
**
**
**
** Copyright (C) Microsoft 1997. All Rights Reserved.
**
**~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=*/
#pragma pack (8)
#include "POV.H" //This module's stuff.
#include "resource.h"
extern HWND hPOVWnd = NULL;
static HINSTANCE ghResInst;
static LPRECT prctOldRegionBox;
static LPRECT prctNewRegionBox;
double degrees = -1;
void SetDegrees(int dDegrees)
{
degrees = (double)dDegrees;
PostMessage(hPOVWnd, PM_MYJOYPOSCHANGED, 0, 0);
}
extern "C"{
void SetResourceInstance(HINSTANCE hInstance)
{
ghResInst = hInstance;
}
HINSTANCE GetResourceInstance()
{
return(ghResInst);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// FUNCTION : POVWndProc
// REMARKS : The callback function for the POVHat Window.
//
// PARAMS : The usual callback funcs for message handling
//
// RETURNS : LRESULT - Depends on the message
// CALLS :
// NOTES :
// WM_PAINT - Just calls DrawControl
//
// PM_MYJOYPOSCHANGED - This is a private (WM_USER) message that is
// called whenever a change in the POV hat occurs.
//
RECT rClient;
HDC hDC;
PAINTSTRUCT ps;
LONG cxClient, cyClient;
HRGN hRegion;
HBITMAP hPOVHubBitmap = NULL;
LRESULT CALLBACK POVWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch( iMsg ) {
case WM_CREATE:
hPOVWnd = hWnd;
return(0);
case WM_PAINT:
{
hDC = BeginPaint(hWnd, &ps);
DrawControl(hWnd, hDC);
EndPaint(hWnd, &ps);
}
return(0);
case PM_MYJOYPOSCHANGED:
{
degrees /= 100; // if angle == 180, degrees comes in as 18000
GetCurrentArrowRegion(&hRegion);
if( hRegion ) {
GetRgnBox(hRegion, prctNewRegionBox);
InvalidateRect(hWnd, prctOldRegionBox, TRUE);
InvalidateRect(hWnd, prctNewRegionBox, TRUE);
DeleteObject(hRegion);
}
}
default:
return(DefWindowProc(hWnd, iMsg,wParam, lParam));
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// FUNCTION : DrawControl
// REMARKS : Function called by WM_PAINT that draws the POV hat control
// PARAMS : HWND - Control's window handle
// HDC - Control's dc created with BeginPaint
// RETURNS : void
// CALLS : GetCurrentArrowRegion
// NOTES :
// 1) So that stuff can be centered.
// 2) Bitblt that hub thingy in the middle.
// 3) Disallow any problems with aspect ratio.
// 4) Draw the circle, should be round because of 3.
// 5) a.Get the coordinates of the rotated arrow.
// b.Paint the region.
// c.Get the bounding rectangle of the region so we
// can invalidate it next time around.
void DrawControl(HWND hWnd, HDC hDC)
{
assert(hWnd);
assert(hDC);
// 1) Get client size information
SetMapMode(hDC, MM_TEXT);
GetClientRect(hWnd, &rClient);
cxClient = rClient.right - rClient.left;
cyClient = -(rClient.bottom - rClient.top);
// 2) Load the hub bitmap and display it
hPOVHubBitmap = LoadBitmap((HMODULE)ghResInst, MAKEINTRESOURCE(IDB_POVHUB));
assert(hPOVHubBitmap);
DrawBitmap(hDC, hPOVHubBitmap, cxClient/2 - 8, -cyClient/2 - 8);
DeleteObject(hPOVHubBitmap);
// 3) Setup the window to use symmetrical units on a 1000 X 1000 cartesian grid
SetMapMode(hDC, MM_ISOTROPIC);
SetWindowExtEx(hDC, 1000, 1000, NULL);
SetViewportExtEx(hDC, cxClient / 2, cyClient / 2, NULL);
SetViewportOrgEx(hDC, cxClient / 2, -cyClient / 2, NULL);
// 4) Draw the circle upon which the arrow seems to rotate
SelectObject(hDC, (HBRUSH)GetStockObject(NULL_BRUSH));
HPEN hPen = CreatePen( PS_SOLID, 1, CIRCLECOLOR);
//PREFIX: dereferencing NULL pointer 'hPen'
//Millen Bug#129156, manbug 29347
if( hPen != NULL ) {
HPEN hPenOld = (HPEN)SelectObject(hDC, hPen);
Ellipse(hDC, -CIRCLERADIUS, CIRCLERADIUS, CIRCLERADIUS, -CIRCLERADIUS);
SelectObject(hDC, hPenOld);
DeleteObject(hPen);
}
// 5) Paint the Arrow at the correct angle if POV active
if( degrees >= 0 ) {
HBRUSH hBrush = CreateSolidBrush( CIRCLECOLOR );
if( !hBrush ) {
return;
}
HBRUSH hBrushOld = (HBRUSH)SelectObject(hDC, hBrush);
assert(hBrushOld);
GetCurrentArrowRegion(&hRegion);
if( !hRegion ) {
return;
}
PaintRgn(hDC, hRegion);
// GetRgnBox returns zero if it fails...
GetRgnBox(hRegion, prctOldRegionBox);
SelectObject(hDC, hBrushOld);
DeleteObject(hBrush);
DeleteObject(hRegion);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// FUNCTION : RegisterPOVClass
// REMARKS : Registers the POV Hat window.
//
// PARAMS : hInstance - Used for the call to RegisterClassEx
//
// RETURNS : TRUE - if successfully registered
// FALSE - failed to register
// CALLS : RegisterClassEx
// NOTES :
//
extern BOOL RegisterPOVClass(HINSTANCE hInstance)
{
WNDCLASSEX POVWndClass;
POVWndClass.cbSize = sizeof(POVWndClass);
POVWndClass.style = CS_HREDRAW | CS_VREDRAW;
POVWndClass.lpfnWndProc = POVWndProc;
POVWndClass.cbClsExtra = 0;
POVWndClass.cbWndExtra = 0;
POVWndClass.hInstance = hInstance;
POVWndClass.hIcon = NULL;
POVWndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
POVWndClass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
POVWndClass.lpszMenuName = NULL;
POVWndClass.lpszClassName = "POVHAT";
POVWndClass.hIconSm = NULL;
if( RegisterClassEx( &POVWndClass ) == 0 )
return(FALSE);
return(TRUE);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// FUNCTION : DrawBitmap
// REMARKS : Copied verbatim from Petzold (WIN95 pg 190)
// PARAMS : HDC - dc for drawing
// HBITMAP - bitmap to draw
// int xstart, ystart - where to place the bitmap
//
// RETURNS : void
// CALLS :
// NOTES :
//
void DrawBitmap(HDC hDC, HBITMAP hBitmap, int xStart, int yStart)
{
BITMAP bm;
HDC hdcMem;
POINT ptSize, ptOrg;
hdcMem = CreateCompatibleDC(hDC);
// Found by prefix: Millen Bug129155. manbugs 29339
// If CreateCompatibleDC fails, we should'nt proceed.
if( hdcMem == NULL ) return;
SelectObject(hdcMem, hBitmap);
SetMapMode(hdcMem,GetMapMode(hDC));
GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
ptSize.x = bm.bmWidth;
ptSize.y = bm.bmHeight;
DPtoLP(hDC, &ptSize, 1);
ptOrg.x = 0;
ptOrg.y = 0;
DPtoLP(hdcMem, &ptOrg, 1);
BitBlt(hDC, xStart, yStart, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y, SRCAND);
DeleteDC(hdcMem);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// FUNCTION : GetCurrentArrowRegion
// REMARKS : Rotates and translate a set of vertices that represents
// the POV hat arrow
//
// PARAMS : HRGN - The region to be rotated
//
// RETURNS : BOOL
// CALLS : GETXCOORD, GETYCOORD (POV.H)
// NOTES :
//
void GetCurrentArrowRegion(HRGN* hRegion)
{
POINT aptPoints[8];
VERTICEINFO aptVInfo[8] = { XARROWPOINT ,YARROWPOINT ,
XARROWRIGHTOUT ,YARROWRIGHTOUT ,
XARROWRIGHTIN ,YARROWRIGHTIN ,
XARROWRIGHTBOTTOM,YARROWRIGHTBOTTOM,
XARROWLEFTBOTTOM ,YARROWLEFTBOTTOM ,
XARROWLEFTIN ,YARROWLEFTIN ,
XARROWLEFTOUT ,YARROWLEFTOUT ,
XARROWPOINT ,YARROWPOINT};
aptPoints[0].x = GETXCOORD(aptVInfo[0].y, aptVInfo[0].x, degrees);
aptPoints[0].y = GETYCOORD(aptVInfo[0].y, aptVInfo[0].x, degrees);
aptPoints[1].x = GETXCOORD(aptVInfo[1].y, aptVInfo[1].x, degrees);
aptPoints[1].y = GETYCOORD(aptVInfo[1].y, aptVInfo[1].x, degrees);
aptPoints[2].x = GETXCOORD(aptVInfo[2].y, aptVInfo[2].x, degrees);
aptPoints[2].y = GETYCOORD(aptVInfo[2].y, aptVInfo[2].x, degrees);
aptPoints[3].x = GETXCOORD(aptVInfo[3].y, aptVInfo[3].x, degrees);
aptPoints[3].y = GETYCOORD(aptVInfo[3].y, aptVInfo[3].x, degrees);
aptPoints[4].x = GETXCOORD(aptVInfo[4].y, aptVInfo[4].x, degrees);
aptPoints[4].y = GETYCOORD(aptVInfo[4].y, aptVInfo[4].x, degrees);
aptPoints[5].x = GETXCOORD(aptVInfo[5].y, aptVInfo[5].x, degrees);
aptPoints[5].y = GETYCOORD(aptVInfo[5].y, aptVInfo[5].x, degrees);
aptPoints[6].x = GETXCOORD(aptVInfo[6].y, aptVInfo[6].x, degrees);
aptPoints[6].y = GETYCOORD(aptVInfo[6].y, aptVInfo[6].x, degrees);
aptPoints[7].x = GETXCOORD(aptVInfo[7].y, aptVInfo[7].x, degrees);
aptPoints[7].y = GETYCOORD(aptVInfo[7].y, aptVInfo[7].x, degrees);
*hRegion = CreatePolygonRgn(aptPoints, 8, WINDING);
}
}