mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-26 12:59:00 +00:00
Remove ShaderProvider
Instead, always use the previous AutoShaderProvider
This commit is contained in:
parent
e12e0b1bed
commit
82f1122e10
@ -53,54 +53,38 @@ impl<
|
|||||||
pub fn auto_renderer<G: Gl>(
|
pub fn auto_renderer<G: Gl>(
|
||||||
gl: G,
|
gl: G,
|
||||||
imgui_context: &mut imgui::Context,
|
imgui_context: &mut imgui::Context,
|
||||||
) -> Result<OwningRenderer<G, TrivialTextureMap, AutoShaderProvider<G>>, InitError> {
|
) -> Result<OwningRenderer<G, TrivialTextureMap>, InitError> {
|
||||||
RendererBuilder::new().build_owning(gl, imgui_context)
|
RendererBuilder::new().build_owning(gl, imgui_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RendererBuilder<G, T, S>
|
pub struct RendererBuilder<G, T>
|
||||||
where
|
where
|
||||||
G: Gl,
|
G: Gl,
|
||||||
T: TextureMap,
|
T: TextureMap,
|
||||||
S: ShaderProvider<G>,
|
|
||||||
{
|
{
|
||||||
texture_map: T,
|
texture_map: T,
|
||||||
shader_provider: S,
|
|
||||||
phantom_gl: PhantomData<G>,
|
phantom_gl: PhantomData<G>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Gl> RendererBuilder<G, TrivialTextureMap, AutoShaderProvider<G>> {
|
impl<G: Gl> RendererBuilder<G, TrivialTextureMap> {
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
texture_map: TrivialTextureMap(),
|
texture_map: TrivialTextureMap(),
|
||||||
shader_provider: <AutoShaderProvider<G> as Default>::default(),
|
|
||||||
phantom_gl: PhantomData::default(),
|
phantom_gl: PhantomData::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G, T, S> RendererBuilder<G, T, S>
|
impl<G, T> RendererBuilder<G, T>
|
||||||
where
|
where
|
||||||
G: Gl,
|
G: Gl,
|
||||||
T: TextureMap,
|
T: TextureMap,
|
||||||
S: ShaderProvider<G>,
|
|
||||||
{
|
{
|
||||||
pub fn with_texture_map<T2: TextureMap>(self, texture_map: T2) -> RendererBuilder<G, T2, S> {
|
pub fn with_texture_map<T2: TextureMap>(self, texture_map: T2) -> RendererBuilder<G, T2> {
|
||||||
RendererBuilder {
|
RendererBuilder {
|
||||||
texture_map,
|
texture_map,
|
||||||
shader_provider: self.shader_provider,
|
|
||||||
phantom_gl: self.phantom_gl,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_shader_provider<S2: ShaderProvider<G>>(
|
|
||||||
self,
|
|
||||||
shader_provider: S2,
|
|
||||||
) -> RendererBuilder<G, T, S2> {
|
|
||||||
RendererBuilder {
|
|
||||||
texture_map: self.texture_map,
|
|
||||||
shader_provider,
|
|
||||||
phantom_gl: self.phantom_gl,
|
phantom_gl: self.phantom_gl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,9 +99,9 @@ where
|
|||||||
self,
|
self,
|
||||||
gl: G,
|
gl: G,
|
||||||
imgui_context: &mut imgui::Context,
|
imgui_context: &mut imgui::Context,
|
||||||
) -> Result<OwningRenderer<G, T, S>, InitError> {
|
) -> Result<OwningRenderer<G, T>, InitError> {
|
||||||
let renderer = self.build_borrowing(&gl, imgui_context)?;
|
let renderer = self.build_borrowing(&gl, imgui_context)?;
|
||||||
Ok(OwningRenderer::<G, T, S> { gl, renderer })
|
Ok(OwningRenderer::<G, T> { gl, renderer })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a renderer which needs to borrow a context in order to render.
|
/// Build a renderer which needs to borrow a context in order to render.
|
||||||
@ -129,8 +113,8 @@ where
|
|||||||
self,
|
self,
|
||||||
gl: &G,
|
gl: &G,
|
||||||
imgui_context: &mut imgui::Context,
|
imgui_context: &mut imgui::Context,
|
||||||
) -> Result<Renderer<G, T, S>, InitError> {
|
) -> Result<Renderer<G, T>, InitError> {
|
||||||
Renderer::<G, T, S>::initialize(gl, imgui_context, self.texture_map, self.shader_provider)
|
Renderer::<G, T>::initialize(gl, imgui_context, self.texture_map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,21 +124,19 @@ where
|
|||||||
///
|
///
|
||||||
/// OpenGL context is still available to the rest of the application through
|
/// OpenGL context is still available to the rest of the application through
|
||||||
/// the `[gl_context]` method.
|
/// the `[gl_context]` method.
|
||||||
pub struct OwningRenderer<G, T = TrivialTextureMap, S = AutoShaderProvider<G>>
|
pub struct OwningRenderer<G, T = TrivialTextureMap>
|
||||||
where
|
where
|
||||||
G: Gl,
|
G: Gl,
|
||||||
T: TextureMap,
|
T: TextureMap,
|
||||||
S: ShaderProvider<G>,
|
|
||||||
{
|
{
|
||||||
gl: G,
|
gl: G,
|
||||||
renderer: Renderer<G, T, S>,
|
renderer: Renderer<G, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G, T, S> OwningRenderer<G, T, S>
|
impl<G, T> OwningRenderer<G, T>
|
||||||
where
|
where
|
||||||
G: Gl,
|
G: Gl,
|
||||||
T: TextureMap,
|
T: TextureMap,
|
||||||
S: ShaderProvider<G>,
|
|
||||||
{
|
{
|
||||||
/// Note: no need to provide a `mut` version of this, as all methods on
|
/// Note: no need to provide a `mut` version of this, as all methods on
|
||||||
/// `[glow::HasContext]` are immutable.
|
/// `[glow::HasContext]` are immutable.
|
||||||
@ -164,7 +146,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn renderer(&self) -> &Renderer<G, T, S> {
|
pub fn renderer(&self) -> &Renderer<G, T> {
|
||||||
&self.renderer
|
&self.renderer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,25 +159,23 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G, T, S> Drop for OwningRenderer<G, T, S>
|
impl<G, T> Drop for OwningRenderer<G, T>
|
||||||
where
|
where
|
||||||
G: Gl,
|
G: Gl,
|
||||||
T: TextureMap,
|
T: TextureMap,
|
||||||
S: ShaderProvider<G>,
|
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.renderer.destroy(&self.gl);
|
self.renderer.destroy(&self.gl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Renderer<G, T = TrivialTextureMap, S = AutoShaderProvider<G>>
|
pub struct Renderer<G, T = TrivialTextureMap>
|
||||||
where
|
where
|
||||||
G: Gl,
|
G: Gl,
|
||||||
T: TextureMap,
|
T: TextureMap,
|
||||||
S: ShaderProvider<G>,
|
|
||||||
{
|
{
|
||||||
pub texture_map: T,
|
pub texture_map: T,
|
||||||
pub shader_provider: S,
|
shaders: Shaders<G>,
|
||||||
state_backup: GlStateBackup,
|
state_backup: GlStateBackup,
|
||||||
pub vbo_handle: G::Buffer,
|
pub vbo_handle: G::Buffer,
|
||||||
pub ebo_handle: G::Buffer,
|
pub ebo_handle: G::Buffer,
|
||||||
@ -207,11 +187,10 @@ where
|
|||||||
pub is_destroyed: bool,
|
pub is_destroyed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G, T, S> Renderer<G, T, S>
|
impl<G, T> Renderer<G, T>
|
||||||
where
|
where
|
||||||
G: Gl,
|
G: Gl,
|
||||||
T: TextureMap,
|
T: TextureMap,
|
||||||
S: ShaderProvider<G>,
|
|
||||||
{
|
{
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// Any error initialising the OpenGL objects (including shaders) will
|
/// Any error initialising the OpenGL objects (including shaders) will
|
||||||
@ -220,7 +199,6 @@ where
|
|||||||
gl: &G,
|
gl: &G,
|
||||||
imgui_context: &mut imgui::Context,
|
imgui_context: &mut imgui::Context,
|
||||||
mut texture_map: T,
|
mut texture_map: T,
|
||||||
shader_provider: S,
|
|
||||||
) -> Result<Self, InitError> {
|
) -> Result<Self, InitError> {
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::similar_names,
|
clippy::similar_names,
|
||||||
@ -256,8 +234,7 @@ where
|
|||||||
|
|
||||||
let font_atlas_texture = prepare_font_atlas(gl, imgui_context.fonts(), &mut texture_map)?;
|
let font_atlas_texture = prepare_font_atlas(gl, imgui_context.fonts(), &mut texture_map)?;
|
||||||
|
|
||||||
let mut shader_provider = shader_provider;
|
let shaders = Shaders::new(gl, gl_version)?;
|
||||||
shader_provider.initialize(gl, gl_version)?;
|
|
||||||
let vbo_handle = unsafe { gl.create_buffer() }.map_err(InitError::CreateBufferObject)?;
|
let vbo_handle = unsafe { gl.create_buffer() }.map_err(InitError::CreateBufferObject)?;
|
||||||
let ebo_handle = unsafe { gl.create_buffer() }.map_err(InitError::CreateBufferObject)?;
|
let ebo_handle = unsafe { gl.create_buffer() }.map_err(InitError::CreateBufferObject)?;
|
||||||
|
|
||||||
@ -265,7 +242,7 @@ where
|
|||||||
|
|
||||||
let out = Self {
|
let out = Self {
|
||||||
texture_map,
|
texture_map,
|
||||||
shader_provider,
|
shaders,
|
||||||
state_backup,
|
state_backup,
|
||||||
vbo_handle,
|
vbo_handle,
|
||||||
ebo_handle,
|
ebo_handle,
|
||||||
@ -297,7 +274,7 @@ where
|
|||||||
unsafe { gl.delete_buffer(self.ebo_handle) };
|
unsafe { gl.delete_buffer(self.ebo_handle) };
|
||||||
self.ebo_handle = 0;
|
self.ebo_handle = 0;
|
||||||
}
|
}
|
||||||
let program = self.shader_provider.data().program;
|
let program = self.shaders.program;
|
||||||
if program != 0 {
|
if program != 0 {
|
||||||
unsafe { gl.delete_program(program) };
|
unsafe { gl.delete_program(program) };
|
||||||
}
|
}
|
||||||
@ -424,13 +401,12 @@ where
|
|||||||
let clip_origin_is_lower_left = true;
|
let clip_origin_is_lower_left = true;
|
||||||
|
|
||||||
let projection_matrix = calculate_matrix(draw_data, clip_origin_is_lower_left);
|
let projection_matrix = calculate_matrix(draw_data, clip_origin_is_lower_left);
|
||||||
let shader_data = self.shader_provider.data();
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.use_program(Some(shader_data.program));
|
gl.use_program(Some(self.shaders.program));
|
||||||
gl.uniform_1_i32(Some(&shader_data.texture_uniform_location), 0);
|
gl.uniform_1_i32(Some(&self.shaders.texture_uniform_location), 0);
|
||||||
gl.uniform_matrix_4_f32_slice(
|
gl.uniform_matrix_4_f32_slice(
|
||||||
Some(&shader_data.matrix_uniform_location),
|
Some(&self.shaders.matrix_uniform_location),
|
||||||
false,
|
false,
|
||||||
&projection_matrix,
|
&projection_matrix,
|
||||||
);
|
);
|
||||||
@ -459,27 +435,27 @@ where
|
|||||||
unsafe {
|
unsafe {
|
||||||
gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo_handle));
|
gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo_handle));
|
||||||
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.ebo_handle));
|
gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.ebo_handle));
|
||||||
gl.enable_vertex_attrib_array(shader_data.position_attribute_index);
|
gl.enable_vertex_attrib_array(self.shaders.position_attribute_index);
|
||||||
gl.vertex_attrib_pointer_f32(
|
gl.vertex_attrib_pointer_f32(
|
||||||
shader_data.position_attribute_index,
|
self.shaders.position_attribute_index,
|
||||||
2,
|
2,
|
||||||
glow::FLOAT,
|
glow::FLOAT,
|
||||||
false,
|
false,
|
||||||
size_of::<imgui::DrawVert>() as _,
|
size_of::<imgui::DrawVert>() as _,
|
||||||
position_field_offset,
|
position_field_offset,
|
||||||
);
|
);
|
||||||
gl.enable_vertex_attrib_array(shader_data.uv_attribute_index);
|
gl.enable_vertex_attrib_array(self.shaders.uv_attribute_index);
|
||||||
gl.vertex_attrib_pointer_f32(
|
gl.vertex_attrib_pointer_f32(
|
||||||
shader_data.uv_attribute_index,
|
self.shaders.uv_attribute_index,
|
||||||
2,
|
2,
|
||||||
glow::FLOAT,
|
glow::FLOAT,
|
||||||
false,
|
false,
|
||||||
size_of::<imgui::DrawVert>() as _,
|
size_of::<imgui::DrawVert>() as _,
|
||||||
uv_field_offset,
|
uv_field_offset,
|
||||||
);
|
);
|
||||||
gl.enable_vertex_attrib_array(shader_data.color_attribute_index);
|
gl.enable_vertex_attrib_array(self.shaders.color_attribute_index);
|
||||||
gl.vertex_attrib_pointer_f32(
|
gl.vertex_attrib_pointer_f32(
|
||||||
shader_data.color_attribute_index,
|
self.shaders.color_attribute_index,
|
||||||
4,
|
4,
|
||||||
glow::UNSIGNED_BYTE,
|
glow::UNSIGNED_BYTE,
|
||||||
true,
|
true,
|
||||||
@ -794,32 +770,85 @@ impl GlStateBackup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ShaderProvider<G: Gl> {
|
/// Parses `GL_VERSION` and `GL_SHADING_LANGUAGE_VERSION` at runtime in order to
|
||||||
/// Called during renderer initialization, before this call the shader
|
/// generate shaders which should work on a wide variety of modern devices
|
||||||
/// provide should be in a neutral state and have not interacted with the
|
/// (GL >= 3.3 and GLES >= 2.0 are expected to work).
|
||||||
/// OpenGL context.
|
struct Shaders<G: Gl> {
|
||||||
///
|
program: G::Program,
|
||||||
/// Implementors should use this opporunity to check whether the version of
|
texture_uniform_location: G::UniformLocation,
|
||||||
/// the GL context (found with `[GlVersion::read]`) is compatible with the
|
matrix_uniform_location: G::UniformLocation,
|
||||||
/// shader they provide.
|
position_attribute_index: u32,
|
||||||
///
|
uv_attribute_index: u32,
|
||||||
/// # Errors
|
color_attribute_index: u32,
|
||||||
/// Any error creating the GL objects, compiling or linking or loading the
|
|
||||||
/// shaders, or an GL context with an incompatible OpenGL version will
|
|
||||||
/// result in an error.
|
|
||||||
fn initialize(&mut self, gl: &G, gl_version: GlVersion) -> Result<(), ShaderError>;
|
|
||||||
|
|
||||||
fn data(&self) -> &GenericShaderData<G>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A generic shader provider that parses `GL_VERSION` and
|
impl<G: Gl> Shaders<G> {
|
||||||
/// `GL_SHADING_LANGUAGE_VERSION` at runtime in order to generate shaders which
|
fn new(gl: &G, gl_version: GlVersion) -> Result<Self, ShaderError> {
|
||||||
/// should work on a wide variety of modern devices (GL >= 3.3 and GLES >= 2.0
|
let (vertex_source, fragment_source) = Self::get_shader_sources(gl, gl_version)?;
|
||||||
/// are expected to work).
|
|
||||||
pub struct AutoShaderProvider<G: Gl>(GenericShaderData<G>);
|
|
||||||
|
|
||||||
impl<G: Gl> ShaderProvider<G> for AutoShaderProvider<G> {
|
let vertex_shader =
|
||||||
fn initialize(&mut self, gl: &G, gl_version: GlVersion) -> Result<(), ShaderError> {
|
unsafe { gl.create_shader(glow::VERTEX_SHADER) }.map_err(ShaderError::CreateShader)?;
|
||||||
|
unsafe {
|
||||||
|
gl.shader_source(vertex_shader, &vertex_source);
|
||||||
|
gl.compile_shader(vertex_shader);
|
||||||
|
if !gl.get_shader_compile_status(vertex_shader) {
|
||||||
|
return Err(ShaderError::CompileShader(
|
||||||
|
gl.get_shader_info_log(vertex_shader),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fragment_shader = unsafe { gl.create_shader(glow::FRAGMENT_SHADER) }
|
||||||
|
.map_err(ShaderError::CreateShader)?;
|
||||||
|
unsafe {
|
||||||
|
gl.shader_source(fragment_shader, &fragment_source);
|
||||||
|
gl.compile_shader(fragment_shader);
|
||||||
|
if !gl.get_shader_compile_status(fragment_shader) {
|
||||||
|
return Err(ShaderError::CompileShader(
|
||||||
|
gl.get_shader_info_log(fragment_shader),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let program = unsafe { gl.create_program() }.map_err(ShaderError::CreateProgram)?;
|
||||||
|
unsafe {
|
||||||
|
gl.attach_shader(program, vertex_shader);
|
||||||
|
gl.attach_shader(program, fragment_shader);
|
||||||
|
gl.link_program(program);
|
||||||
|
|
||||||
|
if !gl.get_program_link_status(program) {
|
||||||
|
return Err(ShaderError::LinkProgram(gl.get_program_info_log(program)));
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.detach_shader(program, vertex_shader);
|
||||||
|
gl.detach_shader(program, fragment_shader);
|
||||||
|
gl.delete_shader(vertex_shader);
|
||||||
|
gl.delete_shader(fragment_shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(unsafe {
|
||||||
|
Self {
|
||||||
|
program,
|
||||||
|
texture_uniform_location: gl
|
||||||
|
.get_uniform_location(program, "tex")
|
||||||
|
.ok_or_else(|| ShaderError::UniformNotFound("tex".into()))?,
|
||||||
|
matrix_uniform_location: gl
|
||||||
|
.get_uniform_location(program, "matrix")
|
||||||
|
.ok_or_else(|| ShaderError::UniformNotFound("matrix".into()))?,
|
||||||
|
position_attribute_index: gl
|
||||||
|
.get_attrib_location(program, "position")
|
||||||
|
.ok_or_else(|| ShaderError::AttributeNotFound("position".into()))?,
|
||||||
|
uv_attribute_index: gl
|
||||||
|
.get_attrib_location(program, "uv")
|
||||||
|
.ok_or_else(|| ShaderError::AttributeNotFound("uv".into()))?,
|
||||||
|
color_attribute_index: gl
|
||||||
|
.get_attrib_location(program, "color")
|
||||||
|
.ok_or_else(|| ShaderError::AttributeNotFound("color".into()))?,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_shader_sources(gl: &G, gl_version: GlVersion) -> Result<(String, String), ShaderError> {
|
||||||
const VERTEX_BODY: &str = r#"
|
const VERTEX_BODY: &str = r#"
|
||||||
layout (location = 0) in vec2 position;
|
layout (location = 0) in vec2 position;
|
||||||
layout (location = 1) in vec2 uv;
|
layout (location = 1) in vec2 uv;
|
||||||
@ -897,170 +926,8 @@ void main() {
|
|||||||
body = FRAGMENT_BODY,
|
body = FRAGMENT_BODY,
|
||||||
);
|
);
|
||||||
|
|
||||||
create_shaders(&mut self.0, gl, &vertex_source, &fragment_source)
|
Ok((vertex_source, fragment_source))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data(&self) -> &GenericShaderData<G> {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<G: Gl> Default for AutoShaderProvider<G> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(<GenericShaderData<G> as Default>::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A shader provider for specific shaders for OpenGL ES (GLSL ES) version(s)
|
|
||||||
/// 3.0
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Es3ShaderProvider<G: Gl>(GenericShaderData<G>);
|
|
||||||
|
|
||||||
impl<G: Gl> ShaderProvider<G> for Es3ShaderProvider<G> {
|
|
||||||
fn initialize(&mut self, gl: &G, gl_version: GlVersion) -> Result<(), ShaderError> {
|
|
||||||
const VERTEX_SOURCE: &str = r#"#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
layout (location = 0) in vec2 position;
|
|
||||||
layout (location = 1) in vec2 uv;
|
|
||||||
layout (location = 2) in vec4 color;
|
|
||||||
|
|
||||||
uniform mat4 matrix;
|
|
||||||
out vec2 fragment_uv;
|
|
||||||
out vec4 fragment_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
fragment_uv = uv;
|
|
||||||
fragment_color = color;
|
|
||||||
gl_Position = matrix * vec4(position.xy, 0, 1);
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
const FRAGMENT_SOURCE: &str = r#"#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
in vec2 fragment_uv;
|
|
||||||
in vec4 fragment_color;
|
|
||||||
|
|
||||||
uniform sampler2D tex;
|
|
||||||
layout (location = 0) out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
out_color = fragment_color * texture(tex, fragment_uv.st);
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
if !gl_version.is_gles {
|
|
||||||
return Err(ShaderError::IncompatibleVersion(format!(
|
|
||||||
"A version of OpenGL ES is required for this shader, found: {}.{}",
|
|
||||||
gl_version.major, gl_version.minor
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
if gl_version < GlVersion::gles(3, 0) {
|
|
||||||
return Err(ShaderError::IncompatibleVersion(format!(
|
|
||||||
"This shader requires OpenGL ES version 3.0 or higher, found: ES {}.{}",
|
|
||||||
gl_version.major, gl_version.minor
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
create_shaders(&mut self.0, gl, VERTEX_SOURCE, FRAGMENT_SOURCE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn data(&self) -> &GenericShaderData<G> {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct GenericShaderData<G: Gl> {
|
|
||||||
pub program: G::Program,
|
|
||||||
pub texture_uniform_location: G::UniformLocation,
|
|
||||||
pub matrix_uniform_location: G::UniformLocation,
|
|
||||||
pub position_attribute_index: u32,
|
|
||||||
pub uv_attribute_index: u32,
|
|
||||||
pub color_attribute_index: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<G: Gl> Default for GenericShaderData<G> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
program: Default::default(),
|
|
||||||
texture_uniform_location: Default::default(),
|
|
||||||
matrix_uniform_location: Default::default(),
|
|
||||||
position_attribute_index: Default::default(),
|
|
||||||
uv_attribute_index: Default::default(),
|
|
||||||
color_attribute_index: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Errors
|
|
||||||
/// Any error creating OpenGL objects, compiling, or linking the given shaders
|
|
||||||
/// results in an error.
|
|
||||||
pub fn create_shaders<G: Gl>(
|
|
||||||
data: &mut GenericShaderData<G>,
|
|
||||||
gl: &G,
|
|
||||||
vertex_source: &str,
|
|
||||||
fragment_source: &str,
|
|
||||||
) -> Result<(), ShaderError> {
|
|
||||||
let vertex_shader =
|
|
||||||
unsafe { gl.create_shader(glow::VERTEX_SHADER) }.map_err(ShaderError::CreateShader)?;
|
|
||||||
unsafe {
|
|
||||||
gl.shader_source(vertex_shader, vertex_source);
|
|
||||||
gl.compile_shader(vertex_shader);
|
|
||||||
if !gl.get_shader_compile_status(vertex_shader) {
|
|
||||||
return Err(ShaderError::CompileShader(
|
|
||||||
gl.get_shader_info_log(vertex_shader),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let fragment_shader =
|
|
||||||
unsafe { gl.create_shader(glow::FRAGMENT_SHADER) }.map_err(ShaderError::CreateShader)?;
|
|
||||||
unsafe {
|
|
||||||
gl.shader_source(fragment_shader, fragment_source);
|
|
||||||
gl.compile_shader(fragment_shader);
|
|
||||||
if !gl.get_shader_compile_status(fragment_shader) {
|
|
||||||
return Err(ShaderError::CompileShader(
|
|
||||||
gl.get_shader_info_log(fragment_shader),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let program = unsafe { gl.create_program() }.map_err(ShaderError::CreateProgram)?;
|
|
||||||
unsafe {
|
|
||||||
gl.attach_shader(program, vertex_shader);
|
|
||||||
gl.attach_shader(program, fragment_shader);
|
|
||||||
gl.link_program(program);
|
|
||||||
|
|
||||||
if !gl.get_program_link_status(program) {
|
|
||||||
return Err(ShaderError::LinkProgram(gl.get_program_info_log(program)));
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.detach_shader(program, vertex_shader);
|
|
||||||
gl.detach_shader(program, fragment_shader);
|
|
||||||
gl.delete_shader(vertex_shader);
|
|
||||||
gl.delete_shader(fragment_shader);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.program = program;
|
|
||||||
unsafe {
|
|
||||||
data.texture_uniform_location = gl
|
|
||||||
.get_uniform_location(program, "tex")
|
|
||||||
.ok_or_else(|| ShaderError::UniformNotFound("tex".into()))?;
|
|
||||||
data.matrix_uniform_location = gl
|
|
||||||
.get_uniform_location(program, "matrix")
|
|
||||||
.ok_or_else(|| ShaderError::UniformNotFound("matrix".into()))?;
|
|
||||||
data.position_attribute_index = gl
|
|
||||||
.get_attrib_location(program, "position")
|
|
||||||
.ok_or_else(|| ShaderError::AttributeNotFound("position".into()))?;
|
|
||||||
data.uv_attribute_index = gl
|
|
||||||
.get_attrib_location(program, "uv")
|
|
||||||
.ok_or_else(|| ShaderError::AttributeNotFound("uv".into()))?;
|
|
||||||
data.color_attribute_index = gl
|
|
||||||
.get_attrib_location(program, "color")
|
|
||||||
.ok_or_else(|| ShaderError::AttributeNotFound("color".into()))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user