Skip to content

Conversation

@bbogdan-ov
Copy link
Contributor

Warning

This PR will break most of the existing code

This PR aims to make MINIQUAD api more flexible by separating texture binding to its own method RenderingBackend::apply_images

Why?

Sometimes i need to use the same buffer bindings (vertex and index buffers) for different sprites for example (because they all are quads), but creating a new Bindings for each sprite just to change their texture is tedious.

This is especially frustrating when, for example, you need to load hundreds of .png files and create a texture for each of them. This can also lead to relatively huge memory usage and poor performance, as you need to allocate and store a vector of buffer IDs + another buffer ID for each texture.

Migration

 struct Stage {
     // ...
 }
 impl Stage {
     fn new() -> Stage {
         let my_texture_1: TextureId = /* load texture... */;
         let my_texture_2: TextureId = /* load texture... */;

         // `images` field was removed from the `Bindings` struct
         let my_bindings = Bindings {
             vertex_buffers: /* ... */,
             index_buffers: /* ... */,
-            images: vec![my_texture_1, my_texture_2],
         }

         // ...

         Stage {
             // ...
             my_bindings,

             // You'd better store these textures as separate variables:
+            my_texture_1,
+            my_texture_2,
         }
     }
 }
 impl EventHandler for Stage {
     // ...

     fn draw(&mut self) {
         // ...

         self.ctx.apply_bindings(self.my_bindings);
         // Now you need to explicitly apply textures
+        self.ctx.apply_images(&[self.my_texture_1, self.my_texture_2]);

         self.ctx.draw(0, 6, 1);
     }
 }

Example

This code is significantly simplified for clarity

Initialization:

let bindings = Bindings {
    vertex_buffers: /* ... */,
    index_buffer: /* ... */,
};

// Storing each texture in a separate variable
let texture1: TextureId = /* load texture... */;
let texture2: TextureId = /* load texture... */;

// All other steps are the same as before (e.g. creating pipeline or shader)
// ...

Drawing logic:

pub fn draw_sprite(&mut self, x: i32, y: i32, texture: &TextureId) {
    self.ctx.apply_pipeline(&self.pipeline);
    self.ctx.apply_bindings(&self.bindings);

    self.ctx.apply_image(texture);
    // If i need to apply multiple textures:
    // self.context.apply_images(&[texture, texture_n, ...]);

    self.ctx.apply_uniforms(/* ... */);

    self.ctx.draw(0, 6, 1);
}

Drawing sprites:

fn draw(&mut self) {
    // ...

    self.draw_sprite(10, 10, &texture1);
    self.draw_sprite(60, 10, &texture2);

    // I can draw as many sprites as i want:
    // self.draw_sprite(0, 0, &texture_n);
}

Result:

image

P.S.

Thanks for your time!

Hopefully this PR will be merged, but as I said earlier, it will break most of the existing code.

@bbogdan-ov bbogdan-ov closed this by deleting the head repository Jun 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant