// coded by user http://www.allegro.cc/members/altalena on December 1, 2012
// see copyright documentation for disclaimer and attribution

#include <stdio.h>
#include <cmath>
#include <allegro5/allegro.h>
#include "allegro5/allegro_image.h"
//#include "allegro5/bitmap.h"
#include <allegro5/allegro_opengl.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <GL/glu.h>
#include "MTwister.h"
#include "PNoise.h"
#define M_2PIE 6.28318530717958647692528676656
#define M_2_5_PIE 1.25663706143591729538505735331 // used for icosahedron
#define M_1_5_PIE 0.62831853071795864769252867665 // ^

int  fast_floor(double x)
{
    return ( ((x)>0) ? ((int)x) : ((int)x-1 ) );
}

const float FPS = 120.0;
enum MYKEYS
{
    KEY_W, KEY_S, KEY_A, KEY_D, KEY_R, KEY_F, KEY_P, KEY_LCTRL, KEY_SPACE, KEY_ALT, KEY_ESC
};

ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_DISPLAY_MODE disp_data;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer = NULL;
ALLEGRO_TIMER *millisecond_timer = NULL;
float cursor_x = 0;
float cursor_y = 0;
float rat_dx = 0;
float rat_dy = 0;
int y_axis = 1;
int gamepaused = 1;
bool key[11] = { false, false, false, false, false, false, false, false, false, false, false };
bool redraw = true;
bool doexit = false;
bool compatibility = 0; //               ------------------ video compatibility mode for analog monitors
double phi = 100.0;
double oldphi = 100.0;
double theta = 0.0;
double oldtheta = 0.0;
char wire_mode = 0;
float aim_spread = 0.0f;
float projectile[6] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
float looking_at[6] = {-0.0f,1.0f,9.0f,-0.0f,1.0f,9.0f};
float cam_unit_vector[6] = {0.0f,1.0f,0.0f,0.0f,1.0f,0.0f};
float proj_unit_vector[9] = {0.0f,1.0f,0.0f,0.0f,1.0f,0.0f,0.0f,1.0f,0.0f};
int lazy_gun_state = 3;
float drag_force = 0;
float upvector[6] = {0.0f,0.0f,1.0f,0.0f,0.0f,1.0f};
float eye[6] = {0.0f,0.0f,9.0f,0.0f,0.0f,9.0f};
float cam_speed = 12.0;
int slow_speed = 0;

int main(int argc, char **argv)
{
    if(!al_init())
    {
        fprintf(stderr, "failed to initialize allegro!\n");
        getchar();
        return -1;
    }

    al_init_image_addon();

    if(!al_install_keyboard())
    {
        fprintf(stderr, "failed to initialize the keyboard!\n");
        getchar();
        return -1;
    }

    if(!al_install_mouse())
    {
        fprintf(stderr, "failed to initialize the mouse!\n");
        getchar();
        return -1;
    }

    timer = al_create_timer(1.0 / FPS);
    if(!timer)
    {
        fprintf(stderr, "failed to create timer!\n");
        getchar();
        return -1;
    }
    millisecond_timer = al_create_timer(0.001);
    if(!millisecond_timer)
    {
        fprintf(stderr, "failed to create millisecond timer!\n");
        getchar();
        return -1;
    }

    int d_pixels[al_get_num_display_modes()];
    for (int n = 0; n < al_get_num_display_modes() - 1; n++)
    {
        al_get_display_mode(n, &disp_data);
        d_pixels[n] = disp_data.height*disp_data.width;
    }
    int d_index = 0;
    int old_d_var = d_pixels[0];
    for (int n = 0; n < al_get_num_display_modes() - 1; n++)
    {
        if(d_pixels[n]>old_d_var) d_index = n;
        old_d_var = d_pixels[n];
    }
    al_get_display_mode(d_index, &disp_data);
    al_set_new_display_flags(ALLEGRO_OPENGL|ALLEGRO_FULLSCREEN);
    if (compatibility)
    {
        display = al_create_display(800, 600);
    }
    else
    {
        display = al_create_display(disp_data.width, disp_data.height);
    }
    if(!display)
    {
        fprintf(stderr, "failed to create display!\n");
        getchar();
        al_destroy_timer(timer);
        al_destroy_timer(millisecond_timer);
        return -1;
    }
    al_hide_mouse_cursor(display);
    int d_w = al_get_display_width(display);
    int d_h = al_get_display_height(display);
    float aspect_ratio = 1.0*d_w/d_h;

    ALLEGRO_PATH *path;
    path = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
    al_change_directory(al_path_cstr(path,ALLEGRO_NATIVE_PATH_SEP));

//al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
    ALLEGRO_BITMAP *terrainimg = NULL;
    //Assuming you have one large image for terrain
    terrainimg = al_load_bitmap("noise.tif");
    if(!terrainimg)
    {
        //al_show_native_message_box(0,"Error","Unable to load terrain file","",NULL,0);
        fprintf(stderr,"Can't load terrain image\n");
        return 1;
    }

    GLuint terrainimgID = al_get_opengl_texture(terrainimg);  //It needs a number to associate which image you want to show at the moment
//    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);  //make it look nicer
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

    if(!al_init_primitives_addon())
    {
        fprintf(stderr, "failed to initialize primitives!\n");
        getchar();
        al_destroy_display(display);
        al_destroy_timer(timer);
        al_destroy_timer(millisecond_timer);
        return -1;
    }

    al_init_font_addon();
    al_init_ttf_addon();
    ALLEGRO_FONT *font_tt = al_load_ttf_font("VeraMono.ttf",int(24.0*d_h/1080.0),0 );

    al_set_target_bitmap(al_get_backbuffer(display));

    event_queue = al_create_event_queue();
    if(!event_queue)
    {
        fprintf(stderr, "failed to create event_queue!\n");
        al_destroy_display(display);
        al_destroy_timer(timer);
        al_destroy_timer(millisecond_timer);
        return -1;
    }

    al_register_event_source(event_queue, al_get_display_event_source(display));
    al_register_event_source(event_queue, al_get_timer_event_source(timer));
    al_register_event_source(event_queue, al_get_keyboard_event_source());
    al_register_event_source(event_queue, al_get_mouse_event_source());

    al_clear_to_color(al_map_rgb(0,0,0));
    al_flip_display();

    al_start_timer(timer);
    al_start_timer(millisecond_timer);

    long int timercount = 0;
    long int mscount = al_get_time();
    while(!doexit)
    {
        ALLEGRO_EVENT ev;
        al_wait_for_event(event_queue, &ev);

        if(ev.type == ALLEGRO_EVENT_TIMER)
        {
            lazy_gun_state+=1;
            timercount++;
            if(gamepaused==0)
            {
                phi -= rat_dx/4.0;
                theta += y_axis*rat_dy/4.0;
                if(theta > 100.0)
                {
                    theta = 100.0;
                }
                else if(theta < -100.0)
                {
                    theta = -100.0;
                }
                if(phi > 400.0)                     // wraps camera azimuth
                {
                    phi -= 400.0;
                }
                else if(phi < 0.0)
                {
                    phi += 400.0;
                }
                if (abs(theta)<99.999)
                {
                    for (int i = 0; i < 3; i++)
                    {
                        upvector[i]=upvector[i+3];
                    }
                }
                else
                {
                    upvector[0] = 1.0*cos((phi+200*(theta>0.0))*M_2PIE/400.0);
                    upvector[1] = 1.0*sin((phi+200*(theta>0.0))*M_2PIE/400.0);
                    upvector[2] = 0.0;
                }
                char diagonal_movement = 1;
                if (key[KEY_W])
                {
                    diagonal_movement += 1;
                }
                if (key[KEY_S])
                {
                    diagonal_movement += 1;
                }
                if (key[KEY_A])
                {
                    diagonal_movement += 1;
                }
                if (key[KEY_D])
                {
                    diagonal_movement += 1;
                }
                float cam_speed_adjusted = cam_speed*(1.0-0.2928932188134524*(diagonal_movement%2));
                if (key[KEY_ALT]) cam_speed_adjusted*=6.25;
                if (key[KEY_LCTRL]) cam_speed_adjusted*=0.064;
                if (slow_speed) cam_speed_adjusted*=0.004096;

                if (key[KEY_W])
                {
                    eye[0] -= cam_speed_adjusted * sin((phi - 100.0)*M_2PIE/400.0) * cos(theta*M_2PIE/400.0) / FPS;
                    eye[1] += cam_speed_adjusted * cos((phi - 100.0)*M_2PIE/400.0) * cos(theta*M_2PIE/400.0) / FPS;
                    eye[2] += cam_speed_adjusted * sin(theta*M_2PIE/400.0) / FPS;
                }
                if (key[KEY_S])
                {
                    eye[0] += cam_speed_adjusted * sin((phi - 100.0)*M_2PIE/400.0) * cos(theta*M_2PIE/400.0) / FPS;
                    eye[1] -= cam_speed_adjusted * cos((phi - 100.0)*M_2PIE/400.0) * cos(theta*M_2PIE/400.0) / FPS;
                    eye[2] -= cam_speed_adjusted * sin(theta*M_2PIE/400.0) / FPS;
                }
                if (key[KEY_A])
                {
                    eye[0] -= cam_speed_adjusted * sin(phi*M_2PIE/400.0) / FPS;
                    eye[1] += cam_speed_adjusted * cos(phi*M_2PIE/400.0) / FPS;
                }
                if (key[KEY_D])
                {
                    eye[0] += cam_speed_adjusted * sin(phi*M_2PIE/400.0) / FPS;
                    eye[1] -= cam_speed_adjusted * cos(phi*M_2PIE/400.0) / FPS;
                }
            }
            if (lazy_gun_state==9)
            {
                for (int i = 0; i < 3; i++)
                {
                    projectile[i] = eye[i]+proj_unit_vector[i]*1.4+proj_unit_vector[i+3]*0.1+proj_unit_vector[i+6]*0.1;
                    projectile[i+3] = proj_unit_vector[i]*0.1+eye[i]-eye[i+3];
                }

            }
            float proj_speed_sq = (projectile[3]*projectile[3]+projectile[4]*projectile[4]+projectile[5]*projectile[5]);
            drag_force = 100.0*0.5*1.293*proj_speed_sq*0.47*0.0314*(1.0/FPS);
            float proj_speed = pow(proj_speed_sq,0.5);
            float speed_multiplier = (proj_speed-drag_force)/proj_speed;
            for (int i = 0; i < 3; i++)
            {
                projectile[i+3] *= speed_multiplier;//+= (projectile[i+3]<0)*drag_force + (projectile[i+3]>0)*drag_force*-1.0;
                projectile[i] += projectile[i+3];
            }
            projectile [5] -= 0.01*9.8/FPS;

            cam_unit_vector[0]=1.0*cos(phi*M_2PIE/400.0)*cos(theta*M_2PIE/400.0);
            cam_unit_vector[1]=1.0*sin(phi*M_2PIE/400.0)*cos(theta*M_2PIE/400.0);
            cam_unit_vector[2]=1.0*sin(theta*M_2PIE/400.0);
            proj_unit_vector[0]=0.0-sin((phi - 100.0)*M_2PIE/400.0) * cos(theta*M_2PIE/400.0);
            proj_unit_vector[1]=cos((phi - 100.0)*M_2PIE/400.0) * cos(theta*M_2PIE/400.0);
            proj_unit_vector[2]=sin(theta*M_2PIE/400.0);
            proj_unit_vector[3]=0.0-sin((phi - 200.0)*M_2PIE/400.0);// * cos(theta*M_2PIE/400.0);
            proj_unit_vector[4]=cos((phi - 200.0)*M_2PIE/400.0);// * cos(theta*M_2PIE/400.0);
            proj_unit_vector[5]=sin(theta*M_2PIE/400.0);
            proj_unit_vector[6]=0.0-sin((phi - 100.0)*M_2PIE/400.0) * cos((theta-100.0)*M_2PIE/400.0);
            proj_unit_vector[7]=cos((phi - 100.0)*M_2PIE/400.0) * cos((theta-100.0)*M_2PIE/400.0);
            proj_unit_vector[8]=sin((theta-100.0)*M_2PIE/400.0);//*(1.0-2.0*(theta<0.0));
            looking_at[0]=eye[0]+cam_unit_vector[0];
            looking_at[1]=eye[1]+cam_unit_vector[1];
            looking_at[2]=eye[2]+cam_unit_vector[2];
            aim_spread += ( ( abs(oldphi-phi)<200 ? abs(oldphi-phi) : 400-abs(oldphi-phi) )/100.0+abs(oldtheta-theta)/100.0
                            +pow(pow((cam_unit_vector[3]-cam_unit_vector[0]),2.0)
                                 +pow((cam_unit_vector[4]-cam_unit_vector[1]),2.0)
                                 +pow((cam_unit_vector[5]-cam_unit_vector[2]),2.0),0.5)
                            +pow(pow((eye[3]-eye[0]),2.0)+pow((eye[4]-eye[1]),2.0)+pow((eye[5]-eye[2]),2.0),0.5) )/3.0;
            aim_spread*=0.9;
            for (int n = 0; n < 3; n++)
            {
                looking_at[3+n]=looking_at[n];
                cam_unit_vector[3+n]=cam_unit_vector[n];
                eye[3+n]=eye[n];
            }
            oldphi=phi;
            oldtheta=theta;

            redraw = true;
            rat_dx = 0;
            rat_dy = 0;
        }
        else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)  // for windowed mode
        {
            //break;
        }
        else if(ev.type == ALLEGRO_EVENT_MOUSE_AXES                 // mouse input
                || ev.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY)  // for windowed mode
        {
            cursor_x = ev.mouse.x;
            cursor_y = ev.mouse.y;
            rat_dx += ev.mouse.dx;
            rat_dy += ev.mouse.dy;
        }
        if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)     // menu click detection
        {
            if (gamepaused == 0)
            {
                lazy_gun_state = 0;
                //
            }
            if (gamepaused == 1)
            {
                if ( cursor_x>=d_w*0.35 && cursor_x<=d_w*0.65 && cursor_y>=d_h*0.61 && cursor_y<=d_h*0.69 )
                {
                    doexit = true;
                }
                if ( cursor_x>=d_w*(0.65-.07*d_h/d_w) && cursor_y>=d_h*0.52 &&
                        cursor_x<=d_w*(0.65-.01*d_h/d_w) && cursor_y<=d_h*0.58 )
                {
                    if (y_axis==1) y_axis=-1;
                    else y_axis=1;
                }
                if ( cursor_x>=d_w*0.35 && cursor_x<=d_w*0.65 && cursor_y>=d_h*0.41 && cursor_y<=d_h*0.49 )
                {
                    gamepaused += 1;
                    gamepaused %= 2;
                }
            }
        }

        if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
        {
            switch(ev.keyboard.keycode)
            {
            case ALLEGRO_KEY_W:
                key[KEY_W] = true;
                break;

            case ALLEGRO_KEY_S:
                key[KEY_S] = true;
                break;

            case ALLEGRO_KEY_A:
                key[KEY_A] = true;
                break;

            case ALLEGRO_KEY_D:
                key[KEY_D] = true;
                break;

            case ALLEGRO_KEY_R:    // fast/slow movement speed
                slow_speed += 1;
                slow_speed %= 2;
                key[KEY_R] = true;
                break;

            case ALLEGRO_KEY_F:   // wireframe mode
                wire_mode += 1;
                wire_mode %= 2;
                key[KEY_F] = true;
                break;

            case ALLEGRO_KEY_P:
                eye[0]=0.0;
                eye[1]=0.0;
                eye[2]=9.0;
                phi=100.0;
                theta=0.0;
                key[KEY_P] = true;
                break;

            case ALLEGRO_KEY_LCTRL:    // slower movement speed
                key[KEY_LCTRL] = true;
                break;

            case ALLEGRO_KEY_ALT:   // faster movement speed
                key[KEY_ALT] = true;
                break;

            case ALLEGRO_KEY_SPACE:
                key[KEY_SPACE] = true;
                break;

            case ALLEGRO_KEY_ESCAPE:
                gamepaused += 1;
                gamepaused %= 2;       // toggle game paused state
                break;

            case ALLEGRO_KEY_F4:
                if (key[KEY_ALT] == true)          // alt-F4 exits
                {
                    doexit = true;
                }
                break;
            }
        }
        else if(ev.type == ALLEGRO_EVENT_KEY_UP)
        {
            switch(ev.keyboard.keycode)
            {
            case ALLEGRO_KEY_W:
                key[KEY_W] = false;
                break;

            case ALLEGRO_KEY_S:
                key[KEY_S] = false;
                break;

            case ALLEGRO_KEY_A:
                key[KEY_A] = false;
                break;

            case ALLEGRO_KEY_D:
                key[KEY_D] = false;
                break;

            case ALLEGRO_KEY_R:
                key[KEY_R] = false;
                break;

            case ALLEGRO_KEY_F:
                key[KEY_F] = false;
                break;

            case ALLEGRO_KEY_P:
                key[KEY_P] = false;
                break;

            case ALLEGRO_KEY_LCTRL:
                key[KEY_LCTRL] = false;
                break;

            case ALLEGRO_KEY_SPACE:
                key[KEY_SPACE] = false;
                break;

            case ALLEGRO_KEY_ALT:
                key[KEY_ALT] = false;
                break;
            }
        }

        if(redraw && al_is_event_queue_empty(event_queue))
        {
            al_clear_to_color(al_map_rgb(0,0,0));

// 3d
            glEnable(GL_DEPTH_TEST);
            glDepthMask(GL_TRUE);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            gluPerspective(85,aspect_ratio,0.001,1000000);
            gluLookAt(eye[0],eye[1],eye[2],                            // camera is here
                      looking_at[0],looking_at[1],looking_at[2],       // camera is looking towards this point
                      upvector[0],upvector[1],upvector[2]);                                 // up vector

            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            if(wire_mode)
            {
                glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
            }
            else
            {
                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
            }

            // 3d drawing code
            glEnable(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D,terrainimgID);    //the actual association

            for (int i = 0; i < 31; i++)
            {
                for (int j = 0; j < 31; j++)
                {
                    float vheight = noise2d (i/4.0,j/4.0,1) * 0.5 + 0.5;
                    glBegin(GL_TRIANGLE_STRIP);
                    float colournoise = noise2d (i/3.0+0.333,j/3.0+0.333,3) * 0.5 + 0.5;
                    float vcolour = ( vheight>0.5 ? vheight * colournoise : 1.0-(1.0-vheight)*1.0-colournoise );
                    glColor3f(vcolour,vcolour,vcolour);
                    vheight *=2.0;
                    glTexCoord2f(0.0f, 0.0f);
                    glVertex3d(i-16,j-16,vheight);
                    glTexCoord2f(0.0f, 1.0f);
                    glVertex3d(i-16,j-15,vheight);
                    glTexCoord2f(1.0f, 0.0f);
                    glVertex3d(i-15,j-16,vheight);
                    glTexCoord2f(1.0f, 1.0f);
                    glVertex3d(i-15,j-15,vheight);
                    glEnd();
                }
            }
            {
                double sqrt_brightness = 100.0;
                double big_star[11][4];

                glDisable(GL_TEXTURE_2D);
                big_star[10][0] = projectile[0];
                big_star[10][1] = projectile[1];
                big_star[10][2] = projectile[2]+0.001*sqrt_brightness;
                big_star[11][0] = projectile[0];
                big_star[11][1] = projectile[1];
                big_star[11][2] = projectile[2]-0.001*sqrt_brightness;

                for(int k = 0; k <= 9; k++)
                {
                    big_star[k][0] = projectile[0]+sin(k * M_2_5_PIE - M_1_5_PIE*(k<5) )*0.0008660254037*sqrt_brightness;
                    big_star[k][1] = projectile[1]+cos(k * M_2_5_PIE - M_1_5_PIE*(k<5) )*0.0008660254037*sqrt_brightness;
                    big_star[k][2] = projectile[2]+0.0005*sqrt_brightness*((k<5)*2-1);
                }
                glEnd();
                glColor3d(1.0f,1.0f,1.0f);
                glBegin(GL_TRIANGLE_FAN);
                for(int k = 0; k <= 4; k++)
                {
                    glTexCoord2f(0.0f, 0.0f);
                    glVertex3d(big_star[10][0],big_star[10][1],big_star[10][2]);
                    glTexCoord2f(1.0f, 0.0f);
                    glVertex3d(big_star[k][0],big_star[k][1],big_star[k][2]);
                    glTexCoord2f(1.0f, 1.0f);
                    glVertex3d(big_star[(k+1)%5][0],big_star[(k+1)%5][1],big_star[(k+1)%5][2]);
                }
                glEnd();
                glBegin(GL_TRIANGLE_FAN);
                for(int k = 5; k <= 9; k++)
                {
                    glTexCoord2f(0.0f, 0.0f);
                    glVertex3d(big_star[11][0],big_star[11][1],big_star[11][2]);
                    glTexCoord2f(0.0f, 1.0f);
                    glVertex3d(big_star[k][0],big_star[k][1],big_star[k][2]);
                    glTexCoord2f(1.0f, 1.0f);
                    glVertex3d(big_star[(k-4)%5+5][0],big_star[(k-4)%5+5][1],big_star[(k-4)%5+5][2]);
                }
                glEnd();
                glBegin(GL_TRIANGLES);
                //glColor3d(1.0f,1.0f,0.0f);

                for(int k = 0; k <= 5; k++)
                {
                    glTexCoord2f(0.0f, 0.0f);
                    glVertex3d(big_star[k%5][0],big_star[k%5][1],big_star[k%5][2]);
                    glTexCoord2f(0.0f, 1.0f);
                    glVertex3d(big_star[k%5+5][0],big_star[k%5+5][1],big_star[k%5+5][2]);
                    glTexCoord2f(1.0f, 0.0f);
                    glVertex3d(big_star[(k+1)%5][0],big_star[(k+1)%5][1],big_star[(k+1)%5][2]);

                    glTexCoord2f(1.0f, 0.0f);
                    glVertex3d(big_star[k%5+5][0],big_star[k%5+5][1],big_star[k%5+5][2]);
                    glTexCoord2f(0.0f, 1.0f);
                    glVertex3d(big_star[(k+1)%5][0],big_star[(k+1)%5][1],big_star[(k+1)%5][2]);
                    glTexCoord2f(1.0f, 1.0f);
                    glVertex3d(big_star[(k+1)%5+5][0],big_star[(k+1)%5+5][1],big_star[(k+1)%5+5][2]);
                }
                glEnd();
            }

            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            gluPerspective(85,aspect_ratio,0.001,1000000);
            float lazy_gun[3] = {0.0f,1.0f,0.0f};
            float lazy_state_adjust = 0.0f;
            if (lazy_gun_state<=9)
            {
                lazy_state_adjust = (9.0-lazy_gun_state)/9.0;
            }
            else if (lazy_gun_state<=FPS+9)
            {
                lazy_state_adjust = (lazy_gun_state-9.0)/(FPS*1.0);
            }
            else
            {
                lazy_state_adjust = 1.0f;
            }
            lazy_gun [0] += lazy_state_adjust*noise1d(timercount/500.0,0)/30.0;
            lazy_gun [1] += lazy_state_adjust*noise1d(timercount/500.0,1)/30.0;
            lazy_gun [2] += lazy_state_adjust*noise1d(timercount/500.0,2)/30.0;
            float magnitude_adjust = pow((lazy_gun[0]*lazy_gun[0]+lazy_gun[1]*lazy_gun[1]+lazy_gun[2]*lazy_gun[2]),0.5);
            for (int i = 0; i < 3; i++)
            {
                lazy_gun[i] /= magnitude_adjust;
            }
            gluLookAt(0.0f,0.0f,0.0f,                            // camera is here
                      lazy_gun[0],lazy_gun[1],lazy_gun[2],       // camera is looking towards this point
                      0.0f,0.0f,1.0f);                                 // up vector

            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();

            float wc[6] = {0.1,0.2,0.6,1.4,-0.1,-0.2};

            glBegin(GL_TRIANGLES);

            glTexCoord2f(0.0f, 0.0f);
            glColor4f(0.2f,0.2f,0.2f,1.0f);//1
            glVertex3d(wc[0],wc[2],wc[4]);
            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.2f,0.2f,0.7f,1.0f);
            glVertex3d(wc[0],wc[2],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.7f,0.2f,0.2f,1.0f);
            glVertex3d(wc[1],wc[2],wc[4]);

            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.2f,0.2f,0.7f,1.0f);
            glVertex3d(wc[0],wc[2],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.7f,0.2f,0.2f,1.0f);
            glVertex3d(wc[1],wc[2],wc[4]);
            glTexCoord2f(1.0f, 1.0f);
            glColor4f(0.7f,0.2f,0.7f,1.0f);
            glVertex3d(wc[1],wc[2],wc[5]);

            glTexCoord2f(0.0f, 0.0f);
            glColor4f(0.7f,0.7f,0.2f,1.0f);//3
            glVertex3d(wc[1],wc[3],wc[4]);
            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.7f,0.7f,0.7f,1.0f);
            glVertex3d(wc[1],wc[3],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.2f,0.7f,0.2f,1.0f);
            glVertex3d(wc[0],wc[3],wc[4]);

            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.7f,0.7f,0.7f,1.0f);
            glVertex3d(wc[1],wc[3],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.2f,0.7f,0.2f,1.0f);
            glVertex3d(wc[0],wc[3],wc[4]);
            glTexCoord2f(1.0f, 1.0f);
            glColor4f(0.2f,0.7f,0.7f,1.0f);
            glVertex3d(wc[0],wc[3],wc[5]);

            glTexCoord2f(0.0f, 0.0f);
            glColor4f(0.7f,0.2f,0.2f,1.0f);//2
            glVertex3d(wc[1],wc[2],wc[4]);
            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.7f,0.2f,0.7f,1.0f);
            glVertex3d(wc[1],wc[2],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.7f,0.7f,0.2f,1.0f);
            glVertex3d(wc[1],wc[3],wc[4]);

            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.7f,0.2f,0.7f,1.0f);
            glVertex3d(wc[1],wc[2],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.7f,0.7f,0.2f,1.0f);
            glVertex3d(wc[1],wc[3],wc[4]);
            glTexCoord2f(1.0f, 1.0f);
            glColor4f(0.7f,0.7f,0.7f,1.0f);
            glVertex3d(wc[1],wc[3],wc[5]);

            glTexCoord2f(0.0f, 0.0f);
            glColor4f(0.2f,0.7f,0.2f,1.0f);//4
            glVertex3d(wc[0],wc[3],wc[4]);
            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.2f,0.7f,0.7f,1.0f);
            glVertex3d(wc[0],wc[3],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.2f,0.2f,0.2f,1.0f);
            glVertex3d(wc[0],wc[2],wc[4]);

            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.2f,0.7f,0.7f,1.0f);
            glVertex3d(wc[0],wc[3],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.2f,0.2f,0.2f,1.0f);
            glVertex3d(wc[0],wc[2],wc[4]);
            glTexCoord2f(1.0f, 1.0f);
            glColor4f(0.2f,0.2f,0.7f,1.0f);
            glVertex3d(wc[0],wc[2],wc[5]);

            glTexCoord2f(0.0f, 0.0f);
            glColor4f(0.2f,0.2f,0.2f,1.0f);//5
            glVertex3d(wc[0],wc[2],wc[4]);
            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.2f,0.7f,0.2f,1.0f);
            glVertex3d(wc[0],wc[3],wc[4]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.7f,0.2f,0.2f,1.0f);
            glVertex3d(wc[1],wc[2],wc[4]);

            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.2f,0.7f,0.2f,1.0f);
            glVertex3d(wc[0],wc[3],wc[4]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.7f,0.2f,0.2f,1.0f);
            glVertex3d(wc[1],wc[2],wc[4]);
            glTexCoord2f(1.0f, 1.0f);
            glColor4f(0.7f,0.7f,0.2f,0.95f);
            glVertex3d(wc[1],wc[3],wc[4]);

            glTexCoord2f(0.0f, 0.0f);
            glColor4f(0.2f,0.2f,0.7f,1.0f);//6
            glVertex3d(wc[0],wc[2],wc[5]);
            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.2f,0.7f,0.7f,1.0f);
            glVertex3d(wc[0],wc[3],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.7f,0.2f,0.7f,1.0f);
            glVertex3d(wc[1],wc[2],wc[5]);

            glTexCoord2f(0.0f, 1.0f);
            glColor4f(0.2f,0.7f,0.7f,1.0f);
            glVertex3d(wc[0],wc[3],wc[5]);
            glTexCoord2f(1.0f, 0.0f);
            glColor4f(0.7f,0.2f,0.7f,1.0f);
            glVertex3d(wc[1],wc[2],wc[5]);
            glTexCoord2f(1.0f, 1.0f);
            glColor4f(0.7f,0.7f,0.7f,1.0f);
            glVertex3d(wc[1],wc[3],wc[5]);
////////
            wc[0] = 0.1;
            wc[1] = 0.2;
            wc[2] = 0.8;
            wc[3] = 0.0;
            wc[4] = -0.3;
            wc[5] = -0.2;

            glColor4f(0.4f,0.3f,0.3f,1.0f);//1
            glVertex3d(wc[0],wc[2],wc[4]);
            glVertex3d(wc[0],wc[2],wc[5]);
            glVertex3d(wc[1],wc[2],wc[4]);

            glVertex3d(wc[0],wc[2],wc[5]);
            glVertex3d(wc[1],wc[2],wc[4]);
            glVertex3d(wc[1],wc[2],wc[5]);

            glVertex3d(wc[1],wc[3],wc[4]);
            glVertex3d(wc[1],wc[3],wc[5]);
            glVertex3d(wc[0],wc[3],wc[4]);

            glVertex3d(wc[1],wc[3],wc[5]);
            glVertex3d(wc[0],wc[3],wc[4]);
            glVertex3d(wc[0],wc[3],wc[5]);

            glVertex3d(wc[1],wc[2],wc[4]);
            glVertex3d(wc[1],wc[2],wc[5]);
            glVertex3d(wc[1],wc[3],wc[4]);

            glVertex3d(wc[1],wc[2],wc[5]);
            glVertex3d(wc[1],wc[3],wc[4]);
            glVertex3d(wc[1],wc[3],wc[5]);

            glVertex3d(wc[0],wc[3],wc[4]);
            glVertex3d(wc[0],wc[3],wc[5]);
            glVertex3d(wc[0],wc[2],wc[4]);

            glVertex3d(wc[0],wc[3],wc[5]);
            glVertex3d(wc[0],wc[2],wc[4]);
            glVertex3d(wc[0],wc[2],wc[5]);

            glVertex3d(wc[0],wc[2],wc[4]);
            glVertex3d(wc[0],wc[3],wc[4]);
            glVertex3d(wc[1],wc[2],wc[4]);

            glVertex3d(wc[0],wc[3],wc[4]);
            glVertex3d(wc[1],wc[2],wc[4]);
            glVertex3d(wc[1],wc[3],wc[4]);

            glVertex3d(wc[0],wc[2],wc[5]);
            glVertex3d(wc[0],wc[3],wc[5]);
            glVertex3d(wc[1],wc[2],wc[5]);

            glVertex3d(wc[0],wc[3],wc[5]);
            glVertex3d(wc[1],wc[2],wc[5]);
            glVertex3d(wc[1],wc[3],wc[5]);

            glEnd();
            glClear(GL_DEPTH_BUFFER_BIT);
            glBegin(GL_TRIANGLES);

            glEnd();/*
            glClear(GL_DEPTH_BUFFER_BIT);
            glBegin(GL_TRIANGLES);
            glColor4f(0.2f,0.2f,0.2f,0.55f);
            glVertex3d(wc[0],wc[2],wc[4]);
            glColor4f(0.2f,0.7f,0.2f,0.55f);
            glVertex3d(wc[0],wc[3],wc[4]);
            glColor4f(0.2f,0.7f,0.7f,0.55f);
            glVertex3d(wc[0],wc[3],wc[5]);
            glEnd();*/


            glClear(GL_DEPTH_BUFFER_BIT);

// 2d
            glMatrixMode (GL_PROJECTION);
            glLoadIdentity ();
            glOrtho (0, d_w, d_h, 0, 0, 1);
            glDisable(GL_DEPTH_TEST);
            glMatrixMode (GL_MODELVIEW);
            glLoadIdentity();
            glDisable(GL_TEXTURE_2D);

            // 2d drawing code
            if (!gamepaused)
            {
                float aim_spread2 = (d_h/90.0)*(1.0 + aim_spread)*d_h/1440.0;
                float aim_spread3 = (d_h/60.0)*(1.0 + aim_spread)*d_h/1440.0;
                glBegin(GL_LINES);
                glColor3f(0.8,0.8,1.0);
                glVertex2d(d_w/2-aim_spread3,d_h/2);
                glVertex2d(d_w/2-aim_spread2,d_h/2);
                glVertex2d(d_w/2,d_h/2-aim_spread3);
                glVertex2d(d_w/2,d_h/2-aim_spread2);
                glVertex2d(d_w/2+aim_spread3,d_h/2);
                glVertex2d(d_w/2+aim_spread2,d_h/2);
                glVertex2d(d_w/2,d_h/2+aim_spread3);
                glVertex2d(d_w/2,d_h/2+aim_spread2);
                glEnd();
                glBegin(GL_POINTS);
                glColor3f(0.8,0.8,1.0);
                glVertex2d(d_w/2-1,d_h/2+0.5);
                glEnd();
            }

            if(0)
            {

                glBegin(GL_POINTS);
                for (int i = 0; i < 2560; i++)
                {

                    for (int j = 0; j < 512; j++)
                    {
                        float noise_bw = noise2d ( j * 0.0625+0.333-128.0, i * 0.0625+0.333-128.0, 0)*0.5+0.5;
                        glColor3f(noise_bw,noise_bw,noise_bw);
                        glVertex2d(0+i,0+j);
                    }
                }
                //glClear(GL_DEPTH_BUFFER_BIT);
                glBegin(GL_LINES);
                glColor3f(1.0f,1.0f,1.0f);
                glVertex2d(512,0);
                glVertex2d(512,600);
                glVertex2d(1024,0);
                glVertex2d(1024,600);
                glVertex2d(1536,0);
                glVertex2d(1536,600);
                glEnd();
            }


            if(0)     // for drawing 3d text
            {
                glDisable(GL_DEPTH_TEST);
                glDepthMask(GL_FALSE);

                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                gluPerspective(85,aspect_ratio,0.001,6800);

                gluLookAt(d_w/2.0,d_h/2.0,0.0-d_h*59.0/108.0, // camera is here
                          d_w/2.0,d_h/2.0,1.0-d_h*59.0/108.0, // camera is looking towards this point
                          0.0f,-1.0f,0.0f);                   // up vector

                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
                if(wire_mode)
                {
                    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                }
                else
                {
                    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                }
                glClear(GL_DEPTH_BUFFER_BIT);
            }

            // Allegro OpenGL code for drawing and text

            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
            if (gamepaused)                                                                                      // menu drawing
            {
                al_draw_filled_rectangle( d_w*0.35, d_h*0.61, d_w*0.65, d_h*0.69, al_map_rgb(127, 127, 127) );
                al_draw_rectangle( d_w*0.35, d_h*0.61, d_w*0.65, d_h*0.69, al_map_rgb(63, 63, 63),2 );
                al_draw_textf( font_tt, al_map_rgb(15,15,15), d_w/2, d_h*0.65-12.0*d_h/1080.0, ALLEGRO_ALIGN_CENTRE, "Quit" );
                al_draw_filled_rectangle( d_w*0.35, d_h*0.41, d_w*0.65, d_h*0.49, al_map_rgb(127, 127, 127) );
                al_draw_rectangle( d_w*0.35, d_h*0.41, d_w*0.65, d_h*0.49, al_map_rgb(63, 63, 63),2 );
                al_draw_textf( font_tt, al_map_rgb(15,15,15), d_w/2, d_h*0.45-12.0*d_h/1080.0, ALLEGRO_ALIGN_CENTRE, "Resume" );
                al_draw_filled_rectangle( d_w*0.35, d_h*0.51, d_w*0.65, d_h*0.59, al_map_rgb(127, 127, 127) );
                al_draw_rectangle( d_w*0.35, d_h*0.51, d_w*0.65, d_h*0.59, al_map_rgb(63, 63, 63),2 );

                if (y_axis==1)                                                                       // 'y axis is inverted' checkbox
                {
                    al_draw_line( d_w*(0.65-.07*d_h/d_w), d_h*0.52, d_w*(0.65-.01*d_h/d_w), d_h*0.58, al_map_rgb(15, 15, 15),2);
                    al_draw_line( d_w*(0.65-.07*d_h/d_w), d_h*0.58, d_w*(0.65-.01*d_h/d_w), d_h*0.52, al_map_rgb(15, 15, 15),2);
                }
                al_draw_rectangle( d_w*(0.65-.07*d_h/d_w), d_h*0.52, d_w*(0.65-.01*d_h/d_w), d_h*0.58, al_map_rgb(15, 15, 15),2);
                al_draw_textf(font_tt, al_map_rgb(15,15,15), d_w/2, d_h*0.55-12.0*d_h/1080.0, ALLEGRO_ALIGN_CENTRE, "y Inverted");
                float cursor_radius = d_h/60.0;
                al_draw_line( cursor_x-cursor_radius, cursor_y, cursor_x+cursor_radius, cursor_y, al_map_rgb(191, 191, 191),2 );
                al_draw_line( cursor_x, cursor_y-cursor_radius, cursor_x, cursor_y+cursor_radius, al_map_rgb(63, 63, 63),2 );
                al_draw_textf( font_tt, al_map_rgb(255,255,255), d_w/2, 24.0*d_h/1080.0,
                               ALLEGRO_ALIGN_CENTRE, "x %f y %f", cursor_x, cursor_y);                              // mouse position
            }
            else
            {
                al_set_mouse_xy(display,d_w/2,d_h/2);                                                           // set mouse position
                al_draw_textf( font_tt, al_map_rgb(255,255,255),                                                    // camera position
                               d_w/2, 48.0*d_h/1080.0, ALLEGRO_ALIGN_CENTRE, "x %f y %f z %f phi %f theta %f drag %f",
                               eye[0],eye[1],eye[2],phi,theta,drag_force );         // position, phi, theta
            }
            redraw = false;
            al_flip_display();
        }
    }
    al_destroy_timer(timer);
    al_destroy_timer(millisecond_timer);
    al_destroy_display(display);
    al_destroy_event_queue(event_queue);
    return 0;
}
