Add opengl canvas implementation.
Adds opengl canvas implementation - display-list-based, all rendering done as textured geometry. Needs shader support. Currently compiles and works on Linux, Mac should be ~easy to add, win32 eventually. Change-Id: Ibf3eb88d6a36a91b2960a3a6320d708160e4fc14
This commit is contained in:
261
canvas/source/opengl/ogl_canvascustomsprite.cxx
Normal file
261
canvas/source/opengl/ogl_canvascustomsprite.cxx
Normal file
@@ -0,0 +1,261 @@
|
||||
/* -*- 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 "ogl_canvascustomsprite.hxx"
|
||||
#include "ogl_canvastools.hxx"
|
||||
#include "ogl_tools.hxx"
|
||||
|
||||
#include <canvas/debug.hxx>
|
||||
#include <canvas/verbosetrace.hxx>
|
||||
#include <canvas/verifyinput.hxx>
|
||||
#include <tools/diagnose_ex.h>
|
||||
|
||||
#include <canvas/canvastools.hxx>
|
||||
|
||||
#include <basegfx/matrix/b2dhommatrix.hxx>
|
||||
#include <basegfx/point/b2dpoint.hxx>
|
||||
#include <basegfx/tools/canvastools.hxx>
|
||||
#include <basegfx/polygon/b2dpolygonclipper.hxx>
|
||||
#include <basegfx/polygon/b2dpolygontriangulator.hxx>
|
||||
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
|
||||
using namespace ::com::sun::star;
|
||||
|
||||
namespace oglcanvas
|
||||
{
|
||||
CanvasCustomSprite::CanvasCustomSprite( const ::com::sun::star::geometry::RealSize2D& rSpriteSize,
|
||||
const SpriteCanvasRef& rRefDevice,
|
||||
SpriteDeviceHelper& rDeviceHelper ) :
|
||||
mpSpriteCanvas( rRefDevice ),
|
||||
maSize(rSpriteSize),
|
||||
mxClip(),
|
||||
maTransformation(),
|
||||
maPosition(),
|
||||
mfAlpha(0.0),
|
||||
mfPriority(0.0)
|
||||
{
|
||||
ENSURE_OR_THROW( rRefDevice.get(),
|
||||
"CanvasCustomSprite::CanvasCustomSprite(): Invalid sprite canvas" );
|
||||
|
||||
::canvas::tools::setIdentityAffineMatrix2D(maTransformation);
|
||||
maCanvasHelper.init( *rRefDevice.get(),
|
||||
rDeviceHelper );
|
||||
}
|
||||
|
||||
void SAL_CALL CanvasCustomSprite::disposeThis()
|
||||
{
|
||||
::osl::MutexGuard aGuard( m_aMutex );
|
||||
|
||||
mpSpriteCanvas.clear();
|
||||
|
||||
// forward to parent
|
||||
CanvasCustomSpriteBaseT::disposeThis();
|
||||
}
|
||||
|
||||
void SAL_CALL CanvasCustomSprite::setAlpha( double alpha ) throw (lang::IllegalArgumentException,
|
||||
uno::RuntimeException)
|
||||
{
|
||||
canvas::tools::verifyRange( alpha, 0.0, 1.0 );
|
||||
|
||||
::osl::MutexGuard aGuard( m_aMutex );
|
||||
mfAlpha = alpha;
|
||||
}
|
||||
|
||||
void SAL_CALL CanvasCustomSprite::move( const geometry::RealPoint2D& aNewPos,
|
||||
const rendering::ViewState& viewState,
|
||||
const rendering::RenderState& renderState ) throw (lang::IllegalArgumentException,
|
||||
uno::RuntimeException)
|
||||
{
|
||||
canvas::tools::verifyArgs(aNewPos, viewState, renderState,
|
||||
BOOST_CURRENT_FUNCTION,
|
||||
static_cast< ::cppu::OWeakObject* >(this));
|
||||
|
||||
::osl::MutexGuard aGuard( m_aMutex );
|
||||
::basegfx::B2DHomMatrix aTransform;
|
||||
::canvas::tools::mergeViewAndRenderTransform(aTransform,
|
||||
viewState,
|
||||
renderState);
|
||||
|
||||
// convert position to device pixel
|
||||
maPosition = ::basegfx::unotools::b2DPointFromRealPoint2D(aNewPos);
|
||||
maPosition *= aTransform;
|
||||
}
|
||||
|
||||
void SAL_CALL CanvasCustomSprite::transform( const geometry::AffineMatrix2D& aTransformation ) throw (lang::IllegalArgumentException,
|
||||
uno::RuntimeException)
|
||||
{
|
||||
::osl::MutexGuard aGuard( m_aMutex );
|
||||
maTransformation = aTransformation;
|
||||
}
|
||||
|
||||
void SAL_CALL CanvasCustomSprite::clip( const uno::Reference< rendering::XPolyPolygon2D >& xClip ) throw (uno::RuntimeException)
|
||||
{
|
||||
mxClip = xClip;
|
||||
}
|
||||
|
||||
void SAL_CALL CanvasCustomSprite::setPriority( double nPriority ) throw (uno::RuntimeException)
|
||||
{
|
||||
::osl::MutexGuard aGuard( m_aMutex );
|
||||
mfPriority = nPriority;
|
||||
}
|
||||
|
||||
void SAL_CALL CanvasCustomSprite::show() throw (uno::RuntimeException)
|
||||
{
|
||||
::osl::MutexGuard aGuard( m_aMutex );
|
||||
if( mpSpriteCanvas.is() )
|
||||
mpSpriteCanvas->show(this);
|
||||
}
|
||||
|
||||
void SAL_CALL CanvasCustomSprite::hide() throw (uno::RuntimeException)
|
||||
{
|
||||
::osl::MutexGuard aGuard( m_aMutex );
|
||||
if( mpSpriteCanvas.is() )
|
||||
mpSpriteCanvas->hide(this);
|
||||
}
|
||||
|
||||
uno::Reference< rendering::XCanvas > SAL_CALL CanvasCustomSprite::getContentCanvas() throw (uno::RuntimeException)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
bool CanvasCustomSprite::renderSprite() const
|
||||
{
|
||||
if( ::basegfx::fTools::equalZero( mfAlpha ) )
|
||||
return true;
|
||||
|
||||
TransformationPreserver aPreserver1;
|
||||
const ::basegfx::B2IVector aSpriteSizePixel(
|
||||
::canvas::tools::roundUp( maSize.Width ),
|
||||
::canvas::tools::roundUp( maSize.Height ));
|
||||
|
||||
// translate sprite to output position
|
||||
glTranslated(maPosition.getX(), maPosition.getY(), 0);
|
||||
|
||||
{
|
||||
TransformationPreserver aPreserver2;
|
||||
|
||||
// apply sprite content transformation matrix
|
||||
double aGLTransform[] =
|
||||
{
|
||||
maTransformation.m00, maTransformation.m10, 0, 0,
|
||||
maTransformation.m01, maTransformation.m11, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
maTransformation.m02, maTransformation.m12, 0, 1
|
||||
};
|
||||
glMultMatrixd(aGLTransform);
|
||||
|
||||
IBufferContextSharedPtr pBufferContext;
|
||||
if( mfAlpha != 1.0 || mxClip.is() )
|
||||
{
|
||||
// drats. need to render to temp surface before, and then
|
||||
// composite that to screen
|
||||
|
||||
// TODO(P3): buffer pbuffer, maybe even keep content
|
||||
// (in a texture?)
|
||||
pBufferContext=maCanvasHelper.getDeviceHelper()->createBufferContext(aSpriteSizePixel);
|
||||
pBufferContext->startBufferRendering();
|
||||
}
|
||||
|
||||
// this ends up in pBufferContext, if that one's "current"
|
||||
if( !maCanvasHelper.renderRecordedActions() )
|
||||
return false;
|
||||
|
||||
if( pBufferContext )
|
||||
{
|
||||
// content ended up in background buffer - compose to
|
||||
// screen now. Calls below switches us back to window
|
||||
// context, and binds to generated, dynamic texture
|
||||
pBufferContext->endBufferRendering();
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D,
|
||||
GL_TEXTURE_MIN_FILTER,
|
||||
GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D,
|
||||
GL_TEXTURE_MAG_FILTER,
|
||||
GL_NEAREST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,
|
||||
GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// blend against fixed vertex color; texture alpha is multiplied in
|
||||
glColor4f(1,1,1,mfAlpha);
|
||||
|
||||
if( mxClip.is() )
|
||||
{
|
||||
const double fWidth=maSize.Width;
|
||||
const double fHeight=maSize.Height;
|
||||
|
||||
// TODO(P3): buffer triangulation
|
||||
const ::basegfx::B2DPolygon& rTriangulatedPolygon(
|
||||
::basegfx::triangulator::triangulate(
|
||||
::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(mxClip)));
|
||||
|
||||
basegfx::B2DPolygon rTriangleList(
|
||||
basegfx::tools::clipTriangleListOnRange(
|
||||
rTriangulatedPolygon,
|
||||
basegfx::B2DRange(
|
||||
0,0,
|
||||
aSpriteSizePixel.getX(),
|
||||
aSpriteSizePixel.getY())));
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
for( sal_uInt32 i=0; i<rTriangulatedPolygon.count(); i++ )
|
||||
{
|
||||
const ::basegfx::B2DPoint& rPt( rTriangulatedPolygon.getB2DPoint(i) );
|
||||
const double s(rPt.getX()/fWidth);
|
||||
const double t(rPt.getY()/fHeight);
|
||||
glTexCoord2f(s,t); glVertex2d(rPt.getX(), rPt.getY());
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
const double fWidth=maSize.Width/aSpriteSizePixel.getX();
|
||||
const double fHeight=maSize.Height/aSpriteSizePixel.getY();
|
||||
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
glTexCoord2f(0,0); glVertex2d(0,0);
|
||||
glTexCoord2f(0,fHeight); glVertex2d(0, aSpriteSizePixel.getY());
|
||||
glTexCoord2f(fWidth,0); glVertex2d(aSpriteSizePixel.getX(),0);
|
||||
glTexCoord2f(fWidth,fHeight); glVertex2d(aSpriteSizePixel.getX(),aSpriteSizePixel.getY());
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
}
|
||||
|
||||
glColor4f(1,0,0,1);
|
||||
glBegin(GL_LINE_STRIP);
|
||||
glVertex2d(-2,-2);
|
||||
glVertex2d(-2,maSize.Height+4);
|
||||
glVertex2d(maSize.Width+4,maSize.Height+4);
|
||||
glVertex2d(maSize.Width+4,-2);
|
||||
glVertex2d(-2,-2);
|
||||
glVertex2d(maSize.Width+4,maSize.Height+4);
|
||||
glEnd();
|
||||
|
||||
std::vector<double> aVec;
|
||||
aVec.push_back(mfAlpha);
|
||||
aVec.push_back(mfPriority);
|
||||
aVec.push_back(maCanvasHelper.getRecordedActionCount());
|
||||
renderOSD( aVec, 10 );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
Reference in New Issue
Block a user