Support M600 filament swaps
Now that we have multi-color rendering to properly preview multi-color prints, the API for extrusionColor was updated to allow an array of colors.
ex. extrusionColors: ['#CF439D', 'rgb(84,74,187)', 'white', 'rgb(83,209,104)'],
But there is another way to use muliple colors for a print, which is a filament swap. This works by manually or automatically changing the filament at a certain layer. In GCode this is controlled via the M600 command.
This technique enables for instance multi-color signs and even color mixing in 2d (hueforge)
The obvious API for this sequence of colors would also be an array. But the question then is: how to define a possible combination of sequential and concurrent colors? Nesting arrays would be confusing.
For tool based multi-color it is known in advance which color is associated with which too. At least that correspondence doesn't change during the print.
For filament swaps, you cannot know how many swaps there will be. The whole gcode stream will have to be processed. And it just depens on what tool is active at that moment. That makes filament swap much more dynamic and less predictable.
Then there are systems, like the AMS from Bambulab that will allow you to continue on the next roll when the first is used up. Since GCode preview doesn't know anything about spools of filament it is impossible te predict when and where to do a color change without extra information. Therefore, I would suggest that this type of filament swap is out-of-scope for this ticket.
So supporting M600 but not sensor based filament swaps, is the focus.
My first suggestion for the api is to define an extra array: swapColors: []. Whenever an M600 is encountered, the next color in this array is used.
I think we are too focused on rendering the actual color of the filament.
There's an expectation of accuracy when visualizing gcode but sometimes we don't have the information and we should abstract it out.
Let's think about representing the changes with color indexes rather than trying to map colors to the actual world! My slicer, for example, does not care about what colors I loaded in to each extruders. Tool 1 is always orange, tool 2 is pink, etc.
Before the gcode is loaded, we can't know how many color changes there will be. But we can loop through a default array that indicates that the color changed. In the case of M600, an array of two is enough to understand what is going on during the print. If the user wants to make it pretty, they can add more colors to the array. It's pretty unlikely that the array will be longer than 10 colors, different or duplicated, because it's a manual change that would be super annoying in the first place.
Why would we use a different param than the existing extrusionColor? It is an array, and we can loop through it. We don't have to have it indexed and mapped perfectly to the number of M600s in the file.
but which color would we pick then, from the extrusionColor arrray?
We also don't know how many tool indices the print will use without processing all of the gcode.
So I don't think we can share a simple array between the tool changing and the filament swaps.
What I want with this feature is to allow users to actually preview their print with the colors that they've planned. It would also be nice to have a fallback for the case where there are not enough colors specified up front for all of the swaps. Like you said we could just loop through the array.
toolchanging does complicate things a little bit. I will be harder for users to create that array for swapped colors. So maybe each tool should have it's own array of colors.... but that seems a bit unwieldy.
but thinking about what you've said again.. I think you're making the case that M600's not very convenient and there less of a priority? I must say I was a little confused myself because my slicer converts 'color changes at Z=something' to tool changes.. So I'm not even using M600 in the way I thought for a minute.
I'll think about it
but which color would we pick then, from the extrusionColor arrray?
I'm thinking about naively starting at index 0 and increment at each M600 until it's time to loop back to 0. So if there are two colors, it will just switch between the two. I'm not sure about what to do when there is only a single color. Should we have a default colors list to fallback to? Or slightly change the brightness? Do nothing?
I'm pretty sure that setting a default value for extrusionColor that is an array would seamlessly allow users to see M600s without having to change their config if they are using the defaults:
static readonly defaultExtrusionColor = [new Color('hotpink'), new Color('lime')];
Users that are already specifying a single color won't technically see that as a breaking change because M600 was not supported before. I will not change the result they used to get unless we implement a fallback.