|
|
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.