dimanche 4 juin 2023

C++ OpenGL Why is only one image rendering?

Hello I am new to OpenGL and I am trying to learn it .
I am trying to create a way to load all the images which I plan to use in OpenGL and then render them all on the screen. It seems OpenGL seems to be very code repetitive in it's process of creating VAO,VBA, and EBOs.

I am a newbie at this , so please explain why this is only rendering one image? I thought the image object would be stored in the VAO.

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#include "ogl_shaders.h"

const int MAX_TEXTURES = 255;
GLuint vaos[MAX_TEXTURES] = {0};
GLuint s_textures[MAX_TEXTURES] = {0};
int x_pos[] = {0, 300, 600};
int y_pox[] = {0, 100, 50};
int w_size[] = {200,200, 200};
int h_wize[] = {200, 200, 200};
std::vector<std::string> g_image_paths = { "image.png", "image2.png", "image3.png" };

struct Vec2 {
    float x;
    float y;
};

Vec2 toNDC(int pixel_x, int pixel_y, int window_width, int window_height) {
    Vec2 vec;
    vec.x = (static_cast<float>(pixel_x) / window_width) * 2.0f - 1.0f;
    vec.y = (static_cast<float>(pixel_y) / window_height) * 2.0f - 1.0f;
    return vec;
}

// I assume the problem is here  <<<
GLuint setupImageRectangle(int posX, int posY, int sizeX, int sizeY, GLuint shaderProgram, GLuint texture) {
    // Convert position to NDC
    Vec2 vec = toNDC(posX, posY, 800, 600);
    float ndcPosX = vec.x;
    float ndcPosY = vec.y;

    // Convert size to NDC
    float ndcSizeX = static_cast<float>(sizeX) / (800 / 2.0f);
    float ndcSizeY = static_cast<float>(sizeY) / (600 / 2.0f);

    // Vertex data for the rectangle
    float vertices[] = {
        ndcPosX, ndcPosY, 0.0f, 0.0f, // Bottom-left
        ndcPosX + ndcSizeX, ndcPosY, 1.0f, 0.0f, // Bottom-right
        ndcPosX + ndcSizeX, ndcPosY + ndcSizeY, 1.0f, 1.0f, // Top-right
        ndcPosX, ndcPosY + ndcSizeY, 0.0f, 1.0f  // Top-left
    };

    GLuint elements[] = {0, 1, 2, 2, 3, 0};

    // Create and bind the VAO
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // Load the vertex data into a VBO
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // Load the element data into an EBO
    GLuint ebo;
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);

    // Specify the layout of the vertex data
    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
    glEnableVertexAttribArray(posAttrib);
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);

    GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
    glEnableVertexAttribArray(texAttrib);
    glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));

    // Bind the texture to the rectangle
    //glBindTexture(GL_TEXTURE_2D, texture);

    return vao;
}


void CreateTexture(std::vector<std::string> image_path) {
    for (int image = 0; image < image_path.size(); image++) {
        // Generate a texture ID
        glGenTextures(1, &s_textures[image]);
        
        // Bind the texture ID
        glBindTexture(GL_TEXTURE_2D, s_textures[image]);

        // Set texture parameters
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // Load the image data
        int width, height, nrChannels;
        stbi_set_flip_vertically_on_load(true); // Flip image
        unsigned char* data = stbi_load(image_path[image].c_str(), &width, &height, &nrChannels, STBI_rgb_alpha); 
        
        if (data) {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
            glGenerateMipmap(GL_TEXTURE_2D);
        } else {
            std::cout << "Failed to load texture: " << image_path[image] << std::endl;
        }

        // Free the image data
        stbi_image_free(data);
    }
}

void helper_gl_bindTextures(GLuint vaos[], int size) {
    
    for (int i = 0; i < size && vaos[i] != 0; i++){
        glActiveTexture(GL_TEXTURE0 + i); // activate the texture unit first before binding texture
        glBindTexture(GL_TEXTURE_2D, s_textures[i]);
        glBindVertexArray(vaos[i]);
        std::cout << "image of vaos loaded " << i << std::endl;
        
    }
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

int main()
{
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(window);
    glewInit();

    // Compile and activate shaders
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexSource, nullptr);
    glCompileShader(vertexShader);
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentSource, nullptr);
    glCompileShader(fragmentShader);
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);



CreateTexture(g_image_paths);

for (int idx = 0 ; idx < g_image_paths.size(); idx++){
    vaos[idx] = setupImageRectangle(x_pos[idx], y_pox[idx], w_size[idx], h_wize[idx], shaderProgram, s_textures[idx]);
}
    while(!glfwWindowShouldClose(window))
    {
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Draw the texture on the screen
        helper_gl_bindTextures(vaos, sizeof(vaos) / sizeof(vaos[0]));
        
        // Swap buffers and poll window events
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // Cleanup and exit
    for (int idx = 0 ; idx < sizeof(s_textures); idx++){
        glDeleteTextures(1, &s_textures[idx]);
    }
    
    glfwTerminate();
    return 0;
}

Aucun commentaire:

Enregistrer un commentaire