/* sf_generate.c * * Snowflake code by Raph Levien * */ #include #include #include #include #include #include #include #include #include #include #include "getopt.h" #include "sf.h" /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* defines */ #define MAX_A 256 #define MAX_B 128 #define COS_60_DEG 0.5000000 #define SIN_60_DEG 0.8660254 #define ROOT_3 1.7320508 #ifndef PI #define PI 3.1415927 #endif #define SCALE 3.6275987 /* = 2.0 *PI / ROOT_3 */ #define RAND_SEED 0x0601 #define MAX_HASH 256 #define MAX_FRONTIER 1024 #define HASH_SIZE 8 /* 1 2 3 4 5 6 7 8 */ #define HASH_MASK (HASH_SIZE-1) /* 0 1 2 3 4 5 6 7 */ #define HASH_BIT (1<cmd; } return cmd_TIMEOUT; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* bit hash */ static void hash_key( char* str ) { int len; int i; unsigned char ch; unsigned char h; len = strlen( str ); if ( len > MAX_HASH-1 ) len = MAX_HASH-1; memset( hash,0,MAX_HASH ); i = 0; do { ch = toupper( str[i] ); h = HEX( ch ); hash[ i / 2 ] |= ( h << ( 4 * ( i & 1 ) ) ); i++; } while ( i < len ); hash_n = i * HASH_FACTOR; hashptr = 0; } static int hash_bit( void ) { int bit; bit = ( ( hash[ hashptr / HASH_SIZE ] & ( HASH_BIT >> ( hashptr & HASH_MASK ) ) ) != 0 ); hashptr++; return bit; } static int hash_eof( void ) { return ( hashptr == hash_n ); } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* random number generation */ static void seed_rand( void ) { random_number = RAND_SEED; } static int next_rand( void ) { random_number = ( ( random_number << 1 ) & 0x7FFF | ( ( random_number >> 13 ) ^ ( random_number >> 14 ) ) & 0x0001 ); return random_number; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* colour a gray pixel, based on the value of the given bit */ static void fill( int a,int b,int bit ) { int i; float x, y, r2; /* x^2 + y^2 */ /* delete coord from frontier, if present. */ for ( i = 0; i < frontier_n; i++ ) if ( frontier[i].a == a && frontier[i].b == b ) frontier[i] = frontier[ --frontier_n ]; if ( bit ) { flake[a][b] = white; /* fill 6 neighbours */ add_if_gray( a + 1,b ); add_if_gray( a - 1,b ); add_if_gray( a - 1,b + 1 ); add_if_gray( a, b + 1 ); add_if_gray( a + 1,b - 1 ); add_if_gray( a, b - 1 ); /* calculate maximum pixel distance */ x = a + b * COS_60_DEG + 1.0; y = b * SIN_60_DEG + 1.0; r2 = x * x + y * y; if ( r2 > max_dist ) max_dist = r2; } else flake[a][b] = black; } /* Add to frontier, but only if gray and within the 30 degree slice. */ static void add_if_gray( int a,int b ) { int i; if ( a < 0 || b < 0 || b > a ) return; if ( flake[a][b] == gray ) { /* add coord to frontier if not already present. */ for ( i = 0; i < frontier_n; i++ ) if ( frontier[i].a == a && frontier[i].b == b ) return; frontier[ frontier_n ].a = a; frontier[ frontier_n ].b = b; frontier_n++; } } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static void build_snowflake( char* image ) { float s; /* scaling factor */ int o; /* offset */ int x, /* pixel column */ y; /* pixel row */ int* h, /* horizontal */ * v; /* vertical */ int a, /* hex coordinate, integer */ b; /* hex coordinate, integer */ s = image_size / ( SCALE * sqrt( max_dist + 1.0 ) ); o = -image_size / 2; /* vertical or horizontal symmetry? */ if ( symmetry == symmetry_VERTICAL ) { v = &x; h = &y; } else { v = &y; h = &x; } /* write the header lines */ write_image_header( image,image_size ); for ( x = 0; x < image_size; x++ ) { for ( y = 0; y < image_size; y++ ) { /* convert coordinates */ rect_to_hex( *h,*v,o,s,&a,&b ); /* write the pixel */ if ( ( a < 0 || a >= MAX_A ) || /* off image */ ( b < 0 || b >= MAX_B ) ) write_image_pixel( image,x,y,black_pixel ); else if ( flake[a][b] == white ) /* white */ write_image_pixel( image,x,y,white_pixel ); else if ( flake[a][b] == black ) /* black */ write_image_pixel( image,x,y,black_pixel ); else /* gray */ { if ( edges == edges_GRAY_SOLID ) write_image_pixel( image,x,y,GRAY_PIXEL ); else /* edges_GRAY_SOLID */ { if ( ( x ^ y ) & 1 ) write_image_pixel( image,x,y,black_pixel ); else write_image_pixel( image,x,y,white_pixel ); } } } } } /* convert a rectangular coordinate [x,y] to * a hexangular coordinate [a,b]. * * the x and y coordinates are offset and scaled. * * y b * * | / * + -- + -- + -- + + -- + -- + -- + * | | | | / / / / * + -- + -- + -- + ==> + -- + -- + -- + * | | | | / / / / * + -- + -- + -- + + -- + -- + -- + * | | | | / / / / * + -- + -- + -- + -- x + -- + -- + -- + -- a * * * the x axis and a axis are parallel */ static void rect_to_hex( int x,int y,int o,float s,int* a_,int* b_ ) { float c, /* triangular coordinate, real */ d; /* triangular coordinate, real */ int p, /* triangular coordinate, integer */ q; /* triangular coordinate, integer */ int a, /* hexangular coordinate */ b; /* hexangular coordinate */ int t; /* convert rectangular grid location (x,y) * to triangular grid location (p,q) */ c = ( x + o ) / ( s * SIN_60_DEG ); d = ( y + o ) / s ; d -= c * COS_60_DEG; p = 2 * floor( d ); q = floor( c ); if ( c - floor( c ) + d - floor( d ) >= 1.0 ) p++; /* convert triangular grid location (p,q) * to hex grid location (a,b) */ a = floor( ( 2 + q + p ) / 3.0 ); b = floor( ( 3 + 2*q - p ) / 6.0 ); /* apply hex symmetries */ if ( b < 0 ) { a = a + b; b = -b; } if ( a < 0 ) { a = -a; b = b - a; } if ( b < 0 ) { a = a + b; b = -b; } if ( b > a ) { t = a; a = b; b = t; } *a_ = a; *b_ = b; } /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */