Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Finally! The InputManager is now working like I imagined it to. And it's even easier to use it as well.
A little explanation: Every time you change something about the input distribution, it is a change of 'state' represented by the class 'InputState'.
That can be for instance: "console", "game", "gui", etc. Every state has a name and a priority which describes who comes first. Now if one state doesn't handle mouse input or instance, then the one with the next lower priority gets it. To prevent that, you can add the 'EmptyHandler' to the state with setMouseHandler.
InputState is just an abstract base class. There are two classes implementing it: SimpleInputState and ExtendedInputState. The latter allows for multiple input handlers for one single device.

Basically, what you need to know is what you see in Orxonox.cc, InGameConsole.cc and Shell.cc.

  • 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::requestEnterState("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::requestLeaveState("console");
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.