Last active
August 29, 2015 14:00
-
-
Save Twinklebear/11025713 to your computer and use it in GitHub Desktop.
Instanced textured quads, produces this render: https://i.imgur.com/opgHu0x.png
This file contains hidden or 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
#version 330 core | |
//Sampler defaults to unit 0 which is where our texture is bound | |
uniform sampler2D tex; | |
in vec2 fuv; | |
out vec4 color; | |
void main(void){ | |
color = texture(tex, fuv); | |
} |
This file contains hidden or 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 <iostream> | |
#include <iomanip> | |
#include <SDL.h> | |
#include "gl_core_3_3.h" | |
#include "util.h" | |
int main(int argc, char **argv){ | |
if (SDL_Init(SDL_INIT_EVERYTHING) != 0){ | |
std::cout << "SDL_Init error: " << SDL_GetError() << "\n"; | |
return 1; | |
} | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | |
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); | |
SDL_Window *win = SDL_CreateWindow("Text Test", SDL_WINDOWPOS_CENTERED, | |
SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL); | |
SDL_GLContext context = SDL_GL_CreateContext(win); | |
if (ogl_LoadFunctions() == ogl_LOAD_FAILED){ | |
std::cout << "ogl load failed\n"; | |
SDL_GL_DeleteContext(context); | |
SDL_DestroyWindow(win); | |
SDL_Quit(); | |
return 1; | |
} | |
std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << "\n" | |
<< "OpenGL Vendor: " << glGetString(GL_VENDOR) << "\n" | |
<< "OpenGL Renderer: " << glGetString(GL_RENDERER) << "\n" | |
<< "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << "\n"; | |
glClearColor(0, 0, 0, 1); | |
glClearDepth(1.f); | |
glEnable(GL_DEPTH_TEST); | |
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); | |
glDebugMessageCallbackARB(util::gldebug_callback, NULL); | |
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); | |
GLint program = util::load_program({std::make_tuple(GL_VERTEX_SHADER, "../vertex.glsl"), | |
std::make_tuple(GL_FRAGMENT_SHADER, "../fragment.glsl")}); | |
if (program == -1){ | |
SDL_GL_DeleteContext(context); | |
SDL_DestroyWindow(win); | |
SDL_Quit(); | |
return 1; | |
} | |
glUseProgram(program); | |
const GLubyte img[] = { | |
255, 0, 0, 255, 0, 255, 0, 255, | |
0, 0, 255, 255, 255, 255, 0, 255 | |
}; | |
GLuint tex; | |
glGenTextures(1, &tex); | |
glBindTexture(GL_TEXTURE_2D, tex); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, img); | |
//No mip-maps & use nearest-neighbor filtering | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
GLuint vao, vbo; | |
glGenVertexArrays(1, &vao); | |
glBindVertexArray(vao); | |
glGenBuffers(1, &vbo); | |
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
const int instances = 10; | |
const int vars_per_instance = 3; | |
//Instance data is: { x, y, uv_idx } | |
GLint pos[instances * vars_per_instance] = { | |
0, 0, 0, | |
1, 0, 1, | |
2, 0, 2, | |
3, 0, 3, | |
0, 1, 1, | |
1, 1, 2, | |
2, 1, 3, | |
0, 2, 2, | |
63, 15, 0, | |
62, 15, 2 | |
}; | |
glBufferData(GL_ARRAY_BUFFER, vars_per_instance * instances * sizeof(GLint), pos, GL_STATIC_DRAW); | |
glEnableVertexAttribArray(0); | |
//Note: must use IPointer for integer types if you don't want them to be converted | |
glVertexAttribIPointer(0, 2, GL_INT, vars_per_instance * sizeof(GLint), 0); | |
glVertexAttribDivisor(0, 1); | |
glEnableVertexAttribArray(1); | |
glVertexAttribIPointer(1, 1, GL_INT, vars_per_instance * sizeof(GLint), (void*)(2 * sizeof(GLint))); | |
glVertexAttribDivisor(1, 1); | |
bool quit = false; | |
while (!quit){ | |
SDL_Event e; | |
while (SDL_PollEvent(&e)){ | |
if (e.type == SDL_QUIT || (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE)){ | |
quit = true; | |
break; | |
} | |
} | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, instances); | |
SDL_GL_SwapWindow(win); | |
} | |
glDeleteProgram(program); | |
glDeleteVertexArrays(1, &vao); | |
SDL_GL_DeleteContext(context); | |
SDL_DestroyWindow(win); | |
SDL_Quit(); | |
return 0; | |
} |
This file contains hidden or 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 <vector> | |
#include <array> | |
#include <map> | |
#include <iostream> | |
#include <iomanip> | |
#include <fstream> | |
#include <string> | |
#include <tuple> | |
#include <SDL.h> | |
#include "gl_core_3_3.h" | |
#include "util.h" | |
std::string util::read_file(const std::string &fName){ | |
std::ifstream file(fName); | |
if (!file.is_open()){ | |
std::cout << "Failed to open file: " << fName << std::endl; | |
return ""; | |
} | |
return std::string((std::istreambuf_iterator<char>(file)), | |
std::istreambuf_iterator<char>()); | |
} | |
GLint util::load_shader(GLenum type, const std::string &file){ | |
GLuint shader = glCreateShader(type); | |
std::string src = read_file(file); | |
const char *csrc = src.c_str(); | |
glShaderSource(shader, 1, &csrc, 0); | |
glCompileShader(shader); | |
GLint status; | |
glGetShaderiv(shader, GL_COMPILE_STATUS, &status); | |
if (status == GL_FALSE){ | |
std::cerr << "loadShader: "; | |
switch (type){ | |
case GL_VERTEX_SHADER: | |
std::cerr << "Vertex shader: "; | |
break; | |
case GL_FRAGMENT_SHADER: | |
std::cerr << "Fragment shader: "; | |
break; | |
case GL_GEOMETRY_SHADER: | |
std::cerr << "Geometry shader: "; | |
break; | |
default: | |
std::cerr << "Other shader type: "; | |
} | |
std::cerr << file << " failed to compile. Compilation log:\n"; | |
GLint len; | |
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); | |
char *log = new char[len]; | |
glGetShaderInfoLog(shader, len, 0, log); | |
std::cerr << log << "\n"; | |
delete[] log; | |
glDeleteShader(shader); | |
return -1; | |
} | |
return shader; | |
} | |
GLint util::load_program(const std::vector<std::tuple<GLenum, std::string>> &shaders){ | |
std::vector<GLuint> glshaders; | |
for (const std::tuple<GLenum, std::string> &s : shaders){ | |
GLint h = load_shader(std::get<0>(s), std::get<1>(s)); | |
if (h == -1){ | |
std::cerr << "loadProgram: A required shader failed to compile, aborting\n"; | |
for (GLuint g : glshaders){ | |
glDeleteShader(g); | |
} | |
return -1; | |
} | |
glshaders.push_back(h); | |
} | |
GLuint program = glCreateProgram(); | |
for (GLuint s : glshaders){ | |
glAttachShader(program, s); | |
} | |
glLinkProgram(program); | |
GLint status; | |
glGetProgramiv(program, GL_LINK_STATUS, &status); | |
if (status == GL_FALSE){ | |
std::cerr << "loadProgram: Program failed to link, log:\n"; | |
GLint len; | |
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len); | |
char *log = new char[len]; | |
glGetProgramInfoLog(program, len, 0, log); | |
std::cerr << log << "\n"; | |
delete[] log; | |
} | |
for (GLuint s : glshaders){ | |
glDetachShader(program, s); | |
glDeleteShader(s); | |
} | |
if (status == GL_FALSE){ | |
glDeleteProgram(program); | |
return -1; | |
} | |
return program; | |
} | |
bool util::log_glerror(const std::string &msg){ | |
GLenum err = glGetError(); | |
if (err != GL_NO_ERROR){ | |
std::cerr << "OpenGL Error: "; | |
switch (err){ | |
case GL_INVALID_ENUM: | |
std::cerr << "Invalid enum"; | |
break; | |
case GL_INVALID_VALUE: | |
std::cerr << "Invalid value"; | |
break; | |
case GL_INVALID_OPERATION: | |
std::cerr << "Invalid operation"; | |
break; | |
case GL_OUT_OF_MEMORY: | |
std::cerr << "Out of memory"; | |
break; | |
case GL_INVALID_FRAMEBUFFER_OPERATION: | |
std::cerr << "Invalid FrameBuffer operation"; | |
break; | |
default: | |
std::cerr << std::hex << err << std::dec; | |
} | |
std::cerr << " - " << msg << "\n"; | |
return true; | |
} | |
return false; | |
} | |
#if _MSC_VER | |
void APIENTRY util::gldebug_callback(GLenum src, GLenum type, GLuint id, GLenum severity, | |
GLsizei len, const GLchar *msg, const GLvoid *user) | |
#else | |
void util::gldebug_callback(GLenum src, GLenum type, GLuint id, GLenum severity, | |
GLsizei len, const GLchar *msg, const GLvoid *user) | |
#endif | |
{ | |
//Print a time stamp for the message | |
float sec = SDL_GetTicks() / 1000.f; | |
int min = static_cast<int>(sec / 60.f); | |
sec -= sec / 60.f; | |
std::cout << "[" << min << ":" | |
<< std::setprecision(3) << sec << "] OpenGL Debug -"; | |
switch (severity){ | |
case GL_DEBUG_SEVERITY_HIGH_ARB: | |
std::cout << " High severity"; | |
break; | |
case GL_DEBUG_SEVERITY_MEDIUM_ARB: | |
std::cout << " Medium severity"; | |
break; | |
case GL_DEBUG_SEVERITY_LOW_ARB: | |
std::cout << " Low severity"; | |
} | |
switch (src){ | |
case GL_DEBUG_SOURCE_API_ARB: | |
std::cout << " API"; | |
break; | |
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: | |
std::cout << " Window system"; | |
break; | |
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: | |
std::cout << " Shader compiler"; | |
break; | |
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: | |
std::cout << " Third party"; | |
break; | |
case GL_DEBUG_SOURCE_APPLICATION_ARB: | |
std::cout << " Application"; | |
break; | |
default: | |
std::cout << " Other"; | |
} | |
switch (type){ | |
case GL_DEBUG_TYPE_ERROR_ARB: | |
std::cout << " Error"; | |
break; | |
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: | |
std::cout << " Deprecated behavior"; | |
break; | |
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: | |
std::cout << " Undefined behavior"; | |
break; | |
case GL_DEBUG_TYPE_PORTABILITY_ARB: | |
std::cout << " Portability"; | |
break; | |
case GL_DEBUG_TYPE_PERFORMANCE_ARB: | |
std::cout << " Performance"; | |
break; | |
default: | |
std::cout << " Other"; | |
} | |
std::cout << ":\n\t" << msg << "\n"; | |
} |
This file contains hidden or 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
#ifndef UTIL_H | |
#define UTIL_H | |
#include <string> | |
#include <vector> | |
#include <tuple> | |
#include "gl_core_3_3.h" | |
namespace util { | |
/* | |
* Read the entire contents of a file into a string, if an error occurs | |
* the string will be empty | |
*/ | |
std::string read_file(const std::string &fName); | |
/* | |
* Load a GLSL shader from some file, returns -1 if loading failed | |
*/ | |
GLint load_shader(GLenum type, const std::string &file); | |
/* | |
* Build a shader program from the list of shaders passed | |
*/ | |
GLint load_program(const std::vector<std::tuple<GLenum, std::string>> &shaders); | |
/* | |
* Check for an OpenGL error and log it along with the message passed | |
* if an error occured. Will return true if an error occured & was logged | |
*/ | |
bool log_glerror(const std::string &msg); | |
/* | |
* A debug callback for the GL_ARB_debug_out extension | |
*/ | |
#ifdef _WIN32 | |
void APIENTRY gldebug_callback(GLenum src, GLenum type, GLuint id, GLenum severity, | |
GLsizei len, const GLchar *msg, const GLvoid *user); | |
#else | |
void gldebug_callback(GLenum src, GLenum type, GLuint id, GLenum severity, | |
GLsizei len, const GLchar *msg, const GLvoid *user); | |
#endif | |
} | |
#endif |
This file contains hidden or 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
#version 330 core | |
const vec2 uvs[16] = vec2[16]( | |
vec2(0, 0), vec2(0.5, 0), vec2(0, 0.5), vec2(0.5, 0.5), | |
vec2(0.5, 0), vec2(1, 0), vec2(0.5, 0.5), vec2(1, 0.5), | |
vec2(0, 0.5), vec2(0, 1), vec2(0.5, 0.5), vec2(0.5, 1), | |
vec2(0.5, 0.5), vec2(0.5, 1), vec2(1, 1), vec2(1, 0.5) | |
); | |
//vectors for the horiziontal/vertical directions to expand the quad in | |
const vec2 dirs[4] = vec2[4]( | |
vec2(0, 0), | |
vec2(0, -1), | |
vec2(1, 0), | |
vec2(1, -1) | |
); | |
const vec4 up = vec4(0, 1, 0, 0); | |
const vec4 right = vec4(1, 0, 0, 0); | |
const ivec2 dim = ivec2(64, 16); | |
const vec2 char_dim = vec2(2.f / dim.x, 2.f / dim.y); | |
layout(location = 0) in ivec2 pos; | |
layout(location = 1) in int tex_idx; | |
out vec2 fuv; | |
void main(void){ | |
fuv = uvs[4 * tex_idx + gl_VertexID]; | |
//Scale positions into NDC and flip y to put 0,0 at top-left | |
float x = pos.x * char_dim.x - 1; | |
float y = -1 * (pos.y * char_dim.y - 1); | |
vec4 p = vec4(x, y, 0, 1); | |
gl_Position = p + char_dim.x * right * dirs[gl_VertexID].x + char_dim.y * up * dirs[gl_VertexID].y; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment