PistonDevelopers / conrod

An easy-to-use, 2D GUI library written entirely in Rust.
Other
3.35k stars 297 forks source link

Ability for a widget to output multiple extra rendering primitives #979

Open daboross opened 7 years ago

daboross commented 7 years ago

My specific use case here is a "game map view", where a large number of rectangles and images would want to be rendered within one widget, and I think it would be a bit overkill to add a widget to the graph for each one of these when they don't need any independent state. I could always render this manually, or render them raw with glium after the conrod rendering, but since everything that I need to render fits within conrod's rendering primitives, I thought this might be a possibility.

I probably won't be getting anywhere near needing to implement this soon, but I wanted to open this issue early to ask if this would be at all within the scope of conrod, or what alternatives there might be.

I think this may also be useful for things like BorderedRectangle, which could output 4 rectangle primitives around the edges of the inner rectangle, without having to pollute the widget graph.

The other thing is that I have no idea about the costs of conrod's widget structure, and no idea what the cost of adding a large number of extra widgets would be. I think for my view it would be adding 2500-5000 rectangle renders, and 100-400 image renders of 10-20 different images. Could anyone more knowledgeable than me possibly gauge what affect this might have with independent widgets vs. rendering primitives vs. raw glium calls?

mitchmindtree commented 7 years ago

Absolutely feel you here, I have a similar issue with the number of notes in my timeline pianoroll - there's definitely no need for them to all have their own spot in the widget graph as they're all just positions and colors for graphics! I was thinking was thinking something along the lines of #841 - I'd love to get your thoughts on it if you get a chance. Lately I've been thinking a nice alternative to the Batch idea might be to just have a Triangles widget that allowed for describing a big list of triangles. This would probably also allow to get rid of the Rectangle, Lines and Polygon primitives in favour of a Triangles primitive in the render backend as they're all just being drawn using triangle lists in all the backends at the moment anyways.

I have some ideas for making the graph::Container a little lighter in weight too, I think I have commented on this before somewhere but I can't think of where at the moment.

daboross commented 7 years ago

Ah, didn't see #841 at all, thank you for linking that!

A Batch widget would seem like a reasonably good idea, the only thing I would wonder about is how the user would input the many different primitives - having a separate Batch widget makes me think the most likely input method would be a supplying a large Vec of primitives to it, is this similar to what you would have in mind?

My thought here, having widgets themselves provide a way to get the primitives (maybe a method producing Box?) would allow the widget or the iterator to be put into the primitive walker, and passed to the rendering, so that the rendering primitives would only be created directly before being consumed. This would force anyone wanting to do batch rendering to create a custom widget, but I think it'd be much faster when the "source" for what to render is much smaller than a raw list of primitives would be. In my case I have a map stored as basically a Vec<Vec<u8>> with 3 different possible colors to render rectangles as - I think it'd be much more memory usage if all rendering primitives had to be created at once.

My current thought would basically be fn additional_renders(&self) -> Box<Iterator<Item=AdditionalPrimitive>>, where AdditionalPrimitive is basically conrod::render::Primitive minus the id, with rect relative to the widget and scizzor fixed to being the widget's borders. It'd be up to the user to yield the same kind of primitive next to each other in the iteration to make it efficient.

Thoughts on this vs. a Batch widget - or maybe you had something more like an iterator in mind anyways with Batch?

mitchmindtree commented 7 years ago

@daboross #1021 introduces a new Triangles widget which can now be used to draw more complex graphical scenes in a much more efficient manner!

The triangles module provides ways of converting polygons, lines and quads into iterators yielding triangles, which can be passed to the constructor of the new Triangles widget. This gives us the ability to instantiate thousands of arbitrary 2D shapes all at once using a single widget.

There's also a Triangles<MultiColor> implementation which takes a list of triangles that have a unique colour per vertex, meaning we can now draw fancy gradients and whatnot.

This is perhaps not quite as nice as the hypothetical Batch widget, but it should be a nice stepping stone!