BARE2D
BARECEGUI.cpp
Go to the documentation of this file.
1 #include "BARECEGUI.hpp"
2 
3 // For SDL_GetTicks64()
4 #include <SDL2/SDL_timer.h>
5 #include "utf8.h"
6 
7 #include "Logger.hpp"
8 
9 namespace BARE2D {
10 
11  bool BARECEGUI::m_initialized = false;
12  BARECEGUI* BARECEGUI::m_instance = nullptr;
13 
15  if(!m_instance) {
16  m_instance = new BARECEGUI();
17  }
18  return m_instance;
19  }
20 
22  if(m_instance)
23  delete m_instance;
24  }
25 
27 
28  }
29 
32  e->rootWindow->destroy();
33 
34  delete e;
35  }
36  m_contexts.clear();
37  }
38 
39  void BARECEGUI::init(std::string& resourceDirectory, unsigned int numContexts) {
40  m_contexts.clear(); // Just in case :)
41 
42  // Create the first context wrapper - we never have less than 1 context.
44 
45  // Make sure we reuse resources if we can:
46  if(m_initialized) {
47  // We can reuse the renderer - it has no mutable state.
48  primary->renderer = static_cast<CEGUI::OpenGL3Renderer*>(CEGUI::System::getSingleton().getRenderer());
49  } else {
50  // This is our first time initializing, we need to actually create the renderer.
51  primary->renderer = &CEGUI::OpenGL3Renderer::bootstrapSystem();
52  m_initialized = true;
53  }
54 
55  // Now that we have our renderer, we can load all of our resources
56  // First, get the resource provider
57  CEGUI::DefaultResourceProvider* rp = static_cast<CEGUI::DefaultResourceProvider*>(CEGUI::System::getSingleton().getResourceProvider());
58 
59  // Next, set where CEGUI can actually find each of its specialized types of data.
60  rp->setResourceGroupDirectory("imagesets", resourceDirectory + "/imagesets/");
61  rp->setResourceGroupDirectory("schemes", resourceDirectory + "/schemes/");
62  rp->setResourceGroupDirectory("fonts", resourceDirectory + "/fonts/");
63  rp->setResourceGroupDirectory("layouts", resourceDirectory + "/layouts/");
64  rp->setResourceGroupDirectory("looknfeels", resourceDirectory + "/looknfeel/");
65  rp->setResourceGroupDirectory("lua_scripts", resourceDirectory + "/lua_scripts/");
66 
67  // Finally, set the labels for the specialized data types.
68  CEGUI::ImageManager::setImagesetDefaultResourceGroup("imagesets");
69  CEGUI::Scheme::setDefaultResourceGroup("schemes");
70  CEGUI::Font::setDefaultResourceGroup("fonts");
71  CEGUI::WindowManager::setDefaultResourceGroup("layouts");
72  CEGUI::WidgetLookManager::setDefaultResourceGroup("looknfeels");
73  CEGUI::ScriptModule::setDefaultResourceGroup("lua_scripts");
74 
75  // Now create the context + root window, so we can actually have something to draw/with
76  // The actual GUI context
77  primary->context = &CEGUI::System::getSingleton().createGUIContext(primary->renderer->getDefaultRenderTarget());
78  // The root window (always with a name of root)
79  primary->rootWindow = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "root");
80  primary->rootWindow->setSize(CEGUI::USize(cegui_reldim(1.0f), cegui_reldim(1.0f)));
81  primary->rootWindow->setPosition(CEGUI::UVector2(cegui_reldim(0.0f), cegui_reldim(0.0f)));
82  // Tie it together!
83  primary->context->setRootWindow(primary->rootWindow);
84 
85  // Add the context!
86  m_contexts.push_back(primary);
87 
88  // Create the other contexts and their root windows
89  for(unsigned int i = 1; i < numContexts; i++) {
90  // As before, use the same renderer if we can (we, indeed, can)
91  CEGUI::OpenGL3Renderer* secondaryRenderer = primary->renderer;
92 
93  // Create a new context, so that we can handle input/output differently from the primary context
94  CEGUI::GUIContext* secondaryContext = &CEGUI::System::getSingleton().createGUIContext(secondaryRenderer->getDefaultRenderTarget());
95 
96  // Create a new root window for this context
97  CEGUI::Window* secondaryRootWindow = CEGUI::WindowManager::getSingleton().createWindow("DefaultWindow", "secondary_root_" + std::to_string(i-1));
98  secondaryRootWindow->setSize(CEGUI::USize(cegui_reldim(1.0f), cegui_reldim(1.0f)));
99  secondaryRootWindow->setPosition(CEGUI::UVector2(cegui_reldim(0.0f), cegui_reldim(0.0f)));
100 
101  // Set the (new) context's root
102  secondaryContext->setRootWindow(secondaryRootWindow);
103 
104  // Create a new wrapper and add it to the vector of contexts!
105  CEGUIContextWrapper* secondary = new CEGUIContextWrapper;
106  secondary->renderer = secondaryRenderer;
107  secondary->rootWindow = secondaryRootWindow;
108  secondary->context = secondaryContext;
109 
110  m_contexts.push_back(secondary);
111  }
112  }
113 
115  for(unsigned int i = 0; i < m_contexts.size(); i++) {
116  // Destroy all of the GUI contexts, as well as the root windows for each context.
117  CEGUI::System::getSingleton().destroyGUIContext(*m_contexts[i]->context);
118  CEGUI::WindowManager::getSingleton().destroyWindow(m_contexts[i]->rootWindow);
119  }
120 
121  // Clear our last little bit of memory.
122  m_contexts.clear();
123  }
124 
126  // To enable semi-transparency within widgets, we must turn off depth-testing.
127  glDisable(GL_DEPTH_TEST);
128 
129  glBindTexture(GL_TEXTURE_2D, 0);
130  glUseProgram(0);
131  glActiveTexture(GL_TEXTURE0);
132 
133  // First, 'begin' rendering for this current context.
134  m_contexts[m_activeContext]->renderer->beginRendering();
135  // Actually add the glyphs to whatever data structure
136  m_contexts[m_activeContext]->context->draw();
137  // Finally, actually draw the stuff
138  m_contexts[m_activeContext]->renderer->endRendering();
139 
140  // Now to clean up after CEGUI.
141  // Unbind their vertex array
142  glBindVertexArray(0);
143  // Disable scissor-testing.
144  glDisable(GL_SCISSOR_TEST);
145  // Re-enable blending
146  glEnable(GL_BLEND);
147  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
148  // Unbind whatever texture they've bound
149  glBindTexture(GL_TEXTURE_2D, 0);
150  }
151 
153  // First of all, find our delta time
154  unsigned int elapsed;
155  if(m_lastTime == 0) {
156  // We are at the verrrrry beginning, so elapsed time is really 0
157  elapsed = 0;
158  m_lastTime = SDL_GetTicks();
159  } else {
160  // SDL_GetTicks will wrap over at ~49 days. Not a huge deal and I don't really want to use SDL_GetTicks64
161  unsigned int nowTime = SDL_GetTicks();
162  elapsed = nowTime - m_lastTime;
163  m_lastTime = nowTime;
164  }
165 
166  // Tell CEGUI how much time has passed for updates.
167  for(unsigned int i = 0; i < m_contexts.size(); i++) {
168  // SDL_GetTicks returns time in milliseconds (seconds * 1e-3) whereas CEGUI takes time pulses in seconds.
169  m_contexts[i]->context->injectTimePulse((float)elapsed / 1000.0f);
170  }
171  }
172 
173  void BARECEGUI::setActiveContext(unsigned int contextIndex) {
174  if(contextIndex < m_contexts.size()) {
175  m_activeContext = contextIndex;
176  } else {
177  Logger::getInstance()->log("WARNING: Access of CEGUI Context with index " + std::to_string(contextIndex) + " was attempted. This context does not exist.", true);
178  }
179  }
180 
181  void BARECEGUI::setMouseCursor(std::string imageFile) {
182  m_contexts[m_activeContext]->context->getMouseCursor().setDefaultImage(imageFile);
183  }
184 
186  if(shown) {
187  m_contexts[m_activeContext]->context->getMouseCursor().show();
188  } else {
189  m_contexts[m_activeContext]->context->getMouseCursor().hide();
190  }
191  }
192 
193  void BARECEGUI::handleSDLEvent(SDL_Event& evnt) {
194  // spark event in each context.
195  for(unsigned int i = 0; i < m_contexts.size(); i++) {
196  switch(evnt.type) {
197  case SDL_MOUSEMOTION:
198  // The mouse has moved, so tell CEGUI
199  m_contexts[i]->context->injectMousePosition((float)evnt.motion.x, (float)evnt.motion.y);
200  break;
201  case SDL_KEYDOWN:
202  // A key is pressed. Tell CEGUI
203  m_contexts[i]->context->injectKeyDown(SDLKeyToCEGUIKey(evnt.key.keysym.sym));
204  break;
205  case SDL_KEYUP:
206  // Conversely, a key has been released. Tell CEGUI
207  m_contexts[i]->context->injectKeyUp(SDLKeyToCEGUIKey(evnt.key.keysym.sym));
208  break;
209  case SDL_MOUSEBUTTONDOWN:
210  // A button has been pressed. Convert it to CEGUI enums and inject it
211  m_contexts[m_activeContext]->context->injectMouseButtonDown(SDLButtonToCEGUIButton(evnt.button.button));
212  break;
213  case SDL_MOUSEBUTTONUP:
214  // A button has been released. Convert it to CEGUI enums and inject it
215  m_contexts[m_activeContext]->context->injectMouseButtonUp(SDLButtonToCEGUIButton(evnt.button.button));
216  break;
217  case SDL_MOUSEWHEEL:
218  // Scrolled! Tell CEGUI
219  m_contexts[i]->context->injectMouseWheelChange(evnt.wheel.y);
220  break;
221  case SDL_TEXTINPUT:
222  // SDL Inputs text in UTF8 - CEGUI takes it in UTF32. This is slightly problematic.
223  // We will use UTF8 (the library) to convert!
224 
225  // First, get the text in string form
226  std::string evntText = std::string(evnt.text.text);
227  // Allocate space for the converted result
228  std::vector<int> utf32result;
229  // Actually convert it
230  utf8::utf8to32(evnt.text.text, evnt.text.text + evntText.size(), std::back_inserter(utf32result));
231  // Cast to CEGUI's UTF32 type
232  CEGUI::utf32 codePoint = (CEGUI::utf32)utf32result[0];
233 
234  // Finally, inject the actual UTF32 version of the input.
235  m_contexts[i]->context->injectChar(codePoint);
236  break;
237  }
238  }
239  }
240 
241  void BARECEGUI::loadScheme(std::string schemeFile) {
242  // Load a scheme
243  CEGUI::SchemeManager::getSingleton().createFromFile(schemeFile);
244  }
245 
246  void BARECEGUI::setFont(std::string fontFile) {
247  // Create the font
248  CEGUI::FontManager::getSingleton().createFromFile(fontFile + ".font");
249  // Set the font in each context.
250  for(unsigned int i = 0; i < m_contexts.size(); i++) {
251  m_contexts[i]->context->setDefaultFont(fontFile);
252  }
253  }
254 
255  CEGUI::Window* BARECEGUI::createWidget(std::string type, glm::vec4 destRectPercent, glm::vec4 destRectPixels, CEGUI::Window* parent, std::string name) {
256  // Create the window for the widget
257  CEGUI::Window* newWindow = CEGUI::WindowManager::getSingleton().createWindow(type, name);
258  // Set its size, position too
259  newWindow->setPosition(CEGUI::UVector2(CEGUI::UDim(destRectPercent.x, destRectPixels.x), CEGUI::UDim(destRectPercent.y, destRectPixels.y)));
260  newWindow->setSize(CEGUI::USize(CEGUI::UDim(destRectPercent.z, destRectPixels.z), CEGUI::UDim(destRectPercent.w, destRectPixels.w)));
261 
262  // If a parent is given, add it as a child
263  if(parent) {
264  parent->addChild(newWindow);
265  } else {
266  // If it's not, add it to the root.
267  m_contexts[m_activeContext]->rootWindow->addChild(newWindow);
268  }
269 
270  return newWindow;
271  }
272 
273  CEGUI::OpenGL3Renderer* BARECEGUI::getRenderer() {
274  return m_contexts[m_activeContext]->renderer;
275  }
276 
277  CEGUI::GUIContext* BARECEGUI::getContext() {
278  if(m_activeContext < m_contexts.size())
279  return m_contexts[m_activeContext]->context;
280  return nullptr;
281  }
282 
283  CEGUI::Key::Scan SDLKeyToCEGUIKey(SDL_Keycode key) {
284  using namespace CEGUI;
285  switch (key) {
286  case SDLK_BACKSPACE:
287  return Key::Backspace;
288  case SDLK_TAB:
289  return Key::Tab;
290  case SDLK_RETURN:
291  return Key::Return;
292  case SDLK_PAUSE:
293  return Key::Pause;
294  case SDLK_ESCAPE:
295  return Key::Escape;
296  case SDLK_SPACE:
297  return Key::Space;
298  case SDLK_COMMA:
299  return Key::Comma;
300  case SDLK_MINUS:
301  return Key::Minus;
302  case SDLK_PERIOD:
303  return Key::Period;
304  case SDLK_SLASH:
305  return Key::Slash;
306  case SDLK_0:
307  return Key::Zero;
308  case SDLK_1:
309  return Key::One;
310  case SDLK_2:
311  return Key::Two;
312  case SDLK_3:
313  return Key::Three;
314  case SDLK_4:
315  return Key::Four;
316  case SDLK_5:
317  return Key::Five;
318  case SDLK_6:
319  return Key::Six;
320  case SDLK_7:
321  return Key::Seven;
322  case SDLK_8:
323  return Key::Eight;
324  case SDLK_9:
325  return Key::Nine;
326  case SDLK_COLON:
327  return Key::Colon;
328  case SDLK_SEMICOLON:
329  return Key::Semicolon;
330  case SDLK_EQUALS:
331  return Key::Equals;
332  case SDLK_LEFTBRACKET:
333  return Key::LeftBracket;
334  case SDLK_BACKSLASH:
335  return Key::Backslash;
336  case SDLK_RIGHTBRACKET:
337  return Key::RightBracket;
338  case SDLK_a:
339  return Key::A;
340  case SDLK_b:
341  return Key::B;
342  case SDLK_c:
343  return Key::C;
344  case SDLK_d:
345  return Key::D;
346  case SDLK_e:
347  return Key::E;
348  case SDLK_f:
349  return Key::F;
350  case SDLK_g:
351  return Key::G;
352  case SDLK_h:
353  return Key::H;
354  case SDLK_i:
355  return Key::I;
356  case SDLK_j:
357  return Key::J;
358  case SDLK_k:
359  return Key::K;
360  case SDLK_l:
361  return Key::L;
362  case SDLK_m:
363  return Key::M;
364  case SDLK_n:
365  return Key::N;
366  case SDLK_o:
367  return Key::O;
368  case SDLK_p:
369  return Key::P;
370  case SDLK_q:
371  return Key::Q;
372  case SDLK_r:
373  return Key::R;
374  case SDLK_s:
375  return Key::S;
376  case SDLK_t:
377  return Key::T;
378  case SDLK_u:
379  return Key::U;
380  case SDLK_v:
381  return Key::V;
382  case SDLK_w:
383  return Key::W;
384  case SDLK_x:
385  return Key::X;
386  case SDLK_y:
387  return Key::Y;
388  case SDLK_z:
389  return Key::Z;
390  case SDLK_DELETE:
391  return Key::Delete;
392  case SDLK_KP_PERIOD:
393  return Key::Decimal;
394  case SDLK_KP_DIVIDE:
395  return Key::Divide;
396  case SDLK_KP_MULTIPLY:
397  return Key::Multiply;
398  case SDLK_KP_MINUS:
399  return Key::Subtract;
400  case SDLK_KP_PLUS:
401  return Key::Add;
402  case SDLK_KP_ENTER:
403  return Key::NumpadEnter;
404  case SDLK_KP_EQUALS:
405  return Key::NumpadEquals;
406  case SDLK_UP:
407  return Key::ArrowUp;
408  case SDLK_DOWN:
409  return Key::ArrowDown;
410  case SDLK_RIGHT:
411  return Key::ArrowRight;
412  case SDLK_LEFT:
413  return Key::ArrowLeft;
414  case SDLK_INSERT:
415  return Key::Insert;
416  case SDLK_HOME:
417  return Key::Home;
418  case SDLK_END:
419  return Key::End;
420  case SDLK_PAGEUP:
421  return Key::PageUp;
422  case SDLK_PAGEDOWN:
423  return Key::PageDown;
424  case SDLK_F1:
425  return Key::F1;
426  case SDLK_F2:
427  return Key::F2;
428  case SDLK_F3:
429  return Key::F3;
430  case SDLK_F4:
431  return Key::F4;
432  case SDLK_F5:
433  return Key::F5;
434  case SDLK_F6:
435  return Key::F6;
436  case SDLK_F7:
437  return Key::F7;
438  case SDLK_F8:
439  return Key::F8;
440  case SDLK_F9:
441  return Key::F9;
442  case SDLK_F10:
443  return Key::F10;
444  case SDLK_F11:
445  return Key::F11;
446  case SDLK_F12:
447  return Key::F12;
448  case SDLK_F13:
449  return Key::F13;
450  case SDLK_F14:
451  return Key::F14;
452  case SDLK_F15:
453  return Key::F15;
454  case SDLK_RSHIFT:
455  return Key::RightShift;
456  case SDLK_LSHIFT:
457  return Key::LeftShift;
458  case SDLK_RCTRL:
459  return Key::RightControl;
460  case SDLK_LCTRL:
461  return Key::LeftControl;
462  case SDLK_RALT:
463  return Key::RightAlt;
464  case SDLK_LALT:
465  return Key::LeftAlt;
466  case SDLK_SYSREQ:
467  return Key::SysRq;
468  case SDLK_MENU:
469  return Key::AppMenu;
470  case SDLK_POWER:
471  return Key::Power;
472  default:
473  return Key::Unknown;
474  }
475  }
476 
477  CEGUI::MouseButton SDLButtonToCEGUIButton(Uint8 sdlButton) {
478  switch (sdlButton) {
479  case SDL_BUTTON_LEFT:
480  return CEGUI::MouseButton::LeftButton;
481  case SDL_BUTTON_MIDDLE:
482  return CEGUI::MouseButton::MiddleButton;
483  case SDL_BUTTON_RIGHT:
484  return CEGUI::MouseButton::RightButton;
485  case SDL_BUTTON_X1:
486  return CEGUI::MouseButton::X1Button;
487  case SDL_BUTTON_X2:
488  return CEGUI::MouseButton::X2Button;
489  }
490  return CEGUI::MouseButton::NoButton;
491  }
492 
493 }
BARE2D::BARECEGUI::setActiveContext
void setActiveContext(unsigned int contextIndex)
Sets the active context.
Definition: BARECEGUI.cpp:173
BARE2D::BARECEGUI::update
void update()
Updates the amount of time passed in CEGUI.
Definition: BARECEGUI.cpp:152
BARE2D::BARECEGUI::getRenderer
CEGUI::OpenGL3Renderer * getRenderer()
Definition: BARECEGUI.cpp:273
BARE2D::BARECEGUI::m_initialized
static bool m_initialized
Definition: BARECEGUI.hpp:102
BARE2D
Definition: App.cpp:13
BARE2D::BARECEGUI::setMouseCursorShown
void setMouseCursorShown(bool shown)
Shows/hides the mouse cursor. Useful for cutscenes!
Definition: BARECEGUI.cpp:185
BARE2D::Logger::getInstance
static Logger * getInstance()
Definition: Logger.cpp:34
BARE2D::CEGUIContextWrapper::renderer
CEGUI::OpenGL3Renderer * renderer
Definition: BARECEGUI.hpp:12
BARE2D::BARECEGUI::m_instance
static BARECEGUI * m_instance
Definition: BARECEGUI.hpp:100
BARE2D::BARECEGUI::getContext
CEGUI::GUIContext * getContext()
Definition: BARECEGUI.cpp:277
BARECEGUI.hpp
BARE2D::BARECEGUI::~BARECEGUI
~BARECEGUI()
Definition: BARECEGUI.cpp:30
BARE2D::BARECEGUI::handleSDLEvent
void handleSDLEvent(SDL_Event &evnt)
Handles and propagates input.
Definition: BARECEGUI.cpp:193
BARE2D::BARECEGUI::setMouseCursor
void setMouseCursor(std::string imageFile)
Sets the image of the mouse cursor.
Definition: BARECEGUI.cpp:181
BARE2D::BARECEGUI::BARECEGUI
BARECEGUI()
Definition: BARECEGUI.cpp:26
BARE2D::BARECEGUI::loadScheme
void loadScheme(std::string schemeFile)
Loads a scheme file from resourceDirectory/schemes.
Definition: BARECEGUI.cpp:241
BARE2D::BARECEGUI::m_lastTime
unsigned int m_lastTime
Definition: BARECEGUI.hpp:110
BARE2D::BARECEGUI::m_activeContext
unsigned int m_activeContext
Definition: BARECEGUI.hpp:111
BARE2D::Logger::log
void log(std::string message, bool important=false)
Logs a message to a file and the terminal.
Definition: Logger.cpp:42
BARE2D::CEGUIContextWrapper::rootWindow
CEGUI::Window * rootWindow
Definition: BARECEGUI.hpp:14
BARE2D::BARECEGUI::getInstance
static BARECEGUI * getInstance()
Definition: BARECEGUI.cpp:14
BARE2D::BARECEGUI::setFont
void setFont(std::string fontFile)
Sets the current font to some font.
Definition: BARECEGUI.cpp:246
BARE2D::CEGUIContextWrapper::context
CEGUI::GUIContext * context
Definition: BARECEGUI.hpp:13
BARE2D::BARECEGUI::init
void init(std::string &resourceDirectory, unsigned int numContexts)
Initializes all of the necessary stuff to use CEGUI!
Definition: BARECEGUI.cpp:39
BARE2D::BARECEGUI::release
static void release()
Definition: BARECEGUI.cpp:21
BARE2D::SDLKeyToCEGUIKey
CEGUI::Key::Scan SDLKeyToCEGUIKey(SDL_Keycode key)
Definition: BARECEGUI.cpp:283
utf8::utf8to32
u32bit_iterator utf8to32(octet_iterator start, octet_iterator end, u32bit_iterator result)
Definition: checked.h:258
utf8.h
BARE2D::BARECEGUI
Definition: BARECEGUI.hpp:17
BARE2D::BARECEGUI::createWidget
CEGUI::Window * createWidget(std::string type, glm::vec4 destRectPercent, glm::vec4 destRectPixels, CEGUI::Window *parent=nullptr, std::string name="")
Creates a widget of some type.
Definition: BARECEGUI.cpp:255
BARE2D::BARECEGUI::m_contexts
std::vector< CEGUIContextWrapper * > m_contexts
Definition: BARECEGUI.hpp:109
BARE2D::CEGUIContextWrapper
Definition: BARECEGUI.hpp:11
BARE2D::BARECEGUI::draw
void draw()
Draws the GUI to the screen over top of what's already there.
Definition: BARECEGUI.cpp:125
BARE2D::BARECEGUI::destroy
void destroy()
Frees all necessary memory and unloads resources. Destroys root + children windows.
Definition: BARECEGUI.cpp:114
Logger.hpp
BARE2D::SDLButtonToCEGUIButton
CEGUI::MouseButton SDLButtonToCEGUIButton(Uint8 sdlButton)
Definition: BARECEGUI.cpp:477