Irrlicht Extensions

Irrlicht – a 3D Engine – is free, cross-platform and open source. See  http://irrlicht.sourceforge.net/


CGUIexScrollWindow

It is said that Irrlicht can’t easily be extended with own features (like, e.g. a window with a scroll bar – which is currently not within the standard functionality). This is not true, though.
Of course, as it is open source, one could fiddle with the engine code itself. Nothing wrong with that. As soon as a new version of the engine is out, you’d probably have to re-do all your personal changes. Although this is feasable, it isn’t the way to go for me (being a lazy butt).

From the irrlicht forum and the nice CGUITextBox tutorial by MasterD I got another way of adding functionality to Irrlicht – without padding and recompiling the source.

The key is to derive an element (here: an GUI element) from an already existing one, add own things, then make it adding itself to the Irrlicht gui environment. The only drawback I found so far is that one can’t use the engine’s built in functions like irr::gui::IGUIEnvironment->irr::gui::IGUIEnvironment::addWindow and (object)->drop for creation/deletion. New and delete must be used instead.

The class presented here (CGUIexScrollWindow) was created while parsing through the above mentioned CGUITextBox code, trying to understand what is happening there. While on it, I removed some features I didn’t need and rewrote some code – just to do it my own way.
The scrollable window can be placed on the screen, stuffed with text, and will take care of user-invoked scrolling. Well, thats it. Code tested with Irrlicht 0.14.0.

How would the class be used?
First, add the source code (.h/.cpp) listed below to your project. Then, add a pointer to a CGUIexScrollWindow object to your code. Finally, create the ScrollWindow object with the new parameter, passing some basics to the constructor. When you are done, remove the ScrollWindow using delete. Like so (where pGUIEnv points to the Irrlicht GUI environment, and pFont to a font of your choice):

irr::gui::CGUIexScrollWindow *m_pHelpTextBox = NULL;
...
irr::core::rect<irr::s32> rDim(0,0,200,100);
m_pHelpTextBox = new irr::gui::CGUIexScrollWindow(pGUIEnv,pFont,rDim);
...do stuff, until the ScrollWindow isn't needed anymore...
delete(m_pHelpTextBox);
m_pHelpTextBox = NULL;

This new “GUI object” behaves just like the others (which are “built in”). And no need to tweak the engine source. You may want to use this – very basic – implementation to e.g. show a help screen with scrollable text. For more features, check the above mentioned CGUITextBox class.

// CGUIexScrollWindow.h
#ifndef ___CGUIEXSCROLLWINDOW_H
#define ___CGUIEXSCROLLWINDOW_H
#include <irrlicht.h>
#include <wchar.h>
namespace irr
{
namespace gui
{
// -------------------------------------------------
class CGUIexScrollWindow : public irr::gui::IGUIElement
{
 public:
 CGUIexScrollWindow(irr::gui::IGUIEnvironment *pGuiEnv,
 irr::gui::IGUIFont *pFont,
 irr::core::rect<irr::s32> rec);
~CGUIexScrollWindow();
 virtual bool OnEvent(irr::SEvent event);
 virtual void setText(const wchar_t* pText);
 private:
 void setVisibleText(irr::s32 iStartLine);
 void Init(void);
 irr::gui::IGUIScrollBar * m_pScrollbar;
 irr::gui::IGUIStaticText * m_pStaticText; // keeping the text
 irr::gui::IGUIStaticText * m_pDummyText; // just for the border
 irr::gui::IGUIFont *m_pFont;
 };
// -------------------------------------------------
} // namespace gui
} // namespace irr
#endif
///\file CGUIexScrollWindow.cpp
/// Containing the CGUIexScrollWindow class

///\class CGUIexScrollWindow
/// Helper class for a window with scroll bar. Based on http://www.irrforge.org/index.php/CGUITextBox .
/// Kudos to MasterD.
/// Irrlicht extension class. Remember to use "new" and "delete" when creating or releasing an element of
/// this type. No add, no drop, no remove. 12/2005 Michael Koch

#include "CGUIexScrollWindow.h"

namespace irr
{
namespace gui
{

/// Constructor, setting itself as a child to the gui root element
// -------------------------------------------------
CGUIexScrollWindow::CGUIexScrollWindow(irr::gui::IGUIEnvironment *pGuiEnv,
irr::gui::IGUIFont *pFont,
irr::core::rect<irr::s32> rec)
: IGUIElement(irr::gui::EGUIET_ELEMENT, pGuiEnv,
pGuiEnv->getRootGUIElement(), -1, rec)
// -------------------------------------------------
{
m_pFont = pFont;

m_pScrollbar = NULL;
m_pDummyText = NULL;
m_pStaticText = NULL;

Init(); // Called once on creation
}

/// Initializing internal elements.
// -------------------------------------------------
void CGUIexScrollWindow::Init(void)
// -------------------------------------------------
{
m_pDummyText = Environment->addStaticText(L"",
irr::core::rect<irr::s32>(0, 0,
RelativeRect.getWidth(),
RelativeRect.getHeight()),
true, true, this, -1 , true);

m_pStaticText = Environment->addStaticText(L"",
irr::core::rect<irr::s32>(5, 5,
RelativeRect.getWidth()-15-5,
RelativeRect.getHeight()-5),
false, true, this);

m_pScrollbar = Environment->addScrollBar(false,
irr::core::rect<irr::s32>(RelativeRect.getWidth()-15,
0,
RelativeRect.getWidth(),
RelativeRect.getHeight()),
this);

m_pStaticText->setOverrideFont(m_pFont);

setText(Text.c_str());
}

/// Destructor. The object is removing itself from the parent (the gui root element, that is)
// -------------------------------------------------
CGUIexScrollWindow::~CGUIexScrollWindow()
// -------------------------------------------------
{
Parent->removeChild(this);
}

/// Called if an event happened. Filter for our scrollbar
// -------------------------------------------------
bool CGUIexScrollWindow::OnEvent(irr::SEvent event)
// -------------------------------------------------
{
Parent->OnEvent(event);

if(event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED)
{
IGUIScrollBar *bar = static_cast <irr::gui::IGUIScrollBar*> (event.GUIEvent.Caller);
if(bar == m_pScrollbar)
{
irr::s32 line = m_pScrollbar->getPos();
setVisibleText(line); // Line is in pixels here
}
}

return true;
}

/// Set new text to the window and calculate new scrollbar range (in pixels)
// -------------------------------------------------
void CGUIexScrollWindow::setText(const wchar_t* pText)
// -------------------------------------------------
{
m_pStaticText->setText(pText);

m_pScrollbar->setMax(m_pStaticText->getTextHeight() - m_pScrollbar->getRelativePosition().getHeight());

m_pScrollbar->setPos(0);
setVisibleText(0);
}

/// Called when scrolling applies
// -------------------------------------------------
void CGUIexScrollWindow::setVisibleText(irr::s32 iStartLine)
// -------------------------------------------------
{
// startLine is given in pixels

irr::core::rect<irr::s32> dim1 = m_pStaticText->getRelativePosition();
irr::core::rect<irr::s32> dim2(dim1.UpperLeftCorner.X,
- iStartLine,
dim1.LowerRightCorner.X,
m_pStaticText->getTextHeight() - iStartLine);

m_pStaticText->setRelativePosition(dim2);
}

} // namespace gui
} // namespace irr

CGUIexChatWindow

The class presented here (CGUIexChatWindow) provides basic chatbox functions (like scrolling, linebreak, showing chat lines with different colors, skipping old messages). I got valuable inputs from the CGUITextBox code, presented by MasterD (CGUITextBox tutorial). The point is that the irrlicht source does not need to be modified (something all Irrlicht extensions should try to cover, IMHO). Just add the class to your project and go. Code tested with Irrlicht 0.14.0.

How would the class be used?
First, add the source code (.h/.cpp) listed below to your project. Then, add a pointer to a CGUIexChatWindow object to your code. Finally, create the ChatWindow object with the new parameter, passing some basics to the constructor. When you are done, remove the ChatWindow using delete. Like so (where pGUIEnv points to the Irrlicht GUI environment, and pFont to a font of your choice):

irr::gui::CGUIexChatWindow *m_pChatBox = NULL;...
irr::core::rect<irr::s32> rDim(0,0,200,100);
m_pChatBox = new irr::gui::CGUIexChatWindow(pGUIEnv,pFont,rDim);
...do stuff, until the ChatWindow isn't needed anymore...
delete(m_pChatBox);
m_pChatBox = NULL;

Here we have the source. Sorry, no downloadable files.

// CGUIexChatWindow.h

#ifndef ___CGUIEXCHATWINDOW_H
#define ___CGUIEXCHATWINDOW_H

/// Maximal lines of chat messages to keep in memory
#define CGUIEXCHATWINDOW_MAXLINES 5

#include <irrlicht.h>
#include <wchar.h>

namespace irr
{
namespace gui
{

// -------------------------------------------------
class CGUIexChatWindow : public irr::gui::IGUIElement
{
public:
CGUIexChatWindow(irr::gui::IGUIEnvironment *pGuiEnv,
irr::gui::IGUIFont *pFont,
irr::core::rect<irr::s32> rec);

~CGUIexChatWindow(void);

virtual bool OnEvent(irr::SEvent event);

void AddChatMessage(const wchar_t *text, irr::video::SColor color = irr::video::SColor(255,0,0,0));
void ScrollPosition(irr::s32 pixelLine);

private:

void Init(void);
void RecalculateScrollbar(void);

irr::gui::IGUIScrollBar *m_pScrollbar;
irr::core::array<irr::gui::IGUIStaticText*> m_aChatLines; // keeping the chat lines
irr::gui::IGUIStaticText *m_pDummyText; // just for the border

irr::gui::IGUIFont *m_pFont;
};
// -------------------------------------------------

} // namespace gui
} // namespace irr

#endif

///\file CGUIexChatWindow.cpp
/// Containing the CGUIexChatWindow class

///\class CGUIexChatWindow
/// Helper class for handling a chatbox with different line colors, scrolling and linebreaks.
/// Irrlicht addon class. Remember to use "new" and "delete" when creating or releasing an element of
/// this type. No add, no drop, no remove. Michael Koch 12/2005
/// Based on routines from CGUIexScrollWindow (which is itself based on CGUITextBox by MasterD)

#include "CGUIexChatWindow.h"

namespace irr
{
namespace gui
{
/// Constructor, setting itself as a child to the gui root element
// -------------------------------------------------
CGUIexChatWindow::CGUIexChatWindow(irr::gui::IGUIEnvironment *pGuiEnv,
irr::gui::IGUIFont *pFont,
irr::core::rect<irr::s32> rec)
:IGUIElement(irr::gui::EGUIET_ELEMENT, pGuiEnv,
pGuiEnv->getRootGUIElement(), -1, rec)
// -------------------------------------------------
{
m_pFont = pFont;

m_pScrollbar = NULL;
m_pDummyText = NULL;

m_aChatLines.clear();
m_aChatLines.reallocate(CGUIEXCHATWINDOW_MAXLINES);

Init(); // Called once on creation
}

/// Destructor. The object is removing itself from the parent (the gui root element, that is)
// -------------------------------------------------
CGUIexChatWindow::~CGUIexChatWindow(void)
// -------------------------------------------------
{
Parent->removeChild(this);
}

/// Initializing internal elements.
// -------------------------------------------------
void CGUIexChatWindow::Init(void)
// -------------------------------------------------
{
m_pDummyText = Environment->addStaticText(L"",
irr::core::rect<irr::s32>(0, 0,
RelativeRect.getWidth(),
RelativeRect.getHeight()),
true, true, this, -1 , true);

m_pScrollbar = Environment->addScrollBar(false,
irr::core::rect<irr::s32>(RelativeRect.getWidth()-15,
0,
RelativeRect.getWidth(),
RelativeRect.getHeight()),
this);

}

/// Called if an event happened. Filter for our scrollbar
// -------------------------------------------------
bool CGUIexChatWindow::OnEvent(irr::SEvent event)
// -------------------------------------------------
{
Parent->OnEvent(event);

if(event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED)
{
IGUIScrollBar *bar = static_cast <irr::gui::IGUIScrollBar*> (event.GUIEvent.Caller);
if(bar == m_pScrollbar)
{
irr::s32 pixelLine = m_pScrollbar->getPos();
ScrollPosition(pixelLine); // Line is in pixels here
}
}

return true;
}

/// Adds a message to the chat window and checks for maximum lines reached. Takes care of scrolling.
// -------------------------------------------------
void CGUIexChatWindow::AddChatMessage(const wchar_t *text, video::SColor color)
// -------------------------------------------------
{
if (!wcslen(text)) return;

// set dimension to height of one line. will expand automatically when wordwrap happens
irr::core::rect<irr::s32> recBox(5, 0, RelativeRect.getWidth()-15, m_pFont->getDimension(L"G").Height);

irr::gui::IGUIStaticText *pLine = Environment->addStaticText(text, recBox, false, true, this, -1);

pLine->setOverrideColor(color);
m_aChatLines.push_back(pLine);

if (m_aChatLines.size()>CGUIEXCHATWINDOW_MAXLINES)
{
m_aChatLines[0]->remove();
m_aChatLines.erase(0);
}

RecalculateScrollbar();
}

/// Recalculates the range of the scrollbar, based on pixel height of all stored chatlines.
// -------------------------------------------------
void CGUIexChatWindow::RecalculateScrollbar(void)
// -------------------------------------------------
{
irr::s32 iPixelRows = 0;

for (irr::u32 i=0;i<m_aChatLines.size();i++)
{
iPixelRows += m_aChatLines[i]->getTextHeight();
}

m_pScrollbar->setMax(iPixelRows);

irr::s32 iFirstLine = RelativeRect.getHeight()-m_pFont->getDimension(L"G").Height;

if (iPixelRows > iFirstLine) ScrollPosition(iPixelRows-iFirstLine);
else ScrollPosition(0);
}

/// Scroll to a certain pixel line
// -------------------------------------------------
void CGUIexChatWindow::ScrollPosition(irr::s32 pixelLine)
// -------------------------------------------------
{
irr::s32 iSum = 0;

m_pScrollbar->setPos(pixelLine);

for (irr::u32 i=0;i<m_aChatLines.size();i++)
{
irr::u32 iSize = m_aChatLines[i]->getTextHeight();
iSum += iSize;

if (iSum < pixelLine) m_aChatLines[i]->setVisible(false);
else
{
m_aChatLines[i]->setVisible(true);
irr::core::rect<s32> pos;
pos = m_aChatLines[i]->getRelativePosition();
pos.UpperLeftCorner.Y = iSum - pixelLine - iSize;
pos.LowerRightCorner.Y = iSum - pixelLine;

m_aChatLines[i]->setRelativePosition(pos);
}
}
}

} // namespace gui
} // namespace irr

My Project Skeleton

To ease up starting a new Irrlicht programming project, I made myself a “project skeleton”.
It comes with the Irrlicht 1.0 headers/libs/dll and should compile and run out-of the box on Win32 (MS VC++ .net 2003) and Linux.
At least, it does on my machine.

Features
  • debug-, gui-, camera-, input-classes with basic functions
  • inline functions for debug output
  • implemented debug- and help window
  • implemented skybox creation
  • includes CGUIexScrollWindow (see elsewhere on this site)
Downloads
FileDateSizeRemarks
irrlicht_skeleton.zip7/22/20063.9 MBComplete source (VC++ .net 2003 and Linux makefile)