summaryrefslogtreecommitdiff
path: root/shaders.ha
diff options
context:
space:
mode:
authorLassi Pulkkinen <lassi@pulk.fi>2024-10-31 03:11:21 +0200
committerLassi Pulkkinen <lassi@pulk.fi>2024-10-31 03:51:35 +0200
commitae44478b30d890fe0fb04022f44d474dcdcc3f9d (patch)
tree5f462459ae4b47d22114eed717d1382d08cf4dfe /shaders.ha
Initial commit (import old repo)HEADmain
Diffstat (limited to 'shaders.ha')
-rw-r--r--shaders.ha183
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);
+};