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); };