Is there a way to draw to the screen faster with StdDraw in java?

531 Views Asked by At

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!

2

There are 2 best solutions below

0
On

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
0
On

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();

}