Skip to content

Instantly share code, notes, and snippets.

@Twinklebear
Last active August 29, 2015 14:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Twinklebear/11025713 to your computer and use it in GitHub Desktop.
Save Twinklebear/11025713 to your computer and use it in GitHub Desktop.
Instanced textured quads, produces this render: https://i.imgur.com/opgHu0x.png
#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);
}
#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;
}
#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";
}
#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
#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