Annotation of pmsdk/samples/petzold/chap10/life.c, revision 1.1.1.1

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:      }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.