diff options
author | Lassi Pulkkinen <lassi@pulk.fi> | 2024-10-31 03:11:21 +0200 |
---|---|---|
committer | Lassi Pulkkinen <lassi@pulk.fi> | 2024-10-31 03:51:35 +0200 |
commit | ae44478b30d890fe0fb04022f44d474dcdcc3f9d (patch) | |
tree | 5f462459ae4b47d22114eed717d1382d08cf4dfe /shaders.ha |
Diffstat (limited to 'shaders.ha')
-rw-r--r-- | shaders.ha | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/shaders.ha b/shaders.ha new file mode 100644 index 0000000..624892b --- /dev/null +++ b/shaders.ha @@ -0,0 +1,183 @@ +use gl::*; +use glw; +use trace; + +let VAO_BLOCKS: uint = 0; +let SHADER_BLOCKS: uint = 0; + +let VAO_GUI: uint = 0; +let SHADER_GUI: uint = 0; + +fn shaders_init() void = { + trace::info(&trace::root, "loading shaders..."); + + glGenVertexArrays(1, &VAO_BLOCKS); + glBindVertexArray(VAO_BLOCKS); + glEnableVertexAttribArray(0); + glVertexAttribBinding(0, 0); + glVertexAttribFormat(0, 3, GL_UNSIGNED_SHORT, 0, + offset(Vertex { ... }.position): uint); + glEnableVertexAttribArray(1); + glVertexAttribBinding(1, 0); + glVertexAttribFormat(1, 3, GL_BYTE, 1, + offset(Vertex { ... }.normal): uint); + glEnableVertexAttribArray(2); + glVertexAttribBinding(2, 0); + glVertexAttribFormat(2, 2, GL_UNSIGNED_SHORT, 0, + offset(Vertex { ... }.texcoord): uint); + glEnableVertexAttribArray(3); + glVertexAttribBinding(3, 0); + glVertexAttribIFormat(3, 1, GL_UNSIGNED_BYTE, + offset(Vertex { ... }.flags): uint); + glBindVertexArray(0); + + SHADER_BLOCKS = glCreateProgram(); + glAttachShader(SHADER_BLOCKS, glw::compile_shader_src( + GL_VERTEX_SHADER, + "#version 310 es + + layout(location = 0) uniform mat4 u_transform; + layout(location = 1) uniform vec3 u_position; + layout(location = 2) uniform float u_texcoord_scale; + + layout(location = 0) in vec3 a_position; + layout(location = 1) in lowp vec3 a_normal; + layout(location = 2) in vec2 a_texcoord; + layout(location = 3) in lowp uint a_flags; + + const lowp uint U_EXCL = 1u << 0u; + const lowp uint V_EXCL = 1u << 1u; + // the smallest value such that 1.0 - EPSILON < 1.0 + const float EPSILON = 1.0 / float(1 << 24); + + out lowp vec3 v_normal; + out vec2 v_texcoord; + + void main() { + vec3 position = a_position * (1.0 / 2048.0) - 1.0 + u_position; + gl_Position = u_transform * vec4(position, 1.0); + v_normal = a_normal; + v_texcoord = u_texcoord_scale * a_texcoord; + // XXX: This fixes an issue with occassional texture + // bleeding at the scale of individual pixels on the + // bottom and right edges of a sprite, caused by the + // interpolated texture coordinate coming out as equal + // to the upper limit for that quad, which under + // GL_NEAREST filtering actually belongs to a texel on + // the wrong side of the sprite boundary. + // + // For whatever reason Mesa llvmpipe exhibits more + // severe rounding errors on all sprite edges, where + // v_texcoord in the fragment shader can be _below_ the + // supposed lower bound. An EPSILON of 2^-16 applied + // to all edges seems to be necessary in that case. + // I assume this to be a numerical compromise in favor + // of acceptable software rendering performance, but + // wasn't able to find a mention of it anywhere + // (I didn't look at the code, though), and the GL spec + // doesn't seem to explicitly permit it, though I well + // might be wrong about that. + // + // (2024 note): I am very tempted to remove all that and + // replace it with 'Removes Herobrine. Do not touch.'. + if ((a_flags & U_EXCL) != 0u) { + v_texcoord.x -= EPSILON; + } + if ((a_flags & V_EXCL) != 0u) { + v_texcoord.y -= EPSILON; + } + } + ", + )); + glAttachShader(SHADER_BLOCKS, glw::compile_shader_src( + GL_FRAGMENT_SHADER, + "#version 310 es + + precision mediump float; + + layout(location = 3) uniform mediump sampler2D tex_albedo; + + in lowp vec3 v_normal; + in highp vec2 v_texcoord; + + layout(location = 0) out vec4 f_color; + + void main() { + vec4 albedo = texture(tex_albedo, v_texcoord); + if (albedo.a < 0.1) { + discard; + } + float light = 0.7 + + dot(vec3(0, 0.2, 0), v_normal) + + abs(dot(vec3(0.1, 0, 0), v_normal)); + f_color = vec4(light * albedo.rgb, albedo.a); + } + ", + )); + glw::link_program(SHADER_BLOCKS); + glUseProgram(SHADER_BLOCKS); + glUniform1f(2, 1.0 / ATLAS_BLOCKS.width: f32); + glUniform1i(3, 0); + + glGenVertexArrays(1, &VAO_GUI); + glBindVertexArray(VAO_GUI); + glEnableVertexAttribArray(0); + glVertexAttribBinding(0, 0); + glVertexAttribFormat(0, 2, GL_FLOAT, 0, + offset(GuiVertex { ... }.position): uint); + glEnableVertexAttribArray(1); + glVertexAttribBinding(1, 0); + glVertexAttribFormat(1, 2, GL_FLOAT, 0, + offset(GuiVertex { ... }.texcoord): uint); + glEnableVertexAttribArray(2); + glVertexAttribBinding(2, 0); + glVertexAttribFormat(2, 3, GL_UNSIGNED_BYTE, 1, + offset(GuiVertex { ... }.color): uint); + glBindVertexArray(0); + + SHADER_GUI = glCreateProgram(); + glAttachShader(SHADER_GUI, glw::compile_shader_src( + GL_VERTEX_SHADER, + "#version 310 es + + layout(location = 0) uniform mat4 u_transform; + + layout(location = 0) in vec2 a_position; + layout(location = 1) in vec2 a_texcoord; + layout(location = 2) in vec4 a_color; + + out vec2 v_texcoord; + out vec4 v_color; + + void main() { + gl_Position = u_transform * vec4(a_position, 0.0, 1.0); + v_texcoord = a_texcoord; + // XXX: crude srgb for now... + v_color = vec4(pow(a_color.rgb, vec3(2.2)), a_color.a); + } + ", + )); + glAttachShader(SHADER_GUI, glw::compile_shader_src( + GL_FRAGMENT_SHADER, + "#version 310 es + + precision mediump float; + + layout(location = 1) uniform sampler2D tex_color; + + in vec2 v_texcoord; + in vec4 v_color; + + layout(location = 0) out vec4 f_color; + + void main() { + f_color = v_color * texture(tex_color, v_texcoord); + } + ", + )); + glw::link_program(SHADER_GUI); + glUseProgram(SHADER_GUI); + glUniform1i(1, 0); + + glUseProgram(0); +}; |