PageRenderTime 333ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/Angel-3.1/Code/Angel/Infrastructure/Console.cpp

https://github.com/chrishaukap/GameDev
C++ | 509 lines | 369 code | 85 blank | 55 comment | 88 complexity | b55fdcccdf5e25c7d1f054f86405f623 MD5 | raw file
  1. //////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 2008-2013, Shane Liesegang
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright
  9. // notice, this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright
  11. // notice, this list of conditions and the following disclaimer in the
  12. // documentation and/or other materials provided with the distribution.
  13. // * Neither the name of the copyright holder nor the names of any
  14. // contributors may be used to endorse or promote products derived from
  15. // this software without specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. // POSSIBILITY OF SUCH DAMAGE.
  28. //////////////////////////////////////////////////////////////////////////////
  29. #include "stdafx.h"
  30. #include "../Infrastructure/Console.h"
  31. #include "../Infrastructure/Common.h"
  32. #include "../Infrastructure/Camera.h"
  33. #include "../Infrastructure/Vector2.h"
  34. #include "../Infrastructure/TextRendering.h"
  35. #include "../Util/MathUtil.h"
  36. #include "../Util/StringUtil.h"
  37. #define MAX_AUTO_COMPLETE 7
  38. Console::Console()
  39. : _enabled(false),
  40. _currentInput(""),
  41. _inputHistoryPos(0),
  42. _cursorPos(0),
  43. _cursorDispTime(0.0f),
  44. _bCursorDisp(true),
  45. _tabWidth(8)
  46. {
  47. if (!IsFontRegistered("Console") || !IsFontRegistered("ConsoleSmall"))
  48. {
  49. RegisterFont("Resources/Fonts/Inconsolata.otf", 24, "Console");
  50. RegisterFont("Resources/Fonts/Inconsolata.otf", 18, "ConsoleSmall");
  51. }
  52. }
  53. Console::~Console()
  54. {
  55. }
  56. void DrawTile( int xPos, int yPos, int width, int height )
  57. {
  58. Vec2i winDimensions;
  59. winDimensions.X = theCamera.GetWindowWidth();
  60. winDimensions.Y = theCamera.GetWindowHeight();
  61. yPos = winDimensions.Y - yPos;
  62. //set up projection
  63. glMatrixMode(GL_PROJECTION);
  64. glPushMatrix();
  65. glLoadIdentity();
  66. gluOrtho2D(0, winDimensions.X, 0, winDimensions.Y);
  67. //set up modelview
  68. glMatrixMode(GL_MODELVIEW);
  69. glPushMatrix();
  70. glLoadIdentity();
  71. glTranslatef((GLfloat)(xPos), (GLfloat)(yPos), 0);
  72. glDisable(GL_DEPTH_TEST);
  73. // glPushAttrib( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT);
  74. //Render console background
  75. float vertices[] = {
  76. (GLfloat)width, 0.0f,
  77. (GLfloat)width, (GLfloat)height,
  78. 0.0f, 0.0f,
  79. 0.0f, (GLfloat)height,
  80. };
  81. glEnableClientState(GL_VERTEX_ARRAY);
  82. glVertexPointer(2, GL_FLOAT, 0, vertices);
  83. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  84. // glPopAttrib();
  85. glEnable(GL_DEPTH_TEST);
  86. glPopMatrix();
  87. glMatrixMode(GL_PROJECTION);
  88. glPopMatrix();
  89. }
  90. void Console::Enable(bool bEnable /* = true */)
  91. {
  92. _enabled = bEnable;
  93. if( _enabled )
  94. {
  95. glfwEnable(GLFW_KEY_REPEAT);
  96. }
  97. else
  98. {
  99. glfwDisable(GLFW_KEY_REPEAT);
  100. }
  101. }
  102. bool Console::GetInput( int key )
  103. {
  104. if( !IsEnabled() )
  105. return false;
  106. if (key == GetToggleConsoleKey())
  107. {
  108. Enable(false);
  109. }
  110. else if( IsTextKey(key) )
  111. {
  112. String oldInput = _currentInput;
  113. _currentInput = oldInput.substr(0, _cursorPos);
  114. _currentInput += key;
  115. if (_cursorPos < oldInput.length())
  116. {
  117. _currentInput += oldInput.substr(_cursorPos, oldInput.length());
  118. }
  119. ++_cursorPos;
  120. RefreshAutoCompletes();
  121. }
  122. return true;
  123. }
  124. bool Console::GetSpecialInputDown( int key )
  125. {
  126. if( !IsEnabled() )
  127. return false;
  128. if( key == GLFW_KEY_ESC || key == GetToggleConsoleKey() )
  129. {
  130. Enable(false);
  131. }
  132. else if( key == GLFW_KEY_ENTER )
  133. {
  134. AcceptCurrentInput();
  135. _autoCompleteList.clear();
  136. }
  137. else if( key == GLFW_KEY_TAB )
  138. {
  139. AcceptAutocomplete();
  140. }
  141. else if( key == GLFW_KEY_DEL )
  142. {
  143. if (_cursorPos < _currentInput.length())
  144. {
  145. String oldInput = _currentInput;
  146. _currentInput = oldInput.substr( 0, _cursorPos );
  147. _currentInput += oldInput.substr(_cursorPos+1, oldInput.length());
  148. RefreshAutoCompletes();
  149. }
  150. }
  151. else if( key == GLFW_KEY_BACKSPACE )
  152. {
  153. if( _cursorPos > 0 )
  154. {
  155. String oldInput = _currentInput;
  156. _currentInput = oldInput.substr( 0, _cursorPos-1 );
  157. if (_cursorPos < oldInput.length())
  158. {
  159. _currentInput += oldInput.substr(_cursorPos, oldInput.length());
  160. }
  161. --_cursorPos;
  162. RefreshAutoCompletes();
  163. }
  164. }
  165. else if( key == GLFW_KEY_UP )
  166. {
  167. AdvanceInputHistory( -1 );
  168. }
  169. else if( key == GLFW_KEY_DOWN )
  170. {
  171. AdvanceInputHistory( 1 );
  172. }
  173. else if( key == GLFW_KEY_RIGHT )
  174. {
  175. if (_cursorPos < _currentInput.length())
  176. {
  177. ++_cursorPos;
  178. }
  179. }
  180. else if( key == GLFW_KEY_LEFT )
  181. {
  182. if (_cursorPos > 0)
  183. {
  184. --_cursorPos;
  185. }
  186. }
  187. else if( key == GLFW_KEY_END )
  188. {
  189. _cursorPos = _currentInput.length();
  190. }
  191. else if( key == GLFW_KEY_HOME )
  192. {
  193. _cursorPos = 0;
  194. }
  195. //TODO: Restore
  196. //else if( key == GLFW_KEY_PAGEUP )
  197. //{
  198. // AdvanceConsoleLog(-1);
  199. //}
  200. //else if( key == GLFW_KEY_PAGEDOWN )
  201. //{
  202. // AdvanceConsoleLog(1);
  203. //}
  204. return true;
  205. }
  206. void Console::RefreshAutoCompletes()
  207. {
  208. if (_currentInput.size() > 2)
  209. {
  210. _autoCompleteList = GetCompletions(_currentInput);
  211. }
  212. else
  213. {
  214. _autoCompleteList.clear();
  215. }
  216. }
  217. void Console::WriteToOutput(String output)
  218. {
  219. // convert tabs first
  220. size_t tabIndex = output.find_first_of('\t');
  221. while (tabIndex != std::string::npos)
  222. {
  223. int numSpaces = _tabWidth - (tabIndex % _tabWidth);
  224. String replacement = "";
  225. for(int i=0; i < numSpaces; i++)
  226. {
  227. replacement += " ";
  228. }
  229. output = output.substr(0, tabIndex) + replacement + output.substr(tabIndex + 1, output.size() - 1);
  230. tabIndex = output.find_first_of('\t');
  231. }
  232. _unsplitBuffer += output;
  233. _buffer = SplitString(_unsplitBuffer, "\n", false);
  234. float largest = 0.0f;
  235. StringList::iterator it = _buffer.begin();
  236. Vector2 extents = Vector2::Zero;
  237. while(it != _buffer.end())
  238. {
  239. extents = GetTextExtents((*it), "ConsoleSmall");
  240. if (extents.Y > largest)
  241. {
  242. largest = extents.Y;
  243. }
  244. it++;
  245. }
  246. _lineHeight = largest;
  247. }
  248. bool Console::IsTextKey(unsigned char key)
  249. {
  250. if( key >= ' ' && key <= '}' )
  251. return true;
  252. return false;
  253. }
  254. void Console::AcceptCurrentInput()
  255. {
  256. Execute(_currentInput);
  257. if (_currentInput.size() > 0)
  258. {
  259. _inputHistory.push_back(_currentInput);
  260. _inputHistoryPos = _inputHistory.size();
  261. }
  262. _currentInput = "";
  263. _cursorPos = 0;
  264. }
  265. void Console::AcceptAutocomplete()
  266. {
  267. if( _autoCompleteList.size() == 0 )
  268. return;
  269. //cycle through the available completions with tab
  270. int found = -1;
  271. for (int i=0; i < _autoCompleteList.size(); i++)
  272. {
  273. if (i > MAX_AUTO_COMPLETE)
  274. {
  275. break;
  276. }
  277. if (_currentInput == _autoCompleteList[i])
  278. {
  279. //found our existing match, try to cycle to the next one
  280. if ( (i == _autoCompleteList.size() - 1) || (i == MAX_AUTO_COMPLETE - 2) )
  281. {
  282. //found it, but at the end of the list, so cycle to top
  283. break;
  284. }
  285. //set the found index to the next line
  286. found = i+1;
  287. break;
  288. }
  289. }
  290. if (-1 == found)
  291. {
  292. found = 0;
  293. }
  294. _currentInput = _autoCompleteList[found];
  295. _cursorPos = _currentInput.length();
  296. }
  297. void Console::AdvanceInputHistory(int byVal)
  298. {
  299. //If we have no input history, ignore this
  300. if( _inputHistory.size() == 0 )
  301. return;
  302. //If we're at the bottom of our input history, do nothing
  303. int lastInputIndex = _inputHistory.size();
  304. if( byVal >= 0 && (_inputHistoryPos + byVal) >= lastInputIndex )
  305. {
  306. _currentInput = "";
  307. _cursorPos = 0;
  308. _inputHistoryPos = lastInputIndex;
  309. return;
  310. }
  311. _inputHistoryPos += byVal;
  312. if( _inputHistoryPos > lastInputIndex )
  313. _inputHistoryPos = lastInputIndex;
  314. else if( _inputHistoryPos < 0 )
  315. _inputHistoryPos = 0;
  316. //otherwise, write over our current input
  317. _currentInput = _inputHistory[_inputHistoryPos];
  318. _cursorPos = _currentInput.length();
  319. }
  320. void Console::ToggleConsole()
  321. {
  322. Enable( !IsEnabled() );
  323. }
  324. void Console::SetPrompt(const String& prompt)
  325. {
  326. _prompt = prompt;
  327. }
  328. void Console::SetTabWidth(unsigned int newTabWidth)
  329. {
  330. _tabWidth = newTabWidth;
  331. }
  332. const unsigned int Console::GetTabWidth()
  333. {
  334. return _tabWidth;
  335. }
  336. void Console::Update( float dt )
  337. {
  338. static const float CURSOR_DISPLAY_TIME = 0.5f;
  339. _cursorDispTime += dt;
  340. if (_cursorDispTime > CURSOR_DISPLAY_TIME)
  341. {
  342. _cursorDispTime = 0.0f;
  343. _bCursorDisp = !_bCursorDisp;
  344. }
  345. }
  346. void Console::Render()
  347. {
  348. if( !IsEnabled() )
  349. return;
  350. //TODO: Clean up this nonsense
  351. static float sTestAlpha = 0.75;
  352. Vec2i winDimensions;
  353. winDimensions.X = theCamera.GetWindowWidth();
  354. winDimensions.Y = theCamera.GetWindowHeight();
  355. static float fScreenHeightPct = 0.5f;
  356. static int sTextBoxBorder = winDimensions.Y/192;
  357. static int sTextBoxHeight = winDimensions.Y/32 + sTextBoxBorder;
  358. int consoleBGHeight = (int)(fScreenHeightPct * (float)winDimensions.Y);
  359. int consoleBGBottomY = consoleBGHeight;
  360. glColor4f(0.0f,0.0f,0.0f,sTestAlpha);
  361. DrawTile(0, consoleBGBottomY, winDimensions.X, consoleBGHeight );
  362. //Draw log
  363. static int sLogXPos = sTextBoxBorder;
  364. int logYPos = consoleBGBottomY - sTextBoxBorder;
  365. if (_buffer.size() > 0)
  366. {
  367. glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  368. StringList::iterator it = _buffer.end();
  369. while (it != _buffer.begin())
  370. {
  371. it--;
  372. /* Vector2 textSize = */ DrawGameText( *it, "ConsoleSmall", sLogXPos, logYPos );
  373. logYPos -= (int)_lineHeight + sTextBoxBorder;
  374. }
  375. }
  376. //Draw text box border
  377. glColor4f(0.0f,1.0f,0.0f,sTestAlpha/2.0f);
  378. int textBoxBottomY = consoleBGBottomY + sTextBoxHeight;
  379. DrawTile(0, textBoxBottomY, winDimensions.X, sTextBoxHeight );
  380. //Draw text box
  381. int textBoxHeight = sTextBoxHeight - sTextBoxBorder;
  382. int textBoxWidth = winDimensions.X - sTextBoxBorder;
  383. int textBoxXPos = (winDimensions.X - textBoxWidth)/2;
  384. int textBoxYPos = textBoxBottomY - (sTextBoxHeight-textBoxHeight)/2;
  385. glColor4f(0.0f,0.0f,0.0f,sTestAlpha);
  386. DrawTile(textBoxXPos, textBoxYPos, textBoxWidth, textBoxHeight);
  387. textBoxXPos += sTextBoxBorder;
  388. textBoxYPos -= sTextBoxBorder + (sTextBoxBorder/2);
  389. glColor4f(0.0f,1.0f,0.0f,1.0f);
  390. String printInput = _prompt;
  391. printInput += _currentInput.substr(0, _cursorPos);
  392. if(_bCursorDisp)
  393. {
  394. printInput += "|";
  395. }
  396. else
  397. {
  398. printInput += " ";
  399. }
  400. if (_cursorPos < _currentInput.length())
  401. {
  402. printInput += _currentInput.substr(_cursorPos, _currentInput.length());
  403. }
  404. DrawGameText(printInput.c_str(), "ConsoleSmall", textBoxXPos, textBoxYPos);
  405. //Draw autocomplete
  406. static int sMaxAutoCompleteLines = MAX_AUTO_COMPLETE;
  407. int numAutoCompleteLines = MathUtil::Min(sMaxAutoCompleteLines, (int)_autoCompleteList.size() );
  408. int autoCompleteBottomY = textBoxBottomY + (numAutoCompleteLines * sTextBoxHeight);
  409. int autoCompleteStartY = textBoxBottomY + 2*sTextBoxHeight/3;
  410. int autoCompleteXPos = textBoxXPos + winDimensions.Y / 24;
  411. int autoCompleteBoxXPos = autoCompleteXPos - sTextBoxBorder;
  412. glColor4f(0.0f,0.0f,0.0f,sTestAlpha);
  413. DrawTile(autoCompleteBoxXPos, autoCompleteBottomY, winDimensions.X-autoCompleteBoxXPos, numAutoCompleteLines * sTextBoxHeight);
  414. glColor4f(0.0f,1.0f,0.0f,1.0f);
  415. Vector2 outPos((float)autoCompleteXPos, (float)autoCompleteStartY);
  416. for( int i = 0; i < numAutoCompleteLines; i++ )
  417. {
  418. if( (int)_autoCompleteList.size() > sMaxAutoCompleteLines-1 && i == sMaxAutoCompleteLines-1 )
  419. DrawGameText( "...", "ConsoleSmall", autoCompleteXPos, (int)outPos.Y );
  420. else
  421. DrawGameText( _autoCompleteList[i].c_str(), "ConsoleSmall", autoCompleteXPos, (int)outPos.Y );
  422. outPos.Y += sTextBoxHeight;
  423. }
  424. }