Difference between revisions of "Using CEGUI with GLUT"
Jim Storch (Talk | contribs) |
m (Robot: Cosmetic changes) |
||
(12 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | + | {{VersionBadge|0.6}} | |
− | + | GLUT is the OpenGL Utility Toolkit. It was designed to make it easy to create | |
− | GLUT is the OpenGL Utility Toolkit. | + | |
simple OpenGL application across different platforms. One reason to use GLUT is | simple OpenGL application across different platforms. One reason to use GLUT is | ||
you may want a basic life support system while you design your CEGUI code. | you may want a basic life support system while you design your CEGUI code. | ||
Line 10: | Line 9: | ||
The information presented here is the result of a couple days of tinkering with | The information presented here is the result of a couple days of tinkering with | ||
− | CEGUI and FreeGLUT on Linux. | + | CEGUI and FreeGLUT on Linux. Let me clearly state that I am an not an expert |
on CEGUI, GLUT, C++, or Linux and the things I say may not be the optimum | on CEGUI, GLUT, C++, or Linux and the things I say may not be the optimum | ||
− | approaches. | + | approaches. This information is presented with the simple hope that some may |
find it useful. | find it useful. | ||
− | ==The Loop== | + | == The Loop == |
We're going to specify FreeGLUT instead of GLUT because we need one of the new | We're going to specify FreeGLUT instead of GLUT because we need one of the new | ||
− | functions added. | + | functions added. In GLUT you call glutMainLoop() and it never comes back. |
FreeGLUT gives us glutMainLoopEvent which invokes one loop and then returns | FreeGLUT gives us glutMainLoopEvent which invokes one loop and then returns | ||
− | control. | + | control. We need this arrangement so we can call CEGUI's renderer later. |
This is a simple teapot drawing app which should compile and run provided you | This is a simple teapot drawing app which should compile and run provided you | ||
Line 32: | Line 31: | ||
// | // | ||
#include <GL/freeglut.h> | #include <GL/freeglut.h> | ||
− | |||
// | // | ||
void render(void); | void render(void); | ||
Line 42: | Line 40: | ||
// | // | ||
int main() | int main() | ||
− | + | { | |
− | + | // Create our OpenGL Window | |
− | + | int fake_argc = 1; | |
− | + | char* fake_argv; | |
− | + | glutInit(&fake_argc, &fake_argv); | |
− | + | glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); | |
− | + | glutInitWindowSize(640, 480); | |
− | + | window_id = glutCreateWindow("GLUT Loop"); | |
− | + | // Set the function to handle normal key presses | |
− | + | glutKeyboardFunc(keyFunc); | |
− | + | // Begin the loop | |
− | + | while(keep_running) | |
− | + | { | |
− | + | glutMainLoopEvent(); | |
− | + | render(); | |
− | + | glutSwapBuffers(); | |
− | + | } | |
− | + | // Exit gracefully | |
− | + | glutDestroyWindow(window_id); | |
− | + | return 0; | |
− | + | } | |
// | // | ||
// This is where you'd draw a frame of your 3D application | // This is where you'd draw a frame of your 3D application | ||
// | // | ||
void render() | void render() | ||
− | + | { | |
− | + | glLoadIdentity(); | |
− | + | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
− | + | // Look on my works, ye Mighty, and despair! | |
− | + | glutWireTeapot( 0.5 ); | |
− | + | } | |
// | // | ||
// Handler for normal keypressed | // Handler for normal keypressed | ||
// | // | ||
void keyFunc(unsigned char key, int x, int y) | void keyFunc(unsigned char key, int x, int y) | ||
− | + | { | |
− | + | switch (key) | |
− | + | { | |
− | + | case 113: // 'q', | |
− | + | case 81: // 'Q', | |
− | + | case 27: // 'ESC' | |
keep_running = false; | keep_running = false; | ||
break; | break; | ||
− | + | } | |
− | + | } | |
− | + | ||
− | ==Makefile for GLUT Only== | + | == Makefile for GLUT Only == |
− | Remember, make expects tabs | + | Remember, 'make' expects tabs not spaces when indenting compiler commands. |
# Makefile to compile glut_loop | # Makefile to compile glut_loop | ||
Line 104: | Line 101: | ||
rm -rf *.o glut_loop | rm -rf *.o glut_loop | ||
− | + | == GLUT's Keyboard Callbacks == | |
− | ==GLUT's Keyboard Callbacks== | + | |
A note on GLUT's keyboard functions: | A note on GLUT's keyboard functions: | ||
Keys that don't generate an ASCII value or aren't in the short list for | Keys that don't generate an ASCII value or aren't in the short list for | ||
− | glutSpecialFunc generate ... nothing. | + | glutSpecialFunc generate ... nothing. There are no events triggered when |
− | pressing the CTRL, ALT, or Shift keys. | + | pressing the CTRL, ALT, or Shift keys. There is no way to tell if '5' was |
− | pressed on the keypad instead of the number keys. | + | pressed on the keypad instead of the number keys. Later, I will show you a way |
to fake CTRL, ALT, and Shift for CEGUI but it wont be in real time. | to fake CTRL, ALT, and Shift for CEGUI but it wont be in real time. | ||
Line 126: | Line 122: | ||
− | Set the handler for a normal keypress. | + | Set the handler for a normal keypress. These would be keys that generate |
− | normal ASCII characters. | + | normal ASCII characters. 'Delete' (ASCII 127) is a normal key. 'Insert' is |
not. The special keys are handled by glutSpecialFunc (see below). | not. The special keys are handled by glutSpecialFunc (see below). | ||
Line 148: | Line 144: | ||
− | Set the handler for a special keypress. | + | Set the handler for a special keypress. |
+ | |||
+ | Example Handler: | ||
+ | * void mySpecialFunc(int key, int x, int y) | ||
+ | You get an int with the special key value and the current mouse x and y. The possible values are: | ||
* GLUT_KEY_F1 through GLUT_KEY_F12 | * GLUT_KEY_F1 through GLUT_KEY_F12 | ||
* GLUT_KEY_UP, GLUT_KEY_RIGHT, and GLUT_KEY_DOWN, and GLUT_KEY_LEFT | * GLUT_KEY_UP, GLUT_KEY_RIGHT, and GLUT_KEY_DOWN, and GLUT_KEY_LEFT | ||
* GLUT_KEY_PAGE_UP and GLUT_KEY_PAGE_DOWN, | * GLUT_KEY_PAGE_UP and GLUT_KEY_PAGE_DOWN, | ||
* GLUT_KEY_HOME, GLUT_KEY_END, and GLUT_KEY_INSERT | * GLUT_KEY_HOME, GLUT_KEY_END, and GLUT_KEY_INSERT | ||
− | |||
− | |||
− | |||
− | |||
Line 168: | Line 164: | ||
You get an int with the special key value and the current mouse x and y. | You get an int with the special key value and the current mouse x and y. | ||
+ | == Connecting GLUT's Keyboard Callbacks to CEGUI == | ||
− | + | As you probably know, CEGUI does not capture any input. You need to feed it in | |
− | + | ||
− | As you probably know, CEGUI does not capture any input. | + | |
it with the various .inject_Something_() functions. | it with the various .inject_Something_() functions. | ||
Line 179: | Line 174: | ||
As mentioned, GLUT does not generate an event when the user presses or releases | As mentioned, GLUT does not generate an event when the user presses or releases | ||
− | these keys. | + | these keys. If does have a function called glutGetModifiers() that lets you |
− | poll their state. | + | poll their state. It returns an INT with certain bits set. |
First we need to add some global flags to our program: | First we need to add some global flags to our program: | ||
Line 246: | Line 241: | ||
} | } | ||
− | We'll call this in every keyboard handler. | + | We'll call this in every keyboard handler. It's not pretty but it should keep |
CEGUI informed. | CEGUI informed. | ||
Line 595: | Line 590: | ||
− | ==GLUT's Mouse Callbacks== | + | == GLUT's Mouse Callbacks == |
Line 601: | Line 596: | ||
− | Sets the handler for any mouse button function. | + | Sets the handler for any mouse button function. This includes presses and |
− | releases. | + | releases. Scrolling a mouse wheels generates a press and a release for each |
tick. | tick. | ||
Line 629: | Line 624: | ||
* void myPassiveMotionFunc(int x, int y) | * void myPassiveMotionFunc(int x, int y) | ||
− | Pretty simple, x == x, y == y. | + | Pretty simple, x == x, y == y. You will not receive callbacks when the mouse |
pointer leaves the GLUT window. | pointer leaves the GLUT window. | ||
Line 641: | Line 636: | ||
* void myMotionFunc(int x, int y) | * void myMotionFunc(int x, int y) | ||
− | Again x==x, y==y. | + | Again x==x, y==y. The behavoir is a little different in that you will get |
callbacks with a button held and the mouse point dragged out of the GLUT window. | callbacks with a button held and the mouse point dragged out of the GLUT window. | ||
Line 648: | Line 643: | ||
− | ==Connecting GLUT's Mouse Callbacks to CEGUI== | + | == Connecting GLUT's Mouse Callbacks to CEGUI == |
Line 655: | Line 650: | ||
void myMouseFunc(int button, int state, int x, int y) | void myMouseFunc(int button, int state, int x, int y) | ||
− | + | { | |
− | + | if (state == 0) // State 0 = Button Pressed | |
− | + | { | |
− | + | switch (button) | |
− | + | { | |
− | + | case 0: // glut's left mouse button | |
− | + | CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::LeftButton); | |
− | + | break; | |
− | + | case 1: // glut's middle mouse button | |
− | + | CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton); | |
− | + | break; | |
− | + | case 2: // glut's right mouse button | |
− | + | CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::RightButton); | |
− | + | break; | |
− | + | case 3: // glut's mouse wheel up | |
− | + | CEGUI::System::getSingleton().injectMouseWheelChange(2.0); | |
− | + | break; | |
− | + | case 4: // glut's mouse wheen down | |
− | + | CEGUI::System::getSingleton().injectMouseWheelChange(-2.0); | |
− | + | break; | |
− | + | } | |
− | + | } | |
− | + | else if (state == 1) // State 1 = Button Released | |
− | + | { | |
− | + | switch (button) | |
− | + | { | |
− | + | case 0: // glut's left mouse button | |
− | + | CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::LeftButton); | |
− | + | break; | |
− | + | case 1: // glut's middle mouse button | |
− | + | CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::MiddleButton); | |
− | + | break; | |
− | + | case 2: // glut's right mouse button | |
− | + | CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::RightButton); | |
− | + | break; | |
− | + | } | |
− | + | } | |
} | } | ||
− | |||
Line 700: | Line 694: | ||
You need both of these, since GLUT uses separate callbacks for normal movement | You need both of these, since GLUT uses separate callbacks for normal movement | ||
− | and dragging: | + | and dragging (or register one function to both callbacks): |
void myPassiveMotionFunc(int x, int y) | void myPassiveMotionFunc(int x, int y) | ||
− | + | { | |
− | + | CEGUI::System::getSingleton().injectMousePosition(x,y); | |
− | + | } | |
void myMotionFunc(int x, int y) | void myMotionFunc(int x, int y) | ||
− | + | { | |
− | + | CEGUI::System::getSingleton().injectMousePosition(x,y); | |
− | + | } | |
− | + | == Registering the Callbacks == | |
− | ==Registering the Callbacks== | + | |
In the initialization code of your GLUT program you'll want to add: | In the initialization code of your GLUT program you'll want to add: | ||
Line 727: | Line 720: | ||
− | ==Creating a Renderer== | + | == Creating a Renderer == |
− | Naturally, GLUT will use the OpenGLRenderer. | + | Naturally, GLUT will use the OpenGLRenderer. So in your CEGUI initialization |
you'll want: | you'll want: | ||
CEGUI::OpenGLRenderer* myRenderer = new CEGUI::OpenGLRenderer(0); | CEGUI::OpenGLRenderer* myRenderer = new CEGUI::OpenGLRenderer(0); | ||
+ | new CEGUI::System(myRenderer); | ||
+ | == The New Loop == | ||
− | + | while( keep_running ) | |
− | + | { | |
− | while(keep_running) | + | glutMainLoopEvent(); |
− | + | render(); | |
− | + | CEGUI::System::getSingleton().renderGUI(); | |
− | + | glutSwapBuffers(); | |
− | + | } | |
− | + | ||
− | + | ||
− | + | ||
− | ==Makefile for GLUT + CEGUI== | + | == Makefile for GLUT + CEGUI == |
# Makefile | # Makefile | ||
Line 762: | Line 754: | ||
− | ==License for the Code Samples== | + | == License for the Code Samples == |
Copyright (C) 2006 Jim Storch | Copyright (C) 2006 Jim Storch | ||
This software is provided 'as-is', without any express or implied | This software is provided 'as-is', without any express or implied | ||
− | warranty. | + | warranty. In no event will the authors be held liable for any damages |
arising from the use of this software. | arising from the use of this software. | ||
Permission is granted to anyone to use this software for any purpose, | Permission is granted to anyone to use this software for any purpose, | ||
including commercial applications, and to alter it and redistribute it | including commercial applications, and to alter it and redistribute it | ||
− | freely. | + | freely. Attribution is not required. |
+ | |||
+ | [[Category:Tutorials]] |
Latest revision as of 16:20, 26 February 2011
Written for CEGUI 0.6
Works with versions 0.6.x (obsolete)
GLUT is the OpenGL Utility Toolkit. It was designed to make it easy to create simple OpenGL application across different platforms. One reason to use GLUT is you may want a basic life support system while you design your CEGUI code. GLUT lets you get up and running with minimal code and dependencies.
On the other hand, GLUT has a wonky input system that you may find inadequate, especially if your GUI needs exotic keypress combinations or unicode support.
The information presented here is the result of a couple days of tinkering with CEGUI and FreeGLUT on Linux. Let me clearly state that I am an not an expert on CEGUI, GLUT, C++, or Linux and the things I say may not be the optimum approaches. This information is presented with the simple hope that some may find it useful.
Contents
- 1 The Loop
- 2 Makefile for GLUT Only
- 3 GLUT's Keyboard Callbacks
- 4 Connecting GLUT's Keyboard Callbacks to CEGUI
- 5 GLUT's Mouse Callbacks
- 6 Connecting GLUT's Mouse Callbacks to CEGUI
- 7 Registering the Callbacks
- 8 Creating a Renderer
- 9 The New Loop
- 10 Makefile for GLUT + CEGUI
- 11 License for the Code Samples
The Loop
We're going to specify FreeGLUT instead of GLUT because we need one of the new functions added. In GLUT you call glutMainLoop() and it never comes back. FreeGLUT gives us glutMainLoopEvent which invokes one loop and then returns control. We need this arrangement so we can call CEGUI's renderer later.
This is a simple teapot drawing app which should compile and run provided you have an OpenGL capable display and freeglut + freeglut-devel packages installed.
Note the while(keep_running){} loop.
//glut_loop.cpp // #include <GL/freeglut.h> // void render(void); void keyFunc(unsigned char, int, int); int window_id; bool keep_running = true; // // A barebones GLUT application // int main() { // Create our OpenGL Window int fake_argc = 1; char* fake_argv; glutInit(&fake_argc, &fake_argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize(640, 480); window_id = glutCreateWindow("GLUT Loop"); // Set the function to handle normal key presses glutKeyboardFunc(keyFunc); // Begin the loop while(keep_running) { glutMainLoopEvent(); render(); glutSwapBuffers(); } // Exit gracefully glutDestroyWindow(window_id); return 0; } // // This is where you'd draw a frame of your 3D application // void render() { glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Look on my works, ye Mighty, and despair! glutWireTeapot( 0.5 ); } // // Handler for normal keypressed // void keyFunc(unsigned char key, int x, int y) { switch (key) { case 113: // 'q', case 81: // 'Q', case 27: // 'ESC' keep_running = false; break; } }
Makefile for GLUT Only
Remember, 'make' expects tabs not spaces when indenting compiler commands.
# Makefile to compile glut_loop glut_loop: glut_loop.o g++ glut_loop.o -lglut -o glut_loop # glut_loop.o: glut_loop.cpp g++ -c glut_loop.cpp # .PHONY: clean clean: rm -rf *.o glut_loop
GLUT's Keyboard Callbacks
A note on GLUT's keyboard functions:
Keys that don't generate an ASCII value or aren't in the short list for glutSpecialFunc generate ... nothing. There are no events triggered when pressing the CTRL, ALT, or Shift keys. There is no way to tell if '5' was pressed on the keypad instead of the number keys. Later, I will show you a way to fake CTRL, ALT, and Shift for CEGUI but it wont be in real time.
Despite this, there should be enough utility in them to support a GUI. You can enter text, tab, arrow key about, etc. But if your app needs RIGHT-CRTL for 'fire missles' and Keypad-Slash for 'shields' you'll want another input library.
These are the Set-Handler and the What-a-Handler-Should-Look-Like functions:
void glutKeyboardFunc(myKeyboardFunc)
Set the handler for a normal keypress. These would be keys that generate
normal ASCII characters. 'Delete' (ASCII 127) is a normal key. 'Insert' is
not. The special keys are handled by glutSpecialFunc (see below).
Example Handler:
- void myKeyboardFunc(unsigned char key, int x, int y);
You get the ASCII value of the key pressed and the current mouse x and y.
void glutKeyboardUpFunc(myKeyboardUpFunc)
Set the handler for a normal key release.
Example Handler:
- void myKeyboardUpFunc(unsigned char key, int x, int y)
You get the ASCII value of the key released and the current mouse x and y.
glutSpecialFunc(mySpecialFunc)
Set the handler for a special keypress.
Example Handler:
- void mySpecialFunc(int key, int x, int y)
You get an int with the special key value and the current mouse x and y. The possible values are:
- GLUT_KEY_F1 through GLUT_KEY_F12
- GLUT_KEY_UP, GLUT_KEY_RIGHT, and GLUT_KEY_DOWN, and GLUT_KEY_LEFT
- GLUT_KEY_PAGE_UP and GLUT_KEY_PAGE_DOWN,
- GLUT_KEY_HOME, GLUT_KEY_END, and GLUT_KEY_INSERT
glutSpecialUpFunc(mySpecialupFunc)
Sets the handler for a special key release.
Example Handler:
- void mySpecialUpFunc(int key, int x, int y)
You get an int with the special key value and the current mouse x and y.
Connecting GLUT's Keyboard Callbacks to CEGUI
As you probably know, CEGUI does not capture any input. You need to feed it in it with the various .inject_Something_() functions.
Faking CTRL, ALT, and Shift
As mentioned, GLUT does not generate an event when the user presses or releases
these keys. If does have a function called glutGetModifiers() that lets you
poll their state. It returns an INT with certain bits set.
First we need to add some global flags to our program:
// Track the status of modifiers bool ctrl_held = false; bool alt_held = false; bool shift_held = false;
Then a function to track the state of these keys:
void fakeCtrlAltShift() { int status = glutGetModifiers(); if (status & GLUT_ACTIVE_CTRL) { if (!ctrl_held) { ctrl_held = true; CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::LeftControl); } } else { if (ctrl_held) { ctrl_held = false; CEGUI::System::getSingleton().injectKeyUp(CEGUI::Key::LeftControl); } } // if (status & GLUT_ACTIVE_ALT) { if (!alt_held) { alt_held = true; CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::LeftAlt); } } else { if (alt_held) { alt_held = false; CEGUI::System::getSingleton().injectKeyUp(CEGUI::Key::LeftAlt); } } // if (status & GLUT_ACTIVE_SHIFT) { if (!shift_held) { shift_held = true; CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::LeftShift); } } else { if (shift_held) { shift_held = false; CEGUI::System::getSingleton().injectKeyUp(CEGUI::Key::LeftShift); } } }
We'll call this in every keyboard handler. It's not pretty but it should keep CEGUI informed.
Scan Codes
For key presses, CEGUI wants to be told the ASCII value of the key pressed and
the system scan code generated. For key releases, CEGUI wants the scan code
only. Our problem is GLUT has no idea what a scan code is.
Here's two functions to create some fake scan codes, one for normal input and one for the special keys:
// Map ASCII to Scan Codes int mapNormal(unsigned char c) { int scancode; switch(c) { case 97: case 65: scancode = CEGUI::Key::A; break; case 98: case 66: scancode = CEGUI::Key::B; break; case 99: case 67: scancode = CEGUI::Key::C; break; case 100: case 68: scancode = CEGUI::Key::D; break; case 101: case 69: scancode = CEGUI::Key::E; break; case 102: case 70: scancode = CEGUI::Key::F; break; case 103: case 71: scancode = CEGUI::Key::G; break; case 104: case 72: scancode = CEGUI::Key::H; break; case 105: case 73: scancode = CEGUI::Key::I; break; case 106: case 74: scancode = CEGUI::Key::J; break; case 107: case 75: scancode = CEGUI::Key::K; break; case 108: case 76: scancode = CEGUI::Key::L; break; case 109: case 77: scancode = CEGUI::Key::M; break; case 110: case 78: scancode = CEGUI::Key::N; break; case 111: case 79: scancode = CEGUI::Key::O; break; case 112: case 80: scancode = CEGUI::Key::P; break; case 113: case 81: scancode = CEGUI::Key::Q; break; case 114: case 82: scancode = CEGUI::Key::R; break; case 115: case 83: scancode = CEGUI::Key::S; break; case 116: case 84: scancode = CEGUI::Key::T; break; case 117: case 85: scancode = CEGUI::Key::U; break; case 118: case 86: scancode = CEGUI::Key::V; break; case 119: case 87: scancode = CEGUI::Key::W; break; case 120: case 88: scancode = CEGUI::Key::X; break; case 121: case 89: scancode = CEGUI::Key::Y; break; case 122: case 90: scancode = CEGUI::Key::Z; break; case 27: scancode = CEGUI::Key::Escape; break; case 49: scancode = CEGUI::Key::One; break; case 50: scancode = CEGUI::Key::Two; break; case 51: scancode = CEGUI::Key::Three; break; case 52: scancode = CEGUI::Key::Four; break; case 53: scancode = CEGUI::Key::Five; break; case 54: scancode = CEGUI::Key::Six; break; case 55: scancode = CEGUI::Key::Seven; break; case 56: scancode = CEGUI::Key::Eight; break; case 57: scancode = CEGUI::Key::Nine; break; case 48: scancode = CEGUI::Key::Zero; break; case 45: scancode = CEGUI::Key::Minus; break; case 61: scancode = CEGUI::Key::Equals; break; case 8: scancode = CEGUI::Key::Backspace; break; case 9: scancode = CEGUI::Key::Tab; break; case 91: scancode = CEGUI::Key::LeftBracket; break; case 93: scancode = CEGUI::Key::RightBracket; break; case 13: scancode = CEGUI::Key::Return; break; case 59: scancode = CEGUI::Key::Semicolon; break; case 39: scancode = CEGUI::Key::Apostrophe; break; case 96: scancode = CEGUI::Key::Grave; break; case 92: scancode = CEGUI::Key::Backslash; break; case 44: scancode = CEGUI::Key::Comma; break; case 46: scancode = CEGUI::Key::Period; break; case 47: scancode = CEGUI::Key::Slash; break; case 42: scancode = CEGUI::Key::Multiply; break; case 32: scancode = CEGUI::Key::Space; break; case 64: scancode = CEGUI::Key::At; break; case 58: scancode = CEGUI::Key::Colon; break; case 95: scancode = CEGUI::Key::Underline; break; case 127: scancode = CEGUI::Key::Delete; break; default: scancode = 0; } return scancode; }
// Map Special GLUT Keys to Scan Codes int mapSpecial(int c) { int scancode; switch(c) { case 1: scancode = CEGUI::Key::F1; break; case 2: scancode = CEGUI::Key::F2; break; case 3: scancode = CEGUI::Key::F3; break; case 4: scancode = CEGUI::Key::F4; break; case 5: scancode = CEGUI::Key::F5; break; case 6: scancode = CEGUI::Key::F6; break; case 7: scancode = CEGUI::Key::F7; break; case 8: scancode = CEGUI::Key::F8; break; case 9: scancode = CEGUI::Key::F9; break; case 10: scancode = CEGUI::Key::F10; break; case 11: scancode = CEGUI::Key::F11; break; case 12: scancode = CEGUI::Key::F12; break; case 104: scancode = CEGUI::Key::PageUp; break; case 105: scancode = CEGUI::Key::PageDown; break; case 106: scancode = CEGUI::Key::Home; break; case 107: scancode = CEGUI::Key::End; break; case 100: scancode = CEGUI::Key::ArrowLeft; break; case 101: scancode = CEGUI::Key::ArrowUp; break; case 102: scancode = CEGUI::Key::ArrowRight; break; case 103: scancode = CEGUI::Key::ArrowDown; break; case 108: scancode = CEGUI::Key::Insert; break; default: scancode = 0; } return scancode; }
Normal Keypresses
void myKeyboardFunc(unsigned char key, int x, int y) { fakeCtrlAltShift(); CEGUI::System::getSingleton().injectChar(key); int scancode = mapNormal(key); if (scancode) { CEGUI::System::getSingleton().injectKeyUp(scancode); } }
void myKeyboardUpFunc(unsigned char key, int x, int y) { fakeCtrlAltShift(); int scancode = mapNormal(key); if (scancode) { CEGUI::System::getSingleton().injectKeyUp(scancode); } }
Special Keypresses
void mySpecialFunc(int key, int x, int y) { fakeCtrlAltShift(); int scancode = mapSpecial(key); if (scancode) { CEGUI::System::getSingleton().injectKeyDown(scancode); } }
void mySpecialUpFunc(int key, int x, int y) { fakeCtrlAltShift(); int scancode = mapSpecial(key); if (scancode) { CEGUI::System::getSingleton().injectKeyUp(scancode); } }
GLUT's Mouse Callbacks
glutMouseFunc(myMouseFunc)
Sets the handler for any mouse button function. This includes presses and
releases. Scrolling a mouse wheels generates a press and a release for each
tick.
Example Handler:
- void myMouseFunc(int button, int state, int x, int y)
The button numbering looks like this (depending on your mouse):
- 0 = Left
- 1 = Middle
- 2 = Right
- 3 = MouseWheel Up
- 4 = MouseWheel Down
You may notice that the middle and right buttons are swapped from what Windows programmers would expect.
If state == 0, the event is a button press. If state == 1, the event is a button release. X and Y are the current mouse co-ordinates.
glutPassiveMotionFunc(myPassiveMotionFunc)
Set the handler for mouse movement with NO buttons held -- ie not dragging.
Example Handler:
- void myPassiveMotionFunc(int x, int y)
Pretty simple, x == x, y == y. You will not receive callbacks when the mouse pointer leaves the GLUT window.
glutMotionFunc(myMotionFunc)
Sets the handler for mouse movent with ANY button held -- ie dragging.
Example Handler:
- void myMotionFunc(int x, int y)
Again x==x, y==y. The behavoir is a little different in that you will get callbacks with a button held and the mouse point dragged out of the GLUT window.
For more exotic callbacks, please see: http://www.opengl.org/resources/libraries/glut/spec3/node45.html
Connecting GLUT's Mouse Callbacks to CEGUI
Handling Buttons
void myMouseFunc(int button, int state, int x, int y) { if (state == 0) // State 0 = Button Pressed { switch (button) { case 0: // glut's left mouse button CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::LeftButton); break; case 1: // glut's middle mouse button CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton); break; case 2: // glut's right mouse button CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::RightButton); break; case 3: // glut's mouse wheel up CEGUI::System::getSingleton().injectMouseWheelChange(2.0); break; case 4: // glut's mouse wheen down CEGUI::System::getSingleton().injectMouseWheelChange(-2.0); break; } } else if (state == 1) // State 1 = Button Released { switch (button) { case 0: // glut's left mouse button CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::LeftButton); break; case 1: // glut's middle mouse button CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::MiddleButton); break; case 2: // glut's right mouse button CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::RightButton); break; } } }
Handling Movement
You need both of these, since GLUT uses separate callbacks for normal movement
and dragging (or register one function to both callbacks):
void myPassiveMotionFunc(int x, int y) { CEGUI::System::getSingleton().injectMousePosition(x,y); }
void myMotionFunc(int x, int y) { CEGUI::System::getSingleton().injectMousePosition(x,y); }
Registering the Callbacks
In the initialization code of your GLUT program you'll want to add:
// Set some input handlers glutKeyboardFunc(myKeyboardFunc); // key pressed glutKeyboardUpFunc(myKeyboardUpFunc); // key released glutSpecialFunc(mySpecialFunc); // special key pressed glutSpecialUpFunc(mySpecialUpFunc); // special key released glutMouseFunc(myMouseFunc); // any mouse button press or release glutPassiveMotionFunc(myPassiveMotionFunc); // mouse movement with no buttons held glutMotionFunc(myMotionFunc); // mouse movement with any button held
Creating a Renderer
Naturally, GLUT will use the OpenGLRenderer. So in your CEGUI initialization you'll want:
CEGUI::OpenGLRenderer* myRenderer = new CEGUI::OpenGLRenderer(0); new CEGUI::System(myRenderer);
The New Loop
while( keep_running ) { glutMainLoopEvent(); render(); CEGUI::System::getSingleton().renderGUI(); glutSwapBuffers(); }
Makefile for GLUT + CEGUI
# Makefile # compile gui_loop # gui_loop: gui_loop.o g++ gui_loop.o -lglut -L/usr/local/lib -lCEGUIBase -lCEGUIOpenGLRenderer -o gui_loop # gui_loop.o: gui_loop.cpp g++ -c gui_loop.cpp -I/usr/local/include/CEGUI # .PHONY: clean clean: rm -rf *.o gui_loop
License for the Code Samples
Copyright (C) 2006 Jim Storch
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely. Attribution is not required.