Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/orxonox/console/InGameConsole.cc @ 1446

Last change on this file since 1446 was 1446, checked in by landauf, 16 years ago

merged console branch into network branch

after several heavy troubles it compiles, but there is still a bug I couldn't fix: orxonox crashes as soon as one presses a key after opening the console… maybe someone else sees the problem?

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