Hands-on Rust: Explain coordinates (page 50)

I think it would be beneficial to shortly explain how the “screen-space coordinates” work or that the proposed system is some sort of simplification. Because the book instructs to create 80x50 window, but how many pixels is the height ? is it 200 or maybe 500 ? i noticed that the set method of console mentions cell, but what is it ?

Hi!

I avoided going into exact pixel placement, because it’s a much bigger can of worms than you’d expect - and Hands-on Rust avoids using pixels parameters.

Say you request an 80x50 grid and are using the default 8 pixel by 8 pixel font. Each character/cell on the grid is using 8x8 pixels, so your natural window size is 640x400. A small window, pretty much guaranteed to work on whatever computers readers are using.

So that seems simple enough; but later on, we use larger characters on some layers (16x16) and retain small characters on other layers. The window retains a natural size, but the pixel positioning on each layer is automatically varied by the library so you don’t need to worry about exact pixel positioning.

Now, what happens if the user resizes the window? By default (you can change this behavior in the library builder calls) it scales. So your 8x8 character might be pretty much any size. If the user made the window really wide and short, you might suddenly have 16x6 characters. Your window pixel positioning is now 1,1280 x 300 in pixels. The console library lets you continue to treat it as an 80x50 grid (unless you disabled the scaling, in which case the grid size changes and you have to query it) - so you don’t have to worry about it so much.

Even more convoluted, what if the user has display scaling enabled? The “logical” window may still be 640x400, but with display scaling it could well actually occupy 1,280 x 800 (at 2x) or 960 x 600 (at 1.5x). It gets really scary when you have multiple monitors with different scaling settings and the window is dragged across the monitor boundary. (There’s altogether too much glue code in bracket-lib’s guts to handle things like that)

It’s pretty uncommon for modern graphics libraries to operate in exact pixel coordinates for this reason. Between resizing, DPI scaling, etc. it gets pretty hard to nail down exactly what a pixel is and how it is addressed. Instead, you tend to see a “virtual resolution” and matrices (in the GPU pipeline) that scale your virtual resolution to the actual physical viewport. In OpenGL, the “normal” matrix transforms treat the screen in floating point from -1.0 to 1.0 on each axis and your “camera” (really a set of matrix math to move the world around where you are looking) is designed to project the coordinates you want to use into that range. Vulkan and similar give you a lot more flexibility to define your coordinate schemes, but it’s still relatively unusual to be doing pixel-perfect placement outside of a virtual representation of your preferred pixel grid. 2D engines that utilize the GPU for rendering sometimes set the “virtual” pixel size to align with window size - but even they are abstracting away the “oh no, 1 pixel is scaled to be 1.5 pixels!” headache for you.

Lastly:
A cell is a character on the console grid, including glyph, foreground and background colors (and other attributes on some console types that the book doesn’t use). I’ll see if I can make that a bit clearer in the library documentation.

What you said makes a lot of sense and i didn’t know that such handling is the standard (which clearly solves quite a few problems).

Thanks a lot, Herbert.

P.S. Great book - really easy to understand.

1 Like