#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;
static void RenderScene() {
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// void glDrawArrays(GLenum mode, GLint first, GLsizei count);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glutSwapBuffers();
}
static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType) {
GLuint ShaderObj = glCreateShader(ShaderType);
if (ShaderObj == 0) {
fprintf(stderr, "Error creating shader type %d\n", ShaderType);
exit(0);
}
const GLchar* p[1];
p[0] = pShaderText;
GLint len[1];
len[0] = (GLint)strlen(pShaderText);
glShaderSource(ShaderObj, 1, p, len);
glCompileShader(ShaderObj);
GLint success;
glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success);
if (!success) {
GLchar InfoLog[1024];
glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog);
fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog);
exit(1);
}
glAttachShader(ShaderProgram, ShaderObj);
}
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();
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);
if (!ReadFile(pFSFileName, fs)) {
exit(1);
};
AddShader(ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER);
GLint Success = 0;
GLchar ErrorLog[1024] = { 0 };
glLinkProgram(ShaderProgram);
glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success);
if (Success == 0) {
glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog);
exit(1);
}
glValidateProgram(ShaderProgram);
glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success);
if (!Success) {
glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog);
exit(1);
}
glUseProgram(ShaderProgram);
}
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);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
int width = 800;
int height = 600;
glutInitWindowSize(width, height);
int win = glutCreateWindow("freeglut - glutCreateWindow() - Draw Triangle with Shaders");
GLenum res = glewInit();
if (res != GLEW_OK) {
std::cout << glewGetErrorString(res);
return 1;
}
GLclampf Red = 0.0f, Green = 0.0f, Blue = 0.0f, Alpha = 0.0f;
glClearColor(Red, Green, Blue, Alpha);
CreateVertexBuffer();
CompileShaders();
glutDisplayFunc(RenderScene);
glutMainLoop();
return 0;
}
/*
run
*/// shader.vs
#version 460 core
layout (location = 0) in vec3 Position;
void main()
{
gl_Position = vec4(0.5 * Position.x, 0.5 * 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
}