Advertisement
Guest User

Untitled

a guest
Feb 2nd, 2025
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.42 KB | None | 0 0
  1. // g++ rgb_draw_array.cpp opengl/glad.c -o rgb_draw_array -lglfw -ldl -lGL -I./include -g
  2. #include <glad/glad.h>
  3. #include <GLFW/glfw3.h>
  4. #include <iostream>
  5. #include <vector>
  6. #include <cstdlib>   // For rand(), srand()
  7. #include <ctime>     // For time()
  8. #include <chrono>    // For std::chrono functions
  9. #include <sstream>   // For std::ostringstream
  10. #include <cmath>     // For std::ceil
  11.  
  12. // Window dimensions
  13. const int WINDOW_WIDTH  = 1920;
  14. const int WINDOW_HEIGHT = 1080;
  15.  
  16. // Number of patches to draw
  17. const int NUM_PATCHES = 10000;
  18.  
  19. // Size for each CPU-generated small patch image
  20. const int TILE_SIZE = 32; // each patch image is 32x32 pixels
  21.  
  22. // Pre-created patch structure (position and size in pixels)
  23. struct RGBPatch {
  24.     int x_offset;  // X position on screen (in pixels)
  25.     int y_offset;  // Y position on screen (in pixels)
  26.     int width;     // Quad's width on screen (pixels)
  27.     int height;    // Quad's height on screen (pixels)
  28. };
  29.  
  30. std::vector<RGBPatch> patches(NUM_PATCHES);
  31.  
  32. // Helper function to generate a small image for a patch (RGBA format)
  33. std::vector<unsigned char> generatePatchImage(int width, int height)
  34. {
  35.     std::vector<unsigned char> data(width * height * 4);
  36.     // For demonstration, generate random noise per pixel.
  37.     for (int j = 0; j < height; j++)
  38.     {
  39.         for (int i = 0; i < width; i++)
  40.         {
  41.             int index = (j * width + i) * 4;
  42.             data[index + 0] = static_cast<unsigned char>(std::rand() % 256); // R
  43.             data[index + 1] = static_cast<unsigned char>(std::rand() % 256); // G
  44.             data[index + 2] = static_cast<unsigned char>(std::rand() % 256); // B
  45.             data[index + 3] = 255; // A (opaque)
  46.         }
  47.     }
  48.     return data;
  49. }
  50.  
  51. // Vertex shader: Pass through position and texture coordinates.
  52. const char* vertexShaderSrc = R"(
  53. #version 330 core
  54. layout(location = 0) in vec2 aPos;      // 2D position
  55. layout(location = 1) in vec2 aTexCoord;   // Texture coordinate
  56. out vec2 TexCoord;
  57. void main()
  58. {
  59.    gl_Position = vec4(aPos, 0.0, 1.0);
  60.    TexCoord = aTexCoord;
  61. }
  62. )";
  63.  
  64. // Fragment shader: Sample from the texture atlas.
  65. const char* fragmentShaderSrc = R"(
  66. #version 330 core
  67. in vec2 TexCoord;
  68. out vec4 FragColor;
  69. uniform sampler2D uTexture;
  70. void main()
  71. {
  72.    FragColor = texture(uTexture, TexCoord);
  73. }
  74. )";
  75.  
  76. // Utility function to check for shader compile/link errors.
  77. void checkCompileErrors(GLuint shader, std::string type)
  78. {
  79.     GLint success;
  80.     GLchar infoLog[1024];
  81.     if(type != "PROGRAM")
  82.     {
  83.         glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
  84.         if(!success)
  85.         {
  86.             glGetShaderInfoLog(shader, 1024, NULL, infoLog);
  87.             std::cerr << "ERROR::SHADER_COMPILATION_ERROR of type: "
  88.                       << type << "\n" << infoLog
  89.                       << "\n -- --------------------------------------------------- -- "
  90.                       << std::endl;
  91.         }
  92.     }
  93.     else
  94.     {
  95.         glGetProgramiv(shader, GL_LINK_STATUS, &success);
  96.         if(!success)
  97.         {
  98.             glGetProgramInfoLog(shader, 1024, NULL, infoLog);
  99.             std::cerr << "ERROR::PROGRAM_LINKING_ERROR of type: "
  100.                       << type << "\n" << infoLog
  101.                       << "\n -- --------------------------------------------------- -- "
  102.                       << std::endl;
  103.         }
  104.     }
  105. }
  106.  
  107. int main()
  108. {
  109.     std::srand(static_cast<unsigned int>(std::time(nullptr)));
  110.    
  111.     // Initialize GLFW.
  112.     if (!glfwInit())
  113.     {
  114.         std::cerr << "Failed to initialize GLFW!\n";
  115.         return -1;
  116.     }
  117.    
  118.     // Create an OpenGL 3.3 core profile context.
  119.     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  120.     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  121.     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  122.    
  123.     GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "RGB Patch Demo (CPU-generated Images)", nullptr, nullptr);
  124.     if (!window)
  125.     {
  126.         std::cerr << "Failed to create GLFW window!\n";
  127.         glfwTerminate();
  128.         return -1;
  129.     }
  130.     glfwMakeContextCurrent(window);
  131.    
  132.     if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
  133.     {
  134.         std::cerr << "Failed to initialize GLAD!\n";
  135.         return -1;
  136.     }
  137.    
  138.     // Build and compile shaders.
  139.     GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
  140.     glShaderSource(vertexShader, 1, &vertexShaderSrc, nullptr);
  141.     glCompileShader(vertexShader);
  142.     checkCompileErrors(vertexShader, "VERTEX");
  143.    
  144.     GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  145.     glShaderSource(fragmentShader, 1, &fragmentShaderSrc, nullptr);
  146.     glCompileShader(fragmentShader);
  147.     checkCompileErrors(fragmentShader, "FRAGMENT");
  148.    
  149.     // Link shaders into a shader program.
  150.     GLuint shaderProgram = glCreateProgram();
  151.     glAttachShader(shaderProgram, vertexShader);
  152.     glAttachShader(shaderProgram, fragmentShader);
  153.     glLinkProgram(shaderProgram);
  154.     checkCompileErrors(shaderProgram, "PROGRAM");
  155.    
  156.     glDeleteShader(vertexShader);
  157.     glDeleteShader(fragmentShader);
  158.    
  159.     // Create the texture atlas that will contain all CPU-generated patch images.
  160.     // Determine atlas dimensions (we assume a roughly square layout).
  161.     int atlasCols = static_cast<int>(std::ceil(std::sqrt(NUM_PATCHES)));
  162.     int atlasRows = (NUM_PATCHES + atlasCols - 1) / atlasCols;
  163.     int atlasWidth  = atlasCols * TILE_SIZE;
  164.     int atlasHeight = atlasRows * TILE_SIZE;
  165.    
  166.     // Some random colors to test
  167.     std::vector<unsigned char> atlasDataSet1(atlasWidth * atlasHeight * 4, 0);
  168.     std::vector<unsigned char> atlasDataSet2(atlasWidth * atlasHeight * 4, 0);
  169.     std::vector<unsigned char> atlasDataSet3(atlasWidth * atlasHeight * 4, 0);
  170.    
  171.     // Generate a small image for each patch and copy it into the atlas.
  172.     for (int i = 0; i < NUM_PATCHES; i++)
  173.     {
  174.         std::vector<unsigned char> patchImage = generatePatchImage(TILE_SIZE, TILE_SIZE);
  175.         int col = i % atlasCols;
  176.         int row = i / atlasCols;
  177.         // Copy patch image into the atlas at its designated location.
  178.         for (int y = 0; y < TILE_SIZE; y++)
  179.         {
  180.             for (int x = 0; x < TILE_SIZE; x++)
  181.             {
  182.                 int atlasIndex = ((row * TILE_SIZE + y) * atlasWidth + (col * TILE_SIZE + x)) * 4;
  183.                 int patchIndex = (y * TILE_SIZE + x) * 4;
  184.  
  185.                 atlasDataSet1[atlasIndex + 0] = patchImage[patchIndex + 0];      // R
  186.                 atlasDataSet1[atlasIndex + 1] = patchImage[patchIndex + 1];      // G
  187.                 atlasDataSet1[atlasIndex + 2] = patchImage[patchIndex + 2];    // B
  188.                 atlasDataSet1[atlasIndex + 3] = patchImage[patchIndex + 3];    // A
  189.  
  190.                 atlasDataSet2[atlasIndex + 0] = patchImage[patchIndex + 1];      // R
  191.                 atlasDataSet2[atlasIndex + 1] = patchImage[patchIndex + 0];      // G    
  192.                 atlasDataSet2[atlasIndex + 2] = patchImage[patchIndex + 2];    // B
  193.                 atlasDataSet2[atlasIndex + 3] = patchImage[patchIndex + 3];    // A
  194.  
  195.                 atlasDataSet3[atlasIndex + 0] = patchImage[patchIndex + 0];      // R
  196.                 atlasDataSet3[atlasIndex + 1] = patchImage[patchIndex + 2];      // G
  197.                 atlasDataSet3[atlasIndex + 2] = patchImage[patchIndex + 1];    // B
  198.                 atlasDataSet3[atlasIndex + 3] = patchImage[patchIndex + 3];    // A
  199.  
  200.                 // Simpler colors to test
  201.                 // atlasDataSet1[atlasIndex + 0] = 0;      // R
  202.                 // atlasDataSet1[atlasIndex + 1] = 0;      // G
  203.                 // atlasDataSet1[atlasIndex + 2] = 255;    // B
  204.                 // atlasDataSet1[atlasIndex + 3] = 255;    // A
  205.  
  206.                 // atlasDataSet2[atlasIndex + 0] = 255;     // R
  207.                 // atlasDataSet2[atlasIndex + 1] = 0;       // G
  208.                 // atlasDataSet2[atlasIndex + 2] = 0;       // B
  209.                 // atlasDataSet2[atlasIndex + 3] = 255;     // A
  210.  
  211.                 // atlasDataSet3[atlasIndex + 0] = 0;     // R
  212.                 // atlasDataSet3[atlasIndex + 1] = 255;   // G
  213.                 // atlasDataSet3[atlasIndex + 2] = 0;     // B
  214.                 // atlasDataSet3[atlasIndex + 3] = 255;   // A
  215.             }
  216.         }
  217.     }
  218.    
  219.     // Create the atlas texture on the GPU.
  220.     GLuint atlasTexture;
  221.     glGenTextures(1, &atlasTexture);
  222.     glBindTexture(GL_TEXTURE_2D, atlasTexture);
  223.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  224.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  225.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  226.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  227.    
  228.     // Create a Vertex Array Object and a dynamic Vertex Buffer Object.
  229.     // Each vertex has 4 floats: 2 for position and 2 for texture coordinate.
  230.     GLuint VAO, VBO;
  231.     glGenVertexArrays(1, &VAO);
  232.     glGenBuffers(1, &VBO);
  233.    
  234.     glBindVertexArray(VAO);
  235.     glBindBuffer(GL_ARRAY_BUFFER, VBO);
  236.     // Reserve maximum buffer size for NUM_PATCHES * 6 vertices * 4 floats per vertex.
  237.     glBufferData(GL_ARRAY_BUFFER, NUM_PATCHES * 6 * 4 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
  238.    
  239.     // Set up vertex attributes.
  240.     // Position attribute.
  241.     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
  242.     glEnableVertexAttribArray(0);
  243.     // Texture coordinate attribute.
  244.     glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
  245.     glEnableVertexAttribArray(1);
  246.    
  247.     glBindVertexArray(0);
  248.    
  249.     // Initialize each patch with a random width and height (for visibility, use values between 20 and 50).
  250.     for(auto &patch : patches)
  251.     {
  252.         patch.width  = std::rand() % 31 + 20;  // 20 to 50
  253.         patch.height = std::rand() % 31 + 20;   // 20 to 50
  254.     }
  255.    
  256.     // Enable v-sync (optional).
  257.     // glfwSwapInterval(0);
  258.    
  259.     auto startTime = std::chrono::high_resolution_clock::now();
  260.     int frameCount = 0;
  261.  
  262.  
  263.     // Main render loop.
  264.     while(!glfwWindowShouldClose(window))
  265.     {
  266.         glBindTexture(GL_TEXTURE_2D, atlasTexture);
  267.         // Track which color channel to use (0=blue, 1=red, 2=green)
  268.         static int colorChannel = 0;
  269.         if (colorChannel == 0) {
  270.             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TILE_SIZE, TILE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, atlasDataSet1.data());
  271.         } else if (colorChannel == 1) {
  272.             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TILE_SIZE, TILE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, atlasDataSet3.data());
  273.         } else {
  274.             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TILE_SIZE, TILE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, atlasDataSet2.data());
  275.         }
  276.        
  277.         // Cycle through colors (blue -> red -> green -> blue...)
  278.         colorChannel = (colorChannel + 1) % 3;
  279.  
  280.         // Build vertex data for all patches.
  281.         // For each patch we create 6 vertices (2 triangles) with:
  282.         // [position.x, position.y, texcoord.x, texcoord.y]
  283.         std::vector<float> verticesData;
  284.         verticesData.reserve(NUM_PATCHES * 6 * 4);
  285.        
  286.         for (int i = 0; i < NUM_PATCHES; i++)
  287.         {
  288.             // Randomize current patch position, ensuring it fits within the window.
  289.             RGBPatch &patch = patches[i];
  290.             patch.x_offset = std::rand() % (WINDOW_WIDTH  - patch.width);
  291.             patch.y_offset = std::rand() % (WINDOW_HEIGHT - patch.height);
  292.            
  293.             // Convert patch screen coordinates to normalized device coordinates (NDC).
  294.             float left   = (2.0f * patch.x_offset / WINDOW_WIDTH) - 1.0f;
  295.             float right  = (2.0f * (patch.x_offset + patch.width) / WINDOW_WIDTH) - 1.0f;
  296.             float bottom = (2.0f * patch.y_offset / WINDOW_HEIGHT) - 1.0f;
  297.             float top    = (2.0f * (patch.y_offset + patch.height) / WINDOW_HEIGHT) - 1.0f;
  298.            
  299.             // Compute the texture coordinates from the atlas.
  300.             int col = i % atlasCols;
  301.             int row = i / atlasCols;
  302.             float tx0 = (col * TILE_SIZE) / float(atlasWidth);
  303.             float ty0 = (row * TILE_SIZE) / float(atlasHeight);
  304.             float tx1 = ((col * TILE_SIZE) + TILE_SIZE) / float(atlasWidth);
  305.             float ty1 = ((row * TILE_SIZE) + TILE_SIZE) / float(atlasHeight);
  306.            
  307.             // Define two triangles (6 vertices) for the quad.
  308.             // Triangle 1: bottom-left, top-left, bottom-right.
  309.             verticesData.insert(verticesData.end(), { left, bottom, tx0, ty0 });
  310.             verticesData.insert(verticesData.end(), { left,    top, tx0, ty1 });
  311.             verticesData.insert(verticesData.end(), { right, bottom, tx1, ty0 });
  312.             // Triangle 2: top-left, top-right, bottom-right.
  313.             verticesData.insert(verticesData.end(), { left,    top, tx0, ty1 });
  314.             verticesData.insert(verticesData.end(), { right,   top, tx1, ty1 });
  315.             verticesData.insert(verticesData.end(), { right, bottom, tx1, ty0 });
  316.         }
  317.        
  318.         // Update the vertex buffer with the current vertex data.
  319.         glBindBuffer(GL_ARRAY_BUFFER, VBO);
  320.         glBufferData(GL_ARRAY_BUFFER, verticesData.size() * sizeof(float), verticesData.data(), GL_DYNAMIC_DRAW);
  321.        
  322.         // Render.
  323.         glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
  324.         glClear(GL_COLOR_BUFFER_BIT);
  325.        
  326.         glUseProgram(shaderProgram);
  327.         glBindTexture(GL_TEXTURE_2D, atlasTexture);
  328.         glBindVertexArray(VAO);
  329.         glDrawArrays(GL_TRIANGLES, 0, verticesData.size() / 4);
  330.        
  331.         glfwSwapBuffers(window);
  332.         glfwPollEvents();
  333.        
  334.         // FPS calculation.
  335.         frameCount++;
  336.         auto currentTime = std::chrono::high_resolution_clock::now();
  337.         float elapsedTime = std::chrono::duration<float>(currentTime - startTime).count();
  338.         if (elapsedTime >= 1.0f)
  339.         {
  340.             float fps = frameCount / elapsedTime;
  341.             std::ostringstream title;
  342.             title << "RGB Patch Demo (CPU-generated Images) - FPS: " << fps;
  343.             glfwSetWindowTitle(window, title.str().c_str());
  344.             frameCount = 0;
  345.             startTime = currentTime;
  346.         }
  347.     }
  348.    
  349.     // Cleanup allocated resources.
  350.     glDeleteVertexArrays(1, &VAO);
  351.     glDeleteBuffers(1, &VBO);
  352.     glDeleteTextures(1, &atlasTexture);
  353.     glDeleteProgram(shaderProgram);
  354.    
  355.     glfwDestroyWindow(window);
  356.     glfwTerminate();
  357.     return 0;
  358. }
  359.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement