Design Help with a Simple Sprite Engine

Hello! I'm playing around trying to design a simple Sprite engine in Rust. The idea is to eventually support any number of graphical backends. Currently I'm using Glium as it has a pretty nice interface. Right now I have something like:

/// A 2D Sprite
pub struct Sprite {
    pub mesh: Mesh,
    pub texture: Option<SrgbTexture2d>,
    pub color: Vector4<f32>,
    pub transform: Transform2d
}

/// This might as well be GliumMesh as it is directly dependent on Glium
pub struct Mesh {
    vertices: Rc<glium::VertexBuffer<Vertex>>,
    index_type: glium::index::PrimitiveType
}

Graphically, it looks something like this:

As you can see there are a lot of coupling issues here: anything that depends on Sprite also depends on Glium!

A few ways to solve this come to mind: I can have some type of SpriteTrait and have everything use dyn SpriteTrait instead of Sprite directly, and then GliumSprite or WhateverSprite can implement that. However this feels like kind of a weird solution because Sprite currently has no methods, it's intended to just kind of be a dummy that composes vertex buffers and textures. I could also play around with Generics that implement this trait.

Any ideas as to what might be a rust-y way of achieving this kind of decoupling? Thanks!

gfx (pre-ll) does this with Resources trait. This way every "abstract" type depends on <R: Resources> type argument, like:

pub struct Slice<R: Resources> {
    pub start: VertexCount,
    pub buffer: IndexBuffer<R>,
    . . .
}

but it works and doesn't have a run-time cost.

You may also be interested in checking how @icefoxen abstracted over gfx backends in ggez engine without cluttering the user-facing API: Fundamental work needed to make graphics context generic by icefoxen · Pull Request #415 · ggez/ggez · GitHub

3 Likes

Cool that makes sense! I’ll check those out. I suppose it makes perfect sense that Rust’s separation-of-concerns philosophy would involve generics and traits. If things get too dicey I suppose I can always use some type of resource ID system. Thanks!

One other thing to consider: there’s a fair chance you might want to start batching draw calls together at some point to speed up rendering, which would likely mean that it’d be the batcher that would own the low level stuff like the buffers, not the individual sprite. So your Sprite type could just stay as a bundle of simple data (like the transform and the color), and it wouldn’t have to care about the specifics of how it gets drawn.

Similarly, rather than the sprite owning the full texture object, you might want to just load each texture once and then give the sprite a handle/ID for it.

1 Like