Glium - UniformsStorage as a field in a struct

Hello,

I am trying to store a UniformsStorage in a struct, but with my application this seems impossible, as I need to be able to add to the UniformsStorage dynamically.

Here's the documentation for UniformsStorage: glium::uniforms::UniformsStorage - Rust

What I'm roughly trying to do, is this:

struct DynShader<'s> {
  program: glium::Program,
  uniforms: glium::uniforms::UniformsStorage<'s, i32, glium::uniforms::EmptyUniforms>
}

impl<'s> DynShader<'s> {
  pub fn new() -> DynShader {
    // create the shader, irrelevant to what I'm trying to achieve
    DynShader {
      program,
      uniforms: glium::uniforms::UniformStorage::new("my_uniform", 42); // i'd rather not initialize the value, but if I must, I will
    }
  }

  pub fn add_uniform<T>(&mut self, name: &str, value: T) {
    // this is where my plan fails. I need to add a uniform to self.uniforms,
    // but UniformsStorage.add returns another UniformsStorage with the original
    // UniformsStorage as its R
  }
}

Is there any solution to this problem?

I'm not familiar with glium or the particular problem you're trying to solve here, but can you use an option initialized to None, or MaybeUninit?

I ended up implementing my own Uniforms, as it was a simpler solution than this weirs UniformsStorage mess.

I am facing the same issue, could you share the code of your solution please?

It's been so long :smile:

I don't have the code anymore (backstory below) but I probably ended up doing something like this (untested but should work with minimal to no tweaks, just follow the compiler errors' advice!):

use std::collections::HashMap;

use glium::uniforms::{Uniforms, UniformValue};

struct DynamicUniforms {
    // Here we can use the 'static lifetime because we'll only ever store POD types that
    // don't contain references.
    uniforms: HashMap<String, UniformValue<'static>>,
}

impl Uniforms for DynamicUniforms {
    fn visit_values<'a, F>(&'a self, mut next_uniform: F)
    where
        F: FnMut(&str, UniformValue<'a>)
    {
        for (name, &value) in self.uniforms {
            // 'static outlives 'a so it's fine to just pass values in here.
            next_uniform(name, value);
        }
    }
}

Except I probably wasn't fluent enough in Rust to even consider using the 'static lifetime. Ahem, anyways...


Back in 2018 I gave up on trying to learn Rust, and went on to adventures with other programming languages. The borrow checker was just too frustrating at the time. So I believe I never actually finished my original solution, and gave up on the language altogether. Fun times.

Now that I'm much more fluent in Rust I could come up with the solution above. Hope it helps you!

As a more experienced graphics programmer now I'd also advise to stay away from glium. OpenGL is a very outdated API and we have more modern crates, such as wgpu, which actually supports all major APIs (DirectX, Metal, Vulkan, WebGL, and WebGPU whenever it's stabilized!) so there's practically no point in trying to learn OpenGL anymore. Unless you're maybe following a tutorial such as learnopengl.com, then using a more low-level OpenGL wrapper such as glow will probably be easier.

Cheers!


EDIT: I'm just looking at glium's docs again and maybe using a 'static lifetime isn't the brightest idea. In that case you can define a custom enum that holds owned values:

enum OwnedUniformValue {
    Float(f32),
    Vec2f([f32; 2]),
    // ...
    Texture(Rc<Texture2d>, Option<SamplerBehavior>),
}

and then translate it to the non-owned UniformValue inside of visit_value.

I'd advise not introducing a lifetime to the struct, it'll only cause you headaches with the borrow checker.

1 Like