text:
#include "Gorilla.h"

#pragma warning ( disable : 4244 )

#if OGRE_VERSION < 67584 // 1.8.0
template<> Gorilla::Silverback* Ogre::Singleton<Gorilla::Silverback>::ms_Singleton = 0;
#else
template<> Gorilla::Silverback* Ogre::Singleton<Gorilla::Silverback>::msSingleton = 0;
#endif

#define PUSH_VERTEX(VERTICES, VERTEX, X, Y, UV, COLOUR)   \
VERTEX.position.x = X;                                           \
VERTEX.position.y = Y;                                           \
VERTEX.position.z = 0;                                           \
VERTEX.uv.x = UV.x;                                              \
VERTEX.uv.y = UV.y;                                              \
VERTEX.colour = COLOUR;                                          \
VERTICES.push_back(VERTEX);

#define PUSH_TRIANGLE(VERTICES, VERTEX, A, B, C, UV, COLOUR)       \
PUSH_VERTEX(VERTICES, VERTEX, A.x, A.y, UV, COLOUR) \
PUSH_VERTEX(VERTICES, VERTEX, B.x, B.y, UV, COLOUR) \
PUSH_VERTEX(VERTICES, VERTEX, C.x, C.y, UV, COLOUR)

#define PUSH_QUAD(VERTICES, VERTEX, POSITIONS, COLOURS, UV)   \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[3].x, POSITIONS[3].y, UV[3], COLOURS[3]) \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[1].x, POSITIONS[1].y, UV[1], COLOURS[1]) \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[0].x, POSITIONS[0].y, UV[0], COLOURS[0]) \
\
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[3].x, POSITIONS[3].y, UV[3], COLOURS[3]) \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[2].x, POSITIONS[2].y, UV[2], COLOURS[2]) \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[1].x, POSITIONS[1].y, UV[1], COLOURS[1])

#define PUSH_QUAD2(VERTICES, VERTEX, POSITIONS, COLOUR, UV)   \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[3].x, POSITIONS[3].y, UV[3], COLOUR) \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[1].x, POSITIONS[1].y, UV[1], COLOUR) \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[0].x, POSITIONS[0].y, UV[0], COLOUR) \
\
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[3].x, POSITIONS[3].y, UV[3], COLOUR) \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[2].x, POSITIONS[2].y, UV[2], COLOUR) \
PUSH_VERTEX(VERTICES, VERTEX, POSITIONS[1].x, POSITIONS[1].y, UV[1], COLOUR)

namespace Gorilla
{

    enum
    {
        SCREEN_RENDERQUEUE = Ogre::RENDER_QUEUE_OVERLAY
    };

    Ogre::ColourValue rgb(Ogre::uchar r, Ogre::uchar g, Ogre::uchar b, Ogre::uchar a )
    {
        static const Ogre::Real inv255 = Ogre::Real(0.00392156863);
        return Ogre::ColourValue(Ogre::Real(r) * inv255, Ogre::Real(g) * inv255, Ogre::Real(b) * inv255, Ogre::Real(a) * inv255);
    }

    Ogre::ColourValue webcolour(Colours::Colour web_colour, Ogre::Real alpha)
    {
        static const Ogre::Real inv255 = Ogre::Real(0.00392156863);
        Ogre::ColourValue ret;
        ret.b = Ogre::Real(web_colour & 0xFF) * inv255;
        ret.g = Ogre::Real((web_colour >> 8) & 0xFF) * inv255;
        ret.r = Ogre::Real((web_colour >> 16) & 0xFF) * inv255;
        ret.a = alpha;
        return ret;
    }

    TextureAtlas::TextureAtlas(const Ogre::String& gorillaFile, const Ogre::String& groupName)
    {

        _reset();
        _load(gorillaFile, groupName);
        _calculateCoordinates();
        _create2DMaterial();
        _create3DMaterial();
    }

    TextureAtlas::~TextureAtlas()
    {
        for (std::map<Ogre::uint, GlyphData*>::iterator it = mGlyphData.begin(); it != mGlyphData.end(); it++)
        {
            OGRE_DELETE (*it).second;
        }

        for (std::map<Ogre::String, Sprite*>::iterator it = mSprites.begin(); it != mSprites.end(); it++)
        {
            OGRE_DELETE (*it).second;
        }

    }

    void  TextureAtlas::_reset()
    {
        refreshMarkupColours();
    }

    void  TextureAtlas::_load(const Ogre::String& gorillaFile, const Ogre::String& groupName)
    {

        Ogre::ConfigFile f;
        f.loadFromResourceSystem(gorillaFile, groupName, " ", true);
        Ogre::ConfigFile::SectionIterator seci = f.getSectionIterator();

        Ogre::String secName;
        while (seci.hasMoreElements())
        {

            secName = seci.peekNextKey();
            Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();

            Ogre::StringUtil::toLowerCase(secName);

            if (secName == "texture")
            {
                settings->find("file")->second.append("~" + groupName);
                _loadTexture(settings);
            }
            else if (Ogre::StringUtil::startsWith(secName, "font.", false))
            {
                Ogre::uint index = Ogre::StringConverter::parseUnsignedInt(secName.substr(5));
                GlyphData* glyphData = OGRE_NEW GlyphData();
                mGlyphData[index] = glyphData;

                _loadGlyphs(settings, glyphData);
                _loadKerning(settings, glyphData);
                _loadVerticalOffsets(settings, glyphData);
            }
            else if (secName == "sprites")
                _loadSprites(settings);

        }

    }

    void  TextureAtlas::_loadTexture(Ogre::ConfigFile::SettingsMultiMap* settings)
    {

        Ogre::String name, data;
        Ogre::ConfigFile::SettingsMultiMap::iterator i;
        for (i = settings->begin(); i != settings->end(); ++i)
        {
            name = i->first;
            data = i->second;

            size_t comment = data.find_first_of('#');
            if (comment != std::string::npos)
                data = data.substr(0, comment);

            Ogre::StringUtil::toLowerCase(name);

            // file texturename ~groupname
            // >  file myatlas.png
            // >  file myatlas.png ~loadinggroup
            if (name == "file")
            {
                Ogre::String textureName = data;
                Ogre::String groupName = Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME;
                size_t groupSplit = data.find_first_of('~');
                if (groupSplit != std::string::npos)
                {
                    textureName = data.substr(0, groupSplit);
                    groupName = data.substr(groupSplit+1);
                    Ogre::StringUtil::trim(textureName);
                    Ogre::StringUtil::trim(groupName);
                }
#if OGRE_VERSION <= 67077 // If the version is less than or equal to 1.6.5
                mTexture = Ogre::TextureManager::getSingletonPtr()->getByName(data);
#else
                mTexture = Ogre::TextureManager::getSingletonPtr()->getByName(data, groupName);
#endif
                if (mTexture.isNull())
                    mTexture = Ogre::TextureManager::getSingletonPtr()->load(textureName, groupName);

                mInverseTextureSize.x = 1.0f / mTexture->getWidth();
                mInverseTextureSize.y = 1.0f / mTexture->getHeight();

                continue;
            }
            // layer x y
            // >  layer 100 105
            else if (name == "whitepixel")
            {
                mWhitePixel = Ogre::StringConverter::parseVector2(data);
                mWhitePixel.x *= mInverseTextureSize.x;
                mWhitePixel.y *= mInverseTextureSize.y;
            }

        }

    }

    void  TextureAtlas::_loadGlyphs(Ogre::ConfigFile::SettingsMultiMap* settings, GlyphData* glyphData)
    {

        Ogre::String name, data;
        Ogre::ConfigFile::SettingsMultiMap::iterator i;

        Ogre::StringVector str_values;
        Ogre::Vector2  offset(0,0);
        for (i = settings->begin(); i != settings->end(); ++i)
        {

            name = i->first;
            data = i->second;

            size_t comment = data.find_first_of('#');
            if (comment != std::string::npos)
                data = data.substr(0, comment);

            Ogre::StringUtil::toLowerCase(name);

            // lineheight x y
            // >  offset 0 80
            if (name == "offset")
            {
                offset = Ogre::StringConverter::parseVector2(data);
                continue;
            }
            // lineheight lineheight
            // >  lineheight 15
            else if (name == "lineheight")
            {
                glyphData->mLineHeight = Ogre::StringConverter::parseReal(data);
                continue;
            }
            // spacelength spacelength
            // >  spacelength 3
            else if (name == "spacelength")
            {
                glyphData->mSpaceLength = Ogre::StringConverter::parseReal(data);
                continue;
            }
            // baseline baseline
            // >  baseline 3
            else if (name == "baseline")
            {
                glyphData->mBaseline = Ogre::StringConverter::parseReal(data);
                continue;
            }
            // linespacing linespacing
            // >  linespacing 2
            else if (name == "linespacing")
            {
                glyphData->mLineSpacing = Ogre::StringConverter::parseReal(data);
                continue;
            }
            // monowidth width
            // >  monowidth 3
            else if (name == "monowidth")
            {
                glyphData->mMonoWidth = Ogre::StringConverter::parseReal(data);
                continue;
            }
            // range lower upper
            // >  range 33 126
            else if (name == "range")
            {
                Ogre::Vector2 t = Ogre::StringConverter::parseVector2(data);
                glyphData->mRangeBegin = t.x;
                glyphData->mRangeEnd = t.y;
            }
            // kerning kerning
            // >  kerning -1
            else if (name == "letterspacing")
            {
                glyphData->mLetterSpacing = Ogre::StringConverter::parseReal(data);
            }
        }

        for (Ogre::uint index = glyphData->mRangeBegin; index <= glyphData->mRangeEnd; index++)
        {

            Glyph* glyph = OGRE_NEW Glyph();
            glyphData->mGlyphs.push_back(glyph);

            std::stringstream s;
            s << "glyph_" << index;

            i = settings->find(s.str());
            if (i == settings->end())
                continue;

            str_values = Ogre::StringUtil::split((*i).second, " ", 5);

            if (str_values.size() < 4)
            {
                //std::cout << "[Gorilla] Glyph #" << (*i).second << " does not have enough properties.\n";
                continue;
            }

            glyph->uvLeft    = offset.x + Ogre::StringConverter::parseReal(  str_values[0]  );
            glyph->uvTop     = offset.y + Ogre::StringConverter::parseReal(  str_values[1]  );
            glyph->uvWidth   = Ogre::StringConverter::parseReal(  str_values[2]  );
            glyph->uvHeight  = Ogre::StringConverter::parseReal(  str_values[3]  );
            glyph->uvRight   = glyph->uvLeft + glyph->uvWidth;
            glyph->uvBottom  = glyph->uvTop + glyph->uvHeight;

            if (str_values.size() == 5)
                glyph->glyphAdvance = Ogre::StringConverter::parseInt(  str_values[4]  );
            else
                glyph->glyphAdvance = glyph->uvWidth;

        }

    }

    void  TextureAtlas::_loadKerning(Ogre::ConfigFile::SettingsMultiMap* settings, GlyphData* glyphData)
    {

        Ogre::String left_name, data;
        Ogre::ConfigFile::SettingsMultiMap::iterator i;
        Ogre::uint left_glyph_id;
        Ogre::uint right_glyph_id;
        int kerning;
        Ogre::StringVector str_values;

        for (i = settings->begin(); i != settings->end(); ++i)
        {

            left_name = i->first;
            data = i->second;
            Ogre::StringUtil::toLowerCase(left_name);

            if (left_name.substr(0,6) != "kerning_")
                continue;

            size_t comment = data.find_first_of('#');
            if (comment != std::string::npos)
                data = data.substr(0, comment);

            left_name = left_name.substr(8); // chop of kerning_
            left_glyph_id = Ogre::StringConverter::parseUnsignedInt(left_name);

            str_values = Ogre::StringUtil::split(data, " ", 2);

            if (str_values.size() != 2)
            {
                //std::cout << "[Gorilla] Kerning Glyph #" << left_name << " does not have enough properties\n";
                continue;
            }

            right_glyph_id = Ogre::StringConverter::parseUnsignedInt(str_values[0]);
            kerning = Ogre::StringConverter::parseInt(str_values[1]);

            glyphData->mGlyphs[right_glyph_id - glyphData->mRangeBegin]->kerning.push_back(Kerning(left_glyph_id, kerning));

        }

    }

    void  TextureAtlas::_loadVerticalOffsets(Ogre::ConfigFile::SettingsMultiMap* settings, GlyphData* glyphData)
    {

        Ogre::String left_name, data;
        Ogre::ConfigFile::SettingsMultiMap::iterator i;
        Ogre::uint glyph_id;
        int verticalOffset;

        for (i = settings->begin(); i != settings->end(); ++i)
        {

            left_name = i->first;
            data = i->second;
            Ogre::StringUtil::toLowerCase(left_name);

            if (left_name.substr(0,15) != "verticaloffset_")
                continue;

            size_t comment = data.find_first_of('#');
            if (comment != std::string::npos)
                data = data.substr(0, comment);

            left_name = left_name.substr(15); // chop of verticalOffset_
            glyph_id = Ogre::StringConverter::parseUnsignedInt(left_name);

            verticalOffset = Ogre::StringConverter::parseInt(data);

            glyphData->getGlyph(glyph_id)->verticalOffset = verticalOffset;

        }

    }

    void  TextureAtlas::_loadSprites(Ogre::ConfigFile::SettingsMultiMap* settings)
    {

        Ogre::String sprite_name, data;
        Ogre::ConfigFile::SettingsMultiMap::iterator i;

        Ogre::StringVector str_values;
        for (i = settings->begin(); i != settings->end(); ++i)
        {

            sprite_name = i->first;
            data = i->second;

            size_t comment = data.find_first_of('#');
            if (comment != std::string::npos)
                data = data.substr(0, comment);

            str_values = Ogre::StringUtil::split(data, " ", 4);

            if (str_values.size() != 4)
            {
                //std::cout << "[Gorilla] Sprite #" << sprite_name << " does not have enough properties\n" << data << "\n";
                continue;
            }

            Sprite* sprite = OGRE_NEW Sprite();

            sprite->uvLeft = Ogre::StringConverter::parseUnsignedInt(str_values[0]);
            sprite->uvTop = Ogre::StringConverter::parseUnsignedInt(str_values[1]);
            sprite->spriteWidth = Ogre::StringConverter::parseUnsignedInt(str_values[2]);
            sprite->spriteHeight = Ogre::StringConverter::parseUnsignedInt(str_values[3]);

            mSprites[sprite_name] = sprite;

        }

    }

    Ogre::MaterialPtr TextureAtlas::createOrGet2DMasterMaterial()
    {
        Ogre::MaterialPtr d2Material = Ogre::MaterialManager::getSingletonPtr()->getByName("Gorilla2D");
        if (d2Material.isNull() == false)
        {
            Ogre::Pass* pass = d2Material->getTechnique(0)->getPass(0);

            if(pass->hasVertexProgram())
            {
                Ogre::GpuProgramPtr gpuPtr = pass->getVertexProgram();
                gpuPtr->load();
            }

            if(pass->hasFragmentProgram())
            {
                Ogre::GpuProgramPtr gpuPtr = pass->getFragmentProgram();
                gpuPtr->load();
            }

            return d2Material;
        }

        d2Material = Ogre::MaterialManager::getSingletonPtr()->create("Gorilla2D", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
        Ogre::Pass* pass = d2Material->getTechnique(0)->getPass(0);
        pass->setCullingMode(Ogre::CULL_NONE);
        pass->setDepthCheckEnabled(false);
        pass->setDepthWriteEnabled(false);
        pass->setLightingEnabled(false);
        pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);

        Ogre::TextureUnitState* texUnit = pass->createTextureUnitState();
        texUnit->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
        texUnit->setTextureFiltering(Ogre::FO_NONE, Ogre::FO_NONE, Ogre::FO_NONE);

        return d2Material;
    }

    Ogre::MaterialPtr TextureAtlas::createOrGet3DMasterMaterial()
    {
        Ogre::MaterialPtr d3Material = Ogre::MaterialManager::getSingletonPtr()->getByName("Gorilla3D");
        if (d3Material.isNull() == false)
        {
            Ogre::Pass* pass = d3Material->getTechnique(0)->getPass(0);

            if(pass->hasVertexProgram())
            {
                Ogre::GpuProgramPtr gpuPtr = pass->getVertexProgram();
                gpuPtr->load();
            }

            if(pass->hasFragmentProgram())
            {
                Ogre::GpuProgramPtr gpuPtr = pass->getFragmentProgram();
                gpuPtr->load();
            }

            return d3Material;
        }

        d3Material = Ogre::MaterialManager::getSingletonPtr()->create("Gorilla3D", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
        Ogre::Pass* pass = d3Material->getTechnique(0)->getPass(0);
        pass->setCullingMode(Ogre::CULL_NONE);
        pass->setDepthCheckEnabled(false);
        pass->setDepthWriteEnabled(false);
        pass->setLightingEnabled(false);
        pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);

        Ogre::TextureUnitState* texUnit = pass->createTextureUnitState();
        texUnit->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP);
        texUnit->setTextureFiltering(Ogre::FO_ANISOTROPIC, Ogre::FO_ANISOTROPIC, Ogre::FO_ANISOTROPIC);

        return d3Material;
    }

    void  TextureAtlas::_create2DMaterial()
    {

        std::string matName = "Gorilla2D." + mTexture->getName();
        m2DMaterial = Ogre::MaterialManager::getSingletonPtr()->getByName(matName);

        if (m2DMaterial.isNull())
            m2DMaterial = createOrGet2DMasterMaterial()->clone(matName);

        m2DPass = m2DMaterial->getTechnique(0)->getPass(0);
        m2DPass->getTextureUnitState(0)->setTextureName(mTexture->getName());

    }

    void  TextureAtlas::_create3DMaterial()
    {

        std::string matName = "Gorilla3D." + mTexture->getName();
        m3DMaterial = Ogre::MaterialManager::getSingletonPtr()->getByName(matName);

        if (m3DMaterial.isNull())
            m3DMaterial = createOrGet3DMasterMaterial()->clone(matName);

        m3DPass = m3DMaterial->getTechnique(0)->getPass(0);
        m3DPass->getTextureUnitState(0)->setTextureName(mTexture->getName());

    }

    void  TextureAtlas::_calculateCoordinates()
    {

        Ogre::RenderSystem* rs = Ogre::Root::getSingletonPtr()->getRenderSystem();

        Ogre::Real texelX =  rs->getHorizontalTexelOffset(),
        texelY =  rs->getVerticalTexelOffset();

        for (std::map<Ogre::uint, GlyphData*>::iterator gd_it = mGlyphData.begin(); gd_it != mGlyphData.end(); gd_it++)
        {
            for(std::vector<Glyph*>::iterator it = (*gd_it).second->mGlyphs.begin(); it != (*gd_it).second->mGlyphs.end(); it++)
            {

                (*it)->uvLeft        -= texelX;
                (*it)->uvTop         -= texelY;
                (*it)->uvRight       += texelX;
                (*it)->uvBottom      += texelY;

                (*it)->uvLeft        *= mInverseTextureSize.x;
                (*it)->uvTop         *= mInverseTextureSize.y;
                (*it)->uvRight       *= mInverseTextureSize.x;
                (*it)->uvBottom      *= mInverseTextureSize.y;

                (*it)->texCoords[TopLeft].x = (*it)->uvLeft;
                (*it)->texCoords[TopLeft].y = (*it)->uvTop;
                (*it)->texCoords[TopRight].x = (*it)->uvRight;
                (*it)->texCoords[TopRight].y = (*it)->uvTop;
                (*it)->texCoords[BottomRight].x = (*it)->uvRight;
                (*it)->texCoords[BottomRight].y = (*it)->uvBottom;
                (*it)->texCoords[BottomLeft].x = (*it)->uvLeft;
                (*it)->texCoords[BottomLeft].y = (*it)->uvBottom;

                (*it)->glyphWidth     = (*it)->uvWidth;
                (*it)->glyphHeight    = (*it)->uvHeight;

            }
        }

        for (std::map<Ogre::String, Sprite*>::iterator it = mSprites.begin(); it != mSprites.end(); it++)
        {
            (*it).second->uvRight    = (*it).second->uvLeft + (*it).second->spriteWidth;
            (*it).second->uvBottom   = (*it).second->uvTop  + (*it).second->spriteHeight;

            (*it).second->uvLeft    *= mInverseTextureSize.x;
            (*it).second->uvTop     *= mInverseTextureSize.y;
            (*it).second->uvRight   *= mInverseTextureSize.x;
            (*it).second->uvBottom  *= mInverseTextureSize.y;

            (*it).second->texCoords[TopLeft].x = (*it).second->uvLeft;
            (*it).second->texCoords[TopLeft].y = (*it).second->uvTop;
            (*it).second->texCoords[TopRight].x = (*it).second->uvRight;
            (*it).second->texCoords[TopRight].y = (*it).second->uvTop;
            (*it).second->texCoords[BottomRight].x = (*it).second->uvRight;
            (*it).second->texCoords[BottomRight].y = (*it).second->uvBottom;
            (*it).second->texCoords[BottomLeft].x = (*it).second->uvLeft;
            (*it).second->texCoords[BottomLeft].y = (*it).second->uvBottom;

        }

    }

    void   TextureAtlas::refreshMarkupColours()
    {
        mMarkupColour[0] = rgb(255, 255, 255);
        mMarkupColour[1] = rgb(0, 0, 0);
        mMarkupColour[2] = rgb(204, 204, 204);
        mMarkupColour[3] = rgb(254, 220, 129);
        mMarkupColour[4] = rgb(254, 138, 129);
        mMarkupColour[5] = rgb(123, 236, 110);
        mMarkupColour[6] = rgb(44,  192, 171);
        mMarkupColour[7] = rgb(199, 93,  142);
        mMarkupColour[8] = rgb(254, 254, 254);
        mMarkupColour[9] = rgb(13,  13,  13);
    }

    void   TextureAtlas::setMarkupColour(Ogre::uint index, const Ogre::ColourValue& colour)
    {
        if (index > 9)
            return;

        mMarkupColour[index] = colour;
    }

    const Ogre::ColourValue &TextureAtlas::getMarkupColour(Ogre::uint index) const
    {
        if (index > 9)
            return Ogre::ColourValue::White;

        return mMarkupColour[index];
    }

    GlyphData::GlyphData()
    : mRangeBegin(0),
    mRangeEnd(0),
    mSpaceLength(0),
    mLineHeight(0),
    mBaseline(0),
    mLineSpacing(0),
    mLetterSpacing(0),
    mMonoWidth(0)
    {
    }

    GlyphData::~GlyphData()
    {

        for (std::vector<Glyph*>::iterator it = mGlyphs.begin(); it != mGlyphs.end(); it++)
        {
            OGRE_DELETE (*it);
        }

    }

    Silverback::Silverback()
    {

        Ogre::Root::getSingletonPtr()->addFrameListener(this);

    }

    Silverback::~Silverback()
    {

        Ogre::Root::getSingletonPtr()->removeFrameListener(this);

        // Delete Screens.
        for (std::vector<Screen*>::iterator it = mScreens.begin(); it != mScreens.end(); it++)
            OGRE_DELETE (*it);

        mScreens.clear();

        // Delete Screens.
        for (std::vector<ScreenRenderable*>::iterator it = mScreenRenderables.begin(); it != mScreenRenderables.end(); it++)
            OGRE_DELETE (*it);

        mScreenRenderables.clear();

        // Delete Atlases.
        for (std::map<Ogre::String, TextureAtlas*>::iterator it = mAtlases.begin(); it != mAtlases.end(); it++)
            OGRE_DELETE (*it).second;
        mAtlases.clear();

    }

    void Silverback::loadAtlas(const Ogre::String &name, const Ogre::String &group)
    {
        TextureAtlas* atlas = OGRE_NEW TextureAtlas(name + ".gorilla", group);
        mAtlases[name] = atlas;
    }

    Screen* Silverback::createScreen(Ogre::Viewport* viewport, const Ogre::String& atlas_name)
    {
        TextureAtlas* atlas = (*mAtlases.find(atlas_name)).second;
        return createScreen(viewport, atlas);
    }

    Screen* Silverback::createScreen(Ogre::Viewport *viewport, TextureAtlas *atlas)
    {
        Screen* screen = OGRE_NEW Screen(viewport, atlas);
        mScreens.push_back(screen);
        return screen;
    }

    ScreenRenderable* Silverback::createScreenRenderable(const Ogre::Vector2& maxSize, const Ogre::String& atlas_name)
    {
        TextureAtlas* atlas = (*mAtlases.find(atlas_name)).second;
        ScreenRenderable* screen = OGRE_NEW ScreenRenderable(maxSize, atlas);
        mScreenRenderables.push_back(screen);
        return screen;
    }

    void Silverback::destroyScreen(Screen* screen)
    {
        if (screen == 0)
            return;

        mScreens.erase(std::find(mScreens.begin(), mScreens.end(), screen));
        OGRE_DELETE screen;
    }

    void Silverback::destroyScreenRenderable(ScreenRenderable* screen_renderables)
    {
        mScreenRenderables.erase(std::find(mScreenRenderables.begin(), mScreenRenderables.end(), screen_renderables));
        OGRE_DELETE screen_renderables;
    }

    bool Silverback::frameStarted(const Ogre::FrameEvent& evt)
    {
        for (std::vector<ScreenRenderable*>::iterator it = mScreenRenderables.begin(); it != mScreenRenderables.end(); it++)
            (*it)->frameStarted();

        return true;
    }

    LayerContainer::LayerContainer(TextureAtlas* atlas)
    : mIndexRedrawAll(false), mAtlas(atlas)
    {
    }

    LayerContainer::~LayerContainer()
    {
        for (std::vector<Layer*>::iterator it = mLayers.begin(); it != mLayers.end(); it++)
            OGRE_DELETE (*it);

        _destroyVertexBuffer();
    }

    Layer* LayerContainer::createLayer(Ogre::uint index)
    {
        Layer* layer = OGRE_NEW Layer(index, this);
        mLayers.push_back(layer);

        std::map<Ogre::uint, IndexData*>::iterator index_data = mIndexData.find( layer->getIndex() );
        if (index_data == mIndexData.end())
        {
            mIndexData[layer->getIndex()] = OGRE_NEW IndexData();
            index_data = mIndexData.find( layer->getIndex() );
        }

        (*index_data).second->mLayers.push_back( layer );
        (*index_data).second->mRedrawNeeded = true;

        mIndexRedrawNeeded = true;

        return layer;
    }

    /*! function. destroyLayer
     desc.
     Destroy a layer and it's contents.
     */
    void LayerContainer::destroy(Layer* layer)
    {
        if (layer == 0)
            return;

        std::map<Ogre::uint, IndexData*>::iterator index_data = mIndexData.find( layer->getIndex() );

        // Remove layer from index, and delete index if index is empty.
        if (index_data != mIndexData.end())
        {
            IndexData* indexData = (*index_data).second;
            indexData->mLayers.erase(std::find(indexData->mLayers.begin(), indexData->mLayers.end(), layer));
            indexData->mRedrawNeeded = true;
            mIndexRedrawNeeded = true;
            if (indexData->mLayers.size() == 0)
            {
                mIndexData.erase(index_data);
                OGRE_DELETE indexData;
            }
        }

        mLayers.erase(std::find(mLayers.begin(), mLayers.end(), layer));
        OGRE_DELETE layer;
    }

    void LayerContainer::_createVertexBuffer(size_t initialSize = 32)
    {
        mVertexBufferSize = initialSize * 6;
        mRenderOpPtr->vertexData = OGRE_NEW Ogre::VertexData;
        mRenderOpPtr->vertexData->vertexStart = 0;

        Ogre::VertexDeclaration* vertexDecl = mRenderOpPtr->vertexData->vertexDeclaration;
        size_t offset = 0;

        // Position.
        vertexDecl->addElement(0,0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);

        // Colour
        vertexDecl->addElement(0, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);

        // Texture Coordinates
        vertexDecl->addElement(0, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);

        mVertexBuffer = Ogre::HardwareBufferManager::getSingletonPtr()
        ->createVertexBuffer(
                             vertexDecl->getVertexSize(0),
                             mVertexBufferSize,
                             Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
                             false
                             );

        mRenderOpPtr->vertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);
        mRenderOpPtr->operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
        mRenderOpPtr->useIndexes = false;
    }

    void LayerContainer::_destroyVertexBuffer()
    {
        OGRE_DELETE mRenderOpPtr->vertexData;
        mRenderOpPtr->vertexData = 0;
        mVertexBuffer.setNull();
        mVertexBufferSize = 0;
    }

    void LayerContainer::_resizeVertexBuffer(size_t requestedSize)
    {

        if (mVertexBufferSize == 0)
            _createVertexBuffer();

        if (requestedSize > mVertexBufferSize)
        {
            size_t newVertexBufferSize = 1;

            while(newVertexBufferSize < requestedSize)
                newVertexBufferSize <<= 1;

            mVertexBuffer = Ogre::HardwareBufferManager::getSingletonPtr()->createVertexBuffer(
                                                                                mRenderOpPtr->vertexData->vertexDeclaration->getVertexSize(0),
                                                                                newVertexBufferSize,
                                                                                Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
                                                                                false
                                                                                );
            mVertexBufferSize = newVertexBufferSize;
            mRenderOpPtr->vertexData->vertexStart = 0;
            mRenderOpPtr->vertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);
        }

    }

    void LayerContainer::_recalculateIndexes()
    {

        std::map<Ogre::uint, IndexData*>::iterator index_data;

        // Clear all index data.
        for(std::map< Ogre::uint, IndexData* >::iterator index_data = mIndexData.begin(); index_data != mIndexData.end(); index_data++)
        {
            (*index_data).second->mVertices.remove_all();
            (*index_data).second->mLayers.clear();
            (*index_data).second->mRedrawNeeded = false;
        }

        // Loop through layers, and add them to IndexData
        for(std::vector<Layer*>::iterator layer = mLayers.begin(); layer != mLayers.end(); layer++)
        {
            index_data = mIndexData.find( (*layer)->getIndex() );
            if (index_data == mIndexData.end())
            {
                mIndexData[(*layer)->getIndex()] = OGRE_NEW IndexData();
                index_data = mIndexData.find( (*layer)->getIndex() );
            }

            (*index_data).second->mLayers.push_back( (*layer) );
        }

        // Prune any index data that is not.
        bool deleted = false;

        while(0xDEADBEEF)
        {
            deleted = false;
            for(std::map< Ogre::uint, IndexData* >::iterator index_data = mIndexData.begin(); index_data != mIndexData.end(); index_data++)
            {
                if (  (*index_data).second->mLayers.size() == 0)
                {
                    OGRE_DELETE (*index_data).second;
                    mIndexData.erase(index_data);
                    deleted = true;
                    break;
                }
            }

            if (!deleted)
                break;

        }

        mIndexRedrawAll = true;

    }

    void LayerContainer::_redrawIndex(Ogre::uint index, bool force)
    {

        std::map<Ogre::uint, IndexData*>::iterator it = mIndexData.find( index );
        if (it == mIndexData.end())
            return;

        IndexData* indexData = (*it).second;

        indexData->mVertices.remove_all();
        indexData->mRedrawNeeded = false;

        for (size_t i=0;i < indexData->mLayers.size();i++)
        {
            if (indexData->mLayers[i]->mVisible)
                indexData->mLayers[i]->_render( indexData->mVertices, force );
        }

    }

    void LayerContainer::_requestIndexRedraw(Ogre::uint index)
    {
        std::map<Ogre::uint, IndexData*>::iterator it = mIndexData.find( index );
        if (it == mIndexData.end())
            return;

        (*it).second->mRedrawNeeded = true;
        mIndexRedrawNeeded = true;
    }

    void LayerContainer::_redrawAllIndexes(bool force)
    {
        mIndexRedrawNeeded = false;
        for(std::map<Ogre::uint, IndexData*>::iterator it = mIndexData.begin(); it != mIndexData.end();it++)
        {
            IndexData* indexData = (*it).second;
            if (indexData->mRedrawNeeded || force)
            {
                //std::cout << "+++ Drawing Index: " << (*it).first;
                indexData->mVertices.remove_all();
                indexData->mRedrawNeeded = false;

                for (size_t i=0;i < indexData->mLayers.size();i++)
                {
                    if (indexData->mLayers[i]->mVisible)
                        indexData->mLayers[i]->_render( indexData->mVertices, force );
                }
            }

        }
    }

    void LayerContainer::_renderVertices(bool force)
    {

        if (mIndexRedrawNeeded == false)
            if (!force)
                return;

        _redrawAllIndexes(force);

        size_t knownVertexCount = 0;

        for(std::map<Ogre::uint, IndexData*>::iterator it = mIndexData.begin(); it != mIndexData.end();it++)
            knownVertexCount += (*it).second->mVertices.size();

        _resizeVertexBuffer(knownVertexCount);
        //std::cout << "+++ Known Vertex Count is: " << knownVertexCount << "\n";
        Vertex* writeIterator = (Vertex*) mVertexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);

        size_t i = 0;
        IndexData* indexData = 0;
        for(std::map<Ogre::uint, IndexData*>::iterator it = mIndexData.begin(); it != mIndexData.end();it++)
        {
            indexData = (*it).second;
            for (i=0;i < indexData->mVertices.size();i++)
            {
                *writeIterator++ = indexData->mVertices[i];
            }
        }

        mVertexBuffer->unlock();
        mRenderOpPtr->vertexData->vertexCount = knownVertexCount;
    }

    Screen::Screen(Ogre::Viewport* viewport, TextureAtlas* atlas)
    : LayerContainer(atlas), mViewport(viewport), mScale(1,1,1), mIsVisible(true), mCanRender(false)
    {
        mRenderOpPtr = &mRenderOp;
        mSceneMgr = mViewport->getCamera()->getSceneManager();

        mRenderSystem = Ogre::Root::getSingletonPtr()->getRenderSystem();

        mWidth = mViewport->getActualWidth();
        mHeight = mViewport->getActualHeight();
#if OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0
        mOrientation = mViewport->getOrientationMode();
#else
        mOrientation = Ogre::OR_DEGREE_0;
        mOrientationChanged = false;
#endif

        mInvWidth = 1.0f / mWidth;
        mInvHeight = 1.0f / mHeight;

        mVertexTransform.makeTransform(Ogre::Vector3::ZERO, mScale, Ogre::Quaternion(1,0,0,0));

        mSceneMgr->addRenderQueueListener(this);
        _createVertexBuffer();
    }

    Screen::~Screen()
    {
        mSceneMgr->removeRenderQueueListener(this);
    }

    void Screen::renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation)
    {
        if (mRenderSystem->_getViewport() != mViewport || queueGroupId != SCREEN_RENDERQUEUE)
            return;
        if (mIsVisible && mLayers.size())
            renderOnce();
    }

    void Screen::_prepareRenderSystem()
    {
        mRenderSystem->_setWorldMatrix( Ogre::Matrix4::IDENTITY );
        mRenderSystem->_setProjectionMatrix( Ogre::Matrix4::IDENTITY );
        mRenderSystem->_setViewMatrix( Ogre::Matrix4::IDENTITY );
        mSceneMgr->_setPass(mAtlas->get2DPass());
    }

    void Screen::renderOnce()
    {
        bool force = false;
        // force == true if viewport size changed.
        if (mWidth != mViewport->getActualWidth() || mHeight != mViewport->getActualHeight()
#if OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0
            || mOrientation != mViewport->getOrientationMode()
#else
            || mOrientationChanged
#endif
            )
        {
            mWidth = mViewport->getActualWidth();
            mHeight = mViewport->getActualHeight();

            mInvWidth = 1.0f / mWidth;
            mInvHeight = 1.0f / mHeight;

#if OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0
            mOrientation = mViewport->getOrientationMode();
#else
            if (mOrientation == Ogre::OR_DEGREE_90 || mOrientation == Ogre::OR_DEGREE_270)
            {
                std::swap(mWidth, mHeight);
                std::swap(mInvWidth, mInvHeight);
            }
            mOrientationChanged = false;
#endif

            if (mOrientation == Ogre::OR_DEGREE_90)
                mVertexTransform.makeTransform(Ogre::Vector3::ZERO, mScale, Ogre::Quaternion(Ogre::Degree(90), Ogre::Vector3::UNIT_Z));
            else if (mOrientation == Ogre::OR_DEGREE_180)
                mVertexTransform.makeTransform(Ogre::Vector3::ZERO, mScale, Ogre::Quaternion(Ogre::Degree(180), Ogre::Vector3::UNIT_Z));
            else if (mOrientation == Ogre::OR_DEGREE_270)
                mVertexTransform.makeTransform(Ogre::Vector3::ZERO, mScale, Ogre::Quaternion(Ogre::Degree(270), Ogre::Vector3::UNIT_Z));
            else
                mVertexTransform.makeTransform(Ogre::Vector3::ZERO, mScale, Ogre::Quaternion(1,0,0,0));

            force = true;
        }

        _renderVertices(force);
        if (mRenderOp.vertexData->vertexCount)
        {
            _prepareRenderSystem();
            mRenderSystem->_render(mRenderOp);
        }
    }

    void  Screen::_transform(buffer<Vertex>& vertices, size_t begin, size_t end)
    {

        for (size_t i = begin; i < end; i++)
        {
            vertices[i].position.x = ((vertices[i].position.x) * mInvWidth) * 2 - 1;
            vertices[i].position.y = ((vertices[i].position.y) * mInvHeight) * -2 + 1;
        }

        if (mVertexTransform != Ogre::Matrix4::IDENTITY)
        {
            for (size_t i = begin; i < end; i++)
                vertices[i].position = mVertexTransform * vertices[i].position;
        }

    }

    ScreenRenderable::ScreenRenderable(const Ogre::Vector2& maxSize, TextureAtlas* atlas)
    : LayerContainer(atlas), mMaxSize(maxSize)
    {
        mRenderOpPtr = &mRenderOp;

        mBox.setInfinite();
        setMaterial(mAtlas->get3DMaterialName());

        _createVertexBuffer();
    }

    ScreenRenderable::~ScreenRenderable()
    {
    }

    void ScreenRenderable::frameStarted()
    {
        renderOnce();
    }

    void ScreenRenderable::renderOnce()
    {
        if (mIndexRedrawNeeded)
        {
            _renderVertices(false);
            calculateBoundingBox();
        }
    }

    void ScreenRenderable::calculateBoundingBox()
    {
        IndexData* indexData = 0;
        mBox.setExtents(0,0,0,0,0,0);
        size_t i = 0;
        for(std::map<Ogre::uint, IndexData*>::iterator it = mIndexData.begin(); it != mIndexData.end();it++)
        {
            indexData = (*it).second;
            for (i=0;i < indexData->mVertices.size();i++)
            {
                mBox.merge( indexData->mVertices[i].position );
            }
        }
        if (mBox.isNull() == false)
        {
            mBox.merge(Ogre::Vector3(0,0,-0.25f));
            mBox.merge(Ogre::Vector3(0,0, 0.25f));

        }

        Ogre::SceneNode* node = getParentSceneNode();
        if (node)
            node->_updateBounds();

    }

    void ScreenRenderable::_transform(buffer<Vertex>& vertices, size_t begin, size_t end)
    {
        Ogre::Vector2 halfSize = mMaxSize * 0.5;
        for (size_t i = begin; i < end; i++)
        {
            vertices[i].position.x = (vertices[i].position.x * 0.01f) - halfSize.x;
            vertices[i].position.y = (vertices[i].position.y * -0.01f) + halfSize.y;
        }
    }

    Layer::Layer(Ogre::uint index, LayerContainer* parent)
    : mIndex(index), mParent(parent), mVisible(true), mAlphaModifier(1.0f)
    {
    }

    Layer::~Layer()
    {
        destroyAllRectangles();
        destroyAllPolygons();
        destroyAllLineLists();
        destroyAllQuadLists();
        destroyAllCaptions();
        destroyAllMarkupTexts();
    }

    void Layer::_markDirty()
    {
        mParent->_requestIndexRedraw(mIndex);
    }

    Rectangle* Layer::createRectangle(Ogre::Real left, Ogre::Real top, Ogre::Real width, Ogre::Real height)
    {
        Rectangle* rectangle = OGRE_NEW Rectangle(left, top, width, height, this);
        mRectangles.push_back(rectangle);
        return rectangle;
    }

    void Layer::destroyRectangle(Rectangle* rectangle)
    {
        if (rectangle == 0)
            return;

        mRectangles.erase(std::find(mRectangles.begin(), mRectangles.end(), rectangle));
        OGRE_DELETE rectangle;
        _markDirty();
    }

    void Layer::destroyAllRectangles()
    {

        for (Rectangles::iterator it = mRectangles.begin(); it != mRectangles.end(); it++)
        {
            OGRE_DELETE (*it);
        }

        mRectangles.clear();
    }

    Polygon* Layer::createPolygon(Ogre::Real left, Ogre::Real top, Ogre::Real radius, Ogre::uint sides)
    {
        if (sides < 3)
            sides = 3;

        Polygon* polygon = OGRE_NEW Polygon(left, top, radius, sides, this);
        mPolygons.push_back(polygon);
        return polygon;
    }

    void Layer::destroyPolygon(Polygon* polygon)
    {
        if (polygon == 0)
            return;

        mPolygons.erase(std::find(mPolygons.begin(), mPolygons.end(), polygon));
        OGRE_DELETE polygon;
        _markDirty();
    }

    void Layer::destroyAllPolygons()
    {

        for (Polygons::iterator it = mPolygons.begin(); it != mPolygons.end(); it++)
        {
            OGRE_DELETE (*it);
        }

        mPolygons.clear();
    }

    LineList* Layer::createLineList()
    {
        LineList* linelist = OGRE_NEW LineList(this);
        mLineLists.push_back(linelist);
        return linelist;
    }

    void Layer::destroyLineList(LineList* linelist)
    {
        if (linelist == 0)
            return;

        mLineLists.erase(std::find(mLineLists.begin(), mLineLists.end(), linelist));
        OGRE_DELETE linelist;
        _markDirty();
    }

    void Layer::destroyAllLineLists()
    {

        for (LineLists::iterator it = mLineLists.begin(); it != mLineLists.end(); it++)
        {
            OGRE_DELETE (*it);
        }

        mLineLists.clear();
    }

    QuadList* Layer::createQuadList()
    {
        QuadList* quadlist = OGRE_NEW QuadList(this);
        mQuadLists.push_back(quadlist);
        return quadlist;
    }

    void Layer::destroyQuadList(QuadList* quadlist)
    {
        if (quadlist == 0)
            return;

        mQuadLists.erase(std::find(mQuadLists.begin(), mQuadLists.end(), quadlist));
        OGRE_DELETE quadlist;
        _markDirty();
    }

    void Layer::destroyAllQuadLists()
    {

        for (QuadLists::iterator it = mQuadLists.begin(); it != mQuadLists.end(); it++)
        {
            OGRE_DELETE (*it);
        }

        mQuadLists.clear();
    }

    Caption* Layer::createCaption(Ogre::uint glyphDataIndex, Ogre::Real x, Ogre::Real y, const Ogre::String& text)
    {
        Caption* caption = OGRE_NEW Caption(glyphDataIndex,x, y, text, this);
        mCaptions.push_back(caption);
        return caption;
    }

    void Layer::destroyCaption(Caption* caption)
    {
        if (caption == 0)
            return;

        mCaptions.erase(std::find(mCaptions.begin(), mCaptions.end(), caption));
        OGRE_DELETE caption;
        _markDirty();
    }

    void Layer::destroyAllCaptions()
    {

        for (Captions::iterator it = mCaptions.begin(); it != mCaptions.end(); it++)
        {
            OGRE_DELETE (*it);
        }

        mCaptions.clear();
    }

    MarkupText* Layer::createMarkupText(Ogre::uint defaultGlyphIndex, Ogre::Real x, Ogre::Real y, const Ogre::String& text)
    {
        MarkupText* markuptext = OGRE_NEW MarkupText(defaultGlyphIndex, x, y, text, this);
        mMarkupTexts.push_back(markuptext);
        return markuptext;
    }

    void Layer::destroyMarkupText(MarkupText* markuptext)
    {
        if (markuptext == 0)
            return;

        mMarkupTexts.erase(std::find(mMarkupTexts.begin(), mMarkupTexts.end(), markuptext));
        OGRE_DELETE markuptext;
        _markDirty();
    }

    void Layer::destroyAllMarkupTexts()
    {

        for (MarkupTexts::iterator it = mMarkupTexts.begin(); it != mMarkupTexts.end(); it++)
        {
            OGRE_DELETE (*it);
        }

        mMarkupTexts.clear();
    }

    void Layer::_render(buffer<Vertex>& vertices, bool force)
    {

        if (mAlphaModifier == 0.0f)
            return;

        size_t begin = vertices.size();
        size_t i = 0;

        // Render/redraw rectangles
        for (Rectangles::iterator it = mRectangles.begin(); it != mRectangles.end(); it++)
        {

            if ((*it)->mDirty || force)
                (*it)->_redraw();

            for (i=0; i < (*it)->mVertices.size(); i++)
                vertices.push_back((*it)->mVertices[i]);

        }

        // Render/redraw polygons
        for (Polygons::iterator it = mPolygons.begin(); it != mPolygons.end(); it++)
        {

            if ((*it)->mDirty || force)
                (*it)->_redraw();

            for (i=0; i < (*it)->mVertices.size(); i++)
                vertices.push_back((*it)->mVertices[i]);

        }

        // Render/redraw line lists
        for (LineLists::iterator it = mLineLists.begin(); it != mLineLists.end(); it++)
        {

            if ((*it)->mDirty || force)
                (*it)->_redraw();

            for (i=0; i < (*it)->mVertices.size(); i++)
                vertices.push_back((*it)->mVertices[i]);

        }

        // Render/redraw quad lists
        for (QuadLists::iterator it = mQuadLists.begin(); it != mQuadLists.end(); it++)
        {

            if ((*it)->mDirty || force)
                (*it)->_redraw();

            for (i=0; i < (*it)->mVertices.size(); i++)
                vertices.push_back((*it)->mVertices[i]);

        }

        // Render/redraw caption
        for (Captions::iterator it = mCaptions.begin(); it != mCaptions.end(); it++)
        {

            if ((*it)->mDirty || force)
                (*it)->_redraw();

            for (i=0; i < (*it)->mVertices.size(); i++)
                vertices.push_back((*it)->mVertices[i]);

        }

        // Render/redraw caption
        for (MarkupTexts::iterator it = mMarkupTexts.begin(); it != mMarkupTexts.end(); it++)
        {

            if ((*it)->mTextDirty || force)
                (*it)->_calculateCharacters();

            if ((*it)->mDirty || force)
                (*it)->_redraw();

            for (i=0; i < (*it)->mVertices.size(); i++)
                vertices.push_back((*it)->mVertices[i]);

        }

        if (mAlphaModifier != 1.0f)
        {
            for (i=begin;i < vertices.size();i++)
                vertices[i].colour.a *= mAlphaModifier;
        }

        mParent->_transform(vertices, begin, vertices.size());

    }

    Rectangle::Rectangle(Ogre::Real left, Ogre::Real top, Ogre::Real width, Ogre::Real height, Layer* layer) : mLayer(layer)
    {
        mDirty       = true;
        mLeft        = left;
        mTop         = top;
        mRight       = left + width;
        mBottom      = top + height;
        mBorderWidth = 0.0f;
        mBackgroundColour[0] = mBackgroundColour[1] =  mBackgroundColour[2] = mBackgroundColour[3] = Ogre::ColourValue::White;
        mUV[0] = mUV[1] = mUV[2] = mUV[3] = mLayer->_getSolidUV();

    }

    void  Rectangle::_redraw()
    {

        if (mDirty == false)
            return;

        mVertices.remove_all();

        Ogre::Real texelOffsetX = mLayer->_getTexelX(), texelOffsetY = mLayer->_getTexelY();
        Ogre::Vector2 a, b, c, d;
        a.x = mLeft  + texelOffsetX; a.y = mTop    + texelOffsetY;
        b.x = mRight + texelOffsetX; b.y = mTop    + texelOffsetY;
        c.x = mLeft  + texelOffsetX; c.y = mBottom + texelOffsetY;
        d.x = mRight + texelOffsetX; d.y = mBottom + texelOffsetY;

        // Border
        if (mBorderWidth != 0)
        {
            Ogre::Vector2 i = a, j = b, k = c, l = d;
            i.x -= mBorderWidth;    i.y -= mBorderWidth;
            j.x += mBorderWidth;    j.y -= mBorderWidth;
            k.x -= mBorderWidth;    k.y += mBorderWidth;
            l.x += mBorderWidth;    l.y += mBorderWidth;

            Vertex temp;
            Ogre::Vector2 uv = mLayer->_getSolidUV();

            // North
            PUSH_TRIANGLE(mVertices, temp, a, j, i, uv, mBorderColour[Border_North])
            PUSH_TRIANGLE(mVertices, temp, a, b, j, uv, mBorderColour[Border_North])

            // East
            PUSH_TRIANGLE(mVertices, temp, d, j, b, uv, mBorderColour[Border_East])
            PUSH_TRIANGLE(mVertices, temp, d, l, j, uv, mBorderColour[Border_East])

            // South
            PUSH_TRIANGLE(mVertices, temp, k, d, c, uv, mBorderColour[Border_South])
            PUSH_TRIANGLE(mVertices, temp, k, l, d, uv, mBorderColour[Border_South])

            // West
            PUSH_TRIANGLE(mVertices, temp, k, a, i, uv, mBorderColour[Border_West])
            PUSH_TRIANGLE(mVertices, temp, k, c, a, uv, mBorderColour[Border_West])

        }

        // Fill
        if (mBackgroundColour[0].a != 0)
        {
            Vertex temp;
            // Triangle A
            PUSH_VERTEX(mVertices, temp, c.x, c.y, mUV[3], mBackgroundColour[3]);    // Left/Bottom  3
            PUSH_VERTEX(mVertices, temp, b.x, b.y, mUV[1], mBackgroundColour[1]);    // Right/Top    1
            PUSH_VERTEX(mVertices, temp, a.x, a.y, mUV[0], mBackgroundColour[0]);    // Left/Top     0

            // Triangle B
            PUSH_VERTEX(mVertices, temp, c.x, c.y, mUV[3], mBackgroundColour[3]);    // Left/Bottom   3
            PUSH_VERTEX(mVertices, temp, d.x, d.y, mUV[2], mBackgroundColour[2]);    // Right/Bottom  2
            PUSH_VERTEX(mVertices, temp, b.x, b.y, mUV[1], mBackgroundColour[1]);    // Right/Top     1
        }

        mDirty = false;

    }

    Polygon::Polygon(Ogre::Real left, Ogre::Real top, Ogre::Real radius, size_t sides, Layer* layer)
    : mLayer(layer), mSprite(0)
    {
        mDirty        = true;
        mLayer->_markDirty();
        mLeft           = left;
        mTop            = top;
        mRadius         = radius;
        mSides          = sides;
        mBackgroundColour         = Ogre::ColourValue::White;
        mBorderColour.a = 0;
        mBorderWidth    = 0;
    }

    void  Polygon::_redraw()
    {

        if (mDirty == false)
            return;

        mVertices.remove_all();
        Vertex temp;

        Ogre::Real theta = mAngle.valueRadians();
        Ogre::Real inc = (2 * Ogre::Math::PI) / Ogre::Real(mSides);

        Ogre::Vector2 lastVertex;
        lastVertex.x = mLeft + (mRadius * cos(theta));
        lastVertex.y = mTop + (mRadius * sin(theta));
        Ogre::Vector2 thisVertex;

        if (mBorderWidth != 0)
        {

            Ogre::Vector2 lastOuterVertex, outerVertex, thisVertex, uv;
            uv = mLayer->_getSolidUV();

            lastOuterVertex.x = mLeft + ((mRadius + mBorderWidth) * cos(theta));
            lastOuterVertex.y = mTop + ((mRadius + mBorderWidth) * sin(theta));

            for (size_t i=0;i < mSides;i++)
            {
                theta += inc;
                thisVertex.x = mLeft + (mRadius * Ogre::Math::Cos(theta));
                thisVertex.y = mTop + (mRadius * Ogre::Math::Sin(theta));
                outerVertex.x = mLeft + ((mRadius + mBorderWidth) * Ogre::Math::Cos(theta));
                outerVertex.y = mTop + ((mRadius + mBorderWidth) * Ogre::Math::Sin(theta));

                PUSH_TRIANGLE(mVertices, temp, lastVertex, outerVertex, lastOuterVertex, uv, mBorderColour);
                PUSH_TRIANGLE(mVertices, temp, lastVertex, thisVertex, outerVertex, uv, mBorderColour);

                lastVertex = thisVertex;
                lastOuterVertex = outerVertex;
            }
        }

        if (mBackgroundColour.a != 0)
        {
            if (mSprite)
            {
                Ogre::Real xRadius = mSprite->spriteWidth * 0.5f;
                Ogre::Real yRadius = mSprite->spriteHeight * 0.5f;

                Ogre::Vector2 centerUV, lastUV, thisUV, baseUV, texSize = mLayer->_getTextureSize();
                baseUV.x = mSprite->uvLeft * texSize.x;
                baseUV.y = mSprite->uvTop * texSize.y;
                baseUV.x += xRadius;
                baseUV.y += yRadius;

                centerUV = baseUV / texSize;
                lastUV = baseUV;
                lastUV.x = baseUV.x + (xRadius * Ogre::Math::Cos(theta));
                lastUV.y = baseUV.y + (yRadius * Ogre::Math::Sin(theta));
                lastUV /= texSize;

                for (size_t i=0;i < mSides;i++)
                {
                    PUSH_VERTEX(mVertices, temp, mLeft, mTop, centerUV, mBackgroundColour);
                    theta += inc;
                    thisVertex.x = mLeft + (mRadius * Ogre::Math::Cos(theta));
                    thisVertex.y = mTop + (mRadius * Ogre::Math::Sin(theta));
                    thisUV.x = baseUV.x + (xRadius * Ogre::Math::Cos(theta));
                    thisUV.y = baseUV.y + (yRadius * Ogre::Math::Sin(theta));
                    thisUV /= texSize;
                    PUSH_VERTEX(mVertices, temp, thisVertex.x, thisVertex.y, thisUV, mBackgroundColour);
                    PUSH_VERTEX(mVertices, temp, lastVertex.x, lastVertex.y, lastUV, mBackgroundColour);
                    lastVertex = thisVertex;
                    lastUV = thisUV;
                }
            }
            else
            {
                Ogre::Vector2 uv = uv = mLayer->_getSolidUV();

                for (size_t i=0;i < mSides;i++)
                {
                    PUSH_VERTEX(mVertices, temp, mLeft, mTop, uv, mBackgroundColour);
                    theta += inc;
                    thisVertex.x = mLeft + (mRadius * Ogre::Math::Cos(theta));
                    thisVertex.y = mTop + (mRadius * Ogre::Math::Sin(theta));
                    PUSH_VERTEX(mVertices, temp, thisVertex.x, thisVertex.y, uv, mBackgroundColour);
                    PUSH_VERTEX(mVertices, temp, lastVertex.x, lastVertex.y, uv, mBackgroundColour);
                    lastVertex = thisVertex;
                }
            }
        }

        mDirty = false;

    }

    LineList::LineList(Layer* layer) : mLayer(layer)
    {
        mDirty = false;
    }

    void  LineList::begin(Ogre::Real lineThickness, const Ogre::ColourValue& colour)
    {
        mDirty = false;
        mPositions.remove_all();
        mThickness = lineThickness;
        mColour = colour;
    }

    void  LineList::position(Ogre::Real x, Ogre::Real y)
    {
        mPositions.push_back(Ogre::Vector2(x,y));
    }

    void  LineList::position(const Ogre::Vector2& position)
    {
        mPositions.push_back(position);
    }

    void  LineList::end(bool closed)
    {
        mIsClosed = closed;
        mDirty = true;
    }

    void  LineList::_redraw()
    {
        if (mDirty == false)
            return;

        mVertices.remove_all();

        if (mPositions.size() < 2)
            return;

        Vertex temp;

        Ogre::Real halfThickness = mThickness * 0.5f;

        Ogre::Vector2 perp, lastLeft, lastRight, thisLeft, thisRight, uv = mLayer->_getSolidUV();

        size_t i = 1;

        for (;i < mPositions.size();i++)
        {

            perp      = (mPositions[i] - mPositions[i-1]).perpendicular().normalisedCopy();
            lastLeft  = mPositions[i-1] - perp * halfThickness;
            lastRight = mPositions[i-1] + perp * halfThickness;
            thisLeft  = mPositions[i] - perp * halfThickness;
            thisRight = mPositions[i] + perp * halfThickness;

            // Triangle A
            PUSH_VERTEX(mVertices, temp, lastRight.x, lastRight.y, uv, mColour);       // Left/Bottom
            PUSH_VERTEX(mVertices, temp, thisLeft.x, thisLeft.y, uv, mColour);         // Right/Top
            PUSH_VERTEX(mVertices, temp, lastLeft.x, lastLeft.y, uv, mColour);          // Left/Top
            // Triangle B
            PUSH_VERTEX(mVertices, temp, lastRight.x, lastRight.y, uv, mColour);       // Left/Bottom
            PUSH_VERTEX(mVertices, temp, thisRight.x, thisRight.y, uv, mColour);      // Right/Bottom
            PUSH_VERTEX(mVertices, temp, thisLeft.x, thisLeft.y, uv, mColour);         // Right/Top

        }

        if (mIsClosed)
        {
            i = mPositions.size() - 1;
            perp      = (mPositions[0] - mPositions[i]).perpendicular().normalisedCopy();
            lastLeft  = mPositions[i] - perp * halfThickness;
            lastRight = mPositions[i] + perp * halfThickness;
            thisLeft  = mPositions[0] - perp * halfThickness;
            thisRight = mPositions[0] + perp * halfThickness;

            // Triangle A
            PUSH_VERTEX(mVertices, temp, lastRight.x, lastRight.y, uv, mColour);       // Left/Bottom
            PUSH_VERTEX(mVertices, temp, thisLeft.x, thisLeft.y, uv, mColour);         // Right/Top
            PUSH_VERTEX(mVertices, temp, lastLeft.x, lastLeft.y, uv, mColour);          // Left/Top
            // Triangle B
            PUSH_VERTEX(mVertices, temp, lastRight.x, lastRight.y, uv, mColour);       // Left/Bottom
            PUSH_VERTEX(mVertices, temp, thisRight.x, thisRight.y, uv, mColour);      // Right/Bottom
            PUSH_VERTEX(mVertices, temp, thisLeft.x, thisLeft.y, uv, mColour);         // Right/Top

        }

    }

    QuadList::QuadList(Layer* layer)
    : mLayer(layer)
    {
        mWhiteUV = mLayer->_getSolidUV();
    }

    void  QuadList::begin()
    {
        mQuads.remove_all();
        mDirty = false;
    }

    void  QuadList::rectangle(Ogre::Real x, Ogre::Real y, Ogre::Real w, Ogre::Real h, const Ogre::ColourValue colour)
    {
        Quad q;
        q.mPosition[TopLeft].x = x; q.mPosition[TopLeft].y = y;
        q.mPosition[TopRight].x = x + w; q.mPosition[TopRight].y = y;
        q.mPosition[BottomRight].x = x + w; q.mPosition[BottomRight].y = y + h;
        q.mPosition[BottomLeft].x = x; q.mPosition[BottomLeft].y = y + h;

        q.mColour[0] = q.mColour[1] = q.mColour[2] = q.mColour[3] = colour;
        q.mUV[0] = q.mUV[1] = q.mUV[2] = q.mUV[3] = mWhiteUV;
        mQuads.push_back(q);
    }

    void  QuadList::gradient(Ogre::Real x, Ogre::Real y, Ogre::Real w, Ogre::Real h, Gradient gradient, const Ogre::ColourValue& colourA, const Ogre::ColourValue& colourB)
    {
        Quad q;
        if (gradient == Gradient_NorthSouth)
        {
            q.mColour[0] = q.mColour[1] = colourA;
            q.mColour[2] = q.mColour[3] = colourB;
        }
        else if (gradient == Gradient_WestEast)
        {
            q.mColour[0] = q.mColour[3] = colourA;
            q.mColour[1] = q.mColour[2] = colourB;
        }
        else if (gradient == Gradient_Diagonal)
        {
            Ogre::ColourValue avg;
            avg.r = (colourA.r + colourB.r) * 0.5f;
            avg.g = (colourA.g + colourB.g) * 0.5f;
            avg.b = (colourA.b + colourB.b) * 0.5f;
            avg.a = (colourA.a + colourB.a) * 0.5f;
            q.mColour[0] = colourA;
            q.mColour[1] = avg = q.mColour[3] = avg;
            q.mColour[2] = colourB;
        }

        q.mPosition[TopLeft].x = x; q.mPosition[TopLeft].y = y;
        q.mPosition[TopRight].x = x + w; q.mPosition[TopRight].y = y;
        q.mPosition[BottomRight].x = x + w; q.mPosition[BottomRight].y = y + h;
        q.mPosition[BottomLeft].x = x; q.mPosition[BottomLeft].y = y + h;

        q.mUV[0] = q.mUV[1] = q.mUV[2] = q.mUV[3] = mWhiteUV;
        mQuads.push_back(q);
    }

    void  QuadList::sprite(Ogre::Real x, Ogre::Real y, Ogre::Real w, Ogre::Real h, Sprite* sprite)
    {
        Quad q;
        q.mPosition[TopLeft].x     = q.mPosition[BottomLeft].x    = x;
        q.mPosition[TopLeft].y     = q.mPosition[TopRight].y      = y;
        q.mPosition[TopRight].x    = q.mPosition[BottomRight].x   = x + w;
        q.mPosition[BottomRight].y = q.mPosition[BottomLeft].y    = y + h;
        q.mColour[0] = q.mColour[1] = q.mColour[2] = q.mColour[3] = Ogre::ColourValue::White;

        q.mUV[TopLeft].x = sprite->uvLeft;
        q.mUV[TopLeft].y = sprite->uvTop;

        q.mUV[TopRight].x = sprite->uvRight;
        q.mUV[TopRight].y = sprite->uvTop;

        q.mUV[BottomLeft].x = sprite->uvLeft;
        q.mUV[BottomLeft].y = sprite->uvBottom;

        q.mUV[BottomRight].x = sprite->uvRight;
        q.mUV[BottomRight].y = sprite->uvBottom;
        mQuads.push_back(q);

    }

    void  QuadList::border(Ogre::Real x, Ogre::Real y, Ogre::Real w, Ogre::Real h, Ogre::Real thickness, const Ogre::ColourValue& colour)
    {
        border(x,y,w,h,thickness,colour,colour,colour,colour);
    }

    void  QuadList::border(Ogre::Real x, Ogre::Real y, Ogre::Real w, Ogre::Real h, Ogre::Real thickness, const Ogre::ColourValue& northColour, const Ogre::ColourValue& eastColour, const Ogre::ColourValue& southColour, const Ogre::ColourValue& westColour)
    {

        Ogre::Vector2 a(x,y), b(x+w,y), c(x,y+h), d(x+w,y+h),
        i = a, j = b, k = c, l = d;
        i.x -= thickness;    i.y -= thickness;
        j.x += thickness;    j.y -= thickness;
        k.x -= thickness;    k.y += thickness;
        l.x += thickness;    l.y += thickness;

        Vertex temp;

        // North
        Quad q;
        q.mUV[0] = q.mUV[1] = q.mUV[2] = q.mUV[3] = mWhiteUV;

        // North
        q.mPosition[TopLeft] = i;
        q.mPosition[TopRight] = j;
        q.mPosition[BottomLeft] = a;
        q.mPosition[BottomRight] = b;
        q.mColour[0] = q.mColour[1] = q.mColour[2] = q.mColour[3] = northColour;
        mQuads.push_back(q);

        // East
        q.mPosition[TopLeft] = b;
        q.mPosition[TopRight] = j;
        q.mPosition[BottomLeft] = d;
        q.mPosition[BottomRight] = l;
        q.mColour[0] = q.mColour[1] = q.mColour[2] = q.mColour[3] = eastColour;
        mQuads.push_back(q);

        // South
        q.mPosition[TopLeft] = c;
        q.mPosition[TopRight] = d;
        q.mPosition[BottomLeft] = k;
        q.mPosition[BottomRight] = l;
        q.mColour[0] = q.mColour[1] = q.mColour[2] = q.mColour[3] = southColour;
        mQuads.push_back(q);

        // West
        q.mPosition[TopLeft] = i;
        q.mPosition[TopRight] = a;
        q.mPosition[BottomLeft] = k;
        q.mPosition[BottomRight] = c;
        q.mColour[0] = q.mColour[1] = q.mColour[2] = q.mColour[3] = westColour;
        mQuads.push_back(q);

    }

    void  QuadList::glyph(Ogre::uint glyphDataIndex, Ogre::Real x, Ogre::Real y, unsigned char character, const Ogre::ColourValue& colour)
    {
        GlyphData* glyphData = mLayer->_getGlyphData(glyphDataIndex);
        if (glyphData == 0)
        {
#if GORILLA_USES_EXCEPTIONS == 1
            OGRE_EXCEPT( Ogre::Exception::ERR_ITEM_NOT_FOUND, "Glyph data not found", __FUNC__ );
#else
            return;
#endif
        }

        Glyph* glyph = glyphData->getGlyph(character);
        if (glyph == 0)
            return;

        y += glyph->verticalOffset;

        Quad q;
        q.mPosition[TopLeft].x = x;
        q.mPosition[TopLeft].y = y;
        q.mPosition[TopRight].x = x + glyph->glyphWidth;
        q.mPosition[TopRight].y = y;
        q.mPosition[BottomRight].x = x + glyph->glyphWidth;
        q.mPosition[BottomRight].y = y + glyph->glyphHeight;
        q.mPosition[BottomLeft].x = x;
        q.mPosition[BottomLeft].y = y + glyph->glyphHeight;

        q.mColour[0] = q.mColour[1] = q.mColour[2] = q.mColour[3] = colour;

        q.mUV[TopLeft].x = glyph->uvLeft;
        q.mUV[TopLeft].y = glyph->uvTop;

        q.mUV[TopRight].x = glyph->uvRight;
        q.mUV[TopRight].y = glyph->uvTop;

        q.mUV[BottomRight].x = glyph->uvRight;
        q.mUV[BottomRight].y = glyph->uvBottom;

        q.mUV[BottomLeft].x = glyph->uvLeft;
        q.mUV[BottomLeft].y = glyph->uvBottom;

        mQuads.push_back(q);
    }

    void  QuadList::glyph(Ogre::uint glyphDataIndex, Ogre::Real x, Ogre::Real y, Ogre::Real w, Ogre::Real h, unsigned char character, const Ogre::ColourValue& colour)
    {
        GlyphData* glyphData = mLayer->_getGlyphData(glyphDataIndex);
        if (glyphData == 0)
        {
#if GORILLA_USES_EXCEPTIONS == 1
            OGRE_EXCEPT( Ogre::Exception::ERR_ITEM_NOT_FOUND, "Glyph data not found", __FUNC__ );
#else
            return;
#endif
        }

        Glyph* glyph = glyphData->getGlyph(character);
        if (glyph == 0)
            return;

        y += glyph->verticalOffset;

        Quad q;
        q.mPosition[TopLeft].x = x;
        q.mPosition[TopLeft].y = y;
        q.mPosition[TopRight].x = x + w;
        q.mPosition[TopRight].y = y;
        q.mPosition[BottomRight].x = x + w;
        q.mPosition[BottomRight].y = y + h;
        q.mPosition[BottomLeft].x = x;
        q.mPosition[BottomLeft].y = y + h;

        q.mColour[0] = q.mColour[1] = q.mColour[2] = q.mColour[3] = colour;

        q.mUV[TopLeft].x = glyph->uvLeft;
        q.mUV[TopLeft].y = glyph->uvTop;

        q.mUV[TopRight].x = glyph->uvRight;
        q.mUV[TopRight].y = glyph->uvTop;

        q.mUV[BottomRight].x = glyph->uvRight;
        q.mUV[BottomRight].y = glyph->uvBottom;

        q.mUV[BottomLeft].x = glyph->uvLeft;
        q.mUV[BottomLeft].y = glyph->uvBottom;

        mQuads.push_back(q);
    }

    void  QuadList::end()
    {
        mDirty = true;
        mLayer->_markDirty();
    }

    void  QuadList::_redraw()
    {
        if (mDirty == false)
            return;

        mVertices.remove_all();
        Vertex temp;

        for (size_t i=0;i < mQuads.size();i++)
        {
            PUSH_QUAD(mVertices, temp, mQuads[i].mPosition, mQuads[i].mColour, mQuads[i].mUV)
        }

        mDirty = false;
    }

    Caption::Caption(Ogre::uint glyphDataIndex, Ogre::Real left, Ogre::Real top, const Ogre::String& caption, Layer* layer)
    : mLayer(layer)
    {
        mGlyphData      = mLayer->_getGlyphData(glyphDataIndex);
        if (mGlyphData == 0)
        {
            mDirty        = false;
#if GORILLA_USES_EXCEPTIONS == 1
            OGRE_EXCEPT( Ogre::Exception::ERR_ITEM_NOT_FOUND, "Glyph data not found", __FUNC__ );
#else
            return;
#endif
        }
        mDirty        = true;
        mLayer->_markDirty();
        mLeft           = left;
        mTop            = top;
        mWidth          = 0.0f;
        mHeight         = 0.0f;
        mText           = caption;
        mColour         = Ogre::ColourValue::White;
        mBackground.a   = 0.0f;
        mAlignment      = TextAlign_Left;
        mVerticalAlign  = VerticalAlign_Top;
        mFixedWidth     = false;
    }

    void Caption::_calculateDrawSize(Ogre::Vector2& retSize)
    {

        Ogre::Real cursor = 0,
        kerning = 0;

        unsigned char thisChar = 0, lastChar = 0;
        Glyph* glyph = 0;
        retSize.x = 0;
        retSize.y = mGlyphData->mLineHeight;

        for (size_t i=0;i < mText.length();i++)
        {
            thisChar = mText[i];

            if (thisChar == ' ')
            {
                lastChar = thisChar;
                cursor += mGlyphData->mSpaceLength;
                continue;
            }

            if (  thisChar < mGlyphData->mRangeBegin || thisChar > mGlyphData->mRangeEnd  )
            {
                lastChar = 0;
                continue;
            }

            glyph = mGlyphData->getGlyph(thisChar);
            if (glyph == 0)
                continue;
            kerning = glyph->getKerning(lastChar);
            if (kerning == 0)
                kerning = mGlyphData->mLetterSpacing;

            cursor  += _getAdvance(glyph, kerning);
            lastChar = thisChar;

        } // for

        retSize.x = cursor - kerning;
    }

    void Caption::_redraw()
    {

        if (mDirty == false)
            return;

        mVertices.remove_all();

        Ogre::Vector2 uv = mLayer->_getSolidUV();

        if (mBackground.a > 0)
        {
            Ogre::Vector2  a, b, c, d;
            a.x = mLeft;  a.y = mTop;
            b.x = mLeft + mWidth; b.y = mTop;
            c.x = mLeft;  c.y = mTop + mHeight;
            d.x = mLeft + mWidth; d.y = c.y = mTop + mHeight;
            Vertex temp;
            PUSH_TRIANGLE(mVertices, temp, c, b, a, uv, mBackground);
            PUSH_TRIANGLE(mVertices, temp, c, d, b, uv, mBackground);
        }

        Ogre::Real left = 0, top = 0, right = 0, bottom = 0, cursorX = 0, cursorY = 0, kerning = 0, texelOffsetX = mLayer->_getTexelX(), texelOffsetY = mLayer->_getTexelY();
        Ogre::Vector2 knownSize;
        Glyph* glyph = 0;

        bool clipLeft = false, clipRight = false;
        Ogre::Real clipLeftPos = 0, clipRightPos = 0;

        if (mAlignment == TextAlign_Left)
        {
            cursorX = mLeft;

            if (mWidth)
            {
                clipRight = true;
                clipRightPos = mLeft + mWidth;
            }

        }
        else if (mAlignment == TextAlign_Centre)
        {
            _calculateDrawSize(knownSize);
            cursorX = mLeft + (mWidth * 0.5f) - (knownSize.x * 0.5f);

            if (mWidth)
            {
                clipLeft = true;
                clipLeftPos = mLeft;
                clipRight = true;
                clipRightPos = mLeft + mWidth;
            }

        }
        else if (mAlignment == TextAlign_Right)
        {
            _calculateDrawSize(knownSize);
            cursorX = mLeft + mWidth - knownSize.x;
            if (mWidth)
            {
                clipLeft = true;
                clipLeftPos = mLeft;
            }
        }

        if (mVerticalAlign == VerticalAlign_Top)
            cursorY = mTop;
        else if (mVerticalAlign == VerticalAlign_Middle)
            cursorY = mTop + (mHeight * 0.5) - (mGlyphData->mLineHeight * 0.5);
        else if (mVerticalAlign == VerticalAlign_Bottom)
            cursorY = mTop +  mHeight - mGlyphData->mLineHeight;

        unsigned char thisChar = 0, lastChar = 0;
        Vertex temp;
        mClippedLeftIndex = std::string::npos;
        mClippedRightIndex = std::string::npos;

        cursorX = Ogre::Math::Floor( cursorX );
        cursorY = Ogre::Math::Floor( cursorY );

        for (size_t i=0;i < mText.size();i++)
        {
            thisChar = mText[i];

            if (thisChar == ' ')
            {
                lastChar = thisChar;
                cursorX += mGlyphData->mSpaceLength;
                continue;
            }

            if (  thisChar < mGlyphData->mRangeBegin || thisChar > mGlyphData->mRangeEnd  )
            {
                lastChar = 0;
                continue;
            }

            glyph = mGlyphData->getGlyph(thisChar);
            if (glyph == 0)
                continue;
            kerning = glyph->getKerning(lastChar);
            if (kerning == 0)
                kerning = mGlyphData->mLetterSpacing;

            left = cursorX - texelOffsetX;
            top = cursorY - texelOffsetY + glyph->verticalOffset;
            right = left + glyph->glyphWidth + texelOffsetX;
            bottom = top + glyph->glyphHeight + texelOffsetY;

            if (clipLeft)
            {
                if (left < clipLeftPos)
                {
                    if (mClippedLeftIndex == std::string::npos)
                        mClippedLeftIndex = i;
                    cursorX  += _getAdvance(glyph, kerning);
                    lastChar = thisChar;
                    continue;
                }
            }

            if (clipRight)
            {
                if (right > clipRightPos)
                {
                    if (mClippedRightIndex == std::string::npos)
                        mClippedRightIndex = i;
                    cursorX  += _getAdvance(glyph, kerning);
                    lastChar = thisChar;
                    continue;
                }
            }

            if(fixedWidth())
            {
                Ogre::Real offset = std::floor((mGlyphData->mMonoWidth - glyph->glyphWidth) / 2.0f);
                left += offset;
                right += offset;
            }

            // Triangle A
            PUSH_VERTEX(mVertices, temp, left, bottom, glyph->texCoords[BottomLeft], mColour);  // Left/Bottom  3
            PUSH_VERTEX(mVertices, temp, right, top, glyph->texCoords[TopRight], mColour);    // Right/Top    1
            PUSH_VERTEX(mVertices, temp, left, top, glyph->texCoords[TopLeft], mColour);     // Left/Top     0

            // Triangle B
            PUSH_VERTEX(mVertices, temp, left, bottom, glyph->texCoords[BottomLeft], mColour);  // Left/Bottom  3
            PUSH_VERTEX(mVertices, temp, right, bottom, glyph->texCoords[BottomRight], mColour); // Right/Bottom 2
            PUSH_VERTEX(mVertices, temp, right, top, glyph->texCoords[TopRight], mColour);    // Right/Top    1

            cursorX  += _getAdvance(glyph, kerning);
            lastChar = thisChar;

        } // for

        mDirty = false;
    }

    Ogre::Real Caption::_getAdvance(Glyph* glyph, Ogre::Real kerning)
    {
        if(mFixedWidth)
            return mGlyphData->mMonoWidth;
        else
            return glyph->glyphAdvance + kerning;
    }

    MarkupText::MarkupText(Ogre::uint defaultGlyphIndex, Ogre::Real left, Ogre::Real top, const Ogre::String& text, Layer* parent)
    : mLayer(parent)
    {
        mDefaultGlyphData = mLayer->_getGlyphData(defaultGlyphIndex);

        if (mDefaultGlyphData == 0)
        {
            mDirty          = false;
            mTextDirty      = false;
#if GORILLA_USES_EXCEPTIONS == 1
            OGRE_EXCEPT( Ogre::Exception::ERR_ITEM_NOT_FOUND, "Glyph data not found", __FUNC__ );
#else
            return;
#endif
        }

        mDirty          = true;
        mTextDirty      = true;
        mLayer->_markDirty();
        mLeft           = left;
        mTop            = top;
        mWidth          = 0.0f;
        mHeight         = 0.0f;
        mText           = text;
        mBackground.a   = 0.0f;

    }

    void MarkupText::_calculateCharacters()
    {
        if (mTextDirty == false)
            return;

        Ogre::Real cursorX = mLeft, cursorY = mTop, kerning = 0, texelOffsetX = mLayer->_getTexelX(), texelOffsetY = mLayer->_getTexelY(), right = 0, bottom = 0, left = 0, top = 0;
        unsigned int thisChar = 0, lastChar = 0;
        Glyph* glyph = 0;

        mMaxTextWidth = 0;

        mCharacters.remove_all();

        bool markupMode = false;
        Ogre::ColourValue colour = mLayer->_getMarkupColour(0);
        bool fixedWidth = false;

        GlyphData* glyphData = mDefaultGlyphData;
        Ogre::Real lineHeight = glyphData->mLineHeight;

        for(size_t i=0;i < mText.length();i++)
        {

            thisChar = mText[i];

            if (thisChar == ' ')
            {
                lastChar = thisChar;
                cursorX += glyphData->mSpaceLength;
                continue;
            }

            if (thisChar == '\n')
            {
                lastChar = thisChar;
                cursorX = mLeft;
                cursorY += lineHeight;
                lineHeight = glyphData->mLineHeight;
                continue;
            }

            if (  thisChar < glyphData->mRangeBegin || thisChar > glyphData->mRangeEnd  )
            {
                lastChar = 0;
                continue;
            }

            if (thisChar == '%' && markupMode == false)
            {
                markupMode = true;
                continue;
            }

            if (markupMode == true)
            {
                if (thisChar == '%')
                {
                    // Escape Character.
                }
                else
                {
                    markupMode = false;

                    if (thisChar >= '0' && thisChar <= '9')
                    {
                        colour = mLayer->_getMarkupColour(thisChar - 48);
                    }
                    else if (thisChar == 'R' || thisChar == 'r')
                    {
                        colour = mLayer->_getMarkupColour(0);
                    }
                    else if (thisChar == 'M' || thisChar == 'm')
                    {
                        fixedWidth = !fixedWidth;
                    }
                    else if (thisChar == '@')
                    {
                        markupMode = false;
                        bool foundIt = false;
                        size_t begin = i;
                        while(i < mText.size())
                        {
                            if (mText[i] == '%')
                            {
                                foundIt = true;
                                break;
                            }
                            i++;
                        }

                        if (foundIt == false)
                            return;

                        Ogre::uint index = Ogre::StringConverter::parseUnsignedInt(mText.substr(begin+1, i - begin - 1));
                        glyphData = mLayer->_getGlyphData(index);
                        if (glyphData == 0)
                            return;
                        lineHeight = std::max(lineHeight, glyphData->mLineHeight);
                        continue;
                    }
                    else if (thisChar == ':')
                    {
                        markupMode = false;
                        bool foundIt = false;
                        size_t begin = i;
                        while(i < mText.size())
                        {
                            if (mText[i] == '%')
                            {
                                foundIt = true;
                                break;
                            }
                            i++;
                        }

                        if (foundIt == false)
                            return;

                        Ogre::String sprite_name = mText.substr(begin+1, i - begin - 1);

                        Sprite* sprite = mLayer->_getSprite(sprite_name);
                        if (sprite == 0)
                            continue;

                        left = cursorX - texelOffsetX;
                        top = cursorY - texelOffsetY + glyph->verticalOffset;
                        right = left + sprite->spriteWidth + texelOffsetX;
                        bottom = top + sprite->spriteHeight + texelOffsetY;

                        Character c;
                        c.mIndex = i;
                        c.mPosition[TopLeft].x = left;
                        c.mPosition[TopLeft].y = top;
                        c.mPosition[TopRight].x = right;
                        c.mPosition[TopRight].y = top;
                        c.mPosition[BottomLeft].x = left;
                        c.mPosition[BottomLeft].y = bottom;
                        c.mPosition[BottomRight].x = right;
                        c.mPosition[BottomRight].y = bottom;
                        c.mUV[0] = sprite->texCoords[0];
                        c.mUV[1] = sprite->texCoords[1];
                        c.mUV[2] = sprite->texCoords[2];
                        c.mUV[3] = sprite->texCoords[3];
                        c.mColour = colour;

                        mCharacters.push_back(c);

                        cursorX  += sprite->spriteWidth;

                        lineHeight = std::max(lineHeight, sprite->spriteHeight);

                        continue;
                    }

                    continue;
                }
                markupMode = false;
            }

            glyph = glyphData->getGlyph(thisChar);

            if (!fixedWidth)
            {
                kerning = glyph->getKerning(lastChar);
                if (kerning == 0)
                    kerning = glyphData->mLetterSpacing;
            }

            left = cursorX;
            top = cursorY + glyph->verticalOffset;
            right = cursorX + glyph->glyphWidth + texelOffsetX;
            bottom = top + glyph->glyphHeight + texelOffsetY;

            if (fixedWidth)
            {
                Ogre::Real offset = std::floor((glyphData->mMonoWidth - glyph->glyphWidth) / 2.0f);
                left += offset;
                right += offset;
            }

            Character c;
            c.mIndex = i;
            c.mPosition[TopLeft].x = left;
            c.mPosition[TopLeft].y = top;
            c.mPosition[TopRight].x = right;
            c.mPosition[TopRight].y = top;
            c.mPosition[BottomLeft].x = left;
            c.mPosition[BottomLeft].y = bottom;
            c.mPosition[BottomRight].x = right;
            c.mPosition[BottomRight].y = bottom;
            c.mUV[0] = glyph->texCoords[0];
            c.mUV[1] = glyph->texCoords[1];
            c.mUV[2] = glyph->texCoords[2];
            c.mUV[3] = glyph->texCoords[3];
            c.mColour = colour;

            mCharacters.push_back(c);

            if (fixedWidth)
                cursorX  += glyphData->mMonoWidth;
            else
                cursorX  += glyph->glyphAdvance + kerning;

            if( cursorX > mMaxTextWidth )
                mMaxTextWidth = cursorX;

            lastChar = thisChar;
        }

        mMaxTextWidth -= mLeft;

        mTextDirty = false;
    }

    void  MarkupText::_redraw()
    {

        if (mDirty == false)
            return;

        mVertices.remove_all();

        Vertex temp;
        for (size_t i=0; i < mCharacters.size();i++)
        {
            PUSH_QUAD2(mVertices, temp, mCharacters[i].mPosition, mCharacters[i].mColour, mCharacters[i].mUV);
        }

        mDirty = false;
    }

} // namespace Gorilla


text:
<?php

namespace BingAds\CampaignManagement;

/**
 * Adds one or more campaign criterions that help determine whether ads in each campaign get served.
 *
 * @link http://msdn.microsoft.com/en-us/library/dn913127(v=msads.90).aspx AddCampaignCriterions Request Object
 *
 * @uses CampaignCriterion
 * @uses CampaignCriterionType
 * @used-by BingAdsCampaignManagementService::AddCampaignCriterions
 */
final class AddCampaignCriterionsRequest
{
    /**
     * A list of criterions that help determine whether ads in each campaign get served.
     *
     * @var CampaignCriterion[]
     */
    public $CampaignCriterions;
    /**
     * The type of campaign criterion to add, for example ProductScope.
     *
     * @var CampaignCriterionType
     */
    public $CriterionType;
}

redpajama_set_name: RedPajamaGithub


text:
using System;
using System.IO;
using MagneticImage.Reader;
using MagneticImage.Writer;

namespace MagneticImage.Sandbox
{
    class Program
    {
        public static void Main(string[] args)
        {
            var arguments = new Arguments(args);
            if (!arguments.IsValid)
                return;

            if (!File.Exists(arguments.InputFile)) {
                Console.Error.WriteLine(String.Format("Input file \"{0}\" not found", arguments.InputFile));
                return;
            }

            var diskImage = DskImageReader.Read(arguments.InputFile);

            var xmlOutput = new XmlDiskWriter(Console.Out, BinaryTextMode.AsciiHexSwitch);
            xmlOutput.Write(diskImage);

            DskImageWriter.Write(diskImage, "testing.dsk");
        }
    }
}