|
|
1.1 root 1: /*--------------------------------------
2: LIFE.C -- John Conway's Game of Life
3: --------------------------------------*/
4:
5: #define INCL_WIN
6: #define INCL_GPI
7: #include <os2.h>
8: #include <stdlib.h>
9: #include <string.h>
10: #include "life.h"
11:
12: #define ID_TIMER 1
13:
14: MRESULT EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ;
15:
16: CHAR szClientClass [] = "Life" ;
17: HAB hab ;
18:
19: int main (void)
20: {
21: static ULONG flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU |
22: FCF_SIZEBORDER | FCF_MINMAX |
23: FCF_SHELLPOSITION | FCF_TASKLIST |
24: FCF_MENU | FCF_ICON ;
25: HMQ hmq ;
26: HWND hwndFrame, hwndClient ;
27: QMSG qmsg ;
28:
29: hab = WinInitialize (0) ;
30: hmq = WinCreateMsgQueue (hab, 0) ;
31:
32: WinRegisterClass (hab, szClientClass, ClientWndProc, CS_SIZEREDRAW, 0) ;
33:
34: hwndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE,
35: &flFrameFlags, szClientClass, NULL,
36: 0L, NULL, ID_RESOURCE, &hwndClient) ;
37:
38: while (WinGetMsg (hab, &qmsg, NULL, 0, 0))
39: WinDispatchMsg (hab, &qmsg) ;
40:
41: WinDestroyWindow (hwndFrame) ;
42: WinDestroyMsgQueue (hmq) ;
43: WinTerminate (hab) ;
44: return 0 ;
45: }
46:
47: VOID EnableMenuItem (HWND hwndMenu, SHORT idMenuItem, BOOL fEnable)
48: {
49: WinSendMsg (hwndMenu, MM_SETITEMATTR,
50: MPFROM2SHORT (idMenuItem, TRUE),
51: MPFROM2SHORT (MIA_DISABLED, fEnable ? 0 : MIA_DISABLED)) ;
52: }
53:
54: VOID ErrorMsg (HWND hwnd, CHAR *szMessage)
55: {
56: WinMessageBox (HWND_DESKTOP, hwnd, szMessage, szClientClass, 0,
57: MB_OK | MB_ICONEXCLAMATION) ;
58: }
59:
60: VOID DrawCell (HPS hps, SHORT x, SHORT y, SHORT cxCell, SHORT cyCell,
61: BYTE bCell)
62: {
63: RECTL rcl ;
64:
65: rcl.xLeft = x * cxCell ;
66: rcl.yBottom = y * cyCell ;
67: rcl.xRight = rcl.xLeft + cxCell - 1 ;
68: rcl.yTop = rcl.yBottom + cyCell - 1 ;
69:
70: WinFillRect (hps, &rcl, bCell & 1 ? CLR_NEUTRAL : CLR_BACKGROUND) ;
71: }
72:
73: VOID DoGeneration (HPS hps, PBYTE pbGrid, SHORT xNumCells, SHORT yNumCells,
74: SHORT cxCell, SHORT cyCell)
75: {
76: SHORT x, y, sSum ;
77:
78: for (y = 0 ; y < yNumCells - 1 ; y++)
79: for (x = 0 ; x < xNumCells ; x++)
80: {
81: if (x == 0 || x == xNumCells - 1 || y == 0)
82: *pbGrid |= *pbGrid << 4 ;
83: else
84: {
85: sSum = (*(pbGrid - 1) + // Left
86: *(pbGrid - xNumCells - 1) + // Lower Left
87: *(pbGrid - xNumCells ) + // Lower
88: *(pbGrid - xNumCells + 1)) // Lower Right
89: >> 4 ;
90:
91: sSum += *(pbGrid + 1) + // Right
92: *(pbGrid + xNumCells + 1) + // Upper Right
93: *(pbGrid + xNumCells ) + // Upper
94: *(pbGrid + xNumCells - 1) ; // Upper Left
95:
96: sSum = (sSum | *pbGrid) & 0x0F ;
97:
98: *pbGrid <<= 4 ;
99:
100: if (sSum == 3)
101: *pbGrid |= 1 ;
102:
103: if ((*pbGrid & 1) != *pbGrid >> 4)
104: DrawCell (hps, x, y, cxCell, cyCell, *pbGrid) ;
105: }
106: pbGrid++ ;
107: }
108: }
109:
110: VOID DisplayGenerationNum (HPS hps, SHORT xGen, SHORT yGen, LONG lGeneration)
111: {
112: static CHAR szBuffer [24] = "Generation " ;
113: POINTL ptl ;
114:
115: ptl.x = xGen ;
116: ptl.y = yGen ;
117:
118: ltoa (lGeneration, szBuffer + 11, 10) ;
119:
120: GpiSavePS (hps) ;
121:
122: GpiSetBackMix (hps, BM_OVERPAINT) ;
123: GpiCharStringAt (hps, &ptl, (LONG) strlen (szBuffer), szBuffer) ;
124:
125: GpiRestorePS (hps, -1L) ;
126: }
127:
128: MRESULT EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
129: {
130: static BOOL fTimerGoing ;
131: static HWND hwndMenu ;
132: static LONG lGeneration ;
133: static SEL selGrid ;
134: static SHORT cxChar, cyChar, cyDesc, cxClient, cyClient, xGenNum, yGenNum,
135: cxCell, cyCell, xNumCells, yNumCells, sCellScale = 1 ;
136: FONTMETRICS fm ;
137: HPS hps ;
138: PBYTE pbGrid ;
139: POINTL ptl ;
140: SHORT x, y ;
141:
142: switch (msg)
143: {
144: case WM_CREATE:
145: hps = WinGetPS (hwnd) ;
146: GpiQueryFontMetrics (hps, (LONG) sizeof fm, &fm) ;
147: cxChar = (SHORT) fm.lAveCharWidth ;
148: cyChar = (SHORT) fm.lMaxBaselineExt ;
149: cyDesc = (SHORT) fm.lMaxDescender ;
150: WinReleasePS (hps) ;
151:
152: hwndMenu = WinWindowFromID (
153: WinQueryWindow (hwnd, QW_PARENT, FALSE),
154: FID_MENU) ;
155: return 0 ;
156:
157: case WM_SIZE:
158: if (selGrid)
159: {
160: DosFreeSeg (selGrid) ;
161: selGrid = 0 ;
162: }
163:
164: if (fTimerGoing)
165: {
166: WinStopTimer (hab, hwnd, ID_TIMER) ;
167: fTimerGoing = FALSE ;
168: }
169:
170: cxClient = SHORT1FROMMP (mp2) ;
171: cyClient = SHORT2FROMMP (mp2) ;
172:
173: xGenNum = cxChar ;
174: yGenNum = cyClient - cyChar + cyDesc ;
175:
176: cxCell = cxChar * 2 / sCellScale ;
177: cyCell = cyChar / sCellScale ;
178:
179: xNumCells = cxClient / cxCell ;
180: yNumCells = (cyClient - cyChar) / cyCell ;
181:
182: if (xNumCells <= 0 || yNumCells <= 0)
183: {
184: ErrorMsg (hwnd, "Not enough room for even one cell.") ;
185: }
186:
187: else if ((LONG) xNumCells * yNumCells > 65536L)
188: {
189: ErrorMsg (hwnd, "More than 64K cells not supported.") ;
190: }
191:
192: else if (DosAllocSeg (xNumCells * yNumCells, &selGrid, 0))
193: {
194: ErrorMsg (hwnd, "Not enough memory for this many cells.") ;
195: selGrid = 0 ;
196: }
197:
198: else
199: {
200: pbGrid = MAKEP (selGrid, 0) ;
201:
202: for (y = 0 ; y < yNumCells ; y++)
203: for (x = 0 ; x < xNumCells ; x++)
204: *pbGrid++ = 0 ;
205: }
206:
207: EnableMenuItem (hwndMenu, IDM_SIZE, TRUE) ;
208: EnableMenuItem (hwndMenu, IDM_START, selGrid != 0) ;
209: EnableMenuItem (hwndMenu, IDM_STOP, FALSE) ;
210: EnableMenuItem (hwndMenu, IDM_STEP, selGrid != 0) ;
211: EnableMenuItem (hwndMenu, IDM_CLEAR, selGrid != 0) ;
212:
213: lGeneration = 0 ;
214: return 0 ;
215:
216: case WM_BUTTON1DOWN:
217: x = MOUSEMSG(&msg)->x / cxCell ;
218: y = MOUSEMSG(&msg)->y / cyCell ;
219:
220: if (selGrid && !fTimerGoing && x < xNumCells && y < yNumCells)
221: {
222: pbGrid = MAKEP (selGrid, 0) ;
223:
224: hps = WinGetPS (hwnd) ;
225:
226: DrawCell (hps, x, y, cxCell, cyCell,
227: *(pbGrid + y * xNumCells + x) ^= 1) ;
228:
229: WinReleasePS (hps) ;
230: }
231: else
232: WinAlarm (HWND_DESKTOP, WA_WARNING) ;
233: break ;
234:
235: case WM_COMMAND:
236: switch (COMMANDMSG(&msg)->cmd)
237: {
238: case IDM_LARGE:
239: case IDM_SMALL:
240: case IDM_TINY:
241: WinSendMsg (hwndMenu, MM_SETITEMATTR,
242: MPFROM2SHORT (sCellScale, TRUE),
243: MPFROM2SHORT (MIA_CHECKED, 0)) ;
244:
245: sCellScale = COMMANDMSG(&msg)->cmd ;
246:
247: WinSendMsg (hwndMenu, MM_SETITEMATTR,
248: MPFROM2SHORT (sCellScale, TRUE),
249: MPFROM2SHORT (MIA_CHECKED, MIA_CHECKED)) ;
250:
251: WinSendMsg (hwnd, WM_SIZE, NULL,
252: MPFROM2SHORT (cxClient, cyClient)) ;
253:
254: WinInvalidateRect (hwnd, NULL, FALSE) ;
255: return 0 ;
256:
257: case IDM_START:
258: if (!WinStartTimer (hab, hwnd, ID_TIMER, 1))
259: {
260: ErrorMsg (hwnd, "Too many clocks or timers.") ;
261: }
262: else
263: {
264: fTimerGoing = TRUE ;
265:
266: EnableMenuItem (hwndMenu, IDM_SIZE, FALSE) ;
267: EnableMenuItem (hwndMenu, IDM_START, FALSE) ;
268: EnableMenuItem (hwndMenu, IDM_STOP, TRUE) ;
269: EnableMenuItem (hwndMenu, IDM_STEP, FALSE) ;
270: EnableMenuItem (hwndMenu, IDM_CLEAR, FALSE) ;
271: }
272: return 0 ;
273:
274: case IDM_STOP:
275: WinStopTimer (hab, hwnd, ID_TIMER) ;
276: fTimerGoing = FALSE ;
277:
278: EnableMenuItem (hwndMenu, IDM_SIZE, TRUE) ;
279: EnableMenuItem (hwndMenu, IDM_START, TRUE) ;
280: EnableMenuItem (hwndMenu, IDM_STOP, FALSE) ;
281: EnableMenuItem (hwndMenu, IDM_STEP, TRUE) ;
282: EnableMenuItem (hwndMenu, IDM_CLEAR, TRUE) ;
283: return 0 ;
284:
285: case IDM_STEP:
286: WinSendMsg (hwnd, WM_TIMER, NULL, NULL) ;
287: return 0 ;
288:
289: case IDM_CLEAR:
290: lGeneration = 0L ;
291:
292: pbGrid = MAKEP (selGrid, 0) ;
293:
294: for (y = 0 ; y < yNumCells ; y++)
295: for (x = 0 ; x < xNumCells ; x++)
296: *pbGrid++ = 0 ;
297:
298: WinInvalidateRect (hwnd, NULL, FALSE) ;
299: return 0 ;
300: }
301: break ;
302:
303: case WM_TIMER:
304: hps = WinGetPS (hwnd) ;
305:
306: DisplayGenerationNum (hps, xGenNum, yGenNum, ++lGeneration) ;
307:
308: pbGrid = MAKEP (selGrid, 0) ;
309:
310: DoGeneration (hps, pbGrid, xNumCells, yNumCells, cxCell, cyCell);
311:
312: WinReleasePS (hps) ;
313: return 0 ;
314:
315: case WM_PAINT:
316: hps = WinBeginPaint (hwnd, NULL, NULL) ;
317: GpiErase (hps) ;
318:
319: if (selGrid)
320: {
321: for (x = 1 ; x <= xNumCells ; x++)
322: {
323: ptl.x = cxCell * x - 1 ;
324: ptl.y = 0 ;
325: GpiMove (hps, &ptl) ;
326:
327: ptl.y = cyCell * yNumCells - 1 ;
328: GpiLine (hps, &ptl) ;
329: }
330:
331: for (y = 1 ; y <= yNumCells ; y++)
332: {
333: ptl.x = 0 ;
334: ptl.y = cyCell * y - 1 ;
335: GpiMove (hps, &ptl) ;
336:
337: ptl.x = cxCell * xNumCells - 1 ;
338: GpiLine (hps, &ptl) ;
339: }
340:
341: pbGrid = MAKEP (selGrid, 0) ;
342:
343: for (y = 0 ; y < yNumCells ; y++)
344: for (x = 0 ; x < xNumCells ; x++)
345: if (*pbGrid++)
346: DrawCell (hps, x, y, cxCell, cyCell,
347: *(pbGrid - 1)) ;
348:
349: DisplayGenerationNum (hps, xGenNum, yGenNum, lGeneration) ;
350: }
351: WinEndPaint (hps) ;
352: return 0 ;
353:
354: case WM_DESTROY:
355: if (fTimerGoing)
356: WinStopTimer (hab, hwnd, ID_TIMER) ;
357:
358: if (selGrid)
359: DosFreeSeg (selGrid) ;
360:
361: return 0 ;
362: }
363: return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
364: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.