Footprint algorithms: in the stamp, or in the paintop?
Cyrille Berger
cberger at cberger.net
Tue Mar 25 19:38:30 CET 2008
On Tuesday 25 March 2008, you wrote:
> Il Tuesday 25 March 2008 11:30:05 Cyrille Berger ha scritto:
> > That said, the priority for Krita 2.0 would be KisStampManipulator (with
> > a better name), all the rest can happen when we have, at last, make that
> > release.
>
> Well. This has a flaw, and I hope to very clear at explaining it.
> If we use KisStampManipulator, we are still relying on a certain paintop
> to "build up" the behavior of the stamp.
>
> Let me explain...
> Imagine: we will prepare a set of KisStampManipulator classes, each of them
> transforms the input stamp in something different, taking pressure, tilt,
> et cetera into account, at paintop discretion. We can imagine something
> like a chain of manipulators that the paintop can build up to obtain the
> final stamp.
>
> This way, the code that "builds up" the stamp is in a particular paintop:
> for example in KisBrushOp there will be the chain that builds a brush-like
> stamp.
>
> But what happens then? It happens that a particular chain is binded to a
> particular paintop. You want a brush stamp? You've to use KisBrushOp! You
> need a pencil stamp? You've to use KisPencilOp (or KisPenOp).
> But again, these paintops not only decide how the *stamp* will look like
> (size, shape, position, et cetera); they decide what to do with that stamp
> too (and, as everyone knows, they just "print" the stamp onto the canvas
> using the current color).
> So, with this infrastructure, KisPaintOp does *two* things:
> 1) Takes a certain stamp from KisStamp and applies to this stamp a chain of
> manipulations.
> 2) Decides what to do with this manipulated stamp.
>
> I think that these two operations needs to be separated. A certain class -
> indipendently from KisPaintOp - has to take and manipulate the stamp using
> current information and settings. Then the paintop has just to decide what
> to do with this ready-to-use stamp.
>
> To make the difference more evident, consider this simil-code:
>
> 1) This is how the code will look like with Cyrille's suggested structure:
>
> KisBrushOp::paintAt(information)
> {
> stamp = currentStamp(information);
> manipulatedStamp = applyBrushManipulationChain(information);
>
> stampDevice->setColor(currentColor);
> bitBlt(stampDevice to canvasDevice);
> }
>
> KisPenOp::paintAt(information)
> {
> stampDevice = currentStamp(information);
> manipulatedStamp = applyPenManipulationChain(information);
>
> stampDevice->setColor(currentColor);
> bitBlt(stampDevice to canvasDevice);
> }
>
> KisCloneOp::paintAt(information)
> {
> stampDevice = currentStamp(information);
> manipulatedStamp = ?????????? <---- You see, here, what will the
> manipulated stamp? A Brush stamp?
> a pencil stamp? And what will happen
> when the number of different chains
> will grow?
>
> bitBlt(sourceDevice to stampDevice);
> bitBlt(stampDevice to canvasDevice);
> }
Wrong, with my proposal it would be
KisPenOp::paintAt(information)
{
stampDevice = manipulation->createStamp(stampobject, information,
currentColor); // yes currentColor need to be set at stamp creation
bitBlt(stampDevice to canvasDevice);
}
KisCloneOp::paintAt(information)
{
stampDevice = manipulation->createStamp(stampobject, information,
sourceDevice); // again no need to copy the source device to the stamp device
bitBlt(stampDevice to canvasDevice);
}
It could even be :
KisDrawingOp::paintAt(information)
{
stampDevice = manipulation->createStamp(stampobject, information,
colorSource); // again no need to copy the source device to the stamp device
bitBlt(stampDevice to canvasDevice);
}
No clone op, no filter op, no brush op, no pencil op. Brush op and pencil op
are replaced by a KisBrushStamp and KisPencilStamp (like in your proposal),
clone, filter and plain color happen in the color source.
Then dynamic brush can be either implemented as a paint op (like done
currently)
KisDynamicOp::paintAt(information)
{
stampDevice = stamp->createStamp( size => sensor1, rotation =>
sensor2, ... , colorInformation );
bitBlt( stampDevice to canvasDevice);
}
Or directly builting by extending the manipulation class.
> 2) This is how the code will look like with my idea:
>
> KisBrushStamp::createStamp(information)
> {
> return brushManipulationChainStamp(information);
> }
>
> KisPencilStamp::createStamp(information)
> {
> return pencilManipulationChainStamp(information);
> }
>
> ...
> ...
> resources::currentStamp = registry->stamp("brushstamp"); <--- call done,
> for example, througth a nice UI. ...
> ...
>
> KisDrawingOp::paintAt(information)
> {
> stampDevice = currentStamp->createStamp(information); <--- currentStamp
> builds directly a complete stamp!
>
> stampDevice->setColor(currentColor); <--- this can even done directly
> in create Stamp!
>
> bitBlt(stampDevice to canvasDevice);
> }
>
> KisCloneOp::paintAt(information)
> {
> stampDevice = currentStamp->createStamp(information); <--- currentStamp
> builds directly a complete stamp!
>
> bitBlt(sourceDevice to stampDevice);
> bitBlt(stampDevice to canvasDevice);
> }
In fact what you want is a function in the stamp that will call the
manipulator ? Instead of having the manipulator called with the stamp object.
It's not really a problem if there is only one kind of manipulator, but if
you want to have different type of manipulator, then it becomes a problem, or
else you recreate an instance of the brush each time the manipulator change.
For me stamp are ressource. While manipulators are algorithms. That's why I
prefer to see them separated, we have allways done this in Krita : algorithms
(filter, pigment's color transformation, KisPainter, KisStampManipulator)
takes ressources as input (KisPaintDevice, raw channels, KisStamp ).
> PS: by the way this integrates perfectly with boud new code.
So does the current code...
--
Cyrille Berger
More information about the kimageshop
mailing list