@Override
    public void run() {
        // Create a new LWJGL window        
        DisplayMode dm = new DisplayMode(
                Settings.Graphics.width, Settings.Graphics.height);
        
        try {
            Display.setDisplayMode(dm);
            Display.create();
        } catch (LWJGLException e) {
            director.interrupted = true;
            System.exit(0);
        }

        // Set the display title
        Display.setTitle(Settings.Graphics.title);
        
        // Setup opengl viewing space
        GL11.glClearColor(0, 0, 0, 0);
        
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glLoadIdentity();
        GL11.glOrtho(0, maze.getWidth(), maze.getHeight(), 0, -1, 1);
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

        // Initialize drawTime with offset for instant first draw
        long drawTime = -Settings.Graphics.drawWaitTime + System.currentTimeMillis();
        
        // Update loop      
        while (!director.interrupted && !Display.isCloseRequested()) {
            // Only draw at certain delta time
            if((System.currentTimeMillis() - drawTime) > Settings.Graphics.drawWaitTime) {
                // Draw to screen
                GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

                // Draw the maze
                drawMaze();

                // Draw best route so far
                GL11.glLineWidth(Settings.Graphics.lineWidth);
                GL11.glColor3f(
                        Settings.Graphics.lineColor[0],
                        Settings.Graphics.lineColor[1],
                        Settings.Graphics.lineColor[2]);
                drawPath(director.getBestRoute());

                // Process input
                handleInput();

                // Update screen
                Display.update(false);
                
                drawTime += Settings.Graphics.drawWaitTime;
            }
            
            // Process messages and sync
            Display.processMessages();
            Display.sync(Settings.Graphics.framesPerSecond);
        }
        
        Display.setTitle(Display.getTitle() + " | STOPPED!");

        // Stop maze iterations
        director.interrupted = true;

        // Keep showing until closed again
        while (!Display.isCloseRequested()) {
            handleInput();
            Display.processMessages();
            Display.sync(Settings.Graphics.framesPerSecond);
        }

        // Destroy the window
        Display.destroy();

        // Thread ends here
        Helper.log("Display destroyed");
    }