This mail comes from some discussions I had with Sven around the time
just before 1.2.0, the recent discussion about textures and natural
painting and a chat on IRC yesterday with Sven.
He told me to write down what I said there and post it to the mailing
list as a RFC --- I assume, just because he's limited on time, as
anything he could have written would be much more informed and better
grounded on reality than all I can come up with.
When we (sven and me) rewrote the pipe code to handle pixmap/bitmap
pipes and rewrote the pixmap brushes to drop the old format, we became
aware of what a mess the current handling of brushes vs. patterns
vs. pipes and so on is, as all of these objects are totally different
or at least the inheritance structure is counterintuitive (at least
Therefore I propose to completely rewrite everything that can be
considered a "PaintObject" into a generic provider form, where the
paintcore for each operation asks the provider for it's data.
E.g. a brush pipe is a provider that gives back a tempbuf of grayscale
data (a brush) or a pixmap brush when asked for it.
Besides providers that give back pixmap data, there will be scalar
providers, which can be used for example to return color values.
Painting with the color selected from a gradient will be just using a
color provider object, that uses a gradient as it's LUT for color values.
All the providers will get as an input parameter the current global
state of the input device, so all providers will be able to select
matching output data much the same way the current pipe does.
As David already pointed out, it doesn't make sense to only provide
for the possibility for a pipe to select from a fixed set of
pregenerated pixmaps. this is nice for the current limited pipe, but
when using a general pipe as a provider for textures/patterns/brushes
one wants to have the possibility to match certain or all dimensions
of the data space to a function.
Here the question naturally arises: what kind of functions should be
possible? Only transformations? Only some set of functions that are
predefined in the core? Or could there be some possibility to handle
user provided functions? How would these (if possible) be specified in
a fileformat? or just LUTs that are used by functionality that is
special to the object (e.g. for textures, there needs to be some
special functionality on how to map the input state (mainly pressure I
assume) to the final buffer returned. Here a LUT or a simply scalar
function seems to be the way to go.
For performance reasons, all ProviderObjects should automatically have
a LRU Cache (or some tuned variant of it) to store already computed
values. This of course can be handled in a base class for them, so
implementing another provider doesn't need the programmer to cope with
Another thing that should be really well thought about is how far this
abstraction is presented to the user. Having all of the paintobjects
fulfill a generic interface w.r.t the paintcore it makes it possible
to e.g. use a texture as a brush and vice versa. I would still
strongly argue against presenting such a possibility to the user. From
his/her point of view, a brush is NOT a pattern, nor a texture.
I'd think that a user wishing to use a brush as a pattern can always
load the brushfile in the gimp, and save it as a pattern (remember
that we talk about general pipes here already: laoding a brush and
saving it as a pattern will result in a pattern that changes according
to the input state in the same way as the original brush does.)
Another thing that's important when talking about brushes, patterns
and stuff is the way they are presented to the user (in grids or
lists). As Sven told me, Mitch is already working on this, so maybe my
comments are way off here, but anyway:
All of these providers should fulfill another contract with some
ViewContainers so they are able to draw representations of themself
into such a container. As far as I understood Sven, Mitch already has
some kind of a GimpViewable object and a general container type to
handle them. My suggestion goes along the line that this
functionality should be put into the same object as the PaintProvider,
so one object is able to do the work it's supposed to do AND draw it's
representation to the screen.
Ok, I hope this is not too mixed up, I wrote it at work with a lot of
people distracting me with things that pay my bills :-) I would like
to hear comments one some of these suggestions from you.