A 2D Question/Challenge

I’m trying to create an effect similar to the paint brush in windows paint.(When you click and hold the mouse button it paints to the screen). I’d only like it to be in the 2DRender. Does anyone know how I could implement this?

Thanks =D

first of all create a blank white (or transparent if you wish) texture.

Then have a plane the size of your texture.

When you press the mouse button check if
a) you intersect the plane
b) get the point of intersection
c) transform that 3D coordinate into 2D space of your texture
d) modify the pixel at that point by your color of choice

e) extend your code to take a radius so it paints in all pixels within the radius of where the mouseclick happened.

f) refresh the texture drawn on the plane

Hey Chrys,
Everything makes sense except for step D).
How do I modify the pixels in the texture from panda? If you could point me to the documentation for that or show an example that would be awesome.
Thanks again

Search for PNMImage. You can’t use that directly as a texture, but you can do Texture.load(PNMImage) to feed a pnm image into a texture, and Texture.store(PNMImage) to do the opposite, feed the texture data into a pnm image.

A question remains will it be fast enough for this particular use. But you won’t know until you try.

there you go mate

class World(DirectObject):

    def __init__(self):
		self.actionMap = {"right":0}
		self.accept("mouse3", self.setAction, ["right",1])
		self.accept("mouse3-up", self.setAction, ["right",0]) 
		taskMgr.add(self.action, "actionTask")
    def setAction(self, key, value):
		self.actionMap[key] = value

    def action(self, task):
			md = base.win.getPointer(0)
			xMax = base.win.getXSize()
			yMax = base.win.getYSize()
			x = md.getX()
			y = md.getY()
			print x, y
			x = (x - (xMax/2.0)) / (xMax/2.0)
			y = (y - (yMax/2.0)) / (yMax/2.0)
			print x, y
			OnscreenImage(image = 'blackDot.PNG', scale = 0.02, pos = (x, 0, -y)).setTransparency(TransparencyAttrib.MAlpha)
		return task.cont

w = World()

Ok, I got it to work using the onscreenImage function and a task however it doesn’t update quite fast enough. The PNMImage method sounds like a better approach as far as getting the image to look the way I want but I imagine it will be even slower. Any thoughts? Maybe there is a way to make the tasks update faster? Or maybe another method other than tasks?

Whoa whoa whoa,

the current method you are doing is this:

Create an individual NodePath (OnscreenImage) that contains an quad (4 vertices), with a texture on it, for each pixel you want to draw.

Now keep in mind that by doing that, you’ll end up with hundreds, probably thousands, of nodes, which are all seperate…

the average number of individual nodes being sent to the GPU is about 300 (for a decent video game, that’s the goal)

Which means that you get… 300 pixels.

If you use PNMImage, you no longer are creating individual nodes = you have no node limit anymore.

If you use PNMImage you are only restricted to computing power and memory constraints, which will be beyond far better than your current method.

a PNMImage is a single texture, an image, which can be represented on a single OnscreenImage (or otherwise geom) which is only a single node, and a single texture.

Instead, you’re currently creating a node (OnscreenImage) and a texture (the texture loaded to display on the OnscreenImage node, for each pixel you want to draw, that’s insane! And will certainly be very slow!

I have no examples or helping code on using PNMImage, however I can tell you that it will easily be a severe performance boost, and I mean quite a bit.

Instead of being able to have around 600 pixels (using OnscreenImage for each pixel you want to display), you could end up getting easilly around 2048x2048 = 4,194,304 pixels.

You want to use PNMImage, and it will boost your performance.


That makes sense. I’ll give that a shot and keep you guys posted.