Skip to content

Instantly share code, notes, and snippets.

@yuriks
Created August 22, 2015 02:06
Show Gist options
  • Select an option

  • Save yuriks/405f0e5e3a507c67e4d5 to your computer and use it in GitHub Desktop.

Select an option

Save yuriks/405f0e5e3a507c67e4d5 to your computer and use it in GitHub Desktop.
Stencil Test
#include <cstdint>
#include <cstdio>
#include <algorithm>
#include <memory>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include "gl_3_2_core.h"
static void checkGLError() {
GLenum err = glGetError();
const char* err_name = nullptr;
switch (err) {
case GL_NO_ERROR: return;
case GL_INVALID_ENUM: err_name = "GL_INVALID_ENUM"; break;
case GL_INVALID_VALUE: err_name = "GL_INVALID_VALUE"; break;
case GL_INVALID_OPERATION: err_name = "GL_INVALID_OPERATION"; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: err_name = "GL_INVALID_FRAMEBUFFER_OPERATION"; break;
case GL_OUT_OF_MEMORY: err_name = "GL_OUT_OF_MEMORY"; break;
default: err_name = "(unknown error)"; break;
}
fprintf(stderr, "OpenGL error: %s (0x%X)\n", err_name, err);
}
static GLuint compileShader(GLenum shader_type, const char* source) {
GLuint shader = glCreateShader(shader_type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
GLint shader_status = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_status);
if (shader_status == GL_FALSE) {
char shader_log_buffer[8 * 1024];
glGetShaderInfoLog(shader, sizeof(shader_log_buffer), nullptr, shader_log_buffer);
fprintf(stderr, "Shader compile failure:\n%s\n", shader_log_buffer);
}
return shader;
}
static void checkLinkStatus(GLuint program) {
GLint link_status = 0;
glGetProgramiv(program, GL_LINK_STATUS, &link_status);
if (link_status == GL_FALSE) {
char shader_log_buffer[8 * 1024];
glGetProgramInfoLog(program, sizeof(shader_log_buffer), nullptr, shader_log_buffer);
fprintf(stderr, "Shader link failure:\n%s\n", shader_log_buffer);
}
}
static uint8_t calculate_value(int x, int y) {
int val = x / 2;
val += (int)(std::sin((float)y * 0.05f) * 8.f);
return std::max(0, std::min(val, 255));
}
static void fill_colorbuffer(uint32_t* buf, int width, int height) {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
uint32_t val = calculate_value(x, y);
buf[y * width + x] = (val << 24) | (val << 16) | (val << 8) | (0xFF << 0);
}
}
}
static void fill_depthbuffer(uint32_t* buf, int width, int height) {
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
uint32_t val = calculate_value(x, y);
buf[y * width + x] = (0 << 8) | (val << 0);
}
}
}
struct Vertex_Pos2f {
float pos[2];
};
static const Vertex_Pos2f vertex_data[4] = {
{-0.5f, 0.5f},
{ 0.5f, 0.5f},
{-0.5f, -0.5f},
{ 0.5f, -0.5f},
};
static const char* vertex_shader_source = R"(
#version 140
in vec2 in_position;
void main() {
gl_Position = vec4(in_position, 0.0, 1.0);
}
)";
static const char* fragment_shader_source = R"(
#version 140
out vec4 out_color;
void main() {
out_color = vec4(1.0, 0.0, 0.0, 1.0);
}
)";
int main() {
const int kWindowWidth = 512;
const int kWindowHeight = 512;
GLFWwindow* window;
if (!glfwInit())
return 1;
glfwDefaultWindowHints();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_ALPHA_BITS, 0);
glfwWindowHint(GLFW_DEPTH_BITS, 0);
glfwWindowHint(GLFW_STENCIL_BITS, 0);
window = glfwCreateWindow(kWindowWidth, kWindowHeight, "Stencil Test", nullptr, nullptr);
if (window == nullptr)
return 1;
glfwMakeContextCurrent(window);
if (ogl_LoadFunctions() == ogl_LOAD_FAILED)
return 1;
// ------------ Textures ------------
auto image_buffer = std::make_unique<uint32_t[]>(kWindowWidth * kWindowHeight);
GLuint color_texture, depth_stencil_texture;
glGenTextures(1, &color_texture);
glGenTextures(1, &depth_stencil_texture);
glBindTexture(GL_TEXTURE_2D, color_texture);
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);
fill_colorbuffer(image_buffer.get(), kWindowWidth, kWindowHeight);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWindowWidth, kWindowHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, nullptr);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWindowWidth, kWindowHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, image_buffer.get());
glBindTexture(GL_TEXTURE_2D, depth_stencil_texture);
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);
fill_depthbuffer(image_buffer.get(), kWindowWidth, kWindowHeight);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, kWindowWidth, kWindowHeight, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWindowWidth, kWindowHeight, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, image_buffer.get());
checkGLError();
// ------------ Framebuffer ------------
GLuint render_fbo;
glGenFramebuffers(1, &render_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, render_fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth_stencil_texture, 0);
checkGLError();
// ------------ Vertex Array ------------
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vertex_vbo;
glGenBuffers(1, &vertex_vbo);
glBindBuffer(GL_ARRAY_BUFFER, vertex_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex_Pos2f), reinterpret_cast<void*>(offsetof(Vertex_Pos2f, pos)));
glEnableVertexAttribArray(0);
checkGLError();
// ------------ Shaders ------------
GLuint vertex_shader = compileShader(GL_VERTEX_SHADER, vertex_shader_source);
GLuint frag_shader = compileShader(GL_FRAGMENT_SHADER, fragment_shader_source);
GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, frag_shader);
glBindAttribLocation(shader_program, 0, "in_position");
glBindFragDataLocation(shader_program, 0, "out_color");
glLinkProgram(shader_program);
checkLinkStatus(shader_program);
glUseProgram(shader_program);
checkGLError();
// ------------ Pipeline State ------------
glViewport(0, 0, kWindowWidth, kWindowHeight);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_LESS, 0x80, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
checkGLError();
while (!glfwWindowShouldClose(window)) {
glBindFramebuffer(GL_FRAMEBUFFER, render_fbo);
GLenum draw_buffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, draw_buffers);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, render_fbo);
glBlitFramebuffer(0, 0, kWindowWidth, kWindowHeight, 0, 0, kWindowWidth, kWindowHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
checkGLError();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment