#include <objc/Object.h>
#include <SDL/SDL.h>

#define TRUE 1
#define FALSE 0
#define SPRITE_NUM 100
#define SPRITE_SPEED_MAX 1

@interface Sprite : Object
{
SDL_Surface * surface;
SDL_Rect rect;
Sint32 velocity_x;
Sint32 velocity_y;
}

+ (id)new:(SDL_Surface *)sprite_surface :(SDL_Surface *)screen_surface;
- (void)init:(SDL_Surface *)sprite_surface :(SDL_Surface *)screen_surface;
- (void)Move:(SDL_Surface *)screen_surface;
@end

@implementation Sprite
+ (id)new:(SDL_Surface *)sprite_surface :(SDL_Surface *)screen_surface
{
id result;

result = [self new];
[result init:sprite_surface :screen_surface];

return result;
}

- (void)init:(SDL_Surface *)sprite_surface :(SDL_Surface *)screen_surface
{
surface = sprite_surface;
rect.x = rand() % (screen_surface->w - surface->w);
rect.y = rand() % (screen_surface->h - surface->h);
rect.w = surface->w;
rect.h = surface->h;
velocity_x = 0;
velocity_y = 0;
while(velocity_x == 0 && velocity_y == 0)
{
velocity_x = (rand() % (SPRITE_SPEED_MAX + 1)) * ((rand() & 1) * 2 - 1);
velocity_y = (rand() % (SPRITE_SPEED_MAX + 1)) * ((rand() & 1) * 2 - 1);
}
}

- (void)Move:(SDL_Surface *)screen_surface
{
rect.x += velocity_x;
if((rect.x < 0) || (rect.x >= (screen_surface->w - rect.w)))
{
velocity_x = velocity_x * -1;
rect.x += velocity_x;
}
rect.y += velocity_y;
if((rect.y < 0) || (rect.y >= (screen_surface->h - rect.h)))
{
velocity_y = velocity_y * -1;
rect.y += velocity_y;
}
SDL_BlitSurface(surface,NULL,screen_surface,&rect);
}
@end

@interface TestSprite : Object
{
SDL_Surface * screen_surface;
SDL_Surface * sprite_surface;
Uint32 background_color;
id sprites[SPRITE_NUM];
}

- (id)init;
- (id)free;
- (float)MainLoop;
- (Sint32)LoadSprite;
@end

@implementation TestSprite
- (id)init
{
Sint32 i;

[super init];
if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
fprintf(stderr,"Couldn't initialize SDL: %s\n",SDL_GetError());
exit(1);
}
atexit(SDL_Quit);

screen_surface = SDL_SetVideoMode(640,480,8,SDL_SWSURFACE | SDL_ANYFORMAT);
if(screen_surface == NULL)
{
fprintf(stderr,"Couldn't set %dx%d video mode: %s\n",640,480,SDL_GetError());
exit(1);
}

if([self LoadSprite] == FALSE)
{
exit(1);
}

background_color = SDL_MapRGB(screen_surface->format,0x00,0x00,0x00);

for(i = 0;i < SPRITE_NUM;i++)
{
sprites[i] = [Sprite new:sprite_surface :screen_surface];
}

return self;
}

- (id)free
{
Sint32 i;

SDL_FreeSurface(sprite_surface);
for(i = 0;i < SPRITE_NUM;i++)
{
[sprites[i] free];
}
[super free];

return self;
}

- (float)MainLoop
{
SDL_Event event;
Sint32 i;
Sint32 frame_num;
Sint32 start_ticks;
Sint32 now_ticks;
Sint32 done;

frame_num = 0;
start_ticks = SDL_GetTicks();
done = FALSE;

while(done == FALSE)
{
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_MOUSEBUTTONDOWN:
SDL_WarpMouse(screen_surface->w / 2,screen_surface->h / 2);
break;

case SDL_KEYDOWN:
case SDL_QUIT:
done = TRUE;
break;

default:
break;
}
}

SDL_FillRect(screen_surface,NULL,background_color);
for(i = 0;i < SPRITE_NUM;i++)
{
[sprites[i] Move:screen_surface];
}
SDL_Flip(screen_surface);

frame_num++;
}

now_ticks = SDL_GetTicks();
if(now_ticks > start_ticks)
{
return ((double)frame_num * 1000.0f) / (now_ticks - start_ticks);
}
else
{
return -1.0f;
}
}

- (Sint32)LoadSprite
{
SDL_Surface * tmp_surface;

sprite_surface = SDL_LoadBMP("icon.bmp");
if(sprite_surface == NULL)
{
fprintf(stderr,"Couldn't load icon.bmp: %s",SDL_GetError());
return FALSE;
}

if(sprite_surface->format->palette)
{
SDL_SetColorKey(sprite_surface,(SDL_SRCCOLORKEY | SDL_RLEACCEL),*(Uint8 *)sprite_surface->pixels);
}

tmp_surface = SDL_DisplayFormat(sprite_surface);
SDL_FreeSurface(sprite_surface);
if(tmp_surface == NULL)
{
fprintf(stderr,"Couldn't convert background: %s\n",SDL_GetError());
return FALSE;
}
sprite_surface = tmp_surface;

return TRUE;
}
@end

int main(int argc,char ** argv)
{
id testsprite;
float fps;

testsprite = [TestSprite new];
fps = [testsprite MainLoop];
printf("%2.2f frames per second\n",fps);
[testsprite free];

return 0;
}