Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add synchronized output/update #756

Merged
merged 4 commits into from
Feb 26, 2023
Merged

feat: add synchronized output/update #756

merged 4 commits into from
Feb 26, 2023

Conversation

jcdickinson
Copy link
Contributor

The Contour terminal describes a VT extension for pausing rendering in the terminal during updates, preventing tearing and other artifacts. This extension is already supported by several terminals, with support planned for many others.

See: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036

This adds the two commands related to pausing and resuming rendering: BeginSynchronizedUpdate and EndSynchronizedUpdate. It also adds a utility function that performs a function within a synchronized update.

A demo of this is also provided in the interactive example, that slowly renders a list of numbers - once without synchronized updates, and then once with.

The Contour terminal describes a VT extension for pausing rendering in
the terminal during updates, preventing tearing and other artifacts.
This extension is already supported by several terminals, with support
planned for many others.

See: https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036

This adds the two commands related to pausing and resuming rendering:
`BeginSynchronizedUpdate` and `EndSynchronizedUpdate`. It also adds a
utility function that performs a function within a synchronized update.

A demo of this is also provided in the interactive example, that slowly
renders a list of numbers - once without synchronized updates, and then
once with.
src/terminal.rs Outdated Show resolved Hide resolved
src/terminal.rs Show resolved Hide resolved
@jcdickinson
Copy link
Contributor Author

@TimonPost Thanks for the review! I have fixed the failing doctests

@David-Else
Copy link

@jcdickinson Sorry for asking here, but there is no discussions area in this repo.

I am trying to decide how I will render my game and am not sure the practical difference between using crosterm's stdout.queue followed by stdout.flush()?; and this new execute!(io::stdout(), BeginSynchronizedUpdate)?; functionality? Could they both work together, or if I abandon using the queue command and simply pause rendering at the start of the function and resume at the end maybe I could get better performance and less chance of tearing or jitter?

Thanks for any input you may have!

My render function is very basic, no async, I currently have the following:

pub fn render_screen(&mut self, mut stdout: &Stdout) -> Result<()> {
        stdout.execute(terminal::Clear(terminal::ClearType::All))?;
        
        // print the wall
        for y in 0..self.screen_size.y {
            for x in 0..self.screen_size.x {
                if (y == 0 || y == self.screen_size.y - 1)
                    || (x == 0 || x == self.screen_size.x - 1)
                {
                    stdout
                        .queue(cursor::MoveTo(y as u16, x as u16))?
                        .queue(style::PrintStyledContent("█".grey()))?;
                }
            }
        }

        // print the zombies
        for zombie in self.zombies.iter() {
            std::thread::sleep(std::time::Duration::from_millis(50));
            stdout
                .queue(cursor::MoveTo(
                    zombie.position.y as u16,
                    zombie.position.x as u16,
                ))?
                .queue(style::PrintStyledContent("z".green()))?;
        }

        // print the hero
        for hero in self.heroes.iter() {
            stdout
                .queue(cursor::MoveTo(
                    hero.position.y as u16,
                    hero.position.x as u16,
                ))?
                .queue(style::PrintStyledContent("h".red()))?;
        }

        // draw screen from queued buffer
        stdout.flush()?;
        Ok(())
    }

@jcdickinson
Copy link
Contributor Author

You should probably use them together. The queue is about efficiency, this command prevents "terminal tearing" (almost like vsync tearing). Issue/queue this at the start of your frame, and terminate it at the end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants