/**
 * "Disco Stu is on the run" - lame satellite rotator
 * gcc -o rotate rotate.c -O3 `sdl-config --libs --cflags`
 * thp <thpinfo.com/about> 2009-01-11
 *
 * You have to generate a 200x200px "rotate.bmp" file in
 * CWD for this to work. Wicked!
 *
 * And yep, it's inefficient and lame. But funny! Enjoy..
 **/

#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "SDL.h"

#define WIDTH 640
#define HEIGHT 480

#define SIDE 200

#define STEP_ROT 3
#define STEP_Y 1
#define STEP_X 1

#define GET_PIXEL_DATA(surface,x,y) (*((Uint32*)(surface->pixels + x * surface->format->BytesPerPixel + y * surface->pitch)))
#define GET_PIXEL_RGB(surface,x,y,r,g,b) (SDL_GetRGB( GET_PIXEL_DATA(surface,x,y), surface->format, r, g, b))
#define SET_PIXEL_RGB(surface,x,y,r,g,b) (GET_PIXEL_DATA(surface,x,y)=SDL_MapRGB(surface->format, r, g, b))
#define SET_PIXEL_MAP(surface,x,y,map) (GET_PIXEL_DATA(surface,x,y)=map)

int main()
{
    int notquit=1;
    int rot=0, x, y;
    int red, black;
    static short xn[SIDE][SIDE][360], yn[SIDE][SIDE][360];
    SDL_Surface *surface, *bmp, *tmp;
    SDL_Event evt;
    SDL_Init(SDL_INIT_VIDEO);

    tmp = SDL_LoadBMP("rotate.bmp");
    if (tmp->w < SIDE || tmp->h < SIDE) {
        fprintf(stderr, "Bitmap is too small for rotation!\n");
        exit(EXIT_FAILURE);
    }

    for (rot=0; rot<360; rot+=STEP_ROT) {
        fprintf(stderr, "\rCalculating |%c%c%c%c| (%d%%)", " #"[rot%4==0], " #"[rot%4==1], " #"[rot%4==2], " #"[rot%4==3], rot*100/360);
        for (x=0; x<SIDE; x+=STEP_X) {
            for (y=0; y<SIDE; y+=STEP_Y) {
                xn[x][y][rot] = WIDTH/2 + (x-SIDE/2)*cosf(rot*M_PI/180) + (y-SIDE/2)*-sinf(rot*M_PI/180);
                yn[x][y][rot] = HEIGHT/2 + (x-SIDE/2)*sinf(rot*M_PI/180) + (y-SIDE/2)*cosf(rot*M_PI/180);
            }
        }
    }

    fprintf(stderr, "\rCalculating - done.\n");

    surface = SDL_SetVideoMode(WIDTH, HEIGHT, 0, SDL_SWSURFACE | SDL_FULLSCREEN);
    SDL_ShowCursor(0);

    bmp = SDL_DisplayFormat(tmp);
    SDL_FreeSurface(tmp);

    red = SDL_MapRGB(surface->format, 255, 0, 0);
    black = SDL_MapRGB(surface->format, 0, 0, 0);
    while (notquit) {
        if (SDL_PollEvent(&evt)) {
            switch (evt.type) {
                case SDL_KEYDOWN:
                case SDL_KEYUP:
                    notquit=0;
                    break;
            }
        }
        SDL_LockSurface(surface);
        SDL_LockSurface(bmp);
        for (x=0; x<SIDE; x+=STEP_X) {
            for (y=0; y<SIDE; y+=STEP_Y) {
                SET_PIXEL_MAP(surface, xn[x][y][rot], yn[x][y][rot], GET_PIXEL_DATA(bmp, x, y));
            }
        }
        SDL_UnlockSurface(bmp);
        SDL_UnlockSurface(surface);
        SDL_Flip(surface);
        SDL_LockSurface(surface);
        for (x=0; x<SIDE; x+=SIDE-1) {
            for (y=0; y<SIDE; y+=STEP_Y) {
                SET_PIXEL_MAP(surface, xn[x][y][rot], yn[x][y][rot], black);
            }
        }
        for (x=0; x<SIDE; x+=STEP_X) {
            for (y=0; y<SIDE; y+=SIDE-1) {
                SET_PIXEL_MAP(surface, xn[x][y][rot], yn[x][y][rot], black);
            }
        }
        SDL_UnlockSurface(surface);
        rot = (rot+STEP_ROT) % 360;
    }
    SDL_FreeSurface(bmp);
    SDL_Quit();
}

