Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //gcc sand.c -O3 -o sand `sdl2-config --libs --cflags` -lm
- //Sand simulator game
- //Controls:
- //1: sand, 2: stone, 3: sand generator, 4: eraser, +/-: change brush size, space: pause, L: load, S: save
- #include <stdio.h>
- #include <SDL2/SDL.h>
- #include <stdint.h>
- #include <math.h>
- #define CELL_EMPTY 0
- #define CELL_SAND 1
- #define CELL_ROCK 3
- #define CELL_SOURCE 5
- uint32_t cellColors[] = {0, 0x00EEAA00, 0, 0x00444444, 0, 0x00BB0000};
- int worldW = 320;
- int worldH = 240;
- int scale = 2;
- int screenW, screenH;
- uint8_t mouseDown = 0;
- uint8_t pause = 0;
- uint32_t drawColor;
- uint32_t drawRadius = 1;
- float fps = 50.0;
- void clearScreen(uint32_t* pixels) {
- int i;
- for (i=0; i<screenW*screenH; i++) {
- pixels[i] = 0x00000000;
- }
- }
- void initState(uint32_t* state) {
- int x, y;
- for (y=0; y<worldH; y++) {
- for (x=0; x<worldW; x++) {
- if (x > worldW/4 && x < 3*worldW/4 && (rand() % 10) < 2)
- state[y*worldW+x] = 1;
- else
- state[y*worldW+x] = 0;
- }
- }
- }
- uint8_t inline cellEmpty(uint32_t state) {
- return !(state & 1);
- }
- uint32_t inline cellAt(uint32_t* world, uint32_t x, uint32_t y) {
- return world[y*worldW+x];
- }
- uint32_t inline cellSet(uint32_t* world, uint32_t x, uint32_t y, uint32_t val) {
- world[y*worldW+x] = val;
- }
- void computeCell(uint32_t* state, int x, int y, int* flag) {
- int lx, rx;
- if (cellAt(state, x, y) == CELL_SOURCE) {
- if ((rand() & 0xFF) < 20 && cellEmpty(cellAt(state, x, y+1)))
- cellSet(state, x, y+1, CELL_SAND);
- }
- if (cellAt(state, x, y) == CELL_SAND) {
- cellSet(state, x, y, CELL_EMPTY);
- if (cellEmpty(cellAt(state, x, y+1))) {
- cellSet(state, x, y+1, CELL_SAND);
- } else {
- //Swap left and right direction on every decision to mitigate asymmetry
- //if (1) { lx = x-1; rx = x+1; *flag = 0; }
- //else { lx = x+1; rx = x-1; *flag = 1; }
- lx = x-1; rx = x+1;
- if (cellEmpty(cellAt(state, lx, y+1))) {
- cellSet(state, lx, y+1, CELL_SAND);
- } else if (cellEmpty(cellAt(state, rx, y+1))) {
- cellSet(state, rx, y+1, CELL_SAND);
- } else {
- cellSet(state, x, y, CELL_SAND);
- }
- }
- }
- }
- void updateState(uint32_t* state) {
- int x, y;
- int flag = 0;
- y = worldH-1;
- for (x=1; x<(worldW-1); x++) {
- if (cellAt(state, x, y) == CELL_SAND) {
- cellSet(state, x, y, CELL_EMPTY);
- }
- }
- for (y=(worldH-2); y>=0; y--) {
- for (x=1; x<(worldW-1); x++) {
- computeCell(state, 1 + (rand() % (worldW-2)), y, &flag);
- computeCell(state, 1 + (rand() % (worldW-2)), y, &flag);
- }
- }
- }
- void draw(uint32_t* state, uint32_t* pixels, float t) {
- int x, y, offset;
- uint32_t color;
- uint32_t cell;
- for (y=0; y<worldH; y++) {
- offset = y*worldW*scale*scale;
- for (x=0; x<worldW; x++) {
- cell = cellAt(state, x ,y);
- if (!cellEmpty(cell)) {
- color = cellColors[cell];
- pixels[offset+x*scale] = color;
- pixels[offset+x*scale+1] = color;
- pixels[offset+x*scale+worldW*scale] = color;
- pixels[offset+x*scale+worldW*scale+1] = color;
- }
- }
- }
- }
- inline uint32_t limitU32(uint32_t umin, uint32_t umax, uint32_t val) {
- if (val < umin) return umin;
- if (val > umax) return umax;
- else return val;
- }
- void drawCell(uint32_t* world, int x, int y) {
- int i,j;
- if (drawRadius == 1) {
- cellSet(world, x, y, drawColor);
- }
- if (drawRadius > 1) {
- for (i=y; i<y+drawRadius; i++)
- for (j=x; j<x+drawRadius; j++)
- cellSet(world, limitU32(0, worldW-1, j), limitU32(0, worldH-1, i), drawColor);
- }
- }
- void handleMouseDown(SDL_MouseButtonEvent* event, uint32_t* world) {
- mouseDown = 1;
- int x = event->x;
- int y = event->y;
- drawCell(world, x/scale, y/scale);
- }
- void handleMouseUp(SDL_MouseButtonEvent* event) {
- mouseDown = 0;
- }
- void handleMouseMove(SDL_MouseMotionEvent* event, uint32_t* world) {
- int x, y;
- if (mouseDown) {
- x = event->x;
- y = event->y;
- drawCell(world, x/scale, y/scale);
- }
- }
- void handleKeyDown(SDL_KeyboardEvent* event, uint32_t* state) {
- SDL_Keysym key = event->keysym;
- if (key.scancode == SDL_SCANCODE_1) drawColor = CELL_SAND;
- if (key.scancode == SDL_SCANCODE_2) drawColor = CELL_ROCK;
- if (key.scancode == SDL_SCANCODE_3) drawColor = CELL_SOURCE;
- if (key.scancode == SDL_SCANCODE_4) drawColor = CELL_EMPTY;
- if (key.scancode == SDL_SCANCODE_SPACE) pause = !pause;
- if (key.scancode == SDL_SCANCODE_EQUALS) drawRadius++;
- if (key.scancode == SDL_SCANCODE_MINUS) if (drawRadius > 1) drawRadius--;
- if (key.scancode == SDL_SCANCODE_S) {
- FILE* f = fopen("save.bin", "w");
- fwrite(state, sizeof(uint32_t), worldW*worldH, f);
- fclose(f);
- }
- if (key.scancode == SDL_SCANCODE_L) {
- FILE* f = fopen("save.bin", "r");
- int n = fread(state, sizeof(uint32_t), worldW*worldH, f);
- fclose(f);
- }
- }
- int main(int argc, char *argv[]) {
- srand(81237);
- screenW = worldW*scale;
- screenH = worldH*scale;
- SDL_Window *win = NULL;
- SDL_Renderer *renderer = NULL;
- SDL_Texture *screen = NULL;
- int posX = 100, posY = 100, width = screenW, height = screenH;
- SDL_Init(SDL_INIT_VIDEO);
- win = SDL_CreateWindow("Hello World", posX, posY, width, height, 0);
- renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);
- screen = SDL_CreateTexture(renderer,
- SDL_PIXELFORMAT_ARGB8888,
- SDL_TEXTUREACCESS_STREAMING,
- screenW, screenH);
- uint32_t* state = (uint32_t*) malloc(sizeof(uint32_t)*worldW*worldH);
- initState(state);
- uint32_t* pixels = (uint32_t*) malloc(sizeof(uint32_t)*screenW*screenH);
- float t = 0;
- uint32_t beforeT, afterT;
- while (1) {
- beforeT = SDL_GetTicks();
- t++;
- SDL_Event e;
- if (SDL_PollEvent(&e)) {
- if (e.type == SDL_QUIT) {
- break;
- }
- if (e.type == SDL_MOUSEBUTTONDOWN) {
- handleMouseDown(&e.button, state);
- }
- if (e.type == SDL_MOUSEBUTTONUP) {
- handleMouseUp(&e.button);
- }
- if (e.type == SDL_MOUSEMOTION) {
- handleMouseMove(&e.motion, state);
- }
- if (e.type == SDL_KEYDOWN) {
- handleKeyDown(&e.key, state);
- }
- }
- if (!pause) {
- clearScreen(pixels);
- updateState(state);
- draw(state, pixels, t);
- SDL_UpdateTexture(screen, NULL, pixels, screenW * sizeof (uint32_t));
- SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, screen, NULL, NULL);
- SDL_RenderPresent(renderer);
- afterT = SDL_GetTicks();
- if (afterT - beforeT < 1000.0/fps) {
- //SDL_Delay(1000.0/fps - (afterT - beforeT));
- //printf("delay: %f\n", 1000.0/fps - (afterT - beforeT));
- }
- } else {
- SDL_Delay(20);
- }
- }
- SDL_DestroyTexture(screen);
- SDL_DestroyRenderer(renderer);
- SDL_DestroyWindow(win);
- SDL_Quit();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment