Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/input/src/orxonox/overlays/console/InGameConsole.cc @ 1629

Last change on this file since 1629 was 1629, checked in by rgrieder, 16 years ago

updated input branch

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