Drawing Large Image: Out of Memory

I’m building an isometric map editor that uses a large gif (5000x3000) as the base/ground layer. Before rendering the image to the screen I create a subImage so that I’m only drawing the portion of the image that is necessary.

The memory problem I’m having appears to be coming from the setPrefferedSize call I use on my jPanel. I want to create the jPanel as 5000x3000 pixels so that the scrollPane knows how large the scrollbars need to be. (The viewport of the scrollPane is the jPanel). The program crashes with a “java heap size” error before I can get anywhere close to 5000x3000.

So obviously using this approach sucks way too much memory. Maybe I’m not handling the scrollpane correctly? I’ve never tried creating a scrollpane on this large of an image before so it’s never been an issue.

My guess is that the jPanel shouldn’t be any larger than the screensize and that there is a better way to handle the size of the scrollpane.

(On a side note, just joined the forums today. I’ve worked with a fair amount of isometric stuff so if anyone has iso questions I may be able to help. My current project is rebuilding an old iso editor that I did in C many years ago.)

I’ve used large JPanels without problems, so I expect the problem is the size of the image.

If it was me, wouldn’t use an image for the background. Instead I would override JPanel.paintComponent(Graphics g). You can call Graphics.getClipBounds() to see what needs painting.

I’m already overriding the paintComponent on the jPanel for all my rendering. However, whether I actually draw an image to the screen or not, as soon as I try to create a jPanel much larger than 2500,3000 I start getting memory errors. At some large sizes the memory error will go away and instead the scroll bars will disappear entirely (whether they are set to always display or not)

The code is simple:

int h = background.getHeight(null);
int w = background.getWidth(null);
System.out.println(“w:”+w+" h:"+h);
jPanel1.setPreferredSize(new java.awt.Dimension(w,h));

The width,height = 5000, 3000.

You have been able to use large jPanels without any problems? Were you using a scrollpane on top of it?

I think it might have been JComponent not JPanel I extended. It was in a scrollpane.

Here’s just a follow up on this issue:

Turns out increasing the heap size did resolve the problem. I’m building my app in websphere and was adding the “-Xms128M -Xmx256M” flags to the Program Arguments instead of the VM Arguments.

Just FYI in case anyone else runs into this.

seems like the demand for that much memory came from the swing-backbuffer…

I wouldn’t use a JScrollPane for stuff like that.

“-Xms128M -Xmx256M”

Using that much memory for a simple 2d editor is a bad joke. It’s the amount of memory you would need for Quake3 and GTK Radiant (a Q3 editor).

Well, a scroll pane isn’t that nice for navigation anyways. Try using the right mouse button for dragging the map. A lot of 3d editors use that technique and it really make things easier (I’m using it for a 2d poly loop editor). Say, you build some stuff and reach the end of the viewport… hold the button… drag over… and continue where your cursor is right now - easy! With scroll bars you have a much longer way to travel especially if you want to move the viewport diagonally.

Believe me - it’s much better. You’ll save a lot of time, if you implement it like this.

I definately like the idea of a draggable window and was planning on adding that in sometime in the future. But since you brought it up, now seems like as good as time as any.

I’m going to opt for the hold down control and left mouse button to drag. This is ala Quark (and probably many other programs)

The 128/256 flag for memory isn’t a requirement for the editor by any means. I just wanted to set a high boundary so I wouldn’t have to bother with it later. But out of curiosity, what would you consider a reasonable amount of mem to be using for a 2d editor?

The default (max 64mb ram) should be perfectly fine.

You only need a backbuffer with the size of the viewport… some room for hundreds of tiles… some room for the programm itself… and some bytes to store the map. Everything added up isn’t that much. You could load more than 10k 32x32 tiles without reaching the maximum :slight_smile:

On the topic of screen dragging …

Has anyone implemented this in an editor? I’ve got the methods to grab the mouse coordinates and the current scroll position on the map. My code sort of works in that while the mouse button is held down I can drag in any direction. But when I let go and press again to drag the map always jumps back to the top left corner.

The basic idea I’m trying to use is subtract the last mouse coordinates from the current mouse coordinates … I believe the problem is that mouse coordinates are measured in screen space while the map coordinates (also measured in pixels) are much larger. Somehow this needs to be accounted for …


public void mouseDragged(java.awt.event.MouseEvent e) {
dragPoint = e.getPoint();

int dpx = (int)dragPoint.getX() - (int)lastDragPoint.getX();
int dpy = (int)dragPoint.getY() - (int)lastDragPoint.getY();

if (dpx>5000) dpx = 5000;
if (dpy>3000) dpy = 3000;
if (dpx<0) dpx=0;
if (dpy<0) dpy=0;

dragPoint.setLocation(dpx,dpy);
System.out.println("DPX: “+dpx+”, DPY: "+dpy);

                          jScrollPane.getViewport().setViewPosition(dragPoint);

lastDragPoint.setLocation(dragPoint);
}

I’d also like to freeze mouse movement while dragging, which if accomplished would change the way I need to calculate screen dragging.

An old C library I use to use (Allegro) had something called mouse “mickeys” I believe. They tracked the positive/negative movement of the mouse since the last time the function was called.

Any ideas?

There is no need to restrict the area to 3000x5000. Restrictions are bad, because you can notice after 2 hours that you should have started the map a bit more to the left (or right).

But but… yea, I know. But there is no need to use the same data representation for both (editor+game). Use a structure which is easy to modify in the editor and one which is fast to jump through in the game. It doesn’t matter if you use somewhat inefficient structures to hold your data, because no one cares if the editor runs with 20fps or 200.

For dragging… use an x/y offset which starts at 0/0… and just add the dragging values to it (MousePressed… relx=e.getX();… MouseDragged… x_off+=e.getX()-relx;).

And freezing mouse movement… why??? That would just force the user to move the mouse back to that position where he/she stopped editing. It would also mean that the user would need to physically reset the mouse position (lift/move/put down) every once in a while, because he/she would be sooner or later unable to reach every spot of the screen.

You’re definitely right about creating map restrictions. In the end I won’t be hard coding those values.

And after thinking more about the mouse freezing idea I realized it didn’t make sense. For some reason I was thinking that was the standard approach that many apps used.

Still having problems getting the dragging to work. It should be really easy, so I must be overlooking something. I’ll post some code when I get it working.

Thanks

Looks like I’m going to need help on this dragging stuff. I almost have it working … For some reason when I am holding the mouse down and start to drag back in the opposite direction it doesn’t start shifting back that way immediately. Instead it won’t start shifting back until it “overcomes” whatever distance I just made it drag the opposite way. This seems absolutely bizarre to me. I determined the dpx and dpy below is the culprit. These are derived straight from the mouse pointer yet will continue to increase even when I begin moving back in the negative direction. This makes me think its not a calculation problem so much as it is how the logic is structured.

Any help would be much appreciated. I’m stuck …

jPanel1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseDragged(java.awt.event.MouseEvent e) {
// grab and store current mouse coords
Point pt = e.getPoint();
dpx = pt.x;
dpy = pt.y;

// this is the change in mouse position
changeX = dpx - lastDPX;
changeY = dpy - lastDPY;

// store current mouse coords for next run through
lastDPX = dpx;
lastDPY = dpy;

// add the mouse change to the scroll position of the panel
int scrollToX = getXScroll() + changeX;
int scrollToY = getYScroll() + changeY;

// some bounding stuff - ignore
if (scrollToX>5000) scrollToX = 5000;
if (scrollToY>3000) scrollToY = 3000;
if (scrollToX<0) scrollToX=0;
if (scrollToY<0) scrollToY=0;

// put the new mouse coords into Point component
dragPoint.setLocation(scrollToX,scrollToY);

// update view position
jScrollPane.getViewport().setViewPosition(dragPoint);

// for debugging
jLabel5.setText("px: “+dpx+”, "+dpy);

}

Ye… as I said before… you need mousePressed and mouseDragged in order to get relative drag coords.

public void mousePressed(MouseEvent e){
relx=e.getX();
rely=e.getY();
}

public void mouseDragged(MouseEvent e) { x_off+=e.getX()-relx;
y_off+=e.getY()-rely;
}

x_off, y_off, relx, rely… are all ints initialized with 0.

Eg if you drag from 200/250 to 180/260… you add -20 to x_off and 10 to y_off :slight_smile:

edit: depending on how you draw it you might need to add a repaint() at the end of mouseDragged.

With a slight change in the calculation you provided I got the dragging working. Here is the code I’m using in its fully functioning entirety. Thanks for your help

public void mouseDragged(java.awt.event.MouseEvent e) {
Point pt = e.getPoint();
int dpx2 = pt.x;
int dpy2 = pt.y;

  changeX = dpx - dpx2;
  changeY = dpy - dpy2;
  System.out.println("chg: "+changeX+" "+changeY);
                          
  int scrollToX = getXScroll() + changeX;
  int scrollToY = getYScroll() + changeY;
                                            
  if (scrollToX>5000) scrollToX = 5000;
  if (scrollToY>3000) scrollToY = 3000;
  if (scrollToX<0) scrollToX=0;
  if (scrollToY<0) scrollToY=0;
                    
  dragPoint.setLocation(scrollToX,scrollToY);

  jLabel5.setText("px: "+scrollToX+", "+scrollToY);
  jScrollPane.getViewport().setViewPosition(dragPoint);

}

public void mousePressed(java.awt.event.MouseEvent e) {
Point pt = e.getPoint();
dpx = (int)pt.getX();
dpy = (int)pt.getY();
System.out.println(“mousePressed(”+dpx+":"+dpy+")"); // TODO Auto-generated stub mousePressed()
}