英文:
How would I do a template (like in C++) for setting shader uniforms in Rust?
问题
shader.h:
template <typename T> void SetUniform(const GLchar* name, const T& data);
shader.cpp:
template <> void ShaderProgram::SetUniform<int>(const GLchar* name, const int& data) {
glUniform1i(GetUniformLocation(name), data);
}
template <> void ShaderProgram::SetUniform<float>(const GLchar* name, const float& data) {
glUniform1f(GetUniformLocation(name), data);
}
template <> void ShaderProgram::SetUniform(const GLchar* name, const glm::vec2& data) {
glUniform2f(GetUniformLocation(name), data.x, data.y);
}
// etc...
在我有限的Rust知识下,我尝试使用匹配语句,因为迄今为止它已经为我节省了很多麻烦,但没有成功。
pub fn set_uniform<T>(&mut self, name: &str, value: T) {
match value {
value if value.is::<u32>() => {/* 在这里插入GL调用 */},
value if value.is::<f32>() => {/* 在这里插入GL调用 */},
// 等等...
_ => {panic!()}
}
}
我还遇到了traits,但尝试调整它们以实现我需要的功能时没有成功。我希望它会像下面这样,尽管我知道语法非常奇怪。
trait SetUniform<T> {
fn set_uniform(&mut self, name: &str, value: T);
}
是否有一种方法可以只使用一个函数名来接受任何类型的参数,还是我应该妥协并为每种不同的类型创建一堆不同命名的set_uniform函数?
英文:
I've been learning Rust recently and am working on a 3d engine using glfw3 and gl. I've got as far as trying to get a shader program that worked in my C++ engine working on my Rust one but have hit a snag on the implementation of setting shader uniforms.
shader.h:
template <typename T> void SetUniform(const GLchar* name, const T& data);
shader.cpp
template <> void ShaderProgram::SetUniform<int>(const GLchar* name, const int& data) {
glUniform1i(GetUniformLocation(name), data);
}
template <> void ShaderProgram::SetUniform<float>(const GLchar* name, const float& data) {
glUniform1f(GetUniformLocation(name), data);
}
template <> void ShaderProgram::SetUniform(const GLchar* name, const glm::vec2& data) {
glUniform2f(GetUniformLocation(name), data.x, data.y);
}
//etc...
With my limited knowledge of Rust, I tried using a match statement, as it has so far saved me a lot of hassle, to no avail.
pub fn set_uniform<T>(&mut self, value: T){
match T {
u32 => {/*insert gl call here*/},
f32 => {/*insert gl call here*/},
//etc...
_ => {panic!()}
}
}
I also came across traits, but had no luck trying to tweak them to do what I needed. I'd hoped it would have been something like this although I understand the syntax is very wonky.
trait SetUniform<T, Self = ShaderProgram> {
fn set_uniform(self: &mut Self, value: T)
where
T: Sized;
}
Is there any way to do this with just one function name that can take in any type of parameter or should I just give in and make a bunch of differently named set_uniform functions for each different type?
答案1
得分: 14
这可以通过特质来完成。
改变的是 value
的类型,所以我们需要一个可以在这些类型上实现的特质,比如 i32
、f32
等。可以像这样实现:
trait SetUniform {
fn set_uniform(location: GLint, value: Self);
}
(我假设 glUniform
函数都具有类似 fn(GLint, ...)
的签名)
现在我们为我们的参数类型实现它:
impl SetUniform for f32 {
fn set_uniform(location: GLint, value: Self) {
glUniform1f(location, value)
}
}
impl SetUniform for i32 {
fn set_uniform(location: GLint, value: Self) {
glUniform1i(location, value)
}
}
// 这里只是猜测类型,但原理应该很清楚
impl SetUniform for &Vec2 {
fn set_uniform(location: GLint, value: Self) {
glUniform2f(location, value.x, value.y)
}
}
// 对于其他类型等等
然后,你的调用函数(为了说明简化了)可以看起来像这样:
fn set_uniform<T: SetUniform>(location: GLint, value: T) {
// ^^^^^^^^^^^^^ `T` is now bound on the `SetUniform` trait...
SetUniform::set_uniform(location, value)
// ^^^^^ ... which is why this works
}
英文:
This can be done with traits.
What changes is the type of value
so we need a trait that we can implement on those types, i32
, f32
, etc. This could look something like this:
trait SetUniform {
fn set_uniform(location: GLint, value: Self);
}
(I'm assuming that the glUniform
functions all have a signature like fn(GLint, ...)
or similar)
Now we implement it for our argument types:
impl SetUniform for f32 {
fn set_uniform(location: GLint, value: Self) {
glUniform1f(location, value)
}
}
impl SetUniform for i32 {
fn set_uniform(location: GLint, value: Self) {
glUniform1i(location, value)
}
}
// guessing the types here, but the principle should be clear
impl SetUniform for &Vec2 {
fn set_uniform(location: GLint, value: Self) {
glUniform2f(location, value.x, value.y)
}
}
// etc for other types
Then your calling function (simplified for this illustration) can look like this:
fn set_uniform<T: SetUniform>(location: GLint, value: T) {
// ^^^^^^^^^^^^^ `T` is now bound on the `SetUniform` trait...
SetUniform::set_uniform(location, value)
// ^^^^^ ... which is why this works
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论