This repository has been archived on 2024-12-16. You can view files and clone it, but cannot push or open issues or pull requests.
CodeBlocksPortable/WATCOM/samples/win/life/patterns.c

423 lines
11 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <direct.h>
#include <malloc.h>
#include <sys/stat.h>
#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();
}