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