Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1455 was 1455, checked in by rgrieder, 16 years ago
  • 'fixed' a bug in CppTcl.cc, but why would map::find pose a problem if the map is empty?
  • 'fixed' InGameConsole destructor: commented everything. We should probably use OverlayManager::destroyOverlay to delete the created overlay elements. Unfortunately that didn't work either. And I changed delete to delete[] for the list.
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                om_->destroyOverlayElement(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.