Last active
August 5, 2016 08:20
-
-
Save MORTAL2000/08619877332ad2ac3f385feae82af6bb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <SFML/Graphics.hpp> | |
#include <GL/glew.h> | |
#include <iostream> | |
#include <cassert> | |
#include <stdexcept> | |
#include <cmath> | |
#define GLM_SWIZZLE | |
#include <glm/glm.hpp> | |
#include <glm/gtx/transform2.hpp> | |
#include <glm/gtc/type_ptr.hpp> | |
template<std::size_t ...> | |
struct add : std::integral_constant< std::size_t, 0 > {}; | |
template<std::size_t X, std::size_t ... Xs> | |
struct add<X, Xs...> : std::integral_constant< std::size_t, X + add<Xs...>::value > {}; | |
template <typename... Ts> | |
constexpr std::size_t size_of() { return add< sizeof(Ts)... >::value; } | |
struct Vertex | |
{ | |
glm::vec3 position; | |
glm::vec4 color; | |
glm::vec2 texCoord; | |
Vertex(const glm::vec3& pos = {}, const glm::vec4& color = {}, const glm::vec2& texCoord = {}) | |
: position(pos) | |
, color(color) | |
, texCoord(texCoord) | |
{} | |
friend std::ostream& operator << (std::ostream& out, const Vertex& v) | |
{ | |
out << '(' << v.position.x << ',' << v.position.y << ',' << v.position.z << ')'; | |
return out; | |
} | |
}; | |
#define glCheck(expr) do { expr; getError(__FILE__, __LINE__); } while (false) | |
void getError(const char* file, int line) | |
{ | |
GLenum error(glGetError()); | |
if (error != GL_NO_ERROR) | |
{ | |
std::string errorString; | |
switch (error) | |
{ | |
case GL_INVALID_OPERATION: errorString = "INVALID_OPERATION"; break; | |
case GL_INVALID_ENUM: errorString = "INVALID_ENUM"; break; | |
case GL_INVALID_VALUE: errorString = "INVALID_VALUE"; break; | |
case GL_OUT_OF_MEMORY: errorString = "OUT_OF_MEMORY"; break; | |
case GL_INVALID_FRAMEBUFFER_OPERATION: errorString = "INVALID_FRAMEBUFFER_OPERATION"; break; | |
} | |
throw std::runtime_error(std::string("GL_" + errorString + " - ").append(file) + ":" + std::to_string(line)); | |
error = glGetError(); | |
} | |
} | |
// shader sources | |
#define GLSL(src) "#version 440 core\n" #src | |
const GLchar* vert = GLSL | |
( | |
layout(location = 0) in vec3 position; | |
layout(location = 1) in vec4 color; | |
layout(location = 2) in vec2 texCoord; | |
uniform mat4 MVP; | |
out vec4 color0; | |
out vec2 texCoord0; | |
void main() | |
{ | |
gl_Position = MVP * vec4(position, 1.0); | |
texCoord0 = texCoord; | |
color0 = color; | |
} | |
); | |
const GLchar* frag = GLSL | |
( | |
const vec4 zeroVec4 = vec4(0); | |
in vec4 color0; | |
in vec2 texCoord0; | |
uniform sampler2D diffuse; | |
uniform vec4 color; | |
out vec4 finalColor; | |
void main() | |
{ | |
vec4 texelColor = texture(diffuse, texCoord0); | |
bool hasUniformColor = color != zeroVec4; | |
bool hasUniformDiffuse = texelColor.x != zeroVec4.x; | |
if (hasUniformDiffuse && hasUniformColor) | |
finalColor = texelColor * color0 * color; | |
else if (hasUniformDiffuse && !hasUniformColor) | |
finalColor = texelColor * color0; | |
else if (!hasUniformDiffuse && hasUniformColor) | |
finalColor = color0 * color; | |
else if (!hasUniformDiffuse && !hasUniformColor) | |
finalColor = color0; | |
} | |
); | |
void checkStatus(GLuint obj) | |
{ | |
GLint status = GL_FALSE; | |
if (glIsShader(obj)) glCheck(glGetShaderiv(obj, GL_COMPILE_STATUS, &status)); | |
if (glIsProgram(obj)) glCheck(glGetProgramiv(obj, GL_LINK_STATUS, &status)); | |
if (status == GL_TRUE) return; | |
glCheck(glDeleteShader(obj)); | |
obj = 0; | |
} | |
void attachShader(GLuint program, GLenum type, const GLchar* src) | |
{ | |
GLuint shader; | |
glCheck(shader = glCreateShader(type)); | |
glCheck(glShaderSource(shader, 1, &src, NULL)); | |
glCheck(glCompileShader(shader)); | |
checkStatus(shader); | |
glCheck(glAttachShader(program, shader)); | |
glCheck(glDeleteShader(shader)); | |
} | |
GLuint loadShader(const GLchar* vert, const GLchar* frag, const GLchar* geom = nullptr) | |
{ | |
GLuint progam; | |
glCheck(progam = glCreateProgram()); | |
if (vert) attachShader(progam, GL_VERTEX_SHADER, vert); | |
if (geom) attachShader(progam, GL_GEOMETRY_SHADER, geom); | |
if (frag) attachShader(progam, GL_FRAGMENT_SHADER, frag); | |
glCheck(glLinkProgram(progam)); | |
checkStatus(progam); | |
return progam; | |
} | |
void pollEvent(sf::Window& window) | |
{ | |
static bool toggle = false; | |
sf::Event event; | |
while (window.pollEvent(event)) | |
{ | |
if (event.type == sf::Event::Closed) | |
window.close(); | |
if (event.type == sf::Event::KeyPressed) { | |
if (event.key.code == sf::Keyboard::Escape) { | |
window.close(); | |
} | |
// for debug | |
else if (event.key.code == sf::Keyboard::D) { | |
toggle = !toggle; | |
if (toggle) glCheck(glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)); | |
else glCheck(glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)); | |
} | |
} | |
} | |
} | |
enum VAOs | |
{ | |
Triangles, | |
NumVAOs | |
}; | |
enum Buffers | |
{ | |
ArrayBuffer, | |
IndexBuffer, | |
NumBuffers | |
}; | |
void application() | |
{ | |
sf::ContextSettings settings; | |
settings.depthBits = 24; | |
settings.stencilBits = 8; | |
settings.antialiasingLevel = 4; | |
settings.majorVersion = 4; | |
settings.minorVersion = 4; | |
sf::Window window({ 800, 600 }, "opengl template", sf::Style::Close, settings); | |
glm::mat4 orthoProjection = glm::ortho(0.f, static_cast<float>(window.getSize().x), static_cast<float>(window.getSize().y), 0.f); | |
if (glewInit() != GLEW_OK) { | |
throw std::runtime_error("Failed to initialize GLEW\n"); | |
} | |
sf::Texture texture; | |
if (!texture.loadFromFile("test.png")) { | |
throw std::runtime_error("Unable to load texture"); | |
} | |
float left = 0; | |
float top = 0; | |
float right = left + 200; | |
float bottom = top + 200; | |
float x = 800.f / 2.f - right / 2.f; | |
float y = 600.f / 2.f - bottom / 2.f; | |
std::vector<Vertex> vertices = { | |
{ glm::vec3(x + left, y + top, 0), glm::vec4(1), glm::vec2(0, 0) }, | |
{ glm::vec3(x + left, y + bottom, 0), glm::vec4(1), glm::vec2(0, 1) }, | |
{ glm::vec3(x + right, y + top, 0), glm::vec4(1), glm::vec2(1, 0) }, | |
{ glm::vec3(x + right, y + bottom, 0), glm::vec4(1), glm::vec2(1, 1) }, | |
}; | |
std::vector<GLuint> indices = { 0, 1, 2, 2, 1, 3 }; | |
//std::vector<Vertex> vertices = { | |
// { glm::vec3(x + left, y + top, 0), glm::vec4(1), glm::vec2(0, 0) }, | |
// { glm::vec3(x + left, y + bottom, 0), glm::vec4(1), glm::vec2(0, 1) }, | |
// { glm::vec3(x + right, y + bottom, 0), glm::vec4(1), glm::vec2(1, 1) }, | |
// { glm::vec3(x + right, y + top, 0), glm::vec4(1), glm::vec2(1, 0) }, | |
//}; | |
//std::vector<GLuint> indices = { 0, 1, 3, 3, 1, 2 }; | |
window.setActive(); | |
std::vector<GLuint> VAOs(NumVAOs); | |
std::vector<GLuint> Buffers(NumBuffers); | |
glCheck(glGenVertexArrays(NumVAOs, VAOs.data())); | |
glCheck(glGenBuffers(NumBuffers, Buffers.data())); | |
glCheck(glBindVertexArray(VAOs[Triangles])); | |
glCheck(glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer])); | |
glCheck(glBufferData(GL_ARRAY_BUFFER, vertices.size() * size_of<Vertex>(), vertices.data(), GL_STATIC_DRAW)); | |
glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Buffers[IndexBuffer])); | |
glCheck(glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * size_of<GLuint>(), indices.data(), GL_STATIC_DRAW)); | |
GLuint program = loadShader(vert, frag); | |
GLint position; | |
glCheck(position = glGetAttribLocation(program, "position")); // NOTE: only if variable is used in shader source | |
glCheck(glEnableVertexAttribArray(position)); | |
glCheck(glVertexAttribPointer(position, size_of<glm::vec3>() / size_of<GLfloat>(), GL_FLOAT, GL_FALSE, size_of<Vertex>(), (GLvoid*)0)); | |
GLint color; | |
glCheck(color = glGetAttribLocation(program, "color")); | |
glCheck(glEnableVertexAttribArray(color)); | |
glCheck(glVertexAttribPointer(color, size_of<glm::vec4>() / size_of<GLfloat>(), GL_FLOAT, GL_FALSE, size_of<Vertex>(), (GLvoid*)size_of<glm::vec3>())); | |
GLint texCoord; | |
glCheck(texCoord = glGetAttribLocation(program, "texCoord")); | |
glCheck(glEnableVertexAttribArray(texCoord)); | |
glCheck(glVertexAttribPointer(texCoord, size_of<glm::vec2>() / size_of<GLfloat>(), GL_FLOAT, GL_FALSE, size_of<Vertex>(), (GLvoid*)size_of<glm::vec3, glm::vec4>())); | |
glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0)); | |
//glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); // NOTE: it is better never turns it off, might help with meshes | |
glCheck(glBindVertexArray(0)); | |
glCheck(glClearColor(0, 0, 1, 1)); | |
while (window.isOpen()) | |
{ | |
glCheck(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); | |
glCheck(glUseProgram(program)); | |
//glCheck(glUniform4f(glGetUniformLocation(program, "color"), 0, 1, 0, 1)); | |
glCheck(glUniform4fv(glGetUniformLocation(program, "color"),1, glm::value_ptr(glm::vec4(0,1,0,1)))); | |
//glCheck(glUniform1i(glGetUniformLocation(program, "diffuse"), texture.getNativeHandle())); | |
//glCheck(glActiveTexture(GL_TEXTURE0 + texture.getNativeHandle())); | |
//sf::Texture::bind(&texture); | |
glCheck(glBindTexture(GL_TEXTURE_2D, texture.getNativeHandle())); | |
//glCheck(glActiveTexture(GL_TEXTURE0)); | |
glCheck(glUniformMatrix4fv(glGetUniformLocation(program, "MVP"), 1, GL_FALSE, glm::value_ptr(orthoProjection))); | |
glCheck(glBindVertexArray(VAOs[Triangles])); | |
//glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Buffers[IndexBuffer])); | |
glCheck(glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0)); | |
//glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); | |
glCheck(glBindVertexArray(0)); | |
glCheck(glUseProgram(0)); | |
glCheck(glBindTexture(GL_TEXTURE_2D, 0)); | |
window.display(); | |
pollEvent(window); | |
} | |
// clean resources | |
glCheck(glDeleteBuffers(NumBuffers, Buffers.data())); | |
glCheck(glDeleteVertexArrays(NumVAOs, VAOs.data())); | |
GLint numShaders = 0; | |
glCheck(glGetProgramiv(program, GL_ATTACHED_SHADERS, &numShaders)); | |
std::vector<GLuint> shaders(numShaders); | |
glCheck(glGetAttachedShaders(program, numShaders, NULL, shaders.data())); | |
for (const auto& type : shaders) { | |
glCheck(glDetachShader(program, type)); | |
} | |
glCheck(glDeleteProgram(program)); | |
} | |
int main() | |
{ | |
try | |
{ | |
application(); | |
} | |
catch (std::runtime_error& e) | |
{ | |
std::cerr << "Exception: " << e.what() << std::endl; | |
std::cin.ignore(); | |
return 1; | |
} | |
//std::cin.ignore(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment