Popcar's Hub

Creating GodotOS - Devlog 2

(In which I add viewports and constantly seek help)

In case you didn't read the previous devlog, GodotOS is a fake operating system made in Godot. It's intended to be more of a proof of concept than a real product, and it will be open-source once the prototype is finished. As you might expect, there's a lot to do to make a good desktop-like user interface!

The past two weeks have been eventful. I've added viewports, scaling options, right clicking to open a context menu, file creation and deletion, and more! Let's get into it.

Scaling the screen

Scaling the screen in Godot turned out to be as simple as changing get_window().content_scale_factor. I made a hotkey increase or decrease it by 0.125 whenever you press it. Unfortunately, scaling text turned out to not be so simple. Here's what my text looked like initially after scaling it down a bit:

Ahhh! My eyes!
Screenshot very blurry text.

By default, font rendering in Godot expects your text to stay the same size at all times. Scaling it up looks blurry, and scaling it down looks even worse. Luckily, there is one option tucked away in the settings designed to help: Multichannel Signed Distance Field (MSDF).

MSDF is an obnoxious way to say "font render good regardless of scale". It's very effective and the documentation claims there are no performance penalties for using it, so I'm not sure why it isn't enabled by default. I'm also not sure why most default font settings are in GUI --> Theme rather than GUI --> Fonts in the project settings window.

Either way, text renders beautifully now. The documentation recommends enabling Generate Mipmaps to increase font quality as well, but I found it makes text look fuzzy when scaled down, so I ended up not using mipmaps.

MSDF off / MSDF on

Here's one last fun fact: Godot's default font is Open Sans SemiBold. This is good to know if you'd like to make variants or use the same font elsewhere.

Adding SubViewports

Viewports are basically a window that shows (and allows you to interact with) another scene. The goal is to add viewports into a game window so you can play any game scene on it. Theoretically, any game (or program) created in Godot should be playable through a viewport!

In order to test viewports, I quickly created Pong within my project. This was a bad idea, since I spent more time procrastinating and playing Pong than I have actually implementing viewports.

There were a ton of issues with SubViewports, from handling the aspect ratio to the fact that the game didn't scale with the window (making the window bigger just resulted in Pong getting zoomed out). There were also issues with input handling, and I spent roughly two days researching why that is. I asked around in the Godot Discord, but it seems like very few people actually use viewports, let alone do something complex with it like scaling it on runtime with multiple resolutions and aspect ratios.

After finally admitting I have no idea what I'm doing, I finally asked about in the Godot forums and found a solution! Shoutout to award for helping me.

The solution was actually simple: Use an AspectRatioContainer over the SubViewportContainer (duh!) and set Size 2D Override to be my game's default resolution, while ticking Size 2D Override Stretch on.

This is one part of Godot's documentation that failed me. The description for Size 2D Override only reads "The 2D size override of the sub-viewport." This doesn't say anything about what it does, and I thought this would just mean the size of the SubViewport. What it actually does is change the resolution the SubViewport is rendered in, since the SubViewportContainer handles the actual size. This is a big difference, and I think the name is misleading.

With viewports finally working, here's a finished version of Pong in GodotOS!

Adding a context menu (right clicking)

Creating a context menu turned out to be the most complex thing in the project thus far. I could go on and on about making it, but first let me explain why it was weird to implement.

In Godot, any Control node can see whether the mouse has clicked it or not. However, there is no way for another node to track which Control node was clicked. There's also no way to get Control nodes based on position. All of this means that if I want something to react to being right clicked, I would have to implement it in that Node specifically.

If I want a Folder, Window, Desktop, Image, etc. to show the context menu when I right click, I would have to implement code in each one to handle the right click itself. This makes what I'm doing difficult, so I went to the Godot forums for help. Shoutout to xyz, award, and other participants for helping me reach a solution.

The solution involved adding a component that handles right clicking to any node within the "right_click_enabled" group. The context menu autoload would add this component to any node at runtime. There is definitely a performance hit for doing this, but it's likely so small that nobody would notice. Please consider liking my proposal to fetch Control nodes on mouse click

Right clicking in action!

Quality of Life

I value quality of life almost more than having a working product. Everything should look and feel nice to use. This post is already too long, so here are some highlights:

Such harmony!
Screenshot showing all window types.

And that's it! The next steps are to add some more basic functionality and try to add more animations (such as when a file gets added)

I hope that by the time the next Devlog gets written, the prototype for GodotOS will be out and open source for everyone to play with. Stay tuned.

P.S: Be careful when using OS.move_to_trash(). I accidentally wiped my res:// folder when testing it.

Use version control, kids 💀
Screenshot showing 400+ errors when Godot can't find any files.

Thanks for reading! You can find more updates on this project in the Godot discord / Showcase channel.

Like my content? Consider buying me a cup of kofi.