#include "../include/zf.h"

static bool done = false; /* boolean */

static bool wire_mode = false; /* boolean for wire frame mode */

static GLuint fx_texture_id;
static ZfAudioStream* background_music;

static bool alt_key_down = false; /* true if the left or right ALT keys are currently held down */
static bool paused       = false; /* true when game is paused */

static bool water_on = true;
static bool super_blur = false;
static bool blur = false;
static bool cheat_mode = false;

static void game_end(int state);

static int game_result;
static int game_time;
static int t;  /* time */

static void 
fullscreen_quad(GLdouble depth,
		GLdouble scale,
		GLfloat s, GLfloat t)
{
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3d(-scale, -scale, depth);
    glTexCoord2f(s, 0.0f);
    glVertex3d(scale, -scale, depth);
    glTexCoord2f(s, t);
    glVertex3d(scale, scale, depth);
    glTexCoord2f(0.0f, t);
    glVertex3d(-scale, scale, depth);
    glEnd();
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
}

static void
draw_gui(void)
{
    zf_weapon_control_step();
    zf_shield_render();
    zf_cross_hair_render();
    zf_weapon_control_render_locked();
    zf_hud_render(); 
}

static void
draw_effects(void)
{
    glBindTexture(GL_TEXTURE_2D, fx_texture_id);

    glPushAttrib(GL_ALL_ATTRIB_BITS);

    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glDisable(GL_LIGHTING);

    if(blur)// simple blur and pseudo-hdr
    {
	
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
	glColor4f(1.0f, 1.0f, 1.0f, 0.4f); // alpha is exposure  was 0.4f
	fullscreen_quad(0.5f, 1.0f, 800.0f / 1024.0f, 600.0f / 
			1024.0f);
    }
    else // crazy pulsing blur and pseudo-hdr
    {
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(1.0f, 1.0f, 1.0f, 0.1f); // alpha is exposure
	{
	    int i;

	    for (i = 0; i <= 10; i++)
		fullscreen_quad(0.5f,
				1.0 +
				(double)i *
				(50.0f
				 * zf_audio_get_spectrum_average()
				 * zf_ship_query_thrust() / 50.0f),
				(800.0f) / 1024.0f,
				(600.0f) / 1024.0f);
	}
    }


    // copy framebuffer to fx texture
    glBindTexture(GL_TEXTURE_2D, fx_texture_id);
    glCopyTexSubImage2D(GL_TEXTURE_2D,
			0, 0, 0, 0, 0,
			800, 600); /* WARNING!!! GROSS HAXOR!!! */

    glPopAttrib();
}

static void
mask_water(void)
{
    //glPushAttrib(GL_ALL_ATTRIB_BITS);
    glEnable(GL_DEPTH_TEST);

    /* getting the reflection for the water */
    glEnable(GL_STENCIL_TEST);
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glStencilFunc(GL_ALWAYS, 1, 1);
    glEnable(GL_STENCIL_TEST);
    
    glDisable(GL_LIGHTING);
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    glDepthMask(GL_FALSE);

    zf_water_render_quad();

    /* clear depth in masked area */
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    glStencilFunc(GL_EQUAL, 1, 1);

    glDepthMask(GL_TRUE);
    glDepthFunc(GL_ALWAYS);
    glColor3f(1.0f, 1.0f, 1.0f);
    fullscreen_quad(1.0, 1.0, 1.0, 1.0);
    glDepthFunc(GL_LESS);

    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

    glEnable(GL_CLIP_PLANE0);
    zf_water_load_clip_plane();
    
    //glPopAttrib();
}

static void
draw_reflected_scene(void)
{
    glPushMatrix();
   
    glTranslatef(0.0f, 2.0f * zf_water_query_level(), 0.0f);
    glScalef(1.0f, -1.0f, 1.0f);

    glFrontFace(GL_CW); /* polygons will be reversed */
    
    zf_skybox_render();
    zf_render_system_step_opaque();
    zf_render_system_step_translucent();

    glFrontFace(GL_CCW); /* return to normal */

    glPopMatrix();
}

static void
unmask_water(void)
{
    glDisable(GL_CLIP_PLANE0);
    glDisable(GL_STENCIL_TEST);
}

static void
draw_water(void)
{ 
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_BLEND);
    glDisable(GL_LIGHTING);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_TEXTURE_2D);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    glDepthMask(GL_TRUE);

    glPolygonOffset(1.0f, 2.0f);
    glEnable(GL_POLYGON_OFFSET_FILL);
    zf_water_render();
    glDisable(GL_POLYGON_OFFSET_FILL);

    glDisable(GL_BLEND);
}

static void
draw_screen(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    glPushAttrib(GL_ALL_ATTRIB_BITS);

    glPushMatrix();

    zf_camera_load();

    zf_skybox_render();

    if(water_on)
    {
	zf_render_system_step_opaque();
	
	mask_water();
	draw_reflected_scene();
	unmask_water();
	draw_water();
	
	
	/* nick - these have to be drawn after the water reflection
	   since they don't write to the depth buffer */
	zf_render_system_step_translucent();
    }
    else
	zf_render_system_step();

    glPopAttrib();
    glPushAttrib(GL_ALL_ATTRIB_BITS);

    if(blur || super_blur)
	draw_effects(); /* take this out when screendumping videos */
    
    draw_gui();

    glPopMatrix();

    glPopAttrib();

    SDL_GL_SwapBuffers();

}

static void
reshape(int width, int height)
{
    /* set the viewport to the window width and height */
    glViewport(0, 0, width, height);
  
    /* load a projection matrix that matches the window aspect ratio */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (double)width/(double)height, 0.1, 100.0);

    /* reset the modelview matrix */
    glMatrixMode(GL_MODELVIEW);
}


/*
 * nick - progress bar moved here since it has nothing to do with any
 * other file
 */

#define PROGRESS_BAR_LENGTH        1.8f

static void
draw_loading(void)
{
    /* load a projection matrix that matches the window aspect ratio */
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluPerspective(60.0, 800.0/600.0, 0.1, 512.0); /* WARNING - GROSS HAXOR! */

    /* reset the modelview matrix */
    glMatrixMode(GL_MODELVIEW);
    
    glPushMatrix();
    glTranslatef(-4.2f, 0.0f, -32.0f);
    glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
    zf_text_draw("loading");
    
    glPopMatrix();

    SDL_GL_SwapBuffers();
    
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
    
    glFlush();
    glFinish();

    SDL_GL_SwapBuffers();
}

static void
update_progress_bar(float progress)
{
    GLfloat x = (float) PROGRESS_BAR_LENGTH * progress;
    GLfloat start = (2.0 - PROGRESS_BAR_LENGTH)/2.0f - 1.0f; 
    
    glDisable(GL_LIGHTING);
    glPushMatrix();
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    
    glColor3f(1.0f, 0.0f, 0.0f);
    glBegin(GL_LINES);
    glVertex3f(start, -0.8f, -0.5f);   
    glVertex3f(x+start, -0.8f, -0.5f);    
    glEnd();
    
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
    
    glFlush();
    glFinish();

    SDL_GL_SwapBuffers();
}

static void
loading_complete(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    /* load a projection matrix that matches the window aspect ratio */
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluPerspective(60.0, 800.0/600.0, 0.1, 512.0); /* WARNING - GROSS HAXOR! */

    /* reset the modelview matrix */
    glMatrixMode(GL_MODELVIEW);
    
    glPushMatrix();
    glTranslatef(-4.2f, 0.0f, -32.0f);
    glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
    zf_text_draw("complete");
    
    glPopMatrix();

    SDL_GL_SwapBuffers();   
}

/*!
  \todo We want to replace all the individual object init calls with ONE call
  to zf_level_load(). How can we do this while still updating the progress
  bar? If we can get rid of the calls, then we can do without the zf_level
  accessor methods entirely.

  \todo Two hacks here (generating textures and loading background music)
*/

void
zf_game_loop_init(char* level_filename)
{
    ZfLevel* level;

    //printf("%s() : START : %s\n", __FUNCTION__, level_filename);

    draw_loading();

    //printf("loading level file\n");
    level = zf_level_read_file(level_filename);

    zf_level_print(level);

    update_progress_bar(0.1f);
    zf_animation_system_init();
    zf_collision_system_init();
    update_progress_bar(0.2f);
    zf_render_system_init();
    zf_trigger_system_init();
    zf_particle_system_init();

    // zf_audio_init(); /* Need to be before things with sounds */

    update_progress_bar(0.3f);
    zf_skybox_init(zf_level_get_skybox_file(level));
    zf_camera_init();
    zf_heightmap_init(zf_level_get_heightmap_file(level));  /* water is init-ed inside this*/
    update_progress_bar(0.4f);
    zf_flux_init(zf_level_get_flux_file(level));

    zf_ship_init();    

    update_progress_bar(0.5f);
    zf_weapon_control_init();
    zf_laser_init();
    zf_missile_init();
     
    zf_tritor_init();
    //  zf_decoy_init();
    update_progress_bar(0.6f);    

    zf_bomb_init();
    zf_explosion_init();
    zf_shield_init();
    zf_debris_init();
   

    update_progress_bar(0.7f);

    zf_hive_init(zf_level_get_hives_file(level));
    zf_leech_init(zf_level_get_leeches_file(level));

    //zf_wasp_init(zf_level_get_wasps_file(level));
    zf_hexfluxfield_init(zf_level_get_hexfluxfields_file(level));
    zf_flux_ring_init(zf_level_get_fluxrings_file(level));
    zf_battery_ring_init(zf_level_get_batteryrings_file(level));
    zf_tier_ring_init(zf_level_get_tierrings_file(level));
    
    update_progress_bar(0.8f);
    zf_drone_init(zf_level_get_drones_file(level));
    zf_drone_pickup_init();
    
    
    /*zf_turret_init("../data/level/turrets.zf");*/

    zf_droid_missile_init();       
    zf_droid_init(zf_level_get_droids_file(level));
    zf_eel_segment_init(zf_level_get_eels_file(level));
    zf_enemy_missile_init();
    
    
    update_progress_bar(0.9f);
    zf_hud_init(zf_level_get_hudmessages_file(level));
    zf_cross_hair_init();
    
    zf_landscape_object_init(zf_level_get_landscape_file(level));
    zf_score_indicator_init();

    zf_boss_target_init(); /* no file needed, as boss file will store it - MUST BE BEFORE boss_init()*/
    zf_boss_bomb_init();
    zf_boss_init(zf_level_get_boss_file(level));


    /* Hack for now */
    glGenTextures(1, &fx_texture_id);
    glBindTexture(GL_TEXTURE_2D, fx_texture_id);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
		 1024, 1024, /* WARNING!!! GROSS HACK!!! check viewport!!! */
		 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8,
		 0); /* no initial image */
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    /* Hack for now */
    background_music = zf_audio_stream_load("../data/music/Defluxed.mp3");
    update_progress_bar(1.0f);
    loading_complete();

    /* play, but immediately pause - so that this plays nicely with the menu system */
    zf_audio_stream_play(background_music);
    zf_audio_stream_pause(background_music);
}

void
zf_game_loop_close(void)
{
    zf_animation_system_close();
    zf_collision_system_close();
    zf_render_system_close();
    zf_trigger_system_close();
    zf_particle_system_close();

    zf_skybox_close();
    zf_camera_close();

    zf_heightmap_close();
    
    zf_flux_close();
    zf_ship_close();

    zf_weapon_control_close();
    zf_laser_close();
    zf_missile_close();

 
    zf_tritor_close();
      /*
      zf_decoy_close();
    */
    zf_bomb_close();

    zf_debris_close();
    zf_explosion_close();
 
    zf_shield_close();
 
    zf_hive_close();
    zf_leech_close();
      //      zf_wasp_close();

   
    zf_hexfluxfield_close();
    zf_flux_ring_close();
    zf_battery_ring_close();
    zf_tier_ring_close();

    zf_drone_close();
    zf_drone_pickup_close();
    
    /*zf_turret_close();*/
    zf_eel_segment_close();
    zf_enemy_missile_close();
    zf_droid_missile_close();
    
    zf_droid_close();
  
    zf_hud_close();
    zf_cross_hair_close();
    zf_score_indicator_close();
    zf_landscape_object_close();
 
    zf_boss_close();
    zf_boss_bomb_close();
    zf_boss_target_close();

    /* Hack for now */
#if 0
    glDeleteTextures(1, &fx_texture_id);
#endif
    
    /* TODO: WE NEED TO MATCH ALL THE INITS WITH CLOSES */
   
    zf_audio_stream_destroy(background_music);
}


void
game_end(int state)
{
    bool finish = false;

    while(!finish)
    {
	SDL_Event event;

	while(SDL_PollEvent(&event))
	{
	    switch(event.type)
	    {
	    case SDL_KEYDOWN:
		finish = true;
		/* Handle key presses. */
		break;
	    case SDL_QUIT:
		/* Handle quit requests (like Ctrl-c). */
		finish = true;
		break;
	    }
	}

	/* different types of 'game over' */
	switch(state)
	{
	    /* finished level */
	case 0:
	    /* rendering "congrats" image?*/
	    break;
	    /* died - but keep rendering*/
	case 1:
	    t = SDL_GetTicks();
	    
	    while ((t - game_time) > ZF_TIME_STEP)
	    {
		zf_animation_system_step();
		zf_collision_system_step();
		game_time += ZF_TIME_STEP;
	    }
	    break;
	}
	draw_screen();
    }

    
}


static void
handle_key_down(SDL_keysym* keysym)
{
    switch(keysym->sym)
    {
	/*
	  case SDLK_1:
	  zf_weapon_control_set_weapon(ZF_LASER);
	  break;
	  case SDLK_2:
	  zf_weapon_control_set_weapon(ZF_BEAM);
	  break;
	  case SDLK_3:
	  zf_weapon_control_set_weapon(ZF_MISSILE);
	  break;
	  case SDLK_4:
	  zf_weapon_control_set_weapon(ZF_SUPER_MISSILE);
	  break;
	  case SDLK_5:
	  zf_weapon_control_set_weapon(ZF_TORPEDO);
	  break;
	  case SDLK_6:
	  zf_weapon_control_set_weapon(ZF_TRITOR);
	  break;
	  case SDLK_7:
	  zf_weapon_control_set_weapon(ZF_BOMB);
	  break;
	  case SDLK_8:
	  zf_weapon_control_set_weapon(ZF_DECOY);
	  break;
	  case SDLK_0:
	  zf_weapon_control_add_to_missile_stock(100);
	  zf_weapon_control_add_to_torpedo_stock(100);
	  zf_weapon_control_add_to_decoy_stock(10);
	  break;
	*/
    case SDLK_w:
	zf_ship_move_up_tier();
	break;
    case SDLK_s:
	zf_ship_move_down_tier();
	break; 
    case SDLK_SPACE:
	if(!zf_ship_start())
	    zf_weapon_control_launch_bomb();
	break;
    case SDLK_c:  /* the 'tester' key */
	if(cheat_mode)
	    zf_ship_jump_flux(1.0f);
	break;
    case SDLK_x:  /* the 'tester' key */
	if(cheat_mode)
	    zf_ship_jump_flux(-1.0f);
	break;
    case SDLK_z:  /* the 'tester' key */
	if(cheat_mode)
	{
	    /*
	      CLvertex vertex;
	      
	      cluSetVertex(&vertex,
	      -4.0f,
	      -33.0f,
	      -433.0f);
	      
	      zf_droid_new(&vertex, 1, 0.2f, 2.0f);
	      zf_droid_new(&vertex, 2, 1.0f, 3.3f);
	      zf_droid_new(&vertex, 3, 0.5f, 3.0f);
	    */
	    /*
	      zf_ship_animate_hit_tier(1);
	      zf_ship_animate_hit_tier(2);
	      zf_ship_animate_hit_tier(3);
	    */

	    
	    CLvertex vert;
	    cluSetVertex(&vert, -12.0f, 0.0f, -35.0f);
	    zf_hud_new_message(0.2f, 0, &vert, "testing.!?testing");

	    /*
	      zf_hud_increase_score(101);
	    */
	    /*
	      CLvertex pos;
	      CLvertex targets[3];
	      CLvertex * test;
	      cluSetVertex(&pos,-100.0f, 0.0f, -300.0f);

	      // local coords 
	      
	      cluSetVertex(&targets[0],0.0f, 50.0f, 0.0f);
	      cluSetVertex(&targets[1],0.0f, 0.0f, -50.0f);
	      cluSetVertex(&targets[2],50.0f, 0.0f, 0.0f);
	      zf_boss_new(&pos, 0.3f, 3, &targets[0]);
	    */
	}
	break;
    case SDLK_1: /* testing only - SMALL DAMAGE */
	if(cheat_mode)
	    zf_camera_shake_start(0.01f);
	break;
    case SDLK_2: /* testing only - MEDIUM DAMAGE */
	if(cheat_mode)
	    zf_camera_shake_start(0.51f);
	break;
    case SDLK_3: /* testing only - MASSIVE DAMAGE */
	if(cheat_mode)
	    zf_camera_shake_start(0.9f);
	break;
    case SDLK_4: /* testing only - DAMAGE ship */
	if(cheat_mode)
	    zf_ship_decrease_power(0.5f);
	break;
    case SDLK_0: /* testing only - secret win */
	if(cheat_mode)
	{
	    CLvertex pos;
	    cluSetVertex(&pos, -12.2f, 0.0f, -20.0f);
	    done = true;
	    zf_hud_new_message(0.0f, 0, &pos, "you pwned that level!");
	    zf_animation_system_step();  /* force redraw to get message */
	    game_result = 0;
	}
	break;
    case SDLK_9: /* testing only - secret die */
	if(cheat_mode)
	{
	    CLvertex pos;
	    ZfHudMessage* msg;
	    cluSetVertex(&pos, -9.2f, 0.0f, -32.0f);
	    done = true;
	    msg = zf_hud_new_message(0.0f, 2, &pos, "game over dude!");
	    game_end(1);
	    zf_hud_message_kill(msg);
	    game_result = 1;
	}
	break;
    case SDLK_ESCAPE:
	game_result = 9; /*paused */
	done = true;
	break;

    case SDLK_F4:
	if (alt_key_down)
	{
	    printf("exiting\n");
	    fflush(stdout);
	    exit(0);
	}
	else
	{
	    printf("f4 pressed without alt\n");
	    fflush(stdout);
	}
	break;

    case SDLK_PAUSE:
	paused = !paused;

	if(!paused)
	    zf_game_loop_reset_time();
	break;

    case SDLK_o:
	wire_mode = !wire_mode;
	zf_heightmap_set_wire_mode(wire_mode);
	break;

    case SDLK_LALT:
    case SDLK_RALT:
	alt_key_down = true;
	game_result = 2; /* have to do this here -once F4 pressed, SDL takes over, and doesn't run the handle_key_down */
	break;

    default:
	break;
    }
}

static void
handle_key_up(SDL_keysym* keysym)
{
    switch(keysym->sym)
    {
    case SDLK_LALT:
    case SDLK_RALT:
	alt_key_down = false;
	break;
	
    default:
	break;
    }
}

static void
handle_key_state(void)
{
    Uint8 *key_state;
	    
    key_state = SDL_GetKeyState(NULL);

    if (key_state[SDLK_l])
    {
	CLvertex vertex;
	
	cluSetVertex(&vertex,
		     10.0f * rand() / RAND_MAX - 5.0f,
		     10.0f * rand() / RAND_MAX - 5.0f,
		     10.0f * rand() / RAND_MAX - 5.0f);
	
	zf_leech_new(&vertex);
    }
    if(!zf_ship_query_end_state())
    {
	/*  - For old system where thrust can increase 
	  if (key_state[SDLK_w])
	  zf_ship_increase_thrust();
	  else
	  zf_ship_decrease_thrust();
	  
	  if (key_state[SDLK_d])
	  zf_ship_increase_roll();
	  
	  if (key_state[SDLK_a])
	  zf_ship_decrease_roll();
	*/

	/* New system of tiers and constant thrust, so no thrust control now */
	  if (key_state[SDLK_d])
	      zf_ship_increase_roll();
	  
	  if (key_state[SDLK_a])
	      zf_ship_decrease_roll();
	  
    }
}

static void
handle_mouse_state(void)
{
    Uint8 mouse_state;
    int x, y;
    int dx, dy;

    mouse_state = SDL_GetMouseState(&x, &y);

    zf_cross_hair_set_position(x, y);

    /* look around with camera 
    mouse_state = SDL_GetRelativeMouseState(&dx, &dy);
    zf_camera_set_lookat(x, y, dx, dy); */
}

static void
handle_mousebutton_down(SDL_Event *event)
{	

    if(!zf_ship_start())
    {
	switch(event->button.button)
	{
	case SDL_BUTTON_RIGHT:
	    zf_weapon_control_shoot_tritor();
	    /*	zf_weapon_control_start_beam_mode();*/
	    break;
	case SDL_BUTTON_LEFT:
	    zf_weapon_control_start_lock_mode();
	    break;	
	}
    }

    /*
      switch(zf_weapon_control_query_weapon())
      {
      case ZF_LASER:
      zf_weapon_control_shoot_laser();
      break;
      case ZF_BEAM:
      zf_weapon_control_start_beam_mode();
      break;
      case ZF_MISSILE:
      zf_weapon_control_start_lock_mode();
      break;
      case ZF_SUPER_MISSILE:
      zf_weapon_control_start_super_lock_mode();
      break;
      case ZF_TORPEDO:
      zf_weapon_control_shoot_torpedo();
      break;
      case ZF_TRITOR:
      zf_weapon_control_shoot_tritor();
      break;
      case ZF_DECOY:
      zf_weapon_control_launch_decoy();
      break;
      case ZF_BOMB:
      zf_weapon_control_launch_bomb();
      break;
      default:
      break;
      }
    */
} 

static void
handle_mousebutton_up(SDL_Event *event)
{

    switch(event->button.button)
    {
    case SDL_BUTTON_RIGHT:
	zf_weapon_control_stop_beam_mode();
	break;
    case SDL_BUTTON_LEFT:
	zf_weapon_control_stop_lock_mode();
	zf_weapon_control_shoot_missile();
	break;
    }

    /*
      switch(zf_weapon_control_query_weapon()) 
      {
      case ZF_MISSILE:
      zf_weapon_control_stop_lock_mode();
      zf_weapon_control_shoot_missile();
      break;
      case ZF_SUPER_MISSILE:
      zf_weapon_control_stop_super_lock_mode();
      zf_weapon_control_shoot_super_missile();
      break;
      case ZF_BEAM:
      zf_weapon_control_stop_beam_mode();
      break;
      default:
      break;
      }
    */
} 

static void
process_events(void)
{
    SDL_Event event;
   
    while(SDL_PollEvent(&event))
    {
	switch(event.type)
	{
	case SDL_KEYDOWN:
	    /* Handle key presses. */
	    handle_key_down(&event.key.keysym);
	    break;
	case SDL_KEYUP:
	    handle_key_up(&event.key.keysym);
	    break;
	case SDL_MOUSEBUTTONDOWN:
	    handle_mousebutton_down(&event);
	    break;
	case SDL_MOUSEBUTTONUP:
	    handle_mousebutton_up(&event);
	    break;
	case SDL_QUIT:
	    /* Handle quit requests (like Ctrl-c). */
	    done = 1;
	    break;
	}
    }
    
    /* also handle key state and mouse state */
    handle_key_state();
    handle_mouse_state();
}


/* return 0 if 'won' level, 1 - died , 2 - altF4 quit*/
int
zf_game_loop_run(void)
{
    Uint32 lt;
    double viewport[4];

    glGetDoublev(GL_VIEWPORT, viewport);
   
    lt = SDL_GetTicks();
    done = 0;
    game_result = 0;

    glPushAttrib(GL_ALL_ATTRIB_BITS);

    /* load a projection matrix that matches the window aspect ratio */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (double)viewport[2]/(double)viewport[3], 0.1, 512.0);

    /* reset the modelview matrix */
    glMatrixMode(GL_MODELVIEW);

    game_time = SDL_GetTicks();


    /* play background music - temporaray taken out */
    zf_audio_stream_play(background_music);

    while(!done)
    {
	process_events();
	
	/* if game is paused, abort game loop here */
	if (paused)
	{
	    continue;
	}

	/* time for game slice */
	t = SDL_GetTicks();
	lt = t;

	while ((t - game_time) > ZF_TIME_STEP)
	{
#if 0
	    printf("anim\n");
	    fflush(stdout);
	    zf_animation_system_step();
	    printf("col\n");
	    fflush(stdout);
	    zf_collision_system_step();
	    printf("done\n");
	    fflush(stdout);
#else 
	    zf_animation_system_step();
	    zf_collision_system_step();
#endif
	    /* Winning state */
	    if (zf_ship_query_landed() || zf_ship_query_defeat_boss())
	    {
		CLvertex pos;
		cluSetVertex(&pos, -12.2f, 0.0f, -20.0f);
		done = true;
		zf_hud_new_message(0.0f, 0, &pos, "you pwned that level!");
		zf_animation_system_step();
		game_result = 0;
		break;
	    }
	    /*  Losing state 1 */
	    else if(zf_ship_query_dead())
	    {
		if(zf_ship_query_lives() <= 0)
		{
		    CLvertex pos;
		    ZfHudMessage* msg;
		    cluSetVertex(&pos, -9.2f, 0.0f, -32.0f);
		    done = true;
		    msg = zf_hud_new_message(0.0f, 2, &pos, "game over dude!");
		    game_end(1);
		    zf_hud_message_kill(msg);
		    game_result = 1;
		}
		else
		{
		    CLvertex pos;
		    ZfHudMessage* msg;
		    cluSetVertex(&pos, -9.2f, 0.0f, -32.0f);
		    /*put hud message to wait for restart */
		    msg = zf_hud_new_message(0.0f, 2, &pos, "ouch! die-zored");
		    game_end(1);
		    zf_hud_message_kill(msg);
		    
		    zf_ship_restart();
		}
		break;
	    }

	    game_time += ZF_TIME_STEP;

	}
	/*
	  printf("drawing screen\n");
	  fflush(stdout);
	*/
	  
	draw_screen();
	/*
	  printf("done\n");
	  fflush(stdout);
	*/

    }
   
    glPopAttrib();

    //if(game_result == 9) /* paused */
//	zf_audio_stream_pause(background_music);
  //  else
	zf_audio_stream_stop(background_music);

    return game_result;
}


/* mainly for HUD to be able to pause. */
void
zf_game_loop_reset_time(void)
{
    game_time = SDL_GetTicks();
}

void
zf_game_loop_set_super_blur(bool mode)
{
    super_blur = mode;
}

void
zf_game_loop_set_blur(bool mode)
{
    blur = mode;
}

void
zf_game_loop_set_cheat_mode(bool mode)
{
    cheat_mode = mode;
}

void
zf_game_loop_set_water(bool mode)
{
    water_on = mode;
}


