Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ogl_spritedevicehelper.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include <sal/config.h>
#include <sal/log.hxx>

#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/utils/canvastools.hxx>
#include <basegfx/utils/unopolypolygon.hxx>
#include <com/sun/star/awt/XTopWindow.hpp>
#include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
#include <com/sun/star/uno/Reference.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <vcl/canvastools.hxx>
#include <vcl/opengl/OpenGLHelper.hxx>
#include <vcl/syschild.hxx>

#include "ogl_spritedevicehelper.hxx"
#include "ogl_spritecanvas.hxx"
#include "ogl_canvasbitmap.hxx"
#include "ogl_canvastools.hxx"
#include "ogl_canvascustomsprite.hxx"
#include "ogl_texturecache.hxx"

using namespace ::com::sun::star;

static void initContext()
{
    // need the backside for mirror effects
    glDisable(GL_CULL_FACE);

    // no perspective, we're 2D
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // misc preferences
    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_POLYGON_SMOOTH);
    glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
    glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
    glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
    glShadeModel(GL_FLAT);
}

static void initTransformation(const ::Size& rSize)
{
    // use whole window
    glViewport( 0,0,
                static_cast<GLsizei>(rSize.Width()),
                static_cast<GLsizei>(rSize.Height()) );

    // model coordinate system is already in device pixel
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslated(-1.0, 1.0, 0.0);
    glScaled( 2.0  / rSize.Width(),
              -2.0 / rSize.Height(),
              1.0 );

    // clear to black
    glClearColor(0,0,0,0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

namespace oglcanvas
{

    SpriteDeviceHelper::SpriteDeviceHelper() :
        mpSpriteCanvas(nullptr),
        mpTextureCache(std::make_shared<TextureCache>()),
        mnLinearTwoColorGradientProgram(0),
        mnLinearMultiColorGradientProgram(0),
        mnRadialTwoColorGradientProgram(0),
        mnRadialMultiColorGradientProgram(0),
        mnRectangularTwoColorGradientProgram(0),
        mnRectangularMultiColorGradientProgram(0),
        mxContext(OpenGLContext::Create())
    {}

    SpriteDeviceHelper::~SpriteDeviceHelper()
    { mxContext->dispose(); }

    void SpriteDeviceHelper::init( vcl::Window&               rWindow,
                                   SpriteCanvas&         rSpriteCanvas,
                                   const awt::Rectangle& rViewArea )
    {
        mpSpriteCanvas = &rSpriteCanvas;

        rSpriteCanvas.setWindow(
            uno::Reference<awt::XWindow2>(
                VCLUnoHelper::GetInterface(&rWindow),
                uno::UNO_QUERY_THROW) );

        mxContext->requestLegacyContext();
        mxContext->init(&rWindow);
        // init window context
        initContext();

        mnLinearMultiColorGradientProgram =
            OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"linearMultiColorGradientFragmentShader"_ustr);

        mnLinearTwoColorGradientProgram =
            OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"linearTwoColorGradientFragmentShader"_ustr);

        mnRadialMultiColorGradientProgram =
            OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"radialMultiColorGradientFragmentShader"_ustr);

        mnRadialTwoColorGradientProgram =
            OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"radialTwoColorGradientFragmentShader"_ustr);

        mnRectangularMultiColorGradientProgram =
            OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"rectangularMultiColorGradientFragmentShader"_ustr);

        mnRectangularTwoColorGradientProgram =
            OpenGLHelper::LoadShaders(u"dummyVertexShader"_ustr, u"rectangularTwoColorGradientFragmentShader"_ustr);

        mxContext->makeCurrent();

        notifySizeUpdate(rViewArea);
        // TODO(E3): check for GL_ARB_imaging extension
    }

    void SpriteDeviceHelper::disposing()
    {
        // release all references
        mpSpriteCanvas = nullptr;
        mpTextureCache.reset();

        if( mxContext->isInitialized() )
        {
            glDeleteProgram( mnRectangularTwoColorGradientProgram );
            glDeleteProgram( mnRectangularMultiColorGradientProgram );
            glDeleteProgram( mnRadialTwoColorGradientProgram );
            glDeleteProgram( mnRadialMultiColorGradientProgram );
            glDeleteProgram( mnLinearTwoColorGradientProgram );
            glDeleteProgram( mnLinearMultiColorGradientProgram );
        }
    }

    geometry::RealSize2D SpriteDeviceHelper::getPhysicalResolution()
    {
        if( !mxContext->isInitialized() )
            return ::canvas::tools::createInfiniteSize2D(); // we're disposed

        // Map a one-by-one millimeter box to pixel
        SystemChildWindow* pChildWindow = mxContext->getChildWindow();
        const MapMode aOldMapMode( pChildWindow->GetMapMode() );
        pChildWindow->SetMapMode( MapMode(MapUnit::MapMM) );
        const Size aPixelSize( pChildWindow->LogicToPixel(Size(1,1)) );
        pChildWindow->SetMapMode( aOldMapMode );

        return vcl::unotools::size2DFromSize( aPixelSize );
    }

    geometry::RealSize2D SpriteDeviceHelper::getPhysicalSize()
    {
        if( !mxContext->isInitialized() )
            return ::canvas::tools::createInfiniteSize2D(); // we're disposed

        // Map the pixel dimensions of the output window to millimeter
        SystemChildWindow* pChildWindow = mxContext->getChildWindow();
        const MapMode aOldMapMode( pChildWindow->GetMapMode() );
        pChildWindow->SetMapMode( MapMode(MapUnit::MapMM) );
        const Size aLogSize( pChildWindow->PixelToLogic(pChildWindow->GetOutputSizePixel()) );
        pChildWindow->SetMapMode( aOldMapMode );

        return vcl::unotools::size2DFromSize( aLogSize );
    }

    uno::Reference< rendering::XLinePolyPolygon2D > SpriteDeviceHelper::createCompatibleLinePolyPolygon(
        const uno::Reference< rendering::XGraphicDevice >&              /*rDevice*/,
        const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >&  points )
    {
        // disposed?
        if( !mpSpriteCanvas )
            return uno::Reference< rendering::XLinePolyPolygon2D >(); // we're disposed

        return uno::Reference< rendering::XLinePolyPolygon2D >(
            new ::basegfx::unotools::UnoPolyPolygon(
                ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( points )));
    }

    uno::Reference< rendering::XBezierPolyPolygon2D > SpriteDeviceHelper::createCompatibleBezierPolyPolygon(
        const uno::Reference< rendering::XGraphicDevice >&                      /*rDevice*/,
        const uno::Sequence< uno::Sequence< geometry::RealBezierSegment2D > >&  points )
    {
        // disposed?
        if( !mpSpriteCanvas )
            return uno::Reference< rendering::XBezierPolyPolygon2D >(); // we're disposed

        return uno::Reference< rendering::XBezierPolyPolygon2D >(
            new ::basegfx::unotools::UnoPolyPolygon(
                ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( points ) ) );
    }

    uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleBitmap(
        const uno::Reference< rendering::XGraphicDevice >&  /*rDevice*/,
        const geometry::IntegerSize2D&                      size )
    {
        // disposed?
        if( !mpSpriteCanvas )
            return uno::Reference< rendering::XBitmap >(); // we're disposed

        return uno::Reference< rendering::XBitmap >(
            new CanvasBitmap( size,
                              mpSpriteCanvas,
                              *this ) );
    }

    uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileBitmap(
        const uno::Reference< rendering::XGraphicDevice >&  /*rDevice*/,
        const geometry::IntegerSize2D&                      /*size*/ )
    {
        return uno::Reference< rendering::XVolatileBitmap >();
    }

    uno::Reference< rendering::XBitmap > SpriteDeviceHelper::createCompatibleAlphaBitmap(
        const uno::Reference< rendering::XGraphicDevice >&  /*rDevice*/,
        const geometry::IntegerSize2D&                      size )
    {
        // disposed?
        if( !mpSpriteCanvas )
            return uno::Reference< rendering::XBitmap >(); // we're disposed

        return uno::Reference< rendering::XBitmap >(
            new CanvasBitmap( size,
                              mpSpriteCanvas,
                              *this ) );
    }

    uno::Reference< rendering::XVolatileBitmap > SpriteDeviceHelper::createVolatileAlphaBitmap(
        const uno::Reference< rendering::XGraphicDevice >&  /*rDevice*/,
        const geometry::IntegerSize2D&                      /*size*/ )
    {
        return uno::Reference< rendering::XVolatileBitmap >();
    }

    namespace
    {
        /** Functor providing a StrictWeakOrdering for XSprites (over
            priority)
         */

        struct SpriteComparator
        {
            bool operator()( const ::rtl::Reference<CanvasCustomSprite>& rLHS,
                             const ::rtl::Reference<CanvasCustomSprite>& rRHS ) const
            {
                const double nPrioL( rLHS->getPriority() );
                const double nPrioR( rRHS->getPriority() );

                // if prios are equal, tie-break on ptr value
                return nPrioL == nPrioR ? rLHS.get() < rRHS.get() : nPrioL < nPrioR;
            }
        };
    }

    bool SpriteDeviceHelper::showBuffer( bool bIsVisible, SAL_UNUSED_PARAMETER bool /*bUpdateAll*/ )
    {
        // hidden or disposed?
        if( !bIsVisible || !mxContext->isInitialized() || !mpSpriteCanvas )
            return false;

        mxContext->makeCurrent();

        SystemChildWindow* pChildWindow = mxContext->getChildWindow();
        const ::Size aOutputSize = pChildWindow->GetSizePixel();
        initTransformation(aOutputSize);

        // render the actual spritecanvas content
        mpSpriteCanvas->renderRecordedActions();

        // render all sprites (in order of priority) on top of that
        std::vector< ::rtl::Reference<CanvasCustomSprite> > aSprites(
                    maActiveSprites.begin(),
                    maActiveSprites.end());
        std::sort(aSprites.begin(),
                  aSprites.end(),
                  SpriteComparator());
        forconst auto& rSprite : aSprites )
            rSprite->renderSprite();


        // frame counter, other info
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslated(-1.0, 1.0, 0.0);
        glScaled( 2.0  / aOutputSize.Width(),
                  -2.0 / aOutputSize.Height(),
                  1.0 );

        const double denominator( maLastUpdate.getElapsedTime() );
        maLastUpdate.reset();

        const double fps(denominator == 0.0 ? 100.0 : 1.0/denominator);
        std::vector<double> aVec { fps, static_cast<double>(maActiveSprites.size()),
                                        static_cast<double>(mpTextureCache->getCacheSize()),
                                        static_cast<double>(mpTextureCache->getCacheMissCount()),
                                        static_cast<double>(mpTextureCache->getCacheHitCount()) };
        renderOSD( aVec, 20 );

        /*
         * TODO: moggi: fix it!
        // switch buffer, sync etc.
        const unx::Window aXWindow=pChildWindow->GetSystemData()->aWindow;
        unx::glXSwapBuffers(reinterpret_cast<unx::Display*>(mpDisplay),
                            aXWindow);
        pChildWindow->Show();
        unx::glXWaitGL();
        XSync( reinterpret_cast<unx::Display*>(mpDisplay), false );
        */

        mxContext->swapBuffers();

        // flush texture cache, such that it does not build up
        // indefinitely.
        // TODO: have max cache size/LRU time in config, prune only on
        // demand
        mpTextureCache->prune();

        return true;
    }

    bool SpriteDeviceHelper::switchBuffer( bool bIsVisible, bool bUpdateAll )
    {
        // no difference for VCL canvas
        return showBuffer( bIsVisible, bUpdateAll );
    }

    uno::Any SpriteDeviceHelper::isAccelerated() const
    {
        return css::uno::Any(false);
    }

    uno::Any SpriteDeviceHelper::getDeviceHandle() const
    {
        const SystemChildWindow* pChildWindow = mxContext->getChildWindow();
        const OutputDevice* pDevice = pChildWindow ? pChildWindow->GetOutDev() : nullptr;
        return uno::Any(reinterpret_cast<sal_Int64>(pDevice));
    }

    uno::Any SpriteDeviceHelper::getSurfaceHandle() const
    {
        return uno::Any();
    }

    uno::Reference<rendering::XColorSpace> SpriteDeviceHelper::getColorSpace() const
    {
        // always the same
        return ::canvas::tools::getStdColorSpace();
    }

    void SpriteDeviceHelper::notifySizeUpdate( const awt::Rectangle& rBounds )
    {
        if( mxContext->isInitialized() )
        {
            SystemChildWindow* pChildWindow = mxContext->getChildWindow();
            pChildWindow->setPosSizePixel(
                0,0,rBounds.Width,rBounds.Height);
        }
    }

    void SpriteDeviceHelper::dumpScreenContent() const
    {
        SAL_INFO("canvas.ogl", __func__ );
    }

    void SpriteDeviceHelper::show( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
    {
        maActiveSprites.insert(xSprite);
    }

    void SpriteDeviceHelper::hide( const ::rtl::Reference< CanvasCustomSprite >& xSprite )
    {
        maActiveSprites.erase(xSprite);
    }

    static void setupUniforms( unsigned int                                 nProgramId,
                               const ::basegfx::B2DHomMatrix&               rTexTransform )
    {
        const GLint nTransformLocation = glGetUniformLocation(nProgramId,
                                                             "m_transform" );
        // OGL is column-major
        float aTexTransform[] =
            {
                float(rTexTransform.get(0,0)), float(rTexTransform.get(1,0)),
                float(rTexTransform.get(0,1)), float(rTexTransform.get(1,1)),
                float(rTexTransform.get(0,2)), float(rTexTransform.get(1,2))
            };
        glUniformMatrix3x2fv(nTransformLocation,1,false,aTexTransform);
    }

    static void setupUniforms( unsigned int                   nProgramId,
                               const rendering::ARGBColor*    pColors,
                               const uno::Sequence< double >& rStops,
                               const ::basegfx::B2DHomMatrix& rTexTransform )
    {
        glUseProgram(nProgramId);

        GLuint nColorsTexture;
        glActiveTexture(GL_TEXTURE0);
        glGenTextures(1, &nColorsTexture);
        glBindTexture(GL_TEXTURE_1D, nColorsTexture);

        const sal_Int32 nColors=rStops.getLength();
        glTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, nColors, 0, GL_RGBA, GL_DOUBLE, pColors );
        glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
        glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

        GLuint nStopsTexture;
        glActiveTexture(GL_TEXTURE1);
        glGenTextures(1, &nStopsTexture);
        glBindTexture(GL_TEXTURE_1D, nStopsTexture);

        glTexImage1D( GL_TEXTURE_1D, 0, GL_ALPHA, nColors, 0, GL_ALPHA, GL_DOUBLE, rStops.getConstArray() );
        glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
        glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );

        const GLint nColorArrayLocation = glGetUniformLocation(nProgramId,
                                                               "t_colorArray4d" );
        glUniform1i( nColorArrayLocation, 0 ); // unit 0

        const GLint nStopArrayLocation = glGetUniformLocation(nProgramId,
                                                              "t_stopArray1d" );
        glUniform1i( nStopArrayLocation, 1 ); // unit 1

        const GLint nNumColorLocation = glGetUniformLocation(nProgramId,
                                                             "i_nColors" );
        glUniform1i( nNumColorLocation, nColors-1 );

        setupUniforms(nProgramId,rTexTransform);
    }

    static void setupUniforms( unsigned int                   nProgramId,
                               const rendering::ARGBColor&    rStartColor,
                               const rendering::ARGBColor&    rEndColor,
                               const ::basegfx::B2DHomMatrix& rTexTransform )
    {
        glUseProgram(nProgramId);

        const GLint nStartColorLocation = glGetUniformLocation(nProgramId,
                                                               "v_startColor4d" );
        glUniform4f(nStartColorLocation,
                    rStartColor.Red,
                    rStartColor.Green,
                    rStartColor.Blue,
                    rStartColor.Alpha);

        const GLint nEndColorLocation = glGetUniformLocation(nProgramId,
                                                             "v_endColor4d" );
        glUniform4f(nEndColorLocation,
                    rEndColor.Red,
                    rEndColor.Green,
                    rEndColor.Blue,
                    rEndColor.Alpha);

        setupUniforms(nProgramId,rTexTransform);
    }

    void SpriteDeviceHelper::useLinearGradientShader( const rendering::ARGBColor*    pColors,
                                                      const uno::Sequence< double >& rStops,
                                                      const ::basegfx::B2DHomMatrix& rTexTransform )
    {
        if( rStops.getLength() > 2 )
            setupUniforms(mnLinearMultiColorGradientProgram, pColors, rStops, rTexTransform);
        else
            setupUniforms(mnLinearTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
    }

    void SpriteDeviceHelper::useRadialGradientShader( const rendering::ARGBColor*    pColors,
                                                      const uno::Sequence< double >& rStops,
                                                      const ::basegfx::B2DHomMatrix& rTexTransform )
    {
        if( rStops.getLength() > 2 )
            setupUniforms(mnRadialMultiColorGradientProgram, pColors, rStops, rTexTransform);
        else
            setupUniforms(mnRadialTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
    }

    void SpriteDeviceHelper::useRectangularGradientShader( const rendering::ARGBColor*    pColors,
                                                           const uno::Sequence< double >& rStops,
                                                           const ::basegfx::B2DHomMatrix& rTexTransform )
    {
        if( rStops.getLength() > 2 )
            setupUniforms(mnRectangularMultiColorGradientProgram, pColors, rStops, rTexTransform);
        else
            setupUniforms(mnRectangularTwoColorGradientProgram, pColors[0], pColors[1], rTexTransform);
    }

    namespace
    {

        class BufferContextImpl : public IBufferContext
        {
            GLuint mnFramebufferId;
            GLuint mnDepthId;
            GLuint mnTextureId;

            virtual void startBufferRendering() override
            {
                glBindFramebuffer(GL_FRAMEBUFFER, mnFramebufferId);
            }

            virtual void endBufferRendering() override
            {
                glBindFramebuffer(GL_FRAMEBUFFER, 0);
            }

            virtual GLuint getTextureId() override
            {
                return mnTextureId;
            }

        public:
            explicit BufferContextImpl(const ::basegfx::B2IVector& rSize) :
                mnFramebufferId(0),
                mnDepthId(0),
                mnTextureId(0)
            {
                OpenGLHelper::createFramebuffer(rSize.getX(), rSize.getY(), mnFramebufferId,
                        mnDepthId, mnTextureId);
            }

            virtual ~BufferContextImpl() override
            {
                glDeleteTextures(1, &mnTextureId);
                glDeleteRenderbuffers(1, &mnDepthId);
                glDeleteFramebuffers(1, &mnFramebufferId);
            }
        };
    }

    IBufferContextSharedPtr SpriteDeviceHelper::createBufferContext(const ::basegfx::B2IVector& rSize) const
    {
        return std::make_shared<BufferContextImpl>(rSize);
    }

    TextureCache& SpriteDeviceHelper::getTextureCache() const
    {
        return *mpTextureCache;
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge