How to draw a grow and shrink triangle using OpenGL with FreeGLUT, Shaders with uniform variable, and GLEW in C++

1 Answer

0 votes
#include <iostream> // For std::cerr, std::cout
#include <fstream>  // For std::ifstream
#include <string>   // For std::string
#include <cstring>  // For strlen
#include <sstream>  // For std::stringstream (used in ReadFile)
#include <GL/glew.h> 
#include <freeglut.h> 

struct Vec3 {
    float x, y, z;

    Vec3() {}

    Vec3(float _x, float _y, float _z) {
        x = _x;
        y = _y;
        z = _z;
    }
};

GLuint VBO;
GLint gScaleLocation;

static void RenderScene() { 
    glClear(GL_COLOR_BUFFER_BIT);

    static float Scale = 0.0f;
    static float Delta = 0.01f;

    Scale += Delta;
    if ((Scale >= 1.0f) || (Scale <= -1.0f)) { // max width of the screen
        Delta *= -1.0f;
    }

    glUniform1f(gScaleLocation, Scale); // glew

    glBindBuffer(GL_ARRAY_BUFFER, VBO); // glew

    glEnableVertexAttribArray(0); // glew

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); // glew

    // void glDrawArrays(GLenum mode, GLint first, GLsizei count);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glDisableVertexAttribArray(0); // glew

    glutPostRedisplay(); // freeglut

    glutSwapBuffers(); // freeglut
}

static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType) {
    GLuint ShaderObj = glCreateShader(ShaderType); // glew

    if (ShaderObj == 0) {
        fprintf(stderr, "Error creating shader type %d\n", ShaderType);
        exit(0);
    }

    const GLchar* p[1]; // glew
    p[0] = pShaderText;

    GLint len[1];
    len[0] = (GLint)strlen(pShaderText);

    glShaderSource(ShaderObj, 1, p, len); // glew

    glCompileShader(ShaderObj); // glew

    GLint success;
    glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success); // glew

    if (!success) {
        GLchar InfoLog[1024]; // glew
        glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog); // glew
        fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog);
        exit(1);
    }

    glAttachShader(ShaderProgram, ShaderObj); // glew
}

const char* pVSFileName = "shader.vs";
const char* pFSFileName = "shader.fs";

static bool ReadFile(const char* pFileName, std::string& outFile)
{
    std::ifstream f(pFileName); // Open the file

    bool rv = false;
    if (f.is_open()) {
        std::stringstream ss;
        ss << f.rdbuf(); // Read entire file buffer into stringstream
        outFile = ss.str(); // Convert stringstream to std::string
        rv = true;
    }
    else {
        std::cerr << "Error opening file: " << pFileName << std::endl;
    }

    return rv;
}

static void CompileShaders()
{
    GLuint ShaderProgram = glCreateProgram(); // glew

    if (ShaderProgram == 0) {
        fprintf(stderr, "Error creating shader program - glCreateProgram\n");
        exit(1);
    }

    std::string vs, fs;

    if (!ReadFile(pVSFileName, vs)) {
        exit(1);
    };

    AddShader(ShaderProgram, vs.c_str(), GL_VERTEX_SHADER); // glew

    if (!ReadFile(pFSFileName, fs)) {
        exit(1);
    };

    AddShader(ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER); // glew

    GLint Success = 0;
    GLchar ErrorLog[1024] = { 0 }; // glew

    glLinkProgram(ShaderProgram); // glew

    glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success); // glew
    if (Success == 0) {
        glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); // glew
        fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog);
        exit(1);
    }

    gScaleLocation = glGetUniformLocation(ShaderProgram, "guScale");
    if (gScaleLocation == -1) {
        printf("Error getting uniform location of 'guScale'\n");
        exit(1);
    }

    glValidateProgram(ShaderProgram); // glew
    glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success); // glew
    if (!Success) {
        glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); // glew
        fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog);
        exit(1);
    }

    glUseProgram(ShaderProgram); // glew
}

static void CreateVertexBuffer() {
    Vec3 Vertices[3];
    Vertices[0] = Vec3(-1.0f, -1.0f, 0.0f); // bottom left
    Vertices[1] = Vec3(0.0f, 1.0f, 0.0f);   // top
    Vertices[2] = Vec3(1.0f, -1.0f, 0.0f);  // bottom right

    glGenBuffers(1, &VBO); // glew
    glBindBuffer(GL_ARRAY_BUFFER, VBO); // glew
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW); // glew
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv); // freeglut
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); // freeglut

    int width = 800;
    int height = 600;
    glutInitWindowSize(width, height); // freeglut

    // freeglut
    int win = glutCreateWindow("freeglut - glutCreateWindow() - Draw Triangle with Shaders"); 
    
    GLenum res = glewInit(); // glew
    if (res != GLEW_OK) { // glew
        std::cout << glewGetErrorString(res); // glew
        return 1;
    }

    GLclampf Red = 0.0f, Green = 0.0f, Blue = 0.0f, Alpha = 0.0f;
    glClearColor(Red, Green, Blue, Alpha);

    CreateVertexBuffer();

    CompileShaders();

    glutDisplayFunc(RenderScene); // freeglut

    glutMainLoop(); // freeglut

    return 0;
}




/*
run



*/

 

// shader.vs
 
#version 460 core

layout (location = 0) in vec3 Position;

uniform float guScale;

void main()
{
    gl_Position = vec4(guScale * Position.x, guScale * Position.y, Position.z, 1.0);
}
 
// shader.fs
 
#version 460 core
 
out vec4 FragColor;
 
void main()
{
    FragColor = vec4(1.0, 0.0, 0.0, 0.0); // Red
}

 



answered Jul 1, 2025 by avibootz
edited Jul 1, 2025 by avibootz
...