diff --git a/asteroids/UserInterface.cc b/asteroids/UserInterface.cc index 7960e69..13ef928 100644 --- a/asteroids/UserInterface.cc +++ b/asteroids/UserInterface.cc @@ -16,6 +16,8 @@ #include "Engine.h" #include "Game.h" +#include "IMGUIControls.h" + namespace asteroids { // static float left = 0; @@ -68,15 +70,31 @@ void MainMenuOverlay::Draw () { glPushMatrix (); 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); + + if (Engine::GUI::Button (1, "Start Game", right * 0.5 - 100, 200, 250, 40)) { + GetModel()->SetGameState(GameStateEnterPlayername); + } + + if (Engine::GUI::Button (2, "Highscores", right * 0.5 - 100, 250, 250, 40)) { + GetModel()->SetGameState(GameStateShowHighscore); + } + + if (Engine::GUI::Button (3, "Quit", right * 0.5 - 100, 330, 250, 40)) { + Engine::RunCommand("quit"); + } + GetView()->SelectFont("console.ttf"); +/* // then we do the drawings - Engine::DrawGLString ( right * 0.5 - 100, bottom * 0.5 - 8 - 64, "A s t e r o i d s"); 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 (); glMatrixMode (GL_PROJECTION); @@ -602,7 +620,9 @@ void EnterPlayernameOverlay::Draw () { Engine::DrawGLString ( x, y, "Enter your name: "); std::string name_output (mPlayerNameInput); - name_output += "_"; + if (SDL_GetTicks() >> 9 & 1) + name_output += "_"; + Engine::DrawGLString ( x + 15*8, y, name_output.c_str()); Engine::DrawGLString ( x + 16, y + 16, "Press [Return] to continue."); diff --git a/asteroids/UserInterface.h b/asteroids/UserInterface.h index 5e7a141..f375bba 100644 --- a/asteroids/UserInterface.h +++ b/asteroids/UserInterface.h @@ -7,6 +7,7 @@ class OverlayBase; #include "OverlayBase.h" #include "Sprite.h" +#include "IMGUIControls.h" #include namespace asteroids { diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index f8acc54..eebc98d 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -32,6 +32,7 @@ SET ( ENGINE_SRCS VariablesCommands.cc SimpleConsoleOverlay.cc Sprite.cc + IMGUIControls.cc Engine.cc Logging.cc diff --git a/engine/ControllerBase.cc b/engine/ControllerBase.cc index 269df1c..c4a73b4 100644 --- a/engine/ControllerBase.cc +++ b/engine/ControllerBase.cc @@ -49,8 +49,13 @@ int ControllerBase::OnInit (int argc, char* argv[]) { // clear all bindings int i; - for (i = 0; i < BINDING_KEYS_LAST; i++) + for (i = 0; i < BINDING_KEYS_LAST; i++) { mBindings[i] = ""; + mButtonStates.set(i, false); + } + + uistate.activeitem = 0; + uistate.hotitem = 0; ControllerInstance = this; @@ -141,8 +146,19 @@ void ControllerBase::EnableTextinput (bool textinput_state) { } } +void ControllerBase::IMGUIFinish () { + if (GetButtonState(MouseButtonLeft) == false) { + uistate.activeitem = 0; + } else { + if (uistate.activeitem == 0) + uistate.activeitem = -1; + } +} + /** \brief Keyboard processing */ bool ControllerBase::OnKeyDown (const SDL_keysym &keysym) { + mButtonStates.set(keysym.sym, true); + if (mView->mOverlayManager.SendKeyDown (keysym)) return true; @@ -156,6 +172,8 @@ bool ControllerBase::OnKeyDown (const SDL_keysym &keysym) { /** \brief Keyboard processing */ bool ControllerBase::OnKeyUp (const SDL_keysym &keysym) { + mButtonStates.set(keysym.sym, false); + if (mView->mOverlayManager.SendKeyUp (keysym)) return true; @@ -174,6 +192,7 @@ bool ControllerBase::OnKeyUp (const SDL_keysym &keysym) { /** \brief Mouse processing */ bool ControllerBase::OnMouseButtonDown (Uint8 button, Uint16 xpos, Uint16 ypos) { MouseButton mouse_button = convert_sdl_button (button); + mButtonStates.set(mouse_button, true); if (mView->mOverlayManager.SendMouseButtonDown (button, xpos, ypos)) return true; @@ -189,6 +208,7 @@ bool ControllerBase::OnMouseButtonDown (Uint8 button, Uint16 xpos, Uint16 ypos) /** \brief Mouse processing */ bool ControllerBase::OnMouseButtonUp (Uint8 button, Uint16 xpos, Uint16 ypos) { MouseButton mouse_button = convert_sdl_button (button); + mButtonStates.set(mouse_button, false); if (mView->mOverlayManager.SendMouseButtonUp (button, xpos, ypos)) return true; diff --git a/engine/ControllerBase.h b/engine/ControllerBase.h index 6a5f3da..8aa9ed4 100644 --- a/engine/ControllerBase.h +++ b/engine/ControllerBase.h @@ -9,6 +9,15 @@ class ModelBase; class Console; class Module; +/** \brief The IMGUI state + * + * See also http://sol.gfxile.net/imgui/ + */ +struct UIState { + int hotitem; + int activeitem; +}; + /** \brief Defines the number of keys (keyboard + mous) that we can bind to. * * As the keysym enum of SDL has about 320 keys defined and we might have some @@ -42,11 +51,26 @@ class ControllerBase : public Module { pos_out[1] = mMouseWorldPosition[1]; pos_out[2] = mMouseWorldPosition[2]; } + bool GetButtonState (unsigned int key) { + assert (key < BINDING_KEYS_LAST); + return mButtonStates.test(key); + } + void SetButtonState (unsigned int key, bool state) { + assert (key < BINDING_KEYS_LAST); + mButtonStates.set (key, state); + } bool BindKey (int key, const char *command); /** \brief Activates or deactivates unicode processing and key delays of the keyboard inputs */ void EnableTextinput (bool textinput_state); + void IMGUIPrepare () { + uistate.hotitem = 0; + } + void IMGUIFinish (); + + UIState uistate; + protected: /** \brief Initializes the system */ virtual int OnInit (int argc, char* argv[]); @@ -82,8 +106,12 @@ class ControllerBase : public Module { /** \brief Stores the current mouse position in screen coordinates */ int mMouseScreenPosition[2]; - /** \brief Stores the current mouse position on the y=0 plane in wolrd * coordinates */ + /** \brief Stores the current mouse position on the y=0 plane in world coordinates */ float mMouseWorldPosition[3]; + + /** \brief Stores for each button of the mouse whether it is clicked + * \TODO [low] move it to a bitset and remove the fixed amount of buttons */ + std::bitset mButtonStates; /** \brief Contains all the bindings for the keyboard */ std::string mBindings[BINDING_KEYS_LAST]; diff --git a/engine/DrawingsGL.cc b/engine/DrawingsGL.cc index 567e90c..dbd51b6 100644 --- a/engine/DrawingsGL.cc +++ b/engine/DrawingsGL.cc @@ -245,3 +245,12 @@ void DrawVector(vector3d start, vector3d end) { glEnd (); } } + +void DrawRect2D (float x, float y, float w, float h) { + glBegin (GL_QUADS); + glVertex3f (x, y, 0.); + glVertex3f (x, y + h, 0.); + glVertex3f (x + w, y + h, 0.); + glVertex3f (x + w, y, 0.); + glEnd (); +} diff --git a/engine/DrawingsGL.h b/engine/DrawingsGL.h index b3bc9c6..e4ce062 100644 --- a/engine/DrawingsGL.h +++ b/engine/DrawingsGL.h @@ -17,5 +17,6 @@ void DrawDisc(float radius, int segments); void DrawCircle(float radius, int segments); void DrawCone(int segments); void DrawVector(vector3d start, vector3d end); +void DrawRect2D (float x, float y, float w, float h); #endif /* _DRAWINGSGL_H */ diff --git a/engine/Engine.cc b/engine/Engine.cc index a061fc3..29ff6cf 100644 --- a/engine/Engine.cc +++ b/engine/Engine.cc @@ -244,7 +244,9 @@ void Engine::OnMainLoop () { mEventManager->Process(); mModel->UpdateTimer (); mModel->Process (); + mController->IMGUIPrepare(); mView->Draw (); + mController->IMGUIFinish(); } } diff --git a/engine/IMGUIControls.cc b/engine/IMGUIControls.cc new file mode 100644 index 0000000..f269005 --- /dev/null +++ b/engine/IMGUIControls.cc @@ -0,0 +1,100 @@ +#include "IMGUIControls.h" + +#include "Engine.h" +#include "ControllerBase.h" +#include "ViewBase.h" +#include +#include "DrawingsGL.h" +#include "keytable.h" + +Engine::ControllerBase *controller = NULL; +Engine::ViewBase *view = NULL; + +namespace Engine { +namespace GUI { + +/** \brief Checks whether the mouse is in the given rectangle */ +bool regionhit (int x, int y, int w, int h) { + controller = EngineGetController(); + assert (controller); + + int mouse_pos[2]; + + controller->GetMouseScreenPosition(mouse_pos); + + if (mouse_pos[0] < x || + mouse_pos[1] < y || + mouse_pos[0] >= x + w || + mouse_pos[1] >= y + h) + return false; + return true; +} + +void Label (int id, const char* caption, int x, int y) { + if (caption != NULL) { + float width, height; + view = EngineGetView (); + assert (view); + + glColor3f (1., 1., 1.); + view->DrawGLStringMeasure(caption, &width, &height); + view->DrawGLString(x , y + height * 0.5, caption); + } +} + +/** \brief Draws a button at the given position + * + * \returns true if it was clicked + * + */ +bool Button (int id, const char* caption, int x, int y, int w, int h) { + controller = EngineGetController(); + assert (controller); + + // 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; + } + + // Render + glColor3f (0.2, 0.2, 0.2); + DrawRect2D (x + 4, y + 4, w, h); + + if (controller->uistate.hotitem == 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); + } + + // Caption + if (caption != NULL) { + float width, height; + view = EngineGetView (); + assert (view); + + glColor3f (1., 1., 1.); + view->DrawGLStringMeasure(caption, &width, &height); + view->DrawGLString(x + w * 0.5 - width * 0.5, y + h * 0.5 - height * 0.5, caption); + } + + // Logic + if (controller->GetButtonState(MouseButtonLeft) == false + && controller->uistate.hotitem == id + && controller->uistate.activeitem == id) + return true; + + return false; +} + +}; +}; diff --git a/engine/IMGUIControls.h b/engine/IMGUIControls.h new file mode 100644 index 0000000..e23c81a --- /dev/null +++ b/engine/IMGUIControls.h @@ -0,0 +1,27 @@ +#ifndef _IMGUICONTROLS_H +#define _IMGUICONTROLS_H + +namespace Engine { + +namespace GUI { + +/** \brief Checks whether the mouse is in the given rectangle */ +bool regionhit (int x, int y, int w, int h); + +/** \brief Draws a label at the given position with vertical center at y */ +void Label (int id, const char* caption, int x, int y); + +/** \brief Draws a button at the given position + * + * The caption will be centered in the middle of the clickable area. + * + * \returns true if it was clicked + * + */ +bool Button (int id, const char* caption, int x, int y, int w, int h); + +}; + +}; + +#endif /* _IMGUICONTROLS_H */ diff --git a/engine/ViewBase.cc b/engine/ViewBase.cc index 024ff5a..476037e 100644 --- a/engine/ViewBase.cc +++ b/engine/ViewBase.cc @@ -22,7 +22,7 @@ static ViewBase* ViewInstance = NULL; void InitGL () { glClearColor(0.3f, 0.3f, 0.3f, 1.0f); glClearDepth(1.0); - glDepthFunc(GL_LESS); + glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glEnable (GL_CULL_FACE); @@ -245,6 +245,12 @@ void ViewBase::DrawGLString (float x, float y, const char* str) { mCurrentFont->draw (x, y, str); } +void ViewBase::DrawGLStringMeasure (const char* str, float *width, float *height) { + OGLFT::BBox bbox = mCurrentFont->measure (str); + *width = bbox.x_max_ - bbox.x_min_; + *height = bbox.y_max_ - bbox.y_min_; +} + void ViewBase::GetCamereEye (float *eye_out) { assert (mCamera); mCamera->GetEye (eye_out); diff --git a/engine/ViewBase.h b/engine/ViewBase.h index 13e8009..652e9a9 100644 --- a/engine/ViewBase.h +++ b/engine/ViewBase.h @@ -42,6 +42,8 @@ class ViewBase : public Module{ /** \brief Draws a string at the given position using current projection * and modelview matrices */ void DrawGLString (float x, float y, const char* str); + /** \brief Computes the width and height of the rasterized string */ + void DrawGLStringMeasure (const char* str, float *width, float *height); /** \brief Stores the eye poisition in eye_out */ void GetCamereEye (float *eye_out);