🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

The Programming Squib

Published April 18, 2008
Advertisement
Heh, yeah, I feel like a squib right now.*

I've been feeeling a little, eh... stagnant with my programming lately, mostly because I haven't been able to properly complete a project. ((Yes, I realize many of you haven't either :D)) So I bought the GameTutorials set of tutorials... so far I think I've made a worthwhile investment.

I ran through the early C++ tutorials really fast just to make sure I knew what I needed, and I eventually got to some Win32 console stuff, like what I had been doing with cConsole before. One tutorial that caught my eye was "Color Text"... I glanced over it, and behold, text coloring in the console that was far simpler than what cConsole attempted. I really was floundering back there, ugh.

So I ran through the tutorial code, tweaked it, and got rid of the positioning code; I didn't feel I needed it at that point. What I got worked well enough: two functions, ColorPrint and ColorPrintln, that took a text string and a color value. I found I was passing the same color value repeatedly, and besides that it looked really monotonous and klutzy. So I tried something I haven't tried before: I made an iostream manipulator, to use with std::cout.

At first I had the most basic of manips:
class color{    private:        ConsoleColor myColor; // This is just an enum of colors I made.    public:        color(ConsoleColor theColor)            : myColor(theColor)        {}        void operator()()        {            HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);            SetConsoleTextAttribute(hOut, myColor);        }};ostream& operator<<(ostream& out, color theColor){    theColor();    return out;}


I liked this solution a lot better than the functions I had made before. All you needed to do was creat the manip and pass it to cout. Like most manipulators that I've seen, all you need to do is this:

cout << color(CC_CYAN) << "Hello, Cyan!\n";


Easy and intuitive, especially because you're using cout there instead of through a function. A few slight gripes I have are that the manipulator does not actually change the state of cout... it changes the attributes of the console itself. This will be important later! For this reason, the operator() doesn't require any parameters, nor does it return anything. The operator<< is then made to call the function object and return the ostream... and nothing at all was done with that ostream. It seems like a waste, but it's the only way to make the manip work with cout! In that regard, it's a little like the differences between overloading the ++ operators; you have an unused variable to differentiate.

Well, me being me, that wasn't enough. I took the positioning code from before and made it into its own manip. All it does is set where the console caret is... thus, again, it does nothing to the ostream itself, only the console. Again, this will be important later!

Further, foreground text coloring isn't the only coloring you can do with the console; you can also color the background of the character cells. I thus renamed the color manip into 'forecolor', and created the 'backcolor' manip, which looked exactly like forecolor, but bitshifted the color value << 4 (because internally the background color is placed at 0xF0, where foreground is 0x0F, in the same mask).

The backcolor manip worked just as well as the forecolor manip did... except that they didn't take eachother into account. Do you see the problem? If the console text attributes already had a foreground, if I called the backcolor manip, it replaced the entire mask with the lone background color. Obviously, that's not good, especially because color values are not the only values held in that mask.

In short (yeah, like anything about this post was short!), I called GetConsoleScreenBufferInfo() for the screen buffer info struct, took the attributes mask out (which is of the WORD type), and did some binary ORs and ANDs. The formula I used to retain the original mask, but replace the value I wanted with the forecolor, is ((theMask & 0xFFF0) | myColor). I AND out the part I want to remove, but retain the rest, and OR in the new value! This fixed my mask problem.

Here's the code for the color manips, with inheritance included. Feel free to use it!

CONCOL.H (CONsole COLor)
#include #include enum ConsoleColor { CC_BLACK = 0, CC_BLUE,    CC_GREEN,  CC_CYAN,                    CC_RED,       CC_PURPLE,  CC_YELLOW, CC_WHITE,                    CCI_BLUE = 9, CCI_GREEN,  CCI_CYAN,  CCI_RED,                    CCI_PURPLE,   CCI_YELLOW, CCI_WHITE};class color{    protected:        ConsoleColor myColor;    public:        color(ConsoleColor theColor);        virtual void operator()() = 0;};class forecolor : public color{    public:        forecolor(ConsoleColor theColor);        void operator()();};class backcolor : public color{    public:        backcolor(ConsoleColor theColor);        void operator()();};std::ostream& operator<<(std::ostream &out, color &theColor);



CONCOL.CPP
#include "concol.h"color::color(ConsoleColor theColor)    : myColor(theColor){}forecolor::forecolor(ConsoleColor theColor)    : color(theColor){}backcolor::backcolor(ConsoleColor theColor)    : color(theColor){}void forecolor::operator()(){    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);    CONSOLE_SCREEN_BUFFER_INFO* csbi = new CONSOLE_SCREEN_BUFFER_INFO;    GetConsoleScreenBufferInfo(hOut, csbi);    SetConsoleTextAttribute(hOut, ((csbi->wAttributes & 0xFFF0) | myColor));    delete csbi;}void backcolor::operator()(){    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);    CONSOLE_SCREEN_BUFFER_INFO* csbi = new CONSOLE_SCREEN_BUFFER_INFO;    GetConsoleScreenBufferInfo(hOut, csbi);    SetConsoleTextAttribute(hOut, ((csbi->wAttributes & 0xFF0F) | (myColor << 4)));    delete csbi;}std::ostream& operator<<(std::ostream &out, color &theColor){    theColor();    return out;}


There it is. Now, remember how the manips affect the console, NOT cout? This is important, and I'll explain why. When you use one of the color manips, for example, it sets the state of the console to put characters in that color scheme from that point on. This includes input typed via cin. Wow, who would have guessed? Ah, well, like I said, the color manips don't touch cout anyways. They're not exactly your usual manips. This means that you can have the user enter input in a different color. That's pretty neat, isn't it? It works the same for the position manip, even though I haven't put the code up here. Once you set the caret position, cout and cin work from there.

So... pointers, ideas, criticism, and of course colored input are all welcome!

~Jonathan

EDIT: And of course, I forgot to mention! Because both manips are derived from the virtual class 'color', only one operator>> is needed, because it can take a reference to an object of type color. Handy!



* Oh yeah, about the squib comment. In Harry Potter, Mr. Filch the caretaker is a Squib, meaning a wizard-born who's barely got a drop of magic in their blood. A programmer squib, thus, should be obvious. To take the analogy further, compare GameTutorials to Kwikspell, and there you have it.
Previous Entry Book reading
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement