home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.sunet.se/pub/OS2/
/
2014.11.ftp.sunet.se_pub_OS2.tar
/
ftp.sunet.se
/
pub
/
OS2
/
hobbes
/
os2
/
games
/
action
/
ow2inst.exe
/
from_me
/
GDIRotate.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2002-11-09
|
12KB
|
457 lines
// GDIRotate.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include <math.h>
#include "resource.h"
#include <stdlib.h>
#include <stdio.h>
#include "comdef.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
float g_angle = 0.2f; // The current Rotation angle
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_GDIROTATE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_GDIROTATE);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_GDIROTATE);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_GDIROTATE;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
// Initialize the Timer to 100 ms delay between screen updates
SetTimer(hWnd, 10, 100, 0);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
// Helper function for getting the minimum of 4 floats
float min4(float a, float b, float c, float d)
{
if (a < b) {
if (c < a) {
if (d < c)
return d;
else
return c;
} else {
if (d < a)
return d;
else
return a;
}
} else {
if (c < b) {
if (d < c)
return d;
else
return c;
} else {
if (d < b)
return d;
else
return b;
}
}
}
// Helper function for getting the maximum of 4 floats
float max4(float a, float b, float c, float d)
{
if (a > b) {
if (c > a) {
if (d > c)
return d;
else
return c;
} else {
if (d > a)
return d;
else
return a;
}
} else {
if (c > b) {
if (d > c)
return d;
else
return c;
} else {
if (d > b)
return d;
else
return b;
}
}
}
// The Representation of a 32 bit color table entry
#pragma pack(push)
#pragma pack(1)
typedef struct ssBGR {
unsigned char b;
unsigned char g;
unsigned char r;
unsigned char pad;
} sBGR;
typedef sBGR *pBGR;
#pragma pack(pop)
// Returns the DI (Device Independent) bits of the Bitmap
// Here I use 32 bit since it's easy to adress in memory and no
// padding of the horizontal lines is required.
pBGR MyGetDibBits(HDC hdcSrc, HBITMAP hBmpSrc, int nx, int ny)
{
BITMAPINFO bi;
BOOL bRes;
pBGR buf;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = nx;
bi.bmiHeader.biHeight = - ny;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = nx * 4 * ny;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
buf = (pBGR) malloc(nx * 4 * ny);
bRes = GetDIBits(hdcSrc, hBmpSrc, 0, ny, buf, &bi, DIB_RGB_COLORS);
if (!bRes) {
free(buf);
buf = 0;
}
return buf;
}
// RotateMemoryDC rotates a memory DC and returns the rotated DC as well as its dimensions
void RotateMemoryDC(HBITMAP hBmpSrc, HDC hdcSrc, int SrcX, int SrcY, float angle, HDC &hdcDst, int &dstX, int &dstY)
{
HBITMAP hBmpDst;
float x1, x2, x3, x4, y1, y2, y3, y4, cA, sA;
float CtX, CtY, orgX, orgY, divisor;
int OfX, OfY;
int stepX, stepY;
int iorgX, iorgY;
RECT rt;
char s[40];
LARGE_INTEGER lStart, lEnd, lFreq;
pBGR src, dst, dstLine;
BITMAPINFO bi;
// Rotate the bitmap around the center
CtX = ((float) SrcX) / 2;
CtY = ((float) SrcY) / 2;
// First, calculate the destination positions for the four courners to get dstX and dstY
cA = (float) cos(angle);
sA = (float) sin(angle);
x1 = CtX + (-CtX) * cA - (-CtY) * sA;
x2 = CtX + (SrcX - CtX) * cA - (-CtY) * sA;
x3 = CtX + (SrcX - CtX) * cA - (SrcY - CtY) * sA;
x4 = CtX + (-CtX) * cA - (SrcY - CtY) * sA;
y1 = CtY + (-CtY) * cA + (-CtX) * sA;
y2 = CtY + (SrcY - CtY) * cA + (-CtX) * sA;
y3 = CtY + (SrcY - CtY) * cA + (SrcX - CtX) * sA;
y4 = CtY + (-CtY) * cA + (SrcX - CtX) * sA;
OfX = ((int) floor(min4(x1, x2, x3, x4)));
OfY = ((int) floor(min4(y1, y2, y3, y4)));
dstX = ((int) ceil(max4(x1, x2, x3, x4))) - OfX;
dstY = ((int) ceil(max4(y1, y2, y3, y4))) - OfY;
// Create the new memory DC
hdcDst = CreateCompatibleDC(hdcSrc);
hBmpDst = CreateCompatibleBitmap(hdcSrc, dstX, dstY);
SelectObject(hdcDst, hBmpDst);
// Fill the new memory DC with the current Window color
rt.left = 0;
rt.top = 0;
rt.right = dstX;
rt.bottom = dstY;
FillRect(hdcDst, &rt, GetSysColorBrush(COLOR_WINDOW));
// Start timing
QueryPerformanceFrequency(&lFreq);
QueryPerformanceCounter(&lStart);
// Get the bitmap bits for the source and destination
src = MyGetDibBits(hdcSrc, hBmpSrc, SrcX, SrcY);
dst = MyGetDibBits(hdcDst, hBmpDst, dstX, dstY);
dstLine = dst;
divisor = cA*cA + sA*sA;
// Step through the destination bitmap
for (stepY = 0; stepY < dstY; stepY++) {
for (stepX = 0; stepX < dstX; stepX++) {
// Calculate the source coordinate
orgX = (cA * (((float) stepX + OfX) + CtX * (cA - 1)) + sA * (((float) stepY + OfY) + CtY * (sA - 1))) / divisor;
orgY = CtY + (CtX - ((float) stepX + OfX)) * sA + cA *(((float) stepY + OfY) - CtY + (CtY - CtX) * sA);
iorgX = (int) orgX;
iorgY = (int) orgY;
if ((iorgX >= 0) && (iorgY >= 0) && (iorgX < SrcX) && (iorgY < SrcY)) {
// Inside the source bitmap -> copy the bits
dstLine[dstX - stepX - 1] = src[iorgX + iorgY * SrcX];
} else {
// Outside the source -> set the color to light grey
dstLine[dstX - stepX - 1].b = 240;
dstLine[dstX - stepX - 1].g = 240;
dstLine[dstX - stepX - 1].r = 240;
}
}
dstLine = dstLine + dstX;
}
// Set the new Bitmap
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = dstX;
bi.bmiHeader.biHeight = dstY;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = dstX * 4 * dstY;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
SetDIBits(hdcDst, hBmpDst, 0, dstY, dst, &bi, DIB_RGB_COLORS);
DeleteObject(hBmpDst);
// 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));
// Free the color arrays
free(src);
free(dst);
}
// Handler for drawing
void OnDraw(HWND hWnd)
{
PAINTSTRUCT ps;
HDC hdc, hdcMem, hdcNew;
HBITMAP hBmp;
HBRUSH hBr;
int dstX, dstY, i, offset;
RECT rt, rtmp;
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rt);
// First draw the colored bars in the upper part of the window that serve as
// the starting bitmap to rotate
offset = (rt.right - rt.left - 200) / 2;
rtmp.left = offset;
rtmp.right = offset + 1;
rtmp.top = 0;
rtmp.bottom = 200;
for (i = 0; i < 200; i++) {
hBr = CreateSolidBrush(RGB(i * 8 % 255, i * 5 % 255, i * 2 % 255));
FillRect(hdc, &rtmp, hBr);
DeleteObject(hBr);
rtmp.left++;
rtmp.right++;
}
// BitBlt the starting Bitmap into a memory HDC
hdcNew = CreateCompatibleDC(hdc);
hBmp = CreateCompatibleBitmap(hdc, 200,200);
SelectObject(hdcNew, hBmp);
BitBlt(hdcNew, 0, 0, 200, 200, hdc, (rt.right - rt.left - 200) / 2, 0, SRCCOPY);
// Rotate that memory HDC
RotateMemoryDC(hBmp, hdcNew, 200, 200, g_angle, hdcMem, dstX, dstY);
DeleteObject(hBmp);
DeleteDC(hdcNew);
// Create the output HDC
hdcNew = CreateCompatibleDC(hdc);
hBmp = CreateCompatibleBitmap(hdc, 400,400);
SelectObject(hdcNew, hBmp);
rtmp.left = rtmp.top = 0;
rtmp.right = rtmp.bottom = 400;
// Fill the output HDC with the window background color and BitBlt the rotated bitmap into it
FillRect(hdcNew, &rtmp, GetSysColorBrush(COLOR_WINDOW));
BitBlt(hdcNew, (400 - dstX) / 2, (400-dstY) / 2, dstX, dstY, hdcMem, 0, 0, SRCCOPY);
DeleteDC(hdcMem);
BitBlt(hdc, (rt.left + rt.right - 400) / 2, rt.bottom - 400, 400, 400, hdcNew, 0, 0, SRCCOPY);
DeleteObject(hBmp);
DeleteDC(hdcNew);
EndPaint(hWnd, &ps);
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
case WM_TIMER:
// Handle the redraw with the timer
g_angle = g_angle + .05f;
RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
OnDraw(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}