Created
August 22, 2015 02:06
-
-
Save yuriks/405f0e5e3a507c67e4d5 to your computer and use it in GitHub Desktop.
Stencil Test
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 <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