Skip to main content
ColoredTextAreaOverlayElement         A class to allow Quake 3 style color codes to be inserted into text overlay elements

Introduction

This article presents a class that extends the TextAreaOverlayElement allowing for different colors to be applied to each character in the string individually. The behaviour was designed to mimic the Quake 3 coloring scheme. This should be very easy to integrate into existing code since the interface is virtually identical to the TextAreaOverlayElement interface. For example, consider the following code:

Copy to clipboard
TextAreaOverlayElement *pTextArea = (TextAreaOverlayElement*)OverlayManager.createOverlayElement("TextArea", "MyTextArea"); pTextArea->setCaption("Some plain text"); ...

Simply needs to be changed to:

Copy to clipboard
TextAreaOverlayElement *pTextArea = (TextAreaOverlayElement*)OverlayManager.createOverlayElement("ColoredTextArea", "MyTextArea"); pTextArea->setCaption("Some ^1red^7 text"); ...
Note that "
1" and "
7" in the string are color codes. Those familiar with Quake 3 will recognise this. The color that corresponds to each code can be found in the ColoredTextAreaOverlayElement::GetColor function, they are the same as Quake 3 but can easily be changed.


Before this code will work however, the new overlay must be registered using the ColoredTextAreaOverlayElementFactory. Here is some sample code on how to do that:

In header file

Copy to clipboard
ColoredTextAreaOverlayElementFactory* pColoredTextAreaOverlayElementFactory;

Initialisation code

Copy to clipboard
// Register the overlay element m_pColoredTextAreaOverlayElementFactory = new ColoredTextAreaOverlayElementFactory(); OverlayManager::getSingleton().addOverlayElementFactory(pColoredTextAreaOverlayElementFactory);

Deinitialisation code

Copy to clipboard
// This must be called before the ogre root is destroyed or crashes may occur on exit delete pColoredTextAreaOverlayElementFactory

Having done this you should also be able to use this class in your overlay scripts (although I haven't tested that).

Similarly to the TextAreaOverlayElement class, a gradient can be applied from the top to the bottom. Instead of specifying an absolute color, a value can be specified instead with the following functions:

Copy to clipboard
void setValueBottom(float Value); void setValueTop(float Value);


This is essentially the value component of the HSV color.

Here is a screenshot of the class in use (see text at the bottom left):

ColoredTextOverlays.png

Important

Keep in mind that this is not thread safe! We had much trouble to figure out why it was broken: "e used updateColours() from a different thread, never do that!

Code

ColoredTextAreaOverlayElement.h

Copy to clipboard
#pragma once class ColoredTextAreaOverlayElement : public TextAreaOverlayElement { public: ColoredTextAreaOverlayElement(const String& name); ~ColoredTextAreaOverlayElement(void); void setValueBottom(float Value); void setValueTop(float Value); void setCaption(const DisplayString& text); static DisplayString StripColors(const DisplayString& text); static ColourValue GetColor(unsigned char ID, float Value = 1.0f); protected: void updateColours(void); vector<unsigned char> m_Colors; float m_ValueTop; float m_ValueBottom; };

ColoredTextAreaOverlayElement.cpp

Copy to clipboard
#include "ColoredTextAreaOverlayElement.h" #define POS_TEX_BINDING 0 #define COLOUR_BINDING 1 ColoredTextAreaOverlayElement::ColoredTextAreaOverlayElement(const String& name) : TextAreaOverlayElement(name) , m_ValueTop(1.0f) , m_ValueBottom(0.8f) { } ColoredTextAreaOverlayElement::~ColoredTextAreaOverlayElement(void) { } void ColoredTextAreaOverlayElement::setValueBottom(float Value) { m_ValueTop = Value; mColoursChanged = true; } void ColoredTextAreaOverlayElement::setValueTop(float Value) { m_ValueBottom = Value; mColoursChanged = true; } ColourValue ColoredTextAreaOverlayElement::GetColor(unsigned char ID, float Value) { switch (ID) { case 0: return ColourValue(0, 0, 0); // Black case 1: return ColourValue(Value, 0, 0); // Red case 2: return ColourValue(0, Value, 0); // Green case 3: return ColourValue(Value, Value, 0); // Yellow case 4: return ColourValue(0, 0, Value); // Blue case 5: return ColourValue(0, Value, Value); // Cyan case 6: return ColourValue(Value, 0, Value); // Magenta case 7: return ColourValue(Value, Value, Value); // White } return ColourValue::Black; } DisplayString ColoredTextAreaOverlayElement::StripColors(const DisplayString& text) { DisplayString StrippedText; int i; for (i = 0; i < (int)text.size()-1; ++i) { if (text[i] == '^' && text[i+1] >= '0' && text[i+1] <= '7') // This is a color code, ignore it { ++i; } else { StrippedText.append(1, text[i]); } } // One last character to add because loop went to size()-1 if (i < (int)text.size()) StrippedText.append(1, text[i]); return StrippedText; } void ColoredTextAreaOverlayElement::setCaption(const DisplayString& text) { m_Colors.resize(text.size(), 7); int i, iNumColorCodes = 0, iNumSpaces = 0; for (i = 0; i < (int)text.size()-1; ++i) { if (text[i] == ' ' || text[i] == '\n') { // Spaces and newlines are skipped when rendering and as such can't have a color ++iNumSpaces; } else if (text[i] == '^' && text[i+1] >= '0' && text[i+1] <= '7') // This is a color code { // Fill the color array starting from this point to the end with the new color code // adjustments need to made because color codes will be removed and spaces are not counted fill(m_Colors.begin()+i-(2*iNumColorCodes)-iNumSpaces, m_Colors.end(), text[i+1]-'0'); ++i; ++iNumColorCodes; } } // Set the caption using the base class, but strip the color codes from it first TextAreaOverlayElement::setCaption(StripColors(text)); } void ColoredTextAreaOverlayElement::updateColours(void) { // Convert to system-specific RGBA topColour, bottomColour; // Set default to white Root::getSingleton().convertColourValue(ColourValue::White, &topColour); Root::getSingleton().convertColourValue(ColourValue::White, &bottomColour); HardwareVertexBufferSharedPtr vbuf = mRenderOp.vertexData->vertexBufferBinding->getBuffer(COLOUR_BINDING); RGBA* pDest = static_cast<RGBA*>( vbuf->lock(HardwareBuffer::HBL_DISCARD) ); for (size_t i = 0; i < mAllocSize; ++i) { if (i < m_Colors.size()) { Root::getSingleton().convertColourValue(GetColor(m_Colors[i], m_ValueTop), &topColour); Root::getSingleton().convertColourValue(GetColor(m_Colors[i], m_ValueBottom), &bottomColour); } // First tri (top, bottom, top) *pDest++ = topColour; *pDest++ = bottomColour; *pDest++ = topColour; // Second tri (top, bottom, bottom) *pDest++ = topColour; *pDest++ = bottomColour; *pDest++ = bottomColour; } vbuf->unlock(); }


ColoredTextAreaOverlayElementFactory.h

Copy to clipboard
#pragma once #include <OgreOverlayElementFactory.h> #include "ColoredTextAreaOverlayElement.h" /** Factory for creating TextAreaOverlayElement instances. */ class ColoredTextAreaOverlayElementFactory : public OverlayElementFactory { public: /** See OverlayElementFactory */ OverlayElement* createOverlayElement(const String& instanceName) { return new ColoredTextAreaOverlayElement(instanceName); } /** See OverlayElementFactory */ const String& getTypeName() const { static String name = "ColoredTextArea"; return name; } };

Updated version

A slightly updated version can be found there:

System error.

An error occurred while performing the request.

Things to check:

  1. Did you complete the Tiki Installer?

  2. Is your database corrupt? Please see how to repair your database

  3. Are your database settings accurate? (username, schema name, etc in db/local.php)

Please see the documentation for more information.