Painting over textures using Cinder


#1

Hello, I’m quite new, and I have a problem.

Generally speaking, what I’m trying to do is Photoshop’s stamp tool. For those who don’t know what it is, it’s a tool which takes pixels from one part of the images and copies them somewhere else using a brush, which may be any alpha shape.

I’ve done it, but stumbled upon performance issues. I guess there’s a way to make it better.

What I’m doing:

  1. My brush (B) is a two-dimensional array with float values for each pixel. [0.0, 1.0]
  2. The image is a surface (S1) AND a texture (T1). I change T1 only once, when I’m done with painting.
  3. There is a second surface (S2), which is used to paint stuff over S1.
  4. As long as a mouse button is down, I copy pixels from S1 to S2 using a vector and B as alpha.
  5. This step causes performance issues. I convert S2 to a texture (T2) every single time mouse moves as long as a button is down.
  6. I render T1, then T2
  7. As soon as a mouse button is up, I merge S2 and T1.

As a pseudocode:

Variables:
	Mouse position _position_;
	Mouse position difference _dpos_ = |old_position - position|;
	Mouse button _button_;
	Brush _brush_ as a two-dimensional array with values [0.0, 1.0];
	Vector _vec_ that defines where to copy from;
	Surface S1, S2;
	Texture T1, T2;

STAMP:

	repeat
		if button down then do
			if(dpos>0) then do
				for each pixel(x,y) in brush down
					S2(position + (x,y)) <- S1(position + (x,y) - vec) * pixel(x,y)
					
				T2 <- S2 // this step causes performance issues			
		else
			if S2 not empty then do
				S1 <- T1 + T2
				T1 <- S1
				clear T2
				clear S2
		draw T1
		draw T2

I know that it slows down because I continuously move things from CPU/RAM to GPU. I’m not sure how to avoid that though.I though about creating a second texture with a shift and paint a white mask instead of texture, but I would still need to make Surface to Texture conversion every single mouse move.


#2

Perhaps you could use a PBO?


#3

I’ll take a look, thanks.


#4

Hi,

welcome to Cinder! This sort of thing can better be done on the GPU entirely. Create an Fbo that will act as the surface to draw on, create a Texture for your brush and then simply bind the Fbo, draw the texture with alpha blending enabled, unbind the Fbo.

See the FboBasic sample for implementation details. For more general information on what an Fbo actually is, see the excellent articles on www.learnopengl.com.

-Paul


#5

Thanks! Although alpha of the brush remains the same, the pixels change as long as one moves the mouse. Therefore I would need three textures and a fragment shader to blend them (since it’s important to draw on a different layer than the source texture). I think I’m going to try to duplicate the texture and shift it. Then I’m going to use Fbo and a shader to blend the two textures together using shifted brush texture. This should work if I’m not mistaken.