Advertisement
Guest User

Untitled

a guest
Feb 16th, 2025
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.01 KB | None | 0 0
  1. #include <glad/glad.h>
  2. #include <GLFW/glfw3.h>
  3.  
  4. #include <glm/glm.hpp>
  5. #include <glm/gtc/matrix_transform.hpp>
  6. #include <glm/gtc/type_ptr.hpp>
  7.  
  8. #include <vector>
  9. #include <cstdlib>
  10. #include <ctime>
  11. #include <iostream>
  12.  
  13. // Window dimensions
  14. const int WINDOW_WIDTH  = 800;
  15. const int WINDOW_HEIGHT = 600;
  16.  
  17. // We might have 1K images per frame.
  18. const int NUM_IMAGES = 1000;
  19.  
  20. // Define a texture atlas size (must be large enough to pack all images)
  21. const int ATLAS_WIDTH  = 2048;
  22. const int ATLAS_HEIGHT = 2048;
  23.  
  24. // A simple structure to hold an RGB image (3 channels, no alpha) with variable dimensions.
  25. struct Image {
  26.     int width;
  27.     int height;
  28.     std::vector<unsigned char> data; // packed as RGB (3 bytes per pixel)
  29. };
  30.  
  31. // Generate a random image with given dimensions.
  32. Image generateRandomImage(int width, int height) {
  33.     Image img;
  34.     img.width  = width;
  35.     img.height = height;
  36.     img.data.resize(width * height * 3);
  37.     for (int i = 0; i < width * height * 3; i++) {
  38.         img.data[i] = static_cast<unsigned char>(std::rand() % 256);
  39.     }
  40.     return img;
  41. }
  42.  
  43. // This structure holds per-image instance data (destination and atlas coordinates).
  44. struct InstanceData {
  45.     // Where on screen to draw this image quad (in pixels)
  46.     float destX, destY, destW, destH;
  47.     // Texture coordinates (normalized: 0.0–1.0) for this image within the atlas.
  48.     float atlasX, atlasY, atlasW, atlasH;
  49. };
  50.  
  51. //
  52. // Main function
  53. //
  54. int main()
  55. {
  56.     std::srand(static_cast<unsigned int>(std::time(nullptr)));
  57.     if (!glfwInit()){
  58.         std::cerr << "Failed to init GLFW" << std::endl;
  59.         return -1;
  60.     }
  61.     // Request OpenGL 3.3 Core Profile.
  62.     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  63.     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  64.     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  65.    
  66.     GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Atlas Rendering with Instancing", nullptr, nullptr);
  67.     if (!window){
  68.         std::cerr << "Failed to create GLFW window" << std::endl;
  69.         glfwTerminate();
  70.         return -1;
  71.     }
  72.     glfwMakeContextCurrent(window);
  73.    
  74.     if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
  75.         std::cerr << "Failed to initialize GLAD" << std::endl;
  76.         return -1;
  77.     }
  78.    
  79.     // -------------------------------------------------------------------
  80.     // Create shaders (using instanced attributes)
  81.     const char* vertexShaderSrc = R"(
  82.        #version 330 core
  83.        // Per-vertex attributes for a unit quad.
  84.        layout (location = 0) in vec2 aPos;   // positions in [0,1]
  85.        layout (location = 1) in vec2 aTex;   // texture coordinates in [0,1]
  86.        // Instance attributes:
  87.        layout (location = 2) in vec4 aDest;  // destination rectangle: x, y, w, h (in screen pixels)
  88.        layout (location = 3) in vec4 aAtlas; // atlas coordinates: x, y, w, h (normalized 0–1)
  89.    
  90.        uniform mat4 uProjection; // Orthographic projection.
  91.    
  92.        out vec2 TexCoord;
  93.    
  94.        void main(){
  95.            // Scale the unit quad (0..1) to the destination rectangle.
  96.            vec2 pos = aPos * aDest.zw + aDest.xy;
  97.            gl_Position = uProjection * vec4(pos, 0.0, 1.0);
  98.            // Compute per-vertex texture coordinate from atlas region.
  99.            TexCoord = aTex * aAtlas.zw + aAtlas.xy;
  100.        }
  101.    )";
  102.    
  103.     const char* fragmentShaderSrc = R"(
  104.        #version 330 core
  105.        in vec2 TexCoord;
  106.        out vec4 FragColor;
  107.    
  108.        uniform sampler2D uAtlas;
  109.    
  110.        void main(){
  111.            FragColor = texture(uAtlas, TexCoord);
  112.        }
  113.    )";
  114.    
  115.     // Simple shader compilation utility.
  116.     auto compile_shader = [](GLenum type, const char* src) -> GLuint {
  117.         GLuint shader = glCreateShader(type);
  118.         glShaderSource(shader, 1, &src, nullptr);
  119.         glCompileShader(shader);
  120.         int success;
  121.         glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
  122.         if (!success){
  123.             char infoLog[512];
  124.             glGetShaderInfoLog(shader, 512, nullptr, infoLog);
  125.             std::cerr << "Shader compilation error: " << infoLog << std::endl;
  126.         }
  127.         return shader;
  128.     };
  129.    
  130.     GLuint vs = compile_shader(GL_VERTEX_SHADER, vertexShaderSrc);
  131.     GLuint fs = compile_shader(GL_FRAGMENT_SHADER, fragmentShaderSrc);
  132.     GLuint shaderProgram = glCreateProgram();
  133.     glAttachShader(shaderProgram, vs);
  134.     glAttachShader(shaderProgram, fs);
  135.     glLinkProgram(shaderProgram);
  136.     glDeleteShader(vs);
  137.     glDeleteShader(fs);
  138.    
  139.     // -------------------------------------------------------------------
  140.     // Create a unit quad (two triangles) VBO/VAO.
  141.     float quadVertices[] = {
  142.         // positions    // texCoords
  143.          0.0f, 0.0f,    0.0f, 0.0f,  // bottom-left
  144.          1.0f, 0.0f,    1.0f, 0.0f,  // bottom-right
  145.          1.0f, 1.0f,    1.0f, 1.0f,  // top-right
  146.    
  147.          0.0f, 0.0f,    0.0f, 0.0f,  // bottom-left
  148.          1.0f, 1.0f,    1.0f, 1.0f,  // top-right
  149.          0.0f, 1.0f,    0.0f, 1.0f   // top-left
  150.     };
  151.     GLuint quadVAO, quadVBO;
  152.     glGenVertexArrays(1, &quadVAO);
  153.     glGenBuffers(1, &quadVBO);
  154.     glBindVertexArray(quadVAO);
  155.       glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
  156.       glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
  157.       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
  158.       glEnableVertexAttribArray(0);
  159.       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
  160.       glEnableVertexAttribArray(1);
  161.     glBindVertexArray(0);
  162.    
  163.     // -------------------------------------------------------------------
  164.     // Create a texture atlas and pack all small images into it.
  165.     // We'll allocate an empty atlas buffer and then copy each image's data into it.
  166.     std::vector<unsigned char> atlasData(ATLAS_WIDTH * ATLAS_HEIGHT * 3, 0);
  167.     std::vector<Image> images;
  168.     std::vector<InstanceData> instances;
  169.    
  170.     // For a simple atlas packer, we use a "shelf" algorithm.
  171.     int curX = 0, curY = 0, rowHeight = 0;
  172.     // Also arrange destination positions in a grid.
  173.     int gridCols = 32; // number of images per row on screen
  174.     int cellSize  = 40;
  175.    
  176.     for (int i = 0; i < NUM_IMAGES; i++){
  177.         // Random image size: for demo, vary between 16 and 40 pixels.
  178.         int w = 16 + std::rand() % 25;
  179.         int h = 16 + std::rand() % 25;
  180.         Image img = generateRandomImage(w, h);
  181.         images.push_back(img);
  182.    
  183.         // Pack into atlas: if not enough room in current row, move to next row.
  184.         if (curX + w > ATLAS_WIDTH) {
  185.             curX = 0;
  186.             curY += rowHeight;
  187.             rowHeight = 0;
  188.         }
  189.         if (curY + h > ATLAS_HEIGHT) {
  190.             std::cerr << "Atlas overflow!" << std::endl;
  191.             break;
  192.         }
  193.    
  194.         // Copy pixel data into atlasData at position (curX, curY)
  195.         for (int row = 0; row < h; row++){
  196.             int destRow = curY + row;
  197.             int srcIndex  = row * w * 3;
  198.             int destIndex = (destRow * ATLAS_WIDTH + curX) * 3;
  199.             std::copy(images[i].data.begin() + srcIndex,
  200.                       images[i].data.begin() + srcIndex + w * 3,
  201.                       atlasData.begin() + destIndex);
  202.         }
  203.    
  204.         // Compute normalized atlas coordinates for this image.
  205.         float atlasX = float(curX) / ATLAS_WIDTH;
  206.         float atlasY = float(curY) / ATLAS_HEIGHT;
  207.         float atlasW = float(w) / ATLAS_WIDTH;
  208.         float atlasH = float(h) / ATLAS_HEIGHT;
  209.    
  210.         // Set destination rectangle (for demonstration, arrange in a grid).
  211.         int col = i % gridCols;
  212.         int row = i / gridCols;
  213.         float destX = col * cellSize + 10.0f;
  214.         float destY = row * cellSize + 10.0f;
  215.         float destW = float(w); // you might choose to scale these to a fixed cell size
  216.         float destH = float(h);
  217.    
  218.         InstanceData inst;
  219.         inst.destX = destX; inst.destY = destY; inst.destW = destW; inst.destH = destH;
  220.         inst.atlasX = atlasX; inst.atlasY = atlasY; inst.atlasW = atlasW; inst.atlasH = atlasH;
  221.         instances.push_back(inst);
  222.    
  223.         curX += w; // advance current x in atlas
  224.         if (h > rowHeight) rowHeight = h;
  225.     }
  226.    
  227.     // Create the atlas texture.
  228.     GLuint atlasTexture;
  229.     glGenTextures(1, &atlasTexture);
  230.     glBindTexture(GL_TEXTURE_2D, atlasTexture);
  231.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ATLAS_WIDTH, ATLAS_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, atlasData.data());
  232.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  233.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  234.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  235.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  236.    
  237.     // -------------------------------------------------------------------
  238.     // Create and fill an instance VBO with per-image data.
  239.     GLuint instanceVBO;
  240.     glGenBuffers(1, &instanceVBO);
  241.     glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
  242.     glBufferData(GL_ARRAY_BUFFER, instances.size() * sizeof(InstanceData), instances.data(), GL_DYNAMIC_DRAW);
  243.    
  244.     // Attach instance data to the quad VAO.
  245.     glBindVertexArray(quadVAO);
  246.       // Location 2: destination rectangle (vec4)
  247.       glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (void*)0);
  248.       glEnableVertexAttribArray(2);
  249.       glVertexAttribDivisor(2, 1); // update per instance
  250.       // Location 3: atlas rectangle (vec4)
  251.       glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(InstanceData), (void*)(4 * sizeof(float)));
  252.       glEnableVertexAttribArray(3);
  253.       glVertexAttribDivisor(3, 1);
  254.     glBindVertexArray(0);
  255.    
  256.     // Create an orthographic projection matrix.
  257.     glm::mat4 projection = glm::ortho(0.0f, float(WINDOW_WIDTH), 0.0f, float(WINDOW_HEIGHT), -1.0f, 1.0f);
  258.    
  259.     // -------------------------------------------------------------------
  260.     // Render loop.
  261.     while (!glfwWindowShouldClose(window))
  262.     {
  263.         glClearColor(0.2f, 0.2f, 0.2f, 1.0f);
  264.         glClear(GL_COLOR_BUFFER_BIT);
  265.    
  266.         glUseProgram(shaderProgram);
  267.         glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "uProjection"), 1, GL_FALSE, glm::value_ptr(projection));
  268.    
  269.         // Bind the atlas texture once.
  270.         glActiveTexture(GL_TEXTURE0);
  271.         glBindTexture(GL_TEXTURE_2D, atlasTexture);
  272.         glUniform1i(glGetUniformLocation(shaderProgram, "uAtlas"), 0);
  273.    
  274.         glBindVertexArray(quadVAO);
  275.         // Draw all image quads with instancing.
  276.         glDrawArraysInstanced(GL_TRIANGLES, 0, 6, instances.size());
  277.    
  278.         glfwSwapBuffers(window);
  279.         glfwPollEvents();
  280.     }
  281.    
  282.     // Cleanup.
  283.     glDeleteVertexArrays(1, &quadVAO);
  284.     glDeleteBuffers(1, &quadVBO);
  285.     glDeleteBuffers(1, &instanceVBO);
  286.     glDeleteTextures(1, &atlasTexture);
  287.     glDeleteProgram(shaderProgram);
  288.     glfwDestroyWindow(window);
  289.     glfwTerminate();
  290.    
  291.     return 0;
  292. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement