Skip to content

Instantly share code, notes, and snippets.

@vittorioromeo
Last active December 29, 2015 22:29
Show Gist options
  • Save vittorioromeo/7736527 to your computer and use it in GitHub Desktop.
Save vittorioromeo/7736527 to your computer and use it in GitHub Desktop.
#include <thread>
#include <string>
#include <iostream>
#include <SSVUtils/SSVUtils.hpp>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
namespace ssvgl
{
class ShaderSource;
class Shader;
class Program;
using Attribute = GLint;
using Uniform = GLint;
constexpr std::size_t shaderLogBufferSize{512};
enum class DataType
{
Byte = GL_BYTE,
UnsignedByte = GL_UNSIGNED_BYTE,
Short = GL_SHORT,
UnsignedShort = GL_UNSIGNED_SHORT,
Int = GL_INT,
UnsignedInt = GL_UNSIGNED_INT,
Float = GL_FLOAT,
Double = GL_DOUBLE
};
enum class PrimitiveType
{
Triangles = GL_TRIANGLES,
Lines = GL_LINES,
Points = GL_POINTS,
};
enum class BufferType
{
StaticDraw = GL_STATIC_DRAW,
StaticRead = GL_STATIC_READ,
StaticCopy = GL_STATIC_COPY,
DynamicDraw = GL_DYNAMIC_DRAW,
DynamicRead = GL_DYNAMIC_READ,
DynamicCopy = GL_DYNAMIC_COPY,
StreamDraw = GL_STREAM_DRAW,
StreamRead = GL_STREAM_READ,
StreamCopy = GL_STREAM_COPY
};
enum class ShaderType
{
Vertex = GL_VERTEX_SHADER,
Fragment = GL_FRAGMENT_SHADER,
Geometry = GL_GEOMETRY_SHADER
};
class VertexBufferObject
{
friend class VertexArrayObject;
private:
GLuint glId;
inline void bind() const noexcept { glBindBuffer(GL_ARRAY_BUFFER, glId); }
inline void buffer() const noexcept { }
public:
template<typename... TArgs> inline VertexBufferObject(TArgs&&... mArgs) noexcept
{
glGenBuffers(1, &glId);
buffer(std::forward<TArgs>(mArgs)...);
}
inline ~VertexBufferObject() noexcept { glDeleteBuffers(1, &glId); }
template<typename T, std::size_t TS> inline void buffer(const T(&mArray)[TS]) const noexcept
{
bind();
glBufferData(GL_ARRAY_BUFFER, sizeof(mArray), mArray, GL_STATIC_DRAW);
}
};
class VertexArrayObject
{
private:
GLuint glId;
inline void bind() const noexcept { glBindVertexArray(glId); }
public:
inline VertexArrayObject() noexcept { glGenVertexArrays(1, &glId); }
inline ~VertexArrayObject() noexcept { glDeleteVertexArrays(1, &glId); }
inline void bindAttribute(const Attribute& mAttribute, const VertexBufferObject& mVBO, DataType mType,
std::size_t mSize, std::size_t mStride = 0, std::size_t mOffset = 0, bool mNormalized = GL_FALSE) const noexcept
{
bind(); mVBO.bind();
glEnableVertexAttribArray(mAttribute);
glVertexAttribPointer(mAttribute, mSize, GLenum(mType), mNormalized, mStride, reinterpret_cast<GLvoid*>(mOffset));
}
};
class ShaderSource
{
private:
std::string sourceStr;
const char* sourceData;
public:
inline ShaderSource(std::string mStr) : sourceStr{std::move(mStr)}, sourceData{sourceStr.c_str()} { }
inline const char** getSourceData() noexcept { return &sourceData; }
};
class Shader
{
friend class Program;
private:
const ShaderType type;
const GLuint glId;
public:
inline Shader(ShaderType mType) : type{mType}, glId{glCreateShader(GLenum(type))} { }
inline Shader(ShaderType mType, ShaderSource& mSource) : Shader{mType} { compile(mSource); }
inline ~Shader() noexcept { glDeleteShader(glId); }
inline void compile(ShaderSource& mSource)
{
glShaderSource(glId, 1, mSource.getSourceData(), nullptr);
glCompileShader(glId);
GLint status;
glGetShaderiv(glId, GL_COMPILE_STATUS, &status);
char logBuffer[shaderLogBufferSize];
glGetShaderInfoLog(glId, shaderLogBufferSize, nullptr, logBuffer);
std::string compilationLog = std::string{logBuffer};
if(!compilationLog.empty()) ssvu::lo("Shader compilation log") << compilationLog << std::endl;
}
};
class Program
{
private:
const GLuint glId{glCreateProgram()};
std::vector<Shader> attached;
public:
inline Program() = default;
inline Program(const Shader& mVertex)
{
assert(mVertex.type == ShaderType::Vertex);
attach(mVertex);
link(); use();
}
inline Program(const Shader& mVertex, const Shader& mFragment)
{
assert(mVertex.type == ShaderType::Vertex);
assert(mFragment.type == ShaderType::Fragment);
attach(mVertex); attach(mFragment);
link(); use();
}
inline Program(const Shader& mVertex, const Shader& mFragment, const Shader& mGeometry)
{
assert(mVertex.type == ShaderType::Vertex);
assert(mFragment.type == ShaderType::Fragment);
assert(mGeometry.type == ShaderType::Geometry);
attach(mVertex); attach(mFragment); attach(mGeometry);
link(); use();
}
inline ~Program() noexcept { glDeleteProgram(glId); }
inline void attach(const Shader& mShader) noexcept
{
glAttachShader(glId, mShader.glId);
attached.push_back(mShader);
}
inline void link() noexcept
{
glLinkProgram(glId);
for(const auto& s : attached) glDetachShader(glId, s.glId);
}
inline void use() noexcept
{ glUseProgram(glId); }
inline Attribute getAttribute(const std::string& mName) const noexcept
{
return glGetAttribLocation(glId, mName.c_str());
}
};
inline void errorCallback(int mError, const char* mDescription)
{
ssvu::lo("GLFW error #" + ssvu::toStr(mError)) << mDescription << std::endl;
}
namespace Internal
{
inline bool& getInitialized() noexcept { static bool initialized{false}; return initialized; }
inline bool isInitialized() noexcept { return Internal::getInitialized(); }
inline void deInitialize() noexcept
{
assert(isInitialized());
glfwTerminate();
Internal::getInitialized() = false;
}
}
inline void initialize() noexcept
{
assert(!Internal::isInitialized());
glfwSetErrorCallback(&errorCallback);
if(!glfwInit()) std::terminate();
glewExperimental = GL_TRUE;
Internal::getInitialized() = true;
std::atexit(&Internal::deInitialize);
}
class Window
{
private:
GLFWwindow* glfwWindow{nullptr};
std::size_t width{640}, height{480};
std::string title;
bool fullscreen{false};
public:
inline Window(std::size_t mWidth, std::size_t mHeight, std::string mTitle, bool mFullscreen)
: width{mWidth}, height{mHeight}, title{std::move(mTitle)}, fullscreen{mFullscreen}
{
assert(Internal::isInitialized());
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
glfwWindow = glfwCreateWindow(width, height, title.c_str(), fullscreen ? glfwGetPrimaryMonitor() : nullptr, nullptr);
if(!glfwWindow) { glfwTerminate(); std::terminate(); }
glfwMakeContextCurrent(glfwWindow);
assert(glfwGetCurrentContext() == glfwWindow);
glewInit();
}
inline ~Window() { glfwDestroyWindow(glfwWindow); }
inline GLFWwindow* getGLFWWindow() noexcept { return glfwWindow; }
inline void display() noexcept { glfwSwapBuffers(glfwWindow); }
inline void close() noexcept { glfwSetWindowShouldClose(glfwWindow, GL_TRUE); }
inline bool shouldClose() const noexcept { return glfwWindowShouldClose(glfwWindow); }
};
}
ssvgl::ShaderSource vertexShaderSource{R"(
#version 150
in vec2 inVSPosition;
in vec3 inVSColor;
out vec3 inFSColor;
void main()
{
inFSColor = inVSColor;
gl_Position = vec4(inVSPosition, 0.0, 1.0);
}
)"};
ssvgl::ShaderSource fragmentShaderSource{R"(
#version 150
in vec3 inFSColor;
out vec4 outFSColor;
void main()
{
outFSColor = vec4(1.0, 1.0, 1.0, 1.0);
}
)"};
int main()
{
ssvgl::initialize();
ssvgl::Window window{800, 600, "ssvgl tests", false};
ssvgl::Shader vertexShader{ssvgl::ShaderType::Vertex, vertexShaderSource};
ssvgl::Shader fragmentShader{ssvgl::ShaderType::Fragment, fragmentShaderSource};
ssvgl::Program program{vertexShader, fragmentShader};
GLfloat vertices[] = {
0.0f, 0.5f,
0.5f, -0.5f,
-0.5f, -0.5f
};
ssvgl::VertexBufferObject vbo{vertices};
/*GLuint ebo;
glGenBuffers(1, &ebo);
GLuint elements[]{
0, 1, 2,
2, 3, 0
};
!glfwWindowShouldClose(window)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);*/
ssvgl::VertexArrayObject vao;
vao.bindAttribute(program.getAttribute("inVSPosition"), vbo, ssvgl::DataType::Float, 2, 0, 0);
//vao.bindAttribute(program.getAttribute("inVSColor"), vbo, ssvgl::AttributeType::Float, 2, 5 * sizeof(GLfloat), 2 * sizeof(GLfloat));
// ssvgl::VertexAttribute{program, ssvgl::VertexAttributeType::Float, "inVSPosition", 2, 5 * sizeof(GLfloat), 0};
// ssvgl::VertexAttribute{program, ssvgl::VertexAttributeType::Float, "inVSColor", 3, 5 * sizeof(GLfloat), 2 * sizeof(GLfloat)};
while(!window.shouldClose())
{
glfwPollEvents();
if(glfwGetKey(window.getGLFWWindow(), GLFW_KEY_ESCAPE) == GLFW_PRESS) window.close();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
window.display();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment