UIRendererGles.h#

Parent directory (OpenGLES)

Contains implementations of functions for the classes in UIRendererGles.h.

Includes#

  • PVRCore/math/MathUtils.h

  • PVRCore/texture/Texture.h

  • PVRUtils/OpenGLES/SpriteGles.h

Included By#

Namespaces#

Classes#

Source Code#

#pragma once
#include "PVRUtils/OpenGLES/SpriteGles.h"
#include "PVRCore/texture/Texture.h"
#include "PVRCore/math/MathUtils.h"

namespace pvr {
namespace ui {

struct GLState
{
    GLint activeProgram;
    GLint activeTextureUnit;
    GLint boundTexture;
    GLint blendEnabled;
    GLint blendSrcRgb;
    GLint blendSrcAlpha;
    GLint blendDstRgb;
    GLint blendDstAlpha;
    GLint blendEqationRgb;
    GLint blendEqationAlpha;
    GLboolean colorMask[4];
    GLint depthTest;
    GLint depthMask;
    GLint stencilTest;
    GLint cullingEnabled;
    GLint culling;
    GLint windingOrder;
    GLint sampler7;
    GLint vbo;
    GLint ibo;
    GLint vao;
    std::vector<bool> vertexAttribArray;
    std::vector<GLint> vertexAttribBindings;
    std::vector<GLint> vertexAttribSizes;
    std::vector<GLint> vertexAttribTypes;
    std::vector<GLint> vertexAttribNormalized;
    std::vector<GLint> vertexAttribStride;
    std::vector<GLvoid*> vertexAttribOffset;

    void storeCurrentGlState(Api api);

    GLState()
        : activeProgram(-1), activeTextureUnit(-1), boundTexture(-1), blendDstAlpha(GL_ONE), blendDstRgb(GL_ONE_MINUS_SRC_ALPHA), blendEnabled(GL_TRUE),
          blendEqationAlpha(GL_FUNC_ADD), blendEqationRgb(GL_FUNC_ADD), blendSrcAlpha(GL_ZERO), blendSrcRgb(GL_SRC_ALPHA), depthMask(GL_FALSE), depthTest(GL_FALSE),
          stencilTest(GL_FALSE), cullingEnabled(GL_FALSE), culling(GL_BACK), windingOrder(GL_CCW), ibo(-1), sampler7(0), vbo(-1), vao(-1), vertexAttribArray(8, GL_FALSE),
          vertexAttribBindings(8, -1), vertexAttribSizes(8, -1), vertexAttribTypes(8, -1), vertexAttribNormalized(8, -1), vertexAttribStride(8, -1),
          vertexAttribOffset(8, static_cast<GLvoid*>(nullptr))
    {
        colorMask[0] = GL_TRUE;
        colorMask[1] = GL_TRUE;
        colorMask[2] = GL_TRUE;
        colorMask[3] = GL_TRUE;
    }
};

struct GLStateTracker : public GLState
{
    bool activeProgramChanged;
    bool activeTextureUnitChanged;
    bool boundTextureChanged;
    bool blendEnabledChanged;
    bool blendSrcRgbChanged;
    bool blendSrcAlphaChanged;
    bool blendDstRgbChanged;
    bool blendDstAlphaChanged;
    bool blendEqationRgbChanged;
    bool blendEqationAlphaChanged;
    bool colorMaskChanged;
    bool depthTestChanged;
    bool depthMaskChanged;
    bool stencilTestChanged;
    bool cullingEnabledChanged;
    bool cullingChanged;
    bool windingOrderChanged;
    bool sampler7Changed;
    bool vboChanged;
    bool iboChanged;
    bool vaoChanged;
    std::vector<bool> vertexAttribArrayChanged;
    std::vector<bool> vertexAttribPointerChanged;

    void setUiState(Api api);

    void checkStateChanged(const GLState& currentGlState);

    void checkStateChanged(const GLStateTracker& stateTracker);

    void restoreState(const GLState& currentGlState, Api api);

    GLStateTracker()
        : activeProgramChanged(GL_FALSE), activeTextureUnitChanged(GL_FALSE), boundTextureChanged(GL_FALSE), blendEnabledChanged(GL_FALSE), blendSrcRgbChanged(GL_FALSE),
          blendDstRgbChanged(GL_FALSE), blendDstAlphaChanged(GL_FALSE), blendEqationRgbChanged(GL_FALSE), blendEqationAlphaChanged(GL_FALSE), colorMaskChanged(GL_FALSE),
          depthTestChanged(GL_FALSE), depthMaskChanged(GL_FALSE), stencilTestChanged(GL_FALSE), cullingEnabledChanged(GL_FALSE), cullingChanged(GL_FALSE),
          windingOrderChanged(GL_FALSE), sampler7Changed(GL_FALSE), vboChanged(GL_FALSE), iboChanged(GL_FALSE), vaoChanged(GL_FALSE), vertexAttribArrayChanged(8, GL_FALSE),
          vertexAttribPointerChanged(8, GL_FALSE)
    {}
};

class UIRenderer
{
public:
    struct ProgramData
    {
        enum Uniform
        {
            UniformMVPmtx,
            UniformFontTexture,
            UniformColor,
            UniformAlphaMode,
            UniformUVmtx,
            NumUniform
        };
        enum Attribute
        {
            AttributeVertex,
            AttributeUV,
            NumAttribute
        };
        int32_t uniforms[NumUniform];
    };

    const GLuint& getFontIbo()
    {
        if (!_fontIboCreated)
        {
            // create the FontIBO
            std::vector<uint16_t> fontFaces;
            fontFaces.resize(impl::Font_::FontElement);

            for (uint32_t i = 0; i < impl::Font_::MaxRenderableLetters; ++i)
            {
                fontFaces[i * 6u] = static_cast<uint16_t>(0u + i * 4u);
                fontFaces[i * 6u + 1u] = static_cast<uint16_t>(3u + i * 4u);
                fontFaces[i * 6u + 2u] = static_cast<uint16_t>(1u + i * 4u);

                fontFaces[i * 6u + 3u] = static_cast<uint16_t>(3u + i * 4u);
                fontFaces[i * 6u + 4u] = static_cast<uint16_t>(0u + i * 4u);
                fontFaces[i * 6u + 5u] = static_cast<uint16_t>(2u + i * 4u);
            }
            GLint binding;
            gl::GetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &binding);

            gl::GenBuffers(1, &_fontIbo);
            gl::BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _fontIbo);
            gl::BufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<uint32_t>(sizeof(fontFaces[0]) * fontFaces.size()), &fontFaces[0], GL_STATIC_DRAW);
            gl::BindBuffer(GL_ELEMENT_ARRAY_BUFFER, binding);

            _uiStateTracker.ibo = _fontIbo;
            _fontIboCreated = true;
        }
        return _fontIbo;
    }

    const GLuint& getImageVbo()
    {
        if (!_imageVboCreated)
        {
            // create the image vbo
            const float verts[] = {
                /*    Position  */
                -1.f, 1.f, 0.f, 1.0f, 0.0f, 1.0f, // upper left
                -1.f, -1.f, 0.f, 1.0f, 0.f, 0.0f, // lower left
                1.f, 1.f, 0.f, 1.0f, 1.f, 1.f, // upper right
                -1.f, -1.f, 0.f, 1.0f, 0.f, 0.0f, // lower left
                1.f, -1.f, 0.f, 1.0f, 1.f, 0.0f, // lower right
                1.f, 1.f, 0.f, 1.0f, 1.f, 1.f, // upper right
            };
            GLint binding;
            gl::GetIntegerv(GL_ARRAY_BUFFER_BINDING, &binding);
            gl::GenBuffers(1, &_imageVbo);
            gl::BindBuffer(GL_ARRAY_BUFFER, _imageVbo);
            gl::BufferData(GL_ARRAY_BUFFER, static_cast<uint32_t>(sizeof(verts)), static_cast<const void*>(verts), GL_STATIC_DRAW);
            gl::BindBuffer(GL_ARRAY_BUFFER, binding);

            _uiStateTracker.vbo = _imageVbo;
            _imageVboCreated = true;
        }
        return _imageVbo;
    }

    UIRenderer() : _screenRotation(.0f), _program(0), _fontIboCreated(false), _imageVboCreated(false), _samplerBilinear(0), _samplerTrilinear(0), _fontIbo(-1), _imageVbo(-1) {}

    UIRenderer(UIRenderer&& rhs)
        : _program(std::move(rhs._program)), _programData(std::move(rhs._programData)), _defaultFont(std::move(rhs._defaultFont)), _sdkLogo(std::move(rhs._sdkLogo)),
          _defaultTitle(std::move(rhs._defaultTitle)), _defaultDescription(std::move(rhs._defaultDescription)), _defaultControls(std::move(rhs._defaultControls)),
          _samplerBilinear(std::move(rhs._samplerBilinear)), _samplerTrilinear(std::move(rhs._samplerTrilinear)), _fontIbo(std::move(rhs._fontIbo)),
          _imageVbo(std::move(rhs._imageVbo)), _screenDimensions(std::move(rhs._screenDimensions)), _screenRotation(std::move(rhs._screenRotation)),
          _groupId(std::move(rhs._groupId)), _sprites(std::move(rhs._sprites)), _textElements(std::move(rhs._textElements)), _fonts(std::move(rhs._fonts)),
          _fontIboCreated(std::move(rhs._fontIboCreated)), _imageVboCreated(std::move(rhs._imageVboCreated))
    {
        _program = std::move(rhs._program);
        rhs._program = 0;
        updateResourceOwnership();
    }

    UIRenderer& operator=(UIRenderer&& rhs)
    {
        if (this == &rhs) { return *this; }
        _program = std::move(rhs._program);
        rhs._program = 0;
        _programData = std::move(rhs._programData);
        _defaultFont = std::move(rhs._defaultFont);
        _sdkLogo = std::move(rhs._sdkLogo);
        _defaultTitle = std::move(rhs._defaultTitle);
        _defaultDescription = std::move(rhs._defaultDescription);
        _defaultControls = std::move(rhs._defaultControls);
        _samplerBilinear = std::move(rhs._samplerBilinear);
        _samplerTrilinear = std::move(rhs._samplerTrilinear);
        _fontIbo = std::move(rhs._fontIbo);
        _imageVbo = std::move(rhs._imageVbo);
        _screenDimensions = std::move(rhs._screenDimensions);
        _screenRotation = std::move(rhs._screenRotation);
        _groupId = std::move(rhs._groupId);
        _fontIboCreated = std::move(rhs._fontIboCreated);
        _imageVboCreated = std::move(rhs._imageVboCreated);
        updateResourceOwnership();
        return *this;
    }

    UIRenderer& operator=(const UIRenderer& rhs) = delete;
    UIRenderer(UIRenderer& rhs) = delete;

    ~UIRenderer() { release(); }

    const ProgramData& getProgramData() { return _programData; }

    void init(uint32_t width, uint32_t height, bool fullscreen, bool isFrameBufferSRGB);

    void release()
    {
        _defaultFont.reset();
        _defaultTitle.reset();
        _defaultDescription.reset();
        _defaultControls.reset();
        _sdkLogo.reset();

        _sprites.clear();
        _fonts.clear();
        _textElements.clear();

        if (_fontIboCreated && _fontIbo != static_cast<uint32_t>(-1)) { gl::DeleteBuffers(1, &_fontIbo); }
        if (_imageVboCreated && _imageVbo != static_cast<uint32_t>(-1)) { gl::DeleteBuffers(1, &_imageVbo); }
#if !SC_ENABLED
        if (_api != Api::OpenGLES2)
        {
            if (_samplerBilinear) { gl::DeleteSamplers(1, &_samplerBilinear); }
            if (_samplerTrilinear) { gl::DeleteSamplers(1, &_samplerTrilinear); }
        }
#endif

        _screenRotation = .0f;
        _program = 0;
        _fontIboCreated = false;
        _imageVboCreated = false;
        _samplerBilinear = static_cast<GLuint>(0);
        _samplerTrilinear = static_cast<GLuint>(0);
        _fontIbo = static_cast<GLuint>(-1);
        _imageVbo = static_cast<GLuint>(-1);
    }

    TextElement createTextElement(const std::string& text = "") { return createTextElement(text, _defaultFont); }

    TextElement createTextElement(const std::string& text, const Font& font);

    TextElement createTextElement(const Font& font) { return createTextElement(std::string(""), font); }

    TextElement createTextElement(const std::wstring& text) { return createTextElement(text, _defaultFont); }

    TextElement createTextElement(const std::wstring& text, const Font& font);

    Text createText(const TextElement& textElement);

    Text createText(const std::string& text = "") { return createText(createTextElement(text)); }

    Text createText(const std::string& text, const Font& font) { return createText(createTextElement(text, font)); }

    Text createText(const Font& font) { return createText(createTextElement(font)); }

    Text createText(const std::wstring& text) { return createText(createTextElement(text)); }

    Text createText(const std::wstring& text, const Font& font) { return createText(createTextElement(text, font)); }

    float getRenderingDimX() const { return _screenDimensions.x; }

    float getRenderingDimY() const { return _screenDimensions.y; }

    glm::vec2 getRenderingDim() const { return _screenDimensions; }

    Rectanglei getViewport() const { return Rectanglei(0, 0, static_cast<int32_t>(getRenderingDimX()), static_cast<int32_t>(getRenderingDimY())); }

    void setRenderingDimX(float value) { _screenDimensions.x = value; }

    void setRenderingDimY(float value) { _screenDimensions.y = value; }

    Font createFont(GLuint texture, const TextureHeader& textureHeader, GLuint sampler = 0);

    Font createFont(const Texture& texture, GLuint sampler = 0);

    Image createImage(GLuint texture, int32_t width, int32_t height, bool useMipmaps, GLuint sampler = 0);

    Image createImage(const Texture& texture, GLuint sampler = 0);

    Image createImageFromAtlas(GLuint texture, const Rectanglef& uv, uint32_t width, uint32_t height, bool useMipmaps = false, GLuint sampler = 0);

    MatrixGroup createMatrixGroup();

    PixelGroup createPixelGroup();

    void beginRendering()
    {
        storeCurrentGlState();
        checkStateChanged();
        setUiState();
    }

    void beginRendering(const GLStateTracker& stateTracker)
    {
        checkStateChanged(stateTracker);
        setUiState();
    }

    void endRendering()
    {
        checkStateChanged();
        restoreState();
    }

    void endRendering(GLStateTracker& stateTracker) { stateTracker = _uiStateTracker; }

    const Font& getDefaultFont() const { return _defaultFont; }

    Font& getDefaultFont() { return _defaultFont; }

    const Image& getSdkLogo() const { return _sdkLogo; }

    Image& getSdkLogo() { return _sdkLogo; }

    const Text& getDefaultTitle() const { return _defaultTitle; }

    Text& getDefaultTitle() { return _defaultTitle; }

    const Text& getDefaultDescription() const { return _defaultDescription; }

    Text& getDefaultDescription() { return _defaultDescription; }

    const Text& getDefaultControls() const { return _defaultControls; }

    Text& getDefaultControls() { return _defaultControls; }

    glm::mat4 getProjection() const { return pvr::math::ortho(Api::OpenGLES2, 0.0, getRenderingDimX(), 0.0f, getRenderingDimY()); }

    void rotateScreen90degreeCCW()
    {
        _screenRotation += glm::pi<float>() * .5f;
        std::swap(_screenDimensions.x, _screenDimensions.y);
    }

    void rotateScreen90degreeCW()
    {
        _screenRotation -= glm::pi<float>() * .5f;
        std::swap(_screenDimensions.x, _screenDimensions.y);
    }

    glm::mat4 getScreenRotation() const { return glm::rotate(_screenRotation, glm::vec3(0.0f, 0.0f, 1.f)); }

    GLStateTracker getStateTracker() const { return _uiStateTracker; }

    Api getApiVersion() { return _api; }

private:
    void storeCurrentGlState();
    void setUiState();
    void checkStateChanged();
    void checkStateChanged(const GLStateTracker& stateTracker);
    void restoreState();

    void updateResourceOwnership()
    {
        std::for_each(_sprites.begin(), _sprites.end(), [this](SpriteWeakRef& sprite) { sprite.lock()->setUIRenderer(this); });

        std::for_each(_fonts.begin(), _fonts.end(), [this](FontWeakRef& font) { font.lock()->setUIRenderer(this); });

        std::for_each(_textElements.begin(), _textElements.end(), [this](TextElementWeakRef& textElement) { textElement.lock()->setUIRenderer(this); });
    }

    friend class ::pvr::ui::impl::Image_;
    friend class ::pvr::ui::impl::Text_;
    friend class ::pvr::ui::impl::Group_;
    friend class ::pvr::ui::impl::Sprite_;
    friend class ::pvr::ui::impl::Font_;
    friend class ::pvr::ui::impl::TextElement_;
    friend class ::pvr::ui::impl::MatrixGroup_;

    uint64_t generateGroupId() { return _groupId++; }

    GLuint getSamplerBilinear() const { return _samplerBilinear; }

    GLuint getSamplerTrilinear() const { return _samplerTrilinear; }

    void init_CreateDefaultFont();
    void init_CreateDefaultSampler();
    void init_CreateDefaultSdkLogo();
    void init_CreateDefaultTitle();
    void init_CreateShaders(bool framebufferSRGB);

    std::vector<SpriteWeakRef> _sprites;
    std::vector<TextElementWeakRef> _textElements;
    std::vector<FontWeakRef> _fonts;

    ProgramData _programData;
    Font _defaultFont;
    Image _sdkLogo;
    Text _defaultTitle;
    Text _defaultDescription;
    Text _defaultControls;
    GLuint _program;

    GLuint _samplerBilinear;
    GLuint _samplerTrilinear;
    GLuint _fontIbo;
    bool _fontIboCreated;
    GLuint _imageVbo;
    bool _imageVboCreated;
    glm::vec2 _screenDimensions;
    float _screenRotation;
    uint64_t _groupId = 1;

    GLStateTracker _uiStateTracker;
    GLState _currentState;

    Api _api;
};
} // namespace ui
} // namespace pvr