#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;
}
};
struct Mat4
{
float m[4][4] = { 0.0f };
Mat4() {}
Mat4(float v00, float v01, float v02, float v03,
float v10, float v11, float v12, float v13,
float v20, float v21, float v22, float v23,
float v30, float v31, float v32, float v33)
{
m[0][0] = v00; m[0][1] = v01; m[0][2] = v02; m[0][3] = v03;
m[1][0] = v10; m[1][1] = v11; m[1][2] = v12; m[1][3] = v13;
m[2][0] = v20; m[2][1] = v21; m[2][2] = v22; m[2][3] = v23;
m[3][0] = v30; m[3][1] = v31; m[3][2] = v32; m[3][3] = v33;
}
};
GLuint VBO;
GLint gTranslationLocation;
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;
}
Mat4 Translation(1.0f, 0.0f, 0.0f, Scale * 0.5f, // x
0.0f, 1.0f, 0.0f, Scale, // y
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
//glUniform1f(gScaleLocation, Scale); // glew
glUniformMatrix4fv(gTranslationLocation, 1, GL_TRUE, &Translation.m[0][0]);
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);
}
gTranslationLocation = glGetUniformLocation(ShaderProgram, "guTranslation");
if (gTranslationLocation == -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(-0.5f, -0.5f, 0.0f); // bottom left
Vertices[1] = Vec3(0.0f, 1.0f, 0.0f); // top
Vertices[2] = Vec3(0.5f, -0.5f, 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
// vertex shader
#version 460 core
layout (location = 0) in vec3 Position;
uniform mat4 guTranslation;
void main()
{
gl_Position = guTranslation * vec4(Position, 1.0);
}
// shader.fs
// fragment shader
#version 460 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0, 0.0, 0.0, 0.0); // Red
}