some progress concerning IMGUI widgets (added simple text input)

main
Martin Felis (berta) 2010-09-11 02:28:50 +02:00
parent 54ea3c21d4
commit 3f962163b3
13 changed files with 299 additions and 74 deletions

View File

@ -10,6 +10,7 @@ BEGIN_ENUM(Event)
DECL_ENUM_ELEMENT(EventAccelerateStart), DECL_ENUM_ELEMENT(EventAccelerateStart),
DECL_ENUM_ELEMENT(EventAccelerateStop), DECL_ENUM_ELEMENT(EventAccelerateStop),
DECL_ENUM_ELEMENT(EventLevelComplete), DECL_ENUM_ELEMENT(EventLevelComplete),
DECL_ENUM_ELEMENT(EventChangeGameState),
DECL_ENUM_ELEMENT(EventGameOver), DECL_ENUM_ELEMENT(EventGameOver),
DECL_ENUM_ELEMENT(EventShipExplode) DECL_ENUM_ELEMENT(EventShipExplode)
} }

View File

@ -1,4 +1,5 @@
#include "Controller.h" #include "Controller.h"
#include "AsteroidsEvents.h"
namespace asteroids { namespace asteroids {
@ -16,7 +17,16 @@ int Controller::OnInit (int argc, char *argv[]) {
mBindings[SDLK_F8] = "toggleconsole"; mBindings[SDLK_F8] = "toggleconsole";
mBindings[SDLK_F9] = "set playerspeed 5.0"; mBindings[SDLK_F9] = "set playerspeed 5.0";
Engine::RegisterListener (this, EventChangeGameState);
return 0; return 0;
} }
bool Controller::OnReceiveEvent (const Engine::EventBasePtr &event) {
if (event->mEventType == EventChangeGameState) {
IMGUIClear();
}
return false;
}
} }

View File

@ -26,6 +26,7 @@ class Controller : public Engine::ControllerBase {
virtual int OnInit (int argc, char* argv[]); virtual int OnInit (int argc, char* argv[]);
/** \brief Registers the commands of the cnotroller */ /** \brief Registers the commands of the cnotroller */
virtual void OnRegisterCommands (); virtual void OnRegisterCommands ();
virtual bool OnReceiveEvent (const Engine::EventBasePtr &event);
}; };
} }

View File

@ -359,6 +359,15 @@ int Model::DoSaveLevel (const char* filename) {
level_file.close(); level_file.close();
return 0; return 0;
} }
void Model::SetGameState (const unsigned int &state) {
mLastGameState = mGameState;
Engine::EventBasePtr changegamestate_event (new Engine::EventBase());
changegamestate_event->mEventType = EventChangeGameState;
QueueEvent (changegamestate_event);
mGameState = state;
}
bool Model::OnLevelComplete() { bool Model::OnLevelComplete() {
Engine::LogMessage ("Level complete!"); Engine::LogMessage ("Level complete!");

View File

@ -17,10 +17,15 @@ class Model : public Engine::ModelBase {
/** \brief Resets values from a previous game */ /** \brief Resets values from a previous game */
void OnNewGame (); void OnNewGame ();
virtual void SetGameState (const unsigned int &state);
int GetPlayerLives () { return mPlayerLives; }; int GetPlayerLives () { return mPlayerLives; };
unsigned int GetPoints () { return mPoints; }; unsigned int GetPoints () { return mPoints; };
std::string GetPlayerName() { return mPlayerName; }; std::string GetPlayerName() { return mPlayerName; };
void SetPlayerName(const std::string &name) { mPlayerName = name; }; void SetPlayerName(const std::string &name) {
Engine::LogDebug("new player name: %s", name.c_str());
mPlayerName = name;
};
float GetWorldWidth (); float GetWorldWidth ();
float GetWorldHeight (); float GetWorldHeight ();

View File

@ -33,19 +33,9 @@ void MainMenuOverlay::Init () {
} }
bool MainMenuOverlay::OnKeyDown (const SDL_keysym &keysym) { bool MainMenuOverlay::OnKeyDown (const SDL_keysym &keysym) {
switch (keysym.sym) { if (keysym.sym == SDLK_ESCAPE)
case SDLK_ESCAPE: Engine::RunCommand("quit");
Engine::RunCommand ("quit"); return false;
return true;
case SDLK_RETURN:
GetModel()->SetGameState(GameStateEnterPlayername);
return true;
case SDLK_h:
GetModel()->SetGameState(GameStateShowHighscore);
return true;
default:
return true;
}
} }
void MainMenuOverlay::Draw () { void MainMenuOverlay::Draw () {
@ -70,16 +60,16 @@ void MainMenuOverlay::Draw () {
glPushMatrix (); glPushMatrix ();
glLoadIdentity (); glLoadIdentity ();
// Engine::DrawGLString ( right * 0.5 - 100, 100, "A s t e r o i d s");
Engine::GUI::Label (4, "A s t e r o i d s", right * 0.5 - 100, 180); Engine::GUI::Label (4, "A s t e r o i d s", right * 0.5 - 100, 180);
if (Engine::GUI::Button (1, "Start Game", right * 0.5 - 100, 200, 250, 40)) { if (Engine::GUI::Button (1, "New Game", right * 0.5 - 100, 200, 250, 40)) {
GetModel()->SetGameState(GameStateEnterPlayername); GetModel()->SetGameState(GameStateEnterPlayername);
GetController()->uistate.hotitem = 0;
} }
if (Engine::GUI::Button (2, "Highscores", right * 0.5 - 100, 250, 250, 40)) { if (Engine::GUI::Button (2, "Highscores", right * 0.5 - 100, 250, 250, 40)) {
GetModel()->SetGameState(GameStateShowHighscore); GetModel()->SetGameState(GameStateShowHighscore);
GetController()->uistate.hotitem = 0;
} }
if (Engine::GUI::Button (3, "Quit", right * 0.5 - 100, 330, 250, 40)) { if (Engine::GUI::Button (3, "Quit", right * 0.5 - 100, 330, 250, 40)) {
@ -88,13 +78,6 @@ void MainMenuOverlay::Draw () {
GetView()->SelectFont("console.ttf"); GetView()->SelectFont("console.ttf");
/*
// then we do the drawings
Engine::DrawGLString ( right * 0.5 - 100, bottom * 0.5 - 8 - 32, "Main Menu");
Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 - 8 - 16, "[Return] - Start Game");
Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 - 8, "[h] - Show Highscore");
Engine::DrawGLString ( right * 0.5 - 80, bottom * 0.5 + 8, "[Escape] - Quit");
*/
glPopMatrix (); glPopMatrix ();
glMatrixMode (GL_PROJECTION); glMatrixMode (GL_PROJECTION);
@ -553,39 +536,13 @@ void EnterPlayernameOverlay::Init () {
} }
bool EnterPlayernameOverlay::OnKeyDown (const SDL_keysym &keysym) { bool EnterPlayernameOverlay::OnKeyDown (const SDL_keysym &keysym) {
GetController()->EnableTextinput(true); if (keysym.sym == SDLK_ESCAPE) {
GetModel()->SetGameState(GameStateMainMenu);
switch (keysym.sym) { GetController()->uistate.hotitem = 0;
case SDLK_ESCAPE: return true;
GetModel()->SetGameState(GameStateMainMenu);
return true;
case SDLK_BACKSPACE:
if (mPlayerNameInput.size() > 0)
mPlayerNameInput = mPlayerNameInput.substr (0, mPlayerNameInput.size() - 1 );
return true;
break;
case SDLK_RETURN:
// If we just entered a new entry we simply show the highscore table,
// otherwise we switch back to the main menu
GetModel()->SetPlayerName(mPlayerNameInput);
GetController()->EnableTextinput(false);
GetModel()->SetGameState(GameStateRunning);
return true;
default:
break;
} }
if (keysym.unicode) { return false;
if ((keysym.unicode & 0xFF80) == 0) {
mPlayerNameInput += keysym.unicode & 0x7F;
return true;
} else {
Engine::LogWarning ("Input key not supported!");
return false;
}
}
return true;
} }
void EnterPlayernameOverlay::Draw () { void EnterPlayernameOverlay::Draw () {
@ -611,21 +568,28 @@ void EnterPlayernameOverlay::Draw () {
glLoadIdentity (); glLoadIdentity ();
GetView()->SelectFont("console.ttf"); GetView()->SelectFont("console.ttf");
float x = right * 0.5 - 100;
float y = bottom * 0.5 - 8 - 128;
// then we do the drawings Engine::GUI::Label (4, "A s t e r o i d s", right * 0.5 - 100, 180);
Engine::DrawGLString ( x, y, "A s t e r o i d s");
y += 30;
Engine::DrawGLString ( x, y, "Enter your name: ");
std::string name_output (mPlayerNameInput); Engine::GUI::Label (1, "Enter your name: ", right * 0.5 - 100, 250);
if (SDL_GetTicks() >> 9 & 1)
name_output += "_"; // Make sure we have UNICODE processing enabled!
GetController()->EnableTextinput(true);
std::string player_name = GetModel()->GetPlayerName();
if (Engine::GUI::LineEdit (2, right * 0.5 + 20, 238, player_name, 16)) {
GetModel()->SetPlayerName(player_name);
}
if (Engine::GUI::Button (3, "Start Game", right - 150 - 20, 500, 150, 40)) {
GetModel()->SetGameState(GameStateRunning);
}
if (Engine::GUI::Button (5, "Back", 20, 500, 150, 40)) {
GetModel()->SetGameState(GameStateMainMenu);
GetController()->uistate.hotitem = 0;
}
Engine::DrawGLString ( x + 15*8, y, name_output.c_str());
Engine::DrawGLString ( x + 16, y + 16, "Press [Return] to continue.");
glPopMatrix (); glPopMatrix ();
glMatrixMode (GL_PROJECTION); glMatrixMode (GL_PROJECTION);

View File

@ -57,6 +57,12 @@ int ControllerBase::OnInit (int argc, char* argv[]) {
uistate.activeitem = 0; uistate.activeitem = 0;
uistate.hotitem = 0; uistate.hotitem = 0;
uistate.kbditem = 0;
uistate.last_keysym = SDLK_CLEAR;
uistate.last_unicode = 0;
uistate.lastwidget = 0;
ControllerInstance = this; ControllerInstance = this;
return 0; return 0;
@ -158,6 +164,12 @@ void ControllerBase::IMGUIFinish () {
/** \brief Keyboard processing */ /** \brief Keyboard processing */
bool ControllerBase::OnKeyDown (const SDL_keysym &keysym) { bool ControllerBase::OnKeyDown (const SDL_keysym &keysym) {
mButtonStates.set(keysym.sym, true); mButtonStates.set(keysym.sym, true);
uistate.last_keysym = keysym.sym;
// Only when Unicode processing is activated store the unicode value
if (SDL_EnableUNICODE(-1)) {
uistate.last_unicode = keysym.unicode;
}
if (mView->mOverlayManager.SendKeyDown (keysym)) if (mView->mOverlayManager.SendKeyDown (keysym))
return true; return true;

View File

@ -16,6 +16,12 @@ class Module;
struct UIState { struct UIState {
int hotitem; int hotitem;
int activeitem; int activeitem;
int kbditem;
SDLKey last_keysym;
Uint16 last_unicode;
int lastwidget;
}; };
/** \brief Defines the number of keys (keyboard + mous) that we can bind to. /** \brief Defines the number of keys (keyboard + mous) that we can bind to.
@ -67,6 +73,11 @@ class ControllerBase : public Module {
void IMGUIPrepare () { void IMGUIPrepare () {
uistate.hotitem = 0; uistate.hotitem = 0;
} }
void IMGUIClear () {
LogMessage ("Called IMGUIClear()");
uistate.hotitem = 0;
uistate.kbditem = 0;
}
void IMGUIFinish (); void IMGUIFinish ();
UIState uistate; UIState uistate;

View File

@ -30,6 +30,15 @@ bool regionhit (int x, int y, int w, int h) {
return true; return true;
} }
/** \brief Draws a label with a given caption at the position (vertically centered)
*
* This function draws the label at the horizontal x position and centers the
* label with regard to the height of the rendered caption.
*
* \TODO [med] The vertical alignment around the center of the vertical height
* of the string is rather unfortunate as different contents will be rendered
* at different vertical positions (e.g. "aaa" and "ggg")
*/
void Label (int id, const char* caption, int x, int y) { void Label (int id, const char* caption, int x, int y) {
if (caption != NULL) { if (caption != NULL) {
float width, height; float width, height;
@ -43,6 +52,9 @@ void Label (int id, const char* caption, int x, int y) {
} }
/** \brief Draws a button at the given position /** \brief Draws a button at the given position
*
* The area defined by the parameters defines the clickable area. However
* decorations might be drawn on a smaller or bigger area.
* *
* \returns true if it was clicked * \returns true if it was clicked
* *
@ -51,6 +63,8 @@ bool Button (int id, const char* caption, int x, int y, int w, int h) {
controller = EngineGetController(); controller = EngineGetController();
assert (controller); assert (controller);
// LogMessage ("id = %d hotitem = %d activeitem = %d kbditem = %d", id, controller->uistate.hotitem, controller->uistate.activeitem, controller->uistate.kbditem);
// Check for hotness // Check for hotness
if (regionhit (x, y, w, h)) { if (regionhit (x, y, w, h)) {
controller->uistate.hotitem = id; controller->uistate.hotitem = id;
@ -59,11 +73,22 @@ bool Button (int id, const char* caption, int x, int y, int w, int h) {
controller->uistate.activeitem = id; controller->uistate.activeitem = id;
} }
// If nothing is selected
if (controller->uistate.hotitem != 0) {
controller->uistate.kbditem = controller->uistate.hotitem;
}
if (controller->uistate.kbditem == 0) {
controller->uistate.hotitem = id;
controller->uistate.kbditem = id;
}
// Render // Render
glColor3f (0.2, 0.2, 0.2); glColor3f (0.2, 0.2, 0.2);
DrawRect2D (x + 4, y + 4, w, h); DrawRect2D (x + 4, y + 4, w, h);
if (controller->uistate.hotitem == id) { if (controller->uistate.hotitem == id
|| controller->uistate.kbditem == id) {
if (controller->uistate.activeitem == id) { if (controller->uistate.activeitem == id) {
glColor3f (0.8, 0.8, 0.8); glColor3f (0.8, 0.8, 0.8);
DrawRect2D (x, y, w, h); DrawRect2D (x, y, w, h);
@ -87,11 +112,179 @@ bool Button (int id, const char* caption, int x, int y, int w, int h) {
view->DrawGLString(x + w * 0.5 - width * 0.5, y + h * 0.5 - height * 0.5, caption); view->DrawGLString(x + w * 0.5 - width * 0.5, y + h * 0.5 - height * 0.5, caption);
} }
// Logic // Mouse Logic
if (controller->GetButtonState(MouseButtonLeft) == false if (controller->GetButtonState(MouseButtonLeft) == false
&& controller->uistate.hotitem == id && controller->uistate.hotitem == id
&& controller->uistate.activeitem == id) && controller->uistate.activeitem == id) {
controller->uistate.lastwidget = id;
return true; return true;
}
// Keyboard Logic
if (controller->uistate.kbditem == id) {
// We have to make sure, that we always clear the uistate.last_keysym
// value, otherwise the same action might be repeated over and over.
switch (controller->uistate.last_keysym) {
case SDLK_DOWN:
controller->uistate.kbditem = 0;
controller->uistate.hotitem = 0;
controller->uistate.last_keysym = SDLK_CLEAR;
break;
case SDLK_UP:
controller->uistate.kbditem = controller->uistate.lastwidget;
controller->uistate.hotitem = controller->uistate.lastwidget;
controller->uistate.last_keysym = SDLK_CLEAR;
break;
case SDLK_RETURN:
controller->uistate.last_keysym = SDLK_CLEAR;
// As we (probably) exit the current set of widgets, we have to clear
// the uistate.kbditem value.
controller->uistate.kbditem = 0;
return true;
break;
}
}
controller->uistate.lastwidget = id;
return false;
}
/** \brief An Edit widget that allows editing of a string consisting of one line
*
* \TODO [med] vertical alignment (especially of text) is a bit whacky
*
* \returns true if it was clicked
*
*/
bool LineEdit (int id, int x, int y, std::string &text_value, const int &maxlength) {
controller = EngineGetController();
assert (controller);
int w = maxlength * 16;
int h = 16;
// LogMessage ("id = %d hotitem = %d activeitem = %d kbditem = %d", id, controller->uistate.hotitem, controller->uistate.activeitem, controller->uistate.kbditem);
// Check for hotness
if (regionhit (x, y, w, h)) {
controller->uistate.hotitem = id;
if (controller->uistate.activeitem == 0
&& controller->GetButtonState(MouseButtonLeft))
controller->uistate.activeitem = id;
}
// If nothing is selected
if (controller->uistate.hotitem != 0) {
controller->uistate.kbditem = controller->uistate.hotitem;
}
if (controller->uistate.kbditem == 0) {
controller->uistate.hotitem = id;
controller->uistate.kbditem = id;
}
// Render
glColor3f (0.2, 0.2, 0.2);
DrawRect2D (x + 4, y + 4, w, h);
if (controller->uistate.hotitem == id
|| controller->uistate.kbditem == id) {
if (controller->uistate.activeitem == id) {
glColor3f (0.8, 0.8, 0.8);
DrawRect2D (x, y, w, h);
} else {
glColor3f (0.7, 0.7, 0.7);
DrawRect2D (x, y, w, h);
}
} else {
glColor3f (0.4, 0.4, 0.4);
DrawRect2D (x, y, w, h);
}
// Rendering of the current value
float width, height;
view = EngineGetView ();
assert (view);
glColor3f (1., 1., 1.);
std::string text_output = text_value;
if (controller->uistate.kbditem == id && SDL_GetTicks() >> 9 & 1)
text_output += "_";
view->DrawGLStringMeasure(text_value.c_str(), &width, &height);
view->DrawGLString(x + 16, y + 12, text_output.c_str());
// Keyboard Logic
if (controller->uistate.kbditem == id) {
switch (controller->uistate.last_keysym) {
case SDLK_DOWN:
controller->uistate.kbditem = 0;
controller->uistate.hotitem = 0;
controller->uistate.last_keysym = SDLK_CLEAR;
break;
case SDLK_UP:
controller->uistate.kbditem = controller->uistate.lastwidget;
controller->uistate.hotitem = controller->uistate.lastwidget;
controller->uistate.last_keysym = SDLK_CLEAR;
break;
case SDLK_CLEAR:
controller->uistate.last_keysym = SDLK_CLEAR;
controller->uistate.last_unicode = 0;
return false;
break;
case SDLK_ESCAPE:
controller->uistate.last_keysym = SDLK_CLEAR;
controller->uistate.last_unicode = 0;
controller->uistate.hotitem = 0;
controller->uistate.kbditem = 0;
return false;
break;
case SDLK_RETURN:
controller->uistate.last_keysym = SDLK_CLEAR;
controller->uistate.last_unicode = 0;
controller->uistate.hotitem = 0;
controller->uistate.kbditem = 0;
return true;
break;
case SDLK_BACKSPACE:
if (text_value.size() > 0) {
text_value = text_value.substr(0, text_value.size() - 1);
controller->uistate.last_keysym = SDLK_CLEAR;
controller->uistate.last_unicode = 0;
return true;
}
break;
default:
// The raw input processing
if (maxlength > 0 && text_value.size() < maxlength) {
if (controller->uistate.last_unicode) {
if ((controller->uistate.last_unicode & 0xFF80) == 0) {
text_value += controller->uistate.last_unicode & 0x7F;
controller->uistate.last_unicode = 0;
return true;
} else {
LogWarning ("Input key not supported!");
return false;
}
}
}
break;
}
}
controller->uistate.lastwidget = id;
// Mouse Logic
if (controller->GetButtonState(MouseButtonLeft) == false
&& controller->uistate.hotitem == id
&& controller->uistate.activeitem == id) {
controller->uistate.kbditem = id;
}
return false; return false;
} }

View File

@ -1,6 +1,8 @@
#ifndef _IMGUICONTROLS_H #ifndef _IMGUICONTROLS_H
#define _IMGUICONTROLS_H #define _IMGUICONTROLS_H
#include <string>
namespace Engine { namespace Engine {
namespace GUI { namespace GUI {
@ -20,6 +22,8 @@ void Label (int id, const char* caption, int x, int y);
*/ */
bool Button (int id, const char* caption, int x, int y, int w, int h); bool Button (int id, const char* caption, int x, int y, int w, int h);
bool LineEdit (int id, int x, int y, std::string &text_value, const int &maxlength);
}; };
}; };

View File

@ -73,7 +73,7 @@ class ModelBase : public Module {
void SendEntityCollisionEvent (const unsigned int reference_entity_id, void SendEntityCollisionEvent (const unsigned int reference_entity_id,
const unsigned int incidence_entity_id, float collision_time, vector3d normal); const unsigned int incidence_entity_id, float collision_time, vector3d normal);
void SetGameState (const unsigned int &state) { virtual void SetGameState (const unsigned int &state) {
mLastGameState = mGameState; mLastGameState = mGameState;
mGameState = state; mGameState = state;
}; };

View File

@ -146,7 +146,7 @@ void ViewBase::UpdateCamera () {
mCamera->Update (); mCamera->Update ();
} }
void ViewBase::Draw () { void ViewBase::PreDraw() {
// Clear the screen // Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -166,7 +166,13 @@ void ViewBase::Draw () {
last_fps_update = 0; last_fps_update = 0;
frame_counter = 0; frame_counter = 0;
} }
}
void ViewBase::Draw () {
// Perform pre-Draw actions
PreDraw ();
// Actual Drawing
UpdateCamera (); UpdateCamera ();
if (mDrawGrid) if (mDrawGrid)
@ -179,7 +185,11 @@ void ViewBase::Draw () {
mOverlayManager.Draw(); mOverlayManager.Draw();
// and update the screen // Perform post-Draw actions
PostDraw();
}
void ViewBase::PostDraw() {
SDL_GL_SwapBuffers (); SDL_GL_SwapBuffers ();
} }

View File

@ -27,6 +27,11 @@ class ViewBase : public Module{
/** \brief Resizes the View */ /** \brief Resizes the View */
void Resize (int width, int height); void Resize (int width, int height);
/** \brief Performs actions before drawing (e.g. timer stuff) */
void PreDraw();
/** \brief Performs actions after drawing (e.g. swapping of buffers, etc.) */
void PostDraw();
/** \brief Performs all drawing */ /** \brief Performs all drawing */
virtual void Draw (); virtual void Draw ();