[Off-Topic] Drawing text, menus etc. in OpenGL

General discussion of current events, conversations with other board members, etc.
Post Reply
User avatar
Stephen
Posts:75
Joined:2006-05-01, 06:34
Location:Australia
Contact:
[Off-Topic] Drawing text, menus etc. in OpenGL

Post by Stephen » 2008-01-03, 15:46

Hi,

I was playing around with OpenGL, and I am making a simple (2D) game. Anyway, the way I am currently drawing text is to have a text class, which in the constructor renders the text, then loads it as a texture. Then, in the draw method, it draws a quad with that texture mapped to it.

This works quite well, but I was wondering if there's an easier way of doing it... How do you do it in Ca3DE?

Then there are the menus - I just have a class which has a couple of vectors in it (one for each type of control), which just goes through and calls each of their draw methods when its draw method is called. I then have arrays of menus so I can draw them like this:

Code: Select all

case E_MENU : _Menus[_CurrentMenu]->Draw();
(in a switch case checking the gamestate)

Is this a good way to do this? The main hindrance is that it's hard to keep track of all the menu items, say if I want to change one of them. Most of the time, I just add controls like this:

Code: Select all

_Menus[E_MAIN]->AddControl(new Button(...));
If I wanted to change, say, the caption of the button, I would have no way to unless I had a bunch of pointers for all the menu items, which I was trying to avoid with my system... I really don't want to have to keep track of a bunch of pointers - do you think I should give the controls numerical IDs or names?

Thanks for your advice,

-Stephen
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: [Off-Topic] Drawing text, menus etc. in OpenGL

Post by Carsten » 2008-01-03, 22:19

Hi Stephen,
Stephen wrote:This works quite well, but I was wondering if there's an easier way of doing it... How do you do it in Ca3DE?
Well, I put the characters of the alphabet into one (or sometimes more) texture maps, then render text strings character-by-character using the right portion of the right texture map for each. If you look at the output images of the MakeFont program you should get the idea.

Some related links with more info: As you can see, many ways to render fonts with OpenGL exist. My personal favourite is the character-bitmap approach as used in Ca3DE; at a quick glance http://nehe.gamedev.net/data/lessons/le ... ?lesson=43 explains something very similar.

Code: Select all

_Menus[E_MAIN]->AddControl(new Button(...));
If I wanted to change, say, the caption of the button, I would have no way to unless I had a bunch of pointers for all the menu items, which I was trying to avoid with my system... I really don't want to have to keep track of a bunch of pointers - do you think I should give the controls numerical IDs or names?
Hmmm. Well, in any case you need to have some identity for the button whose label you want to change, so keeping e.g. a pointer or iterating through the buttons of a menu until the desired one is found (by name, ID, whatever) seems to be necessary.
As keeping pointers in such a case is no more complex than keeping IDs, personally I'd keep pointers of the menu items I want access to.

Anyways, I must say that I'm not sure if I fully understand your question, some of which seems to be related to code design in general, some to GUI code design.
For the former, http://www.parashift.com/c++-faq-lite/ is a very good resource (inheritance...), as well as the excellent and famous book by the GoF.
A very good GUI library is http://www.wxwidgets.org/ that I use to program CaWE (and all other GUI programs). The concepts behind wxWidgets are very well thought out, and I took some of them into account in the design of the Ca3DE GuiSys (which is, in comparison, much simpler).

Hope that helps! :-)
Best regards,
Carsten
User avatar
Stephen
Posts:75
Joined:2006-05-01, 06:34
Location:Australia
Contact:

Re: [Off-Topic] Drawing text, menus etc. in OpenGL

Post by Stephen » 2008-01-04, 05:51

I suppose the main thing I was trying to ask was what would be the best way of keeping track of a lot of controls. An example is that for each button, you give it a pointer to a function (which is executed when the button is pressed). Say in this I wanted to change a text box's contents. I don't want to have hundreds of pointer declarations, or deal with arrays (an keep track of which id each control has). So I think that the best way would be to have a name assigned to each control, so I could just do this:

Code: Select all

_Menu[_CurrentMenu]->GetTextBox("txtExample")->SetCaption("Text");
Now I just have to work out how to store both the names and their position in the vector... I could probably just use two vectors for that.
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: [Off-Topic] Drawing text, menus etc. in OpenGL

Post by Carsten » 2008-01-04, 13:00

Stephen wrote:I suppose the main thing I was trying to ask was what would be the best way of keeping track of a lot of controls.
Why don't you keep in each control an array (std::vector) of subcontrols (or rather, pointers to subcontrols)? The parent control would be responsible e.g. for deleting the subcontrols in it's own destructor, copying them when it itself is copied, etc.
This organizes your big numbers of pointers properly hierarchically.
An example is that for each button, you give it a pointer to a function (which is executed when the button is pressed).
Just for completeness, instead of a callback function like "OnMenuItemSelected(...)" you might also employ the Command Pattern for the same purpose. This is what I'm currently changing CaWE to.
Say in this I wanted to change a text box's contents. I don't want to have hundreds of pointer declarations, or deal with arrays (an keep track of which id each control has). So I think that the best way would be to have a name assigned to each control, so I could just do this:

Code: Select all

_Menu[_CurrentMenu]->GetTextBox("txtExample")->SetCaption("Text");
Why has _Menu[_CurrentMenu] a method GetTextBox()? It seems utterly unrelated to me.
How would you implement GetTextBox()? I think you'd still need to traverse a list of pointers...
I also think both problems would resolve themselves if you employed the parent-keeps-list-of-children approach mentioned above. This is also how things are designed in wxWidgets and the Ca3DE GuiSys.
:idea: Oh, btw., why don't you just have a look into the GuiSys header files? They are included with each recent release, and maybe give you some ideas. When I implement more controls for the Ca3DE GuiSys in the future (better text edit control, list boxes, choice/combo boxes, menus, etc.), I'll use just the same interface headers.
Now I just have to work out how to store both the names and their position in the vector... I could probably just use two vectors for that.
You can do that, but I wonder why you don't simply add a member like std::string Name; to your control (menu, subwindow, etc.) class?
Best regards,
Carsten
User avatar
Stephen
Posts:75
Joined:2006-05-01, 06:34
Location:Australia
Contact:

Re: [Off-Topic] Drawing text, menus etc. in OpenGL

Post by Stephen » 2008-01-04, 14:10

Carsten wrote:
Stephen wrote:I suppose the main thing I was trying to ask was what would be the best way of keeping track of a lot of controls.
Why don't you keep in each control an array (std::vector) of subcontrols (or rather, pointers to subcontrols)? The parent control would be responsible e.g. for deleting the subcontrols in it's own destructor, copying them when it itself is copied, etc.
This organizes your big numbers of pointers properly hierarchically.
This is how the menu class works. The problem is trying to find a control in the array.
Carsten wrote:
Stephen wrote:Now I just have to work out how to store both the names and their position in the vector... I could probably just use two vectors for that.
You can do that, but I wonder why you don't simply add a member like std::string Name; to your control (menu, subwindow, etc.) class?
Oh yeah - I can't believe that I didn't think of that... :oops:
Carsten wrote: Why has _Menu[_CurrentMenu] a method GetTextBox()? It seems utterly unrelated to me.
How would you implement GetTextBox()? I think you'd still need to traverse a list of pointers...
That would be a method in the menu class that returns a pointer to the text box you want, by going through the vectors until it finds the right control. I would rather have a GetControl method that goes through and finds a control with the right name, but:
If the arguments are different, you can have different methods with the same name - eg.

Code: Select all

void Menu::AddControl(Button* control)
void Menu::AddControl(TextBox* control
Can I do that with different return types but the same argument type? Like:

Code: Select all

Button* Menu::GetControl(std::string name)
TextBox* Menu::GetControl(std::string name)
Does it even matter? A pointer is just a memory address, isn't it?

And I will take a look at the GuiSys headers and read up on Command Patterns

Thanks.
User avatar
Carsten
Site Admin
Posts:2170
Joined:2004-08-19, 13:46
Location:Germany
Contact:

Re: [Off-Topic] Drawing text, menus etc. in OpenGL

Post by Carsten » 2008-01-05, 11:51

Stephen wrote:Can I do that with different return types but the same argument type? Like:

Code: Select all

Button* Menu::GetControl(std::string name)
TextBox* Menu::GetControl(std::string name)
No, you generally cannot overload functions by their return type, because doing so would be ambiguous. For example, which GetControl() method should the compiler use in a statement like

Code: Select all

void* Result=GetControl("OkButton");
Does it even matter? A pointer is just a memory address, isn't it?
Sure, but C++ is a (statically) typed language. Types give pure memory data a meaning, and thus forgoing them is something you should almost never do. The compiler uses type information to find program errors and optimize the code, and for the programmer they have documentation and abstraction value.

Unfortunately I cannot remember where I read a great overview about C++ being a statically (and dynamically) typed language, the implied benefits and why you should not try to subvert the type system. Iirc it was in Scott Meyers very good "Effective C++, 3rd edition" book, but I currently haven't my copy handy.
http://en.wikipedia.org/wiki/Type_system has a good overview too, at least the first several subsections.

What you can do (and what can also be very reasonable), is to have a GetControl() method that returns a pointer to the common base class. For example, if your Button and TextBox classes both derive from class Control, then you could have a method

Code: Select all

Control* Menu::GetControl(std::string name)
(The array of children that the Menu keeps is then probably an array of pointers to Control, too.)
Assuming that all related classes have a properly overloaded and implemented SetLabel() method, you could then simply call

Code: Select all

Control* MyControl=Menu->GetControl("OkButton");
MyControl->SetLabel("Cancel");    // Changes the text from "OK" to "Cancel".
Best regards,
Carsten
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests