Creating a TEXT-BASED graphic engine in C++
In his latest video, Mashpoe demonstrated how to install a C compiler and IDE on ReactOS. To showcase the OS's maturity, he decided to create a game from scratch without relying on any functionality other than ReactOS. He started by setting up his Code::Blocks project, opting for C++ as the ideal language for developing games, given its advantages in this area. Most games use some sort of graphics library, but Mashpoe chose to create his own graphics engine based on the Windows console. This would lend a nostalgic character to his game, inspired by older titles like Dwarf Fortress, which draws characters on a window instead of relying on the console.
The first step was to create a display class that stores an array of char info structures representing characters in the console, along with formatting data like foreground and background colors. Using the writeConsoleOutput function, it's possible to set the entire contents of the console window, enabling the creation of a functional graphics library. The buffer storing the graphic characters replaces traditional pixels, and the display class initializes itself with a handle to a console window.
To allow specific characters to be displayed, Mashpoe created texture classes that load text files as if they were images. Through the special connection between the classes, it is now possible to change the characters displayed in the console window and achieve a transparency effect. He also mastered a line-drawing function using an algorithm obtained from another website. Additionally, he faced a challenge in using Git installed on ReactOS to push code to repositories while working on the game.
He installed an older version of Git and built an appropriate system path, which allowed him to push his source files to repositories. Mashpoe showcased how to install tools on ReactOS, which was a significant hurdle, but he managed to overcome it. In future videos, he plans to address input handling and physics in his game, making it a game engine tailored for developing games on Windows.
At the time of writing this article, his video has reached 19,588 views and 470 likes, indicating strong interest in the topic. The journey of creating a game from scratch on an Operating System like ReactOS is sure to inspire many programming and gaming enthusiasts.
Toggle timeline summary
-
Introduction to the previous video about setting up a C compiler and IDE in ReactOS.
-
Announcement of a game development project using ReactOS.
-
Decision to use C++ for game development for better capabilities.
-
Plan to create a custom graphics engine with the Windows console.
-
Discussion on the nostalgic graphics system similar to Dwarf Fortress.
-
Using the Windows console as the basis for the game graphics engine.
-
Creation of a display class to handle character representations.
-
Introduction of the writeConsoleOutput function for displaying content.
-
Explanation of the display class handling character array and output.
-
Introduction of a clear function for filling the console with a character.
-
Creation of a setColor method for character color customization.
-
Introduction of a texture class to manage images as text files.
-
Challenges faced while developing the graphics engine.
-
Installing a dark theme for code blocks to improve visibility.
-
Details on texture class features like loading specific image portions.
-
Implementation of transparency properties for the display class.
-
Navigating the limitations of ReactOS for version control setup.
-
Experience installing an older version of Git on ReactOS.
-
Success in pushing source files to GitHub after overcoming obstacles.
-
Teaser for the next video focusing on game physics and input handling.
-
Future plans for developing a standalone game engine with input handling.
Transcription
In my last video, I was able to install a C compiler and an IDE in ReactOS. In order to show the maturity of the operating system, I've decided to create a game from scratch without relying on any functionality from an operating system besides ReactOS. I began by setting up my code blocks project. I decided to use C++ rather than C, as it's a much better language for developing games. Most games use some kind of graphics library, but I thought it would be cooler if I was able to create my own colorful graphics engine using the Windows console. Many games use this kind of graphics system in order to achieve an old-timey feel, such as Dwarf Fortress. Dwarf Fortress doesn't actually use the Windows console though, or any operating system's console for that matter. Instead, it just draws a bunch of characters onto a regular window as if they were images. This is the reason you can install a tileset for that game. I want to actually use the native console for my game, and since ReactOS is built from the ground up to be compatible with Windows, this graphics engine should work on both Windows and ReactOS. First, I wrote a display class, which stores an array of char info structures. Windows uses these structures in order to represent a character in its console, along with any formatting data such as foreground and background color. The Windows API has a built-in function called writeConsoleOutput, which takes a two-dimensional array of char info structures and uses it to set the entire contents of the console window. Now we have the basis for a conventional graphics library. The array of char info structures acts as a buffer to draw content to, and the writeConsoleOutput function displays the contents of the buffer to the console window. Just about every graphics library uses this exact same system. The only difference is that our buffer is storing colored characters instead of pixels. The display class acts as a wrapper for our char info array and also handles writeConsoleOutput for the user. Display objects are initialized with the handle to a console window, and if no such handle is provided, it will try to use the main console that's associated with stdout. It will then take the width and height of the console in characters and make an appropriately sized buffer. Our display is useless if we don't have any way to draw stuff on it, so I started out by making a clear function, which takes a character as an argument and fills the entire console window with it. I also added a method called setColor that will allow the user to set the foreground and background color of any characters that are drawn to the console window or used to clear it. We could just add a method to set a particular character at any position in the console window and then call it a day, but that would be really inconvenient for the user if they wanted to draw any complex scenes or images. I decided to create a texture class that loads text files as if they were images. I made it a friend of the display class because textures have many characters and it would be inefficient to pass each character to the display object one by one, which would involve many redundant bounds checks. Bounds checks are necessary because characters must not be drawn outside of the charInfo buffer, so we have to make sure any characters we draw are within the bounds of the console window. Any attempt to set values outside the bounds of the buffer will cause undefined behavior. Now that a texture has access to all of a display object's private members, it can do bounds checking once to determine which characters will be displayed on the screen, and then it can start putting them directly into the charInfo buffer. At this point in the development process of my graphics engine, my eyes began to bleed at an unhealthy rate due to the light theme that comes with code blocks by default. Luckily, I managed to install a dark theme by following the tutorial, which I will link in the description. After installing the dark theme, I was able to add a few more features to the texture class. Now, by default, textures will ignore any spaces in order to create a transparency effect. If a texture needs spaces to be drawn, you can set any other character to be ignored instead. Most graphics libraries will allow you to draw a specific portion of an image rather than the entire image, which is very useful if you want to load a sprite sheet with many frames in it. Textures handle this by taking a pointer to a rectangle structure as an optional argument. Textures also allow you to set their foreground and background colors, and you can even set the background or foreground color of the texture's characters to be completely transparent. You can see this working when this stick man is drawn on top of a sky filled with clouds. The part of him that's overlapping a cloud takes its white background, while the rest of him takes the blue background of the sky. I also decided to give the display its own transparency properties for drawing individual characters. Finally, I gave the display class a method for drawing lines. I got the code for this from a cool website that gives an implementation for a line drawing algorithm in a bunch of different languages, which I will of course link in the description. Since I always provide a link to a github repository with the source code for my video projects, I had to find a way to do this in ReactOS. I could have just transferred the files to my host operating system via a shared folder, but that would be cheating because I'm trying to develop my game using only ReactOS. I don't know if this is because I had an outdated browser, but I was unable to upload my code directly to the github website. That was no problem though, because you can just push code to a repository via the command line. I had to install git first, and the latest version does not support the older versions of Windows that ReactOS currently aims to support, and I had to install an older version instead. The installer for the latest version would not download no matter how many times I tried, but I was able to download a zip file full of binaries. If you were to watch the uncut footage of me trying to install this, you would probably cry, but I did manage to figure it out. I basically just put all the binaries into a folder in my system's program files directory, and then added the folder where git.exe is stored to the path environment variable. I was then able to put all of my source files into a folder and finally push them to my github repository. That's it for now. In my next video, I'll set up input handling and create the physics for my game, which will probably be in platformer. I might fork the github repo later in order to create a standalone engine that supports input handling and graphics, which would be very useful for anyone who wants to make a Windows game using my code. As always, the code for this video will be linked in the description.