/* Called whenever a ball is lost, either by it falling off the bottom of the * screen, or the player pressing the "suicide key". */ void lost_ball(nbstate *state) { /* Decrement the balls count and if there are none left: */ if(!state->numballs--) { /* Go to the "game lost" state and update the high score if * appropriate: */ state->state = STATE_GAMELOST; /* Update the high score and save it if necessary: */ save_hiscore(state); /* This could probably be done better by just drawing the * splash- set_level_active() redraws the entire game area: */ set_level_active(state); return; } /* Erase the balls line at the top of the screen: */ draw_background(state, 0, state->scores.h, state->canvaswidth, state->ball.s->h + (BALLS_BORDER * 2)); /* Draw the balls again, but with one less than there was before: */ draw_balls(state); /* Copy the balls row to the output window: */ draw_canvas(state, 0, state->scores.h, state->canvaswidth, state->ball.s->h + (BALLS_BORDER * 2)); /* Park the new ball and erase the old one: */ park_ball(state); move_ball(state); /* Redraw the bat. This is a bit of a hack because sometimes when the * ball falls below the top of the bat on its way to the bottom of the * screen it can clip the bat and erase a bit of it. This redraws the * bat to hide that: */ draw_bat(state); /* Copy the redrawn bat to the output window: */ draw_canvas(state, state->batx - (state->batwidths[state->bat] / 2), state->canvasheight - state->batheight, state->batwidths[state->bat], state->batheight); }
int main(int argc, char** argv) { SDL_Event event; int keypress = 0; int t = 0; // Init everything sdl_init(); init_sin_table(); // Init random number generator srand(clock()); // Init balls for(int i = 0; i < NUM_BALLS; i++) reset_ball(i); // Create sprites ball_surface[0] = sprite_create_ball(1.0, 0.0, 0.0); ball_surface[1] = sprite_create_ball(0.0, 1.0, 0.0); ball_surface[2] = sprite_create_ball(0.0, 0.0, 1.0); // Loop until the end while(!keypress) { // Lock SDL surface if needed if(SDL_MUSTLOCK(screen)) if(SDL_LockSurface(screen) < 0) exit(EXIT_FAILURE); // Draw the plasma draw_balls(screen, t); // Unlock the SDL surface if needed if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); // Flip surfaces SDL_UpdateRect(screen, 0, 0, 0, 0); // Handle SDL events while(SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: case SDL_KEYDOWN: keypress = 1; break; } } // Sleep until next frame (25 FPS) usleep(40000); // Advance time t++; } // Exit gracefully SDL_Quit(); return EXIT_SUCCESS; }
void bBoard::draw() { double vvx = cos(aa), vvy = sin(aa); if( idle() && camera_type == CT_FPS ) { GetCamera.set_eye( bVector3( ball[0]->pos.x - 2*view_r*vvx, 2.0, ball[0]->pos.y - 2*view_r*vvy ) ); GetCamera.set_dst( bVector3( ball[0]->pos.x + 3*view_r*vvx, 0.2, ball[0]->pos.y + 3*view_r*vvy ) ); } else { GetCamera.set_top_view(); } glDisable( GL_TEXTURE_2D ); glColor3f( 0.0, 0.0, 0.0 ); glBegin( GL_TRIANGLE_STRIP ); for( int i=0; i<BOTTOM_SEGMENTS; ++i ) { glVertex3d( bottom_data[i].x, -0.01, bottom_data[i].y ); } glEnd(); if( idle() ) { glLineWidth( 2.0 ); glEnable( GL_LINE_SMOOTH ); glBegin( GL_LINES ); glColor4d( 1.0, 0.3, 0.3, 1.0 ); for(double k=0.0; k<4.0; k+=0.2) { glVertex3d( ball[0]->pos.x+vvx*k, ball[0]->radius, ball[0]->pos.y+vvy*k ); } glEnd(); glDisable( GL_BLEND ); } glColor3f( 1.0, 1.0, 1.0 ); board_shader.enable( bShader::B_FRAGMENT ); board_shader.bind( bShader::B_FRAGMENT ); glActiveTextureARB( GL_TEXTURE0_ARB ); glEnable(GL_TEXTURE_2D); ball_num.bind(); glMultiTexCoord3fARB( GL_TEXTURE1_ARB, 0.0f, 1.0f, 0.0f ); glMultiTexCoord3fARB( GL_TEXTURE2_ARB, 0.0f, 0.1f, 0.0f ); float lx = 0, ly = 0.3f, lz = 0; glEnable( GL_TEXTURE_2D ); desk.bind(); glBegin( GL_TRIANGLE_STRIP ); glNormal3f( 0.0f, 1.0f, 0.0f ); for( int i=0; i<DESK_SEGMENTS; ++i ) { glMultiTexCoord2dARB( GL_TEXTURE0_ARB, desk_data[i].tx, desk_data[i].ty ); glMultiTexCoord3dARB( GL_TEXTURE3_ARB, desk_data[i].x-lx, 0.0-ly, desk_data[i].y-lz ); glVertex3d( desk_data[i].x, 0.0, desk_data[i].y ); } glEnd(); Profiler.begin("ball_mgr::draw_bands"); glActiveTextureARB( GL_TEXTURE0_ARB ); glEnable(GL_TEXTURE_2D); band_tex.bind(); glDisable( GL_CULL_FACE ); for( int i=0; i<band_size; ++i ) { band[i]->draw(); } glMultiTexCoord3dARB( GL_TEXTURE1_ARB, 0.0, 1.0, 0.0 ); glBegin( GL_TRIANGLE_STRIP ); for( int i=0; i<BOARD_SEGMENTS; ++i ) { glNormal3d( 0.0, 1.0, 0.0 ); //glMultiTexCoord3fARB( GL_TEXTURE3_ARB, band_data[i].x, 0.4-ly, band_data[i].y ); glMultiTexCoord2dARB( GL_TEXTURE0_ARB, ((i%2)==0)?0.0:1.0, 0.0 ); glVertex3d( band_data[i].x, 0.4, band_data[i].y ); //glMultiTexCoord3fARB( GL_TEXTURE3_ARB, board_data[i].x, 0.4-ly, board_data[i].y ); glMultiTexCoord2dARB( GL_TEXTURE0_ARB, ((i%2)==0)?0.0:1.0, 1.0 ); glVertex3d( board_data[i].x, 0.4, board_data[i].y ); } //glMultiTexCoord3fARB( GL_TEXTURE3_ARB, band_data[0].x, 0.4-ly, band_data[0].y ); glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 1, 0 ); glVertex3d( band_data[0].x, 0.4, band_data[0].y ); //glMultiTexCoord3fARB( GL_TEXTURE3_ARB, board_data[0].x, 0.4-ly, board_data[0].y ); glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 1, 1 ); glVertex3d( board_data[0].x, 0.4, board_data[0].y ); glEnd(); glColor3f(0.0f,0.0f,0.2f); glBegin( GL_TRIANGLE_STRIP ); for( int i=0; i<BOARD_SEGMENTS; ++i ) { glVertex3d( band_data[i].x, 0.0, band_data[i].y ); glVertex3d( band_data[i].x, 0.4, band_data[i].y ); } glVertex3d( band_data[0].x, 0.0, band_data[0].y ); glVertex3d( band_data[0].x, 0.4, band_data[0].y ); glEnd(); board_shader.disable( bShader::B_FRAGMENT ); Profiler.begin("ball_mgr::draw_balls"); draw_balls(); Profiler.end("ball_mgr::draw_balls"); if( power > 0.0 ) { bSystem::video_sys.set_matrix_2d(); glDisable( GL_TEXTURE_2D ); glDisable( GL_DEPTH_TEST ); glColor3f( 0.0f, 0.0f, 0.0f ); glBegin( GL_TRIANGLE_STRIP ); glVertex2i( 100, 500 ); glVertex2i( 100, 560 ); glVertex2i( 700, 500 ); glVertex2i( 700, 560 ); glEnd(); glBegin( GL_TRIANGLE_STRIP ); glColor3f( 0.0f, 1.0f, 0.0f ); glVertex2i( 102, 502 ); glVertex2i( 102, 558 ); glColor3d( power/18.2, 1.0-power/18.2, 0.0f ); glVertex2d( 100.0 + (598.0*power)/18.2, 502 ); glVertex2d( 100.0 + (598.0*power)/18.2, 558 ); glEnd(); } Profiler.end("ball_mgr::draw_bands"); }
/* Make the current level active. This mainly consists of destroying the old * background image and loading the new one, destroying the splash image, * possibly loading a new splash image depending on the state, copying over the * new level data into the current level state, then redrawing the entire game * area. */ void set_level_active(nbstate *state) { int i; level *lev; grid *g, *gg; int bgchanged; sprite *s = NULL; power *p, *pnext; GR_PIXMAP_ID ctmp; char *backgroundfile; /* Destroy the old splash image sprite: */ destroy_sprite(state, state->splash); /* If we're on the title screen: */ if(state->state == STATE_TITLESCREEN) { /* Set the background file to the title background file: */ backgroundfile = state->titlebackground; /* Set the tiled state appropriately: */ state->backgroundtiled = state->titlebackgroundtiled; /* Try to load the title screen splash graphic (if it doesn't * work nothing bad will happen- load_sprite() will print an * error message and draw_splash() will not draw anything.) */ state->splash = load_sprite(state, state->titlesplash, -1, -1); } else { /* Not on the title screen. */ /* Find the level structure for the current level number: */ for(lev = state->levels, i = 1; i < state->level; lev = lev->next, i++); /* Set the current number of bricks and background info: */ state->numbricks = lev->numbricks; backgroundfile = lev->backgroundname; state->backgroundtiled = lev->backgroundtiled; /* If we're in the "game won" state, try to load the appropriate * splash image: */ if(state->state == STATE_GAMEWON) { state->splash = load_sprite(state, state->gamewonsplash, -1, -1); /* If we're in the "game lost" state, try to load the * appropriate splash image: */ } else if(state->state == STATE_GAMELOST) { state->splash = load_sprite(state, state->gamelostsplash, -1, -1); } else { /* We must be in the STATE_RUNNING state. */ /* No splash image: */ state->splash = NULL; /* Copy this levels game grid into the current game * grid: */ g = state->grid; gg = lev->grid; for(i = 0; i < state->width * state->height; i++) *g++ = *gg++; } } /* If there was a background filename specified: */ if(backgroundfile) { /* If there is a current background sprite with a filename * and the filename is the same as the new background * filename, the background file has not changed. Otherwise, * assume that it has. */ if(state->background && state->background->fname && !strcmp(backgroundfile, state->background->fname)) bgchanged = 0; else bgchanged = 1; /* No background filename was specified, so assume it has changed (to * a blank black frame): */ } else bgchanged = 1; /* If the background image has changed, try to load the new one: */ if(bgchanged && !(s = load_sprite(state, backgroundfile, -1, -1))) { /* If it fails, try to make a new empty sprite and colour it * in black (the 16*16 pixels is purely arbitrary- make it too * large and it uses a lot of memory, make it too small and * we spend ages painting hundreds of tiny tiles onto the * background. */ if(!(s = make_empty_sprite(state, backgroundfile, 16, 16))) { /* If that fails too (shouldn't happen under normal * circumstances), issue a warning and keep the old * background image sprite: */ s = state->background; } else { /* Fill in the new dummy background black: */ GrSetGCForeground(state->gc, GR_COLOR_BLACK); GrFillRect(s->p, state->gc, 0, 0, 16, 16); /* Make it tiled. FIXME: it would make more sense to * have a "no background image" option which simply * coloured in the background black: */ state->backgroundtiled = 1; } } /* If we have made a new background image sprite: */ if(bgchanged && s != state->background) { /* Destroy the old one: */ destroy_sprite(state, state->background); /* Set the background to the new sprite: */ state->background = s; } /* Empty the list of power boxes: */ for(p = state->powers; p; p = pnext) { pnext = p->next; free(p); } state->powers = NULL; /* If fading has been requested, we want to fade the new level in, so * swap the canvasses around so the current screen is the old canvas, * then draw the new screen and make the new canvas, then start the * process of fading it in: */ if(state->faderate) { /* Swap the canvasses around: */ ctmp = state->oldcanvas; state->oldcanvas = state->canvas; state->canvas = ctmp; /* Remember the state we're fading into: */ state->nextstate = state->state; /* Go into the fading state: */ state->state= STATE_FADING; /* Initialise the fade level as completely opaque: */ state->fadelevel = 256; } /* Clear the whole game area to the background image: */ draw_background(state, 0, 0, state->canvaswidth, state->canvasheight); /* If we're not on the title screen or fading to the title screen: */ if(state->state != STATE_TITLESCREEN && !(state->state == STATE_FADING && state->nextstate == STATE_TITLESCREEN)) { /* Draw the bricks: */ draw_bricks(state, 0, 0, state->canvaswidth, state->canvasheight); draw_scores(state); /* Draw the scores bar. */ draw_balls(state); /* Draw the row of balls. */ draw_bat(state); /* Draw the bat. */ /* Draw the current ball unless the game is over: */ if(state->state != STATE_GAMELOST && state->state != STATE_GAMEWON) draw_ball(state); } draw_splash(state); /* Draw the splash graphic (if there is one). */ /* If we're fading, remember the new canvas and generate the first * frame of the fade: */ if(state->state == STATE_FADING) { /* Swap the canvasses around: */ ctmp = state->newcanvas; state->newcanvas = state->canvas; state->canvas = ctmp; /* Reduce the opacity: */ state->fadelevel -= state->faderate; /* Generate the first frame: */ GrCopyArea(state->canvas, state->gc, 0, 0, state->canvaswidth, state->canvasheight, state->newcanvas, 0, 0, 0); GrCopyArea(state->canvas, state->gc, 0, 0, state->canvaswidth, state->canvasheight, state->oldcanvas, 0, 0, GR_CONST_BLEND | state->fadelevel); } /* Copy the entire redrawn canvas to the output window: */ draw_canvas(state, 0, 0, state->canvaswidth, state->canvasheight); }