void mp_setpixel(int x, int y, Uint8 r, Uint8 g, Uint8 b) 
{
    int p;
    if (x>=0 && x<SCREEN_WIDTH && y>=0 && y<SCREEN_HEIGHT) {
        p = (x + y*SCREEN_WIDTH) * 3;
        ((Uint8 *)screen->pixels)[p++] = b;
        ((Uint8 *)screen->pixels)[p++] = g;
        ((Uint8 *)screen->pixels)[p] = r;
    }
}



void mp_setpixel_alpha(int x, int y, Uint8 r, Uint8 g, Uint8 b)
{
    int p;
    if (x>=0 && x<SCREEN_WIDTH && y>=0 && y<SCREEN_HEIGHT) {
        p = (x + y*SCREEN_WIDTH) * 3;
        ((Uint8 *)screen->pixels)[p] = ((Uint8 *)screen->pixels)[p++]>>1 + b>>1;
        ((Uint8 *)screen->pixels)[p] = ((Uint8 *)screen->pixels)[p++]>>1 + g>>1;
        ((Uint8 *)screen->pixels)[p] = ((Uint8 *)screen->pixels)[p]>>1 + r>>1;
    }
}



void mp_setpixel_add(int x, int y, Uint8 r, Uint8 g, Uint8 b)
{
    int p,c;
    if (x>=0 && x<SCREEN_WIDTH && y>=0 && y<SCREEN_HEIGHT) {
        p = (x + y*SCREEN_WIDTH) * 3;
        c = ((Uint8 *)screen->pixels)[p]+b; ((Uint8 *)screen->pixels)[p++] = (c > 255) ? 255 : c;
        c = ((Uint8 *)screen->pixels)[p]+g; ((Uint8 *)screen->pixels)[p++] = (c > 255) ? 255 : c;
        c = ((Uint8 *)screen->pixels)[p]+r; ((Uint8 *)screen->pixels)[p] = (c > 255) ? 255 : c;
    }
}



void mp_setpixel3d(float fx, float fy, float fz, Uint8 r, Uint8 g, Uint8 b)
{
    int x,y;
    fx = (fx/((fz-400)/400));
    fy = (fy/((fz-400)/400));
    x = (int)fx + 200;
    y = (int)fy + 150;
    mp_setpixel_alpha(x-1,y  ,r,g,b);
    mp_setpixel_alpha(x+1,y  ,r,g,b);
    mp_setpixel_alpha(x  ,y-1,r,g,b);
    mp_setpixel_alpha(x  ,y+1,r,g,b);
    mp_setpixel(x,y,r,g,b);
    //printf("%d %d %d %d %d\n", x, y, r, g, b);
}



void gen_ring(int i)
{
    ring_obj[i].x = 0;
    ring_obj[i].y = 0;
    ring_obj[i].r = 20;
}



void draw_line(int x1,int y1,int x2,int y2)
{
    int t;
    if (abs(x2 - x1) > abs(y2 - y1)) {
        if (x2 > x1) {
            for (t = x1; t <= x2; t++) {
                mp_setpixel_add(t,(y1 + ((y2 - y1) * ((t - x1 + 1)) / (x2 - x1 + 1))),5,5,30);
            }
        } else {
            for (t = x2; t <= x1; t++) {
                mp_setpixel_add(t,(y2 + ((y1 - y2) * ((t - x2 + 1)) / (x1 - x2 + 1))),5,5,30);
            }
        }
    } else {
        if (y2 > y1) {
            for (t = y1; t <= y2; t++) {
                mp_setpixel_add(x1 + ((x2 - x1) * ((t - y1 + 1))) / (y2 - y1 +1),t,5,5,30);
            }
        } else {
            for (t = y2; t <= y1; t++) {
                mp_setpixel_add(x2 + ((x1 - x2) * ((t - y2 + 1))) / (y1 - y2 +1),t,5,5,30);
            }
        }
    }
}



void cleanup(void)
{
    /* TODO: free bitmaps etc. Hey, it's soon deadline... */
    SDL_ShowCursor(SDL_ENABLE);
}



int main(int argc, char **argv)
{
    int i,j;
    int x,y;
    float x0,y0,z0;
    float v1,v2;
    int flags;

    if (argc==2 && strcmp(argv[1], "--window")==0) {
        flags = SDL_HWSURFACE|SDL_DOUBLEBUF;
    } else {
        flags = SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN;
    }

    if (SDL_Init(SDL_INIT_AUDIO) < 0) {
        fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
        exit(EXIT_FAILURE);
    }
    
    if ((screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 24, flags)) == NULL) {
        fprintf(stderr, "Couldn't open video device: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }

    if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 4096) < 0) {
        fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }

    if ((music = Mix_LoadMUS(DATAFILE("pip.mod"))) == NULL) {
        fprintf(stderr, "Couldn't load music: %s\n", SDL_GetError());
        exit(EXIT_FAILURE);
    }

    /* init rot_objects */
    for (i=0; i<2000; i++) {
        v1 = (float)(rand()%628)/100;
        v2 = (float)(rand()%628)/100;
        x0 = (sin(v1)*75)*cos(v2);
        y0 = (cos(v1)*75)*cos(v2);
        z0 = (sin(v2)*75);
        rot_obj_show[i].x = (float)x0;
        rot_obj_show[i].y = (float)y0;
        rot_obj_show[i].z = (float)z0;
    }

    /* init ring_objects */
    for (i=0; i<50; i++) {
        gen_ring(i);
        ring_obj[i].r += i*6;
    }

    /* init blur_objects */
    for (i=0; i<100; i++) {
        blur_obj[i].sinx = (float)(rand()%628)/100;
        blur_obj[i].siny = (float)(rand()%628)/100;
        blur_obj[i].sinz = (float)(rand()%628)/100;
        blur_obj[i].facx = (float)(rand()%300)-150;
        blur_obj[i].facy = (float)(rand()%200)-100;
        blur_obj[i].facz = (float)(rand()%20)-10;
        blur_obj[i].hasx = (float)(rand()%100)/3000-(50/3000);
        blur_obj[i].hasy = (float)(rand()%100)/3000-(50/3000);
        blur_obj[i].hasz = (float)(rand()%100)/3000-(50/3000);
    }

    intro    = IMG_Load(DATAFILE("intro.png"));
    bg       = IMG_Load(DATAFILE("bg.png"));
    tux      = IMG_Load(DATAFILE("tux.gif"));
    nerf     = IMG_Load(DATAFILE("nerf.png"));
    greet    = IMG_Load(DATAFILE("greet.png"));
    freeu    = IMG_Load(DATAFILE("free.png"));
    blur     = IMG_Load(DATAFILE("blur.gif"));
    gnu      = IMG_Load(DATAFILE("gnu.png"));
    code0    = IMG_Load(DATAFILE("code0.gif"));
    outtro   = IMG_Load(DATAFILE("outtro.png"));
    txt_a    = IMG_Load(DATAFILE("text_code.png"));
    txt_b    = IMG_Load(DATAFILE("text_music.png"));
    test     = IMG_Load(DATAFILE("test.png"));
    stars[0] = IMG_Load(DATAFILE("star0.png"));
    stars[1] = IMG_Load(DATAFILE("star1.png"));
    stars[2] = IMG_Load(DATAFILE("star2.png"));
    gnutxt   = IMG_Load(DATAFILE("gnutxt.png"));

    SDL_SetColorKey(tux, (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)tux->pixels);
    SDL_SetColorKey(nerf, (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)nerf->pixels);
    SDL_SetColorKey(greet, (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)greet->pixels);
    SDL_SetColorKey(freeu, (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)freeu->pixels);
    SDL_SetColorKey(code0, (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)code0->pixels);
    SDL_SetAlpha(code0, SDL_SRCALPHA, 128);
    SDL_SetColorKey(txt_a, (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)txt_a->pixels);
    SDL_SetColorKey(txt_b, (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)txt_b->pixels);
    SDL_SetColorKey(test, (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)test->pixels);
    SDL_SetColorKey(stars[0], (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)stars[0]->pixels);
    SDL_SetColorKey(stars[1], (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)stars[1]->pixels);
    SDL_SetColorKey(stars[2], (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)stars[2]->pixels);
    SDL_SetColorKey(gnutxt, (SDL_SRCCOLORKEY|SDL_RLEACCEL), *(Uint8 *)gnutxt->pixels);
    SDL_SetAlpha(gnutxt, SDL_SRCALPHA, 128);

    {
        int x,y;
        /* hehe, leak (it's not MY mem ;-) */
        blur = SDL_DisplayFormatAlpha(blur);
        for (y=0; y<blur->h; y++) {
            for (x=0; x<blur->w; x++) {
                ((Uint8 *)blur->pixels)[4*(x+y*blur->w)+3] = ((Uint8 *)blur->pixels)[4*(x+y*blur->w)+0] << 1;
                ((Uint8 *)blur->pixels)[4*(x+y*blur->w)+2] = 255;
                ((Uint8 *)blur->pixels)[4*(x+y*blur->w)+1] = 255;
                ((Uint8 *)blur->pixels)[4*(x+y*blur->w)+0] = 255;
            }
        }
    }

    SDL_ShowCursor(SDL_DISABLE);

    Mix_FadeInMusic(music, 0, 500);

    starttick = SDL_GetTicks();

    effect_0();
    effect_1();
    trans_12();
    effect_2();
    effect_3();
    effect_4();

    SDL_ShowCursor(SDL_ENABLE);
    
    return EXIT_SUCCESS;
}



/* INTRO */
void effect_0(void)
{
    SDL_BlitSurface(intro, NULL, screen, NULL);
    while (TICK < END0) {
        PUBLISH
        SDL_Delay(1);
    }
    FLASH
}
