133 lines
3.9 KiB
Rust
133 lines
3.9 KiB
Rust
use glow::HasContext;
|
|
|
|
/// The [`Version`] of a `Program`.
|
|
pub struct Version {
|
|
vertex: String,
|
|
fragment: String,
|
|
}
|
|
|
|
impl Version {
|
|
pub fn new(gl: &glow::Context) -> Version {
|
|
let version = gl.version();
|
|
|
|
let (vertex, fragment) = match (
|
|
version.major,
|
|
version.minor,
|
|
version.is_embedded,
|
|
) {
|
|
// OpenGL 3.0+
|
|
(3, 0 | 1 | 2, false) => (
|
|
format!("#version 1{}0\n#extension GL_ARB_explicit_attrib_location : enable", version.minor + 3),
|
|
format!(
|
|
"#version 1{}0\n#extension GL_ARB_explicit_attrib_location : enable\n#define HIGHER_THAN_300 1",
|
|
version.minor + 3
|
|
),
|
|
),
|
|
// OpenGL 3.3+
|
|
(3 | 4, _, false) => (
|
|
format!("#version {}{}0\n#extension GL_ARB_explicit_attrib_location : enable", version.major, version.minor),
|
|
format!(
|
|
"#version {}{}0\n#extension GL_ARB_explicit_attrib_location : enable\n#define HIGHER_THAN_300 1",
|
|
version.major, version.minor
|
|
),
|
|
),
|
|
// OpenGL ES 3.0+
|
|
(3, _, true) => (
|
|
format!("#version 3{}0 es", version.minor),
|
|
format!(
|
|
"#version 3{}0 es\n#define HIGHER_THAN_300 1",
|
|
version.minor
|
|
),
|
|
),
|
|
// OpenGL ES 2.0+
|
|
(2, _, true) => (
|
|
String::from(
|
|
"#version 100\n#define in attribute\n#define out varying",
|
|
),
|
|
String::from("#version 100\n#define in varying"),
|
|
),
|
|
// OpenGL 2.1
|
|
(2, _, false) => (
|
|
String::from(
|
|
"#version 120\n#define in attribute\n#define out varying",
|
|
),
|
|
String::from("#version 120\n#define in varying"),
|
|
),
|
|
// OpenGL 1.1+
|
|
_ => panic!("Incompatible context version: {version:?}"),
|
|
};
|
|
|
|
log::info!("Shader directive: {}", vertex.lines().next().unwrap());
|
|
|
|
Version { vertex, fragment }
|
|
}
|
|
}
|
|
|
|
pub struct Shader(<glow::Context as HasContext>::Shader);
|
|
|
|
impl Shader {
|
|
fn compile(gl: &glow::Context, stage: u32, content: &str) -> Shader {
|
|
unsafe {
|
|
let shader = gl.create_shader(stage).expect("Cannot create shader");
|
|
|
|
gl.shader_source(shader, content);
|
|
gl.compile_shader(shader);
|
|
|
|
if !gl.get_shader_compile_status(shader) {
|
|
panic!("{}", gl.get_shader_info_log(shader));
|
|
}
|
|
|
|
Shader(shader)
|
|
}
|
|
}
|
|
|
|
/// Creates a vertex [`Shader`].
|
|
pub fn vertex(
|
|
gl: &glow::Context,
|
|
version: &Version,
|
|
content: &'static str,
|
|
) -> Self {
|
|
let content = format!("{}\n{}", version.vertex, content);
|
|
|
|
Shader::compile(gl, glow::VERTEX_SHADER, &content)
|
|
}
|
|
|
|
/// Creates a fragment [`Shader`].
|
|
pub fn fragment(
|
|
gl: &glow::Context,
|
|
version: &Version,
|
|
content: &'static str,
|
|
) -> Self {
|
|
let content = format!("{}\n{}", version.fragment, content);
|
|
|
|
Shader::compile(gl, glow::FRAGMENT_SHADER, &content)
|
|
}
|
|
}
|
|
|
|
pub unsafe fn create(
|
|
gl: &glow::Context,
|
|
shaders: &[Shader],
|
|
attributes: &[(u32, &str)],
|
|
) -> <glow::Context as HasContext>::Program {
|
|
let program = gl.create_program().expect("Cannot create program");
|
|
|
|
for shader in shaders {
|
|
gl.attach_shader(program, shader.0);
|
|
}
|
|
|
|
for (i, name) in attributes {
|
|
gl.bind_attrib_location(program, *i, name);
|
|
}
|
|
|
|
gl.link_program(program);
|
|
if !gl.get_program_link_status(program) {
|
|
panic!("{}", gl.get_program_info_log(program));
|
|
}
|
|
|
|
for shader in shaders {
|
|
gl.detach_shader(program, shader.0);
|
|
gl.delete_shader(shader.0);
|
|
}
|
|
|
|
program
|
|
}
|