Open
Conversation
* feat: add LineStyle variable to ImPlotSpec * feat: add RendererLineStripUV to render textured liens * feat: add AddLineStyle to register custom line styles * docs: added line style demo tab
* feat: AddLineStyle can now be called before LoadDefaultLineStyles * docs: Added custom line styles demo code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related to #185
Background
First of all, thanks for this incredible library!
I've recently been using ImPlot for a personal project and wanted to display lines with different patterns only to discover it hasn't been implemented yet! Then I came across this issue and the discussion about possible implementations.
From what I understand there is only one viable solution with the current ImGui API that does not require a dedicated render backend: Using textured lines created with the AddCustomRect() API.
This PR implements this idea in what I hope is simple and user friendly.
It is NOT a complete implementation as it currently only supports line strips, lacks AA and does not render properly for large gaps between data points.
I'd like to get the community feedback before going any further and attempt to implement this missing features.
Summary
Added support for line patterns (dashed, dotted, etc.)
Implementation
ImPlotSpec: Added LineStyle property
ImPlotLineStyle: New typedef for line style IDs
ImPlotLineStyle_: New enum for default line styles defined by ImPlot
PrimLineUV: New function to add a textured line primitive to draw_list
RendererLineStripUV: New renderer supporting textured lines
ImPlotLineStyleData: New struct to hold ImFontAtlasRectId, pattern period, max rectangle size and ImFontAtlasRect data
LineStyleData vector: New ImVector in ImPlot context to hold loaded line style data
LoadDefaultLineStyles: Function to load default line styles defined by ImPlot
AddLineStyle: User function to add custom line styles using a sequence of on/off pixel widths
AddLineStyleInternal: Internal function used to generate the default line styles
GetLineStyleData: Internal helper function to gather ImFontAtlasRect data before rendering
Demo_LineStyles: New demo tab showcasing plot line styles, how to load default styles and how to add custom ones.
Demo
A line styles tab has been added to
implot_demo.cppshowcasingTechnical details
First of all the texture data for the line patterns is generated in the
AddLineStyleInternal()function which is called either fromAddLineStyle()orLoadDefaultLineStyles()AddLineStyleInternal()callsAddCustomRect()to reserve a rectangle in the FontAtlas with a fixed size (for now) of 511x1 pixels.The default atlas width is usually 512 pixels and a rectangle of 511 pixels is the maximum we can get without forcing the creation of a 1024 wide texture.
The rectangle height only needs one pixel regardless of the actual plot line width:
With the rectangle reserved, we fill the pixel data according to the on/off sequence passed into
AddLineStyleInternal(). A sequence might look like this ´{6, 6, 2, 6}´ for 6 pixels on, 6 pixels off, 2 pixels on, 6 pixels off. The pattern is repeated until the whole texture is filled.Then, the rectangle ID and pattern period (in pixels) are stored as a
ImPlotLineStyleDataobject in the ImPlot contextAt this point the line pattern is ready to be used.
When the user draws a plot line with LineStyle other than solid line, the rectangle UV coordinates are retrieved using
GetLineStyleData()and passed to the renderer.Finally, the renderer maps the uv coordinates according to the cumulate pixel length of the line and fills the draw_list.
The problem with this approach appears when a single line segment is longer than the atlas rectangle length:
My proposal is to split long lines and generate subsegments. That would require to call
PrimReserve()within the renderer, which isn't very elegant. If we had the ability to load a custom texture to the GPU and set the UV wrap mode to repeating (or equivalent for renderers other than OpenGL) this problem could be avoided. However with the current API I see no alternative other than more geometry.Sorry if the text above was too long and thank you for taking the time to read it!
Let me know your thoughts about this implementation and where I can improve/add functionality.