#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
}