Skip to content

Feat: Line styles (dashed lines)#685

Open
dracir9 wants to merge 2 commits intoepezent:masterfrom
dracir9:feat/line-styles
Open

Feat: Line styles (dashed lines)#685
dracir9 wants to merge 2 commits intoepezent:masterfrom
dracir9:feat/line-styles

Conversation

@dracir9
Copy link
Copy Markdown

@dracir9 dracir9 commented Mar 11, 2026

Related to #185

imagen

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.cpp showcasing

  • Loading Default (ImPlot defined) line styles
  • Adding custom defined line styles
  • How to use ImPlotSpec to set a default line style
  • How to use ImPlotSpec to set a custom line style

Technical details

First of all the texture data for the line patterns is generated in the AddLineStyleInternal() function which is called either from AddLineStyle() or LoadDefaultLineStyles()

AddLineStyleInternal() calls AddCustomRect() 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:

  • For 1 pixel wide lines we can use two triangles per line and UV coordinates around the atlas rectangle to get AA.
  • For thick lines we can draw a core+fringe to get AA. We need more geometry but avoid generating one rectangle for every line pattern and every line width.
  • If no AA is needed, we can still use a 1 pixel wide texture and set the UV coordinates to the center of the line

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 ImPlotLineStyleData object in the ImPlot context
At 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:

  • If there are other rectangles next to the line pattern in the font atlas, they will be drawn into the plot line
  • If the uv coordinates reach the end of the texture, they will be clamped and show whatever color the last pixel has.

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.

dracir9 added 2 commits March 8, 2026 22:22
* 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
@dracir9 dracir9 mentioned this pull request Mar 11, 2026
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