#include #include #include #include #include #include #include "life.h" static HBITMAP MenuBitMap; static HMENU PatternMenu; static HDC MenuDC; static BITMAP MenuBitInfo; static HBITMAP *MenuPatterns; static char **Patterns; static char Pixie[] = { 1, 1, 1 }; static char *Cursor = Pixie; extern BOOL ReadAPatternFile( char *name, int i ) /************************************************ Read the pattern found in file "name", into pattern position "i" */ { FILE *io; int ch; char *array; char *pattern; int xdim,ydim; struct stat status; Patterns = realloc( Patterns, (i+1)*sizeof( Patterns[0] ) ); if( Patterns == NULL ) return( NoMemory() ); MenuPatterns = realloc( MenuPatterns, (i+1)* sizeof( MenuPatterns[0] ) ); if( MenuPatterns == NULL ) return( NoMemory() ); stat( name, &status ); if( status.st_size == 0 ) return( FALSE ); pattern = malloc( status.st_size ); if( pattern == NULL ) return( NoMemory() ); Patterns[i] = pattern; io = fopen( name, "r" ); if( io == NULL ) return( FALSE ); array = pattern+2; xdim = 0; ydim = 0; for( ;; ) { ch = fgetc( io ); if( ch == EOF ) break; if( ch == '\n' ) { ++ydim; pattern[0] = xdim; xdim = 0; } else { ++xdim; if( ch == ' ' || ch == '_' ) { *array = FALSE; } else { *array = TRUE; } ++array; } } fclose( io ); pattern[1] = ydim; if( pattern[0] == 0 || ydim == 0 ) { free( Patterns[i] ); return( FALSE ); } return( TRUE ); } extern BOOL ReadPatterns( void ) /******************************* Read in all the pattern files from disk. (*.LIF in the same directory LIFE.EXE) */ { char filename[_MAX_PATH]; char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; DIR *dir_handle; struct dirent *dir_entry; int i; GetModuleFileName( ThisInst, filename, _MAX_PATH ); _splitpath( filename, drive, dir, NULL, NULL ); _makepath( filename, drive, dir, "*", ".LIF" ); dir_handle = opendir( filename ); Patterns = malloc( sizeof( Patterns[0] ) ); Patterns[0] = &Pixie; MenuPatterns = malloc( 1 * sizeof( MenuPatterns[0] ) ); if( MenuPatterns == NULL ) return( NoMemory() ); i = 1; if( dir_handle != NULL ) { while( dir_entry = readdir( dir_handle ) ) { _makepath( filename, drive, dir, dir_entry->d_name, NULL ); if( !ReadAPatternFile( filename, i ) ) { Error( "Error reading file" ); return( FALSE ); } ++i; } } NumberPatterns = i; return( TRUE ); } extern void FreePatterns( void ) /******************************* Free up the patterns array, and corresponding bit maps */ { int i; if( MenuBitMap != (HBITMAP)0 ) DeleteObject( MenuBitMap ); for( i = 1; i < NumberPatterns; ++i ) { free( Patterns[i] ); } free( Patterns ); } extern void ReflectAboutXequalY( char *pattern ) /********************************************** Reflect an array "pattern" about the line x=y. */ { unsigned x_dim,y_dim; unsigned x,y; char *new; x_dim = *pattern++; y_dim = *pattern++; new = alloca( x_dim * y_dim + 2 ); *new++ = y_dim; *new++ = x_dim; for( x = 0; x < x_dim; x++ ) { for( y = 0; y < y_dim; y++ ) { new[ x*y_dim + y ] = pattern[ y*x_dim + x ]; } } new -= 2; pattern -= 2; for( x = 0; x < x_dim*y_dim + 2; ++x ) { pattern[ x ] = new[ x ]; } } extern void ReflectAboutYAxis( char *pattern ) /******************************************** Reflect an array about the Y axis. */ { unsigned x_dim,y_dim; unsigned x,y,xlate_x; char temp; x_dim = *pattern++; y_dim = *pattern++; for( x = 0; x < x_dim / 2; ++x ) { xlate_x = x_dim - x - 1; for( y = 0; y < y_dim; ++y ) { temp = pattern[ y * x_dim + x ]; pattern[ y * x_dim + x ] = pattern[ y * x_dim + xlate_x ]; pattern[ y * x_dim + xlate_x ] = temp; } } } extern void TransformPatterns( void (*rtn)(char *) ) /*************************************************** Transform each pattern array. "Rtn" is ReflectAboutYAxis or ReflectAboutXEqualY. */ { int i; for( i = 0; i < NumberPatterns; ++i ) { rtn( Patterns[i] ); } } static void LoadPatternFile( void ) /********************************** Load the pattern file named in "Buffer" into our pattern menu. */ { if( ReadAPatternFile( Buffer, NumberPatterns ) ) { ++NumberPatterns; CreatePatternMenu(); } } extern void WritePatternFile( void ) /*********************************** Write the selected region to a pattern file (Prompt for name) */ { pixels start_x, end_x; pixels start_y, end_y; pixels x, y; FILE *io; int rc; if( !GetFileName( "Save A Pattern File", TRUE, "*.LIF", Buffer, BUFSIZ ) ) return; if( !access( Buffer, F_OK ) ) { char buf[ _MAX_PATH + 100 ]; sprintf( buf, "Overwrite file %s?", Buffer ); rc = MessageBox( (HWND)0, buf, "Save A Pattern File", MB_YESNO | MB_ICONEXCLAMATION ); if( rc != IDYES ) return; } GetSelectedCoords( &start_x, &end_x, &start_y, &end_y ); io = fopen( Buffer, "w" ); if( io != NULL ) { for( y = start_y; y < end_y; ++y ) { for( x = start_x; x < end_x; ++x ) { if( CellPointer( x, y )->alive ) { fputc( 'X', io ); } else { fputc( '_', io ); } } fputc( '\n', io ); } fclose( io ); } LoadPatternFile(); } extern void LoadNewPattern( void ) /********************************* Load a new pattern file into the menu (Prompt for name) */ { if( GetFileName( "Read A Pattern File", FALSE, "*.LIF", Buffer, BUFSIZ ) ) { LoadPatternFile(); } } static HBITMAP CreateAMenuBitMap( char *pattern, pixels *total_height ) /********************************************************************** Create a bit map suitable for use in the Pattern menu based on "pattern". Add the height of the pattern to *total_height */ { HDC dc; HDC memory_dc; HBITMAP bit_map; pixels x,y; char dim_x, dim_y; pixels grid_x, grid_y; pixels size_x, size_y; dim_x = *pattern++; dim_y = *pattern++; size_x = MenuBitInfo.bmWidth * dim_x; size_y = MenuBitInfo.bmHeight * dim_y; if( size_x > MAX_MENU_SIZE_X ) size_x = MAX_MENU_SIZE_X; if( size_y > MAX_MENU_SIZE_Y ) size_y = MAX_MENU_SIZE_Y; grid_x = size_x / dim_x; grid_y = size_y / dim_y; if( grid_x == 0 ) grid_x = 1; if( grid_y == 0 ) grid_y = 1; if( size_x < MIN_MENU_SIZE_X ) size_x = MIN_MENU_SIZE_X; if( size_y < MIN_MENU_SIZE_Y ) size_y = MIN_MENU_SIZE_Y; dc = GetDC( WinHandle ); memory_dc = CreateCompatibleDC( dc ); bit_map = CreateCompatibleBitmap( dc, size_x, size_y ); SelectObject( memory_dc, bit_map ); PatBlt( memory_dc, 0, 0, size_x, size_y, WHITENESS ); for( y = 0; y < dim_y; ++y ) { for( x = 0; x < dim_x; ++x ) { if( *pattern++ ) { StretchBlt( memory_dc, x*grid_x, y*grid_y, grid_x, grid_y, MenuDC, 0, 0, MenuBitInfo.bmWidth, MenuBitInfo.bmHeight, SRCCOPY ); } } } DeleteDC( memory_dc ); ReleaseDC( WinHandle, dc ); *total_height += size_y; return( bit_map ); } extern void CreatePatternMenu( void ) /************************************ Create the "&Pattern" menu, based upon MenuPatterns[] */ { HDC dc; int i; HMENU menu; pixels menu_height; if( MenuBitMap == (HBITMAP)0 ) { MenuBitMap = LoadBitmap( ThisInst, "MenuBitMap" ); dc = GetDC( WinHandle ); MenuDC = CreateCompatibleDC( dc ); ReleaseDC( WinHandle, dc ); SelectObject( MenuDC, MenuBitMap ); GetObject( MenuBitMap, sizeof( BITMAP ), (LPSTR)&MenuBitInfo ); } menu = CreateMenu(); if( menu == (HMENU)0 ) { Error( "No room to create a new menu\n" ); return; } PatternMenu = menu; i = 0; menu_height = 0; for( ;; ) { MenuPatterns[i] = CreateAMenuBitMap( Patterns[i], &menu_height ); AppendMenu( PatternMenu, MF_BITMAP+MF_CHECKED, MENU_PATTERN+i, (LPSTR)(LONG)MenuPatterns[i] ); if( (i+1) == NumberPatterns ) break; if( menu_height > ScreenHeight / 3 ) { AppendMenu( PatternMenu, MF_MENUBARBREAK, 0, (LPSTR)(LONG)NULL ); menu_height = 0; } else { AppendMenu( PatternMenu, MF_SEPARATOR, 0, (LPSTR)(LONG)NULL ); } ++i; } AppendMenu( PatternMenu, MF_MENUBARBREAK, 0, (LPSTR)(LONG)NULL ); AppendMenu( PatternMenu, MF_STRING, MENU_ROTATE_P90, "&Rotate +90" ); AppendMenu( PatternMenu, MF_STRING, MENU_ROTATE_M90, "&Rotate -90" ); AppendMenu( PatternMenu, MF_STRING, MENU_ROTATE_180, "&Rotate 180" ); AppendMenu( PatternMenu, MF_STRING, MENU_REFLECT_X, "&Flip Top/Bottom" ); AppendMenu( PatternMenu, MF_STRING, MENU_REFLECT_Y, "&Flip Left/Right" ); ModifyMenu( GetMenu( WinHandle ), 2, MF_BYPOSITION | MF_POPUP, (UINT)PatternMenu, "&Pattern" ); } extern void SetCurrPattern( int i ) /********************************** Set the currently selected pattern to "i" */ { Cursor = Patterns[ i ]; } extern BOOL IsCurrPattern( int i ) /********************************* Is "i" the currently selected pattern? */ { return( Cursor == Patterns[ i ] ); } extern void DrawPattern( pixels pixel_x, pixels pixel_y, BOOL erase ) /******************************************************************** Draw the currently selected pattern at screen location (pixel_x,pixel_y). If "erase" is true, we wipe out a rectangle the size of the pattern. */ { pixels screen_x, screen_y; pixels x, y; pixels wrap_x, wrap_y; HDC dc; cell_ptr cell; char dim_x, dim_y; char *pattern; BOOL change; screen_x = pixel_x / BitInfo.bmWidth; screen_y = pixel_y / BitInfo.bmHeight; pattern = Cursor; dim_x = *pattern++; dim_y = *pattern++; change = FALSE; dc = GetDC( WinHandle ); for( y = 0; y < dim_y; ++y ) { for( x = 0; x < dim_x; ++x ) { wrap_x = screen_x + x; wrap_y = screen_y + y; WrapAround( &wrap_x, &wrap_y ); cell = CellPointer( wrap_x, wrap_y ); if( erase ) { change |= TurnOffCell( dc, cell, wrap_x, wrap_y ); } else if( *pattern ) { change |= TurnOnCell( dc, cell, wrap_x, wrap_y ); } ++pattern; } } ReleaseDC( WinHandle, dc ); if( change ) SetCaption(); }