test.cpp
#include "SimpleGL/glad.c" #include#include #include "SimpleGL/Program.hpp" #include "SimpleGL/Camera.hpp" #include "SimpleGL/Buffer.hpp" #include "SimpleGL/Error.hpp" #include "SimpleGL/Sprite.hpp" using namespace glm; using namespace SimpleGL; using namespace std; void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow* window); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); bool isFirst; vec2 lastPos; float deltaTime; float lastTime; Camera camera; int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWmonitor* monitor = glfwGetPrimaryMonitor(); const GLFWvidmode* videomode = glfwGetVideoMode(monitor); int width = videomode->width; int height = videomode->height; GLFWwindow* window = glfwCreateWindow(width, height, "LearnOpenGL", monitor, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } lastTime = glfwGetTime(); isFirst = true; glEnable(GL_DEPTH_TEST); camera.m_projection.loadPerspective(120.0f, 1.0f, 0.1f, 100.0f); Sprite triangle = Sprite(vec3(0, 0, -1)); Program program; VertexBufferObject vbo1; VertexBufferObject vbo2; VertexArrayObject vao; ElementBufferObject ebo; bool success = program.loadProgramFromFile("shader/usual.vert", "shader/usual.frag"); string error = program.getError(); cout << (success ? "program no error" : error) << endl; GLfloat ver[] = { 0.0f, 0.5f, 0.0f,// 1.0, 0.0, 0.0, -0.5f, -0.5f, 0.0f,// 0.0, 1.0, 0.0, 0.5f, -0.5f, 0.0f,// 0.0, 0.0, 1.0 -100.0f, 0.0f, 0.0f, 100.0f, 0.0f, 0.0f, 0.0f, -100.0f, 0.0f, 0.0f, 100.0f, 0.0f, 0.0f, 0.0f, -100.0f, 0.0f, 0.0f, 100.0f }; GLfloat col[] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }; GLuint ind[] = { 0, 1, 2, }; vao.bindVertexArray(); GLuint v1 = vbo1.getBufferID(); GLuint v2 = vbo2.getBufferID(); GLuint v3 = ebo.getBufferID(); GLenum type = GL_ARRAY_BUFFER; glBindBuffer(type, v1); glBufferData(type, sizeof(ver), ver, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glBindBuffer(type, v2); glBufferData(type, sizeof(col), col, GL_STATIC_DRAW); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(1); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, v3); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ind), ind, GL_STATIC_DRAW); vao.bindVertexArray0(); vbo1.bindBuffer0(); ebo.bindBuffer0(); vbo1.deleteBuffer(); vbo2.deleteBuffer(); ebo.deleteBuffer(); while (!glfwWindowShouldClose(window)) { processInput(window); float nowTime = glfwGetTime(); deltaTime = nowTime - lastTime; lastTime = nowTime; glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); program.useProgram(); program.setUniform("u_projection", camera.m_projection.matrix); program.setUniform("u_view", camera.m_view.matrix); vao.bindVertexArray(); //glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, NULL); program.setUniform("u_model", triangle.matrix); glDrawArrays(GL_TRIANGLES, 0, 3); program.setUniform("u_model", glm::mat4(1.0f)); glDrawArrays(GL_LINES, 3, 6); vao.bindVertexArray0(); triangle.rotate(vec3(0, 1, 0)); glfwSwapBuffers(window); glfwPollEvents(); } program.deleteProgram(); vao.deleteVertexArray(); glfwTerminate(); return 0; } void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); else if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera.processMove(Camera::Direction::FORWARD, deltaTime); else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera.processMove(Camera::Direction::BACKWARD, deltaTime); else if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera.processMove(Camera::Direction::LEFT, deltaTime); else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera.processMove(Camera::Direction::RIGHT, deltaTime); else if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) camera.processMove(Camera::Direction::UP, deltaTime); else if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) camera.processMove(Camera::Direction::DOWN, deltaTime); } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); camera.m_projection.loadPerspective(120.0f, float(width) / float(height), 0.1f, 100.0f); } void mouse_callback(GLFWwindow* window, double xpos, double ypos) { vec2 nowPos = vec2(xpos, ypos); if (isFirst) { lastPos = nowPos; isFirst = false; } vec2 delta = nowPos - lastPos; lastPos = nowPos; camera.processRotate(-delta.x, delta.y); } void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { camera.processZoom(yoffset); }
Sprite.hpp
#ifndef __SIMPLEGL_SPRITE_HPP__ #define __SIMPLEGL_SPRITE_HPP__ #include#include #include namespace SimpleGL { class Sprite { public: glm::vec3 m_position; glm::vec3 m_rotate; glm::vec3 m_scale; glm::mat4 matrix; public: Sprite(glm::vec3 position = glm::vec3(0.0f), glm::vec3 rotate = glm::vec3(0.0f), glm::vec3 scale = glm::vec3(1.0f)) : m_position(position), m_rotate(rotate), m_scale(scale), matrix(glm::mat4(1.0f)) { generateMatrix(); } public: Sprite& setPosition(glm::vec3 position) { m_position = position; generateMatrix(); return *this; } Sprite& setRotate(glm::vec3 angle) { m_rotate = angle; generateMatrix(); return *this; } Sprite& setScale(glm::vec3 size) { m_scale = size; generateMatrix(); return *this; } Sprite& translate(glm::vec3 distance) { m_position += distance; generateMatrix(); return *this; } Sprite& rotate(glm::vec3 angle) { m_rotate += angle; generateMatrix(); return *this; } Sprite& scale(glm::vec3 size) { m_scale += size; generateMatrix(); return *this; } glm::mat4 generateMatrix() { matrix = glm::mat4(1.0f); matrix = glm::translate(matrix, m_position); matrix = glm::rotate(matrix, glm::radians(m_rotate.x), glm::vec3(1.0f, 0.0f, 0.0f)); matrix = glm::rotate(matrix, glm::radians(m_rotate.y), glm::vec3(0.0f, 1.0f, 0.0f)); matrix = glm::rotate(matrix, glm::radians(m_rotate.z), glm::vec3(0.0f, 0.0f, 1.0f)); matrix = glm::scale(matrix, m_scale); return matrix; } }; } #endif
Program.hpp
#ifndef __SIMPLEGL_SHADER_HPP__ #define __SIMPLEGL_SHADER_HPP__ #include#include #include #include #include #include #include #include "Error.hpp" #include "glad.c" namespace SimpleGL { class Program { private: GLuint m_programID; std::stringstream m_error; public: static std::string check(GLuint ID, GLenum type) { GLint success; std::string result = std::string(); if (type != GL_PROGRAM) { glGetShaderiv(ID, GL_COMPILE_STATUS, &success); if (!success) { GLchar* infoLog = NULL; GLint length; glGetShaderiv(ID, GL_INFO_LOG_LENGTH, &length); infoLog = new char[length]; glGetShaderInfoLog(ID, length, NULL, infoLog); result = std::string("Shader Error:n") + std::string(infoLog); delete[] infoLog; } } else { glGetProgramiv(ID, GL_LINK_STATUS, &success); if (!success) { GLchar* infoLog = NULL; GLint length; glGetProgramiv(ID, GL_INFO_LOG_LENGTH, &length); infoLog = new char[length]; glGetProgramInfoLog(ID, length, NULL, infoLog); result = std::string("Program Error:n") + std::string(infoLog); delete[] infoLog; } } return result; } static GLuint createShader(std::string source, GLenum type, std::stringstream* error_output = nullptr) { const GLchar* s = source.data(); GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &s, NULL); glCompileShader(shader); std::string error = check(shader, type); if (error_output != nullptr) { if (error.length() > 0) { *error_output << error << std::endl; } } if (error.length() > 0) { glDeleteShader(shader); return 0; } return shader; } static GLuint createProgram(std::string vSource, std::string fSource, std::string gSource, std::stringstream* error_output = nullptr) { GLuint vShader = createShader(vSource, GL_VERTEX_SHADER, error_output); GLuint fShader = createShader(fSource, GL_FRAGMENT_SHADER, error_output); GLuint gShader = 0; if (gSource.length() > 0) { gShader = createShader(gSource, GL_GEOMETRY_SHADER, error_output); } GLuint program = glCreateProgram(); glAttachShader(program, vShader); glAttachShader(program, fShader); if (gShader != 0) { glAttachShader(program, gShader); } glLinkProgram(program); std::string error = check(program, GL_PROGRAM); glDeleteShader(vShader); glDeleteShader(fShader); if (gShader != 0) { glDeleteShader(gShader); } if (error_output != nullptr) { if (error.length() > 0) { *error_output << error << std::endl; } } if (error.length() > 0) { glDeleteProgram(program); return 0; } return program; } static std::string loadStringFromStream(std::istream& is) { std::stringstream result; std::string temp; while (getline(is, temp)) { result << temp << std::endl; } return result.str(); } public: Program() { m_programID = 0; } Program(std::string vSource, std::string fSource, std::string gSource = "") { m_programID = createProgram(vSource, fSource, gSource, &m_error); } bool loadProgram(std::string vSource, std::string fSource, std::string gSource = "") { GLuint id = createProgram(vSource, fSource, gSource, &m_error); if (id == 0) { return false; } m_programID = id; return true; } bool loadProgramFromStream(std::istream& vStream, std::istream& fStream) { std::string vSource = loadStringFromStream(vStream); std::string fSource = loadStringFromStream(fStream); return loadProgram(vSource, fSource); } bool loadProgramFromStream(std::istream& vStream, std::istream& fStream, std::istream& gStream) { std::string vSource = loadStringFromStream(vStream); std::string fSource = loadStringFromStream(fStream); std::string gSource = loadStringFromStream(gStream); return loadProgram(vSource, fSource, gSource); } bool loadProgramFromFile(std::string vPath, std::string fPath) { std::ifstream vStream; std::ifstream fStream; bool result; try { vStream.open(vPath); fStream.open(fPath); if (!vStream.is_open()) { return false; } if (!fStream.is_open()) { return false; } result = loadProgramFromStream(vStream, fStream); vStream.close(); fStream.close(); } catch (std::ifstream::failure& e) { result = false; m_error << "File Error:n" << e.what() << std::endl; } return result; } bool loadProgramFromFile(std::string vPath, std::string fPath, std::string gPath) { std::ifstream vStream; std::ifstream fStream; std::ifstream gStream; bool result; try { vStream.open(vPath); fStream.open(fPath); gStream.open(gPath); if (!vStream.is_open()) { return false; } if (!fStream.is_open()) { return false; } if (!gStream.is_open()) { return false; } result = loadProgramFromStream(vStream, fStream, gStream); vStream.close(); fStream.close(); gStream.close(); } catch (std::ifstream::failure& e) { result = false; m_error << "File Error:n" << e.what() << std::endl; } return result; } bool compile() { clearError(); glLinkProgram(m_programID); std::string error = check(m_programID, GL_PROGRAM); if (error.length() > 0) { m_error << error << std::endl; return false; } return true; } Program& deleteProgram() { if (m_programID != 0) { glDeleteProgram(m_programID); } return *this; } Program& setProgramId(GLuint ID) { m_programID = ID; return *this; } GLuint getProgramId() { return m_programID; } Program& useProgram() { if (m_programID != 0) { glUseProgram(m_programID); } return *this; } std::string getError() { return m_error.str(); } Program& clearError() { m_error.str(""); return *this; } public: GLuint getUniformLocation(std::string name) { if (m_programID != 0) { return glGetUniformLocation(m_programID, name.data()); } return -1; } Program& setUniform(std::string name, glm::mat4 matrix, GLenum transpose = GL_FALSE) { if (m_programID != 0) { GLuint location = getUniformLocation(name); glUniformMatrix4fv(location, 1, transpose, glm::value_ptr(matrix)); } return *this; } }; //It just means existence,no idea to program it. //GL_COMPUTE_SHADER class ComputeProgram { private: GLuint m_programID; public: static std::string check(GLuint program) { return std::string(); } static GLuint create(std::string cSource) { return 0; } public: ComputeProgram() {} }; } #endif
Buffer.hpp
#ifndef __SIMPLEGL_BUFFER_HPP__
#define __SIMPLEGL_BUFFER_HPP__
#include "glad.c"
namespace SimpleGL
{
class BufferObject
{
private:
GLuint m_bufferObjectID;
GLenum m_type;
public:
static void bindBuffer0(GLenum type)
{
glBindBuffer(type, 0);
}
public:
BufferObject(GLenum type)
{
m_type = type;
genBuffer();
bindBuffer();
bindBuffer0();
}
~BufferObject()
{
deleteBuffer();
}
public:
BufferObject& setBufferID(GLuint id)
{
m_bufferObjectID = id;
return *this;
}
GLuint getBufferID()
{
return m_bufferObjectID;
}
const GLuint getBufferType()
{
return m_type;
}
public:
bool genBuffer()
{
deleteBuffer();
glGenBuffers(1, &m_bufferObjectID);
return (m_bufferObjectID != 0);
}
BufferObject& bindBuffer()
{
if (m_bufferObjectID != 0)
{
glBindBuffer(m_type, m_bufferObjectID);
}
return *this;
}
BufferObject& bindBuffer0()
{
bindBuffer0(m_type);
return *this;
}
BufferObject& deleteBuffer()
{
if (m_bufferObjectID != 0)
{
glDeleteBuffers(1, &m_bufferObjectID);
m_bufferObjectID = 0;
}
return *this;
}
};
class VertexBufferObject : public BufferObject
{
public:
VertexBufferObject() : BufferObject(GL_ARRAY_BUFFER) {}
};
class ElementBufferObject : public BufferObject
{
public:
ElementBufferObject() : BufferObject(GL_ELEMENT_ARRAY_BUFFER) {}
};
class VertexArrayObject
{
private:
GLuint m_VertexArrayObjectID;
public:
static void bindVertexArray0()
{
glBindVertexArray(0);
}
public:
VertexArrayObject()
{
genVertexArray();
bindVertexArray();
bindVertexArray0();
}
~VertexArrayObject()
{
deleteVertexArray();
}
public:
VertexArrayObject& setVertexArrayObjectID(GLuint id)
{
m_VertexArrayObjectID = id;
return *this;
}
GLuint getVertexArrayObjectID()
{
return m_VertexArrayObjectID;
}
public:
bool genVertexArray()
{
deleteVertexArray();
glGenVertexArrays(1, &m_VertexArrayObjectID);
return (m_VertexArrayObjectID != 0);
}
VertexArrayObject& bindVertexArray()
{
if (m_VertexArrayObjectID != 0)
{
glBindVertexArray(m_VertexArrayObjectID);
}
return *this;
}
VertexArrayObject& deleteVertexArray()
{
if (m_VertexArrayObjectID != 0)
{
glDeleteVertexArrays(1, &m_VertexArrayObjectID);
m_VertexArrayObjectID = 0;
}
return *this;
}
};
}
#endif
Error.hpp
#ifndef __SIMPLEGL_ERROR_HPP__ #define __SIMPLEGL_ERROR_HPP__ #include "glad.c" #includenamespace SimpleGL { class Error { public: static std::string parse(GLenum error) { std::string result; switch (error) { case GL_NO_ERROR: result = "GL_NO_ERROR"; break; case GL_INVALID_ENUM: result = "GL_INVALID_ENUM"; break; case GL_INVALID_VALUE: result = "GL_INVALID_VALUE"; break; case GL_INVALID_OPERATION: result = "GL_INVALID_OPERATION"; break; case GL_STACK_OVERFLOW: result = "GL_STACK_OVERFLOW"; break; case GL_STACK_UNDERFLOW: result = "GL_STACK_UNDERFLOW"; break; case GL_OUT_OF_MEMORY: result = "GL_OUT_OF_MEMORY"; break; case GL_INVALID_FRAMEBUFFER_OPERATION: result = "GL_INVALID_FRAMEBUFFER_OPERATION"; break; default: result = "Unknow"; break; } return result; } //https://learnopengl.com/In-Practice/Debugging static std::string describe(GLenum error) { std::string result; switch (error) { case GL_NO_ERROR: result = "No user error reported since the last call to glGetError."; break; case GL_INVALID_ENUM: result = "Set when an enumeration parameter is not legal."; break; case GL_INVALID_VALUE: result = "Set when a value parameter is not legal."; break; case GL_INVALID_OPERATION: result = "Set when the state for a command is not legal for its given parameters."; break; case GL_STACK_OVERFLOW: result = "Set when a stack pushing operation causes a stack overflow."; break; case GL_STACK_UNDERFLOW: result = "Set when a stack popping operation occurs while the stack is at its lowest point."; break; case GL_OUT_OF_MEMORY: result = "Set when a memory allocation operation cannot allocate (enough) memory."; break; case GL_INVALID_FRAMEBUFFER_OPERATION: result = "Set when reading or writing to a framebuffer that is not complete."; break; default: result = "Unknown enumeration."; break; } return result; } public: GLenum error; std::string value; std::string description; public: Error() { error = glGetError(); value = parse(error); description = describe(error); } Error& operator()() { error = glGetError(); value = parse(error); description = describe(error); return *this; } std::string toString() { std::stringstream sstr; sstr << "Error Number:" << error << std::endl << "Error String:" << value << std::endl << "Error Description:" << description << std::endl; return sstr.str(); } }; } #endif
Camera.hpp
#ifndef __SIMPLEGL_CAMERA_HPP__ #define __SIMPLEGL_CAMERA_HPP__ #include运行结果#include #include namespace SimpleGL { class Camera { public: enum Direction { FORWARD, BACKWARD, LEFT, RIGHT, UP, DOWN }; class View { public: glm::vec3 position; glm::vec3 front; glm::vec3 center; glm::vec3 up; glm::vec3 right; float yaw; float pitch; glm::mat4 matrix; public: View(glm::vec3 po = glm::vec3(0.0f), float y = 0, float pi = 0, glm::vec3 u = glm::vec3(0.0f, 1.0f, 0.0f)) { position = po; yaw = y; pitch = pi; up = u; update(); } public: View& update() { if (pitch > 89.9f) pitch = 89.9f; if (pitch < -89.9f) pitch = -89.9f; float h = glm::cos(glm::radians(pitch)); float x = glm::cos(glm::radians(yaw)) * h; float y = glm::sin(glm::radians(pitch)); float z = glm::sin(glm::radians(yaw)) * h; front = glm::normalize(glm::vec3(x, y, z)); center = position + front; right = glm::normalize(glm::cross(front, up)); return *this; } glm::mat4 generateMatrix() { matrix = glm::lookAt(position, center, up); return matrix; } }; class Projection { public: float fovy; float aspect; float near_plane; float far_plane; glm::mat4 matrix; public: Projection() : fovy(120.0f), aspect(1.0f), near_plane(0.1f), far_plane(100.0f), matrix(glm::mat4(1.0f)) {} Projection(float n, float f) : near_plane(n), far_plane(f), matrix(glm::mat4(1.0f)) {} glm::mat4 loadPerspective(float f, float a, float ne, float fa) { fovy = f; aspect = a; near_plane = ne; far_plane = fa; return loadPerspective(); } glm::mat4 loadPerspective() { matrix = glm::perspective(fovy, aspect, near_plane, far_plane); return matrix; }; }; public: View m_view; Projection m_projection; float m_sensitivity; float m_movement_speed; public: Camera(View view = View(), Projection projection = Projection()) : m_view(view), m_projection(projection), m_sensitivity(0.05f), m_movement_speed(1) {} Camera& processMove(Direction direction, float deltaTime) { float distance = m_movement_speed * deltaTime; if (direction == Direction::FORWARD) m_view.position += m_view.front * distance; else if (direction == Direction::BACKWARD) m_view.position += (-m_view.front) * distance; else if (direction == Direction::LEFT) m_view.position += (-m_view.right) * distance; else if (direction == Direction::RIGHT) m_view.position += m_view.right * distance; else if (direction == Direction::UP) m_view.position += m_view.up * distance; else if (direction == Direction::DOWN) m_view.position += (-m_view.up) * distance; m_view.update(); m_view.generateMatrix(); return *this; } Camera& processRotate(float dx, float dy) { m_view.yaw += dx * m_sensitivity; m_view.pitch += dy * m_sensitivity; m_view.update(); m_view.generateMatrix(); return *this; } Camera& processZoom(float offset) { m_projection.fovy += offset; if (m_projection.fovy < 1.0f) m_projection.fovy = 1.0f; else if (m_projection.fovy > 179.9f) m_projection.fovy = 179.9f; m_projection.loadPerspective(); return *this; } }; } #endif


![[C++] [OpenGL] 基于GLFW+GLAD的OpenGL简单程序 [C++] [OpenGL] 基于GLFW+GLAD的OpenGL简单程序](http://www.mshxw.com/aiimages/31/835452.png)
