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