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