Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <SDL2/SDL.h>
- #include <stdlib.h>
- #include <time.h>
- #include <iomanip>
- #include <GL/glew.h>
- #include <cmath>
- #include <algorithm>
- //2-bit cellular automata Kaelygon
- /*
- controls
- New rules..... R
- New add rule.. T
- Draw.......... mouse left/right
- Draw radius... Q:-1 e:+1
- Draw random... W
- Simu Speed.... 1:-1 e:+1
- wild rules.... Y
- print rules... P
- defaults...... M
- exit:......... ESC
- */
- //only tested for square tiles and window
- SDL_Event e;
- bool quit = false;
- bool isMouseHeld;
- bool wildRules=0; //disable ruleSet sorting
- uint8_t simulationSpeed=0;
- const float FRAME_TIME_TARGET = 16.6667;
- uint8_t clickRadius=1;
- uint8_t clickRand=0;
- //ranges 0-5 6-9 10-13 14-17 >=18
- uint8_t ruleSet[4]{
- 5,
- 8,
- 10,
- 23
- };
- //add this to rotMap when rule range is 0-5 = ruleAdd[0], 6-9 = ruleAdd[1] ... >=18 ruleAdd[4]
- int8_t ruleAdd[5]{
- -1,
- 1,
- -1,
- 0,
- -1
- };
- // Set the window size
- int windowWidth = 1024;
- int windowHeight = 1024;
- const int TILE_ROWS = 128; //tile array
- const int TILE_COLS = TILE_ROWS;
- const int TILESIZE = 1;
- const int PIXEL_ROWS = TILESIZE;
- const int PIXEL_COLS = TILESIZE;
- GLubyte tileTexture[PIXEL_ROWS][PIXEL_COLS][3]; //store tile
- uint8_t rotMap[TILE_ROWS][TILE_COLS] = {0}; //tile rotation 0, 1, 2, 3 = 0, 90, 180, 270 degrees
- GLuint textureID; //GPU tileTexture
- uint32_t UKAELSEED = time(NULL)*132387171+3083;
- uint32_t ukaelRand(){
- UKAELSEED = ((UKAELSEED >> 9) | (UKAELSEED << 23))*7+3;
- return UKAELSEED;
- }
- void rotateMatrix(float texCoords[4][2], int steps) {
- // Convert steps to radians
- float theta = steps * (M_PI / 2.0f);
- // Rotation matrix
- float rotationMatrix[2][2] = {
- {cos(theta),-sin(theta)},
- {sin(theta), cos(theta)}
- };
- // Center of rotation (assuming a square matrix)
- float centerX = 0.5f;
- float centerY = 0.5f;
- // Apply rotation to each point
- for (int i = 0; i < 4; ++i) {
- // Translate to the origin
- float x = texCoords[i][0] - centerX;
- float y = texCoords[i][1] - centerY;
- // Apply rotation
- float newX = rotationMatrix[0][0] * x + rotationMatrix[0][1] * y;
- float newY = rotationMatrix[1][0] * x + rotationMatrix[1][1] * y;
- // Translate back to the original position
- texCoords[i][0] = newX + centerX;
- texCoords[i][1] = newY + centerY;
- }
- }
- void initializeTileTexture() {
- uint8_t whiteTile[4][4] =
- {
- 4,4,2,2,
- 4,3,3,2,
- 2,2,3,4,
- 0,2,4,4
- };
- // Initialize the pixel map with RGB values
- for (int i = 0; i < PIXEL_ROWS; ++i) {
- for (int j = 0; j < PIXEL_COLS; ++j) {
- // Set RGB values based on some criteria
- tileTexture[i][j][0] = whiteTile[i][j]*63;
- tileTexture[i][j][1] = whiteTile[i][j]*63;
- tileTexture[i][j][2] = whiteTile[i][j]*63;
- }
- }
- }
- void uploadtileTextureToGPU() {
- // Set up a 2D texture on the GPU
- glGenTextures(1, &textureID);
- glBindTexture(GL_TEXTURE_2D, textureID);
- // Upload the pixel map to the texture
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, PIXEL_COLS, PIXEL_ROWS, 0, GL_RGB, GL_UNSIGNED_BYTE, tileTexture);
- // Set texture parameters (you can customize these based on your needs)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- // Unbind the texture
- glBindTexture(GL_TEXTURE_2D, 0);
- }
- void renderTiles() {
- // Clear the color buffer
- glClear(GL_COLOR_BUFFER_BIT);
- // Enable texturing
- glEnable(GL_TEXTURE_2D);
- // Bind the texture
- glBindTexture(GL_TEXTURE_2D, textureID);
- // Calculate the size of each tile in normalized device coordinates
- float tileWidth = 2.0f / TILE_COLS;
- float tileHeight = 2.0f / TILE_ROWS;
- // Loop through each tile, could be parallelized
- for (int i = 0; i < TILE_ROWS; ++i) {
- for (int j = 0; j < TILE_COLS; ++j) {
- // Calculate the normalized device coordinates for the current tile
- float tileX = -1.0f + j * tileWidth;
- float tileY = -1.0f + i * tileHeight;
- float texCoords[4][2] = {
- {0.0f, 0.0f},
- {1.0f, 0.0f},
- {1.0f, 1.0f},
- {0.0f, 1.0f}
- };
- if(TILESIZE>1){
- rotateMatrix(texCoords,rotMap[i][j]);
- }
- //tint
- glColor4f(
- rotMap[i][j]/4.0f,
- rotMap[i][j]/4.0f,
- rotMap[i][j]/4.0f,
- 1.0f
- );
- // Draw a textured quad for the current tile
- glBegin(GL_QUADS);
- glTexCoord2f(texCoords[0][0], texCoords[0][1]); glVertex2f(tileX, tileY);
- glTexCoord2f(texCoords[1][0], texCoords[1][1]); glVertex2f(tileX + tileWidth, tileY);
- glTexCoord2f(texCoords[2][0], texCoords[2][1]); glVertex2f(tileX + tileWidth, tileY + tileHeight);
- glTexCoord2f(texCoords[3][0], texCoords[3][1]); glVertex2f(tileX, tileY + tileHeight);
- glEnd();
- }
- }
- // Disable texturing
- glDisable(GL_TEXTURE_2D);
- }
- void printRules(){
- uint setSize = 4;
- printf("ruleSet");
- for(int i=0;i<setSize;i++){
- printf(" %d",ruleSet[i]);
- }
- printf("\n");
- }
- void randRuleSet(uint8_t ruleSet[4], uint8_t minValue, uint8_t maxValue) {
- uint setSize = 4;
- for(int i=0;i<setSize;i++){
- ruleSet[i]=ukaelRand()%(maxValue-minValue+1)+minValue;
- }
- if(!wildRules){
- //sort
- bool ordered=0;
- while(!ordered){
- ordered=1;
- for(int i=0;i<setSize-1;i++){
- if(ruleSet[i]>ruleSet[i+1]){
- uint8_t buf=ruleSet[i+1];
- ruleSet[i+1]=ruleSet[i];
- ruleSet[i]=buf;
- ordered=0;
- }
- }
- }
- }
- printRules();
- }
- void printRulesAdd(){
- uint setSize = 5;
- printf("ruleAdd");
- for(int i=0;i<setSize;i++){
- printf(" %d",ruleAdd[i]);
- }
- printf("\n");
- }
- void randRuleAdd(int8_t ruleAdd[5], int8_t minValue, int8_t maxValue) {
- uint setSize = 5;
- int range = maxValue-minValue+1;
- for(int i=0;i<setSize;i++){
- ruleAdd[i]=ukaelRand()%range-(-minValue);
- }
- printRulesAdd();
- }
- void randRotMap(){
- for(int i=0;i<TILE_ROWS;i++){
- for(int j=0;j<TILE_COLS;j++){
- rotMap[i][j]=ukaelRand()%4;
- }
- }
- }
- void checkerRotMap(){
- for(int i=0;i<TILE_ROWS;i++){
- for(int j=0;j<TILE_COLS;j++){
- rotMap[i][j]=(i+j)%2;
- }
- }
- }
- void detectKeys(){
- while (SDL_PollEvent(&e) != 0) {
- if (e.type == SDL_KEYDOWN) {
- if (e.key.keysym.sym == SDLK_ESCAPE) {
- quit = true;
- printf("Exit\n");
- continue;
- }
- if (e.key.keysym.sym == SDLK_r) {
- randRuleSet(ruleSet,0,24);
- randRotMap();
- continue;
- }
- if (e.key.keysym.sym == SDLK_q) {
- clickRadius-=clickRadius!=0;
- printf("clickRadius: %d\n",clickRadius);
- continue;
- }
- if (e.key.keysym.sym == SDLK_e) {
- clickRadius+=clickRadius!=254;
- printf("clickRadius: %d\n",clickRadius);
- continue;
- }
- if (e.key.keysym.sym == SDLK_w) {
- clickRand=!clickRand;
- printf("clickRand: %d\n",clickRand);
- continue;
- }
- if (e.key.keysym.sym == SDLK_3) {
- simulationSpeed+=simulationSpeed<255;
- printf("simulationSpeed: %d\n",simulationSpeed);
- continue;
- }
- if (e.key.keysym.sym == SDLK_1) {
- simulationSpeed-=simulationSpeed>0;
- printf("simulationSpeed: %d\n",simulationSpeed);
- continue;
- }
- if (e.key.keysym.sym == SDLK_y) {
- wildRules=!wildRules;
- printf("wildRules: %d\n",wildRules);
- continue;
- }
- if (e.key.keysym.sym == SDLK_p) {
- printRules();
- printRulesAdd();
- continue;
- }
- if (e.key.keysym.sym == SDLK_t) {
- randRuleAdd(ruleAdd,-1,1);
- continue;
- }
- if (e.key.keysym.sym == SDLK_m) {
- ruleSet[0]= 5;
- ruleSet[1]= 9;
- ruleSet[2]=13;
- ruleSet[3]=17;
- ruleAdd[0]=-1;
- ruleAdd[1]= 1;
- ruleAdd[2]=-1;
- ruleAdd[3]= 0;
- ruleAdd[4]=-1;
- continue;
- }
- continue;
- }
- if (e.type == SDL_MOUSEBUTTONDOWN) {
- isMouseHeld=1;
- }
- if (e.type == SDL_MOUSEBUTTONUP) {
- isMouseHeld=0;
- }
- if(e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEMOTION && isMouseHeld){
- int mouseX, mouseY;
- SDL_GetMouseState(&mouseX, &mouseY);
- mouseY=windowHeight-mouseY;
- // Calculate the grid position based on the mouse coordinates
- uint gridX = (float)mouseX/windowWidth*TILE_ROWS;
- uint gridY = (float)mouseY/windowHeight*TILE_COLS;
- // printf("x%d\n",gridX);
- // printf("y%d\n",gridY);
- // Determine the value based on the mouse button
- int addSign = (e.button.button == SDL_BUTTON_LEFT) ? 1 : 0;
- for (int i = -clickRadius; i <= clickRadius; i++) {
- for (int j = -clickRadius; j <= clickRadius; j++) {
- // Calculate the adjusted coordinates for the circular mask
- int adjustedX = (gridX + i + TILE_ROWS) % TILE_ROWS;
- int adjustedY = (gridY + j + TILE_COLS) % TILE_COLS;
- rotMap[adjustedY][adjustedX] = clickRand ? ukaelRand()%4 : addSign*3;
- }
- }
- }
- }
- }
- int main() {
- srand(time(NULL));
- randRotMap();
- if (SDL_Init(SDL_INIT_VIDEO) < 0) {
- std::cerr << "SDL initialization failed: " << SDL_GetError() << std::endl;
- return -1;
- }
- // Get the number of available displays
- int numDisplays = SDL_GetNumVideoDisplays();
- if (numDisplays <= 0) {
- std::cerr << "No displays found" << std::endl;
- return -1;
- }
- // Choose the display index (monitor) you want to use
- int displayIndex = 2; // Change this to the desired display index
- // Set the window position to the chosen display
- int windowX = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex);
- int windowY = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex);
- SDL_Window* window = SDL_CreateWindow("GPU Rendering", windowX, windowY, windowWidth, windowHeight, SDL_WINDOW_OPENGL);
- if (!window) {
- std::cerr << "Window creation failed: " << SDL_GetError() << std::endl;
- return -1;
- }
- SDL_GLContext glContext = SDL_GL_CreateContext(window);
- if (!glContext) {
- std::cerr << "OpenGL context creation failed: " << SDL_GetError() << std::endl;
- return -1;
- }
- GLenum err = glewInit();
- if (err != GLEW_OK) {
- std::cerr << "GLEW initialization failed: " << glewGetErrorString(err) << std::endl;
- return -1;
- }
- // Set the swap interval (0 for immediate updates, 1 for updates synchronized with the vertical retrace)
- if (SDL_GL_SetSwapInterval(1) < 0) {
- std::cerr << "Failed to set VSync: " << SDL_GetError() << std::endl;
- // Handle the error as needed
- }
- initializeTileTexture();
- uploadtileTextureToGPU();
- // Main loop
- SDL_Event event;
- Uint32 frameStartTime = SDL_GetTicks()+FRAME_TIME_TARGET;
- uint8_t frameCount=1;
- while (!quit) {
- frameCount++;
- uint8_t bufMap[TILE_ROWS][TILE_COLS];
- memcpy(bufMap, rotMap, TILE_ROWS * TILE_COLS * sizeof(uint8_t));
- //simulate rules (could be parallelized)
- for (int ti = 0; ti < TILE_ROWS; ti++) {
- for (int tj = 0; tj < TILE_COLS; tj++) {
- //relative neighbor coordinates
- int xp = (ti + 1 ) % TILE_ROWS;
- int xn = (ti - 1 + TILE_ROWS ) % TILE_ROWS;
- int yp = (tj + 1 ) % TILE_COLS;
- int yn = (tj - 1 + TILE_COLS ) % TILE_COLS;
- //neighbor states
- uint8_t neig[8]={
- bufMap[xn][yp], //NE
- bufMap[xp][tj], //N
- bufMap[xp][yp], //NW
- bufMap[xn][tj], //W
- bufMap[xp][yn], //SW
- bufMap[ti][yp], //S
- bufMap[xn][yn], //SE
- bufMap[ti][yn] //E
- };
- int neigsum=0;
- for(int ni=0; ni<sizeof(neig);ni++){
- neigsum+=(neig[ni]>=2)*neig[ni];
- }
- int8_t adu=0;
- if(neigsum>ruleSet[3]){
- adu=ruleAdd[4];
- }else
- if(neigsum>ruleSet[2] && neigsum<=ruleSet[3] ){
- adu=ruleAdd[3];
- }else
- if(neigsum>ruleSet[1] && neigsum<=ruleSet[2] ){
- adu=ruleAdd[2];
- }else
- if(neigsum>ruleSet[0] && neigsum<=ruleSet[1] ){
- adu=ruleAdd[1];
- }else
- if(neigsum<=ruleSet[0]){
- adu=ruleAdd[0];
- }
- rotMap[ti][tj]+=adu;
- if(adu<0){
- rotMap[ti][tj] = rotMap[ti][tj]>3 ? 0 : rotMap[ti][tj]; //underflow
- }else{
- rotMap[ti][tj] = rotMap[ti][tj]>3 ? 3 : rotMap[ti][tj]; //overflow
- }
- }
- }
- // Calculate the time to render a frame
- uint32_t currentFrameTime = SDL_GetTicks() - frameStartTime;
- uint32_t timeDelta=currentFrameTime-frameStartTime;
- // Wait till FRAME_TIME_TARGET is reached
- if (timeDelta < FRAME_TIME_TARGET ) {
- SDL_Delay(FRAME_TIME_TARGET - timeDelta);
- currentFrameTime = SDL_GetTicks() - frameStartTime;
- }
- //skip even frames? reduces flicker
- if( !(frameCount%(simulationSpeed+1)) ){
- renderTiles();
- SDL_GL_SwapWindow(window);
- frameStartTime = SDL_GetTicks();
- }
- detectKeys();
- }
- // Cleanup
- glDeleteTextures(1, &textureID);
- SDL_GL_DeleteContext(glContext);
- SDL_DestroyWindow(window);
- SDL_Quit();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement