📄 paint.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/******************************************************************************\
*
* MODULE: PAINT.C
*
* PURPOSE: This is the module responsible for painting the SPINCUBE
* custom control. When Paint() is called we retrieve a
* pointer to a SPINCUBEINFO structure, and then use it's
* current rotation & translation values to transform the
* polyhedron described by gNormalizedVertices & gaiFacets.
* Once we've transformed the vertices, we draw the
* background, which consists of a grey rectangle and a few
* black lines (a crass attempt to render a perspective
* view into a "room"), on the offscreen bitmap associated
* with the control (i.e. pSCI->hbmCompat). Then we walk the
* facet list of the transformed polyhedron (gXformedVertices
* & gaiFacets), drawing only those facets whose outward
* normal faces us (again, drawing on pSCI->hbmCompat).
* Finally, we BitBlt the appropriate rectangle from our
* offscreen bitmap to the screen itself.
*
* Drawing to the offscreen bitmap has two advantages over
* drawing straight to the screen:
*
* 1. The actual drawing the user sees consists of only
* a single BitBlt. Otherwise, the user would see us
* both erase the polyhedron in it's old position and
* draw it in it's new position (alot of flashing- not
* very smooth animation).
*
* 2. When a spincube control with the SS_ERASE style
* is brought to the foreground, all it's contents
* i.e. the cube trails) are saved & can be re-Blted
* to the screen. Otherwise, all this info would be
* lost & there'd be a big blank spot in the middle
* of the control!
*
* Interested persons should consult a text on 3 dimensional
* graphics for more information (i.e. "Computer Graphics:
* Principles and Practice", by Foley & van Dam).
*
* Notes:
*
* - A 3x2 tranformation matrix is used instead of a 3x3
* matrix, since the transformed z-values aren't needed.
* (Normally these would be required for use in depth
* sorting [for hidden surface removal], but since we
* draw only a single convex polyhedron this is not
* necessary.)
*
* - A simplified perspective viewing transformation
* (which also precludes the need for the transformed z
* coordinates). In a nutshell, the perspective scale
* is as follows:
*
* p' = S x p
* per
*
* where:
* S = WindowDepth /
* per (WindowDepth + fCurrentZTranslation)
*
* (WindowDepth is the greater of the control's window
* height or window width.)
*
*
* FUNCTIONS: Paint() - the paint routine
* TransformVertices() - transforms vertices
* ComputeRotationTransformation() - computes xformation
* based on current x, y
* and z rotation angles
*
* Microsoft Developer Support
*
\******************************************************************************/
#include <windows.h>
#include <math.h>
#include <stdlib.h>
#include "spincube.h"
#include "paint.h"
/******************************************************************************\
*
* FUNCTION: Paint
*
* INPUTS: hwnd - Handle of the window to draw into.
*
* COMMENTS: Draws window background & a polyhedron in the window.
*
\******************************************************************************/
void Paint(
HWND hwnd
)
{
PSPINCUBEINFO pSCI;
RECT rect;
int i;
LONG lScaleFactor;
PAINTSTRUCT ps;
HRGN hrgnClip;
HBRUSH hBrush, hBrushSave;
int iX, iY, iCX, iCY;
int facetIndex, numPoints;
POINT polygn[MAX_POINTS_PER_FACET];
POINT vector1, vector2;
COLORREF acrColor[6] = { 0x808080, 0xC0C0C0, 0xffffff,
0xffffff, 0x000000, 0x000000 };
POINT points[5];
pSCI = (PSPINCUBEINFO) GetWindowLong(hwnd, GWL_SPINCUBEDATA);
BeginPaint(hwnd, &ps);
if (memcmp((void *)&ps.rcPaint, (void *)&pSCI->rcCubeBoundary, sizeof(RECT))
& !REPAINT_BKGND(pSCI))
{
//
// We're not here because it's time to animate (i.e. this paint isn't
// the result of a WM_TIMER), so just do the Blt & blow out of here...
//
BitBlt(ps.hdc,
ps.rcPaint.left,
ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left,
ps.rcPaint.bottom - ps.rcPaint.top,
pSCI->hdcCompat, ps.rcPaint.left,
ps.rcPaint.top, SRCCOPY);
EndPaint(hwnd, &ps);
return;
}
//
// The rectangle we get back is in Desktop coordinates, so we need to
// modify it to reflect coordinates relative to this window.
//
GetWindowRect(hwnd, &rect);
rect.right -= rect.left;
rect.bottom -= rect.top;
rect.left = rect.top = 0;
//
// Determine a "best fit" scale factor for our polyhedron
//
if (!(lScaleFactor = rect.right > rect.bottom ?
rect.bottom/12 : rect.right/12))
{
lScaleFactor = 1;
}
TransformVertices(hwnd, &rect, pSCI, lScaleFactor);
//
// Draw the window frame & background
//
// Note: The chances are that we are coming through here because we
// got a WM_TIMER message & it's time to redraw the cube to simulate
// animation. In that case all we want to erase/redraw is that small
// rectangle which bounded the polyhedron the last time. The less
// drawing that actually gets done the better, since we wnat to
// minimize the flicker on the screen. __BeginPaint__ is perfect for
// this because it causes all drawing outside of the invalid region
// to be "clipped" (no drawing is performed outside of the invalid
// region), and it also validates the invalid region.
//
if (DO_ERASE(hwnd) || REPAINT_BKGND(pSCI))
{
hrgnClip = CreateRectRgnIndirect(&ps.rcPaint);
SelectClipRgn(pSCI->hdcCompat, hrgnClip);
DeleteObject(hrgnClip);
SelectObject(pSCI->hdcCompat, GetStockObject (GRAY_BRUSH));
Rectangle(pSCI->hdcCompat, (int)rect.left, (int)rect.top,
(int)rect.right, (int)rect.bottom);
iX = (rect.right - rect.left) / 4;
iY = (rect.bottom - rect.top ) / 4;
// Windows CE v1.0 does not support MoveToEx or LineTo, so I've included
// the original code in comments right above code I've written
// to duplicate the original functionality.
// all of this is used to just draw the background lines in the boxes
// (over the black rectangles).
// MoveToEx (pSCI->hdcCompat, (int)rect.left, (int)rect.top, NULL);
points[0].x = (int)rect.left;
points[0].y = (int)rect.top;
// LineTo (pSCI->hdcCompat, (int)rect.left + iX, (int)rect.top + iY);
points[1].x = (int)rect.left + iX;
points[1].y = (int)rect.top + iY;
// LineTo (pSCI->hdcCompat, (int)rect.left + iX, (int)rect.bottom - iY);
points[2].x = (int)rect.left + iX;
points[2].y = (int)rect.bottom - iY;
// LineTo (pSCI->hdcCompat, (int)rect.left, (int)rect.bottom);
points[3].x = (int)rect.left;
points[3].y = (int)rect.bottom;
Polyline( pSCI->hdcCompat, points, 4 );
// MoveToEx (pSCI->hdcCompat, (int)rect.right, (int)rect.top, NULL);
points[0].x = (int)rect.right;
points[0].y = (int) rect.top;
// LineTo (pSCI->hdcCompat, (int)rect.right - iX, (int)rect.top + iY);
points[1].x = (int)rect.right - iX;
points[1].y = (int)rect.top + iY;
// LineTo (pSCI->hdcCompat, (int)rect.right - iX, (int)rect.bottom- iY);
points[2].x = (int)rect.right - iX;
points[2].y = (int)rect.bottom- iY;
// LineTo (pSCI->hdcCompat, (int)rect.right, (int)rect.bottom);
points[3].x = (int)rect.right;
points[3].y = (int)rect.bottom;
Polyline( pSCI->hdcCompat, points, 4 );
// MoveToEx (pSCI->hdcCompat, (int)rect.left + iX, (int)rect.top + iY, NULL);
points[0].x = (int)rect.left + iX;
points[0].y = (int)rect.top + iY, NULL;
// LineTo (pSCI->hdcCompat, (int)rect.right - iX, (int)rect.top + iY);
points[1].x = (int)rect.right - iX;
points[1].y = (int)rect.top + iY;
Polyline( pSCI->hdcCompat, points, 2 );
// MoveToEx (pSCI->hdcCompat, (int)rect.left + iX, (int)rect.bottom - iY, NULL);
points[0].x = (int)rect.left + iX;
points[0].y = (int)rect.bottom - iY, NULL;
// LineTo (pSCI->hdcCompat, (int)rect.right - iX, (int)rect.bottom - iY);
points[1].x = (int)rect.right - iX;
points[1].y = (int)rect.bottom - iY;
Polyline(pSCI->hdcCompat, points, 2);
SelectClipRgn(pSCI->hdcCompat, NULL);
pSCI->iOptions &= ~SPINCUBE_REPAINT_BKGND;
}
//
// Draw the polyhedron. We'll walk through the facets list and compute
// the normal for each facet- if the normal has z > 0, then the facet
// faces us and we'll draw it. Note that this algorithim is ONLY valid
// for scenes with a single, convex polyhedron.
//
// Note: Use GetDC here because the above call to BeginPaint will
// probably not give us a DC with access to as much real estate as
// we'd like (we wouldn't be able to draw outside of the invalid
// region). We can party on the entire control window with the DC
// returned by GetDC.
//
for (i = 0, facetIndex = 0; i < NUMFACETS; i++)
{
vector1.x = gXformedVertices[gaiFacets[facetIndex + 1]].x -
gXformedVertices[gaiFacets[facetIndex]].x;
vector1.y = gXformedVertices[gaiFacets[facetIndex + 1]].y -
gXformedVertices[gaiFacets[facetIndex]].y;
vector2.x = gXformedVertices[gaiFacets[facetIndex + 2]].x -
gXformedVertices[gaiFacets[facetIndex + 1]].x;
vector2.y = gXformedVertices[gaiFacets[facetIndex + 2]].y -
gXformedVertices[gaiFacets[facetIndex + 1]].y;
for (numPoints = 0; gaiFacets[facetIndex] != -1; numPoints++, facetIndex++)
{
polygn[numPoints].x = gXformedVertices[gaiFacets[facetIndex]].x;
polygn[numPoints].y = gXformedVertices[gaiFacets[facetIndex]].y;
}
facetIndex++; /* skip over the -1's in the facets list */
if ((vector1.x*vector2.y - vector1.y*vector2.x) > 0)
{
hBrush = CreateSolidBrush(acrColor[i]);
hBrushSave = (HBRUSH) SelectObject(pSCI->hdcCompat, hBrush);
Polygon(pSCI->hdcCompat, &polygn[0], numPoints);
SelectObject(pSCI->hdcCompat, hBrushSave);
DeleteObject(hBrush);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -