JULIA.C

/******************************Module*Header*******************************\ 
* Module Name: julia.c
*
* Main module for the Mandelbrot Dream
* contains almost everything; windows procedure + misc stuff
*
* Created: 24-Oct-1991 18:34:08
*
* Copyright 1993 - 1998 Microsoft Corporation
*
* The Mandelbrot Dream serves to demonstrate the GDI and USER
* functionalities in the setting of fractals.
*
* The Mandelbrot Dream provides the following functions:
* 1. Drawing the Mandelbrot set and the corresponding julia set
* 2. Zooming into any of the set
* 3. MDI fractal drawing windows
* 4. Floating Point Math/Fix Point Math
* 5. Shifting color table entries
* 6. Changing palette entries and animating palatte aka color cycling
* 7. Loading/Saving bitmap created with special effect
* 8. Changing bitmap color with flood fill
* 9. Boundary tracing and creating a clip region out of it for
* creating special effect
* 10. Enumerate printers for printing
* 11. Load RLE (or convert .bmp files to RLE) for playing in viewer
* 12. Save the RLE in memory to disk.
*
* Note: Users can now draw and saves the julia sets on disk as bmps in
* the Julia windows. These bitmaps can then be read into the memory
* (and converted to RLE format) one by one for displaying in sequence
* in the viewer window. Eg Load the julia.rle in the viewer window
* and select the play or play continuously menu item. 02-Jan-1993
*
* Note2: The fix point math in this sample makes use of the LargeInteger
* 64 bit math library.
*
* Dependencies:
*
* none
*
\**************************************************************************/
#include <windows.h>
#include <stdlib.h>
#include <commdlg.h>
#include <stdarg.h>
#include <math.h>
#include <stdio.h>
#include <shellapi.h>
#include "julia.h"

//
// For T1 to create all pens in advance. This is not a good approach
// because pens are per thread basis. The drawing threads won't be able
// to use them if they are not created in their threads. 18-Sep-1992
//
//#define THRDONE

#define CYCLETHRD

#define PRTTHRD
#define NEWPRTAPI

#ifndef DEBUG
#undef OutputDebugString
#define OutputDebugString(LPCSTR)
#endif

//
// Forward declarations.
//
BOOL InitializeApp (INT*);
LONG APIENTRY MainWndProc (HWND, UINT, DWORD, LONG);
LONG APIENTRY ChildWndProc (HWND, UINT, DWORD, LONG);
BOOL CALLBACK About (HWND, UINT, DWORD, LONG);
LONG APIENTRY TextWndProc (HWND, UINT, DWORD, LONG);
LONG APIENTRY JuliaWndProc (HWND, UINT, DWORD, LONG);
LONG APIENTRY ViewerWndProc (HWND, UINT, DWORD, LONG);
LONG APIENTRY ViewSurfWndProc (HWND, UINT, DWORD, LONG);
BOOL APIENTRY SuspendDrawThrd (HWND, LONG);
BOOL APIENTRY ResumeDrawThrd (HWND, LONG);
BOOL StartDraw (PINFO);
BOOL StartDrawFix (PINFO);
BOOL StartDraw2 (PINFO);
BOOL StartMandelbrot (PINFO);
BOOL StartMandelbrotFix (PINFO);
HBITMAP SaveBitmap (HWND, HPALETTE);
void DrawBitmap (HDC, PINFO, int, int, int, int);
BOOL bDrawDIB (HDC, PINFO, int, int, int, int);
LONG lMul(LONG, LONG);
LONG lDiv(LONG, LONG);
PINFO pGetInfoData(HWND);
BOOL bReleaseInfoData(HWND);
BOOL bCheckMutexMenuItem(PINFO, HMENU, UINT);
VOID vChkMenuItem(PINFO, HMENU, UINT);
BOOL bInitInfo(PINFO);
BOOL bResetGlobal(VOID);
HBRUSH hBrCreateBrush(HDC, DWORD);
BOOL bPrintBmp(PPRTDATA);
BOOL bStoreRleFile(HDC, PINFO, PSTR);
BOOL bFreeRleFile(PINFO);
BOOL bPlayRle(PINFO);
BOOL bSaveRleFile(HDC, PINFO, PSTR);
BOOL bPlayRleCont2(PINFO);
BOOL bSelectDIBPal(HDC, PINFO, LPBITMAPINFO, BOOL);
HBITMAP DIBfromDDB(HDC, HBITMAP, PINFO);


//
// Global variable declarations.
//

HPEN hpnRed;
HPEN hpnBlack;
HPEN hpnGreen;
INT giPen = 0;

HANDLE ghModule;
HWND ghwndMain = NULL;
HWND ghwndClient = NULL;
HANDLE ghAccel;

HMENU hMenu, hChildMenu, hViewMenu;
HMENU hViewSubOne, hSubMenuOne, hSubMenuThree;
HMENU hPrinterMenu;

CHAR gszFile[20];
CHAR gszMapName[20];
char gtext[256];

BOOL gFloat = TRUE;
LONG gStep = 1;
LONG gIteration = 500;
BOOL gbStretch = TRUE;
INT giStretchMode = COLORONCOLOR;
INT giDmOrient = DMORIENT_PORTRAIT;
INT giNPrinters = 0;

HPALETTE ghPal, ghPalOld;

double xFrom, xTo, yFrom, yTo, c1, c2;
LONG lxFrom, lxTo, lyFrom, lyTo, lc1, lc2;




/******************************Public*Routine******************************\
*
* WinMain
*
\**************************************************************************/

int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
MSG msg;

ghModule = GetModuleHandle(NULL);
if (!InitializeApp(&giPen))
{
OutputDebugString("memory: InitializeApp failure!");
return 0;
}

if (!(ghAccel = LoadAccelerators (ghModule, MAKEINTRESOURCE(ACCEL_ID))))
OutputDebugString("memory: Load Accel failure!");


while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator( ghwndMain, ghAccel, &msg) &&
!TranslateMDISysAccel( ghwndClient, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}


DeleteObject(ghPal);

return 1;

UNREFERENCED_PARAMETER(lpCmdLine);
UNREFERENCED_PARAMETER(nShowCmd);
UNREFERENCED_PARAMETER(hInstance);
UNREFERENCED_PARAMETER(hPrevInstance);
}


/***************************************************************************\
* InitializeApp
*
\***************************************************************************/

BOOL InitializeApp(INT *piPen)
{
WNDCLASS wc;
HDC hDC;

#ifdef THRDONE
INT iNumClr;
#endif

wc.style = CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(LONG);
wc.hInstance = ghModule;
wc.hIcon = LoadIcon(ghModule, MAKEINTRESOURCE(APPICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MandelClass";

if (!RegisterClass(&wc))
return FALSE;

wc.lpfnWndProc = (WNDPROC)ChildWndProc;
wc.hIcon = LoadIcon(ghModule, MAKEINTRESOURCE(APPICON));
wc.lpszMenuName = NULL;
wc.lpszClassName = "ChildClass";

if (!RegisterClass(&wc))
return FALSE;

wc.lpfnWndProc = (WNDPROC)ViewerWndProc;
wc.hIcon = LoadIcon(ghModule, MAKEINTRESOURCE(VIEWICON));
wc.lpszMenuName = NULL;
wc.lpszClassName = "ViewerClass";

if (!RegisterClass(&wc))
return FALSE;

wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)TextWndProc;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNSHADOW);
wc.lpszMenuName = NULL;
wc.lpszClassName = "Text";

if (!RegisterClass(&wc))
return FALSE;

wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)JuliaWndProc;
wc.hIcon = NULL;

//
// Nope. Can't have this, screw up my Paint Can cursor
//
//wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszMenuName = NULL;
wc.lpszClassName = "Julia";

if (!RegisterClass(&wc))
return FALSE;

wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)ViewSurfWndProc;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszMenuName = NULL;
wc.lpszClassName = "View";

if (!RegisterClass(&wc))
return FALSE;


//
// Notice, submenu is zero-based
//
hMenu = LoadMenu(ghModule, "MainMenu");
hChildMenu = LoadMenu(ghModule, "ChildMenu");
hViewMenu = LoadMenu(ghModule, "ViewMenu");
hViewSubOne = GetSubMenu(hViewMenu, 1);
hSubMenuOne = GetSubMenu(hMenu, 1);
hSubMenuThree = GetSubMenu(hChildMenu, 8);
hPrinterMenu = GetSubMenu(hChildMenu, 7);

//
// Disable color-cycling for display devices that does not support
// palette like the VGA. As as 29-May-1992, the MIPS display driver
// is the only one that supports palette
//
hDC = GetDC(NULL);
if (!((GetDeviceCaps(hDC, RASTERCAPS)) & RC_PALETTE)) {
EnableMenuItem(hChildMenu, MM_CYCLE, MF_GRAYED);
}

#ifdef THRDONE

if ((iNumClr = iCreatePenFrPal(hDC, NULL, 0, &ghPal)) != 0)
{
sprintf( gtext,"iNumClr = %d\n", iNumClr);
OutputDebugString( gtext);

if ((pInfo->prghPen = (PVOID*) GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(HPEN)*iNumClr)) == NULL)
OutputDebugString ("Failed in Memory Allocation for pInfo->prghPen!");
else
if ((*piPen = iCreatePenFrPal(hDC, pInfo->prghPen, 0, &ghPal)) == 0)
OutputDebugString("Failed in creating pen!");
}

#endif
ReleaseDC(NULL, hDC);

ghwndMain = CreateWindowEx(0L, "MandelClass",
GetStringRes (IDS_MANDEL_DREAM),

WS_OVERLAPPED | WS_CAPTION | WS_BORDER |
WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX |
WS_CLIPCHILDREN | WS_VISIBLE | WS_SYSMENU,
80, 70, 550, 400 /* 550 */,
NULL, hMenu, ghModule, NULL);

if (ghwndMain == NULL)
return FALSE;

bInitPrinter(ghwndMain);

SetWindowLong(ghwndMain, GWL_USERDATA, 0L);

SetFocus(ghwndMain); /* set initial focus */

PostMessage(ghwndMain, WM_COMMAND, MM_MANDEL, 0L);
PostMessage(ghwndMain, WM_COMMAND, MM_CREATE_MANDEL_THREAD, 0L);

return TRUE;
}


/******************************Public*Routine******************************\
*
* MainWndProc
*
\**************************************************************************/

long APIENTRY MainWndProc(
HWND hwnd,
UINT message,
DWORD wParam,
LONG lParam)
{
static int iJuliaCount=1;
static int iMandelCount=1;
static int iViewerCount=1;
CLIENTCREATESTRUCT clientcreate;
HWND hwndChildWindow;
static FARPROC lpfnSuspendThrd, lpfnResumeThrd;


switch (message) {

case WM_CREATE:
SetWindowLong(hwnd, 0, (LONG)NULL);

clientcreate.hWindowMenu = hSubMenuOne;
clientcreate.idFirstChild = 1;

ghwndClient = CreateWindow("MDICLIENT", NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
0,0,0,0,
hwnd, NULL, ghModule, (LPVOID)&clientcreate);
lpfnSuspendThrd = (FARPROC)MakeProcInstance (SuspendDrawThrd, ghModule);
lpfnResumeThrd = (FARPROC)MakeProcInstance (ResumeDrawThrd, ghModule);

return 0L;

case WM_DESTROY: {
bCleanupPrinter();
PostQuitMessage(0);
return 0L;
}

//
// Wait! User is going to zero out our app's visible region. This
// is going to mess up our drawing (we are not keeping any shadow
// bitmap in this version yet.) So, let's suspend our drawing thread
// first before user does that. We will resume after user is done.
//
case WM_SYSCOMMAND: {
LONG lResult;

//
// We'll enumerate our children and suspend their drawing thread.
//
EnumChildWindows(ghwndClient, (WNDENUMPROC)lpfnSuspendThrd, lParam);

//
// Now, let user does it supposed to do
//
lResult = DefFrameProc(hwnd, ghwndClient, message, wParam, lParam);

//
// User's done, we'll resume the suspended threads in our children
//
EnumChildWindows(ghwndClient, (WNDENUMPROC)lpfnResumeThrd, lParam);

return lResult;
break;
}
#if 0
//
// Our window's size is going to change, we'll make sure the new
// window is a square.
//
case WM_WINDOWPOSCHANGING: {
PWINDOWPOS pWndPos;
RECT rect;
LONG lcx, lcy;

GetWindowRect(hwnd, &rect);
lcx = rect.right-rect.left;
lcy = rect.bottom-rect.top;
pWndPos = (PWINDOWPOS)lParam;
if ((pWndPos->cy > lcy) || (pWndPos->cx > lcx))
pWndPos->cx = pWndPos->cy =
((pWndPos->cx > pWndPos->cy) ? pWndPos->cy : pWndPos->cx);
else if ((pWndPos->cy < lcy) || (pWndPos->cx < lcx))
pWndPos->cx = pWndPos->cy =
((pWndPos->cx > pWndPos->cy) ? pWndPos->cy : pWndPos->cx);
break;
}
#endif

case WM_COMMAND:

switch (LOWORD(wParam)) {
case IDM_TILE:
SendMessage(ghwndClient, WM_MDITILE, 0L, 0L);
return 0L;
case IDM_CASCADE:
SendMessage(ghwndClient, WM_MDICASCADE, 0L, 0L);
return 0L;
case IDM_ARRANGE:
SendMessage(ghwndClient, WM_MDIICONARRANGE, 0L, 0L);
return 0L;

//
// Create Julia or Mandelbrot set
//
case MM_JULIA:
case MM_MANDEL: {
HANDLE hInfo;
PINFO pInfo;
MDICREATESTRUCT mdicreate;

hInfo = LocalAlloc(LHND, (WORD) sizeof(INFO));
if (hInfo == NULL)
{
OutputDebugString("Failed to Allocate Info!");
return 0L;
}
if ((pInfo = (PINFO)LocalLock(hInfo)) == NULL)
{
OutputDebugString("Failed in LocalLock, hInfo");
return 0L;
}

bInitInfo(pInfo);
wsprintf((LPSTR) &(pInfo->CaptionBarText),
(LOWORD(wParam) == MM_JULIA) ?
GetStringRes (IDS_JULIA):
GetStringRes (IDS_MANDELBROT),
(LOWORD(wParam) == MM_JULIA) ? iJuliaCount : iMandelCount);
if (LOWORD(wParam) == MM_JULIA) {
c1 = 0.360284;
c2 = 0.100376;
lc1 = 738; //.3603515
lc2 = 206; //.1005859
pInfo->bMandel = FALSE;
} else {
pInfo->bMandel = TRUE;
}

//
// Fill in the MDICREATE structure for MDI child creation
//
mdicreate.szClass = "ChildClass";
mdicreate.szTitle = (LPTSTR)&(pInfo->CaptionBarText);
mdicreate.hOwner = ghModule;
mdicreate.x =
mdicreate.y = CW_USEDEFAULT;
mdicreate.cx = 300;
mdicreate.cy = 300;
mdicreate.style = 0L;
mdicreate.lParam = (LONG) hInfo;

/*Create Child Window*/
hwndChildWindow =
(HANDLE) SendMessage(ghwndClient, WM_MDICREATE,
0L,
(LONG)(LPMDICREATESTRUCT)&mdicreate);

if (hwndChildWindow == NULL)
{
OutputDebugString ("Failed in Creating Child Window");
return 0L;
}

(LOWORD(wParam) == MM_JULIA) ? iJuliaCount++ : iMandelCount++ ;
LocalUnlock(hInfo);
return ((LONG)hwndChildWindow);
}

case MM_RLEVIEWER: {
HANDLE hInfo;
PINFO pInfo;
MDICREATESTRUCT mdicreate;

hInfo = LocalAlloc(LHND, (WORD) sizeof(INFO));
if (hInfo == NULL)
{
OutputDebugString ("Failed to Allocate Info!");
return 0L;
}
if ((pInfo = (PINFO)LocalLock(hInfo)) == NULL)
{
OutputDebugString ("Failed in LocalLock, hInfo");
return 0L;
}

bInitInfo(pInfo);
wsprintf((LPSTR) &(pInfo->CaptionBarText), GetStringRes (IDS_VIEWER), iViewerCount );

//
// Fill in the MDICREATE structure for MDI child creation
//
mdicreate.szClass = "ViewerClass";
mdicreate.szTitle = (LPTSTR)&(pInfo->CaptionBarText);
mdicreate.hOwner = ghModule;
mdicreate.x =
mdicreate.y = CW_USEDEFAULT;
mdicreate.cx = 300;
mdicreate.cy = 300;
mdicreate.style = 0L;
mdicreate.lParam = (LONG) hInfo;

/*Create Child Window*/
hwndChildWindow =
(HANDLE) SendMessage(ghwndClient, WM_MDICREATE,
0L,
(LONG)(LPMDICREATESTRUCT)&mdicreate);

if (hwndChildWindow == NULL)
{
OutputDebugString ("Failed in Creating Child Window");
return 0L;
}

iViewerCount++ ;
LocalUnlock(hInfo);
return ((LONG)hwndChildWindow);

}

case MM_ABOUT:
if (DialogBox(ghModule, "AboutBox", ghwndMain, (DLGPROC)About) == -1)
OutputDebugString ("DEMO: About Dialog Creation Error!");
return 0L;

//
// Only my children know how to deal with these messages, so
// pass these to children for processing
//
case MM_CREATE_JULIA_THREAD:
case MM_SET_XFORM_ATTR:
case MM_CREATE_MANDEL_THREAD:
case MM_OPT_4: // currently not used
case MM_DRAW_SET:
case MM_SETDIB2DEVICE:
case MM_BW:
case MM_SHIFT:
case MM_CUSTOM:
case MM_CYCLE:
case MM_TP_IDLE:
case MM_TP_LOW:
case MM_TP_BELOW_NORMAL:
case MM_TP_NORMAL:
case MM_TP_ABOVE_NORMAL:
case MM_TP_HIGH:
case MM_TP_TIME_CRITICAL:
case MM_FLOAT:
case MM_FIX:
case MM_ITERATION_100:
case MM_ITERATION_500:
case MM_ITERATION_1000:
case MM_ITERATION_5000:
case MM_ITERATION_DOUBLE:
case MM_STEP_ONE:
case MM_STEP_TWO:
case MM_STEP_THREE:
case MM_SAVE:
case MM_SAVE_MONO:
case MM_LOAD:
case MM_STRETCHBLT:
case MM_BITBLT:
case MM_BLACKONWHITE:
case MM_COLORONCOLOR:
case MM_WHITEONBLACK:
case MM_HALFTONE:
case MM_CLIP:
case MM_RM_CLIP:
case MM_SELCLIPRGN:
case MM_ERASE:
case MM_PORTRAIT:
case MM_LANDSCAPE:
case MM_PRINTER:
case MM_PRINTER + 1:
case MM_PRINTER + 2:
case MM_PRINTER + 3:
case MM_PRINTER + 4:
case MM_PRINTER + 5:
case MM_PRINTER + 6:
case MM_PRINTER + 7:
case MM_PRINTER + 8:
case MM_PRINTER + 9:
case MM_RLELOAD_DEMO:
case MM_RLEPLAYCONT:
case MM_RLELOAD:
case MM_RLESAVE:
case MM_CLEAR:
case MM_RLEPLAY:
{
HWND hActiveChild;

hActiveChild = (HANDLE) SendMessage(ghwndClient, WM_MDIGETACTIVE, 0L, 0L);
if (hActiveChild)
SendMessage(hActiveChild, WM_COMMAND, wParam, lParam);
return 0L;
}

default:
return DefFrameProc(hwnd, ghwndClient, message, wParam, lParam);
}
default:

return DefFrameProc(hwnd, ghwndClient, message, wParam, lParam);
}
}

/***************************************************************************\
* ChildWndProc
*
\***************************************************************************/

long APIENTRY ChildWndProc(
HWND hwnd,
UINT message,
DWORD wParam,
LONG lParam)
{
static FARPROC lpfnSuspendThrd, lpfnResumeThrd;
static BOOL bDIB2Device = FALSE;

sprintf( gtext,"message = %lx\n", message);
OutputDebugString( gtext);

switch (message) {
case WM_COMMAND: {
PINFO pInfo;
HWND hTextWnd;

switch (LOWORD(wParam)) {
//
// Create a Julia drawing thread
//
case MM_CREATE_JULIA_THREAD: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

hTextWnd = pInfo->hTextWnd;
sprintf( gtext,"(%g, %g) <-> (%g, %g)", pInfo->xFrom, pInfo->yFrom, pInfo->xTo, pInfo->yTo);
SetWindowText(hTextWnd, gtext);
sprintf( gtext,"(c1 = %g, c2 = %g)\n\n", pInfo->c1, pInfo->c2);
OutputDebugString( gtext );

if (pInfo->hThrd)
CloseHandle(pInfo->hThrd);

pInfo->hThrd = CreateThread(NULL, 0,
(gFloat ? (LPTHREAD_START_ROUTINE)StartDraw : (LPTHREAD_START_ROUTINE)StartDrawFix),
pInfo,
STANDARD_RIGHTS_REQUIRED,
&pInfo->dwThreadId );

if (pInfo->hThrd && pInfo->bDrawing)
{
if (!SetThreadPriority(pInfo->hThrd, pInfo->iPriority))
OutputDebugString ("Can't set Priority!");
}

bReleaseInfoData(hwnd);
return 0L;
}

//
// Reset pInfo reflecting new transformation
//
case MM_SET_XFORM_ATTR: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

hTextWnd = pInfo->hTextWnd;
SetWindowText(hTextWnd, GetStringRes (IDS_CLICK_HERE_VIEW));

pInfo->xFrom = xFrom;
pInfo->xTo = xTo;
pInfo->yFrom = yFrom;
pInfo->yTo = yTo;
pInfo->c1 = c1;
pInfo->c2 = c2;
pInfo->lxFrom = lxFrom;
pInfo->lxTo = lxTo;
pInfo->lyFrom = lyFrom;
pInfo->lyTo = lyTo;
pInfo->lc1 = lc1;
pInfo->lc2 = lc2;

bReleaseInfoData(hwnd);
return 0L;
}

//
// Create a Mandelbrot drawing thread
//
case MM_CREATE_MANDEL_THREAD: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

hTextWnd = pInfo->hTextWnd;
sprintf( gtext,"(%g, %g) <-> (%g, %g)", pInfo->xFrom, pInfo->yFrom, pInfo->xTo, pInfo->yTo);
SetWindowText(hTextWnd, gtext);
sprintf( gtext,"(c1 = %g, c2 = %g)\n\n", pInfo->c1, pInfo->c2);
OutputDebugString( gtext );

if (pInfo->hThrd)
CloseHandle(pInfo->hThrd);

pInfo->hThrd = CreateThread(NULL, 0,
(gFloat ? (LPTHREAD_START_ROUTINE)StartMandelbrot : (LPTHREAD_START_ROUTINE)StartMandelbrotFix),
pInfo,
STANDARD_RIGHTS_REQUIRED,
&pInfo->dwThreadId );

if (pInfo->hThrd && pInfo->bDrawing)
{
if (!SetThreadPriority(pInfo->hThrd, pInfo->iPriority))
OutputDebugString ("Can't set Priority!");
}


bReleaseInfoData(hwnd);
return 0L;
}

//
// Create a Julia drawing thread using algorithm StartDraw2
// Currently not used
//
case MM_OPT_4: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

hTextWnd = pInfo->hTextWnd;
SetWindowText(hTextWnd, "MM_OPT_4");

sprintf( gtext,"xFrom = %g, xTo = %g, yFrom = %g, yTo = %g\n", pInfo->xFrom, pInfo->xTo, pInfo->yFrom, pInfo->yTo);
OutputDebugString( gtext );

if (pInfo->hThrd)
CloseHandle(pInfo->hThrd);

pInfo->hThrd = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)StartDraw2,
pInfo,
STANDARD_RIGHTS_REQUIRED,
&pInfo->dwThreadId );

if (pInfo->hThrd && pInfo->bDrawing)
{
if (!SetThreadPriority(pInfo->hThrd, pInfo->iPriority))
OutputDebugString ("Can't set Priority!");
}

bReleaseInfoData(hwnd);
return 0L;
}

case MM_DRAW_SET: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

PostMessage(hwnd, WM_COMMAND,
pInfo->bMandel ? (DWORD)((WORD)MM_CREATE_MANDEL_THREAD) : (DWORD)((WORD)MM_CREATE_JULIA_THREAD),
(LONG)0L);

bReleaseInfoData(hwnd);
return 0L;
}

{
int iPriority;

case MM_TP_IDLE:
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

iPriority = THREAD_PRIORITY_IDLE;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_TP_IDLE);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
goto CWP_SET_PRIORITY;

case MM_TP_LOW:
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

iPriority = THREAD_PRIORITY_LOWEST;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_TP_LOW);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
goto CWP_SET_PRIORITY;

case MM_TP_BELOW_NORMAL:
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

iPriority = THREAD_PRIORITY_BELOW_NORMAL;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_TP_BELOW_NORMAL);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
goto CWP_SET_PRIORITY;

case MM_TP_NORMAL:
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

iPriority = THREAD_PRIORITY_NORMAL;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_TP_NORMAL);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
goto CWP_SET_PRIORITY;

case MM_TP_ABOVE_NORMAL:
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

iPriority = THREAD_PRIORITY_ABOVE_NORMAL;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_TP_ABOVE_NORMAL);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
goto CWP_SET_PRIORITY;

case MM_TP_HIGH:
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

iPriority = THREAD_PRIORITY_HIGHEST;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_TP_HIGH);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
goto CWP_SET_PRIORITY;

case MM_TP_TIME_CRITICAL:
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

iPriority = THREAD_PRIORITY_TIME_CRITICAL;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_TP_TIME_CRITICAL);
DrawMenuBar(GetParent(GetParent(hwnd))) ;

CWP_SET_PRIORITY:
{
HANDLE hThrd;

hThrd = pInfo->hThrd;
pInfo->iPriority = iPriority;

if (hThrd && pInfo->bDrawing)
{
if (!SetThreadPriority(hThrd, iPriority))
OutputDebugString ("Can't set Priority!");
}

}
bReleaseInfoData(hwnd);
return 0L;

}

case MM_FLOAT: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_FLOAT);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gFloat = TRUE;
bReleaseInfoData(hwnd);
return 0L;
}
case MM_FIX: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_FIX);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gFloat = FALSE;
bReleaseInfoData(hwnd);
return 0L;
}
case MM_ITERATION_100: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_ITERATION_100);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gIteration = 100;
pInfo->iIteration = 100;
SetWindowText(pInfo->hTextWnd, GetStringRes (IDS_ITER_100));
bReleaseInfoData(hwnd);
return 0L;
}
case MM_ITERATION_500: {
if ((pInfo = pGetInfoData(hwnd)) == NULL){
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_ITERATION_500);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gIteration = 500;

pInfo->iIteration = 500;
SetWindowText(pInfo->hTextWnd, GetStringRes (IDS_ITER_500));
bReleaseInfoData(hwnd);
return 0L;
}
case MM_ITERATION_1000: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_ITERATION_1000);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gIteration = 1000;
pInfo->iIteration = 1000;
SetWindowText(pInfo->hTextWnd, GetStringRes (IDS_ITER_1000));
bReleaseInfoData(hwnd);
return 0L;
}
case MM_ITERATION_5000: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_ITERATION_5000);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gIteration = 5000;
pInfo->iIteration = 5000;
SetWindowText(pInfo->hTextWnd, GetStringRes (IDS_ITER_5000));
bReleaseInfoData(hwnd);
return 0L;
}
case MM_ITERATION_DOUBLE: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_ITERATION_DOUBLE);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gIteration *= 2;
pInfo->iIteration = gIteration;
sprintf( gtext, GetStringRes (IDS_ITERATION), pInfo->iIteration);
SetWindowText(pInfo->hTextWnd, gtext);
bReleaseInfoData(hwnd);
return 0L;
}
case MM_STEP_ONE: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_STEP_ONE);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gStep = 1;
pInfo->iStep = 1;

bReleaseInfoData(hwnd);
return 0L;
}
case MM_STEP_TWO: {
if ((pInfo = pGetInfoData(hwnd)) == NULL){
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_STEP_TWO);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gStep = 2;
pInfo->iStep = 2;

bReleaseInfoData(hwnd);
return 0L;
}
case MM_STEP_THREE: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
bCheckMutexMenuItem(pInfo, hChildMenu, MM_STEP_THREE);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
gStep = 3;
pInfo->iStep = 3;

bReleaseInfoData(hwnd);
return 0L;
}

case MM_LOAD: {
HDC hDC;
OPENFILENAME ofn;
char szDirName[256];
char szFile[256], szFileTitle[256];
static char *szFilter;
RECT rc;

if ((pInfo = pGetInfoData(hwnd)) == NULL){
return 0L;
}

szFilter = GetStringRes (IDS_FILE_LIST1);

GetSystemDirectory((LPSTR) szDirName, 256);
strcpy(szFile, "*.bmp\0");

ofn.lStructSize = sizeof(OPENFILENAME); 
ofn.hwndOwner = pInfo->hwnd;
ofn.lpstrFilter = szFilter;
ofn.lpstrCustomFilter = (LPSTR) NULL;
ofn.nMaxCustFilter = 0L;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof(szFileTitle);
ofn.lpstrInitialDir = szDirName;
ofn.lpstrTitle = (LPSTR) NULL;
ofn.Flags = 0L;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = "BMP";

if (!GetOpenFileName(&ofn))
return 0L;

GetClientRect(pInfo->hwnd, &rc);
hDC = GetDC(pInfo->hwnd);
if (LoadBitmapFile(hDC, pInfo, szFile))
bDrawDIB(hDC, pInfo, 0, 0, rc.right, rc.bottom);
ReleaseDC(hwnd, hDC);

bReleaseInfoData(hwnd);

return 0L;
}

case MM_SAVE: {
HDC hDC;
OPENFILENAME ofn;
char szDirName[256];
char szFile[256], szFileTitle[256];
static char *szFilter;

szFilter = GetStringRes (IDS_FILE_LIST2);

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
hDC = GetDC(pInfo->hwnd);
#if 0
{
HPALETTE hPalTmp;

hPalTmp = CopyPalette(pInfo->hPal);
DeleteObject(pInfo->hPal);
pInfo->hPal = hPalTmp;
}
#endif
//
// saving special effects user might have created in window
//
if (pInfo->hBmpSaved)
DeleteObject(pInfo->hBmpSaved);
pInfo->hBmpSaved = SaveBitmap(pInfo->hwnd, pInfo->hPal);
pInfo->bUseDIB = FALSE;

GetSystemDirectory((LPSTR) szDirName, 256);
strcpy(szFile, "*.bmp\0");
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = pInfo->hwnd;
ofn.lpstrFilter = szFilter;
ofn.lpstrCustomFilter = (LPSTR) NULL;
ofn.nMaxCustFilter = 0L;
ofn.nFilterIndex = 0L;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof(szFileTitle);
ofn.lpstrInitialDir = szDirName;
ofn.lpstrTitle = (LPSTR) NULL;
ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = (LPSTR)NULL;

if (!GetSaveFileName(&ofn)) {
ReleaseDC(pInfo->hwnd, hDC);
bReleaseInfoData(hwnd);
return 0L;
}

SelectPalette(hDC,
((pInfo->iStretchMode == HALFTONE) ? pInfo->hHTPal : pInfo->hPal),
FALSE);
RealizePalette(hDC);
UpdateColors(hDC);

//
// test
//
ghPal = pInfo->hPal;

SaveBitmapFile(hDC, pInfo->hBmpSaved, szFile);

ReleaseDC(pInfo->hwnd, hDC);

bReleaseInfoData(hwnd);
return 0L;
}
case MM_SAVE_MONO: {
HDC hDC;
OPENFILENAME ofn;
char szDirName[256];
char szFile[256], szFileTitle[256];
static char *szFilter;

if ((pInfo = pGetInfoData(hwnd)) == NULL){
return 0L;
}

szFilter = GetStringRes (IDS_FILE_LIST2);

GetSystemDirectory((LPSTR) szDirName, 256);
strcpy(szFile, "*.bmp\0");
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = pInfo->hwnd;
ofn.lpstrFilter = szFilter;
ofn.lpstrCustomFilter = (LPSTR) NULL;
ofn.nMaxCustFilter = 0L;
ofn.nFilterIndex = 0L;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof(szFileTitle);
ofn.lpstrInitialDir = szDirName;
ofn.lpstrTitle = GetStringRes (IDS_SAVING_MONO_BITMAP);
ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = (LPSTR)NULL;

if (!GetSaveFileName(&ofn))
return 0L;

hDC = GetDC(pInfo->hwnd);

SaveBitmapFile(hDC, pInfo->hBmpMono, szFile);
ReleaseDC(pInfo->hwnd, hDC);

bReleaseInfoData(hwnd);
return 0L;
}
case MM_STRETCHBLT: {
if ((pInfo = pGetInfoData(hwnd)) == NULL){
return 0L;
}
gbStretch = TRUE;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_STRETCHBLT);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
pInfo->bStretch = gbStretch;
InvalidateRect(pInfo->hwnd, NULL, FALSE);

bReleaseInfoData(hwnd);
return 0L;

}
case MM_BITBLT: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
gbStretch = FALSE;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_BITBLT);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
pInfo->bStretch = gbStretch;
InvalidateRect(pInfo->hwnd, NULL, FALSE);

bReleaseInfoData(hwnd);
return 0L;

}
case MM_BLACKONWHITE: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
giStretchMode = BLACKONWHITE;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_BLACKONWHITE);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
pInfo->iStretchMode = giStretchMode;
InvalidateRect(pInfo->hwnd, NULL, FALSE);

bReleaseInfoData(hwnd);
return 0L;

}
case MM_COLORONCOLOR: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
giStretchMode = COLORONCOLOR;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_COLORONCOLOR);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
pInfo->iStretchMode = giStretchMode;
InvalidateRect(pInfo->hwnd, NULL, FALSE);

bReleaseInfoData(hwnd);
return 0L;

}
case MM_WHITEONBLACK: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
giStretchMode = WHITEONBLACK;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_WHITEONBLACK);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
pInfo->iStretchMode = giStretchMode;
InvalidateRect(pInfo->hwnd, NULL, FALSE);

bReleaseInfoData(hwnd);
return 0L;

}
case MM_HALFTONE: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
giStretchMode = HALFTONE;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_HALFTONE);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
pInfo->iStretchMode = giStretchMode;
InvalidateRect(pInfo->hwnd, NULL, FALSE);

bReleaseInfoData(hwnd);
return 0L;
}
case MM_SETDIB2DEVICE: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
bDIB2Device = (bDIB2Device ? FALSE : TRUE);
pInfo->bSetDIBsToDevice = bDIB2Device;
CheckMenuItem(hChildMenu, MM_SETDIB2DEVICE, (bDIB2Device ? MF_CHECKED : MF_UNCHECKED));
bReleaseInfoData(hwnd);
return 0L;
}
case MM_BW: {
HDC hDC;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
hDC = GetDC(pInfo->hwnd);
bChangeDIBColor(hDC, pInfo, MM_BW);
ReleaseDC(hwnd, hDC);
bReleaseInfoData(hwnd);
return 0L;
}
case MM_SHIFT: {
HDC hDC;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
hDC = GetDC(pInfo->hwnd);
bChangeDIBColor(hDC, pInfo, MM_SHIFT);
ReleaseDC(hwnd, hDC);
bReleaseInfoData(hwnd);
return 0L;
}
case MM_CUSTOM: {
static DWORD argbCust[16] = {
RGB(255, 255, 255), RGB(255, 255, 255),
RGB(255, 255, 255), RGB(255, 255, 255),
RGB(255, 255, 255), RGB(255, 255, 255),
RGB(255, 255, 255), RGB(255, 255, 255),
RGB(255, 255, 255), RGB(255, 255, 255),
RGB(255, 255, 255), RGB(255, 255, 255),
RGB(255, 255, 255), RGB(255, 255, 255),
RGB(255, 255, 255), RGB(255, 255, 255)
};
CHOOSECOLOR cc;
BOOL bResult;
DWORD rgbOld;
HBRUSH hBrush;
HDC hDC;

rgbOld = RGB(255, 255, 255);
cc.lStructSize = sizeof(CHOOSECOLOR);
cc.hwndOwner = ghwndMain;
cc.hInstance = ghModule;
cc.rgbResult = rgbOld;
cc.lpCustColors = argbCust;
cc.Flags = CC_RGBINIT | CC_SHOWHELP;
cc.lCustData = 0;
cc.lpfnHook = NULL;
cc.lpTemplateName = NULL;

bResult = ChooseColor(&cc);
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
if (bResult) {
hDC = GetDC(pInfo->hwnd);
hBrush = hBrCreateBrush(hDC, cc.rgbResult);
ReleaseDC(pInfo->hwnd, hDC);
if (pInfo->hBrush)
DeleteObject(pInfo->hBrush);
pInfo->hBrush = hBrush;
pInfo->bFill = TRUE;
}
bReleaseInfoData(hwnd);
return 0L;
}

#ifndef CYCLETHRD
case MM_CYCLE: {
HDC hDC;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
hDC = GetDC(pInfo->hwnd);

if (pInfo->bClrCycle) {
CheckMenuItem(hChildMenu, MM_CYCLE, MF_UNCHECKED);
pInfo->bClrCycle = FALSE;
} else {
CheckMenuItem(hChildMenu, MM_CYCLE, MF_CHECKED);
pInfo->bClrCycle = TRUE;
bChangeDIBColor(hDC, pInfo, MM_CYCLE);
}

ReleaseDC(hwnd, hDC);
bReleaseInfoData(hwnd);
return 0L;
}
#else

case MM_CYCLE: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

if (pInfo->bFirstTime)
{
if (!SetEvent(pInfo->hQuitEvent))
{
OutputDebugString ("Can't set Quit Event!");
return 0L;
}

if (pInfo->hCycleThrd)
CloseHandle(pInfo->hCycleThrd);

pInfo->hCycleThrd = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)bCycle,
(LPVOID)hwnd,
STANDARD_RIGHTS_REQUIRED,
&pInfo->dwCycleThrdID );
pInfo->bClrCycle = TRUE;
pInfo->bFirstTime = FALSE;
CheckMenuItem(hChildMenu, MM_CYCLE, MF_CHECKED);
} else {
if (pInfo->bClrCycle) {
CheckMenuItem(hChildMenu, MM_CYCLE, MF_UNCHECKED);
pInfo->bClrCycle = FALSE;
pInfo->dwSuspend = SuspendThread(pInfo->hCycleThrd);
} else {
CheckMenuItem(hChildMenu, MM_CYCLE, MF_CHECKED);
pInfo->bClrCycle = TRUE;
pInfo->dwSuspend = ResumeThread(pInfo->hCycleThrd);
}
if (pInfo->dwSuspend == -1) {
(pInfo->bClrCycle ?
sprintf( gtext,"Error in resuming thread\n") :
sprintf( gtext,"Error in suspending thread\n") );
OutputDebugString( gtext );
}
}

bReleaseInfoData(hwnd);
return 0L;
}
#endif
case MM_CLIP: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

hTextWnd = pInfo->hTextWnd;
sprintf( gtext,"(%g, %g) <-> (%g, %g)", pInfo->xFrom, pInfo->yFrom, pInfo->xTo, pInfo->yTo);
SetWindowText(hTextWnd, gtext);
sprintf( gtext,"(c1 = %g, c2 = %g)\n\n", pInfo->c1, pInfo->c2);
OutputDebugString( gtext );
if (!pInfo->bMandel)
{
MessageBox(ghwndMain,
GetStringRes (IDS_BOUNDARY),
NULL, MB_OK);
return 0L;
}

if (pInfo->hThrd)
CloseHandle(pInfo->hThrd);

pInfo->hThrd = CreateThread(NULL, 0,
(gFloat ? (LPTHREAD_START_ROUTINE)bBoundaryScanFix : (LPTHREAD_START_ROUTINE)bBoundaryScanFix),
pInfo,
STANDARD_RIGHTS_REQUIRED,
&pInfo->dwThreadId );

bReleaseInfoData(hwnd);
return 0L;
}
case MM_RM_CLIP: {
HDC hDC;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

hDC = GetDC(pInfo->hwnd);
SelectClipRgn(hDC, (HRGN) NULL);
ReleaseDC(pInfo->hwnd, hDC);
bReleaseInfoData(hwnd);
InvalidateRect(pInfo->hwnd, NULL, FALSE);
return 0L;

}
case MM_SELCLIPRGN: {
HDC hDC;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
hDC = GetDC(pInfo->hwnd);

if (pInfo->hRgnPath != (HRGN) NULL) {
SelectClipRgn(hDC, pInfo->hRgnPath);
}

ReleaseDC(pInfo->hwnd, hDC);
bReleaseInfoData(hwnd);
return 0L;
}
case MM_ERASE: {
HDC hDC;
RECT rc;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}
hDC = GetDC(pInfo->hwnd);
if (pInfo->hRgnPath != (HRGN) NULL) {
SelectClipRgn(hDC, pInfo->hRgnPath);
}
SelectObject(hDC, GetStockObject(WHITE_BRUSH));
GetClientRect(pInfo->hwnd, &rc);
PatBlt(hDC, 0, 0, rc.right, rc.bottom, PATCOPY);
ReleaseDC(pInfo->hwnd, hDC);
bReleaseInfoData(hwnd);
return 0L;
}
case MM_PORTRAIT: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

giDmOrient = DMORIENT_PORTRAIT;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_PORTRAIT);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
bReleaseInfoData(hwnd);
return 0L;
}
case MM_LANDSCAPE: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

giDmOrient = DMORIENT_LANDSCAPE;
bCheckMutexMenuItem(pInfo, hChildMenu, MM_LANDSCAPE);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
bReleaseInfoData(hwnd);
return 0L;
}
case MM_PRINTER:
case MM_PRINTER + 1:
case MM_PRINTER + 2:
case MM_PRINTER + 3:
case MM_PRINTER + 4:
case MM_PRINTER + 5:
case MM_PRINTER + 6:
case MM_PRINTER + 7:
case MM_PRINTER + 8:

#ifdef PRTTHRD
case MM_PRINTER + 9: {
PINFO pInfo;
PRTDATA PrtData, *pPrtData;
ULONG sizINFO;
PBYTE pjTmpInfo, pjTmp;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

if (pInfo->hBmpSaved == NULL)
{
MessageBox(ghwndMain,
GetStringRes (IDS_NO_SAVED_BITMAP),
NULL, MB_OK);
return 0L;
}

//
// Copy the info structure to PrtData
//
pPrtData = &PrtData;
pjTmp = (PBYTE)&(pPrtData->info);
pjTmpInfo = (PBYTE)pInfo;
sizINFO = sizeof(INFO);

while(sizINFO--)
{
*(((PBYTE)pjTmp)++) = *((pjTmpInfo)++);
}

PrtData.index = LOWORD(wParam) - MM_PRINTER;

if (giDmOrient == DMORIENT_PORTRAIT) {
PrtData.bUseDefault = TRUE;
} else {
PrtData.bUseDefault = FALSE;
PrtData.DevMode.dmSize = sizeof(DEVMODE);
PrtData.DevMode.dmDriverExtra = 0;
PrtData.DevMode.dmOrientation = DMORIENT_LANDSCAPE;
PrtData.DevMode.dmFields = DM_ORIENTATION;
}

if (pInfo->hPrtThrd)
CloseHandle(pInfo->hPrtThrd);

pInfo->hPrtThrd = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)bPrintBmp,
&PrtData,
STANDARD_RIGHTS_REQUIRED,
&pInfo->dwPrtThrdID );

bReleaseInfoData(hwnd);
return 0L;
}

#else
case MM_PRINTER + 9: {
HDC hdcPrinter, hDC;
int index;
DEVMODE devmode;
DEVMODE *pdevmode;
PINFO pInfo;
int iWidth, iHeight;


index = LOWORD(wParam) - MM_PRINTER;

if (giDmOrient == DMORIENT_PORTRAIT)
pdevmode = NULL;
else {
pdevmode = &devmode;
devmode.dmSize = sizeof(DEVMODE);
devmode.dmDriverExtra = 0;
devmode.dmOrientation = DMORIENT_LANDSCAPE;
devmode.dmFields = DM_ORIENTATION;
}

if (!(hdcPrinter = CreateDC( "", gpszPrinterNames[index],
"", pdevmode)))
{
return(0L);
}

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

iWidth = GetDeviceCaps(hdcPrinter, HORZRES);
iHeight = GetDeviceCaps(hdcPrinter, VERTRES);

// !!! Why is it necessary to save the image over again? May not want to
// do this because user may want to print the nice HT bitmap. So,
// use the DIB src.
#if 0
if (pInfo->hBmpSaved)
DeleteObject(pInfo->hBmpSaved);

pInfo->hBmpSaved = SaveBitmap(pInfo->hwnd, pInfo->hPal);
#endif
Escape(hdcPrinter, STARTDOC, 20, "Mandelbrot", NULL);
bDrawDIB(hdcPrinter, pInfo, 0, 0, iWidth, iHeight);
Escape(hdcPrinter, NEWFRAME, 0, NULL, NULL);
Escape(hdcPrinter, ENDDOC, 0, NULL, NULL);
ReleaseDC(pInfo->hwnd, hDC);
bReleaseInfoData(hwnd);
DeleteDC(hdcPrinter);
return 0L;
}
#endif
default:
return 0L;

}

}
case WM_SETFOCUS:
break;

case WM_MDIACTIVATE: {
PINFO pInfo;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

if ((HWND) lParam == hwnd) { // being activated
SendMessage(GetParent(hwnd), WM_MDISETMENU,
(DWORD) hChildMenu,
(LONG) hSubMenuThree) ;

(pInfo->bClrCycle ?
CheckMenuItem(hChildMenu, MM_CYCLE, MF_CHECKED) :
CheckMenuItem(hChildMenu, MM_CYCLE, MF_UNCHECKED) );

vChkMenuItem(pInfo, hChildMenu, MF_CHECKED);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
goto MDI_ACT_EXIT;
}

if ((HWND) wParam == hwnd) { // being deactivated

vChkMenuItem(pInfo, hChildMenu, MF_UNCHECKED);
DrawMenuBar(GetParent(GetParent(hwnd))) ;
}
MDI_ACT_EXIT:
bReleaseInfoData(hwnd);
return 0L;
}

case WM_QUERYNEWPALETTE:
case WM_PALETTECHANGED: {
PINFO pInfo;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

SendMessage(pInfo->hwnd, message, wParam, lParam);
bReleaseInfoData(hwnd);
return 0L;
}

#if 0
case WM_WINDOWPOSCHANGING: {
PWINDOWPOS pWndPos;
PINFO pInfo;
HWND hTextWnd;
int iCyText, iCxBorder, iCyBorder, iCyCaption;
RECT rect, rcl;
LONG lcx, lcy;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
break;
}

hTextWnd = pInfo->hTextWnd;

bReleaseInfoData(hwnd);

iCyText = GetWindowLong(hTextWnd, GWL_USERDATA);
iCxBorder = GetSystemMetrics(SM_CXBORDER);
iCyBorder = GetSystemMetrics(SM_CYBORDER);
iCyCaption = GetSystemMetrics(SM_CYCAPTION) - iCyBorder;
GetClientRect(GetParent(hwnd), &rcl);
GetWindowRect(hwnd, &rect);
lcx = rect.right-rect.left;
lcy = rect.bottom-rect.top;
pWndPos = (PWINDOWPOS)lParam;
if ((pWndPos->cy > lcy) || (pWndPos->cx > lcx)) {
pWndPos->cx =
((pWndPos->cx > pWndPos->cy) ? pWndPos->cy-iCyText : pWndPos->cx);
pWndPos->cy = pWndPos->cx + iCyText;
} else { if ((pWndPos->cy < lcy) || (pWndPos->cx < lcx)) {
pWndPos->cx =
((pWndPos->cx > pWndPos->cy) ? pWndPos->cy-iCyText : pWndPos->cx);
pWndPos->cy = pWndPos->cx + iCyText;
}
}
break;
}
#endif
case WM_SIZE: {
HANDLE hThrd;
PINFO pInfo;
HWND hTextWnd, hJulia;
BOOL bMandel;
WORD wCx;
int iCyText;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
break;
}

hTextWnd = pInfo->hTextWnd;
hJulia = pInfo->hwnd;
hThrd = pInfo->hThrd;
bMandel = pInfo->bMandel;
bReleaseInfoData(hwnd);
iCyText = GetWindowLong(hTextWnd, GWL_USERDATA);
wCx = (WORD) (HIWORD(lParam) - iCyText);

MoveWindow(hJulia, 0, 0,
LOWORD(lParam),
wCx,
TRUE);

MoveWindow(hTextWnd,
0,
wCx,
LOWORD(lParam),
iCyText,
TRUE);

if (hThrd) {
TerminateThread(hThrd, (DWORD)0L);
/*
PostMessage(hwnd, WM_COMMAND,
bMandel ? (DWORD)((WORD)MM_CREATE_MANDEL_THREAD) : (DWORD)((WORD)MM_CREATE_JULIA_THREAD),
(LONG)0L);
*/
}

break;
}

//
// display info in the status window
//
case WM_USER+0xa: {
PINFO pInfo;
static ULONG ulClick = 0;
HWND hTextWnd;

ulClick++;
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

hTextWnd = pInfo->hTextWnd;
switch (ulClick % 6) {
case 0: sprintf( gtext,"%g <= x <= %g, %g <= y <= %g", pInfo->xFrom, pInfo->xTo, pInfo->yTo, pInfo->yFrom);
break;
case 1: sprintf( gtext,"c1 = %g, c2 = %g", pInfo->c1, pInfo->c2);
break;
case 2: sprintf( gtext,
GetStringRes (IDS_ELAPSED_TIME),
(ULONG) pInfo->dwElapsed);
break;
case 3: sprintf( gtext,
GetStringRes (IDS_ITERATION),
pInfo->iIteration);
break;
case 4:sprintf( gtext,
GetStringRes (IDS_STEP),
pInfo->iStep);
break;
case 5:
(gFloat ? sprintf( gtext, GetStringRes (IDS_FLOATING_PT))
: sprintf( gtext, GetStringRes (IDS_FIXED_PT))) ;
break;

default: break;
}
SetWindowText(hTextWnd, gtext);
bReleaseInfoData(hwnd);
return 0L;
}

case WM_SYSCOMMAND: {
LONG lResult;

EnumChildWindows(ghwndClient, (WNDENUMPROC)lpfnSuspendThrd, lParam);

lResult = DefMDIChildProc(hwnd, message, wParam, lParam);

EnumChildWindows(ghwndClient, (WNDENUMPROC)lpfnResumeThrd, lParam);

return lResult;
break;
}

case WM_CREATE: {
PINFO pInfo;
HANDLE hInfo;
HWND hTextWnd, hJulia;
RECT rcl;

//
// CR! MakeProcInstance is noop!
//
lpfnSuspendThrd = (FARPROC)MakeProcInstance (SuspendDrawThrd, ghModule);
lpfnResumeThrd = (FARPROC)MakeProcInstance (ResumeDrawThrd, ghModule);

hTextWnd = CreateWindow("Text", NULL,
WS_BORDER | SS_LEFT | WS_CHILD | WS_VISIBLE,
0, 0, 0, 0,
hwnd,
(HMENU) 2,
ghModule,
NULL);

GetClientRect(hwnd, &rcl);
hJulia = CreateWindow("Julia", (LPSTR) NULL,
WS_CHILD | WS_VISIBLE |
WS_BORDER,
0,0, rcl.right-rcl.left,
rcl.bottom-rcl.top-GetWindowLong(hTextWnd, GWL_USERDATA),
hwnd, (HMENU)1, ghModule, (LPVOID)NULL);

SetWindowText(hTextWnd, GetStringRes (IDS_SELECT_DRAW_SET));

hInfo = (HANDLE) ((LPMDICREATESTRUCT) ((LPCREATESTRUCT) lParam)->lpCreateParams)->lParam ;
if (hInfo) {
if ((pInfo = (PINFO)LocalLock(hInfo)) == NULL)
{
OutputDebugString ("Failed in LocalLock, hNode");
break;
}
else
{
HDC hDC;

if (!GetClientRect(hwnd, &pInfo->rcClient))
OutputDebugString ("Failed in GetClientRect!");

pInfo->hTextWnd = hTextWnd;
pInfo->hwnd = hJulia;
hDC = GetDC(hJulia);
pInfo->hHTPal = CreateHalftonePalette(hDC);
ReleaseDC(hJulia, hDC);
#ifdef CYCLETHRD
//
// Creating a signal quit color cycling event
//
if ((pInfo->hQuitEvent = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
OutputDebugString ("Failed in creating Quit Event!");
#endif
SetWindowLong(hwnd, 0, (LONG) hInfo);
LocalUnlock(hInfo);
}
}
else
{
OutputDebugString ("Can't allocate hInfo!");
}

#if 0
//
// Initialize printers here will detect printers availiability
// more often, but kind of overkill.
//
bInitPrinter(hwnd);
#endif
break;
}

case WM_CLOSE: {
SendMessage(GetParent(hwnd), WM_MDISETMENU,
(DWORD) hMenu,
(LONG) hSubMenuOne) ;
DrawMenuBar(GetParent(GetParent(hwnd))) ;
break;
}

case WM_DESTROY: {
PINFO pInfo;
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
break;
}

if (pInfo->hThrd) {
TerminateThread(pInfo->hThrd, (DWORD)0L);
CloseHandle(pInfo->hThrd);
}
if (pInfo->hPrtThrd) {
TerminateThread(pInfo->hPrtThrd, (DWORD)0L);
CloseHandle(pInfo->hPrtThrd);
}
if (pInfo->hCycleThrd) {
TerminateThread(pInfo->hCycleThrd, (DWORD)0L);
CloseHandle(pInfo->hCycleThrd);
}


#ifdef CYCLETHRD
//
// Cleanup color cycling
//
if (!ResetEvent(pInfo->hQuitEvent))
OutputDebugString ("Failed in reseting quit event!");
#endif
if (pInfo->hBmpMono)
DeleteObject(pInfo->hBmpMono);

if (pInfo->hBmpSaved)
DeleteObject(pInfo->hBmpSaved);

if (pInfo->hBrush)
DeleteObject(pInfo->hBrush);

bReleaseInfoData(hwnd);
LocalFree((HANDLE) GetWindowLong(hwnd, 0));
break;
}

default:
return DefMDIChildProc(hwnd, message, wParam, lParam);

} //switch
return DefMDIChildProc(hwnd, message, wParam, lParam);
}

/******************************Public*Routine******************************\
*
* ViewerWndProc
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG APIENTRY ViewerWndProc(
HWND hwnd,
UINT message,
DWORD wParam,
LONG lParam)
{
static FARPROC lpfnSuspendThrd, lpfnResumeThrd;

switch (message) {
case WM_COMMAND: {
PINFO pInfo;
HWND hTextWnd;

switch (LOWORD(wParam)) {
case MM_RLELOAD_DEMO: {
HDC hDC;
char szDirName[256];
char szFile[400];
HWND hViewSurf;

GetCurrentDirectory(256, (LPTSTR) szDirName);

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

if ((hViewSurf = pInfo->hwnd) == NULL)
return 0L;

hTextWnd = pInfo->hTextWnd;
sprintf( gtext,"Loading bitmap(s) into memory");
SetWindowText(hTextWnd, gtext);

hDC = GetDC(hViewSurf);
strcpy(szFile, szDirName);
strcat(szFile, "\\rsc\\julia.rle");

if (bStoreRleFile(hDC, pInfo, szFile)) {
pInfo->RleData.ulFiles++;
PostMessage(ghwndMain, WM_COMMAND, MM_RLEPLAYCONT, 0L);
}

ReleaseDC(hViewSurf, hDC);

bReleaseInfoData(hwnd);
return 0L;

}


case MM_RLELOAD: {
HDC hDC;
OPENFILENAME ofn;
char szDirName[256];
char szFile[256], szFileTitle[256];
static char *szFilter;
RECT rc;
HWND hViewSurf;

szFilter = GetStringRes (IDS_FILE_LIST1);

GetSystemDirectory((LPSTR) szDirName, 256);
strcpy(szFile, "*.bmp\0");
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szFilter;
ofn.lpstrCustomFilter = (LPSTR) NULL;
ofn.nMaxCustFilter = 0L;
ofn.nFilterIndex = 1;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof(szFileTitle);
ofn.lpstrInitialDir = szDirName;
ofn.lpstrTitle = (LPSTR) NULL;
ofn.Flags = 0L;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = "BMP";

if (!GetOpenFileName(&ofn))
return 0L;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

if ((hViewSurf = pInfo->hwnd) == NULL)
return 0L;

hTextWnd = pInfo->hTextWnd;
sprintf( gtext, GetStringRes (IDS_LOADING_BITMAPS));
SetWindowText(hTextWnd, gtext);

GetClientRect(hwnd, &rc);
hDC = GetDC(hViewSurf);
if (bStoreRleFile(hDC, pInfo, szFile))
pInfo->RleData.ulFiles++;
ReleaseDC(hViewSurf, hDC);

bReleaseInfoData(hwnd);
return 0L;

}

case MM_RLESAVE: {
HDC hDC;
OPENFILENAME ofn;
char szDirName[256];
char szFile[256], szFileTitle[256];
static char *szFilter;
HWND hViewSurf;

szFilter = GetStringRes (IDS_FILE_LIST3);

GetSystemDirectory((LPSTR) szDirName, 256);
strcpy(szFile, "*.rle\0");
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szFilter;
ofn.lpstrCustomFilter = (LPSTR) NULL;
ofn.nMaxCustFilter = 0L;
ofn.nFilterIndex = 0L;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof(szFileTitle);
ofn.lpstrInitialDir = szDirName;
ofn.lpstrTitle = GetStringRes(IDS_SAVING_MEMORY_RLE);
ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = (LPSTR)NULL;

if (!GetSaveFileName(&ofn))
return 0L;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

if ((hViewSurf = pInfo->hwnd) == NULL)
return 0L;

hTextWnd = pInfo->hTextWnd;
sprintf( gtext, GetStringRes (IDS_SAVING_LOADED_BMP));
SetWindowText(hTextWnd, gtext);

hDC = GetDC(hViewSurf);
bSaveRleFile(hDC, pInfo, szFile);
ReleaseDC(hViewSurf, hDC);

bReleaseInfoData(hwnd);
return 0L;
}

case MM_CLEAR: {
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

hTextWnd = pInfo->hTextWnd;
sprintf( gtext,GetStringRes (IDS_DISCARD_LOADED_BMP));
SetWindowText(hTextWnd, gtext);

bFreeRleFile(pInfo);

bReleaseInfoData(hwnd);
return 0L;
}

case MM_RLEPLAY: {
HDC hDC;
HWND hViewSurf;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

if ((hViewSurf = pInfo->hwnd) == NULL)
return 0L;

hTextWnd = pInfo->hTextWnd;
sprintf( gtext, GetStringRes (IDS_PLAY_LOADED_BMP));
SetWindowText(hTextWnd, gtext);

hDC = GetDC(hViewSurf);
EnableMenuItem(hViewSubOne, MM_CLEAR, MF_GRAYED);

if (pInfo->hThrd0)
CloseHandle(pInfo->hThrd0);

pInfo->hThrd0 = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)bPlayRle,
pInfo,
STANDARD_RIGHTS_REQUIRED,
&pInfo->dwThreadId );

if (pInfo->hThrd0)
{
if (!SetThreadPriority(pInfo->hThrd0, THREAD_PRIORITY_BELOW_NORMAL))

OutputDebugString ("Can't set Priority!"); 
}

//bPlayRle(hDC, pInfo);
EnableMenuItem(hViewSubOne, MM_CLEAR, MF_ENABLED);
ReleaseDC(hViewSurf, hDC);

bReleaseInfoData(hwnd);
return 0L;
}

case MM_RLEPLAYCONT: {
HWND hViewSurf;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

if ((hViewSurf = pInfo->hwnd) == NULL)
return 0L;

hTextWnd = pInfo->hTextWnd;
sprintf( gtext, GetStringRes (IDS_PLAY_BMP_CONT));
SetWindowText(hTextWnd, gtext);

if (pInfo->bFirstTime)
{
if (!SetEvent(pInfo->hQuitEvent))
{
OutputDebugString ("Can't set Quit Event!");
return 0L;
}

EnableMenuItem(hViewSubOne, MM_CLEAR, MF_GRAYED);

if (pInfo->hThrd)
CloseHandle(pInfo->hThrd);

pInfo->hThrd = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)bPlayRleCont2,
pInfo,
STANDARD_RIGHTS_REQUIRED,
&pInfo->dwThreadId );

if (pInfo->hThrd) {
if (!SetThreadPriority(pInfo->hThrd, THREAD_PRIORITY_BELOW_NORMAL))
OutputDebugString ("Can't set Priority!");
}

pInfo->bPlayRleCont = TRUE;
pInfo->bFirstTime = FALSE;
CheckMenuItem(hViewMenu, MM_RLEPLAYCONT, MF_CHECKED);
}
else
{
if (pInfo->bPlayRleCont) {
EnableMenuItem(hViewSubOne, MM_CLEAR, MF_ENABLED);
CheckMenuItem(hViewMenu, MM_RLEPLAYCONT, MF_UNCHECKED);
pInfo->bPlayRleCont = FALSE;
pInfo->dwSuspend = SuspendThread(pInfo->hThrd);
} else {
EnableMenuItem(hViewSubOne, MM_CLEAR, MF_GRAYED);
CheckMenuItem(hViewMenu, MM_RLEPLAYCONT, MF_CHECKED);
pInfo->bPlayRleCont = TRUE;
pInfo->dwSuspend = ResumeThread(pInfo->hThrd);
}
if (pInfo->dwSuspend == -1) {
(pInfo->bPlayRleCont ?
sprintf( gtext,"Error in resuming thread\n") :
sprintf( gtext,"Error in suspending thread\n") );
OutputDebugString( gtext );
}
}

bReleaseInfoData(hwnd);
return 0L;
}

default:
return 0L;

} //switch

} // WM_COMMAND
case WM_SETFOCUS:
break;

case WM_MDIACTIVATE: {
PINFO pInfo;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

if ((HWND) lParam == hwnd) {
SendMessage(GetParent(hwnd), WM_MDISETMENU,
(WPARAM) hViewMenu,
(LPARAM) NULL) ;
DrawMenuBar(GetParent(GetParent(hwnd))) ;
}

bReleaseInfoData(hwnd);
return 0L;
}
case WM_QUERYNEWPALETTE:
case WM_PALETTECHANGED: {
PINFO pInfo;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

SendMessage(pInfo->hwnd, message, wParam, lParam);
bReleaseInfoData(hwnd);
return 0L;
}

case WM_SIZE: {
PINFO pInfo;
HWND hTextWnd, hView;
WORD wCx;
int iCyText;

if ((pInfo = pGetInfoData(hwnd)) == NULL) {
break;
}

hTextWnd = pInfo->hTextWnd;
hView = pInfo->hwnd;
bReleaseInfoData(hwnd);
iCyText = GetWindowLong(hTextWnd, GWL_USERDATA);
wCx = (WORD) (HIWORD(lParam) - iCyText);

MoveWindow(hView, 0, 0,
LOWORD(lParam),
wCx,
TRUE);

MoveWindow(hTextWnd,
0,
wCx,
LOWORD(lParam),
iCyText,
TRUE);

break;
}

//
// display info in the status window
//
case WM_USER+0xa: {
PINFO pInfo;
static ULONG ulClick = 0;
HWND hTextWnd;

ulClick++;
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 0L;
}

hTextWnd = pInfo->hTextWnd;
switch (ulClick % 4) {
case 0:
sprintf( gtext, GetStringRes (IDS_FRAMES));
break;
case 1:
sprintf( gtext, GetStringRes (IDS_FRAMES));
break;
case 2: sprintf( gtext, (pInfo->bPlayRleCont ?
GetStringRes (IDS_CONT_PLAY) :
GetStringRes (IDS_SINGLE_PLAY)));
break;
case 3: sprintf( gtext,"");
break;
default: break;
}
SetWindowText(hTextWnd, gtext);
bReleaseInfoData(hwnd);
return 0L;
}

case WM_SYSCOMMAND: {
LONG lResult;

EnumChildWindows(ghwndClient, (WNDENUMPROC)lpfnSuspendThrd, lParam);

lResult = DefMDIChildProc(hwnd, message, wParam, lParam);

EnumChildWindows(ghwndClient, (WNDENUMPROC)lpfnResumeThrd, lParam);

return lResult;
break;
}

case WM_CREATE: {
PINFO pInfo;
HANDLE hInfo;
HWND hTextWnd, hView;
RECT rcl;

//
// CR! MakeProcInstance is noop!
//
lpfnSuspendThrd = (FARPROC)MakeProcInstance (SuspendDrawThrd, ghModule);
lpfnResumeThrd = (FARPROC)MakeProcInstance (ResumeDrawThrd, ghModule);

hTextWnd = CreateWindow("Text", NULL,
WS_BORDER | SS_LEFT | WS_CHILD | WS_VISIBLE,
0, 0, 0, 0,
hwnd,
(HMENU) 2,
ghModule,
NULL);

GetClientRect(hwnd, &rcl);
hView = CreateWindow("View", (LPSTR) NULL,
WS_CHILD | WS_VISIBLE |
WS_BORDER,
0,0, rcl.right-rcl.left,
rcl.bottom-rcl.top-GetWindowLong(hTextWnd, GWL_USERDATA),
hwnd, (HMENU)1, ghModule, (LPVOID)NULL);

SetWindowText(hTextWnd, GetStringRes (IDS_SELECT_DRAW_SET));
hInfo = (HANDLE) ((LPMDICREATESTRUCT) ((LPCREATESTRUCT) lParam)->lpCreateParams)->lParam ;
if (hInfo) {
if ((pInfo = (PINFO)LocalLock(hInfo)) == NULL)
{
OutputDebugString ("Failed in LocalLock, hNode");
break;
}
else
{
HDC hDC;

if (!GetClientRect(hwnd, &pInfo->rcClient))
OutputDebugString ("Failed in GetClientRect!");

pInfo->hTextWnd = hTextWnd;
pInfo->hwnd = hView;

hDC = GetDC(hView);
pInfo->hHTPal = CreateHalftonePalette(hDC);
ReleaseDC(hView, hDC);

//
// Creating a signal quit play continuous event
//
if ((pInfo->hQuitEvent = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
OutputDebugString ("Failed in creating Quit Event!");

SetWindowLong(hwnd, 0, (LONG) hInfo);
LocalUnlock(hInfo);
}
}
else
{
OutputDebugString ("Can't allocate hInfo!");
}

break;
}

case WM_CLOSE: {
SendMessage(GetParent(hwnd), WM_MDISETMENU,
(DWORD) hMenu,
(LONG) hSubMenuOne) ;
DrawMenuBar(GetParent(GetParent(hwnd))) ;
break;
}

case WM_DESTROY: {
PINFO pInfo;
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
break;
}

TerminateThread(pInfo->hThrd, (DWORD)0L);
CloseHandle(pInfo->hThrd);

//
// Cleanup continuous play
//
if (!ResetEvent(pInfo->hQuitEvent))
OutputDebugString ("Failed in reseting quit event!");

bFreeRleFile(pInfo);
bReleaseInfoData(hwnd);
LocalFree((HANDLE) GetWindowLong(hwnd, 0));
break;
}

default:
return DefMDIChildProc(hwnd, message, wParam, lParam);

} //switch
return DefMDIChildProc(hwnd, message, wParam, lParam);
}

/******************************Public*Routine******************************\
*
* ViewSurfWndProc
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

LONG APIENTRY ViewSurfWndProc (HWND hwnd, UINT message, DWORD wParam, LONG lParam)
{
switch (message)
{
case WM_CREATE: {
break;
}

case WM_DESTROY: {
break;
}

case WM_QUERYNEWPALETTE: {
HWND hParent;
PINFO pInfo;
HDC hDC;
UINT i;
HPALETTE hOldPal;

if ((hParent=GetParent(hwnd)) == NULL)
{
OutputDebugString ("Can't get hParent!");
return 0L;
}
if ((pInfo = pGetInfoData(hParent)) == NULL) {
return 0L;
}

// If palette realization causes a palette change,
// we need to do a full redraw.

hDC = GetDC (hwnd);

hOldPal = SelectPalette (hDC,
pInfo->RleData.hPal,
0);

i = RealizePalette(hDC);

SelectPalette (hDC, hOldPal, 0);
ReleaseDC (hwnd, hDC);
bReleaseInfoData(hParent);

if (i) {
InvalidateRect (hwnd, (LPRECT) (NULL), TRUE);
return TRUE;
} else
return FALSE;

}
case WM_PALETTECHANGED: {
HWND hParent;
PINFO pInfo;
HDC hDC;
UINT i;
HPALETTE hOldPal;

if ((hParent=GetParent(hwnd)) == NULL) {
MessageBox(ghwndMain, "Can't get hParent!", "Error", MB_OK);
return 0L;
}
if ((pInfo = pGetInfoData(hParent)) == NULL) {
return 0L;
}

// if we were not responsible for palette change and if
// palette realization causes a palette change, do a redraw.

if ((HWND)wParam != hwnd){
hDC = GetDC (hwnd);

hOldPal = SelectPalette (hDC,
pInfo->RleData.hPal,
0);

i = RealizePalette (hDC);

if (i){
UpdateColors (hDC);
}
SelectPalette (hDC, hOldPal, 0);
ReleaseDC (hwnd, hDC);
}
bReleaseInfoData(hParent);
break;
}

case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC;
RECT rc;

GetClientRect(hwnd,&rc);
hDC = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0L;
}

} // switch
return DefWindowProc(hwnd, message, wParam, lParam);
}

/***************************************************************************\
* About
*
* About dialog proc.
*
\***************************************************************************/

BOOL CALLBACK About(
HWND hDlg,
UINT message,
DWORD wParam,
LONG lParam)
{
switch (message) {
case WM_INITDIALOG:
return TRUE;

case WM_COMMAND:
if (wParam == IDOK)
EndDialog(hDlg, wParam);
break;
}

return FALSE;

UNREFERENCED_PARAMETER(lParam);
UNREFERENCED_PARAMETER(hDlg);
}

/*************************************************************************
*
* TextWndProc
*
* Text Window proc.
*
\***************************************************************************/

LONG APIENTRY TextWndProc (HWND hwnd, UINT message, DWORD wParam, LONG lParam)
{
static HFONT hFont = (HFONT) NULL;

switch (message)
{
case WM_CREATE:
{
LOGFONT lf;
HDC hDC;
HFONT hOldFont;
TEXTMETRIC tm;
RECT rect;
LONG lHeight;

SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), (PVOID) &lf, FALSE);

hDC = GetDC(hwnd);
// this is the height for 8 point size font in pixels
lf.lfHeight = 8 * GetDeviceCaps(hDC, LOGPIXELSY) / 72;

hFont = CreateFontIndirect(&lf);
hOldFont = SelectObject(hDC, hFont);
GetTextMetrics(hDC, &tm);
GetClientRect(GetParent(hwnd), &rect);

// base the height of the window on size of text
lHeight = tm.tmHeight+6*GetSystemMetrics(SM_CYBORDER)+2;
// saved the height for later reference
SetWindowLong(hwnd, GWL_USERDATA, lHeight);
SetWindowPos(hwnd, NULL,
0,
rect.bottom-lHeight,
rect.right-rect.left,
lHeight,
SWP_NOZORDER | SWP_NOMOVE);

ReleaseDC(hwnd, hDC);
break;
}

case WM_LBUTTONDOWN: {
PostMessage(GetParent(hwnd), WM_USER+0xa, (DWORD)0L, (LONG)0L);
break;
}

case WM_DESTROY:
if (hFont)
DeleteObject(hFont);
break;

case WM_SETTEXT:
DefWindowProc(hwnd, message, wParam, lParam);
InvalidateRect(hwnd,NULL,TRUE);
UpdateWindow(hwnd);
return 0L;

case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
char ach[128];
int len, nxBorder, nyBorder;
HFONT hOldFont = NULL;

BeginPaint(hwnd, &ps);

GetClientRect(hwnd,&rc);

nxBorder = GetSystemMetrics(SM_CXBORDER);
rc.left += 9*nxBorder;
rc.right -= 9*nxBorder;

nyBorder = GetSystemMetrics(SM_CYBORDER);
rc.top += 3*nyBorder;
rc.bottom -= 3*nyBorder;

// 3D Text
len = GetWindowText(hwnd, ach, sizeof(ach));
SetBkColor(ps.hdc, GetSysColor(COLOR_BTNFACE));

SetBkMode(ps.hdc, TRANSPARENT);
SetTextColor(ps.hdc, RGB(64,96,96));
if (hFont)
hOldFont = SelectObject(ps.hdc, hFont);
ExtTextOut(ps.hdc, rc.left+2*nxBorder+2, rc.top+2, ETO_OPAQUE | ETO_CLIPPED,
&rc, ach, len, NULL);

SetTextColor(ps.hdc, RGB(128,128,128));
if (hFont)
hOldFont = SelectObject(ps.hdc, hFont);
ExtTextOut(ps.hdc, rc.left+2*nxBorder+1, rc.top+1, ETO_CLIPPED,
&rc, ach, len, NULL);

SetTextColor(ps.hdc, RGB(255,255,255));
if (hFont)
hOldFont = SelectObject(ps.hdc, hFont);
ExtTextOut(ps.hdc, rc.left+2*nxBorder, rc.top, ETO_CLIPPED,
&rc, ach, len, NULL);

SetBkMode(ps.hdc, OPAQUE);

if (hOldFont)
SelectObject(ps.hdc, hOldFont);

EndPaint(hwnd, &ps);
return 0L;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}


/**************************************************************************\
*
* JuliaWndProc
*
\**************************************************************************/

LONG APIENTRY JuliaWndProc (HWND hwnd, UINT message, DWORD wParam, LONG lParam)
{
//
// These statics are shared by all the Julia windows. But, this is
// fine because only one Julia window is tracking at any one time.
// Ideally, we should place this in the per-window INFO data structure.
// But, this is not necessary.
//
static BOOL bTrack = FALSE;
static int OrgX, OrgY;
static int PrevX, PrevY;
static HDC hDC;
static HCURSOR hCurArrow, hCurPaintCan;

switch (message)
{
case WM_CREATE: {

hpnRed = CreatePen(PS_SOLID, 0, RGB(0xFF, 0, 0));
hpnGreen = CreatePen(PS_SOLID, 0, RGB(0, 0xFF, 0));
hpnBlack = CreatePen(PS_SOLID, 0, RGB(0, 0, 0));

hCurPaintCan = LoadCursor(ghModule, MAKEINTRESOURCE(PAINTCURSOR));
hCurArrow = LoadCursor(NULL, IDC_ARROW);
break;
}

case WM_DESTROY: {
HWND hParent;
PINFO pInfo;

DeleteObject(hpnRed);
DeleteObject(hpnGreen);
DeleteObject(hpnBlack);

if ((hParent=GetParent(hwnd)) == NULL)
{
OutputDebugString ("Can't get hParent!");
break;
}
if ((pInfo = pGetInfoData(hParent)) == NULL) {
break;
}

// we might have open resource if we ever load bitmap in this wnd.
bFreeRleFile(pInfo);
bReleaseInfoData(hParent);
break;
}

case WM_QUERYNEWPALETTE: {
HWND hParent;
PINFO pInfo;
HDC hDC;
UINT i;
HPALETTE hOldPal;

if ((hParent=GetParent(hwnd)) == NULL)
{
OutputDebugString ("Can't get hParent!");
return 0L;
}
if ((pInfo = pGetInfoData(hParent)) == NULL) {
return 0L;
}

// If palette realization causes a palette change,
// we need to do a full redraw.

hDC = GetDC (hwnd);

hOldPal = SelectPalette (hDC,
((pInfo->iStretchMode == HALFTONE) ? pInfo->hHTPal : pInfo->hPal),
0);

i = RealizePalette(hDC);
SelectPalette (hDC, hOldPal, 0);
ReleaseDC (hwnd, hDC);
bReleaseInfoData(hParent);

if (i) {
InvalidateRect (hwnd, (LPRECT) (NULL), TRUE);
return TRUE;
} else
return FALSE;

}
case WM_PALETTECHANGED: {
HWND hParent;
PINFO pInfo;
HDC hDC;
UINT i;
HPALETTE hOldPal;

if ((hParent=GetParent(hwnd)) == NULL) {
OutputDebugString ("Can't get hParent!");
return 0L;
}
if ((pInfo = pGetInfoData(hParent)) == NULL) {
return 0L;
}

// if we were not responsible for palette change and if
// palette realization causes a palette change, do a redraw.

if ((HWND)wParam != hwnd){
hDC = GetDC (hwnd);

hOldPal = SelectPalette (hDC,
((pInfo->iStretchMode == HALFTONE) ? pInfo->hHTPal : pInfo->hPal),
0);

i = RealizePalette (hDC);

if (i){
UpdateColors (hDC);
}
SelectPalette (hDC, hOldPal, 0);
ReleaseDC (hwnd, hDC);
}
bReleaseInfoData(hParent);
break;
}

case WM_PAINT:
{
PAINTSTRUCT ps;
HWND hParent;
PINFO pInfo;
HDC hDC;
RECT rc;

GetClientRect(hwnd,&rc);
hDC = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
if ((hParent=GetParent(hwnd)) == NULL) {
OutputDebugString ("Can't get hParent!");
return 0L;
}
if ((pInfo = pGetInfoData(hParent)) == NULL) {
return 0L;
}

if (pInfo->hBmpSaved) {
hDC = GetDC(hwnd);
bDrawDIB(hDC, pInfo, 0, 0, rc.right, rc.bottom);
ReleaseDC(hwnd, hDC);
}
bReleaseInfoData(hParent);

//EndPaint(hwnd, &ps);
return 0L;
}

case WM_RBUTTONDOWN: {
RECT rc;
HANDLE hParent;
PINFO pInfo;
int x, y;
HWND hJulia;
HANDLE hTextWnd;

x = (int) LOWORD(lParam);
y = (int) HIWORD(lParam);
if ((hParent=GetParent(hwnd)) == NULL) {
OutputDebugString ("Can't get hParent!");
break;
}

if ((pInfo = pGetInfoData(hParent)) == NULL) {
break;
}

hTextWnd = pInfo->hTextWnd;

if (GetWindowLong(GetParent(hwnd), GWL_STYLE) & WS_MAXIMIZE) {
GetClientRect(ghwndMain, &rc);
rc.bottom -= GetWindowLong(hTextWnd,GWL_USERDATA);
} else {
GetClientRect(hwnd, &rc);
}

if (pInfo->bMandel) {

hJulia = (HWND) SendMessage(ghwndMain, WM_COMMAND,
(DWORD)((WORD)MM_JULIA), 0L);
if (hJulia) {
//GetClientRect(hwnd, &rc);
//
// calculate the c value corresponding to the point
//
c1 = Xform((double) x, 0.0, (double) rc.right, pInfo->xFrom, pInfo->xTo);
c2 = Xform((double) y, 0.0, (double) rc.bottom, pInfo->yFrom, pInfo->yTo);
lc1 = XformFix(x, 0, rc.right, pInfo->lxFrom, pInfo->lxTo);
lc2 = XformFix(y, 0, rc.bottom, pInfo->lyFrom, pInfo->lyTo);

sprintf( gtext,"(c1 = %g, c2 = %g)\n", c1, c2);
OutputDebugString( gtext );

//
// Reset globals to default values for creating Julia set
// (Entire set, not zoom in)
//
bResetGlobal();
PostMessage(hJulia, WM_COMMAND, (DWORD)((WORD) MM_SET_XFORM_ATTR), 0L);
} else {
OutputDebugString ("Can't create hJulia!");
}
}
bReleaseInfoData(hParent);
break;
}
case WM_LBUTTONDOWN: {
HANDLE hParent;
PINFO pInfo;
int x, y;
DWORD dwRGB;
HBRUSH hBrOld;

x = (int) LOWORD(lParam);
y = (int) HIWORD(lParam);
if ((hParent=GetParent(hwnd)) == NULL) {
OutputDebugString ("Can't get hParent!");
break;
}

if ((pInfo = pGetInfoData(hParent)) == NULL) {
break;
}

if (pInfo->bFill) {
hDC = GetDC(hwnd);
hBrOld = SelectObject(hDC, pInfo->hBrush);

dwRGB = GetPixel(hDC, x, y);

ExtFloodFill(hDC, x, y, (COLORREF)dwRGB, FLOODFILLSURFACE);
SelectObject(hDC, hBrOld);
ReleaseDC(hwnd, hDC);
pInfo->bFill = FALSE;

if (pInfo->hBmpSaved)
DeleteObject(pInfo->hBmpSaved);

pInfo->hBmpSaved = SaveBitmap(hwnd, pInfo->hPal);
pInfo->bUseDIB = FALSE;


SetCursor(hCurArrow);
} else {
bTrack = TRUE;
OrgX = PrevX = x = LOWORD(lParam);
OrgY = PrevY = y = HIWORD(lParam);

hDC = GetDC(hwnd);
SetCapture(hwnd);
}
bReleaseInfoData(hParent);
break;
}
case WM_MOUSEMOVE: {
RECT rectClient;
int NextX;
int NextY;
HANDLE hParent;
PINFO pInfo;

if ((hParent=GetParent(hwnd)) == NULL) {
OutputDebugString ("Can't get hParent!");
break;
}

if ((pInfo = pGetInfoData(hParent)) == NULL) {
break;
}

if (pInfo->bFill) {
SetCursor(hCurPaintCan);
} else {
SetCursor(hCurArrow);
}

bReleaseInfoData(hParent);

// Update the selection region
if (bTrack) {
NextX = (SHORT) LOWORD(lParam);
NextY = (SHORT) HIWORD(lParam);

// Do not draw outside the window's client area

GetClientRect (hwnd, &rectClient);
if (NextX < rectClient.left) {
NextX = rectClient.left;
} else if (NextX >= rectClient.right) {
NextX = rectClient.right - 1;
}
if (NextY < rectClient.top) {
NextY = rectClient.top;
} else if (NextY >= rectClient.bottom) {
NextY = rectClient.bottom - 1;
}
if ((NextX != PrevX) || (NextY != PrevY)) {
SetROP2(hDC, R2_NOT); // Erases the previous box

MoveToEx(hDC, OrgX, OrgY, NULL);
LineTo(hDC, OrgX, PrevY);
LineTo(hDC, PrevX, PrevY);
LineTo(hDC, PrevX, OrgY);
LineTo(hDC, OrgX, OrgY);
// Get the current mouse position

PrevX = NextX;
PrevY = NextY;
MoveToEx(hDC, OrgX, OrgY, NULL); // Draws the new box
LineTo(hDC, OrgX, PrevY);
LineTo(hDC, PrevX, PrevY);
LineTo(hDC, PrevX, OrgY);
LineTo(hDC, OrgX, OrgY);
}
}
break;

}

case WM_LBUTTONUP: {
RECT rc;
HANDLE hParent;
PINFO pInfo;
int NextX;
int NextY;
int iDistX, iDistY, iAbsDstX, iAbsDstY;
HWND hZoom;
HANDLE hTextWnd;

if (!bTrack)
break;

// End the selection
ReleaseCapture();
bTrack = FALSE;

MoveToEx(hDC, OrgX, OrgY, NULL); // Erases the box
LineTo(hDC, OrgX, PrevY);
LineTo(hDC, PrevX, PrevY);
LineTo(hDC, PrevX, OrgY);
LineTo(hDC, OrgX, OrgY);

NextX = LOWORD(lParam);
NextY = HIWORD(lParam);

iDistX = NextX - OrgX;
iDistY = NextY - OrgY;
iAbsDstX = (iDistX > 0 ? iDistX : -iDistX);
iAbsDstY = (iDistY > 0 ? iDistY : -iDistY);
if (iAbsDstX > iAbsDstY) {
NextY = OrgY + (iDistY > 0 ? iAbsDstX : -iAbsDstX);
} else if (iAbsDstX < iAbsDstY) {
NextX = OrgX + (iDistX > 0 ? iAbsDstY : -iAbsDstY);
}

MoveToEx(hDC, OrgX, OrgY, NULL); // Draws the new box
LineTo(hDC, OrgX, NextY);
LineTo(hDC, NextX, NextY);
LineTo(hDC, NextX, OrgY);
LineTo(hDC, OrgX, OrgY);

SetROP2(hDC, R2_COPYPEN);

ReleaseDC(hwnd, hDC);
if ((hParent=GetParent(hwnd)) == NULL) {
OutputDebugString ("Can't get hParent!");
break;
}

if ((pInfo = pGetInfoData(hParent)) == NULL) {
break;
}

hTextWnd = pInfo->hTextWnd;
sprintf(gtext, GetStringRes (IDS_MOUSE), OrgX, OrgY, NextX, NextY);

//SetWindowText(hTextWnd, gtext);
OutputDebugString(gtext);


if (GetWindowLong(GetParent(hwnd), GWL_STYLE) & WS_MAXIMIZE) {

GetClientRect(ghwndMain, &rc);
rc.bottom -= GetWindowLong(hTextWnd,GWL_USERDATA);
sprintf(gtext, "(%d, %d), (%d, %d)\n", rc.left, rc.top, rc.right, rc.bottom);
//SetWindowText(hTextWnd, gtext);
OutputDebugString(gtext);

} else {
GetClientRect(hwnd, &rc);
}

if ((OrgX == NextX) && (OrgY == NextY)) {
bReleaseInfoData(hParent);
break;
}

hZoom = (HWND) SendMessage(ghwndMain, WM_COMMAND,
pInfo->bMandel ? (DWORD)((WORD)MM_MANDEL) : (DWORD)((WORD)MM_JULIA),
0L);
if (hZoom) {
//GetClientRect(hwnd, &rc);
xFrom = Xform((double) OrgX, 0.0, (double) rc.right, pInfo->xFrom, pInfo->xTo);
xTo = Xform((double) NextX, 0.0, (double) rc.right, pInfo->xFrom, pInfo->xTo);
yFrom = Xform((double) OrgY, 0.0, (double) rc.bottom, pInfo->yFrom, pInfo->yTo);
yTo = Xform((double) NextY, 0.0, (double) rc.bottom, pInfo->yFrom, pInfo->yTo);
lxFrom = XformFix(OrgX, 0, rc.right, pInfo->lxFrom, pInfo->lxTo);
lxTo = XformFix(NextX, 0, rc.right, pInfo->lxFrom, pInfo->lxTo);
lyFrom = XformFix(OrgY, 0, rc.bottom, pInfo->lyFrom, pInfo->lyTo);
lyTo = XformFix(NextY, 0, rc.bottom, pInfo->lyFrom, pInfo->lyTo);
if (!pInfo->bMandel) {
c1 = pInfo->c1;
c2 = pInfo->c2;
lc1 = pInfo->lc1;
lc2 = pInfo->lc2;
}
PostMessage(hZoom, WM_COMMAND, (DWORD)((WORD) MM_SET_XFORM_ATTR), 0L);
} else {
OutputDebugString ("Can't create hZoom!");
}
bReleaseInfoData(hParent);
break;
} // case WM_LBUTTONUP
} // switch
return DefWindowProc(hwnd, message, wParam, lParam);
}


/******************************Public*Routine******************************\
*
* SuspendDrawThrd
*
* Effects: Enumerates all the MDI children. Suspending the drawing thread
* in those windows, if any.
*
* Warnings: assumes the MDI children has class name "ChildClass."
*
\**************************************************************************/


BOOL APIENTRY SuspendDrawThrd (HWND hwnd, LONG lParam) {
HANDLE hThrd;
PINFO pInfo;
DWORD dwSuspend;
BOOL bDrawing;
char sz[30];

GetClassName(hwnd, sz, 15);
if (strcmp(sz, "ChildClass") != 0)
return 1L;
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 1L;
}

bDrawing = pInfo->bDrawing;
hThrd = pInfo->hThrd;
bReleaseInfoData(hwnd);

if (hThrd && bDrawing) {
dwSuspend = SuspendThread(hThrd);
sprintf( gtext,"\nSuspend: dwSuspend = %d, dwSuspend = %g\n", dwSuspend, dwSuspend);
OutputDebugString( gtext );

if (dwSuspend == -1) {
sprintf( gtext,"Error in suspending thread\n");
OutputDebugString( gtext );
}
}
return 1L;
UNREFERENCED_PARAMETER(lParam);
}


/******************************Public*Routine******************************\
*
* ResumeDrawThrd
*
* Effects: Enumerates all the MDI children. Resuming the drawing thread
* in those windows, if any.
*
* Warnings: Assumes the MDI children has class name "ChildClass." Also,
* assumes the drawing has been suspended by SuspendDrawThrd.
*
\**************************************************************************/


BOOL APIENTRY ResumeDrawThrd (HWND hwnd, LONG lParam) {
HANDLE hThrd;
PINFO pInfo;
DWORD dwSuspend;
BOOL bDrawing;
char sz[30];

GetClassName(hwnd, sz, 15);
if (strcmp(sz, "ChildClass") != 0)
return 1L;
if ((pInfo = pGetInfoData(hwnd)) == NULL) {
return 1L;
}

bDrawing = pInfo->bDrawing;
hThrd = pInfo->hThrd;
bReleaseInfoData(hwnd);

if (hThrd && bDrawing) {
dwSuspend = ResumeThread(hThrd);
sprintf( gtext,"Resume: dwSuspend = %d, dwSuspend = %g\n", dwSuspend, dwSuspend);
OutputDebugString( gtext );

if (dwSuspend == -1) {
sprintf( gtext,"Error in resuming thread\n");
OutputDebugString( gtext );
}
}
return 1L;
UNREFERENCED_PARAMETER(lParam);
}


/******************************Public*Routine******************************\
*
* lMul
*
* Effects: Fix point multiplication
*
* Warnings: 9.23 fix point representation used. This is only good for
* multiplication in a limited range. Will overflow.
* CR! Will be implemented as macros in the future
*
\**************************************************************************/

LONG lMul(LONG l1, LONG l2)
{
LONGLONG lliTmp;
LONG lReturn;

lliTmp = l1;
lliTmp *= l2;
lReturn = (LONG)(lliTmp >> 23);

return(lReturn);
}

/******************************Public*Routine******************************\
*
* lDiv
*
* Effects: fix point division
*
* Warnings: 9.23 fix point representation used. This is only good for
* division in a limited range. Will overflow.
* CR! Will be implemented as macros in the future
*
\**************************************************************************/

LONG lDiv(long l1, long l2)
{
LONGLONG lliTmp;
LONG lReturn;



lliTmp = (LONGLONG)l1;
lliTmp <<= 23;

lReturn = (LONG)(lliTmp / (LONGLONG)l2);

return (lReturn); 
}


/**************************************************************************\
*
* StartDrawFix
* 2
* Effects: Draw'g the Julia Set for Q (z) = z + c, where z, c are complex
* c
* Fact: |Q (0)| = |c| > 2, the orbit of 0 escapes immediately
* c
* claim: |z| >= |c| = 2 + l, l > 0 escapes under Q
* c
* The Julia Set: Basin Boundaries algorithm.
*
* Warnings:
*
\**************************************************************************/
BOOL StartDrawFix(PINFO pInfo)
{
DWORD dwTick1;
HDC hDC;
RECT rc;

int m, n, i, iPrev;
int xCurr, yCurr;
int iPen;

LONG c1, c2;
LONG x0, y0, x1, y1, x, y, z;

int iBand=1;
int iScan=0;
int iDiff=0;

#ifndef THRDONE
INT iNumClr;
#endif

HDC hDCMem;
HBITMAP hBitmap, hOldBitmap;

iPen = pInfo->iPen + 1;
iPrev = FIRST_PIXEL; // a big value to signal the first pixel
//iPrev = pInfo->iIteration + FIRST_PIXEL;
c1 = pInfo->lc1;
c2 = pInfo->lc2;

pInfo->bMandel = FALSE;
pInfo->bDrawing = TRUE;
hDC = GetDC(pInfo->hwnd);

#ifndef THRDONE
if ((iNumClr = iCreatePenFrPal(hDC, NULL, 0, &(pInfo->hPal))) != 0) {
sprintf( gtext,"iNumClr = %d\n", iNumClr);
OutputDebugString( gtext);

if ((pInfo->prghPen = (PVOID*) GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(HPEN)*iNumClr)) == NULL) {
OutputDebugString ("Failed in Memory Allocation for pInfo->prghPen!");
} else {
if ((pInfo->iPen = iCreatePenFrPal(hDC, pInfo->prghPen, 0, &(pInfo->hPal))) == 0)
OutputDebugString ("Failed in creating pen!");
}
}

hDCMem = CreateCompatibleDC(hDC);

SelectPalette(hDCMem, pInfo->hPal, FALSE);
SelectPalette(hDC, pInfo->hPal, FALSE);
RealizePalette(hDC);
iPen = pInfo->iPen + 1;
#endif

GetClientRect(pInfo->hwnd, &rc);
hBitmap = CreateCompatibleBitmap(hDC, (int)rc.right, (int)rc.bottom);
hOldBitmap = SelectObject(hDCMem, hBitmap);
yCurr = rc.top;

dwTick1 = GetTickCount();
iScan = (((iScan = BATCH / rc.right) == 0) ? 1 : iScan);

for (n=rc.top; n<=rc.bottom; n+=pInfo->iStep, yCurr+=pInfo->iStep, iPrev = FIRST_PIXEL) {
xCurr = rc.left; // since LineTo excludes last point
MoveToEx(hDCMem, 0, yCurr, NULL);
y0 = XformFix(n, rc.top, rc.bottom, pInfo->lyFrom, pInfo->lyTo);

for (m=rc.left; m<=rc.right; m++, xCurr++) {
x0 = XformFix(m, rc.left, rc.right, pInfo->lxFrom, pInfo->lxTo);
x = x0;
y = y0;

for (i=1; i<=pInfo->iIteration; i++) {
x1 = lMul(x - y, x + y) + c1; // Z = x1 + i x2

y1 = (lMul(x, y) * 2) + c2;
x = x1;
y = y1; // 2 2 2 1/2 2
z = lMul(x, x) + lMul(y, y); // |Z| = ((x1 + x2 ) ) > 2

if (z > 33554432)
break;
}

if (i != iPrev)
{
if (iPrev != FIRST_PIXEL)
{
switch(iPrev)
{
case 1:
if (pInfo->prghPen)
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[0]);
break;
default:

if (iPrev >= pInfo->iIteration)
{
SelectObject(hDCMem, hpnBlack);
break;
}
if (pInfo->prghPen)
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[iPrev % iPen]);
break;
}
iPrev = i;
LineTo(hDCMem,xCurr,yCurr);
}
else
iPrev = i; // remember the color for the first pixel
}
}
switch(i) {
case 1:
if (pInfo->prghPen)
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[0]);
break;
default:
if (iPrev >= pInfo->iIteration) {
SelectObject(hDCMem, hpnBlack);
break;
}
if (pInfo->prghPen)
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[i % iPen]);
break;
}

LineTo(hDCMem,xCurr,yCurr);

sprintf(gtext, GetStringRes (IDS_DRAWING), ((FLOAT)n/(FLOAT)rc.bottom)*100);

SetWindowText(pInfo->hTextWnd, gtext);

if (n >= iScan * iBand) {
BitBlt(hDC, 0, iScan * (iBand-1), rc.right, iScan, hDCMem, 0, iScan * (iBand-1), SRCCOPY);
iBand++;
}
}

if ((iDiff = iScan * iBand - rc.bottom) != 0) {
BitBlt(hDC, 0, iScan * (iBand-1), rc.right, iScan-iDiff, hDCMem, 0, iScan * (iBand-1), SRCCOPY);
}

sprintf(gtext, GetStringRes (IDS_DRAWING_DONE));

SetWindowText(pInfo->hTextWnd, gtext);

ReleaseDC(pInfo->hwnd, hDC);

pInfo->dwElapsed = GetTickCount() - dwTick1;

if (pInfo->hBmpSaved)
DeleteObject(pInfo->hBmpSaved);

pInfo->hBmpSaved = SelectObject(hDCMem, hOldBitmap);
pInfo->bDrawing = FALSE;
#ifndef THRDONE
if (pInfo->prghPen != NULL) {
for (i = 0; i <= pInfo->iPen; i++) {
DeleteObject((HPEN) (pInfo->prghPen)[i]);
}
GlobalFree(pInfo->prghPen);
}
#endif
DeleteDC(hDCMem);
ExitThread(0);
return TRUE;
}

/**************************************************************************\
*
* StartDraw
* 2
* Effects: Draw'g the Julia Set for Q (z) = z + c, where z, c are complex
* c
* Fact: |Q (0)| = |c| > 2, the orbit of 0 escapes immediately
* c
* claim: |z| >= |c| = 2 + l, l > 0 escapes under Q
* c
* The Julia Set: Basin Boundaries algorithm.
*
* Warnings:
*
\**************************************************************************/
BOOL StartDraw(PINFO pInfo)
{
DWORD dwTick1;
HDC hDC;
RECT rc;

int m, n, i, iPrev;
int xCurr, yCurr;
int iPen;

double c1, c2;
double x0, y0, x1, y1, x, y, z;

int iBand=1;
int iScan=0;
int iDiff=0;


HDC hDCMem;
HBITMAP hBitmap, hOldBitmap;

#ifndef THRDONE
INT iNumClr;
#endif

iPen = pInfo->iPen + 1;
iPrev = FIRST_PIXEL; // a big value to signal the first pixel
//iPrev = pInfo->iIteration + FIRST_PIXEL;
c1 = pInfo->c1;
c2 = pInfo->c2;

pInfo->bMandel = FALSE;
pInfo->bDrawing = TRUE;
hDC = GetDC(pInfo->hwnd);

#ifndef THRDONE
if ((iNumClr = iCreatePenFrPal(hDC, NULL, 0, &(pInfo->hPal))) != 0) {
sprintf( gtext,"iNumClr = %d\n", iNumClr);
OutputDebugString( gtext);

if ((pInfo->prghPen = (PVOID*) GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(HPEN)*iNumClr)) == NULL) {
OutputDebugString ("Failed in Memory Allocation for pInfo->prghPen!");
} else {
if ((pInfo->iPen = iCreatePenFrPal(hDC, pInfo->prghPen, 0, &(pInfo->hPal))) == 0)
OutputDebugString ("Failed in creating pen!");
}
}

hDCMem = CreateCompatibleDC(hDC);

SelectPalette(hDCMem, pInfo->hPal, FALSE);
SelectPalette(hDC, pInfo->hPal, FALSE);
RealizePalette(hDC);
iPen = pInfo->iPen + 1;
#endif

GetClientRect(pInfo->hwnd, &rc);
hBitmap = CreateCompatibleBitmap(hDC, (int)rc.right, (int)rc.bottom);
hOldBitmap = SelectObject(hDCMem, hBitmap);
yCurr = rc.top;

dwTick1 = GetTickCount();

iScan = (((iScan = BATCH / rc.right) == 0) ? 1 : iScan);

for (n=rc.top; n<=rc.bottom; n+=pInfo->iStep, yCurr+=pInfo->iStep, iPrev = FIRST_PIXEL) {
xCurr = rc.left; // since LineTo excludes last point
MoveToEx(hDCMem, 0, yCurr, NULL);
y0 = Xform((double) n, 0.0, (double) rc.bottom, pInfo->yFrom, pInfo->yTo);

for (m=rc.left; m<=rc.right; m++, xCurr++) {
x0 = Xform((double) m, 0.0, (double) rc.right, pInfo->xFrom, pInfo->xTo);
x = x0;
y = y0;

for (i=1; i<=pInfo->iIteration; i++) {
x1 = (x - y) * (x + y) + c1; // Z = x1 + i x2

y1 = 2 * x * y + c2;
x = x1;
y = y1; // 2 2 2 1/2 2
z = x * x + y * y; // |Z| = ((x1 + x2 ) ) > 2

if (z > 4.0)
break;
}

if (i != iPrev)
{
if (iPrev != FIRST_PIXEL)
{
switch(iPrev)
{
case 1:
if (pInfo->prghPen)
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[0]);
break;
default:

if (iPrev >= pInfo->iIteration) {
SelectObject(hDCMem, hpnBlack);
break;
}
if(pInfo->prghPen)
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[iPrev % iPen]);
break;
}
iPrev = i;
LineTo(hDCMem,xCurr,yCurr);
}
else
iPrev = i; // remember the color for the first pixel
}
}
switch(i) {
case 1:
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[0]);
break;
default:
if (iPrev >= pInfo->iIteration) {
SelectObject(hDCMem, hpnBlack);
break;
}
if (pInfo->prghPen)
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[i % iPen]);
break;
}

LineTo(hDCMem,xCurr,yCurr);

sprintf(gtext, GetStringRes (IDS_DRAWING), ((FLOAT)n/(FLOAT)rc.bottom)*100);
SetWindowText(pInfo->hTextWnd, gtext);

if (n >= iScan * iBand) {
BitBlt(hDC, 0, iScan * (iBand-1), rc.right, iScan, hDCMem, 0, iScan * (iBand-1), SRCCOPY);
iBand++;
}
}

if ((iDiff = iScan * iBand - rc.bottom) != 0) {
BitBlt(hDC, 0, iScan * (iBand-1), rc.right, iScan-iDiff, hDCMem, 0, iScan * (iBand-1), SRCCOPY);
}

sprintf(gtext, GetStringRes(IDS_DRAWING_DONE));

SetWindowText(pInfo->hTextWnd, gtext);

ReleaseDC(pInfo->hwnd, hDC);

pInfo->dwElapsed = GetTickCount() - dwTick1;

if (pInfo->hBmpSaved)
DeleteObject(pInfo->hBmpSaved);

pInfo->hBmpSaved = SelectObject(hDCMem, hOldBitmap);
pInfo->bDrawing = FALSE;
#ifndef THRDONE
if (pInfo->prghPen != NULL) {
for (i = 0; i <= pInfo->iPen; i++) {
DeleteObject((HPEN) (pInfo->prghPen)[i]);
}
GlobalFree(pInfo->prghPen);
}
#endif
DeleteDC(hDCMem);

ExitThread(0);
return TRUE;
}

/**************************************************************************\
*
* StartDraw2
* 2
* Effects: Draw'g the Julia Set for Q (z) = z + c, where z, c are complex
*
* The Julia Set: Backward iteration algorithm.
*
* Warnings:
*
\**************************************************************************/

BOOL StartDraw2(PINFO pInfo)
{
HDC hDC;
RECT rc;
int m, n, i;
double c1, c2;
double x0, y0, w0, w1, pi, theta, r;

pi = 22.0/7.0;
c1 = 0.360284;
c2 = 0.100376;
x0 = 1.5;
y0 = 1.5;

hDC = GetDC(pInfo->hwnd);

GetClientRect(pInfo->hwnd, &rc);
for (i=0; i<=15000; i++) {
w0 = x0 - c1;
w1 = y0 - c2;
sprintf( gtext,"w(%g, %g) xy(%g, %g)\n", w0, w1, x0, y0);
OutputDebugString( gtext );

if (w0 == 0.0) {
theta = pi/2;
sprintf( gtext,"(w0 == 0.0) theta = %g\n\n", theta);
OutputDebugString( gtext );

} else {
if (w0 > 0.0) {
theta = atan(w1/w0);
sprintf( gtext,"(w0 > 0.0) theta = %g\n\n", theta);
OutputDebugString( gtext );

} else { // w0 < 0.0
theta = pi + atan(w1/w0);
sprintf( gtext,"(w0 < 0.0) theta = %g\n\n", theta);
OutputDebugString( gtext );
}
}
r = sqrt(w0 * w0 + w1 + w1);
//theta = theta/2.0 + ((int) ((2.0*rand()/(RAND_MAX+1.0)))*pi);
//theta = theta/2.0 + ((2.0*rand()/((double)RAND_MAX+1.0))*pi);
r = sqrt(r);
x0 = r*cos(theta);
y0 = r*sin(theta);
if (i > 50) {
m = Xform2(x0, pInfo->xFrom, pInfo->xTo, 0.0, (double) rc.right);
n = Xform2(y0, pInfo->yFrom, pInfo->yTo, 0.0, (double) rc.bottom);
SetPixel(hDC, m, n, 0x000000ff);
}
}

ReleaseDC(pInfo->hwnd, hDC);

ExitThread(0);
return TRUE;
}

/**************************************************************************\
*
* StartMandelbrotFix
* 2
* Effects: Draw'g the Mandelbrot Set for Q (z) = z + c, where z, c complex
*
* Warnings:
\**************************************************************************/
BOOL StartMandelbrotFix(PINFO pInfo)
{
DWORD dwTick1;
HDC hDC;
RECT rc;
int m, n, i, iPrev;
int xCurr, yCurr;
int iPen;

LONG c1, c2;
LONG x1, y1, x, y, r;
#ifndef THRDONE
INT iNumClr;
#endif

HDC hDCMem;
HBITMAP hBitmap, hOldBitmap;

int iBand=1;
int iScan=0;
int iDiff=0;

iPen = pInfo->iPen + 1;
pInfo->bMandel = TRUE;
pInfo->bDrawing = TRUE;
hDC = GetDC(pInfo->hwnd);

#ifndef THRDONE
if ((iNumClr = iCreatePenFrPal(hDC, NULL, 0, &(pInfo->hPal))) != 0) {
sprintf( gtext,"iNumClr = %d\n", iNumClr);
OutputDebugString( gtext);

if ((pInfo->prghPen = (PVOID*) GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(HPEN)*iNumClr)) == NULL) {
OutputDebugString ("Failed in Memory Allocation for pInfo->prghPen!");
} else {
if ((pInfo->iPen = iCreatePenFrPal(hDC, pInfo->prghPen, 0, &(pInfo->hPal))) == 0)
OutputDebugString ("Failed in creating pen!");
}
}

hDCMem = CreateCompatibleDC(hDC);

SelectPalette(hDCMem, pInfo->hPal, FALSE);
SelectPalette(hDC, pInfo->hPal, FALSE);
RealizePalette(hDC);
iPen = pInfo->iPen + 1;
#endif

GetClientRect(pInfo->hwnd, &rc);

hBitmap = CreateCompatibleBitmap(hDC, (int)rc.right, (int)rc.bottom);
hOldBitmap = SelectObject(hDCMem, hBitmap);

dwTick1 = GetTickCount();
yCurr = rc.top;

iScan = (((iScan = BATCH / rc.right) == 0) ? 1 : iScan);

for (n=rc.top; n<=rc.bottom; n+=pInfo->iStep, yCurr+=pInfo->iStep, iPrev = FIRST_PIXEL) {
xCurr = rc.left; // since LineTo excludes last point
MoveToEx(hDCMem, 0, yCurr, NULL);
c2 = XformFix(n, rc.top, rc.bottom, pInfo->lyFrom, pInfo->lyTo);

for (m=rc.left; m<=rc.right; m++, xCurr++) {
c1 = XformFix(m, rc.left, rc.right, pInfo->lxFrom, pInfo->lxTo);
x = c1;
y = c2;

for (i=1; i<=pInfo->iIteration; i++) {
x1 = lMul(x - y, x + y) + c1;
y1 = (lMul(x, y) * 2) + c2;
r = lMul(x1, x1) + lMul(y1, y1);
x = x1;
y = y1;
if (r > 33554432) {
break;
}
}

if (i != iPrev) {
if (iPrev != FIRST_PIXEL) {
switch(iPrev) {
case 1:
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[0]); break;
default:
if (iPrev >= pInfo->iIteration) {
SelectObject(hDCMem, hpnBlack);
break;
}
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[iPrev % iPen]);
break;
}
iPrev = i;
LineTo(hDCMem, xCurr, yCurr);
}
else
iPrev = i; // remember the color for the first pixel
}
}

switch(i) {
case 1:
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[0]);
break;
default:
if (i >= pInfo->iIteration) {
SelectObject(hDCMem, hpnBlack);
break;
}
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[i % iPen]);
break;
}
LineTo(hDCMem,xCurr,yCurr);

sprintf(gtext, GetStringRes (IDS_DRAWING), ((FLOAT)n/(FLOAT)rc.bottom)*100);

SetWindowText(pInfo->hTextWnd, gtext);

if (n >= iScan * iBand) {
BitBlt(hDC, 0, iScan * (iBand-1), rc.right, iScan, hDCMem, 0, iScan * (iBand-1), SRCCOPY);
iBand++;
}

}

if ((iDiff = iScan * iBand - rc.bottom) != 0) {
BitBlt(hDC, 0, iScan * (iBand-1), rc.right, iScan-iDiff, hDCMem, 0, iScan * (iBand-1), SRCCOPY);
}

sprintf(gtext, GetStringRes (IDS_DRAWING_DONE));

SetWindowText(pInfo->hTextWnd, gtext);

ReleaseDC(pInfo->hwnd, hDC);

pInfo->dwElapsed = GetTickCount() - dwTick1;

if (pInfo->hBmpSaved)
DeleteObject(pInfo->hBmpSaved);

pInfo->hBmpSaved = SelectObject(hDCMem, hOldBitmap);
pInfo->bDrawing = FALSE;

#ifndef THRDONE
if (pInfo->prghPen != NULL) {
for (i = 0; i <= pInfo->iPen; i++) {
DeleteObject((HPEN) (pInfo->prghPen)[i]);
}
GlobalFree(pInfo->prghPen);
}
#endif

DeleteDC(hDCMem);

ExitThread(0);
return TRUE;
}

/**************************************************************************\
*
* StartMandelbrot
* 2
* Effects: Draw'g the Mandelbrot Set for Q (z) = z + c, where z, c complex
*
* Warnings:
*
\**************************************************************************/
BOOL StartMandelbrot(PINFO pInfo)
{
DWORD dwTick1;
HDC hDC;
RECT rc;
int m, n, i, iPrev;
int xCurr, yCurr;
int iPen;

#ifndef THRDONE
INT iNumClr;
char text[256];
#endif

double c1, c2;
double x1, y1, x, y, r;

HDC hDCMem;
HBITMAP hBitmap, hOldBitmap;

int iBand=1;
int iScan=0;
int iDiff=0;

iPrev = 0;
iPen = pInfo->iPen + 1;
pInfo->bMandel = TRUE;
pInfo->bDrawing = TRUE;
hDC = GetDC(pInfo->hwnd);

#ifndef THRDONE
if ((iNumClr = iCreatePenFrPal(hDC, NULL, 0, &(pInfo->hPal))) != 0) {
sprintf( gtext,"iNumClr = %d\n", iNumClr);
OutputDebugString( gtext);

if ((pInfo->prghPen = (PVOID*) GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(HPEN)*iNumClr)) == NULL) {
OutputDebugString ("Failed in Memory Allocation for pInfo->prghPen!");
} else {
if ((pInfo->iPen = iCreatePenFrPal(hDC, pInfo->prghPen, 1, &(pInfo->hPal))) == 0)
OutputDebugString ("Failed in creating pen!");
}
}

hDCMem = CreateCompatibleDC(hDC);

SelectPalette(hDCMem, pInfo->hPal, FALSE);
SelectPalette(hDC, pInfo->hPal, FALSE);
RealizePalette(hDC);
iPen = pInfo->iPen + 1;
wsprintf(text, "iPen = %d\n", iPen);
//MessageBox(ghwndMain, text, "Error", MB_OK);
#endif

GetClientRect(pInfo->hwnd, &rc);

hBitmap = CreateCompatibleBitmap(hDC, (int)rc.right, (int)rc.bottom);
hOldBitmap = SelectObject(hDCMem, hBitmap);

#if 0
{
int iWidth, i, j;

iWidth = rc.right/iNumClr;

for (i = 0; i < iNumClr; i++) {
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[i % iNumClr]);
for (j = 0; j < iWidth; j++) {
MoveToEx(hDCMem, i*iWidth+j, 0, NULL);
LineTo(hDCMem, i*iWidth+j, rc.bottom);
}

}
}
#endif

dwTick1 = GetTickCount();

iScan = (((iScan = BATCH / rc.right) == 0) ? 1 : iScan);

yCurr = rc.top;
for (n=rc.top; n<=rc.bottom; n+=pInfo->iStep, yCurr+=pInfo->iStep, iPrev = FIRST_PIXEL) {
xCurr = rc.left; // since LineTo excludes last point
MoveToEx(hDCMem, 0, yCurr, NULL);
c2 = Xform((double) n, 0.0, (double) rc.bottom, pInfo->yFrom, pInfo->yTo);

for (m=rc.left; m<=rc.right; m++, xCurr++) {
c1 = Xform((double) m, 0.0, (double) rc.right, pInfo->xFrom, pInfo->xTo);
x = c1;
y = c2;

for (i=1; i<=pInfo->iIteration; i++) {
x1 = (x - y) * (x + y) + c1;
y1 = 2 * x * y + c2;
r = x1 * x1 + y1 * y1;
x = x1;
y = y1;
if (r > 4.0) {
break;
}
}

if (i != iPrev) {
if (iPrev != FIRST_PIXEL) {
switch(iPrev) {
case 1:
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[0]);
break;
default:
if (iPrev >= pInfo->iIteration) {
SelectObject(hDCMem, hpnBlack);
break;
}
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[iPrev % iPen]);
break;
}
iPrev = i;
LineTo(hDCMem, xCurr, yCurr);
}
else
iPrev = i; // remember the color for the first pixel
}
}

switch(i) {
case 1:
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[0]);
break;
default:
if (i >= pInfo->iIteration) {
SelectObject(hDCMem, hpnBlack);
break;
}
SelectObject(hDCMem, (HPEN)(pInfo->prghPen)[i % iPen]);
break;
}

LineTo(hDCMem,xCurr,yCurr);

sprintf(gtext, GetStringRes (IDS_DRAWING), ((FLOAT)n/(FLOAT)rc.bottom)*100);

SetWindowText(pInfo->hTextWnd, gtext);

if (n >= iScan * iBand) {
BitBlt(hDC, 0, iScan * (iBand-1), rc.right, iScan, hDCMem, 0, iScan * (iBand-1), SRCCOPY);
iBand++;
}
}

if ((iDiff = iScan * iBand - rc.bottom) != 0) {
BitBlt(hDC, 0, iScan * (iBand-1), rc.right, iScan-iDiff, hDCMem, 0, iScan * (iBand-1), SRCCOPY);
}

sprintf(gtext, GetStringRes (IDS_DRAWING_DONE));

SetWindowText(pInfo->hTextWnd, gtext);

ReleaseDC(pInfo->hwnd, hDC);

pInfo->dwElapsed = GetTickCount() - dwTick1;

if (pInfo->hBmpSaved)
DeleteObject(pInfo->hBmpSaved);

pInfo->hBmpSaved = SelectObject(hDCMem, hOldBitmap);
pInfo->bDrawing = FALSE;
#ifndef THRDONE
if (pInfo->prghPen != NULL) {
for (i = 0; i <= pInfo->iPen; i++) {
DeleteObject((HPEN) (pInfo->prghPen)[i]);
}
GlobalFree(pInfo->prghPen);
}
#endif

DeleteDC(hDCMem);

ExitThread(0);
return TRUE;
}


/******************************Public*Routine******************************\
*
* Xform
*
* Effects: Given m, find x.
*
* Xform(Pt) : Src |--> Dest
* eg.
* Src |----|--------| |--> Dest |----|--------|
* -2 x 2 0 m 320
*
* x = (m - 0)/(320 - 0) * (2 - -2) + -2
*
* Warnings: 1. This will become a macro in the future for speed. For now,
* it is here for debugging purposes.
*
\**************************************************************************/
#if 0
double Xform(
double Pt,
double SrcFrom,
double SrcTo,
double DestFrom,
double DestTo)
{
//sprintf( gtext,"%g = Xform(%g, %g, %g, %g, %g)\n", ((Pt-SrcFrom)/(SrcTo-SrcFrom)*(DestTo-DestFrom))+DestFrom, Pt, SrcFrom, SrcTo, DestFrom, DestTo);
//OutputDebugString( gtext );
return(((Pt-SrcFrom)/(SrcTo-SrcFrom)*(DestTo-DestFrom))+DestFrom);
}
#endif

/******************************Public*Routine******************************\
*
* Xform2
*
* Effects: Given x, find m.
*
* Xform(Pt) : Src |--> Dest
* eg.
* Src |----|--------| |--> Dest |----|--------|
* -2 x 2 0 m 320
*
* m = (x - -2)/(2 - -2) * 320
*
* Warnings: 1. This will become a macro in the future for speed. For now,
* it is here for debugging purposes.
*
\**************************************************************************/
#if 0
int Xform2(
double Pt,
double SrcFrom,
double SrcTo,
double DestFrom,
double DestTo)
{
//sprintf( gtext,"%g = Xform(%g, %g, %g, %g, %g)\n", ((Pt-SrcFrom)/(SrcTo-SrcFrom)*(DestTo-DestFrom))+DestFrom, Pt, SrcFrom, SrcTo, DestFrom, DestTo);
//OutputDebugString( gtext );
return((int) ((Pt-SrcFrom)/(SrcTo-SrcFrom)*(DestTo-DestFrom)+DestFrom));
}
#endif

/******************************Public*Routine******************************\
*
* SaveBitmap
*
* Effects: Returns the handle of a bitmap corresponding to the window.
* using utilizing BitBlt.
*
* Warnings:
* // should we set the dirty flag here?
*
*
\**************************************************************************/

HBITMAP SaveBitmap(HWND hWnd, HPALETTE hPal) {
HDC hdcMem, hDC;
HBITMAP hBitmap, hOldBitmap;
RECT rc;
HPALETTE hPalOld, hPalMemOld;
int ii;

hDC = GetDC(hWnd);
GetClientRect(hWnd, &rc);

if (hPal) {

hPalOld = SelectPalette(hDC, hPal, FALSE);
ii=RealizePalette(hDC);
if (ii){
UpdateColors (hDC);
}

}

hdcMem = CreateCompatibleDC(hDC);

if (hPal) {

hPalMemOld = SelectPalette(hdcMem, hPal, FALSE);
RealizePalette(hdcMem);
}

hBitmap = CreateCompatibleBitmap(hDC, (int)rc.right-rc.left, (int)rc.bottom-rc.top);

hOldBitmap = SelectObject(hdcMem, hBitmap);


BitBlt(hdcMem, 0, 0, (int)rc.right-rc.left, (int)rc.bottom-rc.top, hDC, 0, 0, SRCCOPY);
hBitmap = SelectObject(hdcMem, hOldBitmap);

DeleteDC(hdcMem);
ReleaseDC(hWnd, hDC);

return(hBitmap);

}

/******************************Public*Routine******************************\
*
* DrawBitmap
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

void DrawBitmap(HDC hdc, PINFO pInfo, int xStart, int yStart, int cx, int cy) {
BITMAP bm;
HDC hdcMem;
POINT ptSize, ptOrg;
HPALETTE hPalOld, hPalMemOld;
char text[128];

if ((pInfo->hPal) && !(pInfo->bUseMono)) {

hPalOld = SelectPalette(hdc,
((pInfo->iStretchMode == HALFTONE) ? pInfo->hHTPal : pInfo->hPal),
FALSE);
//RealizePalette(hdc);

wsprintf(text, "Realized Palette = %d", RealizePalette(hdc));

OutputDebugString (text);


UpdateColors (hdc);
}

hdcMem = CreateCompatibleDC(hdc);

if ((pInfo->hPal) && !(pInfo->bUseMono)) {

hPalMemOld = SelectPalette(hdcMem,
((pInfo->iStretchMode == HALFTONE) ? pInfo->hHTPal : pInfo->hPal),
FALSE);
//RealizePalette(hdcMem);
wsprintf(text, "Realized Palette = %d", RealizePalette(hdcMem));
OutputDebugString (text);


UpdateColors (hdcMem);



}

SelectObject(hdcMem, (pInfo->bUseMono ? pInfo->hBmpMono : pInfo->hBmpSaved));
SetMapMode(hdcMem, GetMapMode(hdc));

GetObject((pInfo->bUseMono ? pInfo->hBmpMono : pInfo->hBmpSaved), sizeof(BITMAP), (LPSTR)&bm);
ptSize.x = bm.bmWidth;
ptSize.y = bm.bmHeight;
DPtoLP(hdc, &ptSize, 1);

ptOrg.x = 0;
ptOrg.y = 0;
DPtoLP(hdcMem, &ptOrg, 1);

if (pInfo->bStretch) {
SetStretchBltMode(hdc, pInfo->iStretchMode);
// cx+1 and cy+1: temporary work around for a bug!
StretchBlt(hdc, xStart, yStart, cx+1, cy+1,
hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y,SRCCOPY);
} else {
BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y,
hdcMem, xStart, yStart, SRCCOPY);
}

if (pInfo->bUseMono)
pInfo->bUseMono = FALSE;

DeleteDC(hdcMem);
UNREFERENCED_PARAMETER(cx);
UNREFERENCED_PARAMETER(cy);
}

/******************************Public*Routine******************************\
*
* bDrawDIB
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

BOOL bDrawDIB(HDC hDC, PINFO pInfo, int xStart, int yStart, int cx, int cy)
{
HBITMAP hBmpOld, hBmp;
BOOL bSuccess;
PBITMAPINFO pbmi;
HDC hdcMem;
BITMAP bm;

bSuccess = TRUE;
if (pInfo->bUseMono) {
DrawBitmap(hDC, pInfo, xStart, yStart, cx, cy);
return bSuccess;
}

if ((hBmp = pInfo->hBmpSaved) == NULL) {

MessageBox(ghwndMain, GetStringRes (IDS_NO_BITMAP_TO_DRAW),
NULL, MB_OK);
return FALSE;
}

if (pInfo->bStretch) {
SetStretchBltMode(hDC, pInfo->iStretchMode);

if (pInfo->bUseDIB) { // this'll give a src for halftone...
pbmi = (PBITMAPINFO) (pInfo->RleData.rgpbmi[0]);

// Select and realize the appropriate palette to destination DC
if ((pInfo->iStretchMode == HALFTONE) && (pInfo->hHTPal)) {
SelectPalette(hDC, pInfo->hHTPal, FALSE);
RealizePalette(hDC);
} else {
if ((pInfo->iStretchMode != HALFTONE) && (pInfo->hPal)) {
SelectPalette(hDC, pInfo->hPal, FALSE);
RealizePalette(hDC);
}
}
if (pInfo->bCoreHdr) {
StretchDIBits(hDC, xStart, yStart, cx, cy,
0, 0, ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcWidth,
((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcHeight,
(LPSTR)pInfo->RleData.rgpjFrame[0], pbmi, DIB_RGB_COLORS, SRCCOPY);
} else {
StretchDIBits(hDC, xStart, yStart, cx, cy,
0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight,
(LPSTR)pInfo->RleData.rgpjFrame[0], pbmi, DIB_RGB_COLORS, SRCCOPY);
}
} else { // image is dirty or created on this device

HBITMAP hDIB;

//
// Get the source DIB info from the DDB for halftoning

// 
hDIB = DIBfromDDB(hDC, hBmp, pInfo);

hdcMem = CreateCompatibleDC(hDC);
hBmpOld = SelectObject(hdcMem, hDIB);

if ((pInfo->iStretchMode == HALFTONE) && (pInfo->hHTPal)) {
SelectPalette(hDC, pInfo->hHTPal, FALSE);
RealizePalette(hDC);
} else {
if ((pInfo->iStretchMode != HALFTONE) && (pInfo->hPal)) {
SelectPalette(hDC, pInfo->hPal, FALSE);
RealizePalette(hDC);
}
}

//
// Use StretchBlt here instead of StretchDIBits just for
// demonstrating using the API with halftone
//
GetObject(hDIB, sizeof(BITMAP), (LPSTR)&bm);
StretchBlt(hDC, xStart, yStart, cx, cy, hdcMem,
0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);

DeleteDC(hdcMem);

}
return bSuccess;
}

//
// Not stretching...No halftone
//

GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bm);

// Select and realize the appropriate palette to destination DC
if (pInfo->hPal) {
SelectPalette(hDC, pInfo->hPal, FALSE);
RealizePalette(hDC);
}

if (pInfo->bUseDIB) { // this'll give a src
pbmi = (PBITMAPINFO) (pInfo->RleData.rgpbmi[0]);

// default to use SetDIBitsToDevice
SetDIBitsToDevice(hDC, xStart, yStart, bm.bmWidth, bm.bmHeight,
0, 0, 0, bm.bmHeight, pInfo->RleData.rgpjFrame[0],
pbmi, DIB_RGB_COLORS);
} else { // image is dirty or created on this device

hdcMem = CreateCompatibleDC(hDC);
hBmpOld = SelectObject(hdcMem, hBmp);

BitBlt(hDC, xStart, yStart, bm.bmWidth, bm.bmHeight,
hdcMem, 0, 0, SRCCOPY);

DeleteDC(hdcMem);
}

return bSuccess;
}

/******************************Public*Routine******************************\
*
* pGetInfoData(HWND hwnd)
*
* Effects: calls LocalLock, returning pointer to Info structure.
* assumes hwnd contains handle to Info structure at index 0.
* should call bReleaseInfoData when done.
* Global alert: ghwndMain used.
*
* Warnings:
*
\**************************************************************************/

PINFO pGetInfoData(HWND hwnd)
{
HANDLE hInfo;
PINFO pInfo;

hInfo = (HANDLE) GetWindowLong(hwnd, 0);
if (hInfo == NULL) {
OutputDebugString ("Null Info handle retrieved - GetInfo");
return NULL;
}

if ((pInfo = (PINFO)LocalLock(hInfo)) == NULL) {
return NULL;
}

return pInfo;
}

/******************************Public*Routine******************************\
*
* bReleaseInfoData(HWND hwnd)
*
* Effects: calls LocalUnlock. Returns whatever LocalUnlock returns.
*
* Warnings: assumes LocalLock was called previously.
* assumes hwnd contains handle to Info structure at index 0.
* Global alert: ghwndMain used.
*
\**************************************************************************/

BOOL bReleaseInfoData(HWND hwnd)
{
HANDLE hInfo;

hInfo = (HANDLE) GetWindowLong(hwnd, 0);
if (hInfo == NULL) {
OutputDebugString ("Null Info handle retrieved - ReleaseInfo");
return FALSE;
}

return (LocalUnlock(hInfo));
}


/******************************Public*Routine******************************\
*
* bCheckMutexMenuItem
*
* Effects: Put a check mark on uiCheckItem in the hMenu. Remove previous
* check mark, if any, on items in the same group. Returns TRUE
* if successful, FALSE otherwise (item not exists).
*
* Warnings:
*
\**************************************************************************/

BOOL bCheckMutexMenuItem(PINFO pInfo, HMENU hMenu, UINT uiCheckItem)
{

switch(uiCheckItem) {
case MM_TP_IDLE:
case MM_TP_LOW:
case MM_TP_BELOW_NORMAL:
case MM_TP_NORMAL:
case MM_TP_ABOVE_NORMAL:
case MM_TP_HIGH:
case MM_TP_TIME_CRITICAL:
switch (pInfo->iPriority) {
case THREAD_PRIORITY_IDLE:
CheckMenuItem(hMenu, MM_TP_IDLE, MF_UNCHECKED);
break;
case THREAD_PRIORITY_LOWEST:
CheckMenuItem(hMenu, MM_TP_LOW, MF_UNCHECKED);
break;
case THREAD_PRIORITY_BELOW_NORMAL:
CheckMenuItem(hMenu, MM_TP_BELOW_NORMAL, MF_UNCHECKED);
break;
case THREAD_PRIORITY_NORMAL:
CheckMenuItem(hMenu, MM_TP_NORMAL, MF_UNCHECKED);
break;
case THREAD_PRIORITY_ABOVE_NORMAL:
CheckMenuItem(hMenu, MM_TP_ABOVE_NORMAL, MF_UNCHECKED);
break;
case THREAD_PRIORITY_HIGHEST:
CheckMenuItem(hMenu, MM_TP_HIGH, MF_UNCHECKED);
break;
case THREAD_PRIORITY_TIME_CRITICAL:
CheckMenuItem(hMenu, MM_TP_TIME_CRITICAL, MF_UNCHECKED);
break;
default:
break;
}
break;
case MM_FLOAT:
case MM_FIX:
CheckMenuItem(hMenu, MM_FLOAT, MF_UNCHECKED);
CheckMenuItem(hMenu, MM_FIX, MF_UNCHECKED);
break;
case MM_ITERATION_100:
case MM_ITERATION_500:
case MM_ITERATION_1000:
case MM_ITERATION_5000:
case MM_ITERATION_DOUBLE:
switch (pInfo->iIteration) {
case 100:
CheckMenuItem(hMenu, MM_ITERATION_100, MF_UNCHECKED);
break;
case 500:
CheckMenuItem(hMenu, MM_ITERATION_500, MF_UNCHECKED);
break;
case 1000:
CheckMenuItem(hMenu, MM_ITERATION_1000, MF_UNCHECKED);
break;
case 5000:
CheckMenuItem(hMenu, MM_ITERATION_5000, MF_UNCHECKED);
break;
default:
CheckMenuItem(hMenu, MM_ITERATION_DOUBLE, MF_UNCHECKED);
break;
}
break;
case MM_STEP_ONE:
case MM_STEP_TWO:
case MM_STEP_THREE:
switch (pInfo->iStep) {
case 1:
CheckMenuItem(hMenu, MM_STEP_ONE, MF_UNCHECKED);
break;
case 2:
CheckMenuItem(hMenu, MM_STEP_TWO, MF_UNCHECKED);
break;
default:
CheckMenuItem(hMenu, MM_STEP_THREE, MF_UNCHECKED);
break;
}
break;
case MM_STRETCHBLT:
case MM_BITBLT:
CheckMenuItem(hMenu, MM_STRETCHBLT, MF_UNCHECKED);
CheckMenuItem(hMenu, MM_BITBLT, MF_UNCHECKED);
break;
case MM_BLACKONWHITE:
case MM_COLORONCOLOR:
case MM_WHITEONBLACK:
case MM_HALFTONE:
switch (pInfo->iStretchMode) {
case BLACKONWHITE:
CheckMenuItem(hMenu, MM_BLACKONWHITE, MF_UNCHECKED);
break;
case COLORONCOLOR:
CheckMenuItem(hMenu, MM_COLORONCOLOR, MF_UNCHECKED);
break;
case WHITEONBLACK:
CheckMenuItem(hMenu, MM_WHITEONBLACK, MF_UNCHECKED);
break;
case HALFTONE:
CheckMenuItem(hMenu, MM_HALFTONE, MF_UNCHECKED);
break;
default:
break;
}
break;
case MM_PORTRAIT:
case MM_LANDSCAPE:
CheckMenuItem(hMenu, MM_PORTRAIT, MF_UNCHECKED);
CheckMenuItem(hMenu, MM_LANDSCAPE, MF_UNCHECKED);
break;
default:
return FALSE;
}
CheckMenuItem(hMenu, uiCheckItem, MF_CHECKED);
return TRUE;
}


/******************************Public*Routine******************************\
*
* vChkMenuItem
*
* Effects: Helper function for checking or unchecking menu items based on
* values set in the pInfo. Gets called when processing
* WM_MDIACTIVATE
*
* Warnings:
*
\**************************************************************************/

VOID vChkMenuItem(PINFO pInfo, HMENU hMenu, UINT uiFlag)
{
(pInfo->bStretch ?
CheckMenuItem(hMenu, MM_STRETCHBLT, uiFlag) :
CheckMenuItem(hMenu, MM_BITBLT, uiFlag) );

switch (pInfo->iPriority) {
case THREAD_PRIORITY_IDLE:
CheckMenuItem(hMenu, MM_TP_IDLE, uiFlag);
break;
case THREAD_PRIORITY_LOWEST:
CheckMenuItem(hMenu, MM_TP_LOW, uiFlag);
break;
case THREAD_PRIORITY_BELOW_NORMAL:
CheckMenuItem(hMenu, MM_TP_BELOW_NORMAL, uiFlag);
break;
case THREAD_PRIORITY_NORMAL:
CheckMenuItem(hMenu, MM_TP_NORMAL, uiFlag);
break;
case THREAD_PRIORITY_ABOVE_NORMAL:
CheckMenuItem(hMenu, MM_TP_ABOVE_NORMAL, uiFlag);
break;
case THREAD_PRIORITY_HIGHEST:
CheckMenuItem(hMenu, MM_TP_HIGH, uiFlag);
break;
case THREAD_PRIORITY_TIME_CRITICAL:
CheckMenuItem(hMenu, MM_TP_TIME_CRITICAL, uiFlag);
break;
default:
break;
}

switch (pInfo->iStretchMode) {
case BLACKONWHITE:
CheckMenuItem(hMenu, MM_BLACKONWHITE, uiFlag);
break;
case COLORONCOLOR:
CheckMenuItem(hMenu, MM_COLORONCOLOR, uiFlag);
break;
case WHITEONBLACK:
CheckMenuItem(hMenu, MM_WHITEONBLACK, uiFlag);
break;
case HALFTONE:
CheckMenuItem(hMenu, MM_HALFTONE, uiFlag);
break;
default:
break;
}

switch (pInfo->iStep) {
case 1:
CheckMenuItem(hMenu, MM_STEP_ONE, uiFlag);
break;
case 2:
CheckMenuItem(hMenu, MM_STEP_TWO, uiFlag);
break;
default:
CheckMenuItem(hMenu, MM_STEP_THREE, uiFlag);
break;
}

switch (pInfo->iIteration) {
case 100:
CheckMenuItem(hMenu, MM_ITERATION_100, uiFlag);
break;
case 500:
CheckMenuItem(hMenu, MM_ITERATION_500, uiFlag);
break;
case 1000:
CheckMenuItem(hMenu, MM_ITERATION_1000, uiFlag);
break;
case 5000:
CheckMenuItem(hMenu, MM_ITERATION_5000, uiFlag);
break;
default:
CheckMenuItem(hMenu, MM_ITERATION_DOUBLE, uiFlag);
break;
}
return;
}

/******************************Public*Routine******************************\
*
* bInitInfo
*
* Effects: Initialize the Info data structure
*
* Warnings:
*
\**************************************************************************/

BOOL bInitInfo(PINFO pInfo)
{
pInfo->hParent = ghwndClient;
pInfo->xFrom = -2.0;
pInfo->xTo = 1.0;
pInfo->yFrom = 1.5;
pInfo->yTo = -1.5;
pInfo->lxFrom = -16777216; // 9.23 fix point
pInfo->lxTo = 8388608; // representation of
pInfo->lyFrom = 12582912; // -2, 1.0, 1.5, and -1.5
pInfo->lyTo = -12582912; //
pInfo->iIteration = gIteration;
pInfo->iStep = gStep;
pInfo->bStretch = gbStretch;
pInfo->iStretchMode = giStretchMode;
wsprintf((LPSTR) &(pInfo->CaptionBarText), "");
pInfo->hwnd = NULL;
pInfo->hTextWnd = NULL;
pInfo->rcClient.top = 0;
pInfo->rcClient.left = 0;
pInfo->rcClient.bottom = 0;
pInfo->rcClient.right = 0;
pInfo->hdcClient = NULL;
pInfo->hRgnPath = NULL;
pInfo->hThrd0 = NULL;
pInfo->hThrd = NULL;
pInfo->bDrawing = FALSE;
pInfo->dwThreadId = 0;
pInfo->dwElapsed = 0L;
pInfo->c1 = 0.0;
pInfo->c2 = 0.0;
pInfo->lc1 = 0L;
pInfo->lc2 = 0L;
pInfo->hBmpSaved = NULL;
pInfo->bSizeChng = FALSE;
pInfo->bMandel = TRUE;
pInfo->bSetDIBsToDevice = FALSE;
pInfo->bFill = FALSE;
pInfo->hBrush = NULL;
pInfo->hQuitEvent = NULL;
pInfo->hCycleThrd = NULL;
pInfo->dwCycleThrdID = 0;
pInfo->bClrCycle = FALSE;
pInfo->bFirstTime = TRUE;
pInfo->dwSuspend = 0;
pInfo->hBmpMono = NULL;
pInfo->bUseMono = FALSE;
pInfo->hPrtThrd = NULL;
pInfo->dwPrtThrdID = 0;
pInfo->hPal = NULL;
pInfo->hCyclePal = NULL;
pInfo->RleData.ulFiles = 0;
pInfo->RleData.ulFrames = 0;
pInfo->bPlayRleCont = FALSE;
pInfo->prghPen = NULL;
pInfo->iPen = 0;
pInfo->iPriority = THREAD_PRIORITY_NORMAL;
pInfo->bUseDIB = FALSE;
pInfo->bCoreHdr = FALSE;

return TRUE;
}

/******************************Public*Routine******************************\
*
* bResetGlobal
*
* Effects: Set (l) x/y From/To to their default values
* Used for Julia set
*
* Warnings:
*
\**************************************************************************/

BOOL bResetGlobal(VOID)
{
xFrom = -2.0;
xTo = 2.0;
yFrom = 2.0;
yTo = -2.0;
lxFrom = -16777216;
lxTo = 16777216;
lyFrom = 16777216;
lyTo = -16777216;
return TRUE;
}

/******************************Public*Routine******************************\
*
* hBrCreateBrush
*
* Effects: Creates a brush with the specified RGB
*
* Warnings:
*
\**************************************************************************/

HBRUSH hBrCreateBrush(HDC hDC, DWORD dwRGB)
{
HDC hdcMem;
HBRUSH hbr;
HBRUSH hbrOld;
HBITMAP hbmPat;
HBITMAP hbmOld;

hbr = CreateSolidBrush(dwRGB);
hdcMem = CreateCompatibleDC(hDC);

//
// Minimum size for a bitmap to be used in a fill pattern is 8x8
//
hbmPat = CreateCompatibleBitmap(hDC, 8, 8);

hbmOld = SelectObject(hdcMem, hbmPat);
hbrOld = SelectObject(hdcMem, hbr);
PatBlt(hdcMem, 0, 0, 8, 8, PATCOPY);

//
// Deselect hbmPat and hbr
//
SelectObject(hdcMem, hbmOld);
SelectObject(hdcMem, hbrOld);

DeleteDC(hdcMem);
DeleteObject(hbr);

hbr = CreatePatternBrush(hbmPat);

DeleteObject(hbmPat);

return hbr;
}


/******************************Public*Routine******************************\
*
* bPrintBmp
*
* Effects: A Thread routine for printing bitmap
*
* Warnings:
*
\**************************************************************************/

BOOL bPrintBmp(PPRTDATA pPrtData) {
HDC hdcPrinter;
int iWidth, iHeight;

#ifdef NEWPRTAPI
DOCINFO DocInfo;
#endif

if (pPrtData->bUseDefault) {
hdcPrinter = CreateDC( "", gpszPrinterNames[pPrtData->index],
"", NULL);
} else {
hdcPrinter = CreateDC( "", gpszPrinterNames[pPrtData->index],
"", &(pPrtData->DevMode));
}

if (!hdcPrinter)
{
ExitThread(0);
return(FALSE);
}

iWidth = GetDeviceCaps(hdcPrinter, HORZRES);
iHeight = GetDeviceCaps(hdcPrinter, VERTRES);

#ifdef NEWPRTAPI

memset(&DocInfo, 0, sizeof(DOCINFO));
DocInfo.cbSize = sizeof(DOCINFO);
DocInfo.lpszDocName = pPrtData->info.CaptionBarText;
DocInfo.lpszOutput = NULL;
StartDoc(hdcPrinter, &DocInfo);
StartPage(hdcPrinter);
bDrawDIB(hdcPrinter, &(pPrtData->info), 0, 0, iWidth, iHeight);
EndPage(hdcPrinter);
EndDoc(hdcPrinter);

#else

Escape(hdcPrinter, STARTDOC, 20, "Mandelbrot", NULL);
bDrawDIB(hdcPrinter, &(pPrtData->info), 0, 0, iWidth, iHeight);
Escape(hdcPrinter, NEWFRAME, 0, NULL, NULL);
Escape(hdcPrinter, ENDDOC, 0, NULL, NULL);

#endif

DeleteDC(hdcPrinter);
ExitThread(0);
return(TRUE);

}



/******************************Public*Routine******************************\
*
* StoreRleFile
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

BOOL bStoreRleFile(HDC hDC, PINFO pInfo, PSTR pszFileName)
{
BOOL bSuccess;
HANDLE hFile, hMapFile;
LPVOID pMapFile;
LPBITMAPINFOHEADER pbmh;
LPBITMAPINFO pbmi;
PBYTE pjTmp, pjDIBits, pjRleBits;
ULONG sizBMI, sizImage, ulfSize;
DWORD dwOffBits;
LONG lScan;
INT iNumClr;
ULONG ulFrames, ulFiles, ulOffset;
PFILEINFO pFileInfo;
DWORD dwFileSizeLow, dwFileSizeHigh;
WORD wBitCount;
BOOL bCoreHdr;

bSuccess = TRUE;

if ((hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL)) == (HANDLE)-1) {
bSuccess = FALSE;
goto ErrExit1;
}

dwFileSizeLow = GetFileSize(hFile, &dwFileSizeHigh);
if ((dwFileSizeLow == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) {
bSuccess = FALSE;
goto ErrExit2;
}

//
// Create a map file of the opened file
//
if ((hMapFile = CreateFileMapping(hFile, NULL,
PAGE_READONLY, 0, 0, NULL)) == (HANDLE)-1) {
bSuccess = FALSE;
goto ErrExit2;
}

//
// Map a view of the whole file
//
if ((pMapFile = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0)) == NULL) {
bSuccess = FALSE;
goto ErrExit3;
}

ulFiles = pInfo->RleData.ulFiles;
pFileInfo = &(pInfo->RleData.rgFileInfo[ulFiles]);
pFileInfo->hFile = hFile;
pFileInfo->hMapFile = hMapFile;
pFileInfo->lpvMapView = pMapFile;

ulFrames = pInfo->RleData.ulFrames;
ulOffset = 0;

while (TRUE) {
//
// First check that it is a bitmap file
//
if (*((PWORD)pMapFile) != 0x4d42) { // 'BM'
OutputDebugString ("This is not a DIB bitmap file!");
bSuccess = FALSE;
goto ErrExit3;
}
#ifdef DEBUG
{
static ULONG ulCnt=0;
char buf[128];

ulCnt++;
wsprintf(buf, "ulCnt = %ld", ulCnt);
OutputDebugString (buf);
}
#endif
//
// Saving the bfSize field in the BITMAPFILEHEADER for incrementing to the
// next frame. bfSize does not start at DWORD boundary...
//
{
PBYTE pjTmp;
FILEHDR fHdr, *pfHdr;
ULONG ulSiz;

pjTmp = (PBYTE)pMapFile+2;
pfHdr = &fHdr;

ulSiz = sizeof(FILEHDR);
while (ulSiz--) {
*(((PBYTE)pfHdr)++) = *(((PBYTE)pjTmp)++);
}
ulfSize = fHdr.bfSize;
dwOffBits = fHdr.bfOffbits;
}

//
// advance pMapFile to point pass BITMAPFILEHEADER
//
//pMapFile = (PBYTE)pMapFile + sizeof(BITMAPFILEHEADER);

//
// Since the file header doesn't end on DWORD boundary...
//
pbmh = (LPBITMAPINFOHEADER)((PBYTE)pMapFile + sizeof(BITMAPFILEHEADER));

{
BITMAPCOREHEADER bmch, *pbmch;
BITMAPINFOHEADER bmih, *pbmih;
PBYTE pjTmp;
ULONG ulSiz;

pbmch = &bmch;
pbmih = &bmih;

pjTmp = (PBYTE)pbmh;
ulSiz = sizeof(BITMAPCOREHEADER);
while (ulSiz--) {
*(((PBYTE)pbmch)++) = *(((PBYTE)pjTmp)++);
}

pjTmp = (PBYTE)pbmh;
ulSiz = sizeof(BITMAPINFOHEADER);
while (ulSiz--) {
*(((PBYTE)pbmih)++) = *(((PBYTE)pjTmp)++);
}

//
// Use the size to determine if it is a BitmapCoreHeader or
// BitmapInfoHeader
//
if (bmch.bcSize == sizeof(BITMAPCOREHEADER))
{
wBitCount = bmch.bcBitCount;
iNumClr = ((wBitCount == 24) ? 0 : (1 << wBitCount));
sizBMI = sizeof(BITMAPCOREHEADER)+sizeof(RGBTRIPLE)*iNumClr;
bCoreHdr = TRUE;
}
else // BITMAPINFOHEADER
{
wBitCount = bmih.biBitCount;
switch (wBitCount) {
case 16:
case 32:
sizBMI = sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3;
break;
case 24:
sizBMI = sizeof(BITMAPINFOHEADER);
break;
default:
iNumClr = (1 << wBitCount);
sizBMI = sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*iNumClr;
break;
}
bCoreHdr = FALSE;
}
}

if ((pbmi = (LPBITMAPINFO) LocalAlloc(LMEM_FIXED,sizBMI)) == NULL) {
bSuccess = FALSE;
goto ErrExit3;
}

//
// Make sure we pass in a DWORD aligned BitmapInfo to CreateDIBitmap
// Otherwise, exception on the MIPS platform
// CR!!! Equivalent to memcpy
//
pjTmp = (PBYTE)pbmi;

while(sizBMI--)
{
*(((PBYTE)pjTmp)++) = *(((PBYTE)pbmh)++);
}

//
// assuming CreateDIBitmap() is doing a byte fetch...
//
pjDIBits = (PBYTE)pMapFile + dwOffBits;

if (pbmi->bmiHeader.biCompression == BI_RGB)
{
//
// Converting to RLE bits...
//

OutputDebugString ("Converting to RLE format!");
lScan = pbmi->bmiHeader.biHeight;
sizImage = pbmi->bmiHeader.biSizeImage;

//
// select the palette into the DC first...
//
bSelectDIBPal(hDC, pInfo, pbmi, bCoreHdr);
if ((pInfo->hBmpSaved = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)pbmi,
CBM_INIT, pjDIBits, pbmi, DIB_RGB_COLORS)) == NULL) {
bSuccess = FALSE;
goto ErrExit4;
}

// We want to retrieve the RLE format...
pbmi->bmiHeader.biCompression = ((wBitCount==4) ? BI_RLE4 : BI_RLE8);

pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;

if (GetDIBits(hDC, pInfo->hBmpSaved, 0, lScan, NULL, pbmi,
DIB_RGB_COLORS) == 0) {
OutputDebugString ("Not all scans are converted!");
bSuccess = FALSE;
goto ErrExit4;
}

if (pbmi->bmiHeader.biSizeImage == 0) {
if (sizImage == 0) {
OutputDebugString ("biSizeImage == 0!");
bSuccess = FALSE;
goto ErrExit4;
}
OutputDebugString ("Engine returns zero image size, making one up!");
sizImage = (sizImage *3)/2;
} else {
sizImage = pbmi->bmiHeader.biSizeImage;
}

if ((pjRleBits = (PBYTE) LocalAlloc(LMEM_FIXED, sizImage)) == NULL) {
bSuccess = FALSE;
goto ErrExit4;
}

pbmi->bmiHeader.biSizeImage = sizImage;
if (GetDIBits(hDC, pInfo->hBmpSaved, 0, lScan, pjRleBits, pbmi,
DIB_RGB_COLORS) < lScan) {
bSuccess = FALSE;
goto ErrExit5;
}

SetDIBitsToDevice(hDC, 0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight,
0, 0, 0, lScan, pjRleBits, pbmi, DIB_RGB_COLORS);

pInfo->RleData.rgpjFrame[ulFrames] = pjRleBits;
} else {
bSelectDIBPal(hDC, pInfo, pbmi, bCoreHdr);
lScan = pbmi->bmiHeader.biHeight;
if (bCoreHdr) {
lScan = ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcHeight;
SetDIBitsToDevice(hDC, 0, 0, ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcWidth, ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcHeight,
0, 0, 0, lScan, pjDIBits, pbmi, DIB_RGB_COLORS);
} else {
lScan = pbmi->bmiHeader.biHeight;
SetDIBitsToDevice(hDC, 0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight,
0, 0, 0, lScan, pjDIBits, pbmi, DIB_RGB_COLORS);
}
pInfo->RleData.rgpjFrame[ulFrames] = pjDIBits;
}

pInfo->RleData.ulSize[ulFrames] = sizImage;
pInfo->RleData.rgpbmi[ulFrames] = pbmi;

//
// Go to next frame
//
pMapFile = (PBYTE)pMapFile + ulfSize;
ulOffset += ulfSize;
ulFrames++;

//
// end condition
//
if (ulOffset >= dwFileSizeLow) {
break;
}

}

//
// set pbmi to the very first bmi
//
pInfo->RleData.pbmi = pInfo->RleData.rgpbmi[0];

pInfo->RleData.hPal = pInfo->hPal;
pInfo->RleData.ulFrames = ulFrames;
return (bSuccess);

ErrExit5:
LocalFree(pjRleBits);
ErrExit4:
LocalFree(pbmi);
ErrExit3:
CloseHandle(pFileInfo->hMapFile);
ErrExit2:
CloseHandle(pFileInfo->hFile);
ErrExit1:
return (bSuccess);

}

/******************************Public*Routine******************************\
*
* bSelectDIBPal
*
* Effects: Creates a logical palette from the DIB and select it into the DC
* and realize the palette. Saving the hPal in the pInfo->hPal
*
* Warnings: Based on Windows NT DIB support. If PM support 16,24,32 bpp
* we need to modify this routine.
*
\**************************************************************************/

BOOL bSelectDIBPal(HDC hDC, PINFO pInfo, LPBITMAPINFO pbmi, BOOL bCoreHdr)
{
LOGPALETTE *plogPal;
UINT uiSizPal;
INT i, iNumClr;
WORD wBitCount;

if (bCoreHdr) {
wBitCount = ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcBitCount;
} else {
wBitCount = pbmi->bmiHeader.biBitCount;
}

switch (wBitCount) {
case 16:
case 24:
case 32: // Does PM supports these?
return FALSE;
default:
iNumClr = (1 << wBitCount);
break;
}

uiSizPal = sizeof(WORD)*2 + sizeof(PALETTEENTRY)*iNumClr;
if ((plogPal = (LOGPALETTE *) LocalAlloc(LMEM_FIXED,uiSizPal)) == NULL) {
pInfo->hPal = NULL;
return FALSE;
}

plogPal->palVersion = 0x300;
plogPal->palNumEntries = (WORD) iNumClr;

if (bCoreHdr) {
for (i=0; i<iNumClr; i++) {
plogPal->palPalEntry[i].peRed = ((LPBITMAPCOREINFO)pbmi)->bmciColors[i].rgbtRed;
plogPal->palPalEntry[i].peGreen = ((LPBITMAPCOREINFO)pbmi)->bmciColors[i].rgbtGreen;
plogPal->palPalEntry[i].peBlue = ((LPBITMAPCOREINFO)pbmi)->bmciColors[i].rgbtBlue;
plogPal->palPalEntry[i].peFlags = PC_RESERVED;
}
} else {
for (i=0; i<iNumClr; i++) {
plogPal->palPalEntry[i].peRed = pbmi->bmiColors[i].rgbRed;
plogPal->palPalEntry[i].peGreen = pbmi->bmiColors[i].rgbGreen;
plogPal->palPalEntry[i].peBlue = pbmi->bmiColors[i].rgbBlue;
plogPal->palPalEntry[i].peFlags = PC_RESERVED;
}
}

DeleteObject(pInfo->hPal);
pInfo->hPal = CreatePalette((LPLOGPALETTE)plogPal);
if ((pInfo->hPal) == NULL) {
return FALSE;
}

if ((GetDeviceCaps(hDC, RASTERCAPS)) & RC_PALETTE) {
SelectPalette(hDC, pInfo->hPal, FALSE);
RealizePalette(hDC);
}

GlobalFree(plogPal);

return TRUE;
}

/******************************Public*Routine******************************\
*
* bFreeRleFile
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

BOOL bFreeRleFile(PINFO pInfo)
{
ULONG ulFiles;
ULONG ulFrames;
ULONG i;
PFILEINFO pFileInfo;

ulFiles = pInfo->RleData.ulFiles;
ulFrames = pInfo->RleData.ulFrames;

for (i = 0; i < ulFrames; i++) {
LocalFree(pInfo->RleData.rgpjFrame[i]);
LocalFree(pInfo->RleData.rgpbmi[i]);
}

for (i = 0; i < ulFiles; i++) {
pFileInfo = &(pInfo->RleData.rgFileInfo[i]);
CloseHandle(pFileInfo->hFile);
CloseHandle(pFileInfo->hMapFile);
UnmapViewOfFile(pFileInfo->lpvMapView);
}

pInfo->RleData.ulFiles = 0;
pInfo->RleData.ulFrames = 0;
return TRUE;
}

/******************************Public*Routine******************************\
*
* bPlayRle
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

BOOL bPlayRle(PINFO pInfo)
{
ULONG ulFrames;
ULONG i;
LPBITMAPINFO pbmi;
HDC hDC;
HWND hViewSurf;
int ii;

// RECT rc;

hDC = GetDC(hViewSurf=pInfo->hwnd);

SelectPalette(hDC, pInfo->RleData.hPal, FALSE);
ii=RealizePalette(hDC);
if (ii){
UpdateColors (hDC);
}

ulFrames = pInfo->RleData.ulFrames;

for (i = 0; i < ulFrames; i++) {
pbmi = pInfo->RleData.rgpbmi[i];
SetDIBitsToDevice(hDC,
0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight,
0, 0, 0, pbmi->bmiHeader.biHeight,
pInfo->RleData.rgpjFrame[i], pbmi, DIB_RGB_COLORS);

#if 0
GetClientRect(pInfo->hwnd, &rc);
StretchDIBits(hDC,
0, 0, rc.right, rc.bottom,
0, 0, pbmi->bmiHeader.biWidth, pbmi->bmiHeader.biHeight,
(LPSTR)pInfo->RleData.rgpjFrame[i], pbmi, DIB_RGB_COLORS,
SRCCOPY);
#endif
}

ReleaseDC(hViewSurf, hDC);

return TRUE;
}


/******************************Public*Routine******************************\
*
* bSaveRleFile
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

BOOL bSaveRleFile(HDC hDC, PINFO pInfo, PSTR pszFileName)
{
int hFile;
OFSTRUCT ofReOpenBuff;
BOOL bSuccess;
BITMAPFILEHEADER bfh;
ULONG ulFrames;
ULONG i;
LPBITMAPINFO pbmi;
ULONG ulNumClr;
ULONG ulSize;

bSuccess = TRUE;
ulFrames = pInfo->RleData.ulFrames;

if (ulFrames == 0) {
MessageBox(GetFocus(), GetStringRes (IDS_NO_RLE_TO_SAVE),
NULL, MB_OK);
return FALSE;
}

// Let's open the file and get ready for writing
if ((hFile = OpenFile(pszFileName, (LPOFSTRUCT)&ofReOpenBuff,
OF_CREATE | OF_WRITE)) == -1) {
OutputDebugString ("Failed in OpenFile!");
return FALSE;
}

for (i = 0; i < ulFrames; i++) {

pbmi = pInfo->RleData.rgpbmi[i];

switch(pbmi->bmiHeader.biBitCount) {
case 24:
ulSize = 0;
break;
case 16:
case 32:
ulSize = sizeof(DWORD)*3;
break;
default:
ulNumClr = 1<<pbmi->bmiHeader.biBitCount;
ulSize = sizeof(RGBQUAD)*ulNumClr;
break;
}
#if 0
ulNumClr = ((pbmi->bmiHeader.biBitCount == 24)
? 0
: (1<<pbmi->bmiHeader.biBitCount));

#endif 
// fill in the info for the BitmapFileHeader
bfh.bfType = 0x4D42; // 'BM'
bfh.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+
ulSize;
//sizeof(RGBQUAD)*ulNumClr;
bfh.bfSize = bfh.bfOffBits + pbmi->bmiHeader.biSizeImage;
bfh.bfReserved1 =
bfh.bfReserved2 = 0;

// Write out the file header now
if (_lwrite(hFile, (LPSTR)&bfh, sizeof(BITMAPFILEHEADER)) == -1) {
bSuccess = FALSE;
goto ErrExit1;
}

// Now write out the BitmapInfoHeader and color table, if any
if (_lwrite(hFile, (LPSTR)pbmi, sizeof(BITMAPINFOHEADER) +
ulSize) == -1) {
//sizeof(RGBQUAD)*ulNumClr) == -1) {
bSuccess = FALSE;
goto ErrExit1;
}

// write the bits also
if (_lwrite(hFile, (LPSTR)pInfo->RleData.rgpjFrame[i],
pbmi->bmiHeader.biSizeImage) == -1) {
bSuccess = FALSE;
goto ErrExit1;
}

}

ErrExit1:
_lclose(hFile);
return bSuccess;
}


/******************************Public*Routine******************************\
*
* bPlayRleCont
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

BOOL bPlayRleCont(HDC hDC, PINFO pInfo)
{
BOOL bQuit;
MSG msg;
int ii;

bQuit = FALSE;

SelectPalette(hDC, pInfo->RleData.hPal, FALSE);
ii=RealizePalette(hDC);
if (ii){
UpdateColors (hDC);
}

while (TRUE && !bQuit) {

if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

if ((msg.message == WM_QUIT) || (msg.message == WM_CLOSE) ||
((msg.message == WM_SYSCOMMAND) && (msg.wParam == SC_CLOSE))) {
bQuit = TRUE;
PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam);
} else {
if (!TranslateAccelerator(msg.hwnd, ghAccel, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}

if (!pInfo->bPlayRleCont) {
bQuit = TRUE;
}

if (!bQuit) {
bPlayRle(pInfo);
}

}
return TRUE;
}


/******************************Public*Routine******************************\
*
* bPlayRleCont2
*
* Effects:
*
* Warnings:
*
\**************************************************************************/

BOOL bPlayRleCont2(PINFO pInfo)
{
HDC hDC;
HWND hViewSurf;
DWORD dwWait;
BOOL bQuit;
int ii;

hDC = GetDC(hViewSurf=pInfo->hwnd);

SelectPalette(hDC, pInfo->RleData.hPal, FALSE);
ii=RealizePalette(hDC);
if (ii){
UpdateColors (hDC);
}

bQuit = FALSE;
while (TRUE) {
//
// If parent gets a WM_CLOSE, we will return
//
dwWait = WaitForSingleObject(pInfo->hQuitEvent, 0);
if (dwWait == WAIT_TIMEOUT) {
MessageBox(ghwndMain,
GetStringRes (IDS_PLAY_THREAD_END),
GetStringRes (IDS_PLAY_THREAD),
MB_OK);
break;
}

if (!pInfo->bPlayRleCont) {
bQuit = TRUE;
}

if (!bQuit)
bPlayRle(pInfo);
}

ReleaseDC(hViewSurf, hDC);

ExitThread(0);
return TRUE;

}


/******************************Public*Routine******************************\
*
* DIBfromDDB
*
* Effects: Call GetDIBits to retrieve the DIB info from DDB
*
* Warnings:
*
\**************************************************************************/

HBITMAP DIBfromDDB(HDC hDC, HBITMAP hBmp, PINFO pInfo)
{
LPBITMAPINFO pbmi;
HBITMAP hDIB;
INT iBitCount, iNumClr;
BITMAP bm;
DWORD sizImage;
PBYTE pjBits;
ULONG sizBMI;
LONG lScan;

iBitCount = GetDeviceCaps(hDC, BITSPIXEL);
switch (iBitCount) {
case 16:
case 32:
sizBMI = sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3;
break;
case 24:
sizBMI = sizeof(BITMAPINFOHEADER);
break;
default:
iNumClr = (1 << iBitCount);
sizBMI = sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*iNumClr;
break;
}

if ((pbmi = (LPBITMAPINFO) LocalAlloc(LMEM_FIXED,sizBMI)) == NULL) {
goto ErrExit1;
}

pbmi->bmiHeader.biSize = 0x28; // GDI need this to work
pbmi->bmiHeader.biBitCount = 0; // don't get the color table
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;

GetObject(hBmp, sizeof(BITMAP), &bm);

//
// Important! Select the correct palette corresponding to the DDB
//
SelectPalette(hDC, pInfo->hPal, FALSE);
if (GetDIBits(hDC, hBmp, 0, bm.bmHeight, NULL, pbmi,
DIB_RGB_COLORS) == 0) {
goto ErrExit2;
}

sizImage = pbmi->bmiHeader.biSizeImage;
if (sizImage == 0) {
goto ErrExit2;
}

if ((pjBits = (PBYTE) LocalAlloc(LMEM_FIXED, sizImage)) == NULL) {
goto ErrExit2;
}

lScan = pbmi->bmiHeader.biHeight;

if (GetDIBits(hDC, pInfo->hBmpSaved, 0, lScan, pjBits, pbmi,
DIB_RGB_COLORS) < lScan) {
goto ErrExit3;
}

//
// Saving the DIB...free memory when the windows is closed.
//
pInfo->RleData.rgpjFrame[0] = pjBits;
pInfo->RleData.rgpbmi[0] = pbmi;
pInfo->RleData.pbmi = (PBITMAPINFO) &(pInfo->RleData.rgpbmi[0]);
pInfo->RleData.ulFrames = 1;
pInfo->RleData.ulFiles = 1;

// set flag to use original DIB as source for blting so HT can be done
pInfo->bUseDIB = TRUE;

pInfo->bCoreHdr = FALSE;

// hDIB = CreateDIBitmap(hDC, NULL, CBM_INIT, pjBits, pbmi, DIB_RGB_COLORS);
hDIB = CreateDIBSection(hDC, pbmi, DIB_RGB_COLORS, &pjBits, NULL, 0);

return hDIB;

ErrExit3:
LocalFree(pjBits);
ErrExit2:
LocalFree(pbmi);
ErrExit1:
return ((HBITMAP)NULL);
}


//---------------------------------------------------------------------------
//
// FUNCTION: GetStringRes (int id INPUT ONLY)
//
// COMMENTS: Load the resource string with the ID given, and return a
// pointer to it. Notice that the buffer is common memory so
// the string must be used before this call is made a second time.
//
//---------------------------------------------------------------------------

LPTSTR GetStringRes (int id)
{
static TCHAR buffer[MAX_PATH];

buffer[0]=0;
LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
return buffer;
}