Believe it or not, I can actually draw.
Jean-Michel Basquiat
As we learned in previous lessons, programmers often build libraries of functions to provide a “customized” version of C/C++ language. Today, we are going to build our own library of functions to draw things on the console. Drawing on the console is not a part of C/C++ standard and the underlying functions we will be using are specific to the Microsoft Windows API. The Linux, Mac OSX or other operating systems will require a different implementation.
Microsoft Windows API is very well documented through Microsoft Developer Network (MSDN). We are going to look at the Consoles section and the Console Functions. But before we jump into the implementation, lets define what the console is and what functions do we want to implement.
A console is a two dimensional rectangular screen with (0,0) point in the top left corner. X-axis goes from left to right and Y axis goes from top to bottom. A console has a size – the rectangular width and height. Only the points inside this rectangular are visible to the user. A console also has a notion of “cursor” – a point on the console where we can print a character. When we print a character, the cursor moves one position to the right. If we hit the console’s right border, then cursor moves to the first position on the next’s line. To draw on the console, we would need to implement the following functions:
SIZE ConsoleGetSize(); // gets the size of the console COORD ConsoleGetCursor(); // gets the current position of the cursor void ConsoleSetCursor(COORD p); // moves cursor to point p void ConsolePrint(char ch); // prints a character at the current cursor’s position void ConsoleClear(); // clears the console
To implement the first two functions, we will need to use GetConsoleScreenBufferInfo() function. This function queries the Windows console object and returns back information about the console in the CONSOLE_SCREEN_BUFFER_INFO structure:
- the current console size is returned in the dwSize field;
- the current cursor position is returned in the dwCursorPosition field.
We will also need to use GetStdHandle() function to retrieve the “handle” of the current console. An application may use multiple consoles to improve performance and make rendering smoother. For now, let’s simply use the main console. Finally, don’t forget to include <windows.h> file that contains definition for the Windows API functions we are going to use!
// returns a console size or invalid size {-1,-1} on error
SIZE ConsoleGetSize() {
HANDLE hConsole;
CONSOLE_SCREEN_BUFFER_INFO csbi;
SIZE szError = {-1, -1}; // special return value to indicate error
// get special console handle to identify the console
hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
if(hConsole == INVALID_HANDLE_VALUE) {
return szError; // the invalid size value to indicate error
}
// get information about console
if (GetConsoleScreenBufferInfo(hConsole, &csbi) == 0) {
return szError; // the invalid size value to indicate error
}
// done
return csbi.dwSize;
}
Can you write a similar function ConsoleGetCursor() that returns dwCursorPosition field instead of the dwSize field?
To implement the ConsoleSetCursor() function we will need to use SetConsoleCursorPosition() function from Microsoft Windows API. Again, we will need first to get the console’s handle (this is the first parameter for the SetConsoleCursorPosition() function). The rest should be easy! Can you write ConsoleSetCursor() yourself?
Finally, you already know how to implement ConsolePrint() and ConsoleClear() functions: use the standard “cout” to print a character on the console and use the system(“cls”) call to clear the console!
Now we have all the console functions to draw a few things! Checkout a few examples of ASCII art – drawing on the screen with symbols instead of pixels for inspirations.
Exercises
1) Create console.h and console.cpp files in your project. Put functions’ declarations in the .h file and function implementations into .cpp file. Make sure to “add” these two files to all the other projects you will build for this lesson.
2) Write ConsoleGetCursor(), ConsoleSetCursor(), ConsolePrint() and ConsoleClear () functions.
3) Draw a picture of a tree in the middle of the screen (feel free to change it!):
\/ \/ \ / \/ ||
4) Draw a car. Can you draw an animation of a car going from the left to the right side of the screen:
_ _/___\_ o o
5) Draw an animation of a man walking form the left to the right side of the screen:
0 0 0 0 /|\ /|\ /|\ /|\ / \ |\ | /|
6) Draw graphics of the following functions (use ‘*’ for the points of the graph):
a) y(x) = 5
b) y(x) = x^2
c) y(x) = sqrt(x)
7) Add rocket animation to the Lunar Lander game.
/ \ / \ \ / |_| / \
Pingback: Practical programming | Random Notes