Loading...
Logo
Processing Forum
Hello! I have created an application that loads a set of photos and spreads them by separate windows. Each window has 2 rows and 8 columns of photos. By pressing the "right" and "left" buttons, the "window ribbon" may be scrolled left and right. This is done by first preparing two images by drawing them on PGraphics canvas and copying to separate PImages. Then the same PGraphics canvas is used to draw these images progressing their position so as for the "scrolling" effect to occure. All PImage instances are pre-created, and the copy() method is used to cache the right and left window (there images are too drawn with the copy() method to the canvas) because I know that the renderer caches the images and there is a bug in OPENGL renderer that stores them indefinetely. That first bug took me a weak of sweating while trying to find an error in my code. Finally, I was surprised by finding that topic in the internet that says that it is a bug in OPENGL and that OPENGL2 or present P3D would do fine. I have first reimplemented the render through P3D, it was lagging waaaaay toooo muuuuuch! Then I have downloaded Processing 2.04a and used OPENGL2 (which is named just OPENGL there). Same memory leak! It is not huge, but it builds up and lets only about 50 scrollings to be done.

Could anyone comment on that?

Aside from that, I am interested, how would you implement scrolling? I use the pre-draw method because aside from the images, there are also many other things drawn and the effect that I acheive is that they are not drawn while go partially out of the canvas, the PGraphics cuts it out.

EDIT: Please note that all the other things drawn aside from images are not the cause. Since commenting out the single line responsible for drawing the images, eliminates the used heap growth. I use visualjvm to monitor the condition.

Replies(3)

Post some code that demonstrates the issue?

D.
Ok, the code of the project is too huge to post here, I will try to cut out the related parts of the GUIWindowRibbon class that implements all this.

this is in the GUIWindowsRibbon class variables definition:
Copy code
  1. public GUICanvasGL canvas;
  2. PImage winAnimFrom;
  3. PImage winAnimTo;
  4. PImage animationImg;
the entire code of the GUICanvasGL class is small enough to fit in the post:

Copy code
  1. public class GUICanvasGL extends GUIImage{
  2. //GLGraphicsOffScreen canvas; // NO WORK WITH OPENGL2 SADLY
  3. PGraphics canvas;
  4. public GUICanvasGL(GUIElement parent, float x, float y, float xx, float yy) {
  5. super(parent, x, y, xx, yy);
  6. setGraphics(xx, yy);
  7. }

  8. public void setGraphics(float xx, float yy) {
  9. //canvas = new GLGraphicsOffScreen(Global.applet, (int)xx, (int)yy, false);
  10. canvas = Global.applet.createGraphics((int)xx, (int)yy, PApplet.OPENGL);
  11. }
  12. public PGraphics getCanvas() {
  13. return canvas;
  14. }
  15. public void flip() {
  16. this.setContent(canvas.get());
  17. }
  18. }
Then, continuing the GUIWindowsRibbon class, there is the related part of it's constructor:
Copy code
  1. this.canvas = new GUICanvasGL(this, 0, 0, this.bounds.size.x, Service.height);
  2. winAnimFrom = Global.applet.createImage((int)this.bounds.size.x, (int)this.bounds.size.y, PApplet.RGB);
  3. winAnimTo = Global.applet.createImage((int)this.bounds.size.x, (int)this.bounds.size.y, PApplet.RGB);
Then the GUIWindowsRibbon class method that is triggered upon scroll button press. It prepares the scrolling surface:
Copy code
  1. void startAnimaton(int direction, int indexA, int indexB) {
  2. PGraphics context = canvas.getCanvas();
  3. int sizeX = (int) bounds.size.x;
  4. int sizeY = (int) bounds.size.y;

  5. //////////////////////////////////////////////////////////first window (from)
  6. context.beginDraw();
  7. GUIWindow windowA = getWindow(indexA);
  8. windowA.alsoDrawFor(context, (int) - windowA.getAbsoluteBounds().start.x, (int) -windowA.getAbsoluteBounds().start.y);
  9. context.endDraw();
  10. winAnimFrom.copy(context, 0, 0, context.width, context.height, 0, 0, context.width, context.height);

  11. //////////////////////////////////////////////////////////second window (to)
  12. context.beginDraw();
  13. GUIWindow windowB = getWindow(indexB);
  14. windowB.alsoDrawFor(context, (int) - windowB.getAbsoluteBounds().start.x, (int) -windowB.getAbsoluteBounds().start.y);
  15. context.endDraw();
  16. winAnimTo.copy(context, 0, 0, context.width, context.height, 0, 0, context.width, context.height);

  17. animTimer = Global.timerServer.createTimerGlobal(intervalSlide);
  18. animDirection = direction;
  19. isAnimating = true;

  20. animationImg = Global.applet.createImage(context.width, context.height, PApplet.RGB);
  21. }
Comment: the   windowA.alsoDrawFor and  windowB.alsoDrawFor  methods only draw things like line() and rect(), and an image - for image elements. Needless to say, all images are cached in memory once and are never loaded twice from the hard drive. I have also reimplemented the image drawing statements through copy() to avoid asking the renderer about that, instead doing the pixeldata copying directly.

Then, the related part from the GUIWindowRibbon update method:
Copy code
  1. if(isAnimating) {
  2. float percent = animTimer.getPercent();
  3. if(percent > 1f) percent = 1f;
  4. PGraphics context = canvas.getCanvas();
  5. context.beginDraw();
  6. context.background(0);//.clear(0);
  7. float size = bounds.size.x;
  8. float start = 0;
  9. switch(animDirection) {
  10. case PApplet.LEFT: // <<-- [2][1]
  11. start = - (float)size * percent;
  12. context.image(Global.imageDB.getGUIPart(Image.BG), start, 0);
  13. context.image(Global.imageDB.getGUIPart(Image.BG), size + start, 0);
  14. context.image(winAnimFrom, start, 0);
  15. context.image(winAnimTo, size + start, 0);
  16. break;
  17. case PApplet.RIGHT: // -->> [1][2]
  18. start = (float)size * percent;
  19. context.image(Global.imageDB.getGUIPart(Image.BG), start, 0);
  20. context.image(Global.imageDB.getGUIPart(Image.BG), - size + start, 0);
  21. context.image(winAnimFrom, start, 0);
  22. context.image(winAnimTo, - size + start, 0);
  23. break;
  24. }
  25. context.endDraw();
  26. animationImg.copy(context, 0, 0, context.width, context.height, 0, 0, animationImg.width, animationImg.height);
  27. this.hideChildren();
  28. if(percent >= 1) {
  29. isAnimating = false;
  30. animationImg = null;
  31. winAnimFrom.removeCache(canvas.getCanvas());
  32. winAnimTo.removeCache(canvas.getCanvas());
  33. System.gc();
  34. this.showChildren();
  35. if(!this.showWindowTitles) hideTitlesOfAllWindows();
  36. return;
  37. }
  38. }
And finally, the GUIWindowRibbon class draw method:
Copy code
  1. @Override
  2. void customDraw() {
  3. if(isAnimating){ //animationImg != null) {
  4. Global.applet.image(animationImg, absoluteBounds.start.x, absoluteBounds.start.y);
  5. }
  6. }
I have to say that I have tried all kinds of copy() methods and getTexture() methods and such... only this method allows to see the image (otherwise it is black).
As someone who has battled with Processing's opengl memory leak issues, I can sympathise.

However if you want to have issues fixed towards 2.0 for yourself and all of us, you should:

1. Create a small runnable (!) code example displaying the issue.
2. Search the bug tracker and if it's not already there, add the issue to the bug tracker.
3. Preferably include a zipped version of the code example displaying the issue in your bug report.