|
|
1.1 root 1: /****************************************************************************
2:
3: MANDEL.C --
4:
5: Main code for the Windows Mandelbrot Set distributed drawing program.
6:
7: Copyright (C) 1990 Microsoft Corporation.
8:
9: This code sample is provided for demonstration purposes only.
10: Microsoft makes no warranty, either express or implied,
11: as to its usability in any given situation.
12:
13: ****************************************************************************/
14:
15: #include <sys\types.h>
16: #include <sys\stat.h>
17: #include <direct.h>
18: #include <dos.h>
19: #include <string.h>
20: #include <ctype.h>
21: #include <malloc.h> // malloc, free
22: #include <stdio.h>
23: #include <stdlib.h>
24: #include <time.h>
25:
26: #ifdef RPC
27: #include <rpc.h>
28: #include "mdlrpc.h"
29: #endif
30:
31: #include <windows.h> /* Required for all Windows applications */
32: #include "mandel.h" /* Specific to this program */
33:
34: #define MENUNAME "MandelMenu"
35: #define CLASSNAME "MandelClass"
36: #define ABOUTBOX "AboutBox"
37: #define SAVEBOX "SAVEBOX"
38:
39:
40: #define POLL_TIME 100
41: #define LINES 4
42:
43: #ifdef RPC
44: char szTitle[] = "Mandelbrot RPC";
45: #else
46: char szTitle[] = "Mandelbrot Standalone";
47: #endif
48:
49: char szBitmap[] = "Mandel";
50:
51: CPOINT cptUL = { (double) -2.05, (double) 1.4 };
52: double dPrec = (double) .01;
53:
54: void PaintLine( HWND, svr_table *, HDC, int);
55: COLORREF MapColor( DWORD, DWORD );
56: void DrawRect( HWND, PRECT, BOOL, HDC);
57: long get_drivemap(void);
58: void set_dlgitems(HWND, char *, long);
59: BOOL update_curdir(HWND, char *, long);
60: char * getdcwd( int, char *, unsigned);
61: void set_filename( HWND );
62: BOOL munge_path( char *);
63:
64: HANDLE hInst; /* current instance */
65:
66: int iLines = LINES;
67: svr_table SvrTable[20];
68: int SvrTableSz = 0;
69:
70: #define NCOLORS 11
71: int fContinueZoom = TRUE;
72: int fZoomIn = TRUE;
73: int Histogram[4][4][NCOLORS+1] = {0}; /* split current picture into 16 regions */
74: /* zoom on most complex region; region with most colors represented */
75: int ColorCount[4][4] = {0};
76: int Max[4][4] = { 0 };
77: int iHistMaxI = 2;
78: int iHistMaxJ = 3;
79: RECT rcZoom;
80: BOOL fRectDefined = FALSE;
81:
82:
83: /*
84: *
85: * FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
86: *
87: * PURPOSE: Calls initialization function, processes message loop
88: *
89: * COMMENTS:
90: *
91: * Windows recognizes this function by name as the initial entry point
92: * for the program. This function calls the application initialization
93: * routine, if no other instance of the program is running, and always
94: * calls the instance initialization routine. It then executes a message
95: * retrieval and dispatch loop that is the top-level control structure
96: * for the remainder of execution. The loop is terminated when a WM_QUIT
97: * message is received, at which time this function exits the application
98: * instance by returning the value passed by PostQuitMessage().
99: *
100: * If this function must abort before entering the message loop, it
101: * returns the conventional value NULL.
102: *
103: */
104:
105: int APIENTRY WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
106: HANDLE hInstance; /* current instance */
107: HANDLE hPrevInstance; /* previous instance */
108: LPSTR lpCmdLine; /* command line */
109: int nCmdShow; /* show-window type (open/icon) */
110: {
111: MSG msg; /* message */
112:
113: UNREFERENCED_PARAMETER(lpCmdLine);
114:
115: // add a runtime exception handler for RPC version
116: // see below for additional exception handling code
117: #ifdef RPC
118: RpcTryExcept {
119: #endif
120:
121: if (!hPrevInstance) /* Other instances of app running? */
122: if (!InitApplication(hInstance)) /* Initialize shared things */
123: return (FALSE); /* Exits if unable to initialize */
124:
125: /* Perform initializations that apply to a specific instance */
126:
127: if (!InitInstance(hInstance, nCmdShow))
128: return (FALSE);
129:
130: /* Acquire and dispatch messages until a WM_QUIT message is received. */
131:
132:
133: while (GetMessage(&msg, /* message structure */
134: NULL, /* handle of window receiving the message */
135: 0, /* lowest message to examine */
136: 0)) /* highest message to examine */
137: {
138: TranslateMessage(&msg); /* Translates virtual key codes */
139: DispatchMessage(&msg); /* Dispatches message to window */
140: }
141:
142: return (msg.wParam); /* Returns the value from PostQuitMessage */
143:
144: // add a runtime exception handler for RPC version
145: // see above for additional exception handling code
146: #ifdef RPC
147: } // end of RpcTryExcept statements
148: RpcExcept(1) {
149: sprintf(pszFail, "Please start the server application.");
150: MessageBox(msg.hwnd, pszFail, "Mandel Server Not Started",
151: MB_ICONHAND | MB_SYSTEMMODAL);
152: }
153: RpcEndExcept
154: #endif
155:
156: } // end WinMain
157:
158:
159:
160:
161: /*
162: * FUNCTION: InitApplication(HANDLE)
163: *
164: * PURPOSE: Initializes window data and registers window class
165: *
166: * COMMENTS:
167: *
168: * This function is called at initialization time only if no other
169: * instances of the application are running. This function performs
170: * initialization tasks that can be done once for any number of running
171: * instances.
172: *
173: * In this case, we initialize a window class by filling out a data
174: * structure of type WNDCLASS and calling the Windows RegisterClass()
175: * function. Since all instances of this application use the same window
176: * class, we only need to do this when the first instance is initialized.
177: */
178:
179: BOOL InitApplication(hInstance)
180: HANDLE hInstance; /* current instance */
181: {
182: WNDCLASS wc;
183:
184: /* Fill in window class structure with parameters that describe the */
185: /* main window. */
186:
187: wc.style = 0; /* Class style(s). */
188: wc.lpfnWndProc = (WNDPROC)MainWndProc; /* Function to retrieve messages for */
189: /* windows of this class. */
190: wc.cbClsExtra = 0; /* No per-class extra data. */
191: wc.cbWndExtra = 0; /* No per-window extra data. */
192: wc.hInstance = hInstance; /* Application that owns the class. */
193: wc.hIcon = LoadIcon(hInstance, "RPC_ICON");
194: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
195: wc.hbrBackground = GetStockObject(WHITE_BRUSH);
196: wc.lpszMenuName = MENUNAME; /* Name of menu resource in .RC file. */
197: wc.lpszClassName = CLASSNAME; /* Name used in call to CreateWindow. */
198:
199: /* Register the window class and return success/failure code. */
200:
201: return (RegisterClass(&wc));
202:
203: }
204:
205:
206:
207: /*
208: * FUNCTION: InitInstance(HANDLE, int)
209: *
210: * PURPOSE: Saves instance handle and creates main window.
211: *
212: * COMMENTS:
213: *
214: * This function is called at initialization time for every instance of
215: * this application. This function performs initialization tasks that
216: * cannot be shared by multiple instances.
217: *
218: * In this case, we save the instance handle in a static variable and
219: * create and display the main program window.
220: */
221:
222: BOOL InitInstance(hInstance, nCmdShow)
223: HANDLE hInstance; /* Current instance identifier. */
224: int nCmdShow; /* Param for first ShowWindow() call. */
225: {
226: HWND hWnd; /* Main window handle. */
227: RECT rc;
228:
229: /* Save the instance handle in static variable, which will be used in */
230: /* many subsequence calls from this application to Windows. */
231:
232: hInst = hInstance;
233:
234: /* Create a main window for this application instance. */
235:
236: hWnd = CreateWindow(
237: CLASSNAME, /* See RegisterClass() call. */
238: szTitle, /* Text for window title bar. */
239: WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX,
240: CW_USEDEFAULT, /* Default horizontal position. */
241: CW_USEDEFAULT, /* Default vertical position. */
242: WIDTH, /* Default width. */
243: HEIGHT, /* Default height. */
244: NULL, /* Overlapped windows have no parent. */
245: NULL, /* Use the window class menu. */
246: hInstance, /* This instance owns this window. */
247: NULL /* Pointer not needed. */
248: );
249:
250: /* If window could not be created, return "failure" */
251:
252: if (!hWnd)
253: return (FALSE);
254:
255: /* Make the window visible; update its client area; and return "success" */
256:
257: ShowWindow(hWnd, nCmdShow); /* Show the window */
258: UpdateWindow(hWnd); /* Sends WM_PAINT message */
259:
260: rc.top = rc.left = 0;
261: rc.bottom = HEIGHT-1;
262: rc.right = WIDTH-1;
263:
264: SetNewCalc(cptUL, dPrec, rc);
265:
266: return (TRUE); /* Returns the value from PostQuitMessage */
267: }
268:
269:
270:
271: /*
272: * FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)
273: *
274: * PURPOSE: Processes messages
275: *
276: * MESSAGES:
277: *
278: * WM_COMMAND - application menu (About dialog box)
279: * WM_DESTROY - destroy window
280: *
281: * COMMENTS:
282: *
283: * To process the IDM_ABOUT message, call MakeProcInstance() to get
284: * the current instance address of the About() function, then call
285: * DialogBox to create the box according to the information in the
286: * MANDEL.RC file and turn control over to the About() function.
287: * When it returns, free the intance address.
288: */
289:
290: LONG APIENTRY MainWndProc(
291: HWND hWnd, /* window handle */
292: UINT message, /* type of message */
293: UINT wParam, /* additional information */
294: LONG lParam) /* additional information */
295: {
296: FARPROC lpProcAbout; /* pointer to the "About" function */
297: PAINTSTRUCT ps;
298: HDC hdc;
299: static HDC hdcMem;
300: static HBITMAP hbmMem;
301: static int width;
302: static int height;
303: RECT rc;
304: static BOOL fButtonDown = FALSE;
305: static POINT pSelected;
306: POINT pMove;
307: int iWidthNew;
308: int iHeightNew;
309: static int miOldLines;
310: double scaling;
311:
312: switch (message)
313: {
314:
315: case WM_CREATE:
316: if (!InitRemote(hWnd))
317: return FALSE;
318:
319: InitHistogram();
320:
321: hdc = GetDC(hWnd);
322: hdcMem = CreateCompatibleDC(hdc);
323: GetWindowRect(hWnd, &rc);
324: width = rc.right - rc.left;
325: height = rc.bottom - rc.top;
326: hbmMem = CreateCompatibleBitmap(hdc, width, height);
327: SelectObject(hdcMem, hbmMem);
328:
329: ReleaseDC(hWnd,hdc);
330:
331: rc.left = rc.top = 0;
332: rc.right = width+1;
333: rc.bottom = height + 1;
334: FillRect(hdcMem, &rc, GetStockObject(WHITE_BRUSH));
335:
336: SetTimer(hWnd, 1, POLL_TIME, NULL); // set timer for polls
337:
338: CheckMenuItem(GetMenu(hWnd), IDM_4LINES, MF_CHECKED);
339: CheckMenuItem(GetMenu(hWnd), IDM_CONTINUOUS, MF_CHECKED);
340: miOldLines = IDM_4LINES; // save to uncheck
341:
342: break;
343:
344: case WM_PAINT:
345: hdc = BeginPaint(hWnd, &ps);
346: BitBlt(hdc, ps.rcPaint.left,
347: ps.rcPaint.top,
348: ps.rcPaint.right - ps.rcPaint.left,
349: ps.rcPaint.bottom - ps.rcPaint.top,
350: hdcMem, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
351: EndPaint(hWnd, &ps);
352: break;
353:
354: case WM_COMMAND: /* message: command from application menu */
355: switch(wParam)
356: {
357:
358: case IDM_ABOUT:
359: lpProcAbout = MakeProcInstance((FARPROC)About, hInst);
360:
361: DialogBox(hInst, /* current instance */
362: ABOUTBOX, /* resource to use */
363: hWnd, /* parent handle */
364: (WNDPROC)lpProcAbout); /* About() instance address */
365:
366: FreeProcInstance(lpProcAbout);
367: break;
368:
369: case IDM_ZOOMOUT:
370: if (dPrec > (double)MAXPREC) // don't allow the zoom out
371: break;
372: rcZoom.left = WIDTH/4 + (WIDTH/8); // center square
373: rcZoom.top = HEIGHT/4 + (HEIGHT/8);
374: rcZoom.right = rcZoom.left + (WIDTH/4);
375: rcZoom.bottom = rcZoom.top + (HEIGHT/4);
376:
377: cptUL.real -= (rcZoom.left * dPrec); // inverse of zoom in
378: cptUL.imag += (rcZoom.top * dPrec);
379: iWidthNew = (rcZoom.right - rcZoom.left + 1);
380: iHeightNew = (rcZoom.bottom - rcZoom.top + 1);
381: scaling =
382: ( (double) ((iWidthNew > iHeightNew) ? iWidthNew : iHeightNew)
383: / (double)width);
384: dPrec /= scaling;
385:
386: rc.left = rc.top = 0;
387: rc.bottom = height - 1;
388: rc.right = width - 1;
389:
390: SetNewCalc(cptUL, dPrec, rc);
391: fRectDefined = FALSE;
392: DoSomeWork(hWnd, FALSE);
393: break;
394:
395: case IDM_ZOOMIN: // zoom in on selected rectangle
396: // if no rectangle, don't zoom in
397: if (!fRectDefined)
398: break;
399: if (dPrec < (double)MINPREC) // don't allow zoom in
400: break;
401: DrawRect(hWnd, &rcZoom, TRUE, hdcMem); // draw new rect
402:
403: // calculate new upper-left
404: cptUL.real += (rcZoom.left * dPrec);
405: cptUL.imag -= (rcZoom.top * dPrec);
406:
407: iWidthNew = (rcZoom.right - rcZoom.left + 1);
408: iHeightNew = (rcZoom.bottom - rcZoom.top + 1);
409: scaling =
410: ( (double) ((iWidthNew > iHeightNew) ? iWidthNew : iHeightNew)
411: / (double)width);
412:
413: dPrec *= scaling;
414:
415: rc.left = rc.top = 0;
416: rc.bottom = height - 1;
417: rc.right = width - 1;
418:
419: SetNewCalc( cptUL, dPrec, rc);
420: IncPictureID();
421:
422: fRectDefined = FALSE;
423: DoSomeWork(hWnd, FALSE);
424: break;
425:
426: case IDM_CONTINUOUS: // continuous zoom in
427: if (fContinueZoom == TRUE) {
428: CheckMenuItem(GetMenu(hWnd), IDM_CONTINUOUS, MF_UNCHECKED);
429: fContinueZoom = FALSE;
430: }
431: else {
432: CheckMenuItem(GetMenu(hWnd), IDM_CONTINUOUS, MF_CHECKED);
433: fContinueZoom = TRUE;
434: }
435: break;
436:
437: case IDM_REDRAW:
438: if (fContinueZoom == TRUE)
439: InitHistogram();
440: rc.left = rc.top = 0;
441: rc.right = width+1;
442: rc.bottom = height + 1;
443: FillRect(hdcMem, &rc, GetStockObject(WHITE_BRUSH));
444: InvalidateRect(hWnd, NULL, TRUE);
445:
446: rc.left = rc.top = 0;
447: rc.bottom = height - 1;
448: rc.right = width - 1;
449: SetNewCalc( cptUL, dPrec, rc);
450:
451: fRectDefined = FALSE;
452: DoSomeWork(hWnd, FALSE);
453: break;
454:
455: case IDM_EXIT:
456: DestroyWindow(hWnd);
457: break;
458:
459: case IDM_TOP:
460: cptUL.real = (double) -2.05;
461: cptUL.imag = (double) 1.4;
462: dPrec = .01;
463:
464: rc.left = rc.top = 0;
465: rc.bottom = height - 1;
466: rc.right = width - 1;
467: SetNewCalc( cptUL, dPrec, rc);
468: cPictureID = 0; // incremented past original
469:
470: fRectDefined = FALSE;
471: DoSomeWork(hWnd, FALSE);
472: break;
473:
474: case IDM_1LINE:
475: case IDM_2LINES:
476: case IDM_4LINES:
477: case IDM_8LINES:
478: case IDM_16LINES:
479: case IDM_32LINES:
480:
481: CheckMenuItem(GetMenu(hWnd), miOldLines, MF_UNCHECKED);
482: miOldLines = wParam;
483: switch(wParam)
484: {
485: case IDM_1LINE:
486: iLines = 1;
487: break;
488: case IDM_2LINES:
489: iLines = 2;
490: break;
491: case IDM_4LINES:
492: iLines = 4;
493: break;
494: case IDM_8LINES:
495: iLines = 8;
496: break;
497: case IDM_16LINES:
498: iLines = 16;
499: break;
500: case IDM_32LINES:
501: iLines = 32;
502: }
503:
504: CheckMenuItem(GetMenu(hWnd), miOldLines, MF_CHECKED);
505: break;
506:
507:
508: default: /* Lets Windows process it */
509: return (DefWindowProc(hWnd, message, wParam, lParam));
510: }
511: break;
512:
513: case WM_DESTROY: /* message: window being destroyed */
514: PostQuitMessage(0);
515: DeleteDC(hdcMem);
516: DeleteObject(hbmMem);
517: break;
518:
519: case WM_DOSOMEWORK:
520: // do another slice of calculation work
521: DoSomeWork(hWnd, FALSE);
522: break;
523:
524: case WM_PAINTLINE:
525: // The shared buffer contains a line of data; draw it
526: PaintLine(hWnd,
527: (svr_table *)&SvrTable[(signed int)wParam],
528: hdcMem,
529: height);
530: break;
531:
532: case WM_TIMER:
533: // timer means we should do another slice of work
534: DoSomeWork(hWnd, TRUE);
535: break;
536:
537: case WM_LBUTTONDOWN:
538: // left button down; start to define a zoom rectangle
539:
540: if (fRectDefined)
541: DrawRect(hWnd, &rcZoom, FALSE, hdcMem); // undraw old rectangle
542:
543: // initialize rectangle
544: rcZoom.left = rcZoom.right = pSelected.x = LOWORD(lParam);
545: rcZoom.top = rcZoom.bottom = pSelected.y = HIWORD(lParam);
546:
547: // draw the new rectangle
548: DrawRect(hWnd, &rcZoom, TRUE, hdcMem);
549:
550: fRectDefined = TRUE;
551: fButtonDown = TRUE;
552: SetCapture(hWnd); // capture all mouse events
553: break;
554:
555: case WM_MOUSEMOVE:
556:
557: // mouse move -- if the button is down, change the rect
558: if (!fButtonDown)
559: break;
560:
561: DrawRect(hWnd, &rcZoom, FALSE, hdcMem); // undraw old rect
562:
563: pMove.x = LOWORD(lParam);
564: pMove.y = HIWORD(lParam);
565:
566: // update the selection rectangle
567: if (pMove.x <= pSelected.x)
568: rcZoom.left = pMove.x;
569: if (pMove.x >= pSelected.x)
570: rcZoom.right = pMove.x;
571: if (pMove.y <= pSelected.y)
572: rcZoom.top = pMove.y;
573: if (pMove.y >= pSelected.y)
574: rcZoom.bottom = pMove.y;
575:
576: DrawRect(hWnd, &rcZoom, TRUE, hdcMem); // draw new rect
577: break;
578:
579: case WM_LBUTTONUP:
580: // button up; end selection
581: fButtonDown = FALSE;
582: ReleaseCapture();
583: break;
584:
585: default: /* Passes it on if unproccessed */
586: return (DefWindowProc(hWnd, message, wParam, lParam));
587: }
588: return (0L);
589: }
590:
591:
592:
593: /*
594: * FUNCTION: About(HWND, unsigned, WORD, LONG)
595: *
596: * PURPOSE: Processes messages for "About" dialog box
597: *
598: * MESSAGES:
599: *
600: * WM_INITDIALOG - initialize dialog box
601: * WM_COMMAND - Input received
602: *
603: * COMMENTS:
604: *
605: * No initialization is needed for this particular dialog box, but TRUE
606: * must be returned to Windows.
607: *
608: * Wait for user to click on "Ok" button, then close the dialog box.
609: */
610:
611: BOOL APIENTRY About(
612: HWND hDlg, /* window handle of the dialog box */
613: UINT message, /* type of message */
614: UINT wParam, /* message-specific information */
615: LONG lParam)
616: {
617: UNREFERENCED_PARAMETER(lParam);
618:
619: switch (message)
620: {
621: case WM_INITDIALOG: /* message: initialize dialog box */
622:
623: return (TRUE);
624:
625: case WM_COMMAND: /* message: received a command */
626: if (wParam == IDOK /* "OK" box selected? */
627: || wParam == IDCANCEL) /* System menu close command? */
628: {
629: EndDialog(hDlg, TRUE); /* Exits the dialog box */
630: return (TRUE);
631: }
632: break;
633: }
634: return (FALSE); /* Didn't process a message */
635: }
636:
637:
638:
639:
640: /*
641: * DoSomeWork --
642: *
643: * This function does our work for us. It does it in little pieces, and
644: * will schedule itself as it sees fit.
645: */
646:
647: void
648: DoSomeWork( HWND hwnd,
649: BOOL fTimer)
650: {
651:
652: static WORD wIteration = 0;
653:
654: if (fTimer) {
655: wIteration++;
656:
657: // on every nth tick, we send out a poll
658: if (wIteration == 120) { // tune this?
659: wIteration = 0;
660: return;
661: }
662:
663: // on the half-poll, we check for responses
664: if ((wIteration == 2) || (wIteration == 10)) {
665: return;
666: }
667:
668: }
669:
670: if (CheckDrawStatus(hwnd))
671: SendMessage(hwnd, WM_DOSOMEWORK, 0, 0L);
672:
673: return;
674: }
675:
676:
677:
678: /*
679: * DrawRect --
680: *
681: * This function draws (or undraws) the zoom rectangle.
682: */
683:
684: void
685: DrawRect( HWND hwnd,
686: PRECT prc,
687: BOOL fDrawIt,
688: HDC hdcBM)
689: {
690:
691: HDC hdc;
692: DWORD dwRop;
693:
694: hdc = GetDC(hwnd);
695:
696: if (fDrawIt)
697: dwRop = NOTSRCCOPY;
698: else
699: dwRop = SRCCOPY;
700:
701:
702: // top side
703: BitBlt(hdc, prc->left, prc->top, (prc->right - prc->left) + 1,
704: 1, hdcBM, prc->left, prc->top, dwRop);
705:
706: // bottom side
707: BitBlt(hdc, prc->left, prc->bottom, (prc->right - prc->left) + 1,
708: 1, hdcBM, prc->left, prc->bottom, dwRop);
709:
710: // left side
711: BitBlt(hdc,prc->left, prc->top, 1, (prc->bottom - prc->top) + 1,
712: hdcBM, prc->left, prc->top, dwRop);
713:
714: // right side
715: BitBlt(hdc,prc->right, prc->top, 1, (prc->bottom - prc->top) + 1,
716: hdcBM, prc->right, prc->top, dwRop);
717:
718: ReleaseDC(hwnd, hdc);
719: }
720:
721:
722:
723: /*
724: * PaintLine --
725: *
726: * This function paints a buffer of data into the bitmap.
727: */
728:
729: void
730: PaintLine( HWND hwnd,
731: svr_table * pst,
732: HDC hdcBM,
733: int cHeight)
734: {
735:
736: PWORD pwDrawData;
737: int y;
738: int x;
739: DWORD dwThreshold;
740: RECT rc;
741: WORD lines;
742:
743: lines = (WORD) pst->cLines;
744:
745: // picture ID had better match, or else we skip it
746: if (CheckDrawingID(pst->cPicture))
747: {
748: // figure out our threshold
749: dwThreshold = QueryThreshold();
750:
751: // get a pointer to the draw buffer
752: pwDrawData = (PWORD)GetDrawBuffer();
753: if (pwDrawData == NULL) {
754: ReturnDrawBuffer();
755: return;
756: }
757:
758: // starting x coordinate
759: x = (int) pst->dwLine;
760:
761: // now loop through the rectangle
762: while (lines-- > 0)
763: {
764: // bottom to top, since that's the order of the data in the buffer
765: y = (int) cHeight-1;
766:
767:
768: while (y >= 0) {
769: // draw a pixel
770: SetPixel(hdcBM, x,y, MapColor((DWORD)*pwDrawData, dwThreshold));
771: if (fContinueZoom == TRUE)
772: CalcHistogram(x, y, (DWORD)*pwDrawData, dwThreshold);
773: // now increment buffer pointer and y coord
774: y--;
775: pwDrawData++;
776: }
777: x++; // increment X coordinate
778: }
779:
780: // figure out the rectangle to invalidate
781: rc.top = 0;
782: rc.bottom = cHeight;
783: rc.left = (int)(pst->dwLine);
784: rc.right = (int)(pst->dwLine) + pst->cLines;
785:
786: FreeDrawBuffer();
787:
788: // and invalidate it on the screen so we redraw it
789: InvalidateRect(hwnd, &rc, FALSE);
790: }
791:
792: // free this for someone else to use
793: ReturnDrawBuffer();
794:
795: // and change the pipe state, if necessary
796: if (pst->iStatus == SS_PAINTING)
797: pst->iStatus = SS_IDLE;
798:
799: }
800:
801:
802: #define CLR_BLACK RGB(0,0,0)
803: #define CLR_DARKBLUE RGB(0,0,127)
804: #define CLR_BLUE RGB(0,0,255)
805: #define CLR_CYAN RGB(0,255,255)
806: #define CLR_DARKGREEN RGB(0,127,0)
807: #define CLR_GREEN RGB(0,255,0)
808: #define CLR_YELLOW RGB(255,255,0)
809: #define CLR_RED RGB(255,0,0)
810: #define CLR_DARKRED RGB(127,0,0)
811: #define CLR_WHITE RGB(255,255,255)
812: #define CLR_PALEGRAY RGB(194,194,194)
813: #define CLR_DARKGRAY RGB(127,127,127)
814:
815:
816: static COLORREF ColorMapTable[] = { // size = NCOLORS
817: CLR_DARKBLUE,
818: CLR_BLUE,
819: CLR_CYAN,
820: CLR_DARKGREEN,
821: CLR_GREEN,
822: CLR_YELLOW,
823: CLR_RED,
824: CLR_DARKRED,
825: CLR_WHITE,
826: CLR_PALEGRAY,
827: CLR_DARKGRAY};
828:
829:
830: /*
831: * MapColor --
832: *
833: * This function maps an iteration count into a corresponding RGB color.
834: */
835:
836: COLORREF
837: MapColor(DWORD dwIter,
838: DWORD dwThreshold)
839: {
840:
841: // if it's beyond the threshold, call it black
842: if (dwIter >= dwThreshold) {
843: return CLR_BLACK;
844: }
845:
846: // get a modulus based on the number of colors
847: dwIter = (dwIter / 3) % NCOLORS; // 11;
848:
849: // and return the appropriate color
850: return ColorMapTable[dwIter];
851:
852: }
853: /* CalcHistogram
854: * This function is used to select the region that is the
855: * most complex and will be used to zoom in for the next picture;
856: * it contains the most colors. The number of colors are counted.
857: */
858:
859: void
860: CalcHistogram(int x,
861: int y,
862: DWORD dwIter,
863: DWORD dwThreshold)
864: {
865:
866: // if it's beyond the threshold, call it black
867: if (dwIter >= dwThreshold) {
868: Histogram[x/(WIDTH/4)][y/(HEIGHT/4)][NCOLORS]++;
869: return;
870: }
871: // get a modulus based on the number of colors
872: dwIter = (dwIter / 3) % NCOLORS; // 11;
873:
874: // and bump the count for the appropriate color
875: Histogram[x/(WIDTH/4)][y/(HEIGHT/4)][dwIter]++; // region of map
876:
877: return;
878:
879: }
880:
881:
882: /* InitHistogram
883: * This function initializes the histogram data structures.
884: */
885:
886: void InitHistogram(void)
887: {
888: int i, j, k;
889:
890: for (i = 0; i < 4; i++)
891: for (j = 0; j < 4; j++)
892: for (k = 0; k <= NCOLORS; k++)
893: Histogram[i][j][k] = 0; /* count of colors */
894: }
895:
896: /* CountHistogram
897: * This function determines the number of colors represented
898: * within a region. The region with the most colors is
899: * selected using the maxi and maxj values. X and Y coordinates
900: * corresponding to these regions are stored in the HistRegion
901: * table and are used for the next picture.
902: */
903:
904: void CountHistogram(void)
905: {
906: int i, j, k;
907: /* count the number of colors in each region */
908: /* find the color that dominates each region */
909: for (i = 0; i < 4; i++) {
910: for (j = 0; j < 4; j++) {
911: ColorCount[i][j] = 0;
912: Max[i][j] = 0;
913: for (k = 0; k <= NCOLORS; k++) {
914: if (Histogram[i][j][k] > Max[i][j])
915: Max[i][j] = Histogram[i][j][k];
916: if (Histogram[i][j][k] != 0) /* count of colors */
917: ColorCount[i][j]++;
918: }
919:
920: }
921: }
922: iHistMaxI = 0;
923: iHistMaxJ = 0;
924: /* if several regions have the same number of colors, */
925: /* select the region with the most variety: the smallest max */
926: for (i = 0; i < 4; i++) {
927: for (j = 0; j < 4; j++) {
928: if ( (ColorCount[i][j] >= ColorCount[iHistMaxI][iHistMaxJ])
929: && (Max[i][j] < Max[iHistMaxI][iHistMaxJ]) ) {
930: iHistMaxI = i;
931: iHistMaxJ = j;
932: }
933: }
934: }
935: InitHistogram(); /* initialize for next time */
936:
937: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.