Hi people. Once again, newbie requires your help
Let's see if I can make me clear. English isn't my mother tongue, so I apologize in advance.
Well, I'm writing this very simple app where an image is shown. If the user clicks and drags the mouse, a new underlying image will be unveiled, but only on those points where the mouse has passed by. So it would look like if we were having three layers in photoshop, and we were brushing off the one on top. The result is that we would be able to see the underlying one only at the mouse's track.
I'm aware that it's not the best explanation, but I guess the code would clarify it a bit
Well, my problem is that after writing such a program, the code that runs is DAMN SLOW. What I basically do is to print a circle (the rubber/brush stroke) of a certain dimension pixel by pixel, accesing the pixels array of the image that I want to show. And there it is the problem. The bigger it is the radius of the stroke, the slower it becomes the program.
I tried many approaches. Tried to use P2D anda JAVA2D, but OPENGL turned out to be slightly faster on this. Tried as well to deactivate the error management in OPENGL, since I read that it's performance consuming, but still, no big improvements. I also tried to print each pixel in different ways, like 1x1 rects, 1x1 ellipses, point, etc. The one that seemed to work better was the rect approach, but anyway, I never manage to get more than 30 FPS at a 1600x1200 resolution (it actually drops from 300 FPS to 30 FPS!!).
I tried another different approach, which was using the method get, and printing a square section of the new image as big as the radius that I had defined. It works really smoothly this way, but I still need the effect of a circular stroke since the app is going to be used together with a tablet.
So to summarize, what I'm asking is for advice about how to optimize my code, and if it's not possible, some recommendation in general.
I was opening the task manager while playing with the sketch, and I realized that the processor was having no more than a 60% of load. Could it be possible as an approach to push the JVM to use all the resources available?
Anyway, here is the simplified version of the code. You should put a couple of images in your own for it to work. Resolution 1600x1200 pixels. Another thing is that if you press ENTER, you switch from the
get mode to the
pixel by pixel with recs mode, so you can easily compare performance between both. Hope it helps:
Code:import processing.opengl.*;
int BRUSH_RADIUS = 30;
boolean WITH_GET = true;
PImage baseLayer, newLayer;
void setup(){
// Engine
size(1600,1200,OPENGL); hint(DISABLE_DEPTH_TEST); hint(DISABLE_OPENGL_ERROR_REPORT);
// Options
noStroke(); frameRate(300);
// Load images
baseLayer = loadImage("layer1.jpg");
newLayer = loadImage("layer2.jpg");
// First image
image(baseLayer, 0, 0);
}
void draw(){
int x = mouseX;
int y = mouseY;
if(mousePressed){
// Circular shape by drawing pixels/(1x1)squares. Slow performance.
if(!WITH_GET){
for(int i = x-BRUSH_RADIUS; i < x+BRUSH_RADIUS; i++)
for(int j = y-BRUSH_RADIUS; j < y+BRUSH_RADIUS; j++){
if(checkPoint(x, y, i, j)){
// Get pixel from the new layer
color c = newLayer.pixels[j*width + i];
// Print pixel on the screen
pushStyle();
fill(c);
rect(i,j,1,1);
popStyle();
}
}
}
// Square shape. Fast performance.
else{
PImage tmp = newLayer.get(x - BRUSH_RADIUS, y - BRUSH_RADIUS, 2*BRUSH_RADIUS, 2*BRUSH_RADIUS);
image(tmp, x - BRUSH_RADIUS, y - BRUSH_RADIUS);
}
}
}
// Discards the points that dont belong to the circle with center (centerX, centerY) and radius BRUSH_RADIUS
boolean checkPoint(int centerX, int centerY, int pointX, int pointY){
float pointValue = sq(pointX - centerX) + sq(pointY - centerY);
if (pointValue < sq(BRUSH_RADIUS) && (pointX >= 0) && (pointX < width) && (pointY >= 0) && (pointY < height))
return true;
else return false;
}
// Pressing enter toggles rendering mode
void keyPressed(){
if(keyCode == ENTER)
if(WITH_GET)
WITH_GET = false;
else WITH_GET = true;
}
Thank you very much for all your help in advance. I mean it!
/F