public DepthClipShader()
        {
            ShaderBuilder vert = new ShaderBuilder(ShaderType.VertexShader, false);
            vert.AddUniform(ShaderVarType.Mat4, "vp_matrix");
            vert.AddUniform(ShaderVarType.Mat4, "transform");
            vert.AddAttribute(ShaderVarType.Vec3, "in_vertex");
            vert.Logic = @"
                void main(void)
                {
                    gl_Position = vp_matrix * (transform * vec4(in_vertex, 1.0));
                }
            ";

            ShaderBuilder frag = new ShaderBuilder(ShaderType.FragmentShader, false, vert);
            frag.Logic = @"
                void main(void)
                {
                    out_colour = vec4(0.0, 0.0, 0.0, 0.0);
                }
            ";

            VertexSource = vert.Generate(GL3);
            FragmentSource = frag.Generate(GL3);

            BeginMode = BeginMode.Triangles;

            Create();
        }
        public SkyShader()
        {
            ShaderBuilder vert = new ShaderBuilder(ShaderType.VertexShader, false);
            vert.AddUniform(ShaderVarType.Mat4, "vp_matrix");
            vert.AddAttribute(ShaderVarType.Vec3, "in_vertex");
            vert.AddVarying(ShaderVarType.Vec3, "var_texcoord");
            vert.Logic = @"
                void main(void)
                {
                    vec4 pos = vp_matrix * vec4(in_vertex, 0.0);
                    gl_Position = pos.xyww;
                    var_texcoord = in_vertex;
                }
            ";

            ShaderBuilder frag = new ShaderBuilder(ShaderType.FragmentShader, false, vert);
            frag.AddUniform(ShaderVarType.SamplerCube, "skybox");
            frag.Logic = @"
                void main(void)
                {
                    out_colour = textureCube(skybox, var_texcoord);
                    out_colour += (vec4(0.0, 0.0, 0.0, 1.0) - out_colour) * max(0.0, -var_texcoord.y);
                }
            ";

            VertexSource = vert.Generate(GL3);
            FragmentSource = frag.Generate(GL3);

            BeginMode = BeginMode.Quads;

            Create();
        }
        protected WaterEffectShader()
        {
            ShaderBuilder vert = new ShaderBuilder(ShaderType.VertexShader, true);
            vert.AddAttribute(ShaderVarType.Vec2, "in_position");
            vert.AddVarying(ShaderVarType.Vec2, "tex_pos");
            vert.AddUniform(ShaderVarType.Int, "resolution");
            vert.Logic = @"
                void main( void )
                {
                    tex_pos = in_position.xy * vec2(1.0, -1.0) / resolution;
                    gl_Position = in_position;
                }
            ";

            ShaderBuilder frag = new ShaderBuilder(ShaderType.FragmentShader, true, vert);
            OnAddShaderVariables(frag);
            OnAddShaderLogic(frag);

            VertexSource = vert.Generate(GL3);
            FragmentSource = frag.Generate(GL3);

            BeginMode = BeginMode.Quads;

            Create();
            SetScreenSize(Water.Resolution, Water.Resolution);
            _bounds = new float[] {
                0f, 0f,
                Water.Resolution, 0f,
                Water.Resolution, Water.Resolution,
                0f, Water.Resolution
            };
        }
        public ModelShader()
        {
            ShaderBuilder vert = new ShaderBuilder(ShaderType.VertexShader, false);
            vert.AddUniform(ShaderVarType.Mat4, "vp_matrix");
            vert.AddUniform(ShaderVarType.Mat4, "transform");
            vert.AddAttribute(ShaderVarType.Vec3, "in_vertex");
            vert.AddAttribute(ShaderVarType.Vec2, "in_textuv");
            vert.AddAttribute(ShaderVarType.Vec3, "in_normal");
            vert.AddVarying(ShaderVarType.Vec3, "var_normal");
            vert.AddVarying(ShaderVarType.Vec2, "var_textuv");
            vert.Logic = @"
                void main(void)
                {
                    var_normal = (transform * vec4(in_normal, 0.0)).xyz;
                    var_textuv = in_textuv;
                    gl_Position = vp_matrix * (transform * vec4(in_vertex, 1.0));
                }
            ";

            ShaderBuilder frag = new ShaderBuilder(ShaderType.FragmentShader, false, vert);
            frag.AddUniform(ShaderVarType.Vec4, "colour");
            frag.AddUniform(ShaderVarType.Sampler2D, "tex");
            frag.AddUniform(ShaderVarType.Vec3, "view_vector");
            frag.AddUniform(ShaderVarType.Vec3, "light_vector");
            frag.AddUniform(ShaderVarType.Float, "shinyness");
            frag.Logic = @"
                void main(void)
                {
                    out_colour = vec4(colour.rgb * texture2D(tex, var_textuv + vec2(0.5, 0.5)).rgb * (dot(-light_vector, var_normal) * 0.5 + 0.5), colour.a);
                    if (shinyness > 0.0) {
                        out_colour = vec4(out_colour.rgb + (vec3(1.0, 1.0, 1.0) - out_colour.rgb) * 0.5 * pow(max(0.0, dot(reflect(-light_vector, var_normal), view_vector)), shinyness), out_colour.a);
                    }
                }
            ";

            VertexSource = vert.Generate(GL3);
            FragmentSource = frag.Generate(GL3);

            BeginMode = BeginMode.Triangles;

            Create();
        }
        public WaterShader()
        {
            ShaderBuilder vert = new ShaderBuilder(ShaderType.VertexShader, false);
            vert.AddUniform(ShaderVarType.Mat4, "vp_matrix");
            vert.AddUniform(ShaderVarType.Vec3, "view_origin");
            vert.AddUniform(ShaderVarType.Vec3, "view_vector");
            vert.AddUniform(ShaderVarType.Sampler2D, "heightmap");
            vert.AddAttribute(ShaderVarType.Vec2, "in_vertex");
            vert.AddVarying(ShaderVarType.Float, "var_height");
            vert.AddVarying(ShaderVarType.Float, "var_scale");
            vert.AddVarying(ShaderVarType.Vec3, "var_position");
            vert.AddVarying(ShaderVarType.Vec2, "var_texpos");
            vert.Logic = @"
                void main(void)
                {
                    const float size = 512.0;

                    float rot = -atan(view_vector.z, view_vector.x);
                    mat2 rmat = mat2(cos(rot), -sin(rot), sin(rot), cos(rot));

                    var_scale = max(0.0, 2.0 - max(1.0, length(in_vertex * size) / 48.0));

                    vec2 offset = rmat * (in_vertex * size) + view_origin.xz;
                    var_texpos = offset / 128.0 + vec2(0.5, 0.5);
                    var_height = texture2D(heightmap, var_texpos).a * 2.0 * var_scale;

                    vec4 pos = vec4(offset.x, var_height - 1.0, offset.y, 1.0);

                    var_position = pos.xyz;
                    gl_Position = vp_matrix * pos;
                }
            ";

            ShaderBuilder frag = new ShaderBuilder(ShaderType.FragmentShader, false, vert);
            frag.AddUniform(ShaderVarType.Sampler2D, "heightmap");
            frag.AddUniform(ShaderVarType.Sampler2D, "ripplemap");
            frag.AddUniform(ShaderVarType.Sampler2D, "spraymap");
            frag.AddUniform(ShaderVarType.SamplerCube, "skybox");
            frag.AddUniform(ShaderVarType.Vec4, "colour");
            frag.AddUniform(ShaderVarType.Vec3, "view_origin");
            frag.AddUniform(ShaderVarType.Vec3, "light_vector");
            frag.Logic = @"
                void main(void)
                {
                    float l = textureOffset(heightmap, var_texpos, ivec2(-1,  0 )).a;
                    float t = textureOffset(heightmap, var_texpos, ivec2( 0, -1 )).a;
                    float r = textureOffset(heightmap, var_texpos, ivec2( 1,  0 )).a;
                    float b = textureOffset(heightmap, var_texpos, ivec2( 0,  1 )).a;

                    vec3 horz = normalize(vec3(0.0, (r - l) * 2.0 * var_scale, 1.0));
                    vec3 vert = normalize(vec3(1.0, (b - t) * 2.0 * var_scale, 0.0));
                    vec3 normal = cross(horz, vert);

                    vec3 cam_dir = normalize(var_position - view_origin);

                    vec3 reflected = normalize(reflect(cam_dir, normal));

                    out_colour = vec4(colour.rgb * max(0.0, dot(light_vector, normal)), colour.a);
                    out_colour += vec4((textureCube(skybox, reflected).rgb - out_colour.rgb) * 0.5, 0.0);

                    if (var_scale > 0.0) {
                        float ripple = texture2D(ripplemap, (var_texpos * 8.0) + normal.xz * 0.125).a;
                        float spray = texture2D(spraymap, var_texpos).a;
                        if (ripple * pow(spray, 2.0) > 0.75) {
                            out_colour += spray * 0.75 * (vec4(1.0, 1.0, 1.0, 1.0) - out_colour) * var_scale;
                        }
                    }
                }
            ";

            VertexSource = vert.Generate(GL3);
            FragmentSource = frag.Generate(GL3);

            BeginMode = BeginMode.Quads;

            Create();
        }