Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // g++ rgb_draw_array.cpp opengl/glad.c -o rgb_draw_array -lglfw -ldl -lGL -I./include -g
- #include <glad/glad.h>
- #include <GLFW/glfw3.h>
- #include <iostream>
- #include <vector>
- #include <cstdlib> // For rand(), srand()
- #include <ctime> // For time()
- #include <chrono> // For std::chrono functions
- #include <sstream> // For std::ostringstream
- #include <cmath> // For std::ceil
- // Window dimensions
- const int WINDOW_WIDTH = 1920;
- const int WINDOW_HEIGHT = 1080;
- // Number of patches to draw
- const int NUM_PATCHES = 10000;
- // Size for each CPU-generated small patch image
- const int TILE_SIZE = 32; // each patch image is 32x32 pixels
- // Pre-created patch structure (position and size in pixels)
- struct RGBPatch {
- int x_offset; // X position on screen (in pixels)
- int y_offset; // Y position on screen (in pixels)
- int width; // Quad's width on screen (pixels)
- int height; // Quad's height on screen (pixels)
- };
- std::vector<RGBPatch> patches(NUM_PATCHES);
- // Helper function to generate a small image for a patch (RGBA format)
- std::vector<unsigned char> generatePatchImage(int width, int height)
- {
- std::vector<unsigned char> data(width * height * 4);
- // For demonstration, generate random noise per pixel.
- for (int j = 0; j < height; j++)
- {
- for (int i = 0; i < width; i++)
- {
- int index = (j * width + i) * 4;
- data[index + 0] = static_cast<unsigned char>(std::rand() % 256); // R
- data[index + 1] = static_cast<unsigned char>(std::rand() % 256); // G
- data[index + 2] = static_cast<unsigned char>(std::rand() % 256); // B
- data[index + 3] = 255; // A (opaque)
- }
- }
- return data;
- }
- // Vertex shader: Pass through position and texture coordinates.
- const char* vertexShaderSrc = R"(
- #version 330 core
- layout(location = 0) in vec2 aPos; // 2D position
- layout(location = 1) in vec2 aTexCoord; // Texture coordinate
- out vec2 TexCoord;
- void main()
- {
- gl_Position = vec4(aPos, 0.0, 1.0);
- TexCoord = aTexCoord;
- }
- )";
- // Fragment shader: Sample from the texture atlas.
- const char* fragmentShaderSrc = R"(
- #version 330 core
- in vec2 TexCoord;
- out vec4 FragColor;
- uniform sampler2D uTexture;
- void main()
- {
- FragColor = texture(uTexture, TexCoord);
- }
- )";
- // Utility function to check for shader compile/link errors.
- void checkCompileErrors(GLuint shader, std::string type)
- {
- GLint success;
- GLchar infoLog[1024];
- if(type != "PROGRAM")
- {
- glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
- if(!success)
- {
- glGetShaderInfoLog(shader, 1024, NULL, infoLog);
- std::cerr << "ERROR::SHADER_COMPILATION_ERROR of type: "
- << type << "\n" << infoLog
- << "\n -- --------------------------------------------------- -- "
- << std::endl;
- }
- }
- else
- {
- glGetProgramiv(shader, GL_LINK_STATUS, &success);
- if(!success)
- {
- glGetProgramInfoLog(shader, 1024, NULL, infoLog);
- std::cerr << "ERROR::PROGRAM_LINKING_ERROR of type: "
- << type << "\n" << infoLog
- << "\n -- --------------------------------------------------- -- "
- << std::endl;
- }
- }
- }
- int main()
- {
- std::srand(static_cast<unsigned int>(std::time(nullptr)));
- // Initialize GLFW.
- if (!glfwInit())
- {
- std::cerr << "Failed to initialize GLFW!\n";
- return -1;
- }
- // Create an OpenGL 3.3 core profile context.
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
- GLFWwindow* window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "RGB Patch Demo (CPU-generated Images)", nullptr, nullptr);
- if (!window)
- {
- std::cerr << "Failed to create GLFW window!\n";
- glfwTerminate();
- return -1;
- }
- glfwMakeContextCurrent(window);
- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
- {
- std::cerr << "Failed to initialize GLAD!\n";
- return -1;
- }
- // Build and compile shaders.
- GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vertexShader, 1, &vertexShaderSrc, nullptr);
- glCompileShader(vertexShader);
- checkCompileErrors(vertexShader, "VERTEX");
- GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(fragmentShader, 1, &fragmentShaderSrc, nullptr);
- glCompileShader(fragmentShader);
- checkCompileErrors(fragmentShader, "FRAGMENT");
- // Link shaders into a shader program.
- GLuint shaderProgram = glCreateProgram();
- glAttachShader(shaderProgram, vertexShader);
- glAttachShader(shaderProgram, fragmentShader);
- glLinkProgram(shaderProgram);
- checkCompileErrors(shaderProgram, "PROGRAM");
- glDeleteShader(vertexShader);
- glDeleteShader(fragmentShader);
- // Create the texture atlas that will contain all CPU-generated patch images.
- // Determine atlas dimensions (we assume a roughly square layout).
- int atlasCols = static_cast<int>(std::ceil(std::sqrt(NUM_PATCHES)));
- int atlasRows = (NUM_PATCHES + atlasCols - 1) / atlasCols;
- int atlasWidth = atlasCols * TILE_SIZE;
- int atlasHeight = atlasRows * TILE_SIZE;
- // Some random colors to test
- std::vector<unsigned char> atlasDataSet1(atlasWidth * atlasHeight * 4, 0);
- std::vector<unsigned char> atlasDataSet2(atlasWidth * atlasHeight * 4, 0);
- std::vector<unsigned char> atlasDataSet3(atlasWidth * atlasHeight * 4, 0);
- // Generate a small image for each patch and copy it into the atlas.
- for (int i = 0; i < NUM_PATCHES; i++)
- {
- std::vector<unsigned char> patchImage = generatePatchImage(TILE_SIZE, TILE_SIZE);
- int col = i % atlasCols;
- int row = i / atlasCols;
- // Copy patch image into the atlas at its designated location.
- for (int y = 0; y < TILE_SIZE; y++)
- {
- for (int x = 0; x < TILE_SIZE; x++)
- {
- int atlasIndex = ((row * TILE_SIZE + y) * atlasWidth + (col * TILE_SIZE + x)) * 4;
- int patchIndex = (y * TILE_SIZE + x) * 4;
- atlasDataSet1[atlasIndex + 0] = patchImage[patchIndex + 0]; // R
- atlasDataSet1[atlasIndex + 1] = patchImage[patchIndex + 1]; // G
- atlasDataSet1[atlasIndex + 2] = patchImage[patchIndex + 2]; // B
- atlasDataSet1[atlasIndex + 3] = patchImage[patchIndex + 3]; // A
- atlasDataSet2[atlasIndex + 0] = patchImage[patchIndex + 1]; // R
- atlasDataSet2[atlasIndex + 1] = patchImage[patchIndex + 0]; // G
- atlasDataSet2[atlasIndex + 2] = patchImage[patchIndex + 2]; // B
- atlasDataSet2[atlasIndex + 3] = patchImage[patchIndex + 3]; // A
- atlasDataSet3[atlasIndex + 0] = patchImage[patchIndex + 0]; // R
- atlasDataSet3[atlasIndex + 1] = patchImage[patchIndex + 2]; // G
- atlasDataSet3[atlasIndex + 2] = patchImage[patchIndex + 1]; // B
- atlasDataSet3[atlasIndex + 3] = patchImage[patchIndex + 3]; // A
- // Simpler colors to test
- // atlasDataSet1[atlasIndex + 0] = 0; // R
- // atlasDataSet1[atlasIndex + 1] = 0; // G
- // atlasDataSet1[atlasIndex + 2] = 255; // B
- // atlasDataSet1[atlasIndex + 3] = 255; // A
- // atlasDataSet2[atlasIndex + 0] = 255; // R
- // atlasDataSet2[atlasIndex + 1] = 0; // G
- // atlasDataSet2[atlasIndex + 2] = 0; // B
- // atlasDataSet2[atlasIndex + 3] = 255; // A
- // atlasDataSet3[atlasIndex + 0] = 0; // R
- // atlasDataSet3[atlasIndex + 1] = 255; // G
- // atlasDataSet3[atlasIndex + 2] = 0; // B
- // atlasDataSet3[atlasIndex + 3] = 255; // A
- }
- }
- }
- // Create the atlas texture on the GPU.
- GLuint atlasTexture;
- glGenTextures(1, &atlasTexture);
- glBindTexture(GL_TEXTURE_2D, atlasTexture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- // Create a Vertex Array Object and a dynamic Vertex Buffer Object.
- // Each vertex has 4 floats: 2 for position and 2 for texture coordinate.
- GLuint VAO, VBO;
- glGenVertexArrays(1, &VAO);
- glGenBuffers(1, &VBO);
- glBindVertexArray(VAO);
- glBindBuffer(GL_ARRAY_BUFFER, VBO);
- // Reserve maximum buffer size for NUM_PATCHES * 6 vertices * 4 floats per vertex.
- glBufferData(GL_ARRAY_BUFFER, NUM_PATCHES * 6 * 4 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
- // Set up vertex attributes.
- // Position attribute.
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
- glEnableVertexAttribArray(0);
- // Texture coordinate attribute.
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
- glEnableVertexAttribArray(1);
- glBindVertexArray(0);
- // Initialize each patch with a random width and height (for visibility, use values between 20 and 50).
- for(auto &patch : patches)
- {
- patch.width = std::rand() % 31 + 20; // 20 to 50
- patch.height = std::rand() % 31 + 20; // 20 to 50
- }
- // Enable v-sync (optional).
- // glfwSwapInterval(0);
- auto startTime = std::chrono::high_resolution_clock::now();
- int frameCount = 0;
- // Main render loop.
- while(!glfwWindowShouldClose(window))
- {
- glBindTexture(GL_TEXTURE_2D, atlasTexture);
- // Track which color channel to use (0=blue, 1=red, 2=green)
- static int colorChannel = 0;
- if (colorChannel == 0) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TILE_SIZE, TILE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, atlasDataSet1.data());
- } else if (colorChannel == 1) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TILE_SIZE, TILE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, atlasDataSet3.data());
- } else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TILE_SIZE, TILE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, atlasDataSet2.data());
- }
- // Cycle through colors (blue -> red -> green -> blue...)
- colorChannel = (colorChannel + 1) % 3;
- // Build vertex data for all patches.
- // For each patch we create 6 vertices (2 triangles) with:
- // [position.x, position.y, texcoord.x, texcoord.y]
- std::vector<float> verticesData;
- verticesData.reserve(NUM_PATCHES * 6 * 4);
- for (int i = 0; i < NUM_PATCHES; i++)
- {
- // Randomize current patch position, ensuring it fits within the window.
- RGBPatch &patch = patches[i];
- patch.x_offset = std::rand() % (WINDOW_WIDTH - patch.width);
- patch.y_offset = std::rand() % (WINDOW_HEIGHT - patch.height);
- // Convert patch screen coordinates to normalized device coordinates (NDC).
- float left = (2.0f * patch.x_offset / WINDOW_WIDTH) - 1.0f;
- float right = (2.0f * (patch.x_offset + patch.width) / WINDOW_WIDTH) - 1.0f;
- float bottom = (2.0f * patch.y_offset / WINDOW_HEIGHT) - 1.0f;
- float top = (2.0f * (patch.y_offset + patch.height) / WINDOW_HEIGHT) - 1.0f;
- // Compute the texture coordinates from the atlas.
- int col = i % atlasCols;
- int row = i / atlasCols;
- float tx0 = (col * TILE_SIZE) / float(atlasWidth);
- float ty0 = (row * TILE_SIZE) / float(atlasHeight);
- float tx1 = ((col * TILE_SIZE) + TILE_SIZE) / float(atlasWidth);
- float ty1 = ((row * TILE_SIZE) + TILE_SIZE) / float(atlasHeight);
- // Define two triangles (6 vertices) for the quad.
- // Triangle 1: bottom-left, top-left, bottom-right.
- verticesData.insert(verticesData.end(), { left, bottom, tx0, ty0 });
- verticesData.insert(verticesData.end(), { left, top, tx0, ty1 });
- verticesData.insert(verticesData.end(), { right, bottom, tx1, ty0 });
- // Triangle 2: top-left, top-right, bottom-right.
- verticesData.insert(verticesData.end(), { left, top, tx0, ty1 });
- verticesData.insert(verticesData.end(), { right, top, tx1, ty1 });
- verticesData.insert(verticesData.end(), { right, bottom, tx1, ty0 });
- }
- // Update the vertex buffer with the current vertex data.
- glBindBuffer(GL_ARRAY_BUFFER, VBO);
- glBufferData(GL_ARRAY_BUFFER, verticesData.size() * sizeof(float), verticesData.data(), GL_DYNAMIC_DRAW);
- // Render.
- glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- glUseProgram(shaderProgram);
- glBindTexture(GL_TEXTURE_2D, atlasTexture);
- glBindVertexArray(VAO);
- glDrawArrays(GL_TRIANGLES, 0, verticesData.size() / 4);
- glfwSwapBuffers(window);
- glfwPollEvents();
- // FPS calculation.
- frameCount++;
- auto currentTime = std::chrono::high_resolution_clock::now();
- float elapsedTime = std::chrono::duration<float>(currentTime - startTime).count();
- if (elapsedTime >= 1.0f)
- {
- float fps = frameCount / elapsedTime;
- std::ostringstream title;
- title << "RGB Patch Demo (CPU-generated Images) - FPS: " << fps;
- glfwSetWindowTitle(window, title.str().c_str());
- frameCount = 0;
- startTime = currentTime;
- }
- }
- // Cleanup allocated resources.
- glDeleteVertexArrays(1, &VAO);
- glDeleteBuffers(1, &VBO);
- glDeleteTextures(1, &atlasTexture);
- glDeleteProgram(shaderProgram);
- glfwDestroyWindow(window);
- glfwTerminate();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement