#include #include #include "SDL.h" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define GRID_WIDTH 64 #define GRID_HEIGHT 48 struct GridNode { // Position of the node float x, y; // Height (color) of the node float h; // Movement of the node float fx, fy, fh; }; SDL_Surface *screen; SDL_MouseMotionEvent g_MouseEvent; GridNode g_Grid[GRID_WIDTH][GRID_HEIGHT]; GridNode g_GridOrig[GRID_WIDTH][GRID_HEIGHT]; inline int clamp(int value, int min, int max) { return (value < min) ? min : ((value > max) ? max : value); } inline int GetColor(float fColor) { int iRed = 0, iBlue = 0, iGreen = 0; iGreen = fColor * 255; iBlue = (255 - iGreen) / 8; if(fColor > 1.0f) { iRed = (fColor - 1.0f) * 255; iGreen = 255 - (iRed / 6); iBlue = 0; } iRed = clamp(iRed, 0, 255); iBlue = clamp(iBlue, 0, 255); iGreen = clamp(iGreen, 0, 255); return (iRed << 16) + (iGreen << 8) + iBlue; } void DetonateAt(int dx, int dy, float fPower, float fRadius) { int x, y; for(x = 0; x < GRID_WIDTH; x++) for(y = 0; y < GRID_HEIGHT; y++) if((g_Grid[x][y].x - dx) * (g_Grid[x][y].x - dx) + (g_Grid[x][y].y - dy) * (g_Grid[x][y].y - dy) < fRadius * fRadius) { g_Grid[x][y].fx += (g_Grid[x][y].x - dx) * fPower; g_Grid[x][y].fy += (g_Grid[x][y].y - dy) * fPower; g_Grid[x][y].fh += fPower; } } void tick() { // Ask SDL for the time in milliseconds static int lastTick = SDL_GetTicks() - 100; int iDelta = SDL_GetTicks() - lastTick; lastTick = SDL_GetTicks(); if(iDelta > 33) iDelta = 33; int x, y, nx, ny; signed int xLut[] = { -1, 1, 0, 0}; signed int yLut[] = { 0, 0, -1, 1}; // Pick every node for(x = 0; x < GRID_WIDTH; x++) for(y = 0; y < GRID_HEIGHT; y++) // Make the nodes move all its neighbours for(int i = 0; i < 4; i++) { nx = x + xLut[i], ny = y + yLut[i]; if(nx >= 0 && nx < GRID_WIDTH && ny >= 0 && ny < GRID_HEIGHT) { g_Grid[nx][ny].fx += g_Grid[x][y].fx * iDelta / 350.0f; g_Grid[nx][ny].fy += g_Grid[x][y].fy * iDelta / 350.0f; g_Grid[nx][ny].fh += g_Grid[x][y].fh * iDelta / 350.0f; } } for(x = 0; x < GRID_WIDTH; x++) for(y = 0; y < GRID_HEIGHT; y++) { // Move the nodes g_Grid[x][y].x += g_Grid[x][y].fx * iDelta / 200.0f; g_Grid[x][y].y += g_Grid[x][y].fy * iDelta / 200.0f; g_Grid[x][y].h += g_Grid[x][y].fh * iDelta / 200.0f; // Remove momentum from the nodes g_Grid[x][y].fx -= g_Grid[x][y].fx * iDelta / 90.0f; g_Grid[x][y].fy -= g_Grid[x][y].fy * iDelta / 90.0f; g_Grid[x][y].fh -= g_Grid[x][y].fh * iDelta / 90.0f; } // Move towards their original state for(x = 0; x < GRID_WIDTH; x++) for(y = 0; y < GRID_HEIGHT; y++) { g_Grid[x][y].x -= ((g_Grid[x][y].x - g_GridOrig[x][y].x) * iDelta) / 100.0f; g_Grid[x][y].y -= ((g_Grid[x][y].y - g_GridOrig[x][y].y) * iDelta) / 100.0f; g_Grid[x][y].h -= ((g_Grid[x][y].h - g_GridOrig[x][y].h) * iDelta) / 100.0f; } } inline bool PlotPixel(int x, int y, int color) { if(x < 0 || y < 0 || x > WINDOW_WIDTH -1 || y > WINDOW_HEIGHT -1) return false; ((unsigned int*)screen->pixels)[y * WINDOW_WIDTH + x] = color; return true; } inline void swap(int *x, int *y) { int tmp = *x; *x = *y; *y = tmp; } // Bresenham's line algorithm as explained by wikipedia void DrawLine(int color, int x0, int y0, int x1, int y1) { bool steep = abs(y1 - y0) > abs(x1 - x0); if(steep) { swap(&x0, &y0); swap(&x1, &y1); } if(x0 > x1) { swap(&x0, &x1); swap(&y0, &y1); } signed int y = y0; int deltax = x1 - x0; int deltay = abs(y1 - y0); int error = -deltax / 2; int ystep = (y0 < y1) ? 1 : -1; for(int x = x0; x <= x1; x++) { if(steep) { if(!PlotPixel(y, x, color)) return; } else { if(!PlotPixel(x, y, color)) return; } error = error + deltay; if(error > 0) { y = y + ystep; error = error - deltax; } } } void render() { // Lock surface if needed if (SDL_MUSTLOCK(screen)) if (SDL_LockSurface(screen) < 0) return; // Clear screen SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); // Draw grid signed int xLut[] = { -1, 1, 0, 0}; signed int yLut[] = { 0, 0, -1, 1}; int x, y, nx, ny; float color; for(x = 0; x < GRID_WIDTH; x++) for(y = 0; y < GRID_HEIGHT; y++) { color = g_Grid[x][y].h; for(int i = 0; i < 4; i++) { nx = x + xLut[i], ny = y + yLut[i]; if(nx >= 0 && nx < GRID_WIDTH && ny >= 0 && ny < GRID_HEIGHT) color += g_Grid[nx][ny].h; } color /= 2.0f; for(int i = 0; i < 4; i++) // Doesnt really need all 4 here { nx = x + xLut[i], ny = y + yLut[i]; if(nx >= 0 && nx < GRID_WIDTH && ny >= 0 && ny < GRID_HEIGHT) DrawLine(GetColor(color), g_Grid[x][y].x, g_Grid[x][y].y, g_Grid[nx][ny].x, g_Grid[nx][ny].y); } } // Unlock if needed if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); // Tell SDL to update the whole screen SDL_UpdateRect(screen, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); } // Entry point int main(int argc, char *argv[]) { // Initialize SDL's subsystems - in this case, only video. if(SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); exit(1); } // Register SDL_Quit to be called at exit; makes sure things are // cleaned up when we quit. atexit(SDL_Quit); // Attempt to create a 640x480 window with 32bit pixels. screen = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 32, SDL_SWSURFACE); // If we fail, return error. if(!screen) { fprintf(stderr, "Unable to set video: %s\n", SDL_GetError()); exit(1); } // Set up the grids for(int x = 0; x < GRID_WIDTH; x++) for(int y = 0; y < GRID_HEIGHT; y++) { g_Grid[x][y].x = g_GridOrig[x][y].x = x * WINDOW_WIDTH / GRID_WIDTH + (WINDOW_WIDTH / GRID_WIDTH / 2); g_Grid[x][y].y = g_GridOrig[x][y].y = y * WINDOW_HEIGHT / GRID_HEIGHT + (WINDOW_HEIGHT / GRID_HEIGHT / 2); g_Grid[x][y].h = g_GridOrig[x][y].h = 0; } // Main loop: loop forever. while(true) { // Tick stuff; tick(); // Render stuff render(); // Poll for events, and handle the ones we care about. SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: break; case SDL_KEYUP: // If escape is pressed, return (and thus, quit) if(event.key.keysym.sym == SDLK_ESCAPE) return 0; else if(event.key.keysym.sym == SDLK_SPACE) DetonateAt(g_MouseEvent.x, g_MouseEvent.y, 1.5f, 150.0f); break; case SDL_MOUSEMOTION: g_MouseEvent = event.motion; DetonateAt(g_MouseEvent.x, g_MouseEvent.y, 0.5f, 15.0f); break; case SDL_QUIT: return 0; } } } return 0; }