Created
October 25, 2022 11:45
-
-
Save tuket/034101ef4132dad7005bbb5d6259ab1f to your computer and use it in GitHub Desktop.
OpenGL sRGB experiment
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 "utils.hpp" | |
#include <GLFW/glfw3.h> | |
constexpr int W = 800; | |
constexpr int H = 600; | |
GLFWwindow* window; | |
namespace shader_srcs | |
{ | |
ConstStr vertShad_constant = | |
R"GLSL( | |
layout(location = 0)in vec2 a_pos; | |
void main() | |
{ | |
gl_Position = vec4(a_pos, 0, 1); | |
} | |
)GLSL"; | |
ConstStr fragShad_constant = | |
R"GLSL( | |
layout(location = 0) out vec4 o_color; | |
void main() | |
{ | |
o_color = vec4(vec3(0.5), 1); | |
} | |
)GLSL"; | |
ConstStr vertShad_textured = | |
R"GLSL( | |
layout(location = 0)in vec2 a_pos; | |
layout(location = 1)in vec2 a_tc; | |
out vec2 v_tc; | |
void main() | |
{ | |
gl_Position = vec4(a_pos, 0, 1); | |
v_tc = a_tc; | |
} | |
)GLSL"; | |
ConstStr fragShad_textured = | |
R"GLSL( | |
layout(location = 0) out vec4 o_color; | |
in vec2 v_tc; | |
uniform sampler2D u_tex; | |
void main() | |
{ | |
o_color = vec4(texture(u_tex, v_tc).rgb, 1); | |
} | |
)GLSL"; | |
} | |
static void glfwErrorCallback(int error, const char* description) | |
{ | |
fprintf(stderr, "Glfw Error %d: %s\n", error, description); | |
} | |
int main() | |
{ | |
glfwSetErrorCallback(glfwErrorCallback); | |
if (!glfwInit()) | |
return 1; | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); | |
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); | |
window = glfwCreateWindow(W, H, "test", nullptr, nullptr); | |
if (window == nullptr) | |
return 1; | |
glfwMakeContextCurrent(window); | |
glfwSwapInterval(1); // Enable vsync | |
if (gladLoadGL() == 0) { | |
fprintf(stderr, "Failed to initialize OpenGL loader!\n"); | |
return 1; | |
} | |
glad_set_post_callback(glErrorCallback); | |
glfwSetWindowSizeCallback(window, [](GLFWwindow* window, int w, int h) {} ); | |
glfwSetMouseButtonCallback(window, [](GLFWwindow* window, int button, int action, int mods) {} ); | |
glfwSetCursorPosCallback(window, [](GLFWwindow* window, double x, double y) {} ); | |
glfwSetScrollCallback(window, [](GLFWwindow* window, double dx, double dy) {} ); | |
glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int scancode, int action, int mods) | |
{ | |
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) | |
glfwSetWindowShouldClose(window, true); | |
}); | |
glClearColor(0.5, 0.5, 0.5, 0); | |
u32 vbo_big; | |
u32 vao_big; | |
{ | |
glGenVertexArrays(1, &vao_big); | |
glBindVertexArray(vao_big); | |
glGenBuffers(1, &vbo_big); | |
struct Vert { vec2 pos;}; | |
const Vert verts[] = { | |
{{-0.8, -0.8}}, | |
{{+0.8, -0.8}}, | |
{{+0.8, +0.8}}, | |
{{-0.8, +0.8}}, | |
}; | |
glBindBuffer(GL_ARRAY_BUFFER, vbo_big); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); | |
glEnableVertexAttribArray(0); | |
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vert), nullptr); | |
} | |
u32 vbo_small; | |
u32 vao_small; | |
{ | |
glGenVertexArrays(1, &vao_small); | |
glBindVertexArray(vao_small); | |
glGenBuffers(1, &vbo_small); | |
struct Vert { vec2 pos; vec2 tc; }; | |
const Vert verts[] = { | |
{{-0.5, -0.5}, {0, 0}}, | |
{{+0.5, -0.5}, {1, 0}}, | |
{{+0.5, +0.5}, {1, 1}}, | |
{{-0.5, +0.5}, {0, 1}}, | |
}; | |
glBindBuffer(GL_ARRAY_BUFFER, vbo_small); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); | |
glEnableVertexAttribArray(0); | |
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vert), nullptr); | |
glEnableVertexAttribArray(1); | |
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vert), (void*)offsetof(Vert, tc)); | |
} | |
u32 tex; | |
glGenTextures(1, &tex); | |
glBindTexture(GL_TEXTURE_2D, tex); | |
const glm::u8vec3 pixelColor(127); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixelColor[0]); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
const u32 prog_constant = easyCreateShaderProg("shader0", shader_srcs::vertShad_constant, shader_srcs::fragShad_constant); | |
const u32 prog_textured = easyCreateShaderProg("shader1", shader_srcs::vertShad_textured, shader_srcs::fragShad_textured); | |
glUseProgram(prog_textured); | |
glUniform1i(glGetUniformLocation(prog_textured, "u_tex"), 0); | |
glViewport(0, 0, W, H); | |
glScissor(0, 0, W, H); | |
while (!glfwWindowShouldClose(window)) | |
{ | |
glfwPollEvents(); | |
// clear with 50% grey | |
glClear(GL_COLOR_BUFFER_BIT); | |
// uses hard-coded 50% grey in the shader | |
glUseProgram(prog_constant); | |
glBindVertexArray(vao_big); | |
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | |
// uses a sRGB texture with 50% (perceptual) grey | |
glUseProgram(prog_textured); | |
glBindVertexArray(vao_small); | |
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | |
glfwSwapBuffers(window); | |
} | |
} |
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 "utils.hpp" | |
#include <span> | |
char buffer[SCRATCH_BUFFER_SIZE]; | |
std::span<u8> bufferU8((u8*)buffer, SCRATCH_BUFFER_SIZE); | |
namespace shader_srcs | |
{ | |
ConstStr header = | |
R"GLSL( | |
#version 330 | |
#define PI 3.1415926535897932 | |
)GLSL"; | |
} | |
static const char* geGlErrStr(GLenum const err) | |
{ | |
switch (err) { | |
case GL_NO_ERROR: return "GL_NO_ERROR"; | |
case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; | |
case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; | |
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; | |
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; | |
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; | |
case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW"; | |
case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW"; | |
default: | |
assert(!"unknown error"); | |
return nullptr; | |
} | |
} | |
void glErrorCallback(const char* name, void* funcptr, int len_args, ...) { | |
GLenum error_code; | |
error_code = glad_glGetError(); | |
if (error_code != GL_NO_ERROR) { | |
fprintf(stderr, "ERROR %s in %s\n", geGlErrStr(error_code), name); | |
assert(false); | |
} | |
} | |
// --- shader utils --- | |
char* checkCompileErrors(u32 shad, std::span<char> buffer) | |
{ | |
i32 ok; | |
glGetShaderiv(shad, GL_COMPILE_STATUS, &ok); | |
if (!ok) { | |
GLsizei outSize; | |
glGetShaderInfoLog(shad, buffer.size(), &outSize, buffer.data()); | |
return buffer.data(); | |
} | |
return nullptr; | |
} | |
char* checkLinkErrors(u32 prog, std::span<char> buffer) | |
{ | |
GLint success; | |
glGetProgramiv(prog, GL_LINK_STATUS, &success); | |
if (!success) { | |
glGetProgramInfoLog(prog, buffer.size(), nullptr, buffer.data()); | |
return buffer.data(); | |
} | |
return nullptr; | |
} | |
static void printCodeWithLines(std::span<const char*> srcs) | |
{ | |
printf("%4d| ", 0); | |
int line = 1; | |
for (const char* s : srcs) | |
{ | |
int start = 0; | |
int end = 0; | |
while (s[end]) { | |
if (s[end] == '\n') { | |
printf("%.*s\n", end - start, s + start); | |
printf("%4d| ", line); | |
start = end = end + 1; | |
line++; | |
} | |
else | |
end++; | |
} | |
} | |
printf("\n"); | |
} | |
void printShaderCodeWithHeader(const char* src) | |
{ | |
const char* srcs[2] = { shader_srcs::header, src }; | |
printCodeWithLines(srcs); | |
} | |
u32 easyCreateShader(const char* name, const char* src, GLenum type) | |
{ | |
static ConstStr s_shaderTypeNames[] = { "VERT", "FRAG", "GEOM" }; | |
const char* typeName = nullptr; | |
switch (type) { | |
case GL_VERTEX_SHADER: | |
typeName = s_shaderTypeNames[0]; break; | |
case GL_FRAGMENT_SHADER: | |
typeName = s_shaderTypeNames[1]; break; | |
case GL_GEOMETRY_SHADER: | |
typeName = s_shaderTypeNames[2]; break; | |
default: | |
assert(false); | |
} | |
const u32 shad = glCreateShader(type); | |
ConstStr srcs[] = { shader_srcs::header, src }; | |
glShaderSource(shad, 2, srcs, nullptr); | |
glCompileShader(shad); | |
if (const char* errMsg = checkCompileErrors(shad, buffer)) { | |
printf("Error in '%s'(%s):\n%s", name, typeName, errMsg); | |
printShaderCodeWithHeader(src); | |
assert(false); | |
} | |
return shad; | |
} | |
u32 easyCreateShaderProg(const char* name, const char* vertShadSrc, const char* fragShadSrc, u32 vertShad, u32 fragShad) | |
{ | |
u32 prog = glCreateProgram(); | |
glAttachShader(prog, vertShad); | |
glAttachShader(prog, fragShad); | |
defer( | |
glDetachShader(prog, vertShad); | |
glDetachShader(prog, fragShad); | |
); | |
glLinkProgram(prog); | |
if (const char* errMsg = checkLinkErrors(prog, buffer)) { | |
printf("%s\n", errMsg); | |
printf("Vertex Shader:\n"); | |
printShaderCodeWithHeader(vertShadSrc); | |
printf("Fragment Shader:\n"); | |
printShaderCodeWithHeader(fragShadSrc); | |
assert(false); | |
} | |
return prog; | |
} | |
u32 easyCreateShaderProg(const char* name, const char* vertShadSrc, const char* fragShadSrc) | |
{ | |
const u32 vertShad = easyCreateShader(name, vertShadSrc, GL_VERTEX_SHADER); | |
const u32 fragShad = easyCreateShader(name, fragShadSrc, GL_FRAGMENT_SHADER); | |
const u32 prog = easyCreateShaderProg(name, vertShadSrc, fragShadSrc, vertShad, fragShad); | |
glDeleteShader(vertShad); | |
glDeleteShader(fragShad); | |
return prog; | |
} |
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
#pragma once | |
#include <stdio.h> | |
#include <assert.h> | |
#include <string.h> | |
#define GLAD_DEBUG | |
#include <glad/glad.h> | |
#include <glm/glm.hpp> | |
#include <span> | |
typedef uint8_t u8; | |
typedef int32_t i32; | |
typedef uint32_t u32; | |
using glm::vec2; | |
using glm::vec3; | |
using glm::vec4; | |
typedef const char* const ConstStr; | |
constexpr int SCRATCH_BUFFER_SIZE = 4 * 1024 * 1024; | |
extern char buffer[SCRATCH_BUFFER_SIZE]; | |
extern std::span<u8> bufferU8; | |
template <typename T> auto bufferSpan(size_t offset = 0) { return std::span<T>((T*)(buffer + offset), (SCRATCH_BUFFER_SIZE - offset) / sizeof(T)); } | |
typedef const char* const ConstStr; | |
void glErrorCallback(const char* name, void* funcptr, int len_args, ...); | |
char* checkCompileErrors(u32 shad, std::span<char> buffer); | |
char* checkLinkErrors(u32 prog, std::span<char> buffer); | |
void printShaderCodeWithHeader(const char* src); | |
u32 easyCreateShader(const char* name, const char* src, GLenum type); | |
u32 easyCreateShaderProg(const char* name, const char* vertShadSrc, const char* fragShadSrc); | |
u32 easyCreateShaderProg(const char* name, const char* vertShadSrc, const char* fragShadSrc, u32 vertShad, u32 fragShad); | |
// -- DEFER -- | |
template <typename F> | |
struct _Defer { | |
F f; | |
_Defer(F f) : f(f) {} | |
~_Defer() { f(); } | |
}; | |
template <typename F> | |
_Defer<F> _defer_func(F f) { | |
return _Defer<F>(f); | |
} | |
#define DEFER_1(x, y) x##y | |
#define DEFER_2(x, y) DEFER_1(x, y) | |
#define DEFER_3(x) DEFER_2(x, __COUNTER__) | |
#define defer(code) auto DEFER_3(_defer_) = _defer_func([&](){code;}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment