Advertisement
Kaelygon

2bit glew cellular automata

Nov 30th, 2023 (edited)
780
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.94 KB | None | 0 0
  1. #include <iostream>
  2. #include <SDL2/SDL.h>
  3. #include <stdlib.h>
  4. #include <time.h>
  5. #include <iomanip>
  6. #include <GL/glew.h>
  7. #include <cmath>
  8. #include <algorithm>
  9.  
  10. //2-bit cellular automata Kaelygon
  11. /*
  12. controls
  13. New rules..... R
  14. New add rule.. T
  15. Draw.......... mouse left/right
  16. Draw radius... Q:-1 e:+1
  17. Draw random... W
  18. Simu Speed.... 1:-1 e:+1
  19. wild rules.... Y
  20. print rules... P
  21. defaults...... M
  22. exit:......... ESC
  23. */
  24. //only tested for square tiles and window
  25.  
  26. SDL_Event e;
  27. bool quit = false;
  28. bool isMouseHeld;
  29. bool wildRules=0; //disable ruleSet sorting
  30. uint8_t simulationSpeed=0;
  31.  
  32.  
  33. const float FRAME_TIME_TARGET = 16.6667;
  34.  
  35. uint8_t clickRadius=1;
  36. uint8_t clickRand=0;
  37.  
  38. //ranges 0-5 6-9 10-13 14-17 >=18
  39. uint8_t ruleSet[4]{
  40.     5,
  41.     8,
  42.     10,
  43.     23
  44. };
  45.  
  46. //add this to rotMap when rule range is 0-5 = ruleAdd[0], 6-9 = ruleAdd[1] ... >=18 ruleAdd[4]
  47. int8_t ruleAdd[5]{
  48.     -1,
  49.      1,
  50.     -1,
  51.      0,
  52.     -1
  53. };
  54.  
  55. // Set the window size
  56. int windowWidth = 1024;
  57. int windowHeight = 1024;
  58.  
  59. const int TILE_ROWS = 128; //tile array
  60. const int TILE_COLS = TILE_ROWS;  
  61.  
  62. const int TILESIZE = 1;
  63. const int PIXEL_ROWS = TILESIZE;
  64. const int PIXEL_COLS = TILESIZE;
  65.  
  66. GLubyte tileTexture[PIXEL_ROWS][PIXEL_COLS][3];  //store tile
  67. uint8_t rotMap[TILE_ROWS][TILE_COLS] = {0}; //tile rotation 0, 1, 2, 3 = 0, 90, 180, 270 degrees
  68.  
  69. GLuint textureID; //GPU tileTexture
  70.  
  71. uint32_t UKAELSEED = time(NULL)*132387171+3083;
  72. uint32_t ukaelRand(){
  73.     UKAELSEED = ((UKAELSEED >> 9) | (UKAELSEED << 23))*7+3;
  74.     return UKAELSEED;
  75. }
  76.  
  77. void rotateMatrix(float texCoords[4][2], int steps) {
  78.     // Convert steps to radians
  79.     float theta = steps * (M_PI / 2.0f);
  80.  
  81.     // Rotation matrix
  82.     float rotationMatrix[2][2] = {
  83.         {cos(theta),-sin(theta)},
  84.         {sin(theta), cos(theta)}
  85.     };
  86.  
  87.     // Center of rotation (assuming a square matrix)
  88.     float centerX = 0.5f;
  89.     float centerY = 0.5f;
  90.  
  91.     // Apply rotation to each point
  92.     for (int i = 0; i < 4; ++i) {
  93.         // Translate to the origin
  94.         float x = texCoords[i][0] - centerX;
  95.         float y = texCoords[i][1] - centerY;
  96.  
  97.         // Apply rotation
  98.         float newX = rotationMatrix[0][0] * x + rotationMatrix[0][1] * y;
  99.         float newY = rotationMatrix[1][0] * x + rotationMatrix[1][1] * y;
  100.  
  101.         // Translate back to the original position
  102.         texCoords[i][0] = newX + centerX;
  103.         texCoords[i][1] = newY + centerY;
  104.     }
  105. }
  106.  
  107. void initializeTileTexture() {
  108.  
  109.     uint8_t whiteTile[4][4] =
  110.     {
  111.         4,4,2,2,
  112.         4,3,3,2,
  113.         2,2,3,4,
  114.         0,2,4,4
  115.     };
  116.  
  117.     // Initialize the pixel map with RGB values
  118.     for (int i = 0; i < PIXEL_ROWS; ++i) {
  119.         for (int j = 0; j < PIXEL_COLS; ++j) {
  120.             // Set RGB values based on some criteria
  121.             tileTexture[i][j][0] = whiteTile[i][j]*63;
  122.             tileTexture[i][j][1] = whiteTile[i][j]*63;
  123.             tileTexture[i][j][2] = whiteTile[i][j]*63;
  124.         }
  125.     }
  126. }
  127.  
  128. void uploadtileTextureToGPU() {
  129.     // Set up a 2D texture on the GPU
  130.     glGenTextures(1, &textureID);
  131.     glBindTexture(GL_TEXTURE_2D, textureID);
  132.  
  133.     // Upload the pixel map to the texture
  134.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, PIXEL_COLS, PIXEL_ROWS, 0, GL_RGB, GL_UNSIGNED_BYTE, tileTexture);
  135.  
  136.     // Set texture parameters (you can customize these based on your needs)
  137.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  138.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  139.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  140.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  141.  
  142.     // Unbind the texture
  143.     glBindTexture(GL_TEXTURE_2D, 0);
  144. }
  145.  
  146. void renderTiles() {
  147.     // Clear the color buffer
  148.     glClear(GL_COLOR_BUFFER_BIT);
  149.  
  150.     // Enable texturing
  151.     glEnable(GL_TEXTURE_2D);
  152.  
  153.     // Bind the texture
  154.     glBindTexture(GL_TEXTURE_2D, textureID);
  155.  
  156.     // Calculate the size of each tile in normalized device coordinates
  157.     float tileWidth = 2.0f / TILE_COLS;
  158.     float tileHeight = 2.0f / TILE_ROWS;
  159.  
  160.     // Loop through each tile, could be parallelized
  161.     for (int i = 0; i < TILE_ROWS; ++i) {
  162.         for (int j = 0; j < TILE_COLS; ++j) {
  163.             // Calculate the normalized device coordinates for the current tile
  164.             float tileX = -1.0f + j * tileWidth;
  165.             float tileY = -1.0f + i * tileHeight;
  166.  
  167.             float texCoords[4][2] = {
  168.                 {0.0f, 0.0f},
  169.                 {1.0f, 0.0f},
  170.                 {1.0f, 1.0f},
  171.                 {0.0f, 1.0f}
  172.             };
  173.  
  174.             if(TILESIZE>1){
  175.                 rotateMatrix(texCoords,rotMap[i][j]);
  176.             }
  177.  
  178.             //tint
  179.             glColor4f(
  180.                 rotMap[i][j]/4.0f,
  181.                 rotMap[i][j]/4.0f,
  182.                 rotMap[i][j]/4.0f,
  183.                 1.0f
  184.             );
  185.  
  186.             // Draw a textured quad for the current tile
  187.             glBegin(GL_QUADS);
  188.             glTexCoord2f(texCoords[0][0], texCoords[0][1]); glVertex2f(tileX, tileY);
  189.             glTexCoord2f(texCoords[1][0], texCoords[1][1]); glVertex2f(tileX + tileWidth, tileY);
  190.             glTexCoord2f(texCoords[2][0], texCoords[2][1]); glVertex2f(tileX + tileWidth, tileY + tileHeight);
  191.             glTexCoord2f(texCoords[3][0], texCoords[3][1]); glVertex2f(tileX, tileY + tileHeight);
  192.             glEnd();
  193.         }
  194.     }
  195.  
  196.     // Disable texturing
  197.     glDisable(GL_TEXTURE_2D);
  198. }
  199.  
  200. void printRules(){
  201.     uint setSize = 4;
  202.     printf("ruleSet");
  203.     for(int i=0;i<setSize;i++){
  204.         printf(" %d",ruleSet[i]);
  205.     }
  206.     printf("\n");
  207. }
  208.  
  209. void randRuleSet(uint8_t ruleSet[4], uint8_t minValue, uint8_t maxValue) {
  210.     uint setSize = 4;
  211.  
  212.     for(int i=0;i<setSize;i++){
  213.         ruleSet[i]=ukaelRand()%(maxValue-minValue+1)+minValue;
  214.     }
  215.  
  216.     if(!wildRules){
  217.         //sort
  218.         bool ordered=0;
  219.         while(!ordered){
  220.             ordered=1;
  221.             for(int i=0;i<setSize-1;i++){
  222.                 if(ruleSet[i]>ruleSet[i+1]){
  223.                     uint8_t buf=ruleSet[i+1];
  224.                     ruleSet[i+1]=ruleSet[i];
  225.                     ruleSet[i]=buf;
  226.                     ordered=0;
  227.                 }
  228.             }
  229.         }
  230.     }
  231.    
  232.     printRules();
  233. }
  234.  
  235. void printRulesAdd(){
  236.     uint setSize = 5;
  237.     printf("ruleAdd");
  238.     for(int i=0;i<setSize;i++){
  239.         printf(" %d",ruleAdd[i]);
  240.     }
  241.     printf("\n");
  242. }
  243.  
  244. void randRuleAdd(int8_t ruleAdd[5], int8_t minValue, int8_t maxValue) {
  245.     uint setSize = 5;
  246.  
  247.     int range = maxValue-minValue+1;
  248.  
  249.     for(int i=0;i<setSize;i++){
  250.         ruleAdd[i]=ukaelRand()%range-(-minValue);
  251.     }
  252.  
  253.     printRulesAdd();
  254. }
  255.  
  256. void randRotMap(){
  257.     for(int i=0;i<TILE_ROWS;i++){
  258.         for(int j=0;j<TILE_COLS;j++){
  259.             rotMap[i][j]=ukaelRand()%4;
  260.         }
  261.     }
  262. }
  263.  
  264. void checkerRotMap(){
  265.     for(int i=0;i<TILE_ROWS;i++){
  266.         for(int j=0;j<TILE_COLS;j++){
  267.             rotMap[i][j]=(i+j)%2;
  268.         }
  269.     }
  270. }
  271.  
  272. void detectKeys(){
  273.     while (SDL_PollEvent(&e) != 0) {
  274.  
  275.         if (e.type == SDL_KEYDOWN) {
  276.             if (e.key.keysym.sym == SDLK_ESCAPE) {
  277.                 quit = true;
  278.                 printf("Exit\n");
  279.                 continue;
  280.             }
  281.             if (e.key.keysym.sym == SDLK_r) {
  282.                 randRuleSet(ruleSet,0,24);
  283.                 randRotMap();
  284.                 continue;
  285.             }
  286.  
  287.             if (e.key.keysym.sym == SDLK_q) {
  288.                 clickRadius-=clickRadius!=0;
  289.                 printf("clickRadius: %d\n",clickRadius);
  290.                 continue;
  291.             }
  292.             if (e.key.keysym.sym == SDLK_e) {
  293.                 clickRadius+=clickRadius!=254;
  294.                 printf("clickRadius: %d\n",clickRadius);
  295.                 continue;
  296.             }
  297.             if (e.key.keysym.sym == SDLK_w) {
  298.                 clickRand=!clickRand;
  299.                 printf("clickRand: %d\n",clickRand);
  300.                 continue;
  301.             }
  302.             if (e.key.keysym.sym == SDLK_3) {
  303.                 simulationSpeed+=simulationSpeed<255;
  304.                 printf("simulationSpeed: %d\n",simulationSpeed);
  305.                 continue;
  306.             }
  307.             if (e.key.keysym.sym == SDLK_1) {
  308.                 simulationSpeed-=simulationSpeed>0;
  309.                 printf("simulationSpeed: %d\n",simulationSpeed);
  310.                 continue;
  311.             }
  312.             if (e.key.keysym.sym == SDLK_y) {
  313.                 wildRules=!wildRules;
  314.                 printf("wildRules: %d\n",wildRules);
  315.                 continue;
  316.             }
  317.             if (e.key.keysym.sym == SDLK_p) {
  318.                 printRules();
  319.                 printRulesAdd();
  320.                 continue;
  321.             }
  322.             if (e.key.keysym.sym == SDLK_t) {
  323.                 randRuleAdd(ruleAdd,-1,1);
  324.                 continue;
  325.             }
  326.             if (e.key.keysym.sym == SDLK_m) {
  327.                 ruleSet[0]= 5;
  328.                 ruleSet[1]= 9;
  329.                 ruleSet[2]=13;
  330.                 ruleSet[3]=17;
  331.                
  332.                 ruleAdd[0]=-1;
  333.                 ruleAdd[1]= 1;
  334.                 ruleAdd[2]=-1;
  335.                 ruleAdd[3]= 0;
  336.                 ruleAdd[4]=-1;
  337.  
  338.  
  339.                 continue;
  340.             }
  341.  
  342.             continue;
  343.         }
  344.  
  345.         if (e.type == SDL_MOUSEBUTTONDOWN) {
  346.             isMouseHeld=1;
  347.            
  348.         }
  349.         if (e.type == SDL_MOUSEBUTTONUP) {
  350.             isMouseHeld=0;
  351.         }
  352.  
  353.         if(e.type == SDL_MOUSEBUTTONDOWN || e.type == SDL_MOUSEMOTION && isMouseHeld){
  354.             int mouseX, mouseY;
  355.             SDL_GetMouseState(&mouseX, &mouseY);
  356.             mouseY=windowHeight-mouseY;
  357.  
  358.             // Calculate the grid position based on the mouse coordinates
  359.             uint gridX = (float)mouseX/windowWidth*TILE_ROWS;
  360.             uint gridY = (float)mouseY/windowHeight*TILE_COLS;
  361.  
  362.         //  printf("x%d\n",gridX);
  363.         //  printf("y%d\n",gridY);
  364.  
  365.             // Determine the value based on the mouse button
  366.             int addSign = (e.button.button == SDL_BUTTON_LEFT) ? 1 : 0;
  367.  
  368.             for (int i = -clickRadius; i <= clickRadius; i++) {
  369.                 for (int j = -clickRadius; j <= clickRadius; j++) {
  370.                     // Calculate the adjusted coordinates for the circular mask
  371.                     int adjustedX = (gridX + i + TILE_ROWS) % TILE_ROWS;
  372.                     int adjustedY = (gridY + j + TILE_COLS) % TILE_COLS;
  373.  
  374.                     rotMap[adjustedY][adjustedX] = clickRand ? ukaelRand()%4 : addSign*3;
  375.  
  376.                 }
  377.             }
  378.  
  379.         }
  380.        
  381.  
  382.     }
  383. }
  384.  
  385.  
  386. int main() {
  387.     srand(time(NULL));
  388.  
  389.     randRotMap();
  390.  
  391.     if (SDL_Init(SDL_INIT_VIDEO) < 0) {
  392.         std::cerr << "SDL initialization failed: " << SDL_GetError() << std::endl;
  393.         return -1;
  394.     }    
  395.  
  396.     // Get the number of available displays
  397.     int numDisplays = SDL_GetNumVideoDisplays();
  398.     if (numDisplays <= 0) {
  399.         std::cerr << "No displays found" << std::endl;
  400.         return -1;
  401.     }
  402.  
  403.     // Choose the display index (monitor) you want to use
  404.     int displayIndex = 2;  // Change this to the desired display index
  405.  
  406.     // Set the window position to the chosen display
  407.     int windowX = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex);
  408.     int windowY = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex);
  409.  
  410.     SDL_Window* window = SDL_CreateWindow("GPU Rendering", windowX, windowY, windowWidth, windowHeight, SDL_WINDOW_OPENGL);
  411.     if (!window) {
  412.         std::cerr << "Window creation failed: " << SDL_GetError() << std::endl;
  413.         return -1;
  414.     }
  415.  
  416.     SDL_GLContext glContext = SDL_GL_CreateContext(window);
  417.     if (!glContext) {
  418.         std::cerr << "OpenGL context creation failed: " << SDL_GetError() << std::endl;
  419.         return -1;
  420.     }
  421.  
  422.     GLenum err = glewInit();
  423.     if (err != GLEW_OK) {
  424.         std::cerr << "GLEW initialization failed: " << glewGetErrorString(err) << std::endl;
  425.         return -1;
  426.     }
  427.  
  428.  
  429.     // Set the swap interval (0 for immediate updates, 1 for updates synchronized with the vertical retrace)
  430.     if (SDL_GL_SetSwapInterval(1) < 0) {
  431.         std::cerr << "Failed to set VSync: " << SDL_GetError() << std::endl;
  432.         // Handle the error as needed
  433.     }
  434.  
  435.  
  436.     initializeTileTexture();
  437.     uploadtileTextureToGPU();
  438.  
  439.     // Main loop
  440.     SDL_Event event;
  441.  
  442.     Uint32 frameStartTime = SDL_GetTicks()+FRAME_TIME_TARGET;
  443.  
  444.     uint8_t frameCount=1;
  445.  
  446.     while (!quit) {
  447.         frameCount++;
  448.         uint8_t bufMap[TILE_ROWS][TILE_COLS];
  449.         memcpy(bufMap, rotMap, TILE_ROWS * TILE_COLS * sizeof(uint8_t));
  450.            
  451.         //simulate rules (could be parallelized)
  452.             for (int ti = 0; ti < TILE_ROWS; ti++) {
  453.                 for (int tj = 0; tj < TILE_COLS; tj++) {
  454.  
  455.                     //relative neighbor coordinates
  456.                     int xp = (ti + 1             ) % TILE_ROWS;
  457.                     int xn = (ti - 1 + TILE_ROWS ) % TILE_ROWS;
  458.                     int yp = (tj + 1             ) % TILE_COLS;
  459.                     int yn = (tj - 1 + TILE_COLS ) % TILE_COLS;
  460.  
  461.                     //neighbor states
  462.                     uint8_t neig[8]={
  463.                         bufMap[xn][yp], //NE
  464.                         bufMap[xp][tj], //N
  465.                         bufMap[xp][yp], //NW
  466.                         bufMap[xn][tj], //W
  467.                         bufMap[xp][yn], //SW
  468.                         bufMap[ti][yp], //S
  469.                         bufMap[xn][yn], //SE
  470.                         bufMap[ti][yn]  //E
  471.                     }; 
  472.  
  473.                     int neigsum=0;
  474.                     for(int ni=0; ni<sizeof(neig);ni++){
  475.                             neigsum+=(neig[ni]>=2)*neig[ni];
  476.                     }
  477.  
  478.                     int8_t adu=0;
  479.  
  480.                     if(neigsum>ruleSet[3]){
  481.                         adu=ruleAdd[4];
  482.                     }else
  483.                     if(neigsum>ruleSet[2] && neigsum<=ruleSet[3] ){
  484.                         adu=ruleAdd[3];
  485.                     }else
  486.                     if(neigsum>ruleSet[1] && neigsum<=ruleSet[2] ){
  487.                         adu=ruleAdd[2];
  488.                     }else
  489.                     if(neigsum>ruleSet[0] && neigsum<=ruleSet[1] ){
  490.                         adu=ruleAdd[1];
  491.                     }else
  492.                     if(neigsum<=ruleSet[0]){
  493.                         adu=ruleAdd[0];
  494.                     }
  495.  
  496.                     rotMap[ti][tj]+=adu;
  497.                     if(adu<0){
  498.                         rotMap[ti][tj] = rotMap[ti][tj]>3 ? 0 : rotMap[ti][tj]; //underflow
  499.                     }else{
  500.                         rotMap[ti][tj] = rotMap[ti][tj]>3 ? 3 : rotMap[ti][tj]; //overflow
  501.                     }
  502.  
  503.                 }
  504.             }
  505.  
  506.         // Calculate the time to render a frame
  507.         uint32_t currentFrameTime = SDL_GetTicks() - frameStartTime;
  508.         uint32_t timeDelta=currentFrameTime-frameStartTime;
  509.  
  510.         // Wait till FRAME_TIME_TARGET is reached
  511.         if (timeDelta < FRAME_TIME_TARGET ) {
  512.             SDL_Delay(FRAME_TIME_TARGET - timeDelta);
  513.             currentFrameTime = SDL_GetTicks() - frameStartTime;
  514.         }
  515.  
  516.         //skip even frames? reduces flicker
  517.         if( !(frameCount%(simulationSpeed+1)) ){
  518.             renderTiles();
  519.             SDL_GL_SwapWindow(window);
  520.             frameStartTime = SDL_GetTicks();
  521.         }
  522.  
  523.        
  524.         detectKeys();
  525.     }
  526.  
  527.     // Cleanup
  528.     glDeleteTextures(1, &textureID);
  529.     SDL_GL_DeleteContext(glContext);
  530.     SDL_DestroyWindow(window);
  531.     SDL_Quit();
  532.  
  533.     return 0;
  534. }
  535.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement