We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpSyntax Questions › XOR drawing mode (without loadPixels/updatePixels)
Page Index Toggle Pages: 1
XOR drawing mode (without loadPixels/updatePixels) (Read 1051 times)
XOR drawing mode (without loadPixels/updatePixels)
Dec 29th, 2008, 11:00pm
 
I want to be able to draw several "cursors" over top of a digital painting a user is creating in Processing.

The regular cursor is drawn non-destructively over top of the Processing window, so it doesn't affect the underlying image.  Using a regular Processing drawing element (e.g., ellipse()), this changes the underlying image.

I realize I can draw using XOR, but the only way I know how is to: (a) loadPixels(), (b) draw, pixels[x +y*width] ^= color(255); (c) updatePixels().  The next frame, I can draw again, and since I used XOR, the cursor will disappear, leaving the original image restored.  Although this works, it is painfully slow.  My frameRate drops from 300 fps to 20 fps, because my pixels array is so large.

I am wondering whether it is possible to use an OpenGL XOR drawing more, or maybe get access to multiple "hardware" cursors (in addition to the regular cursor that follows the mouse).

I am sure this is a generic problem that many people would like to see a good solution for, ... the ability to draw a few cursors over top of the main processing window, without changing the underlying drawing ... and without have to keep re-drawing the image.

Any pointers or suggestions would be appreciated.

-- djones
Re: XOR drawing mode (without loadPixels/updatePix
Reply #1 - Dec 29th, 2008, 11:58pm
 
A possible way to do that is to use the good old sprite trick: you save the area corresponding to the bounding box of the cursor and draw over the image. When you move the cursor, you restore the area (hoping it is fixed!), erasing the old cursor, then repeat.
Re: XOR drawing mode (without loadPixels/updatePix
Reply #2 - Dec 30th, 2008, 6:06pm
 
Hey!  That sounds like it should do the trick.  I will give it a try.

-- djones

PhiLho  wrote on Dec 29th, 2008, 11:58pm:
A possible way to do that is to use the good old sprite trick: you save the area corresponding to the bounding box of the cursor and draw over the image. When you move the cursor, you restore the area (hoping it is fixed!), erasing the old cursor, then repeat.

Re: XOR drawing mode (without loadPixels/updatePix
Reply #3 - Dec 30th, 2008, 6:51pm
 
PhiLho  wrote on Dec 29th, 2008, 11:58pm:
A possible way to do that is to use the good old sprite trick: you save the area corresponding to the bounding box of the cursor and draw over the image. When you move the cursor, you restore the area (hoping it is fixed!), erasing the old cursor, then repeat.


Actually, I just tried this "sprite" method, and unfortunately, it is painfully slow.

As far as I can tell, if your sketch ever calls "get() or set()", it ends up calling loadPixels()/updatePixels() behind the scenes.  This is horribly slow.

My sketch size is 1500x1000, and my sprite is only 16x16.  I just want to img=get(x,y,16,16), draw a cursor there, ... and then on the next frame set(x,y,img) to erase my cursor.

As a benchmark, ... my sketch runs at 300 fps without the get/set, but falls to 15 fps when I use get/set, even for a tiny 16x16 sprite.

There should be a way to implement sprites more efficiently, without calling loadPixels/updatePixels for the entire image (1.5 million pixels)!!  Is this something that needs to be fixed inside the core of Processing ... or is there something a mere user like me can do

-- djones


Re: XOR drawing mode (without loadPixels/updatePix
Reply #4 - Dec 31st, 2008, 11:47am
 
Mmm, I have no idea what is your strategy of screen updating. Perhaps an optimization can be done.
Can you make a dummy example/simplification of your sketch, to see what can be improved? I would be curious to see how to compute/display the actual framerate too.
Re: XOR drawing mode (without loadPixels/updatePix
Reply #5 - Dec 31st, 2008, 8:18pm
 
PhiLho  wrote on Dec 31st, 2008, 11:47am:
Can you make a dummy example/simplification of your sketch, to see what can be improved I would be curious to see how to compute/display the actual framerate too.


Here is some sample code ...
Let me know what you think ...

-- djones

Code:

// sprite_demo
//
// This demo illustrates how painfully slow "get/set" are in Processing 1.01
// Whenever you call get/set inside draw(),
// this seems to invoke loadPixels()/updatePixels() behind the scenes.
// When the sketch image is large (800x800) this is extremely slow,
// even though the image patch we want to get/set is tiny (32x32).
//
// On my Mac, this sketch runs at 800 frames/sec without calling get/set,
// but slows down to 30 frames/sec when calling get/set.
//
// You can try this demo yourself. Just click the mouse to toggle
// whether or not get/set are called. The frameRate is displayed every 4 seconds.
//
// There should be a fast way to grab a small portion of the sketch image.
//

final int SPRITE_SIZE = 32;
int sx, sy;
PImage sprite;
boolean drawsprite = true;
int t;

void setup() {
size(800,800);
frameRate(1000);
background(0);
sprite = get(0,0,SPRITE_SIZE,SPRITE_SIZE);
}

void mouseReleased() {
drawsprite = !drawsprite;
println("Sprite drawing turned " + (drawsprite ? "ON" : "OFF"));
}

void draw() {
if (drawsprite) {
// remove the old sprite
set(sx,sy, sprite);
}

// draw something new
stroke(random(0,255));
strokeWeight(random(1,10));
noFill();
line(random(0,width),random(0,height), random(0,width),random(0,height));

noStroke();
fill(255,0,0);
sx = mouseX-(SPRITE_SIZE)/2;
sy = mouseY-(SPRITE_SIZE)/2;
if (drawsprite) {
// remember image patch under the new sprite
sprite = get(sx,sy,SPRITE_SIZE,SPRITE_SIZE);
}
ellipse(mouseX,mouseY,SPRITE_SIZE/2 - 1, SPRITE_SIZE/2 - 1);

// display frameRate every 4 seconds
if ((millis() - t)/1000 > 4) {
println("frameRate = " + frameRate);
t = millis();
}
}
Re: XOR drawing mode (without loadPixels/updatePix
Reply #6 - Jan 1st, 2009, 1:11pm
 
Hum, on my old (2004) Windows XP system with an average (or lower) graphics card, I have the same frame rate, between 30 and 33, with or without the sprite. So it will be hard to see an improvement... Even if I push size to 1500x1000 (more than my current screen), it drops to ~15fps but it is still the same.
Anyway, the method isn't really suited to a moving/rapidly changing background, since the part that was saved might have changed when you restore it. It is more suited to fixed (or scrolling) background where the only moving parts are sprites...
Maybe you can try and see if createCustomCursor is useful for you.
Re: XOR drawing mode (without loadPixels/updatePix
Reply #7 - Jan 2nd, 2009, 11:11pm
 
PhiLho  wrote on Jan 1st, 2009, 1:11pm:
Hum, on my old (2004) Windows XP system with an average (or lower) graphics card, I have the same frame rate, between 30 and 33, with or without the sprite. So it will be hard to see an improvement... Even if I push size to 1500x1000 (more than my current screen), it drops to ~15fps but it is still the same.
Anyway, the method isn't really suited to a moving/rapidly changing background, since the part that was saved might have changed when you restore it. It is more suited to fixed (or scrolling) background where the only moving parts are sprites...
Maybe you can try and see if createCustomCursor is useful for you.


Maybe there is a Windows vs. Mac difference in how Processing is implemented.

Actually, the "sprite" method works fine with changing backgrounds, as long as you grab a snapshot of the background at the end of the draw() function, just before you draw the sprite on top, ... and then at the *beginning* of the next draw(), you restore the background before any more changes occur.

-- djones

Re: XOR drawing mode (without loadPixels/updatePix
Reply #8 - Jan 3rd, 2009, 5:25pm
 
If using JAVA2D renderer, you could try something like:
Quote:
    Graphics2D g2 = ((PGraphicsJava2D)g).g2;
    g2.setXORMode(Color.white);
    // draw cursor
    g2.setPaintMode();

then repeat exactly to erase.
Re: XOR drawing mode (without loadPixels/updatePix
Reply #9 - Jan 5th, 2009, 10:15pm
 
davbol wrote on Jan 3rd, 2009, 5:25pm:
If using JAVA2D renderer, you could try something like:
Code:

Graphics2D g2 = ((PGraphicsJava2D)g).g2;

then repeat exactly to erase.


When I try your suggestion to use the Java2D XOR drawing mode, this line of code (above) gives this error message (Processing 1.0).  I am using JAVA2D.  Any suggestions?  I feel like I am close to a real solution!

Code:

java.lang.NullPointerException at sprite_demo.<init>(sprite_demo.java:40)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
at java.lang.Class.newInstance0(Class.java:350)
at java.lang.Class.newInstance(Class.java:303)
at processing.core.PApplet.main(PApplet.java:6486)

Re: XOR drawing mode (without loadPixels/updatePix
Reply #10 - Jan 6th, 2009, 5:18pm
 
djones wrote on Jan 5th, 2009, 10:15pm:
Code:

java.lang.NullPointerException at sprite_demo.<init>(sprite_demo.java:40)



It should run on 1.0/1.01, what's the specific code that occurs on line 40?

Also, aside, check that you're not mixing and matching techniques...  If you're still using get/set then you're essentially bypassing JAVA2D's Graphics2D object and operating directly on its pixels, thus xor mode won't have any effect -- you need to be "drawing" (things like lines, rects, ellipses, etc) in order for this trick to work.
Page Index Toggle Pages: 1