ClassiCube icon indicating copy to clipboard operation
ClassiCube copied to clipboard

Discussing major changes to GUI rendering and scaling

Open bunabyt3 opened this issue 1 month ago • 3 comments

I was playing with the ClassiCube client and I noticed some issues with the GUI. For one, elements like the menu, chat, hotbar, and crosshair use completely different scaling factors that the user has to fix manually. It might even be impossible to fix because of the limitations of the number input system. I'm going to suggest some improvements to the GUI renderer that should finally fix these issues at their core.

The Minecraft approach

In Minecraft (which this project is undeniably based off of), the GUI is rendered to a(n approximately) 320x240 "screen". From there, the GUI "screens" (which usually contain a background, text, buttons, and other UI elements) are scaled based on the user's preference and placed in the correct spot on the user's real, arbitrarily-sized screen. This, for example, is vanilla Minecraft 1.21.10 running at 320x240 with a GUI scale of 1:

Image

As you can see, the game's GUI scales perfectly to this size, as it's likely the resolution that the GUI graphics were designed for.

This is the same scene, this time rendered in 640x480 with a GUI scale of 2, an integer multiple of the previous resolution (note that I forgot to let the whole view load in, so it looks a little weird):

Image

Now, you can see that the GUI still fits on-screen in the same way, but is now twice the size. This is an easy case to account for, because the user's resolution is an integer multiple of the previous resolution. Let's look at a more special case:

Image

Using the same GUI scale from before, but with a more awkward resolution (800x600), you can see how Minecraft works with resolutions that aren't integer multiples of the GUI's base resolution. Every element's position is aligned with a particular edge of the screen, while the scale of each element is still based on the GUI scale and "base" resolution. The same approach is used for every "piece" of the game's GUI (I didn't screenshot all of them, so you'll just have to take my word for this one). Each one is "anchored" to an edge of the screen, so you don't have to worry about misalignment caused by strange screen resolutions.

How ClassiCube does it

The ClassiCube client appears to draw all of the GUI elements in a coordinate space defined by the user's screen resolution. It seems to support the "anchoring" thing I talked about earlier, with each GUI element being attached to the proper edge of the screen, which is great! However, the default scale for UI elements seems rather arbitrary and is not aligned with any "base" resolution. The chat, menu, and HUD are all at different scales by default, and seem to support fractional scaling, meaning that a user can very easily make the GUI pixels look very bad.

What is to be done?

It might sound like I'm complaining about minor details in a volunteer-driven project with much more important things to focus on. I agree, that's exactly what I'm doing. HOWEVER...

The reason I want to discuss this publicly is that I plan on actually doing something. I'm going to use my very limited C programming knowledge to implement a better GUI system for ClassiCube. I just need to know if my contributions are needed.

Here are the changes I plan to make:

  • Draw GUI elements in a coordinate system which ranges from (0, 0) at the top-left to (320, 240) at the bottom-right, rather than from (0, 0) to (window width, window height)
  • Ensure integer scaling and positioning for every element so that pixels in the GUI are aligned to pixels in the graphics (this might already be taken care of depending on what type of value is used for coordinates)
  • Remove per-element scaling options and replace them with a global "GUI Scale" option

Note that I am by no means an expert on ClassiCube development! I might have gotten some things wrong about how GUI scaling works here, and I'm not even sure my planned changes will be possible to implement. Either way, I'm happy to compromise on many of these planned changes so that my contribution may be appreciated by everyone working on this project.

bunabyt3 avatar Nov 02 '25 01:11 bunabyt3

elements like the menu, chat, hotbar, and crosshair use completely different scaling factors that the user has to fix manually.

Which of these values are incorrect by default? What specifically needs to be changed to "fix" them?

Draw GUI elements in a coordinate system which ranges from (0, 0) at the top-left to (320, 240) at the bottom-right, rather than from (0, 0) to (window width, window height)

It sounds like you want to change an implementation detail, but I'm not sure what the actual purpose of this is.

meaning that a user can very easily make the GUI pixels look very bad.

Unfortunately, some users prefer being able to do this. Removing the option seems unnecessary given you can still set it to whole integers and it looks fine for personal use.

Remove per-element scaling options and replace them with a global "GUI Scale" option

Why? Being able to customize elements individually is good.

Goodlyay avatar Nov 02 '25 03:11 Goodlyay

I'd also add that ClassiCube is based on Minecraft c0.30, which has no example to follow when it comes to GUI scaling, since the game was a fixed resolution (854 480). I don't see the value in trying to precisely follow what modern Minecraft does with its scaling. Generally I think allowing more customization is better than less.

Goodlyay avatar Nov 02 '25 03:11 Goodlyay

The GUI in c0.30 doesn't scale with screen resolution, but it still uses a 320x240 baseline resolution for all GUI elements. The HUD, menu, and (reviewing old MP test footage) chat window are all rendered at the same resolution, where 1 pixel in the graphics is scaled up to a fixed number of pixels (likely 2x) on-screen. All elements are spaced in increments of 1 unscaled pixel (2 screen pixels in this case), presumably because each part of GUI uses a (0, 0) to (320, 240) coordinate space. The elements may be positioned for widescreen, etc. by anchoring them to a side of the screen.

Also, ClassiCube usually doesn't replicate classic behavior where it interferes with the usability of the game client. That's why ClassiCube can change resolutions. If there's going to be GUI scaling at all, it should be done in a way that works best for the particular type of graphics and layout used in the game's GUI. ClassiCube has pixel art graphics that would work best with the proposed system.

The issue with ClassiCube's existing scaling implementation is that it's inconsistent and difficult to configure. The default scale for all elements, 1.0, doesn't actually represent a 1:1 scaling between graphics pixels and screen pixels. Additionally, HUD elements and the chat are scaled relative to the screen resolution, while the menu isn't, so a scale value of 1.0 could mean something completely different based on what resolution the user is playing at. For example, at the default resolution of the window, the menu (+render stats) are at the same scale as the HUD, but when I go into fullscreen on my 1920x1080 monitor, the HUD becomes bigger. There's no way for me to make the HUD smaller without using fractional scaling, since nice values like 0.75 aren't supported in the settings menu (it gets truncated to 0.7 instead).

I understand that the existing implementation might be "good enough" for some users, but it really isn't as neat of a solution as what Minecraft was doing from the start.

Also, I'm willing to add options to let users scale different elements independently. The intent was to promote consistency and easy configuration, but it seems a little too inflexible in hindsight. Whether or not it's good to have too many settings is more design philosophy than anything else, so I'll just stick to the established conventions of this project.

bunabyt3 avatar Nov 02 '25 04:11 bunabyt3