/* schierke.c - Don Yang (uguu.org) 10/30/11 */ #include #include #include"SDL.h" #define TRAIL_SIZE 64 #define SWARM_SIZE 256 /* All particles, mapping from cycle to element to swarm of points to (x, y). At each frame, we update points in the next cycle, and raw particles from the previous cycle at a slightly dimmer color. Each value is a fixed point value, with higher 16 bits being the screen coordinates, and the lower 16 bits to be the fractional part. All swarm particles with point index > 0 follows the 0th point. */ Sint32 Position[TRAIL_SIZE][4][SWARM_SIZE][2], Direction[4][SWARM_SIZE][2], Cycle = 0, /* Targets for swarm point 0, same fixed point format as above */ Target[4][2], /* Shared indices */ i, j, k, element, x, y, bpp, run_loop = 1, w = 800, h = 600; /* Drawing state */ Uint32 current_time, next_time, pixel, flags = SDL_HWSURFACE|SDL_DOUBLEBUF, /* Color palette for each elemental */ Palette[4][3] = { {255, 16, 16}, {0, 255, 0}, {255, 255, 64}, {64, 128, 255} }; SDL_Event event; const SDL_VideoInfo *video_info; SDL_Surface *screen; /* Return a random number in the range of [min, max) */ Sint32 Rand(Sint32 min, Sint32 max) { return (max - min) * (float)rand() / RAND_MAX + min; } /* Update velocity for a single point to approach a target point */ void Approach(Sint32 tx, Sint32 minv, Sint32 maxv) { if( Position[Cycle][element][i][j] < tx ) Direction[element][i][j] += Rand(minv, maxv); if( Position[Cycle][element][i][j] > tx ) Direction[element][i][j] -= Rand(minv, maxv); x = Direction[element][i][j]; Direction[element][i][j] = x < -k ? -k : (x > k ? k : x); } /* Render a single frame */ #define RENDER(type) \ { \ /* At each cycle, we will update points such that cycle points at the \ latest set of points. Since we want to draw points from oldest \ cycle to newest cycle, we will start at cycle+1. */ \ for(i = 1; i <= TRAIL_SIZE; i++) \ { \ j = (Cycle + i) % TRAIL_SIZE; \ for(element = 0; element < 4; element++) \ { \ /* The leader point will have shades of white */ \ pixel = SDL_MapRGB(screen->format, \ i * 255 / TRAIL_SIZE, \ i * 255 / TRAIL_SIZE, \ i * 255 / TRAIL_SIZE); \ for(k = 0; k < SWARM_SIZE; k++) \ { \ /* After drawing the leader point, set color to draw \ follower points. */ \ if( k == 1 ) \ pixel = SDL_MapRGB(screen->format, \ Palette[element][0] * i / TRAIL_SIZE, \ Palette[element][1] * i / TRAIL_SIZE, \ Palette[element][2] * i / TRAIL_SIZE); \ \ /* Scale coordinates and clip */ \ x = Position[j][element][k][0]; \ x >>= 16; \ if( x >= 0 && x < w ) \ { \ y = Position[j][element][k][1]; \ y >>= 16; \ if( y >= 0 && y < h ) \ /* Draw pixel */ \ *(type*)((Uint8*)(screen->pixels) + \ y * screen->pitch + \ x * bpp) \ = (type)pixel; \ } \ } \ } \ } \ } void Render16() RENDER(Uint16) void Render32() RENDER(Uint32) int main(int argc, char **argv) { /* Initialize SDL */ if( SDL_Init(SDL_INIT_VIDEO) < 0 ) printf("Unable to init SDL: %s\n", SDL_GetError()); else { atexit(SDL_Quit); /* Initialize surface */ video_info = SDL_GetVideoInfo(); bpp = video_info->vfmt->BytesPerPixel; if( bpp != 2 && bpp != 4 ) puts("Unsupported pixel format"); else { if( argc > 1 ) flags |= SDL_FULLSCREEN; screen = SDL_SetVideoMode(w, h, bpp * 8, flags); if( screen == NULL ) printf("Error initializing screen: %s\n", SDL_GetError()); else { SDL_WM_SetCaption("Schierke", NULL); SDL_ShowCursor(SDL_DISABLE); /* Initialize random seed */ srand(time(NULL)); /* Initialize swarms */ for(element = 0; element < 4; element++) { for(i = 0; i < SWARM_SIZE; i++) { Position[0][element][i][0] = Rand(0, w * 0x10000); for(Position[j = 0][element][i][1] = Rand(0, h * 0x10000); j < 2; Direction[element][i][j++] = Rand(-0x30000, 0x30000)); } for(i = 1; i < TRAIL_SIZE; i++) for(j = 0; j < SWARM_SIZE; j++) for(k = 0; k < 2; k++) Position[i][element][j][k] = Position[0][element][j][k]; Target[element][0] = Rand(0, w * 0x10000); Target[element][1] = Rand(0, h * 0x10000); } for(next_time = SDL_GetTicks(); run_loop;) { next_time += 1000/60; /* Render points */ SDL_LockSurface(screen); SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); if( screen->format->BytesPerPixel == 4 ) Render32(); else Render16(); SDL_UnlockSurface(screen); SDL_Flip(screen); /* Update animation state */ for(element = 0; element < 4; element++) { /* Update target for leader about once per second */ if( !Rand(0, 60) ) { Target[element][0] = Rand(0x1000 * w, 0xf000 * w); Target[element][1] = Rand(0x1000 * h, 0xf000 * h); } k = 0x20000; Approach(Target[element][i = j = 0], 0x10, 0x1000); Approach(Target[element][j = 1], 0x10, 0x1000); /* Update velocities for followers */ k *= 2; for(i = 1; i < SWARM_SIZE; i++) { Approach(Position[Cycle][element][0][j = 0], 0x20, 0x1800); Approach(Position[Cycle][element][0][j = 1], 0x20, 0x1800); } /* Update point positions */ k = (Cycle + 1) % TRAIL_SIZE; for(i = 0; i < SWARM_SIZE; i++) for(j = 0; j < 2; j++) Position[k][element][i][j] = Position[Cycle][element][i][j] + Direction[element][i][j]; } for (Cycle = k; /* Check for keyboard events */ SDL_PollEvent(&event);) if( event.type == SDL_KEYDOWN || event.type == SDL_QUIT ) run_loop = 0; /* Sleep until next frame */ current_time = SDL_GetTicks(); if( current_time < next_time ) SDL_Delay(next_time - current_time); } /* Cleanup */ SDL_FreeSurface(screen); } } SDL_Quit(); } return 0; }