Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/console/InGameConsole.cc @ 1577

Last change on this file since 1577 was 1577, checked in by rgrieder, 16 years ago
  • cleaned up InGameConsole a little bit
  • adjusted noise (has a config value noiseSize_)
  • replaced panel cursor with text area cursor
  • initialise()/destroy() concept like in other Singletons
  • therefore console is initialised and destroyed via Orxonox class (earlier message colouring)
  • replace linear console scroll with exponential one (no, it doesn't take infinite time to reach 0 ;))

UPDATE YOUR MEDIA REPOSITORY!

  • Property svn:eol-style set to native
File size: 21.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Felix Schulthess
24 *   Co-authors:
25 *      Fabian 'x3n' Landau
26 *
27 */
28
29#include "OrxonoxStableHeaders.h"
30
31#include "InGameConsole.h"
32
33#include <string>
34#include <OgreOverlay.h>
35#include <OgreOverlayElement.h>
36#include <OgreOverlayManager.h>
37#include <OgreOverlayContainer.h>
38#include <OgreStringConverter.h>
39
40#include "core/Debug.h"
41#include "core/CoreIncludes.h"
42#include "core/ConfigValueIncludes.h"
43#include "core/ConsoleCommand.h"
44#include "core/input/InputManager.h"
45#include "util/Math.h"
46#include "GraphicsEngine.h"
47
48#define LINES 30
49#define CHAR_WIDTH 7.45 // fix this please - determine the char-width dynamically
50
51namespace orxonox
52{
53    SetConsoleCommand(InGameConsole, openConsole, true);
54    SetConsoleCommand(InGameConsole, closeConsole, true);
55
56    using namespace Ogre;
57
58    /**
59        @brief Constructor: Creates and initializes the InGameConsole.
60    */
61    InGameConsole::InGameConsole() :
62        consoleOverlay_(0), consoleOverlayContainer_(0),
63        consoleOverlayNoise_(0), consoleOverlayCursor_(0), consoleOverlayBorder_(0),
64        consoleOverlayTextAreas_(0)
65    {
66        RegisterObject(InGameConsole);
67
68        this->bActive_ = false;
69        this->cursor_ = 0.0f;
70        this->cursorSymbol_ = '|';
71        this->inputWindowStart_ = 0;
72        this->numLinesShifted_ = LINES - 1;
73        // for the beginning, don't scroll
74        this->scroll_ = 0;
75
76        this->setConfigValues();
77    }
78
79    /**
80        @brief Destructor: Destroys the TextAreas.
81    */
82    InGameConsole::~InGameConsole(void)
83    {
84        this->destroy();
85    }
86
87    /**
88        @brief Returns a reference to the only existing instance of InGameConsole.
89    */
90    InGameConsole& InGameConsole::getInstance()
91    {
92        static InGameConsole instance;
93        return instance;
94    }
95
96    /**
97        @brief Sets the config values, describing the size of the console.
98    */
99    void InGameConsole::setConfigValues()
100    {
101        SetConfigValue(relativeWidth, 0.8);
102        SetConfigValue(relativeHeight, 0.4);
103        SetConfigValue(blinkTime, 0.5);
104        SetConfigValue(scrollSpeed_, 3.0f);
105        SetConfigValue(noiseSize_, 1.0f);
106    }
107
108    /**
109        @brief Initializes the InGameConsole.
110    */
111    void InGameConsole::initialise()
112    {
113        // create overlay and elements
114        Ogre::OverlayManager* ovMan = Ogre::OverlayManager::getSingletonPtr();
115
116        // create actual overlay
117        this->consoleOverlay_ = ovMan->create("InGameConsoleConsole");
118
119        // create a container
120        this->consoleOverlayContainer_ = static_cast<OverlayContainer*>(ovMan->createOverlayElement("Panel", "InGameConsoleContainer"));
121        this->consoleOverlayContainer_->setMetricsMode(Ogre::GMM_RELATIVE);
122        this->consoleOverlayContainer_->setPosition((1 - this->relativeWidth) / 2, 0);
123        this->consoleOverlayContainer_->setDimensions(this->relativeWidth, this->relativeHeight);
124        this->consoleOverlay_->add2D(this->consoleOverlayContainer_);
125
126        // create BorderPanel
127        this->consoleOverlayBorder_ = static_cast<BorderPanelOverlayElement*>(ovMan->createOverlayElement("BorderPanel", "InGameConsoleBorderPanel"));
128        this->consoleOverlayBorder_->setMetricsMode(Ogre::GMM_PIXELS);
129        this->consoleOverlayBorder_->setMaterialName("ConsoleCenter");
130        this->consoleOverlayBorder_->setBorderSize(16, 16, 0, 16);
131        this->consoleOverlayBorder_->setBorderMaterialName("ConsoleBorder");
132        this->consoleOverlayBorder_->setLeftBorderUV(0.0, 0.49, 0.5, 0.51);
133        this->consoleOverlayBorder_->setRightBorderUV(0.5, 0.49, 1.0, 0.5);
134        this->consoleOverlayBorder_->setBottomBorderUV(0.49, 0.5, 0.51, 1.0);
135        this->consoleOverlayBorder_->setBottomLeftBorderUV(0.0, 0.5, 0.5, 1.0);
136        this->consoleOverlayBorder_->setBottomRightBorderUV(0.5, 0.5, 1.0, 1.0);
137        this->consoleOverlayContainer_->addChild(this->consoleOverlayBorder_);
138
139        // create the text lines
140        this->consoleOverlayTextAreas_ = new TextAreaOverlayElement*[LINES];
141        for (int i = 0; i < LINES; i++)
142        {
143            this->consoleOverlayTextAreas_[i] = static_cast<TextAreaOverlayElement*>(ovMan->createOverlayElement("TextArea", "InGameConsoleTextArea" + Ogre::StringConverter::toString(i)));
144            this->consoleOverlayTextAreas_[i]->setMetricsMode(Ogre::GMM_PIXELS);
145            this->consoleOverlayTextAreas_[i]->setFontName("Monofur");
146            this->consoleOverlayTextAreas_[i]->setCharHeight(18);
147            this->consoleOverlayTextAreas_[i]->setParameter("colour_top", "0.21 0.69 0.21");
148            this->consoleOverlayTextAreas_[i]->setLeft(8);
149            this->consoleOverlayTextAreas_[i]->setCaption("");
150            this->consoleOverlayContainer_->addChild(this->consoleOverlayTextAreas_[i]);
151        }
152
153        // create cursor (also a text area overlay element)
154        this->consoleOverlayCursor_ = static_cast<TextAreaOverlayElement*>(ovMan->createOverlayElement("TextArea", "InGameConsoleTextArea" + Ogre::StringConverter::toString(i)));
155        this->consoleOverlayCursor_->setMetricsMode(Ogre::GMM_PIXELS);
156        this->consoleOverlayCursor_->setFontName("Monofur");
157        this->consoleOverlayCursor_->setCharHeight(18);
158        this->consoleOverlayCursor_->setParameter("colour_top", "0.21 0.69 0.21");
159        this->consoleOverlayCursor_->setLeft(7);
160        this->consoleOverlayCursor_->setCaption("|");
161        this->consoleOverlayContainer_->addChild(this->consoleOverlayCursor_);
162
163        // create noise
164        this->consoleOverlayNoise_ = static_cast<PanelOverlayElement*>(ovMan->createOverlayElement("Panel", "InGameConsoleNoise"));
165        this->consoleOverlayNoise_->setMetricsMode(Ogre::GMM_PIXELS);
166        this->consoleOverlayNoise_->setPosition(5,0);
167        this->consoleOverlayNoise_->setMaterialName("ConsoleNoiseSmall");
168        // comment following line to disable noise
169        this->consoleOverlayContainer_->addChild(this->consoleOverlayNoise_);
170
171        this->resize();
172
173        // move overlay "above" the top edge of the screen
174        // we take -1.2 because the border makes the panel bigger
175        this->consoleOverlayContainer_->setTop(-1.2 * this->relativeHeight);
176
177        Shell::getInstance().addOutputLevel(true);
178
179        COUT(4) << "Info: InGameConsole initialized" << std::endl;
180    }
181
182    /**
183        @brief Destroys all the elements if necessary.
184    */
185    void InGameConsole::destroy()
186    {
187        Ogre::OverlayManager* ovMan = Ogre::OverlayManager::getSingletonPtr();
188        if (ovMan)
189        {
190            if (this->consoleOverlayNoise_)
191                Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayNoise_);
192            if (this->consoleOverlayCursor_)
193                Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayCursor_);
194            if (this->consoleOverlayBorder_)
195                Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayBorder_);
196            if (this->consoleOverlayTextAreas_)
197            {
198                for (int i = 0; i < LINES; i++)
199                {
200                    if (this->consoleOverlayTextAreas_[i])
201                      Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayTextAreas_[i]);
202                    this->consoleOverlayTextAreas_[i] = 0;
203                }
204
205            }
206            if (this->consoleOverlayContainer_)
207                Ogre::OverlayManager::getSingleton().destroyOverlayElement(this->consoleOverlayContainer_);
208        }
209        if (this->consoleOverlayTextAreas_)
210        {
211            delete[] this->consoleOverlayTextAreas_;
212            this->consoleOverlayTextAreas_ = 0;
213        }
214    }
215
216    // ###############################
217    // ###  ShellListener methods  ###
218    // ###############################
219
220    /**
221        @brief Called if all output-lines have to be redrawn.
222    */
223    void InGameConsole::linesChanged()
224    {
225        std::list<std::string>::const_iterator it = Shell::getInstance().getNewestLineIterator();
226        int max = 0;
227        for (int i = 1; i < LINES; ++i)
228        {
229            if (it != Shell::getInstance().getEndIterator())
230            {
231                ++it;
232                max = i;
233            }
234            else
235                break;
236        }
237
238        for (int i = LINES - 1; i > max; --i)
239            this->print("", i, true);
240
241        for (int i = max; i >= 1; --i)
242        {
243            --it;
244            this->print(*it, i, true);
245        }
246    }
247
248    /**
249        @brief Called if only the last output-line has changed.
250    */
251    void InGameConsole::onlyLastLineChanged()
252    {
253        if (LINES > 1)
254            this->print(*Shell::getInstance().getNewestLineIterator(), 1);
255    }
256
257    /**
258        @brief Called if a new output-line was added.
259    */
260    void InGameConsole::lineAdded()
261    {
262        this->numLinesShifted_ = 0;
263        this->shiftLines();
264        this->onlyLastLineChanged();
265    }
266
267    /**
268        @brief Called if the text in the input-line has changed.
269    */
270    void InGameConsole::inputChanged()
271    {
272        if (LINES > 0)
273            this->print(Shell::getInstance().getInput(), 0);
274
275        if (Shell::getInstance().getInput() == "" || Shell::getInstance().getInput().size() == 0)
276            this->inputWindowStart_ = 0;
277    }
278
279    /**
280        @brief Called if the position of the cursor in the input-line has changed.
281    */
282    void InGameConsole::cursorChanged()
283    {
284        unsigned int pos = Shell::getInstance().getCursorPosition() - inputWindowStart_;
285        if (pos > maxCharsPerLine_)
286            pos = maxCharsPerLine_;
287        else if (pos < 0)
288            pos = 0;
289
290        this->consoleOverlayCursor_->setCaption(std::string(pos,' ') + cursorSymbol_);
291        this->consoleOverlayCursor_->setTop((int) this->windowH_ * this->relativeHeight - 24);
292    }
293
294    /**
295        @brief Called if the console gets closed.
296    */
297    void InGameConsole::exit()
298    {
299        this->deactivate();
300    }
301
302    // ###############################
303    // ###  other external calls   ###
304    // ###############################
305
306    /**
307        @brief Used to control the actual scrolling and the cursor.
308    */
309    void InGameConsole::tick(float dt)
310    {
311        if (this->scroll_ != 0)
312        {
313            float oldTop = this->consoleOverlayContainer_->getTop();
314
315            if (this->scroll_ > 0)
316            {
317                // scrolling down
318                // enlarge oldTop a little bit so that this exponential function
319                // reaches 0 before infinite time has passed...
320                float deltaScroll = (oldTop - 0.01) * dt * this->scrollSpeed_;
321                if (oldTop - deltaScroll >= 0)
322                {
323                    // window has completely scrolled down
324                    this->consoleOverlayContainer_->setTop(0);
325                    this->scroll_ = 0;
326                }
327                else
328                    this->consoleOverlayContainer_->setTop(oldTop - deltaScroll);
329            }
330
331            else
332            {
333                // scrolling up
334                // note: +0.01 for the same reason as when scrolling down
335                float deltaScroll = (1.2 * this->relativeHeight + 0.01 + oldTop) * dt * this->scrollSpeed_;
336                if (oldTop - deltaScroll <= -1.2 * this->relativeHeight)
337                {
338                    // window has completely scrolled up
339                    this->consoleOverlayContainer_->setTop(-1.2 * this->relativeHeight);
340                    this->scroll_ = 0;
341                    this->consoleOverlay_->hide();
342                }
343                else
344                    this->consoleOverlayContainer_->setTop(oldTop - deltaScroll);
345            }
346        }
347
348        if (this->bActive_)
349        {
350            this->cursor_ += dt;
351            if (this->cursor_ >= this->blinkTime)
352            {
353                this->cursor_ = 0;
354                bShowCursor_ = !bShowCursor_;
355                if (bShowCursor_)
356                    this->consoleOverlayCursor_->show();
357                else
358                    this->consoleOverlayCursor_->hide();
359            }
360
361            // this creates a flickering effect (extracts exactly 80% of the texture at a random location)
362            float uRand = (rand() & 1023) / 1023.0f * 0.2f;
363            float vRand = (rand() & 1023) / 1023.0f * 0.2f;
364            this->consoleOverlayNoise_->setUV(uRand, vRand, 0.8f + uRand, 0.8f + vRand);
365        }
366    }
367
368    /**
369        @brief Resizes the console elements. Call if window size changes.
370    */
371    void InGameConsole::resize()
372    {
373        this->windowW_ = GraphicsEngine::getSingleton().getWindowWidth();
374        this->windowH_ = GraphicsEngine::getSingleton().getWindowHeight();
375        this->consoleOverlayBorder_->setWidth((int) this->windowW_* this->relativeWidth);
376        this->consoleOverlayBorder_->setHeight((int) this->windowH_ * this->relativeHeight);
377        this->consoleOverlayNoise_->setWidth((int) this->windowW_ * this->relativeWidth - 10);
378        this->consoleOverlayNoise_->setHeight((int) this->windowH_ * this->relativeHeight - 5);
379        this->consoleOverlayNoise_->setTiling(consoleOverlayNoise_->getWidth() / 80.0f * this->noiseSize_, consoleOverlayNoise_->getHeight() / 80.0f * this->noiseSize_);
380
381        // now adjust the text lines...
382        this->desiredTextWidth_ = (int) (this->windowW_ * this->relativeWidth) - 12;
383
384        if (LINES > 0)
385            this->maxCharsPerLine_ = max((unsigned int)10, (unsigned int) ((float)this->desiredTextWidth_ / CHAR_WIDTH));
386        else
387            this->maxCharsPerLine_ = 10;
388
389        for (int i = 0; i < LINES; i++)
390        {
391            this->consoleOverlayTextAreas_[i]->setWidth(this->desiredTextWidth_);
392            this->consoleOverlayTextAreas_[i]->setTop((int) this->windowH_ * this->relativeHeight - 24 - 14*i);
393        }
394
395        this->linesChanged();
396        this->cursorChanged();
397    }
398
399    // ###############################
400    // ###    internal methods     ###
401    // ###############################
402
403    /**
404        @brief Prints string to bottom line.
405        @param s String to be printed
406    */
407    void InGameConsole::print(const std::string& text, int index, bool alwaysShift)
408    {
409        char level = 0;
410        if (text.size() > 0)
411            level = text[0];
412
413        std::string output = text;
414
415        if (level >= -1 && level <= 5)
416            output.erase(0, 1);
417
418        if (LINES > index)
419        {
420            this->colourLine(level, index);
421
422            if (index > 0)
423            {
424                unsigned int linesUsed = 1;
425                while (output.size() > this->maxCharsPerLine_)
426                {
427                    ++linesUsed;
428                    this->consoleOverlayTextAreas_[index]->setCaption(convert2UTF(output.substr(0, this->maxCharsPerLine_)));
429                    output.erase(0, this->maxCharsPerLine_);
430                    output.insert(0, 1, ' ');
431                    if (linesUsed > numLinesShifted_ || alwaysShift)
432                        this->shiftLines();
433                    this->colourLine(level, index);
434                }
435                this->consoleOverlayTextAreas_[index]->setCaption(convert2UTF(output));
436                this->displayedText_ = output;
437                this->numLinesShifted_ = linesUsed;
438            }
439            else
440            {
441                if (output.size() > this->maxCharsPerLine_)
442                {
443                    if (Shell::getInstance().getInputBuffer().getCursorPosition() < this->inputWindowStart_)
444                        this->inputWindowStart_ = Shell::getInstance().getInputBuffer().getCursorPosition();
445                    else if (Shell::getInstance().getInputBuffer().getCursorPosition() >= (this->inputWindowStart_ + this->maxCharsPerLine_ - 1))
446                        this->inputWindowStart_ = Shell::getInstance().getInputBuffer().getCursorPosition() - this->maxCharsPerLine_ + 1;
447
448                    output = output.substr(this->inputWindowStart_, this->maxCharsPerLine_);
449                }
450                else
451                  this->inputWindowStart_ = 0;
452                this->displayedText_ = output;
453                this->consoleOverlayTextAreas_[index]->setCaption(convert2UTF(output));
454            }
455        }
456    }
457
458    /**
459        @brief Shows the InGameConsole.
460    */
461    void InGameConsole::activate()
462    {
463        if (!this->bActive_)
464        {
465            this->bActive_ = true;
466            InputManager::setInputState(InputManager::IS_CONSOLE);
467            Shell::getInstance().registerListener(this);
468
469            this->resize();
470            this->linesChanged();
471            this->cursorChanged();
472            this->consoleOverlay_->show();
473
474            // scroll down
475            this->scroll_ = 1;
476            // the rest is done by tick
477        }
478    }
479
480    /**
481    @brief Hides the InGameConsole.
482    */
483    void InGameConsole::deactivate()
484    {
485        if (this->bActive_)
486        {
487            this->bActive_ = false;
488            InputManager::setInputState(InputManager::IS_NORMAL);
489            Shell::getInstance().unregisterListener(this);
490
491            // scroll up
492            this->scroll_ = -1;
493            // the rest is done by tick
494        }
495    }
496
497    /**
498        @brief Shifts all output lines one line up
499    */
500    void InGameConsole::shiftLines()
501    {
502        for (unsigned int i = LINES - 1; i > 1; --i)
503        {
504            this->consoleOverlayTextAreas_[i]->setCaption(this->consoleOverlayTextAreas_[i - 1]->getCaption());
505            this->consoleOverlayTextAreas_[i]->setColourTop(this->consoleOverlayTextAreas_[i - 1]->getColourTop());
506            this->consoleOverlayTextAreas_[i]->setColourBottom(this->consoleOverlayTextAreas_[i - 1]->getColourBottom());
507        }
508    }
509
510    void InGameConsole::colourLine(int colourcode, int index)
511    {
512        if (colourcode == -1)
513        {
514            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.90, 0.90, 0.90, 1.00));
515            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(1.00, 1.00, 1.00, 1.00));
516        }
517        else if (colourcode == 1)
518        {
519            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.95, 0.25, 0.25, 1.00));
520            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(1.00, 0.50, 0.50, 1.00));
521        }
522        else if (colourcode == 2)
523        {
524            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.95, 0.50, 0.20, 1.00));
525            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(1.00, 0.70, 0.50, 1.00));
526        }
527        else if (colourcode == 3)
528        {
529            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.50, 0.50, 0.95, 1.00));
530            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(0.80, 0.80, 1.00, 1.00));
531        }
532        else if (colourcode == 4)
533        {
534            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.65, 0.48, 0.44, 1.00));
535            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(1.00, 0.90, 0.90, 1.00));
536        }
537        else if (colourcode == 5)
538        {
539            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.40, 0.20, 0.40, 1.00));
540            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(0.80, 0.60, 0.80, 1.00));
541        }
542        else
543        {
544            this->consoleOverlayTextAreas_[index]->setColourTop   (ColourValue(0.21, 0.69, 0.21, 1.00));
545            this->consoleOverlayTextAreas_[index]->setColourBottom(ColourValue(0.80, 1.00, 0.80, 1.00));
546        }
547    }
548
549    // ###############################
550    // ###      satic methods      ###
551    // ###############################
552
553    /**
554        @brief Activates the console.
555    */
556    /*static*/ void InGameConsole::openConsole()
557    {
558        InGameConsole::getInstance().activate();
559    }
560
561    /**
562        @brief Deactivates the console.
563    */
564    /*static*/ void InGameConsole::closeConsole()
565    {
566        InGameConsole::getInstance().deactivate();
567    }
568
569    /**
570        @brief Converts a string into an Ogre::UTFString.
571        @param s The string to convert
572        @return The converted string
573    */
574    /*static*/ Ogre::UTFString InGameConsole::convert2UTF(std::string s)
575    {
576        Ogre::UTFString utf;
577        Ogre::UTFString::code_point cp;
578        for (unsigned int i = 0; i < s.size(); ++i)
579        {
580          cp = s[i];
581          cp &= 0xFF;
582          utf.append(1, cp);
583        }
584        return utf;
585    }
586}
Note: See TracBrowser for help on using the repository browser.