title: Drawing thousands of shapes with Java2D efficiently?
body: <p>I have an issue with drawing potentially hundreds of thousands rectangles with Java2D.</p>
  
  <p>At first what I did was something along these lines:</p>
  
  <pre><code>private void render() {
     BufferStrategy bs = getBufferStrategy();
     if (bs == null) {
        createBufferStrategy(3);
        return;
     }
  
     Graphics g = bs.getDrawGraphics();
     //Draw Graphics here
     g.dispose();
     bs.show();
  }
  </code></pre>
  
  <p>I then realized after testing that this was horribly inefficient when having anything above 500 rectangles, so I thought that maybe drawing the graphics to a BufferedImage then displaying the BufferedImage would be more efficient, so I came up with this.</p>
  
  <pre><code>private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  
  private void render() {
     BufferStrategy bs = getBufferStrategy();
     if (bs == null) {
        createBufferStrategy(3);
        return;
     }
  
     Graphics g = image.createGraphics();
     //Draw Graphics here
     g.dispose();
  
     Graphics g2 = bs.getDrawGraphics();
     g2.drawImage(image, 0, 0, width, height, null);
     g2.dispose();
     bs.show();
  }
  </code></pre>
  
  <p>However this was still just as inefficient as the first way, I'm having trouble thinking of a better way to do this, and I'd prefer to stay away from something like OpenGL for this.</p>
  
  <p>At between 500-1000 rectangles it gets really slow, and anything above that the program freezes very quickly.</p>
  
  <p>So it would seem collision detection seems to be the main problem, rather than Java2D rendering. This is how I've handled the detection, it checks if two rectangles are touching on any side. If someone has a better approach to this I would appreciate it, because I'm seeing how inefficient this is.</p>
  
  <pre><code>public boolean collides(Entity e) {
      Point2D upperLeftIn = new Point2D.Double(bounds.getX() + 1, bounds.getY());
      Point2D upperRightIn = new Point2D.Double(bounds.getX() + 8, bounds.getY());
      Point2D lowerLeftIn = new Point2D.Double(bounds.getX() + 1, bounds.getY() + 9);
      Point2D lowerRightIn = new Point2D.Double(bounds.getX() + 8, bounds.getY() + 9);
  
      Point2D upperLeftDown = new Point2D.Double(bounds.getX(), bounds.getY() + 1);
      Point2D lowerLeftUp = new Point2D.Double(bounds.getX(), bounds.getY() + 8);
      Point2D upperRightDown = new Point2D.Double(bounds.getX() + bounds.getWidth(), bounds.getY() + 1);
      Point2D lowerRightUp = new Point2D.Double(bounds.getX() + bounds.getWidth(), bounds.getY() + 8);
  
      Line2D top = new Line2D.Double(upperLeftIn, upperRightIn);
      Line2D bottom = new Line2D.Double(lowerLeftIn, lowerRightIn);
      Line2D left = new Line2D.Double(upperLeftDown, lowerLeftUp);
      Line2D right = new Line2D.Double(upperRightDown, lowerRightUp);
  
      if (e.bounds.intersectsLine(top)) {
          return true;
      }
      if (e.bounds.intersectsLine(bottom)) {
          return true;
      }
      if (e.bounds.intersectsLine(left)) {
          return true;
      }
      if (e.bounds.intersectsLine(right)) {
          return true;
      }
  
      return false;
  }
  </code></pre>