|
|
1.1 root 1: /************************************************************************
2: *
3: * fatpel.c -- The Diamond Metric, Theory vs. Practice
4: *
5: * Created by Microsoft, IBM Corporation, 1990
6: *
7: * DISCLAIMER OF WARRANTIES. The following [enclosed] code is
8: * sample code created by Microsoft Corporation and/or IBM
9: * Corporation. This sample code is not part of any standard
10: * Microsoft or IBM product and is provided to you solely for
11: * the purpose of assisting you in the development of your
12: * applications. The code is provided "AS IS", without
13: * warranty of any kind. Neither Microsoft nor IBM shall be
14: * liable for any damages arising out of your use of the sample
15: * code, even if they have been advised of the possibility of
16: * such damages.
17: *
18: ************************************************************************/
19:
20: #define INCL_WINFRAMEMGR
21: #define INCL_WINWINDOWMGR
22: #define INCL_WINMESSAGEMGR
23: #define INCL_WINPOINTERS
24: #define INCL_WINSWITCHLIST
25: #define INCL_WINTRACKRECT
26: #define INCL_WINDIALOGS
27: #define INCL_WINBUTTONS
28: #define INCL_GPILOGCOLORTABLE
29: #define INCL_GPIBITMAPS
30: #define INCL_GPITRANSFORMS
31: #define INCL_DOSMEMMGR
32: #define INCL_DOSFILEMGR
33: #define INCL_BITMAPFILEFORMAT
34: #define INCL_GPIPRIMITIVES
35: #define INCL_WINMENUS
36: #define INCL_GPIREGIONS
37: #define INCL_WINPOINTERS
38: #define INCL_WININPUT
39: #include <os2.h>
40:
41: #include <stdio.h>
42: #include <stdlib.h>
43: #include <string.h>
44:
45: #include "..\opendlg\opendlg.h"
46: #include "fatpel.h"
47:
48:
49:
50:
51: /************************************************************************
52: *
53: * Function declarations
54: *
55: ************************************************************************/
56:
57: /* Private functions */
58:
59: VOID cdecl main(VOID);
60: BOOL FAR InitGlobals(VOID);
61: BOOL FAR InitApp(VOID);
62: VOID Close(HWND);
63: VOID Command(HWND, USHORT);
64: VOID Paint(HPS, USHORT);
65: VOID EraseBackground(HPS);
66: VOID DrawGrid(HPS);
67: VOID DisplayRenderedPels(HPS, USHORT);
68: VOID DisplayControlPoints(HPS, LONG, PPOINTL, USHORT);
69: VOID DisplayMathematicalObject(HPS, USHORT);
70: VOID DrawFatPels(HPS);
71: VOID DrawOneFatPel(HPS, PPOINTL, COLOR);
72: VOID GetFatPelFromPt(PPOINTL, PPOINTL);
73: VOID SetFatPel(PPOINTL, COLOR);
74: VOID RoundControlPoints(HPS, LONG, PPOINTL, PPOINTL, LONG, LONG);
75: VOID ComputeTransform(PRECTL, PRECTL);
76: VOID DrawPrimitive(HPS, LONG, PPOINTL);
77: VOID UpdateSurfaceDims(VOID);
78: VOID MySetWindowLong (HWND, USHORT, LONG);
79: VOID MySetWindowLongHex(HWND, USHORT, LONG);
80: LONG MyGetWindowLong (HWND, USHORT);
81: VOID MouseMove(HWND, MPARAM);
82: VOID ButtonUp(HWND, USHORT);
83: VOID ButtonDown(HWND, USHORT, MPARAM);
84: VOID DragPelSize(HWND, POINTS);
85: VOID WriteFile(HWND, HPS);
86: BOOL WriteBMP(HFILE, HPS, PBITMAPINFOHEADER2);
87: VOID MyMessageBox(HWND, PSZ);
88: VOID SaveWindowToFile(HWND);
89: SHORT IsPtInList(PPOINTL);
90: SHORT AddPtToList(PPOINTL);
91: BOOL IsPtCloseToLine(PPOINTL, PPOINTL, PPOINTL);
92: VOID SwapLong(PLONG, PLONG);
93:
94:
95: /* Exported functions */
96:
97: MRESULT EXPENTRY WndProc (HWND, USHORT, MPARAM, MPARAM);
98: MRESULT EXPENTRY AboutDlg (HWND, USHORT, MPARAM, MPARAM);
99: MRESULT EXPENTRY ColorsDlg (HWND, USHORT, MPARAM, MPARAM);
100: MRESULT EXPENTRY PelSizeDlg(HWND, USHORT, MPARAM, MPARAM);
101:
102:
103:
104:
105: /************************************************************************
106: *
107: * Global Variables
108: *
109: ************************************************************************/
110:
111: /* compute absolute value for arbitrary (in my case, LONG) number */
112: /* this is to avoid compiler warnings about data conversion */
113: #define L_ABS(x) (((x) > 0) ? (x) : (-(x)))
114:
115: typedef struct
116: {
117: HAB hab;
118: HMQ hMsgQ;
119: HWND hwndFrame;
120: HWND hwnd;
121:
122: BOOL fFirstTime; /* TRUE --> first time initialization of rcl */
123: RECTL rcl; /* dimensions of client rectangle */
124:
125: HPS hpsFat;
126: HDC hdcFat;
127: HBITMAP hbmFat;
128: HPS hpsFatShadow;
129: HDC hdcFatShadow;
130: HBITMAP hbmFatShadow;
131:
132: RECTL rclFatBM; /* dimensions of fatbits bitmap */
133: RECTL rclFat; /* dimensions of active fat bits grid */
134: LONG cxFatPel; /* width of fat pel */
135: LONG cyFatPel; /* height of fat pel */
136: LONG cxHalfFatPel;
137: LONG cyHalfFatPel;
138: USHORT usPelShape;
139:
140: MATRIXLF matlf; /* goes from window coords to fatpel coords */
141:
142: BOOL fRGB; /* TRUE --> color mode is RGB */
143: COLOR clrMathObj;
144: COLOR clrRenderedObj;
145: COLOR clrField;
146: COLOR clrCrossHair;
147: COLOR clrInterstice;
148: COLOR clrControlPoints;
149:
150: COLOR clrBlackIndex;
151: COLOR clrEditPel;
152:
153: USHORT usControlPointSymbol;
154:
155: BOOL fDisplayRenderedObj;
156: BOOL fDisplayMathObj;
157: BOOL fDisplayControlPoints;
158: BOOL fDisplayCrossHairs;
159: BOOL fDisplayPelBorder;
160: BOOL fRoundControlPoints;
161: BOOL fAutoRedraw;
162: USHORT usCurPrim;
163: USHORT usMix;
164:
165: LONG cptl;
166: PPOINTL pptl;
167: PPOINTL pptlTmp;
168:
169: BOOL fDraggingPelSize;
170: HPOINTER hptrDragSize;
171:
172: BOOL fDraggingPelColor;
173: HPOINTER hptrDragColor;
174:
175: SHORT sPtGrabbed;
176: BOOL fDraggingControlPoint;
177: LONG lHitPrecision;
178:
179: BOOL fEditPelColors;
180:
181: } GLOBALDATA;
182: GLOBALDATA global;
183:
184:
185:
186:
187: /************************************************************************
188: *
189: * main
190: *
191: * WinInitialize resizes our ring 2 stack, among other things, so
192: * we won't GP fault trying to do graphics. WinCreateMsgQueue defines
193: * us as a REAL PM app. (WINDOWAPI in .DEF file does also).
194: * Call a sub to register our window class and create a window.
195: * Loop over messages. Exit cleanly.
196: *
197: ************************************************************************/
198:
199: VOID cdecl
200: main()
201: {
202: QMSG qMsg;
203: int iRet = 0;
204:
205:
206: global.hab = WinInitialize(NULL);
207: global.hMsgQ = WinCreateMsgQueue(global.hab, 0);
208:
209: if (InitApp())
210: while (WinGetMsg( global.hab, (PQMSG)&qMsg, (HWND)NULL, 0, 0 ))
211: WinDispatchMsg( global.hab, (PQMSG)&qMsg );
212: else
213: iRet = -1;
214:
215: WinDestroyWindow( global.hwndFrame );
216: WinDestroyMsgQueue( global.hMsgQ );
217: WinTerminate( global.hab );
218: DosExit(EXIT_PROCESS, iRet);
219: }
220:
221:
222:
223:
224: /****************************************************************************
225: *
226: * InitGlobals
227: *
228: * Initialize global variables.
229: *
230: ****************************************************************************/
231:
232: BOOL FAR
233: InitGlobals()
234: {
235: global.fFirstTime = TRUE;
236:
237: global.rcl.xLeft = 0L;
238: global.rcl.yBottom = 0L;
239: global.rcl.xRight = 0L;
240: global.rcl.yTop = 0L;
241:
242: global.hpsFat = NULL;
243: global.hdcFat = NULL;
244: global.hbmFat = NULL;
245: global.hpsFatShadow = NULL;
246: global.hdcFatShadow = NULL;
247: global.hbmFatShadow = NULL;
248: global.rclFatBM.xLeft = 0L;
249: global.rclFatBM.yBottom = 0L;
250: global.rclFatBM.xRight = 0L;
251: global.rclFatBM.yTop = 0L;
252:
253: global.cxFatPel = 32L;
254: global.cyFatPel = 32L;
255: global.cxHalfFatPel = global.cxFatPel / 2L;
256: global.cyHalfFatPel = global.cyFatPel / 2L;
257: global.usPelShape = IDC_CIRCLE;
258:
259: global.fRGB = FALSE;
260: global.clrMathObj = CLR_BLUE;
261: global.clrRenderedObj = CLR_NEUTRAL;
262: global.clrField = CLR_CYAN;
263: global.clrCrossHair = CLR_DARKCYAN;
264: global.clrInterstice = CLR_BACKGROUND;
265: global.clrControlPoints = CLR_YELLOW;
266:
267: global.clrBlackIndex = CLR_ERROR;
268: global.clrEditPel = CLR_ERROR;
269:
270: global.usControlPointSymbol = MARKSYM_SOLIDDIAMOND;
271:
272: global.fDisplayRenderedObj = TRUE;
273: global.fDisplayMathObj = TRUE;
274: global.fDisplayControlPoints = TRUE;
275: global.fDisplayCrossHairs = TRUE;
276: global.fDisplayPelBorder = TRUE;
277: global.fRoundControlPoints = FALSE;
278: global.fAutoRedraw = TRUE;
279: global.usCurPrim = IDM_POLYLINE;
280: global.usMix = FM_OVERPAINT;
281:
282: global.fDraggingPelSize = FALSE;
283: global.fDraggingPelColor = FALSE;
284: global.fDraggingControlPoint = FALSE;
285: global.sPtGrabbed = NO_POINT;
286: global.lHitPrecision = 0L;
287:
288: global.fEditPelColors = FALSE;
289:
290: global.cptl = 0L;
291: global.pptl = global.pptlTmp = NULL;
292: if (DosAllocMem(&global.pptl, CPTLMAX * sizeof(POINTL), fPERM|PAG_COMMIT))
293: return FALSE;
294: if (DosAllocMem(&global.pptlTmp, CPTLMAX * sizeof(POINTL), fPERM|PAG_COMMIT))
295: return FALSE;
296:
297: return TRUE;
298: }
299:
300:
301:
302:
303: /****************************************************************************
304: *
305: * InitApp
306: *
307: * Register application window class and creates standard window.
308: *
309: ****************************************************************************/
310:
311: #define INIT_MENU_ITEM(val, var) \
312: TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var))
313:
314: BOOL FAR
315: InitApp()
316: {
317: char szTitle[24];
318: ULONG ctldata;
319: PID pid;
320: TID tid;
321: HSWITCH hsw;
322: static SWCNTRL swctl = { 0, 0, 0, 0, 0, SWL_VISIBLE,
323: SWL_JUMPABLE, "FatPels", 0 };
324:
325: if (!InitGlobals())
326: return FALSE;
327:
328:
329: /* Register Application Window Class */
330:
331: WinLoadString( global.hab, NULL, IDS_TITLE, sizeof(szTitle), (PCH)szTitle );
332: if ( !WinRegisterClass( global.hab, (PCH)szTitle, (PFNWP)WndProc,
333: CS_SIZEREDRAW, 0 ))
334: return FALSE;
335:
336:
337: /* Load the pointer to use when dragging pel size. */
338: if (!(global.hptrDragSize = WinLoadPointer( HWND_DESKTOP, NULL, IDR_DRAGSIZEPTR )))
339: return FALSE;
340:
341: /* Load the pointer to use when dragging pel color. */
342: if (!(global.hptrDragColor = WinLoadPointer( HWND_DESKTOP, NULL, IDR_DRAGCOLORPTR )))
343: return FALSE;
344:
345:
346: /* Create a window instance of class "FatPel" */
347:
348: ctldata = FCF_STANDARD &
349: ~(ULONG)(FCF_ACCELTABLE | FCF_TASKLIST);
350:
351: if (global.hwndFrame = WinCreateStdWindow(
352: HWND_DESKTOP, /* specify desktop as parent window */
353: WS_VISIBLE, /* window styles */
354: &ctldata, /* frame creation flags */
355: (PCH)szTitle, /* window class name */
356: (PCH)szTitle, /* name appearing in window caption */
357: 0L, /* */
358: (HMODULE)NULL, /* use current executable module id */
359: IDW_FATPEL, /* menu id */
360: (HWND FAR *)&global.hwnd /* window handle */
361: ))
362: {
363: INIT_MENU_ITEM(IDM_RENDEREDOBJ, global.fDisplayRenderedObj);
364: INIT_MENU_ITEM(IDM_MATHOBJ, global.fDisplayMathObj);
365: INIT_MENU_ITEM(IDM_CTLPOINTS, global.fDisplayControlPoints);
366: INIT_MENU_ITEM(IDM_CROSSHAIRS, global.fDisplayCrossHairs);
367: INIT_MENU_ITEM(IDM_PELBORDER, global.fDisplayPelBorder);
368: INIT_MENU_ITEM(IDM_ROUNDPOINTS, global.fRoundControlPoints);
369: INIT_MENU_ITEM(IDM_AUTOREDRAW, global.fAutoRedraw);
370: INIT_MENU_ITEM(IDM_EDITPELCOLORS, global.fEditPelColors);
371:
372: CHECK_MENU_ITEM(global.hwndFrame, global.usCurPrim);
373:
374:
375: /* Add ourselves to the switch list. */
376:
377: WinQueryWindowProcess(global.hwndFrame, &pid, &tid);
378: swctl.hwnd = global.hwndFrame;
379: swctl.idProcess = pid;
380: hsw = WinAddSwitchEntry(&swctl);
381:
382: return TRUE;
383: }
384: return FALSE;
385: }
386:
387:
388:
389:
390: /*************************************************************************
391: *
392: * WndProc
393: *
394: * Process messages for the window class.
395: *
396: ************************************************************************/
397:
398: MRESULT EXPENTRY
399: WndProc( hwnd, usMsg, mp1, mp2 )
400: HWND hwnd;
401: USHORT usMsg;
402: MPARAM mp1;
403: MPARAM mp2;
404: {
405: switch (usMsg)
406: {
407: case WM_CLOSE:
408: Close(hwnd);
409: break;
410:
411: case WM_COMMAND:
412: Command(hwnd, LOUSHORT(mp1));
413: break;
414:
415: case WM_PAINT:
416: {
417: HPS hps;
418:
419: if (global.fFirstTime)
420: {
421: SIZEF sizfx;
422:
423: hps = WinGetPS(hwnd);
424: GpiQueryMarkerBox(hps, &sizfx);
425: global.lHitPrecision = sizfx.cx / 0x20000L + 1L;
426: WinReleasePS(hps);
427:
428: UpdateSurfaceDims();
429: global.fFirstTime = FALSE;
430: }
431:
432: /* The small bitmap may have been resized since we last
433: * painted, in which case it will have been initialized to
434: * the field color. Therefore, we will render the mathematical
435: * object to make sure the right fatpels are there.
436: */
437: global.usMix = FM_OVERPAINT;
438: hps = WinBeginPaint(global.hwnd, NULL, NULL);
439: Paint(hps, CLEAR_BACKGROUND|RENDER_MATH_OBJ);
440: WinEndPaint(hps);
441: }
442: break;
443:
444: case WM_BUTTON1DOWN:
445: case WM_BUTTON2DOWN:
446: ButtonDown(hwnd, usMsg, mp1);
447: break;
448:
449: case WM_BUTTON1UP:
450: case WM_BUTTON2UP:
451: ButtonUp(hwnd, usMsg);
452: break;
453:
454: case WM_MOUSEMOVE:
455: MouseMove(hwnd, mp1);
456: break;
457:
458: case WM_SIZE:
459: UpdateSurfaceDims();
460: return( (MRESULT)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
461: break;
462:
463: default:
464: return( (MRESULT)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
465: break;
466: }
467:
468: return FALSE;
469: }
470:
471:
472:
473:
474: /************************************************************************
475: *
476: * MouseMove
477: *
478: ************************************************************************/
479:
480: VOID
481: MouseMove(hwnd, mp1)
482: HWND hwnd;
483: MPARAM mp1;
484: {
485: POINTL ptl;
486: HPS hps;
487:
488:
489: /* make sure we still have our pointer */
490: /* notice the hierarchy of pointer modes */
491:
492: if (global.fDraggingPelSize)
493: {
494: if (global.hptrDragSize)
495: WinSetPointer(HWND_DESKTOP,global.hptrDragSize);
496: }
497: else if (global.fEditPelColors)
498: {
499: if (global.hptrDragColor)
500: WinSetPointer(HWND_DESKTOP,global.hptrDragColor);
501: }
502: else
503: WinSetPointer(HWND_DESKTOP,
504: WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,FALSE));
505:
506:
507: if (global.fDraggingPelColor)
508: {
509: POINTL ptl, ptlFat;
510: HPS hps;
511:
512:
513: ptl.x = (LONG) LOUSHORT(mp1);
514: ptl.y = (LONG) HIUSHORT(mp1);
515:
516: /* letting the point go negative causes overflow errors */
517: if (ptl.x < 0)
518: ptl.x = 0;
519: if (ptl.y < 0)
520: ptl.y = 0;
521:
522: GetFatPelFromPt(&ptl, &ptlFat);
523: SetFatPel(&ptlFat, global.clrEditPel);
524:
525: hps = WinGetPS(hwnd);
526: Paint(hps, OVERRIDE_RENDERED_OBJ);
527: Paint(hps, IGNORED); /* this call just copies fatpels to the screen */
528: WinReleasePS(hps);
529: }
530: else if (global.fDraggingControlPoint)
531: {
532: ptl.x = (LONG) LOUSHORT(mp1);
533: ptl.y = (LONG) HIUSHORT(mp1);
534:
535: /* letting the point go negative causes overflow errors */
536: if (ptl.x < 0)
537: ptl.x = 0;
538: if (ptl.y < 0)
539: ptl.y = 0;
540:
541: if (global.sPtGrabbed != NO_POINT)
542: {
543: hps = WinGetPS(hwnd);
544: Paint(hps, OVERRIDE_RENDERED_OBJ);
545:
546: global.pptl[global.sPtGrabbed] = ptl;
547:
548: Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
549: WinReleasePS(hps);
550: }
551: }
552: }
553:
554:
555:
556:
557: /************************************************************************
558: *
559: * ButtonUp
560: *
561: ************************************************************************/
562:
563: VOID
564: ButtonUp(hwnd, usMsg)
565: HWND hwnd;
566: USHORT usMsg;
567: {
568: SHORT i;
569: HPS hps;
570:
571:
572: if (global.fDraggingPelColor)
573: {
574: global.fDraggingPelColor = FALSE;
575: WinSetCapture(HWND_DESKTOP, NULL);
576: }
577: else if (global.fDraggingControlPoint)
578: {
579: global.fDraggingControlPoint = FALSE;
580: WinSetCapture(HWND_DESKTOP, NULL);
581: if (global.sPtGrabbed != NO_POINT)
582: {
583: if (usMsg == WM_BUTTON2UP) /* remove point? */
584: {
585: hps = WinGetPS(hwnd);
586: Paint(hps, OVERRIDE_RENDERED_OBJ);
587:
588: /* squeeze out selected point */
589: if ((i = global.sPtGrabbed) < (SHORT)(global.cptl-1))
590: while (i < (SHORT)(global.cptl-1))
591: {
592: global.pptl[i] = global.pptl[i+1];
593: ++i;
594: }
595:
596: --global.cptl;
597: global.sPtGrabbed = NO_POINT;
598:
599: Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
600: WinReleasePS(hps);
601: }
602: else /* WM_BUTTON1UP */
603: global.sPtGrabbed = NO_POINT;
604: }
605: }
606: }
607:
608:
609:
610:
611: /************************************************************************
612: *
613: * ButtonDown
614: *
615: ************************************************************************/
616:
617: VOID
618: ButtonDown(hwnd, usMsg, mp1)
619: HWND hwnd;
620: USHORT usMsg;
621: MPARAM mp1;
622: {
623: if (global.fDraggingPelSize)
624: {
625: POINTS pt;
626: HPS hps;
627:
628: pt.x = LOUSHORT(mp1);
629: pt.y = HIUSHORT(mp1);
630: DragPelSize(hwnd, pt);
631: global.fDraggingPelSize = FALSE;
632:
633: WinSetPointer(HWND_DESKTOP,
634: WinQuerySysPointer(HWND_DESKTOP,SPTR_ARROW,FALSE));
635:
636: hps = WinGetPS(hwnd);
637: global.usMix = FM_OVERPAINT;
638: Paint(hps, CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
639: WinReleasePS(hps);
640: }
641: else if (global.fEditPelColors)
642: {
643: POINTL ptl, ptlFat;
644: HPS hps;
645:
646: global.fDraggingPelColor = TRUE;
647: WinSetCapture(HWND_DESKTOP, hwnd);
648:
649: ptl.x = (LONG) LOUSHORT(mp1);
650: ptl.y = (LONG) HIUSHORT(mp1);
651:
652: if (global.usMix != FM_XOR)
653: {
654: hps = WinGetPS(hwnd);
655: global.usMix = FM_XOR;
656: Paint(hps, CLEAR_BACKGROUND);
657: WinReleasePS(hps);
658: }
659:
660: if (usMsg == WM_BUTTON1DOWN)
661: global.clrEditPel = global.clrRenderedObj;
662: else
663: global.clrEditPel = global.clrField;
664:
665: GetFatPelFromPt(&ptl, &ptlFat);
666: SetFatPel(&ptlFat, global.clrEditPel);
667:
668: hps = WinGetPS(hwnd);
669: Paint(hps, OVERRIDE_RENDERED_OBJ);
670: Paint(hps, IGNORED); /* this call just copies fatpels to the screen */
671: WinReleasePS(hps);
672: }
673: else if (!global.fDraggingControlPoint)
674: {
675: POINTL ptl;
676: SHORT sNewPtGrabbed;
677: HPS hps;
678:
679: global.fDraggingControlPoint = TRUE;
680: WinSetCapture(HWND_DESKTOP, hwnd);
681:
682: ptl.x = (LONG) LOUSHORT(mp1);
683: ptl.y = (LONG) HIUSHORT(mp1);
684:
685: sNewPtGrabbed = IsPtInList(&ptl);
686:
687: if (global.usMix != FM_XOR)
688: {
689: hps = WinGetPS(hwnd);
690: global.usMix = FM_XOR;
691: Paint(hps, CLEAR_BACKGROUND);
692: WinReleasePS(hps);
693: }
694:
695: if (usMsg == WM_BUTTON1DOWN) /* add/move point? */
696: {
697: hps = WinGetPS(hwnd);
698:
699: if (sNewPtGrabbed != NO_POINT)
700: global.sPtGrabbed = sNewPtGrabbed;
701: Paint(hps, OVERRIDE_RENDERED_OBJ);
702:
703: if (sNewPtGrabbed == NO_POINT)
704: global.sPtGrabbed = AddPtToList(&ptl);
705: else
706: global.sPtGrabbed = sNewPtGrabbed;
707:
708: Paint(hps, CLEAR_FAT_BITMAP|RENDER_MATH_OBJ);
709: WinReleasePS(hps);
710:
711: if (global.sPtGrabbed == NO_POINT)
712: MyMessageBox(global.hwnd, "Cannot add any more points.");
713: }
714: else if (sNewPtGrabbed != NO_POINT)
715: global.sPtGrabbed = sNewPtGrabbed;
716: }
717: }
718:
719:
720:
721:
722: /************************************************************************
723: *
724: * GetFatPelFromPt
725: *
726: ************************************************************************/
727:
728: VOID
729: GetFatPelFromPt(pptl, pptlFat)
730: PPOINTL pptl;
731: PPOINTL pptlFat;
732: {
733: pptlFat->x = pptl->x / global.cxFatPel;
734: pptlFat->y = pptl->y / global.cyFatPel;
735: }
736:
737:
738:
739:
740: /************************************************************************
741: *
742: * SetFatPel
743: *
744: ************************************************************************/
745:
746: VOID
747: SetFatPel(pptl, clr)
748: PPOINTL pptl;
749: COLOR clr;
750: {
751: LINEBUNDLE lb;
752:
753: if (global.hpsFat)
754: {
755: lb.lColor = clr;
756: GpiSetAttrs(global.hpsFat, PRIM_LINE, LBB_COLOR, 0L, &lb);
757: GpiSetPel(global.hpsFat, pptl);
758: }
759: }
760:
761:
762:
763:
764: /************************************************************************
765: *
766: * IsPtInList
767: *
768: ************************************************************************/
769:
770: SHORT
771: IsPtInList(pptl)
772: PPOINTL pptl;
773: {
774: SHORT i;
775:
776:
777: /* try to find pptl in the points we already have */
778: for (i = 0; i < (SHORT)global.cptl; ++i)
779: if (((L_ABS(pptl->x - global.pptl[i].x)) <= global.lHitPrecision) &&
780: ((L_ABS(pptl->y - global.pptl[i].y)) <= global.lHitPrecision))
781: return i;
782:
783: /* couldn't find it */
784: return NO_POINT;
785: }
786:
787:
788:
789:
790: /************************************************************************
791: *
792: * AddPtToList
793: *
794: ************************************************************************/
795:
796: SHORT
797: AddPtToList(pptl)
798: PPOINTL pptl;
799: {
800: SHORT i, j;
801:
802: if (global.cptl < CPTLMAX)
803: {
804: /* check for new points lying on a line segment */
805: for (i = 0; i < (SHORT)(global.cptl-1L); ++i)
806: if (IsPtCloseToLine(&global.pptl[i], &global.pptl[i+1], pptl))
807: {
808: /* insert point between endpoints of nearest line segment */
809: for (j = (SHORT)global.cptl; j > i+1; --j)
810: global.pptl[j] = global.pptl[j - 1];
811: global.pptl[i+1] = *pptl;
812: ++global.cptl;
813: return i+1;
814: }
815:
816: /* append the point */
817:
818: i = (SHORT) global.cptl;
819: global.pptl[i] = *pptl;
820: ++global.cptl;
821: return i;
822: }
823:
824: return NO_POINT;
825: }
826:
827:
828:
829:
830: /************************************************************************
831: *
832: * IsPtCloseToLine
833: *
834: ************************************************************************/
835:
836: BOOL
837: IsPtCloseToLine(pptl1, pptl2, pptlTest)
838: PPOINTL pptl1;
839: PPOINTL pptl2;
840: PPOINTL pptlTest;
841: {
842: POINTL ptlLL, ptlUR;
843: LONG dx, dy, yIntercept, error;
844: LONG lBoxAdjustment;
845:
846:
847: /* find the bounding box of the line segment */
848:
849: ptlLL = *pptl1; /* assume line goes lower left to upper right */
850: ptlUR = *pptl2;
851: if (pptl1->x > pptl2->x)
852: SwapLong(&ptlLL.x, &ptlUR.x);
853: if (pptl1->y > pptl2->y)
854: SwapLong(&ptlLL.y, &ptlUR.y);
855:
856:
857: /* adjust the bounding box if it's too narrow */
858:
859: lBoxAdjustment = global.lHitPrecision/2L;
860:
861: dx = pptl2->x - pptl1->x;
862: if (L_ABS(dx) <= global.lHitPrecision)
863: {
864: ptlLL.x -= lBoxAdjustment;
865: ptlUR.x += lBoxAdjustment;
866: }
867: dy = pptl2->y - pptl1->y;
868: if (L_ABS(dy) <= global.lHitPrecision)
869: {
870: ptlLL.y -= lBoxAdjustment;
871: ptlUR.y += lBoxAdjustment;
872: }
873:
874:
875: /* see if the test point is in the bounding box of the line segment */
876:
877: if ((pptlTest->x >= ptlLL.x) &&
878: (pptlTest->x <= ptlUR.x) &&
879: (pptlTest->y >= ptlLL.y) &&
880: (pptlTest->y <= ptlUR.y))
881: {
882: /* test for special cases */
883:
884: if (dx == 0) /* vertical line */
885: {
886: return (L_ABS(pptlTest->x - pptl1->x) <= global.lHitPrecision);
887: }
888:
889: if (dy == 0) /* horizontal line */
890: {
891: return (L_ABS(pptlTest->y - pptl1->y) <= global.lHitPrecision);
892: }
893:
894:
895: /* test for general case */
896:
897: yIntercept = pptl1->y - (pptl1->x * dy) / dx;
898:
899: error = pptlTest->y - (pptlTest->x * dy / dx) - yIntercept;
900: if (L_ABS(error) <= global.lHitPrecision)
901: return TRUE;
902: }
903:
904: return FALSE;
905: }
906:
907:
908:
909:
910: /************************************************************************
911: *
912: * SwapLong
913: *
914: ************************************************************************/
915:
916: VOID
917: SwapLong(pl1, pl2)
918: PLONG pl1, pl2;
919: {
920: LONG lTmp;
921:
922: lTmp = *pl1;
923: *pl1 = *pl2;
924: *pl2 = lTmp;
925: }
926:
927:
928:
929:
930: /************************************************************************
931: *
932: * DragPelSize
933: *
934: * Set the dimensions of a fat pel by dragging a rectangle
935: * on the screen.
936: *
937: ************************************************************************/
938:
939: VOID
940: DragPelSize(hwnd, pt)
941: HWND hwnd;
942: POINTS pt;
943: {
944: TRACKINFO ti;
945:
946: WinSendMsg(global.hwndFrame, WM_QUERYTRACKINFO, (MPARAM)TF_MOVE, (MPARAM)&ti);
947:
948: ti.cxBorder = 1;
949: ti.cyBorder = 1;
950: ti.rclTrack.xLeft = (LONG)pt.x;
951: ti.rclTrack.yBottom = (LONG)pt.y;
952: ti.rclTrack.xRight = (LONG)pt.x;
953: ti.rclTrack.yTop = (LONG)pt.y;
954: ti.fs = TF_RIGHT | TF_TOP;
955: ti.ptlMinTrackSize.x = 1L;
956: ti.ptlMinTrackSize.y = 1L;
957:
958: if (WinTrackRect(hwnd, NULL, &ti))
959: {
960: global.cxFatPel = (ti.rclTrack.xRight - ti.rclTrack.xLeft) ;
961: global.cyFatPel = (ti.rclTrack.yTop - ti.rclTrack.yBottom);
962:
963: if (global.cxFatPel < 1L)
964: global.cxFatPel = 1L;
965:
966: if (global.cyFatPel < 1L)
967: global.cyFatPel = 1L;
968:
969: global.cxHalfFatPel = global.cxFatPel / 2L;
970: global.cyHalfFatPel = global.cyFatPel / 2L;
971:
972: UpdateSurfaceDims();
973: }
974: }
975:
976:
977:
978:
979: /************************************************************************
980: *
981: * Close
982: *
983: ************************************************************************/
984:
985: VOID
986: Close(hwnd)
987: HWND hwnd;
988: {
989: if (global.hptrDragSize)
990: WinDestroyPointer(global.hptrDragSize);
991: WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
992: }
993:
994:
995:
996:
997: /************************************************************************
998: *
999: * Command
1000: *
1001: * Dispatches menu commands to the proper handlers.
1002: *
1003: ************************************************************************/
1004:
1005: #define UPDATE_MENU_BOOL(var, val) \
1006: { \
1007: TOGGLE_BOOL((var)); \
1008: TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var)); \
1009: }
1010:
1011: #define UPDATE_MENU_LIST(var, val) \
1012: { \
1013: UNCHECK_MENU_ITEM(global.hwndFrame, (var)); \
1014: (var) = (val); \
1015: CHECK_MENU_ITEM(global.hwndFrame, (var)); \
1016: }
1017:
1018: VOID
1019: Command(hwnd, id)
1020: HWND hwnd;
1021: USHORT id;
1022: {
1023: BOOL fRedraw = FALSE;
1024: USHORT fsCmd = IGNORED;
1025:
1026:
1027: switch (id)
1028: {
1029: case IDM_SAVE:
1030: SaveWindowToFile(hwnd);
1031: break;
1032:
1033: case IDM_ABOUT:
1034: WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)AboutDlg, NULL,
1035: IDD_ABOUTDLG, NULL );
1036: break;
1037:
1038: case IDM_REDRAW:
1039: fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
1040: break;
1041:
1042: case IDM_SETPELSIZE:
1043: {
1044: LONG cxFatPel, cyFatPel;
1045:
1046: cxFatPel = global.cxFatPel;
1047: cyFatPel = global.cyFatPel;
1048:
1049: if (WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)PelSizeDlg, NULL,
1050: IDD_PELSIZEDLG, NULL ))
1051: {
1052: if ((cxFatPel == global.cxFatPel) &&
1053: (cyFatPel == global.cyFatPel))
1054: fsCmd = CLEAR_BACKGROUND;
1055: else
1056: fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
1057: fRedraw = TRUE;
1058: }
1059: }
1060: break;
1061:
1062: case IDM_DRAGPELSIZE:
1063: global.fDraggingPelSize = TRUE;
1064: break;
1065:
1066: case IDM_RENDEREDOBJ:
1067: UPDATE_MENU_BOOL(global.fDisplayRenderedObj, IDM_RENDEREDOBJ);
1068: fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
1069: fRedraw = TRUE;
1070: break;
1071:
1072: case IDM_MATHOBJ:
1073: UPDATE_MENU_BOOL(global.fDisplayMathObj, IDM_MATHOBJ);
1074: fsCmd = CLEAR_BACKGROUND;
1075: fRedraw = TRUE;
1076: break;
1077:
1078: case IDM_CTLPOINTS:
1079: UPDATE_MENU_BOOL(global.fDisplayControlPoints, IDM_CTLPOINTS);
1080: fsCmd = CLEAR_BACKGROUND;
1081: fRedraw = TRUE;
1082: break;
1083:
1084: case IDM_CROSSHAIRS:
1085: UPDATE_MENU_BOOL(global.fDisplayCrossHairs, IDM_CROSSHAIRS);
1086: fsCmd = CLEAR_BACKGROUND;
1087: fRedraw = TRUE;
1088: break;
1089:
1090: case IDM_PELBORDER:
1091: UPDATE_MENU_BOOL(global.fDisplayPelBorder, IDM_PELBORDER);
1092: fsCmd = CLEAR_BACKGROUND;
1093: fRedraw = TRUE;
1094: break;
1095:
1096: case IDM_ROUNDPOINTS:
1097: UPDATE_MENU_BOOL(global.fRoundControlPoints, IDM_ROUNDPOINTS);
1098: fsCmd = CLEAR_BACKGROUND;
1099: fRedraw = TRUE;
1100: break;
1101:
1102: case IDM_AUTOREDRAW:
1103: UPDATE_MENU_BOOL(global.fAutoRedraw, IDM_AUTOREDRAW);
1104: break;
1105:
1106: case IDM_NOPRIM:
1107: case IDM_POLYLINE:
1108: case IDM_POLYFILLET:
1109: case IDM_POLYSPLINE:
1110: case IDM_POINTARC:
1111: UPDATE_MENU_LIST(global.usCurPrim, id);
1112: fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
1113: fRedraw = TRUE;
1114: break;
1115:
1116: case IDM_SETCOLORS:
1117: if (WinDlgBox( HWND_DESKTOP, hwnd, (PFNWP)ColorsDlg, NULL,
1118: IDD_COLORSDLG, NULL ))
1119: {
1120: fsCmd = CLEAR_BACKGROUND|RENDER_MATH_OBJ;
1121: fRedraw = TRUE;
1122: }
1123: break;
1124:
1125: case IDM_EDITPELCOLORS:
1126: UPDATE_MENU_BOOL(global.fEditPelColors, IDM_EDITPELCOLORS);
1127: break;
1128:
1129: case IDM_CLEARALL:
1130: global.cptl = 0L;
1131: fsCmd = CLEAR_BACKGROUND|CLEAR_FAT_BITMAP|RENDER_MATH_OBJ;
1132: fRedraw = TRUE;
1133: break;
1134: }
1135:
1136: if ((global.fAutoRedraw && fRedraw) || (id == IDM_REDRAW))
1137: {
1138: HPS hps;
1139:
1140: hps = WinGetPS(hwnd);
1141: global.usMix = FM_OVERPAINT;
1142: Paint(hps, fsCmd);
1143: WinReleasePS(hps);
1144: }
1145: }
1146:
1147:
1148:
1149:
1150: /************************************************************************
1151: *
1152: * Paint
1153: *
1154: ************************************************************************/
1155:
1156: VOID
1157: Paint(hps, fsCmd)
1158: HPS hps;
1159: USHORT fsCmd;
1160: {
1161: HRGN hrgn, hrgnClipOld, hrgnT;
1162:
1163:
1164: /* Clear the unused part of the client rectangle to a hatch pattern. */
1165: if (fsCmd & CLEAR_BACKGROUND)
1166: EraseBackground(hps);
1167:
1168:
1169: /* Set up the color mode as the user has requested */
1170:
1171: if (global.fRGB)
1172: {
1173: GpiCreateLogColorTable(hps, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
1174: if (global.hpsFat)
1175: {
1176: GpiCreateLogColorTable(global.hpsFat, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
1177: GpiCreateLogColorTable(global.hpsFatShadow, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL);
1178: }
1179: }
1180: else
1181: if (global.hpsFat)
1182: {
1183: GpiCreateLogColorTable(global.hpsFat, LCOL_RESET, LCOLF_INDRGB, 0L, 0L, NULL);
1184: GpiCreateLogColorTable(global.hpsFatShadow, LCOL_RESET, LCOLF_INDRGB, 0L, 0L, NULL);
1185: global.clrBlackIndex = GpiQueryColorIndex(hps, 0L, 0x000000L);
1186: }
1187:
1188:
1189: if (global.usPelShape == IDC_CIRCLE)
1190: {
1191: ARCPARAMS arcp;
1192:
1193: arcp.lP = global.cxFatPel / 2L;
1194: arcp.lQ = global.cyFatPel / 2L;
1195: arcp.lR = 0L;
1196: arcp.lS = 0L;
1197:
1198: GpiSetArcParams(hps, &arcp);
1199: }
1200:
1201:
1202: /* set clipping rectangle to the fatbit surface */
1203:
1204: if ((hrgn = GpiCreateRegion(hps, 1L, &global.rcl)) != HRGN_ERROR)
1205: GpiSetClipRegion(hps, hrgn, &hrgnClipOld);
1206:
1207:
1208: if (fsCmd & CLEAR_BACKGROUND)
1209: {
1210: DrawGrid(hps);
1211:
1212: if (global.hpsFatShadow)
1213: {
1214: AREABUNDLE ab;
1215:
1216: /* clear shadow fatpel surface to background color */
1217: ab.lColor = global.clrField;
1218: GpiSetAttrs(global.hpsFatShadow, PRIM_AREA, ABB_COLOR, 0L, &ab);
1219: GpiBitBlt(global.hpsFatShadow, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY, NULL);
1220: }
1221: }
1222:
1223: if (global.fDisplayRenderedObj && !(fsCmd & OVERRIDE_RENDERED_OBJ))
1224: DisplayRenderedPels(hps, fsCmd);
1225:
1226: if (global.fDisplayControlPoints)
1227: {
1228: /* when rubberbanding with the rendered obj, newly drawn fatpels
1229: * can wipe out stationary control point markers, so we have to
1230: * redraw them all each time
1231: */
1232:
1233: if (global.fDisplayRenderedObj || (fsCmd & CLEAR_BACKGROUND))
1234: DisplayControlPoints(hps, global.cptl, global.pptl, global.usMix);
1235: else if (global.sPtGrabbed != NO_POINT)
1236: /* draw just the control point that moved */
1237: DisplayControlPoints(hps, 1L, global.pptl+global.sPtGrabbed, global.usMix);
1238: }
1239:
1240: if (global.fDisplayMathObj)
1241: DisplayMathematicalObject(hps, global.usMix);
1242:
1243: /* delete the clip region we set up */
1244:
1245: if (hrgnClipOld != HRGN_ERROR)
1246: GpiSetClipRegion(hps, hrgnClipOld, &hrgnT);
1247: if (hrgn != HRGN_ERROR)
1248: GpiDestroyRegion(hps, hrgn);
1249: }
1250:
1251:
1252:
1253:
1254: /************************************************************************
1255: *
1256: * DisplayMathematicalObject
1257: *
1258: ************************************************************************/
1259:
1260: VOID
1261: DisplayMathematicalObject(hps, usMix)
1262: HPS hps;
1263: USHORT usMix;
1264: {
1265: PPOINTL pptl;
1266: LINEBUNDLE lb;
1267:
1268: if (global.cptl > 0)
1269: {
1270: if (global.fRoundControlPoints)
1271: {
1272: RoundControlPoints(hps, global.cptl, global.pptl, global.pptlTmp,
1273: global.cxFatPel, global.cyFatPel);
1274: pptl = global.pptlTmp;
1275: }
1276: else
1277: pptl = global.pptl;
1278:
1279: /* draw line */
1280: lb.lColor = global.clrMathObj;
1281: lb.usMixMode = usMix;
1282: GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR|LBB_MIX_MODE, 0L, &lb);
1283: DrawPrimitive(hps, global.cptl, pptl);
1284: }
1285: }
1286:
1287:
1288:
1289:
1290: /************************************************************************
1291: *
1292: * DisplayControlPoints
1293: *
1294: ************************************************************************/
1295:
1296: VOID
1297: DisplayControlPoints(hps, cptl, pptl, usMix)
1298: HPS hps;
1299: LONG cptl;
1300: PPOINTL pptl;
1301: USHORT usMix;
1302: {
1303: PPOINTL pptlT;
1304: MARKERBUNDLE mb;
1305:
1306: if (cptl > 0)
1307: {
1308: if (global.fRoundControlPoints)
1309: {
1310: RoundControlPoints(hps, cptl, pptl, global.pptlTmp,
1311: global.cxFatPel, global.cyFatPel);
1312: pptlT = global.pptlTmp;
1313: }
1314: else
1315: pptlT = pptl;
1316:
1317:
1318: mb.lColor = global.clrControlPoints;
1319: mb.usMixMode = usMix;
1320: mb.usSymbol = global.usControlPointSymbol;
1321: GpiSetAttrs(hps, PRIM_MARKER, MBB_COLOR|MBB_MIX_MODE|MBB_SYMBOL, 0L, &mb);
1322:
1323: GpiPolyMarker(hps, cptl, pptlT);
1324: }
1325: }
1326:
1327:
1328:
1329:
1330: /************************************************************************
1331: *
1332: * EraseBackground
1333: *
1334: * Erase the unused part of the window to a hatch pattern.
1335: *
1336: ************************************************************************/
1337:
1338: VOID
1339: EraseBackground(hps)
1340: HPS hps;
1341: {
1342: RECTL rclClient, rclT;
1343: AREABUNDLE ab;
1344:
1345:
1346: WinQueryWindowRect(global.hwnd, &rclClient);
1347:
1348: ab.lColor = CLR_BLACK;
1349: ab.lBackColor = CLR_WHITE;
1350: ab.usSymbol = PATSYM_DIAG1;
1351: GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR|ABB_BACK_COLOR|ABB_SYMBOL,
1352: 0L, (PBUNDLE)&ab);
1353:
1354: if (global.rcl.yTop < rclClient.yTop)
1355: {
1356: rclT.xLeft = rclClient.xLeft;
1357: rclT.yBottom = global.rcl.yBottom;
1358: rclT.xRight = rclClient.xRight;
1359: rclT.yTop = rclClient.yTop;
1360: GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, NULL);
1361: }
1362:
1363: if (global.rcl.xRight < rclClient.xRight)
1364: {
1365: rclT.xLeft = global.rcl.xRight;
1366: rclT.yBottom = rclClient.yBottom;
1367: rclT.xRight = rclClient.xRight;
1368: rclT.yTop = global.rcl.yTop;
1369: GpiBitBlt(hps, NULL, 2L, (PPOINTL)&rclT, ROP_PATCOPY, NULL);
1370: }
1371:
1372: ab.usSymbol = PATSYM_SOLID;
1373: GpiSetAttrs(hps, PRIM_AREA, ABB_SYMBOL, 0L, (PBUNDLE)&ab);
1374: }
1375:
1376:
1377:
1378:
1379: /************************************************************************
1380: *
1381: * DrawGrid
1382: *
1383: ************************************************************************/
1384:
1385: VOID
1386: DrawGrid(hps)
1387: HPS hps;
1388: {
1389: AREABUNDLE ab;
1390: POINTL ptl;
1391: POINTL aptl[3];
1392:
1393:
1394: /* clear fatpel surface to background color */
1395: ab.lColor = global.clrInterstice;
1396: GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR, 0L, &ab);
1397: GpiBitBlt(hps, NULL, 2L, (PPOINTL)&global.rcl, ROP_PATCOPY, NULL);
1398:
1399:
1400: /* draw one pel in lower left corner */
1401:
1402: ptl.x = global.cxFatPel / 2L;
1403: ptl.y = global.cyFatPel / 2L;
1404: DrawOneFatPel(hps, &ptl, global.clrField);
1405:
1406:
1407: /* blt up first column then across -- we don't have to worry
1408: * about the edges because a clip region has been setup to do that.
1409: */
1410:
1411: aptl[0].x = 0L;
1412: aptl[0].y = global.cyFatPel;
1413: aptl[1].x = global.cxFatPel;
1414: aptl[2].x = 0L;
1415: aptl[2].y = 0L;
1416:
1417: while (aptl[0].y <= global.rcl.yTop)
1418: {
1419: aptl[1].y = aptl[0].y + aptl[0].y;
1420: GpiBitBlt(hps, hps, 3L, aptl, ROP_SRCCOPY, (LONG)NULL);
1421: aptl[0].y += aptl[1].y - aptl[0].y;
1422: }
1423:
1424: aptl[0].x = global.cxFatPel;
1425: aptl[0].y = 0L;
1426: aptl[1].y = global.rcl.yTop;
1427: aptl[2].x = 0L;
1428: aptl[2].y = 0L;
1429:
1430: while (aptl[0].x <= global.rcl.xRight)
1431: {
1432: aptl[1].x = aptl[0].x + aptl[0].x;
1433: GpiBitBlt(hps, hps, 3L, aptl, ROP_SRCCOPY, (LONG)NULL);
1434: aptl[0].x += aptl[1].x - aptl[0].x;
1435: }
1436: }
1437:
1438:
1439:
1440:
1441: /************************************************************************
1442: *
1443: * DisplayRenderedPels
1444: *
1445: ************************************************************************/
1446:
1447: VOID
1448: DisplayRenderedPels(hps, fsCmd)
1449: HPS hps;
1450: USHORT fsCmd;
1451: {
1452: LINEBUNDLE lb;
1453: AREABUNDLE ab;
1454: POINTL aptl[3];
1455:
1456: /* Call GPI to draw the current primitive into the small bitmap,
1457: * then fatbit it to the display.
1458: */
1459:
1460: if (global.hbmFat)
1461: {
1462: if (fsCmd & CLEAR_FAT_BITMAP)
1463: {
1464: /* clear fatpel surface to background color */
1465: ab.lColor = global.clrField;
1466: GpiSetAttrs(global.hpsFat, PRIM_AREA, ABB_COLOR, 0L, &ab);
1467: GpiBitBlt(global.hpsFat, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY, NULL);
1468: }
1469:
1470: if (fsCmd & RENDER_MATH_OBJ)
1471: {
1472: if (global.cptl > 0)
1473: {
1474: /* draw line */
1475: lb.lColor = global.clrRenderedObj;
1476: GpiSetAttrs(global.hpsFat, PRIM_LINE, LBB_COLOR, 0L, &lb);
1477: GpiSetModelTransformMatrix(global.hpsFat, 9L,
1478: &global.matlf, TRANSFORM_REPLACE);
1479: DrawPrimitive(global.hpsFat, global.cptl, global.pptl);
1480: GpiSetModelTransformMatrix(global.hpsFat, 0L, NULL, TRANSFORM_REPLACE);
1481: }
1482: }
1483:
1484: /* xor the new rendered bitmap into the shadow bitmap */
1485: *((PRECTL)&aptl[0]) = global.rclFat;
1486: aptl[2].x = 0L;
1487: aptl[2].y = 0L;
1488: GpiBitBlt(global.hpsFatShadow, global.hpsFat, 3L, aptl, ROP_SRCINVERT, NULL);
1489:
1490: /* fatbit object to the display */
1491: DrawFatPels(hps);
1492:
1493: /* get the new shadow bitmap */
1494: GpiBitBlt(global.hpsFatShadow, global.hpsFat, 3L, aptl, ROP_SRCCOPY, NULL);
1495: }
1496: }
1497:
1498:
1499:
1500:
1501: /************************************************************************
1502: *
1503: * DrawFatPels
1504: *
1505: ************************************************************************/
1506:
1507: VOID
1508: DrawFatPels(hps)
1509: HPS hps;
1510: {
1511: POINTL ptl, ptlCenter;
1512: LONG i, j;
1513: COLOR clr;
1514:
1515:
1516: /* if the pel size is 1,1, then just blt the small bitmap to the
1517: * display.
1518: */
1519:
1520: if ((global.cxFatPel == 1L) && (global.cyFatPel == 1L))
1521: {
1522: POINTL aptl[3];
1523:
1524: *((PRECTL)&aptl[0]) = global.rcl;
1525: aptl[2].x = 0L;
1526: aptl[2].y = 0L;
1527: GpiBitBlt(hps, global.hpsFat, 3L, aptl, ROP_SRCCOPY, 0L);
1528:
1529: return;
1530: }
1531:
1532: for (i = 0; i < global.rclFat.xRight; ++i)
1533: for (j = 0; j < global.rclFat.yTop; ++j)
1534: {
1535: ptl.x = i;
1536: ptl.y = j;
1537:
1538: clr = GpiQueryPel(global.hpsFatShadow, &ptl);
1539: if ((global.fRGB && (clr != 0x000000L)) ||
1540: (!global.fRGB && (clr != global.clrBlackIndex)))
1541: {
1542: clr = GpiQueryPel(global.hpsFat, &ptl);
1543: ptlCenter.x = (i * global.cxFatPel) + global.cxHalfFatPel;
1544: ptlCenter.y = (j * global.cyFatPel) + global.cyHalfFatPel;
1545: DrawOneFatPel(hps, &ptlCenter, clr);
1546: }
1547: }
1548: }
1549:
1550:
1551:
1552:
1553: /************************************************************************
1554: *
1555: * DrawOneFatPel
1556: *
1557: ************************************************************************/
1558:
1559: VOID
1560: DrawOneFatPel(hps, pptl, clr)
1561: HPS hps;
1562: PPOINTL pptl;
1563: COLOR clr;
1564: {
1565: POINTL ptl;
1566: LINEBUNDLE lb;
1567: AREABUNDLE ab;
1568:
1569:
1570: if (global.fDisplayPelBorder || global.fDisplayCrossHairs)
1571: {
1572: lb.lColor = global.clrCrossHair;
1573: GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
1574: }
1575:
1576: ab.lColor = clr;
1577: GpiSetAttrs(hps, PRIM_AREA, ABB_COLOR, 0L, &ab);
1578:
1579:
1580: switch (global.usPelShape)
1581: {
1582: case IDC_SQUARE:
1583: {
1584: POINTL ptlT;
1585: ULONG flCmd;
1586:
1587: if (global.fDisplayPelBorder)
1588: flCmd = DRO_OUTLINEFILL;
1589: else
1590: flCmd = DRO_FILL;
1591:
1592: ptlT.x = pptl->x - global.cxHalfFatPel;
1593: ptlT.y = pptl->y - global.cyHalfFatPel;
1594: GpiSetCurrentPosition(hps, &ptlT);
1595: ptlT.x = pptl->x + global.cxHalfFatPel;
1596: ptlT.y = pptl->y + global.cyHalfFatPel;
1597: GpiBox(hps, flCmd, &ptlT, 0L, 0L);
1598: }
1599: break;
1600:
1601: case IDC_DIAMOND:
1602: {
1603: POINTL aptlT[4];
1604: ULONG flCmd;
1605:
1606: if (global.fDisplayPelBorder)
1607: flCmd = BA_BOUNDARY;
1608: else
1609: flCmd = 0L;
1610:
1611: aptlT[0].x = pptl->x;
1612: aptlT[0].y = pptl->y - global.cyHalfFatPel;
1613: aptlT[1].x = pptl->x - global.cxHalfFatPel;
1614: aptlT[1].y = pptl->y;
1615: aptlT[2].x = pptl->x;
1616: aptlT[2].y = pptl->y + global.cyHalfFatPel;
1617: aptlT[3].x = pptl->x + global.cxHalfFatPel;
1618: aptlT[3].y = pptl->y;
1619:
1620: GpiSetCurrentPosition(hps, &aptlT[3]);
1621: GpiBeginArea(hps, flCmd);
1622: GpiPolyLine(hps, 4L, aptlT);
1623: GpiEndArea(hps);
1624: }
1625:
1626: break;
1627:
1628: case IDC_CIRCLE:
1629: {
1630: ULONG flCmd;
1631:
1632: if (global.fDisplayPelBorder)
1633: flCmd = DRO_OUTLINEFILL;
1634: else
1635: flCmd = DRO_FILL;
1636:
1637: GpiSetCurrentPosition(hps, pptl);
1638: GpiFullArc(hps, flCmd, 0x10000L);
1639: }
1640: break;
1641: }
1642:
1643:
1644: if (global.fDisplayCrossHairs)
1645: {
1646: /* draw cross in center of pel */
1647:
1648: ptl.x = pptl->x - global.cxHalfFatPel;
1649: ptl.y = pptl->y;
1650: GpiSetCurrentPosition(hps, &ptl);
1651: ptl.x = pptl->x + global.cxHalfFatPel;
1652: GpiPolyLine(hps, 1L, &ptl);
1653:
1654: ptl.x = pptl->x;
1655: ptl.y = pptl->y - global.cyHalfFatPel;
1656: GpiSetCurrentPosition(hps, &ptl);
1657: ptl.y = pptl->y + global.cyHalfFatPel;
1658: GpiPolyLine(hps, 1L, &ptl);
1659: }
1660: }
1661:
1662:
1663:
1664:
1665: /************************************************************************
1666: *
1667: * RoundControlPoints
1668: *
1669: ************************************************************************/
1670:
1671: VOID
1672: RoundControlPoints(hps, cptl, pptl1, pptl2, cx, cy)
1673: HPS hps;
1674: LONG cptl;
1675: PPOINTL pptl1;
1676: PPOINTL pptl2;
1677: LONG cx;
1678: LONG cy;
1679: {
1680: LONG cx2, cy2;
1681: LONG i;
1682: MATRIXLF matlf;
1683:
1684:
1685: /* copy the input buffer to the output/scratch buffer */
1686: for (i = 0; i < cptl; ++i)
1687: pptl2[i] = pptl1[i];
1688:
1689:
1690: /* set the transform, transform the points to device space (i.e. to
1691: * hpsFat dimensions), then restore the original transform
1692: */
1693: GpiQueryModelTransformMatrix(hps, 9L, &matlf);
1694: GpiSetModelTransformMatrix(hps, 9L, &global.matlf, TRANSFORM_REPLACE);
1695: GpiConvert(hps, CVTC_WORLD, CVTC_DEVICE, cptl, pptl2);
1696: GpiSetModelTransformMatrix(hps, 9L, &matlf, TRANSFORM_REPLACE);
1697:
1698:
1699: /* position each point in the center of its fatpel */
1700:
1701: cx2 = cx / 2L;
1702: cy2 = cy / 2L;
1703:
1704: for (i = 0; i < cptl; ++i, ++pptl2)
1705: {
1706: pptl2->x = pptl2->x * cx + cx2;
1707: pptl2->y = pptl2->y * cy + cy2;
1708: }
1709: }
1710:
1711:
1712:
1713:
1714: /************************************************************************
1715: *
1716: * ComputeTransform
1717: *
1718: ************************************************************************/
1719:
1720: VOID
1721: ComputeTransform(prcl1, prcl2)
1722: PRECTL prcl1;
1723: PRECTL prcl2;
1724: {
1725: LONG xExt1, yExt1;
1726: LONG xExt2, yExt2;
1727: FIXED xScale, yScale;
1728:
1729:
1730: xExt1 = prcl1->xRight - prcl1->xLeft;
1731: yExt1 = prcl1->yTop - prcl1->yBottom;
1732: xExt2 = prcl2->xRight - prcl2->xLeft;
1733: yExt2 = prcl2->yTop - prcl2->yBottom;
1734:
1735:
1736: /* If the rectangles are of exactly the same dimensions, then
1737: * set the unity transform. If not, compute the x and y scale
1738: * factors. Note that in world coordinates rectangles are
1739: * inclusive-inclusive, whereas in device coordinates they are
1740: * inclusive-exclusive. The extents of the destination are
1741: * therefore one pel too large as computed, so we subtract one
1742: * in the scale factor computation.
1743: */
1744:
1745: if (xExt1 == xExt2)
1746: xScale = 0x10000L;
1747: else
1748: xScale = ((xExt2-1L) * 0x10000L) / xExt1;
1749:
1750: if (yExt1 == yExt2)
1751: yScale = 0x10000L;
1752: else
1753: yScale = ((yExt2-1L) * 0x10000L) / yExt1;
1754:
1755:
1756: /* store the transform matrix for easy access */
1757:
1758: global.matlf.fxM11 = xScale;
1759: global.matlf.fxM12 = 0L;
1760: global.matlf. lM13 = 0L;
1761: global.matlf.fxM21 = 0L;
1762: global.matlf.fxM22 = yScale;
1763: global.matlf. lM23 = 0L;
1764: global.matlf. lM31 = 0L;
1765: global.matlf. lM32 = 0L;
1766: global.matlf. lM33 = 1L;
1767: }
1768:
1769:
1770:
1771:
1772: /************************************************************************
1773: *
1774: * DrawPrimitive
1775: *
1776: ************************************************************************/
1777:
1778: VOID
1779: DrawPrimitive(hps, cptl, pptl)
1780: HPS hps;
1781: LONG cptl;
1782: PPOINTL pptl;
1783: {
1784: switch (global.usCurPrim)
1785: {
1786: case IDM_NOPRIM:
1787: break;
1788:
1789: case IDM_POLYLINE:
1790: GpiSetCurrentPosition(hps, pptl);
1791: GpiPolyLine(hps, cptl-1L, pptl + 1);
1792: break;
1793:
1794: case IDM_POLYFILLET:
1795: if (cptl >= 3L)
1796: {
1797: GpiSetCurrentPosition(hps, pptl);
1798: GpiPolyFillet(hps, cptl-1L, pptl + 1);
1799: }
1800: break;
1801:
1802: case IDM_POLYSPLINE:
1803: if (cptl >= 4L)
1804: {
1805: LONG cptSlack; /* # points in pptl not usable by PolySpline */
1806:
1807: cptSlack = ((cptl-1L) % 3) + 1;
1808: GpiSetCurrentPosition( hps, pptl );
1809: GpiPolySpline( hps, cptl-cptSlack, pptl+1 );
1810: }
1811: break;
1812:
1813: case IDM_POINTARC:
1814: if (cptl >= 3L)
1815: {
1816: GpiSetCurrentPosition( hps, pptl );
1817: GpiPointArc( hps, pptl+1 );
1818: }
1819: break;
1820: }
1821: }
1822:
1823:
1824:
1825:
1826: /************************************************************************
1827: *
1828: * UpdateSurfaceDims
1829: *
1830: ************************************************************************/
1831:
1832: VOID
1833: UpdateSurfaceDims()
1834: {
1835: SIZEL size;
1836: static BITMAPINFOHEADER2 bminfo;
1837: AREABUNDLE ab;
1838:
1839:
1840: WinQueryWindowRect(global.hwnd, &global.rcl);
1841:
1842: /* compute size of small surface */
1843: global.rclFat.xLeft = 0L;
1844: global.rclFat.yBottom = 0L;
1845: global.rclFat.xRight = global.rcl.xRight / global.cxFatPel;
1846: global.rclFat.yTop = global.rcl.yTop / global.cyFatPel;
1847:
1848: /* compute size of fatpel version of small surface */
1849: global.rcl.xLeft = 0L;
1850: global.rcl.yBottom = 0L;
1851: global.rcl.xRight = global.rclFat.xRight * global.cxFatPel;
1852: global.rcl.yTop = global.rclFat.yTop * global.cyFatPel;
1853:
1854: ComputeTransform(&global.rcl, &global.rclFat);
1855:
1856: if ((global.rclFat.xRight <= global.rclFatBM.xRight) &&
1857: (global.rclFat.yTop <= global.rclFatBM.yTop))
1858: return;
1859:
1860:
1861:
1862: /* The new fatbits surface doesn't fit in the bitmap, so we
1863: * have to make a new one. If we don't have a DC or PS, make
1864: * those before making the bitmap. If we do have a bitmap,
1865: * delete it before making the new one.
1866: */
1867:
1868: global.rclFatBM = global.rclFat;
1869:
1870: if (global.hbmFat)
1871: {
1872: GpiSetBitmap(global.hpsFat, NULL);
1873: GpiDeleteBitmap(global.hbmFat);
1874: GpiSetBitmap(global.hpsFatShadow, NULL);
1875: GpiDeleteBitmap(global.hbmFatShadow);
1876: }
1877:
1878: if (!global.hdcFat)
1879: {
1880: global.hdcFat = DevOpenDC(global.hab, OD_MEMORY, "*", 0L, NULL, NULL);
1881: if (!global.hdcFat)
1882: goto usd_error;
1883:
1884: global.hdcFatShadow = DevOpenDC(global.hab, OD_MEMORY, "*", 0L, NULL, NULL);
1885: if (!global.hdcFatShadow)
1886: goto usd_error;
1887: }
1888:
1889: if (!global.hpsFat)
1890: {
1891: size.cx = 0L;
1892: size.cy = 0L;
1893: global.hpsFat = GpiCreatePS(global.hab, global.hdcFat, &size,
1894: PU_PELS|GPIT_MICRO|GPIA_ASSOC);
1895: if (!global.hpsFat)
1896: goto usd_error;
1897:
1898: global.hpsFatShadow = GpiCreatePS(global.hab, global.hdcFatShadow, &size,
1899: PU_PELS|GPIT_MICRO|GPIA_ASSOC);
1900: if (!global.hpsFatShadow)
1901: goto usd_error;
1902: }
1903:
1904: /* create bitmap with maximum color resolution (24-bit color) */
1905: bminfo.cbFix = sizeof(BITMAPINFOHEADER2);
1906: bminfo.cx = (USHORT) (global.rclFatBM.xRight - global.rclFatBM.xLeft);
1907: bminfo.cy = (USHORT) (global.rclFatBM.yTop - global.rclFatBM.yBottom);
1908: bminfo.cPlanes = 1L;
1909: bminfo.cBitCount = 24L;
1910: global.hbmFat = GpiCreateBitmap(global.hpsFat, &bminfo, 0L, 0L, 0L);
1911: if (!global.hbmFat)
1912: goto usd_error;
1913: GpiSetBitmap(global.hpsFat, global.hbmFat);
1914:
1915: /* create a shadow bitmap of the one we just created */
1916: bminfo.cbFix = sizeof(BITMAPINFOHEADER2);
1917: bminfo.cx = (USHORT) (global.rclFatBM.xRight - global.rclFatBM.xLeft);
1918: bminfo.cy = (USHORT) (global.rclFatBM.yTop - global.rclFatBM.yBottom);
1919: bminfo.cPlanes = 1L;
1920: bminfo.cBitCount = 24L;
1921: global.hbmFatShadow = GpiCreateBitmap(global.hpsFatShadow, &bminfo, 0L, 0L, 0L);
1922: if (!global.hbmFat)
1923: goto usd_error;
1924: GpiSetBitmap(global.hpsFatShadow, global.hbmFatShadow);
1925:
1926: /* clear bitmap surface to field color */
1927: ab.lColor = global.clrField;
1928: GpiSetAttrs(global.hpsFat, PRIM_AREA, ABB_COLOR, 0L, &ab);
1929: GpiBitBlt(global.hpsFat, NULL, 2L, (PPOINTL)&global.rclFat, ROP_PATCOPY, NULL);
1930:
1931: return;
1932:
1933:
1934: /* error exit point */
1935:
1936: usd_error:
1937: if (global.hpsFat)
1938: GpiDestroyPS(global.hpsFat);
1939: if (global.hpsFatShadow)
1940: GpiDestroyPS(global.hpsFatShadow);
1941: if (global.hdcFat)
1942: DevCloseDC(global.hdcFat);
1943: if (global.hdcFatShadow)
1944: DevCloseDC(global.hdcFatShadow);
1945:
1946: global.hpsFat = NULL;
1947: global.hdcFat = NULL;
1948: global.hpsFatShadow = NULL;
1949: global.hdcFatShadow = NULL;
1950: }
1951:
1952:
1953:
1954:
1955: /************************************************************************
1956: *
1957: * AboutDlg
1958: *
1959: * Process messages for the About box.
1960: *
1961: ************************************************************************/
1962:
1963: MRESULT EXPENTRY
1964: AboutDlg(hwnd, usMsg, mp1, mp2)
1965: HWND hwnd;
1966: USHORT usMsg;
1967: MPARAM mp1;
1968: MPARAM mp2;
1969: {
1970: switch (usMsg)
1971: {
1972: case WM_COMMAND:
1973: if (SHORT1FROMMP(mp1) == DID_OK)
1974: WinDismissDlg(hwnd, TRUE);
1975: else
1976: return FALSE;
1977: break;
1978:
1979: default:
1980: return (MRESULT)WinDefDlgProc(hwnd, usMsg, mp1, mp2);
1981: }
1982: return FALSE;
1983: }
1984:
1985:
1986:
1987:
1988: /************************************************************************
1989: *
1990: * PelSizeDlg
1991: *
1992: * Process messages for the Pel Size dialog box.
1993: *
1994: ************************************************************************/
1995:
1996: MRESULT EXPENTRY
1997: PelSizeDlg(hwnd, usMsg, mp1, mp2)
1998: HWND hwnd;
1999: USHORT usMsg;
2000: MPARAM mp1;
2001: MPARAM mp2;
2002: {
2003: BOOL fRet = FALSE;
2004:
2005: switch (usMsg)
2006: {
2007: case WM_INITDLG:
2008: MySetWindowLong(hwnd, IDC_PELWIDTH, global.cxFatPel);
2009: MySetWindowLong(hwnd, IDC_PELHEIGHT, global.cyFatPel);
2010: WinSendDlgItemMsg(hwnd, global.usPelShape,
2011: BM_SETCHECK, (MPARAM)TRUE, 0L);
2012: return FALSE;
2013: break;
2014:
2015: case WM_COMMAND:
2016: switch (SHORT1FROMMP(mp1))
2017: {
2018: case DID_OK:
2019: global.cxFatPel = MyGetWindowLong(hwnd, IDC_PELWIDTH);
2020: global.cyFatPel = MyGetWindowLong(hwnd, IDC_PELHEIGHT);
2021:
2022: if (global.cxFatPel < 1L)
2023: global.cxFatPel = 1L;
2024:
2025: if (global.cyFatPel < 1L)
2026: global.cyFatPel = 1L;
2027:
2028: global.cxHalfFatPel = global.cxFatPel / 2L;
2029: global.cyHalfFatPel = global.cyFatPel / 2L;
2030:
2031: global.usPelShape = (USHORT) WinSendDlgItemMsg(hwnd, IDC_SQUARE,
2032: BM_QUERYCHECKINDEX, 0L, 0L) + IDC_SQUARE;
2033:
2034:
2035: UpdateSurfaceDims();
2036:
2037: fRet = TRUE;
2038:
2039: /* fall through to some common code */
2040:
2041: case DID_CANCEL:
2042: WinDismissDlg(hwnd, fRet);
2043: break;
2044:
2045: default:
2046: return FALSE;
2047: }
2048: break;
2049:
2050: default:
2051: return (MRESULT)WinDefDlgProc(hwnd, usMsg, mp1, mp2);
2052: }
2053: return FALSE;
2054: }
2055:
2056:
2057:
2058:
2059: /************************************************************************
2060: *
2061: * ColorsDlg
2062: *
2063: * Process messages for the Set Colors dialog box.
2064: *
2065: ************************************************************************/
2066:
2067: MRESULT EXPENTRY
2068: ColorsDlg(hwnd, usMsg, mp1, mp2)
2069: HWND hwnd;
2070: USHORT usMsg;
2071: MPARAM mp1;
2072: MPARAM mp2;
2073: {
2074: BOOL fRet = FALSE;
2075: BOOL fRGB;
2076: COLOR clrMathObj;
2077: COLOR clrRenderedObj;
2078: COLOR clrField;
2079: COLOR clrCrossHair;
2080: COLOR clrInterstice;
2081: COLOR clrControlPoints;
2082:
2083: switch (usMsg)
2084: {
2085: case WM_INITDLG:
2086: if (global.fRGB)
2087: {
2088: MySetWindowLongHex(hwnd, IDC_MATHOBJ, global.clrMathObj);
2089: MySetWindowLongHex(hwnd, IDC_RENDEREDOBJ, global.clrRenderedObj);
2090: MySetWindowLongHex(hwnd, IDC_FIELD, global.clrField);
2091: MySetWindowLongHex(hwnd, IDC_CROSSHAIRS, global.clrCrossHair);
2092: MySetWindowLongHex(hwnd, IDC_INTERSTICE, global.clrInterstice);
2093: MySetWindowLongHex(hwnd, IDC_CTLPOINTS, global.clrControlPoints);
2094: }
2095: else
2096: {
2097: MySetWindowLong (hwnd, IDC_MATHOBJ, global.clrMathObj);
2098: MySetWindowLong (hwnd, IDC_RENDEREDOBJ, global.clrRenderedObj);
2099: MySetWindowLong (hwnd, IDC_FIELD, global.clrField);
2100: MySetWindowLong (hwnd, IDC_CROSSHAIRS, global.clrCrossHair);
2101: MySetWindowLong (hwnd, IDC_INTERSTICE, global.clrInterstice);
2102: MySetWindowLong (hwnd, IDC_CTLPOINTS, global.clrControlPoints);
2103: }
2104: WinSendDlgItemMsg(hwnd, IDC_RGB, BM_SETCHECK, MPFROM2SHORT(global.fRGB,0), 0L);
2105: return FALSE;
2106: break;
2107:
2108: case WM_CONTROL:
2109: if ((SHORT1FROMMP(mp1) == IDC_RGB) && (SHORT2FROMMP(mp1)== BN_CLICKED))
2110: {
2111: fRGB = !(SHORT)WinSendDlgItemMsg(hwnd, IDC_RGB, BM_QUERYCHECK, 0L, 0L);
2112: WinSendDlgItemMsg(hwnd, IDC_RGB, BM_SETCHECK, MPFROM2SHORT(fRGB,0), 0L);
2113:
2114: clrMathObj = MyGetWindowLong(hwnd, IDC_MATHOBJ);
2115: clrRenderedObj = MyGetWindowLong(hwnd, IDC_RENDEREDOBJ);
2116: clrField = MyGetWindowLong(hwnd, IDC_FIELD);
2117: clrCrossHair = MyGetWindowLong(hwnd, IDC_CROSSHAIRS);
2118: clrInterstice = MyGetWindowLong(hwnd, IDC_INTERSTICE);
2119: clrControlPoints = MyGetWindowLong(hwnd, IDC_CTLPOINTS);
2120:
2121: if (fRGB)
2122: {
2123: HPS hps;
2124:
2125: /* for each color, get rgb value from index */
2126:
2127: hps = WinGetPS(hwnd);
2128:
2129: clrMathObj = GpiQueryRGBColor(hps, 0L, clrMathObj);
2130: clrRenderedObj = GpiQueryRGBColor(hps, 0L, clrRenderedObj);
2131: clrField = GpiQueryRGBColor(hps, 0L, clrField);
2132: clrCrossHair = GpiQueryRGBColor(hps, 0L, clrCrossHair);
2133: clrInterstice = GpiQueryRGBColor(hps, 0L, clrInterstice);
2134: clrControlPoints = GpiQueryRGBColor(hps, 0L, clrControlPoints);
2135:
2136: WinReleasePS(hps);
2137:
2138: MySetWindowLongHex(hwnd, IDC_MATHOBJ, clrMathObj);
2139: MySetWindowLongHex(hwnd, IDC_RENDEREDOBJ, clrRenderedObj);
2140: MySetWindowLongHex(hwnd, IDC_FIELD, clrField);
2141: MySetWindowLongHex(hwnd, IDC_CROSSHAIRS, clrCrossHair);
2142: MySetWindowLongHex(hwnd, IDC_INTERSTICE, clrInterstice);
2143: MySetWindowLongHex(hwnd, IDC_CTLPOINTS, clrControlPoints);
2144: }
2145: else
2146: {
2147: HPS hps;
2148:
2149: /* for each color, get nearest index value from rgb */
2150:
2151: hps = WinGetPS(hwnd);
2152:
2153: clrMathObj = GpiQueryColorIndex(hps, 0L, clrMathObj);
2154: clrRenderedObj = GpiQueryColorIndex(hps, 0L, clrRenderedObj);
2155: clrField = GpiQueryColorIndex(hps, 0L, clrField);
2156: clrCrossHair = GpiQueryColorIndex(hps, 0L, clrCrossHair);
2157: clrInterstice = GpiQueryColorIndex(hps, 0L, clrInterstice);
2158: clrControlPoints = GpiQueryColorIndex(hps, 0L, clrControlPoints);
2159:
2160: WinReleasePS(hps);
2161:
2162: MySetWindowLong (hwnd, IDC_MATHOBJ, clrMathObj);
2163: MySetWindowLong (hwnd, IDC_RENDEREDOBJ, clrRenderedObj);
2164: MySetWindowLong (hwnd, IDC_FIELD, clrField);
2165: MySetWindowLong (hwnd, IDC_CROSSHAIRS, clrCrossHair);
2166: MySetWindowLong (hwnd, IDC_INTERSTICE, clrInterstice);
2167: MySetWindowLong (hwnd, IDC_CTLPOINTS, clrControlPoints);
2168: }
2169: }
2170: return (MRESULT)WinDefDlgProc(hwnd, usMsg, mp1, mp2);
2171: break;
2172:
2173: case WM_COMMAND:
2174: switch (SHORT1FROMMP(mp1))
2175: {
2176: case DID_OK:
2177: global.clrMathObj = MyGetWindowLong(hwnd, IDC_MATHOBJ);
2178: global.clrRenderedObj = MyGetWindowLong(hwnd, IDC_RENDEREDOBJ);
2179: global.clrField = MyGetWindowLong(hwnd, IDC_FIELD);
2180: global.clrCrossHair = MyGetWindowLong(hwnd, IDC_CROSSHAIRS);
2181: global.clrInterstice = MyGetWindowLong(hwnd, IDC_INTERSTICE);
2182: global.clrControlPoints = MyGetWindowLong(hwnd, IDC_CTLPOINTS);
2183:
2184: global.fRGB = (SHORT)WinSendDlgItemMsg(hwnd, IDC_RGB, BM_QUERYCHECK, 0L, 0L);
2185:
2186: fRet = TRUE;
2187:
2188: /* fall through to some common code */
2189:
2190: case DID_CANCEL:
2191: WinDismissDlg(hwnd, fRet);
2192: break;
2193:
2194: default:
2195: return FALSE;
2196: }
2197: break;
2198:
2199: default:
2200: return (MRESULT)WinDefDlgProc(hwnd, usMsg, mp1, mp2);
2201: }
2202: return FALSE;
2203: }
2204:
2205:
2206:
2207:
2208: /************************************************************************
2209: *
2210: * MySetWindowLong
2211: *
2212: * Sets the given control id to the value specified.
2213: *
2214: ************************************************************************/
2215:
2216: VOID
2217: MySetWindowLong(hWnd, id, num)
2218: HWND hWnd;
2219: USHORT id;
2220: LONG num;
2221: {
2222: char szStr[CCHSTR];
2223:
2224: sprintf((NPCH)szStr, "%ld", num);
2225: WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
2226: }
2227:
2228:
2229:
2230:
2231: /************************************************************************
2232: *
2233: * MySetWindowLongHex
2234: *
2235: * Sets the given control id to the value specified, in hexadecimal
2236: * notation.
2237: *
2238: ************************************************************************/
2239:
2240: VOID
2241: MySetWindowLongHex(hWnd, id, num)
2242: HWND hWnd;
2243: USHORT id;
2244: LONG num;
2245: {
2246: char szStr[CCHSTR];
2247:
2248: sprintf((NPCH)szStr, "0x%06lX", num);
2249: WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
2250: }
2251:
2252:
2253:
2254:
2255: /************************************************************************
2256: *
2257: * MyGetWindowLong
2258: *
2259: * Returns the value from the given control id.
2260: *
2261: ************************************************************************/
2262:
2263: LONG
2264: MyGetWindowLong(hWnd, id)
2265: HWND hWnd;
2266: USHORT id;
2267: {
2268: char szStr[CCHSTR];
2269: LONG num;
2270:
2271: WinQueryWindowText(WinWindowFromID(hWnd, id), CCHSTR, (PCH)szStr);
2272:
2273: if (strchr(szStr, 'x'))
2274: sscanf((NPCH)szStr, "0x%lx", &num);
2275: else if (strchr(szStr, 'X'))
2276: sscanf((NPCH)szStr, "0X%lx", &num);
2277: else
2278: sscanf((NPCH)szStr, "%ld", &num);
2279:
2280: return num;
2281: }
2282:
2283:
2284:
2285:
2286: /************************************************************************
2287: *
2288: * SaveWindowToFile
2289: *
2290: * Copy the bits from the client rectangle (actually, just the fatpel
2291: * area) into a bitmap, then save that bitmap.
2292: *
2293: ************************************************************************/
2294:
2295: VOID
2296: SaveWindowToFile(hwnd)
2297: HWND hwnd;
2298: {
2299: static BITMAPINFOHEADER2 bminfo;
2300: HBITMAP hbm;
2301: HPS hps;
2302: POINTL aptl[3];
2303:
2304: /* create bitmap in display's favorite format */
2305: bminfo.cbFix = sizeof(BITMAPINFOHEADER2);
2306: bminfo.cx = (USHORT) (global.rcl.xRight - global.rcl.xLeft);
2307: bminfo.cy = (USHORT) (global.rcl.yTop - global.rcl.yBottom);
2308: bminfo.cPlanes = 0L;
2309: bminfo.cBitCount = 0L;
2310: if (hbm = GpiCreateBitmap(global.hpsFat, &bminfo, 0L, 0L, 0L))
2311: {
2312: /* select it into the small bitmap's PS */
2313: GpiSetBitmap(global.hpsFat, hbm);
2314:
2315: /* GpiBitBlt from the window to the bitmap */
2316: hps = WinGetPS(hwnd);
2317:
2318: *((PRECTL)&aptl[0]) = global.rcl;
2319: aptl[2].x = 0L;
2320: aptl[2].y = 0L;
2321: GpiBitBlt(global.hpsFat, hps, 3L, aptl, ROP_SRCCOPY, 0L);
2322:
2323: WinReleasePS(hps);
2324:
2325: /* save the bitmap */
2326: WriteFile(hwnd, global.hpsFat);
2327: }
2328:
2329: /* deselect the bitmap and delete it */
2330: GpiSetBitmap(global.hpsFat, global.hbmFat);
2331: if (hbm)
2332: GpiDeleteBitmap(hbm);
2333: }
2334:
2335:
2336:
2337:
2338: /************************************************************************
2339: *
2340: * WriteFile
2341: *
2342: * Calls the OpenDlg's DlgFile function to ask the user what file name to
2343: * save under.
2344: *
2345: ************************************************************************/
2346:
2347: VOID
2348: WriteFile(hwnd, hps)
2349: HWND hwnd;
2350: HPS hps;
2351: {
2352: HFILE hfile;
2353: DLF dlf;
2354: BITMAPINFOHEADER2 bmih;
2355:
2356: dlf.rgbAction = DLG_SAVEDLG;
2357: dlf.rgbFlags = 0;
2358: dlf.phFile = &hfile;
2359: dlf.pszExt = "";
2360: dlf.pszAppName = "FatPel";
2361: dlf.pszInstructions = NULL;
2362: dlf.szFileName[0] = '\0';
2363: dlf.szOpenFile[0] = '\0';
2364: dlf.pszTitle = "Save Bitmap";
2365:
2366:
2367: switch (DlgFile(hwnd,&dlf))
2368: {
2369: case TDF_ERRMEM:
2370: case TDF_INVALID:
2371: MyMessageBox(hwnd, "Error opening file.");
2372: break;
2373:
2374: case TDF_NOSAVE:
2375: break;
2376:
2377: default:
2378: bmih.cbFix = sizeof(BITMAPINFOHEADER2);
2379: bmih.cx = (USHORT) global.rcl.xRight;
2380: bmih.cy = (USHORT) global.rcl.yTop;
2381: bmih.cPlanes = 0L;
2382: bmih.cBitCount = 0L;
2383:
2384: if (!WriteBMP(hfile, hps, &bmih))
2385: MyMessageBox(hwnd, "Error writing file.");
2386: }
2387: }
2388:
2389:
2390:
2391:
2392: /************************************************************************
2393: *
2394: * WriteBMP
2395: *
2396: * Write the bitmap out to a BMP format file. Write the file
2397: * header first, then the bitmap bits. Space for the header
2398: * and the bits is allocated. The file
2399: * will have been opened by the time this function is called,
2400: * and the file handle will be in the *pdlf structure.
2401: *
2402: ************************************************************************/
2403:
2404: BOOL
2405: WriteBMP(hfile, hps, pbmih)
2406: HFILE hfile;
2407: HPS hps; /* hps from which to get bitmap bits. */
2408: PBITMAPINFOHEADER2 pbmih; /* Bitmap information. */
2409: {
2410: ULONG cScans;
2411: ULONG ulSize; /* Number of bytes occupied by bitmap bits. */
2412: ULONG cbBMHdr; /* Size of bitmap header. */
2413: PBITMAPFILEHEADER2 pbfh; /* Pointer to private copy of bitmap info data. */
2414: ULONG cbWritten; /* Number of bytes written by DosWrite. */
2415: BOOL fRet = FALSE; /* Function return code. */
2416: PVOID pBits;
2417: int i; /* Generic loop index. */
2418: struct
2419: {
2420: LONG cPlanes;
2421: LONG cBitCount;
2422: } bmFmt;
2423:
2424:
2425: /*******************************************************************
2426: * If the bitmap was created with either 0 planes or 0 bits per
2427: * pixel, then query the format to write with. By asking for just
2428: * one format (two LONGs, or one instance of structure of bmFmt),
2429: * we'll get the device's favored format.
2430: *******************************************************************/
2431:
2432: if ((pbmih->cPlanes == 0) || (pbmih->cBitCount == 0))
2433: {
2434: if (!GpiQueryDeviceBitmapFormats(hps, 2L, (PLONG)&bmFmt))
2435: goto lfwrite_error_close_file;
2436: }
2437: else
2438: {
2439: bmFmt.cPlanes = pbmih->cPlanes;
2440: bmFmt.cBitCount = pbmih->cBitCount;
2441: }
2442:
2443:
2444: /*******************************************************************
2445: * Determine size of bitmap header. The header consists of a
2446: * a fixed-size part and a variable-length color table. The
2447: * latter has 2^cBitCount entries, each of which is sizeof(RGB)
2448: * bytes long. The exception is when cBitCount is 24, in which
2449: * case the color table is omitted because the pixels are direct
2450: * rgb values.
2451: *******************************************************************/
2452:
2453: i = (int) bmFmt.cBitCount;
2454: if (i == 24)
2455: cbBMHdr = 0;
2456: else
2457: for (cbBMHdr = sizeof(RGB); i > 0; --i)
2458: cbBMHdr *= 2;
2459: cbBMHdr += sizeof(BITMAPFILEHEADER);
2460:
2461:
2462: /*******************************************************************
2463: * Copy structure from input to work buffer. The call to
2464: * GpiQueryBitmapBits will have write-access to this, so we won't
2465: * let it have the user's data.
2466: *******************************************************************/
2467:
2468: pbfh = NULL;
2469: if (DosAllocMem((PPVOID)&pbfh, cbBMHdr, fPERM|PAG_COMMIT))
2470: goto lfwrite_error_close_file;
2471: pbfh->bmp2 = *pbmih;
2472: if ((pbmih->cPlanes == 0) || (pbmih->cBitCount))
2473: {
2474: pbfh->bmp2.cPlanes = (USHORT) bmFmt.cPlanes;
2475: pbfh->bmp2.cBitCount = (USHORT) bmFmt.cBitCount;
2476: }
2477:
2478:
2479: /*******************************************************************
2480: * Allocate space for the bitmap bits -- all of them at once.
2481: * The extra ULONG casts are there to force all the arithmetic
2482: * to be done in 32 bits.
2483: *******************************************************************/
2484:
2485: ulSize = (
2486: (
2487: (
2488: (ULONG)pbfh->bmp2.cBitCount
2489: * (ULONG)pbfh->bmp2.cx
2490: + 31L
2491: ) / 32L
2492: ) * (ULONG)pbfh->bmp2.cPlanes * 4L
2493: ) * (ULONG)pbfh->bmp2.cy;
2494:
2495: if (DosAllocMem((PPVOID)&pBits, ulSize, fPERM|PAG_COMMIT))
2496: goto lfwrite_error_free_header;
2497:
2498:
2499: /*******************************************************************
2500: * Tell GPI to give us the bits. The function returns the number
2501: * of scan lines of the bitmap that were copied. We want all of
2502: * them at once.
2503: *******************************************************************/
2504:
2505: cScans = GpiQueryBitmapBits( hps
2506: , 0L
2507: , (ULONG)pbfh->bmp2.cy
2508: , (PBYTE)pBits
2509: , (PBITMAPINFO2)&pbfh->bmp2);
2510: if (cScans != pbfh->bmp2.cy) /* compare with original number of scans */
2511: goto lfwrite_error_free_bits;
2512:
2513:
2514: /*******************************************************************
2515: * Fill in the extra header fields and write the header out to
2516: * the file.
2517: *******************************************************************/
2518:
2519: pbfh->usType = BFT_BMAP;
2520: pbfh->cbSize = ulSize + cbBMHdr;
2521: pbfh->xHotspot = pbfh->bmp2.cx / 2;
2522: pbfh->yHotspot = pbfh->bmp2.cy / 2;
2523: pbfh->offBits = cbBMHdr;
2524:
2525: if (DosWrite( hfile, (PVOID)pbfh, cbBMHdr, &cbWritten))
2526: goto lfwrite_error_free_bits;
2527: if (cbWritten != cbBMHdr)
2528: goto lfwrite_error_free_bits;
2529:
2530:
2531: /*******************************************************************
2532: * Write the bits out to the file.
2533: *******************************************************************/
2534:
2535: if (DosWrite( hfile, (PVOID)pBits, ulSize, &cbWritten))
2536: goto lfwrite_error_free_bits;
2537: if (cbWritten != ulSize)
2538: goto lfwrite_error_free_bits;
2539:
2540: fRet = TRUE; /* The bits are on the disk. */
2541:
2542:
2543: /*******************************************************************
2544: * Close the file, free the buffer space and leave. This is a
2545: * common exit point from the function. Since the same cleanup
2546: * operations need to be performed for such a large number of
2547: * possible error conditions, this is concise way to do the right
2548: * thing.
2549: *******************************************************************/
2550:
2551: lfwrite_error_free_bits:
2552: DosFreeMem(pBits);
2553: lfwrite_error_free_header:
2554: DosFreeMem(&pbfh);
2555: lfwrite_error_close_file:
2556: DosClose(hfile);
2557: return fRet;
2558: }
2559:
2560:
2561:
2562:
2563: /************************************************************************
2564: *
2565: * MyMessageBox
2566: *
2567: * Displays a message box with the given string. To simplify matters,
2568: * the box will always have the same title ("FatPel"), will always
2569: * have a single button ("Ok"), will always have an exclamation point
2570: * icon, and will always be application modal.
2571: *
2572: ************************************************************************/
2573:
2574: VOID
2575: MyMessageBox(hWnd, sz)
2576: HWND hWnd;
2577: PSZ sz;
2578: {
2579: static char *szTitle = "FatPel Application";
2580:
2581: WinMessageBox(HWND_DESKTOP, hWnd, sz, szTitle, NULL,
2582: MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
2583: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.