diff --git a/.gitignore b/.gitignore index 259148f..ab779c3 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ *.exe *.out *.app + +include/SDL2/ +.vscode diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0943947 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "include/ConfigurationParser"] + path = include/ConfigurationParser + url = https://github.com/Syntriax/ConfigurationParser diff --git a/README.md b/README.md index 219ecb2..764cb74 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # SDL2_GameOfLife +Simple Conway's Game of Life written with SDL2 in C++ diff --git a/include/ConfigurationParser b/include/ConfigurationParser new file mode 160000 index 0000000..a92b2fe --- /dev/null +++ b/include/ConfigurationParser @@ -0,0 +1 @@ +Subproject commit a92b2fe91a0989619c5284c7e9c5962a8047ec16 diff --git a/makefile b/makefile new file mode 100644 index 0000000..860f5e5 --- /dev/null +++ b/makefile @@ -0,0 +1,8 @@ +includeF = -Iinclude +libraryF = -Llib -lSDL2 + +bin/main.exe: src/main.cpp obj/GameOfLife.o + g++ -std=c++17 -o bin/main.exe src/main.cpp obj/GameOfLife.o $(includeF) $(libraryF) + +obj/GameOfLife.o: src/GameOfLife.cpp + g++ -std=c++17 -c -o obj/GameOfLife.o src/GameOfLife.cpp $(includeF) $(libraryF) diff --git a/src/GameOfLife.cpp b/src/GameOfLife.cpp new file mode 100644 index 0000000..505d4da --- /dev/null +++ b/src/GameOfLife.cpp @@ -0,0 +1,79 @@ +#include "GameOfLife.h" + +int *GameOfLife::GetCell(int x, int y, int *buffer) { return buffer + y * width + x; } + +int GameOfLife::GetNeighborCount(int x, int y, int *buffer) +{ + int i, j; + int result = 0; + + for (i = -1; i < 2; i++) + for (j = -1; j < 2; j++) + result += *GetCell(x + i, y + j, buffer) & 1; + + return result - (*GetCell(x, y, buffer) & 1); +} + +int GameOfLife::CalculateState(int state, int neighborCount) +{ + if (state == 0) + return neighborCount == 3; + + return neighborCount == 2 || neighborCount == 3; +} + +void GameOfLife::Iterate() +{ + int x, y; + int count = 0; + int *backCell; + + for (y = 1; y < height - 1; y++) + for (x = 1; x < width - 1; x++) + { + count = GetNeighborCount(x, y, front); + backCell = GetCell(x, y, back.get()); + if (CalculateState(*GetCell(x, y, front), count)) + *backCell = livePixelColor; + else + *backCell = 0; + } + + std::memcpy(front, back.get(), width * height * sizeof(int)); +} + +void GameOfLife::SetDisplay(int *pixelPointer, SDL_PixelFormat *pixelFormat) +{ + front = pixelPointer; + livePixelColor = SDL_MapRGBA(pixelFormat, 255, 255, 255, 255); +} + +bool GameOfLife::SetDimensions(int width, int height) +{ + this->width = width; + this->height = height; + + back = std::make_unique(width * height); + return back.get() != nullptr; +} + +bool GameOfLife::Randomize(int seed) +{ + if (front == nullptr) + return false; + + int count = width * height; + std::srand(seed); + + for (int i = 0; i < count; i++) + if (rand() % 2 == 0) + *(front + i) = livePixelColor; + else + *(front + i) = 0; + + return true; +} + +GameOfLife::GameOfLife() { SetDimensions(100, 100); } +GameOfLife::GameOfLife(int width, int height) { SetDimensions(width, height); } +GameOfLife::~GameOfLife() {} diff --git a/src/GameOfLife.h b/src/GameOfLife.h new file mode 100644 index 0000000..d533a70 --- /dev/null +++ b/src/GameOfLife.h @@ -0,0 +1,26 @@ +#pragma once +#include "headers.h" + +class GameOfLife +{ +private: + int width; + int height; + int livePixelColor; + int *front; + std::unique_ptr back; + + int *GetCell(int, int, int *); + int GetNeighborCount(int, int, int *); + int CalculateState(int, int); + +public: + const int *GetGridPointer(); + void Iterate(); + void SetDisplay(int *, SDL_PixelFormat *); + bool SetDimensions(int, int); + bool Randomize(int); + GameOfLife(); + GameOfLife(int, int); + ~GameOfLife(); +}; diff --git a/src/headers.h b/src/headers.h new file mode 100644 index 0000000..f38a480 --- /dev/null +++ b/src/headers.h @@ -0,0 +1,20 @@ +#pragma once +// #ifndef GameOfLifeHeaders +// #define GameOfLifeHeaders + +#define SDL_MAIN_HANDLED + +#include + +#include +#include +#include +#include +#include +#include + +#include "GameOfLife.h" + +#include "ConfigurationParser/ConfigurationParser.h" + +// #endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..20e40f0 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,85 @@ +#include "headers.h" + +#define CONFIG_PATH "config.cfg" + +#define WIDTH_CONF_KEY "WIDTH" +#define HEIGHT_CONF_KEY "HEIGHT" +#define FPS_CONF_KEY "FPS" +#define SEED_CONF_KEY "SEED" + +void ReadConfig(Syn::ConfigurationParser &parser) +{ + if (parser.ParseFile(CONFIG_PATH)) + return; + + parser[WIDTH_CONF_KEY] = "400"; + parser[HEIGHT_CONF_KEY] = "400"; + parser[FPS_CONF_KEY] = "60"; + parser[SEED_CONF_KEY] = "0"; + + parser.WriteFile(CONFIG_PATH); +} + +void Update(SDL_Surface *surface, GameOfLife *life) +{ + SDL_LockSurface(surface); + life->Iterate(); + SDL_UnlockSurface(surface); +} + +int main(int argc, char *argv[]) +{ + SDL_Event event; + SDL_Renderer *renderer; + SDL_Window *window; + SDL_Surface *surface; + + GameOfLife life; + Syn::ConfigurationParser config; + ReadConfig(config); + + int width = std::stoi(config[WIDTH_CONF_KEY]); + int height = std::stoi(config[HEIGHT_CONF_KEY]); + int fps = std::stoi(config[FPS_CONF_KEY]); + int seed = std::stoi(config[SEED_CONF_KEY]); + + bool isRunning = true; + int tickForNext = 1000 / fps; + int nextTick = 0; + + SDL_Init(SDL_INIT_VIDEO); + window = SDL_CreateWindow( + "Game of Life", + SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + width, height, + SDL_WindowFlags::SDL_WINDOW_OPENGL); + renderer = SDL_CreateRenderer(window, -1, SDL_RendererFlags::SDL_RENDERER_ACCELERATED); + surface = SDL_GetWindowSurface(window); + + life.SetDimensions(width, height); + life.SetDisplay((int *)surface->pixels, surface->format); + life.Randomize(seed); + + while (isRunning) + { + while (SDL_PollEvent(&event) != 0) + { + switch (event.type) + { + case SDL_QUIT: + isRunning = false; + break; + } + } + if (SDL_GetTicks() >= nextTick) + { + Update(surface, &life); + SDL_UpdateWindowSurface(window); + nextTick += tickForNext; + } + } + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + return EXIT_SUCCESS; +}