0

I am using the StdDraw library from https://introcs.cs.princeton.edu/java/stdlib/StdDraw.java. To my knowledge it just implements a simple interface for drawing to the screen using JFrame.

In my implementation, I simply have a 2d array of pixels, and I am drawing each one like so:

StdDraw.clear()
for (int y = 0; y < Engine.HEIGHT; y += 1) {
    for (int x = 0; x < Engine.WIDTH; x += 1) {
        map[x][y].draw((float) x / Engine.WIDTH, (float) y / Engine.HEIGHT);
    }
}

This, however, is extremely slow. Like insanely slow. Not to mention that I have to redraw the entire screen every time I want to update it.

I clear the screen and then redraw every pixel. There is no way this is how it supposed to work, but I just don't really know where to look. Some suggestions on what I should look out for would be really helpful!

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
yeeshue99
  • 238
  • 2
  • 8
  • 1
    If you're willing to use plain Java Swing, the Oracle tutorial, [Performing Custom Painting](https://docs.oracle.com/javase/tutorial/uiswing/painting/index.html) will show you how to draw on the drawing JPanel with Graphics and Graphics2D methods. – Gilbert Le Blanc May 06 '21 at 16:31
  • 1
    Draw yourself for a better understanding of event driven drawing. It is not difficult to override a JPanel's paintComponent and draw yourself. Pixel drawing _is_ slow. You may draw an image instead, and fill the BufferedImage using its createGraphics. – Joop Eggen Jun 29 '21 at 11:18
  • Joop's advice to look into using BufferedImage is good. But you haven't explained what `map` is. It's a two-dimensional array, but of what? Which class's `draw` is being called? It could be that the draw is fast (unlikely) and getting to it through map is slow (unlikely). However unlikely, we want to eliminate ambiguities in case a cause is hiding among them. – Alan Jun 29 '21 at 14:18
  • It looks like you are using Princeton's StdDraw library. But there is no ".draw" in it. https://introcs.cs.princeton.edu/java/stdlib/javadoc/StdDraw.html Are you mixing classes? – Alan Jun 29 '21 at 15:34

2 Answers2

1

This is not the final answer, but a way to put some measurable code on the table. BufferedImage is the way to go, but for reference on my not-too-fast system, this code takes 5 seconds to draw 40 million pixels, or 125 milliseconds per megapixel. How may pixels do you have?!? This code uses a call to line as a proxy for drawing a single pixel because the class doesn't offer single pixel drawing, but theoretically code that draws an actual pixel like you do should be faster.

What class is YOUR map?

How many pixels?

What amount of time is "insanely slow"?

public class SandBox {


    public static void main (String [] args) {

        boolean [] [] map = new boolean [1000] [1000];
        for (int i = 0; i < 1000; i++) {
            for (int j = 0; j < 1000; j++) {
                map [i] [j] = true;
            }
        }
        JFrame myFrame = new JFrame ();
        myFrame.setSize (1100, 1100);
        SPanel myPanel = new SPanel ();
        myPanel.myMap = map;
        myFrame.add (myPanel);
        myFrame.setVisible (true);
    }

} // class SandBox


class SPanel extends JPanel {

    public boolean [] [] myMap;


    @Override
    public void paintComponent (Graphics g) {
        g.drawString ("Hello", 30, 30);
        Instant start = Instant.now ();
        for (int i = 0; i < 10; i++) {
            g.setColor (new Color (0, 0, 0));
            drawMap (g);
            g.setColor (new Color (255, 0, 0));
            drawMap (g);
            g.setColor (new Color (0, 255, 0));
            drawMap (g);
            g.setColor (new Color (0, 0, 255));
            drawMap (g);
        }
        reportElapsed (start);
        g.drawRect (50, 50, 1000, 1000);
    }


    void drawMap (Graphics g) {
        for (int i = 0; i < 1000; i++) {
            for (int j = 0; j < 1000; j++) {
                if (myMap [i] [j] == true) {
                    g.drawLine (i + 50, j + 50, i + 50, j + 50);
                }
            }
        }
    }


    private static void reportElapsed (Instant start) {
        Duration elapsed = Duration.between (start, Instant.now ());
        long millis = elapsed.toMillis ();
        System.out.println ("Duration (ms):  " + millis + ".");
    } // reportElapsed


} // class SPanel
Alan
  • 716
  • 5
  • 15
1

It is simple and it is fast!

But you have to use correct library, i.e Picture.java class available at

https://introcs.cs.princeton.edu/java/stdlib/Picture.java

public static void main(String[] args) 

{
    int SIZE = 250;
    
    Random rnd = new Random();
    
    int[][] mapR = new int[SIZE][SIZE];
    int[][] mapG = new int[SIZE][SIZE];
    int[][] mapB = new int[SIZE][SIZE];
    
    for(int i = 0; i < SIZE; i++)
    for(int j = 0; j < SIZE; j++)
        
    {
        mapR[i][j] = rnd.nextInt(256);
        mapG[i][j] = rnd.nextInt(256);
        mapB[i][j] = rnd.nextInt(256);      }
        
    
    Picture p = new Picture(SIZE, SIZE);
    
    for(int i = 0; i < SIZE; i++)
        for(int j = 0; j < SIZE; j++)
            
            p.set(i, j, new Color(mapR[i][j], mapG[i][j], mapB[i][j]));
    
    p.show();

}