7

In real-time games, there is always a game loop that runs every few milliseconds, updates the game with new data and repaints the entire screen.

Is this something that is seen in other types of applications, other than games? A 'constant-update-loop'?

For example, imagine an application like MSPaint. The user can draw lines on the screen with the mouse. The line that is being drawn is displayed on the screen as it is being drawn.

Please imagine this line is actually made of a lot of smaller lines, each 2 pixels long. It would make sense to store each of these small lines in a List.

But as I said, the line that is being drawn (the large line, made out of lots of small lines) is displayed as it is being drawn. This means that a repaint of the screen would be necessary to display the new small line that was added the previous moment.

But - please correct me if I'm mistaken - it would be difficult to repaint only the specific part of the screen where the new small line was drawn. If so, a repaint of the entire screen would be necessary.

Thus it would make sense to use an 'update loop' to constantly repaint the entire screen, and constantly iterate over the list of lines and draw these lines over and over again - like in games.

Is this approach existent in non-game applications, and specifically in 'drawing' applications?

Thanks

  • 5
    Part of Windows runs in a loop... the message loop that constantly pumps messages about when is happening in a given window. Does that meet your criteria? – Simon Whitehead Feb 15 '14 at 14:48
  • 3
    All desktop applications do run in what's typically called an "event loop". In most cases, this is handled by the framework (.NET, Qt, etc) and transparent to the programmer, but the raw Windows API is an exception. See the Wikipedia article: en.wikipedia.org/wiki/Message_loop_in_Microsoft_Windows – user16764 Feb 15 '14 at 18:07
12

In games constant redrawing makes sense, because it is rare for whole image not change than small part of it.

Then there is case of UI, in which redrawing just part of the screen is exceedingly common. When you push button, only the visual of the button changes, and not anything else. So it makes sense to redraw just the button. Rest of the screen is saved in static image. Many of the visual glitches actually come from partial UI update. It is actually not that difficult.

Drawing applications are somewhere in the middle. They don't need constant updates but on the other side, when they do update, they update the whole image. For example 3D editors use pseudo-loop that only runs while user is editing the model but otherwise stays still. Also, modern graphics cards allow composition of multiple layers of images so whole image consists of many small images and changes are done to those small images, but the whole image is repainted every time small change occurs. Many 3D accelerated UI frameworks are like that. But this redrawing might also happen only when something changes. Constantly redrawing a screen when nothing changes eats too much energy.

To sum it up, this issue is much more complex than having or not having a loop that constantly updates the screen. But generally speaking, games are only software that actually need such constant updates. Everything is fine with on-demand updates.

  • I see. So basically, in drawing applications it's pretty common to see "constant-update-loops" - that run only when the user is drawing the screen? AKA, when a user isn't drawing things on the screen, the loop doesn't run. But when he/she is drawing things, the loop starts running, and constantly repaints the entire drawing area. Did I understand correctly? – user3150201 Feb 15 '14 at 11:59
  • That's definitely not how Photoshop works. You can see the UI update small tiles of the image as you paint over it. They do a lot of work to make sure they aren't painting where they don't need to be. – user1118321 Dec 9 '17 at 16:56
5

Take note that most of what happens in your computer is based on some kind of such a "game-like" loop. For example take your video card. The Open GL library taps into it via such a loop, and the Open GL API gives you hooks into that loop (like call-back functions for certain parts of the loop, when it's idle, when it's about to run etc). In fact, when you make a game using open GL, you have the option of not making the graphics-refresh part of te game loop "by hand" at all, and just letting the Open GL loop drive your game's graphics refreshing.

Similarly, JavaScript in the browser already creates a similar loop for you. This is something that is part of HTML5, and this particular API is not final now. It's called "requestAnimationFrame" and it basically promises to notify a function of your choice, each time the system is ready (about to) refresh the graphics (and you can only update the graphics-related state at this point, so as to compute it only when necessary, aka only when it is possible to make it visible via a new graphics refresh).

As for the issue of whether it's better to update only a portion of the screen or all of it, I believe the preferred option is to redraw it all, for multiple reasons (some of which you also mention):

  • avoid "flickering-like effect". The new screen is drawn "off-screen" completely, and only when its creation is done, is he actually shown on screen (double-buffering). This is because if it were to be drawn in real time, those real-time computations may make it that it takes too long for the drawing to happen, and this may be perceived as a "screen-flicker" by the user
  • in certain contexts it may be easy to quickly compute which part of the screen has been modified, and only repaint that. For example Java's Swing library allows you to do that (basically declare a rectangular sub-area of the screen which you want to update). Things can gen tricky fast, if everything can potentially move on the screen (as a contrast to your line-drawing example, imagine a game like Starcraft, where the player can scroll around the game area at any moment, thus rendering the whole screen "obsolete").
  • certain platforms don't support this partial screen refresh. For example certain Open GL implementations may offer non-standard ways to do this, but then you get tied in to that certain implementation, you lose portability... it's not great.

At any rate, IMHO, the purpose of the game-loop is not simply to give you "continuous screen refresh" due to the ever-changing, real-time ways in which games behave. As I said, such a "best effort" infinite refresh loop is already present in many platforms (add Java's Swing to those mentioned above). The game loop's main point is to regulate that loop, to make sure that no matter what happens, certain things move at a fixed speed. That a 3 seconds animation will always run in 3 seconds (even if this means skipping some parts of it on slower computers). This is very crucial for games, you can't have a player execute a complex, 15 buttons combo, and not have its animation run exactly at the same speed each time (and on as varied hardware as possible).

Obviously, other types of applications may require this kind of precision as well (and hence, need to implement something very similar to a game loop to achieve it). Imagine you make a word text processor, and for some reason you think it's a good idea to have a paper-clip-like character pop up and talk to the user. Now let's say you deem it acceptable that the initial pop-up animation for this guy should run in 2 seconds (a word processor user doesn't want to spend time looking at animations - apparently). You want to make sure that that animation will be 2 seconds long on either a ultra-portable laptop, as well as on a heavy gaming rig. The game loop, with it's ability to constantly self-regulate it's state-refresh-rate is perfect for achieving this.

0

By "game loop", I'm assuming a loop which doesn't block (doesn't put the thread to sleep, e.g.) and has things to process regardless of whether there are new OS events. In Windows, that would be like an application that uses PeekMessage instead of GetMessage. PeekMessage is non-blocking and won't put the thread/process to sleep even if there are no events in the queue to process.

It's also only a relevant concept in multitasking environments. In the DOS days, practically every GUI application that didn't finish and close on its own without user input had a loop in the main entry point doing things like polling hardware for input. The idea definitely wasn't reserved primarily for games back then.

Game loops would be overkill for 99.999% of paint applications if not all, since there's nothing meaningful to process when there's no user input. If I go away from the computer with MS Paint open, it shouldn't be doing anything behind my back. It shouldn't take any CPU cycles at all. The only time the software has something to do is when I'm interacting with it, like clicking and dragging on the canvas.

Meanwhile games have to process all kinds of things going on many times per second even if you step away from the computer. Enemies will still continue to run at you, try to kill you, etc. regardless of whether you're pushing buttons or not. Unless the design is multithreaded at a broad design level, often the design that makes the most sense is simply avoid blocking functions in event processing (including blocking functions with timer events since those still tend to suffer from latency issues).

A non-game application which might benefit from the game-style loop might be a video player, at least while a video is playing. There it has many frames of video to render and audio to play even when you step away from the computer while playing your favorite movie. Ancient Win32 examples at least avoided blocking in their event processing to render the video that was constantly playing.

But - please correct me if I'm mistaken - it would be difficult to repaint only the specific part of the screen where the new small line was drawn. If so, a repaint of the entire screen would be necessary.

This is completely independent of game looping concepts, just efficient redrawing, but it's not so difficult to avoid redrawing everything any time anything changes, especially in a 2D context like this one.

A crude but very effective technique is partition your canvas into a grid, with each cell containing, say, 64x64 pixels. Whenever you modify a shape or insert or erase one, mark the cells of the grid they belong to as needing to be redrawn. For simplicity you can just look at the bounding rectangle of each shape instead of doing fancy intersection tests to figure out what cells it occupies.

Now when you render the results, just repaint the cells that were marked as needing to be redrawn. This is similar to marking each and every pixel that needs to be redrawn, except that tends to be too granular and requires working with too much data to the point where it could be just as slow or slower than redrawing everything. After all, if you're rendering lines with Bresenham, most of the cost is in figuring out which pixels to plot, so you wouldn't gain anything by marking each individual pixel the line drawing function has to paint yet again.

So instead we work with coarser grid cells that span, say, 64x64 pixels each to mark as needing to be redrawn or not, and work with the bounding rectangles of shapes to determine what cells they occupy. Simple diagram to illustrate:

enter image description here

Each 64x64 cell need store nothing more than a boolean to indicate whether or not it needs to be redrawn if it's only used for drawing purposes, and can simply be 1-bit.

This grid can also double over as a useful way to query what shape is under the mouse cursor without looping through every single shape in the entire canvas. If you use it to accelerate things like this, then each cell can be a singly-linked list pointer (which could be a 32-bit index). For 2D video games, it's also useful for collision detection.

It also allows your back buffer to simply be the size of a grid cell, like 64x64 (4096) pixels instead of having to match the entire size of the window, since you can just draw to a 64x64 image and blit it to the window. If you want to render multithreaded, then you still only need a 64x64 tile to use per thread before blitting it and returning it to the "tile/image bucket pool". That can really minimize memory use and make your painting application just take, say, 24 kilobytes in RAM as opposed to megabytes if you had a 2560x1440 (3,686,400) pixel back buffer for a maximized window. I'm not sure if people really care much about that these days. I'm still stuck to my old habits and still find a lot of aesthetic value in having applications that take kilobytes of RAM, barely any disk space, and open and close in the blink of an eye. I don't find that so time-consuming to achieve if you can come up with core data structures that efficiently fulfill many needs at once in with very little mem use as in this case.

A fancier solution is to allow each cell in the grid to subdivide as needed, at which point you get a quad-tree. However, in practice, I find grids to outperform quad-tree implementations at least for my needs which usually revolve around very dynamic inputs with millions of elements moving around all the time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.