#include #include #include #include #include #include #include "suzie_maths.h" #include "suzie_particle2.h" //#include "suzie_openGL.h" /* Initializes a 2-D viewing area, background is white, drawing colour red */ void initialize( void ) { //Set the background colour to white glClearColor( 1.0, 1.0, 1.0, 1.0 ); //Default drawing colour set to red glColor3f( 1.0, 0.0, 0.0 ); //Set up viewing area for a projection viewing area, (frustum) glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluOrtho2D( 0.0, SCREEN, 0.0, SCREEN ); glMatrixMode( GL_MODELVIEW ); } /******************************************************** * Takes the current height array, and draws the terrain *******************************************************/ void draw_terrain( Particle_list no_particles[NUM_STEPS] ) { int count, count_particles; Particle *current; glClear( GL_COLOR_BUFFER_BIT ); /* Step through the particle array, drawing all the particles */ for( count = 0; count < NUM_STEPS; count++ ) { current = no_particles[count].first; glPointSize(1.0); glPushMatrix(); for( count_particles = 0; count_particles < no_particles[count].number; count_particles++ ) { //current = no_particles[count].first; /* Draw the particle at it's starting position */ draw_particle( count*2*RADIUS + RADIUS, count_particles*2*RADIUS + RADIUS, current ); current = current->next; } glPopMatrix(); } //fprintf(stderr, "finished drawing the terrain\n"); } /********************************************************** * Stabilize the structure, by shaking loose any unstable * particles and allowing them to settle at lower points. * Assuming a wind is blowing from left to right, giving a * bias towards the particles moving right. *********************************************************/ void stabilize( Particle_list no_particles[NUM_STEPS], int start, int run) { int current, count_slots = 0, moved_flag = 0, current_height; float move_right, move_left; Particle *loose_particle; /* find the highest point */ current = find_highest_point( no_particles, start, run ); //fprintf(stderr, "found highest point at: %d\n", current ); /* For the current height, step through, possibly moving any particles * currently at that height. Starting from the highest point, step * through each height from highest to lowest. */ for( current_height = no_particles[current].number; current_height > 0; current_height-- ) { //printf("current height is %d\n", current_height); /* Step through each of the columns */ for( count_slots = start; count_slots < start+run; count_slots++ ) { //printf("currently looking at slot %d\n", count_slots ); //printf("particles at %d is %d\n", count_slots, //no_particles[count_slots].number ); //printf("current_height is %d\n", current_height ); /* If the height of the current column is greater than or equal to * the current height being checked, then look to see if the particle * can be moved. */ if( correct_height( current_height, no_particles[count_slots].number ) ) { /* If current point is at right most end, cannot move right */ //printf("correct number of particles\n"); if( can_move_right( count_slots ) ) { //fprintf(stderr, "check if particle can move right\n"); /* check if particle can be moved. * Look for left and right neighbours */ /* Check first for right neighbour */ //if( no_particles[count_slots+1].number < current_height ) if( !has_right_neighbour(no_particles, count_slots, current_height) ) { //fprintf(stderr, "can move right\n"); move_right = rand()/(float)RAND_MAX; if( move_right <= PROB_RIGHT ) { loose_particle = find_particle( &no_particles[count_slots], current_height ); move_particle( &no_particles[count_slots+1], &no_particles[count_slots], loose_particle ); move_column( current_height, no_particles, count_slots, 1 ); moved_flag = 1; } } //fprintf(stderr, "finished looking for right neighbour\n"); } /* Check to see if the particle is eligable to move towards the left. * Particle must not be in the leftmost column, and must not have * already moved. */ if( can_move_left( count_slots ) && moved_flag == 0 ) { //fprintf(stderr, "check if particle can move left\n"); /* if there is no left neighbour, and particle has not already * moved, then the particle is allowed to move left. */ //if( no_particles[count_slots-1].number < current_height ) if( !has_left_neighbour(no_particles, count_slots, current_height) ) { //fprintf(stderr, "can move left\n"); move_left = rand()/(float)RAND_MAX; /* Decide if the particle will move left. Use random number * and if less than or equal to the probability of the * particle moving left, then the particle will move left. */ if( move_left <= PROB_LEFT ) { //fprintf(stderr, "moving particle left\n"); loose_particle = find_particle( &no_particles[count_slots], current_height ); move_particle( &no_particles[count_slots-1], &no_particles[count_slots], loose_particle ); move_column( current_height, no_particles, count_slots, 1 ); } } //fprintf(stderr, "finished looking for left neighbour\n"); } //fprintf(stderr, "redrawing terrain\n"); //glClear( GL_COLOR_BUFFER_BIT ); //draw_terrain( no_particles ); //fprintf(stderr, "swapping buffers\n"); //glutSwapBuffers(); //fprintf(stderr, "resetting moved flag\n"); moved_flag = 0; } current = 0; //printf("reset current\n"); } } //draw_terrain( no_particles ); //glutSwapBuffers(); } /****************************************************************** * Given a starting point and block size, this function checks that * the section of slope has a gradient no greater than the * maximum allowable. Returns a 1 if the slope is greater than * allowed, and a 0 if gradient is okay. *****************************************************************/ int check_slope_block( Particle_list heightField[NUM_STEPS], int rise, int run, int first ) { int count, max, min; //fprintf(stderr, "Checking a particular block\n"); max = first; min = first; for( count = 1; count < run; count++ ) { if( heightField[first+count].number > heightField[max].number ) max = first+count; if( heightField[first+count].number < heightField[min].number ) min = first + count; } //fprintf(stderr, "Finished checking a block\n"); if( heightField[max].number-heightField[min].number > rise ) return 1; else return 0; } /****************************************************************** * Break the terrain up into blocks of length 'run' and check that * each block has a gradient no more more than the allowable * 'rise' over the whole landscape. Stabilize any sections that * don't satisfy this. ******************************************************************/ int check_slope_angle( int rise, int run, Particle_list heightField[NUM_STEPS] ) { int count, check_bit, return_bit = 0; //fprintf(stderr, "At start of checking slope angle\n"); for( count = 0; count <= NUM_STEPS-run; count++ ) { //fprintf(stderr, "LOOKING AT COLUMN %d\n", count ); check_bit = check_slope_block( heightField, rise, run, count ); while( check_bit == 1 ) { //fprintf(stderr, "check bit is 1\n"); glClear( GL_COLOR_BUFFER_BIT ); stabilize( heightField, count, run ); draw_terrain( heightField ); glutSwapBuffers(); check_bit = check_slope_block( heightField, rise, run, count ); return_bit = 1; } //fprintf(stderr, "CHECK BIT IS 0\n"); } fprintf(stderr, "Finished checking slope angle\n"); glClear( GL_COLOR_BUFFER_BIT ); draw_terrain( heightField ); glutSwapBuffers(); return return_bit; } /************************************************************* * Given a value for the critical angle of a slope, this * function calculates by how many particles a section is * able to rise given a certain number of particles along * the same horizontal section. ************************************************************/ int gradient( int run, float slope ) { return round(run*sin(slope*M_PI/180.0) ); } /********************************************************* * Display function, to actually draw the scene ********************************************************/ void display( void ) { Particle_list no_particles[NUM_STEPS]; int count, total_particles, loop = 1, pause, rise, check_bit = 1; //while( loop ) { glClear( GL_COLOR_BUFFER_BIT ); total_particles = 0; /* Initialize the number of particles in each slot to 0 */ initialize_particle_array( no_particles ); draw_terrain( no_particles ); glutSwapBuffers(); rise = gradient( RUN, SLOPE ); fprintf( stderr, "the rise of the slope is: %d\n", rise); fprintf(stderr, "Pausing for rendering to finish: "); scanf("%d", &pause); //rise = gradient( RUN, SLOPE ); //fprintf( stderr, "the rise of the slope is: %d\n", rise); //glClear( GL_COLOR_BUFFER_BIT ); while( check_bit == 1 ) { check_bit = check_slope_angle( rise, RUN, no_particles ); //draw_terrain( no_particles ); /*for( count = 0; count < ITERATIONS; count++ ) { glClear( GL_COLOR_BUFFER_BIT ); //fprintf(stderr, "About to stabilize: iteration number %d\n", count ); stabilize( no_particles ); draw_terrain( no_particles ); glutSwapBuffers(); } */ /* Count the number of particles, make sure it matches the original count */ //for( count = 0; count < (int)NO_STEPS; count++ ) //total_particles += no_particles[count].number; //fprintf(stderr, "final number of particles is %d\n", total_particles ); glClear( GL_COLOR_BUFFER_BIT ); draw_terrain( no_particles ); glutSwapBuffers(); loop = 0; } } fprintf(stderr, "Waiting for input: "); scanf("%d", &loop ); } int main( int argc, char** argv ) { FILE* input; srand( time(NULL) ); input = fopen( argv[1], "r" ); if( !input ) { fprintf(stderr, "input file did not open, using defaults\n"); RADIUS = 25.0; ITERATIONS = 10; PROB_RIGHT = 0.9; PROB_LEFT = 0.2; STEP_SIZE = RADIUS*2; NUM_STEPS = (int)SCREEN / (RADIUS*2); } else { fscanf( input, "%d, %f, %f, %f", &ITERATIONS, &RADIUS, &PROB_RIGHT, &PROB_LEFT ); STEP_SIZE = RADIUS*2; NUM_STEPS = (int)SCREEN / (RADIUS*2); fclose( input ); } glutInit( &argc, argv ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB ); glutInitWindowSize( SCREEN, SCREEN ); glutInitWindowPosition( 0, 0); glutCreateWindow("Stabilization simulation"); glutDisplayFunc( display ); initialize(); glutMainLoop(); }