Canvas: basic support for rectangular clipping (like CSS clip property)

This commit is contained in:
Thomas Geymayer 2012-12-07 18:36:37 +01:00
parent 4dfe36cdc1
commit fd27e7bd43
5 changed files with 116 additions and 2 deletions

View File

@ -335,6 +335,18 @@ namespace canvas
_texture.setViewSize(_view_width, _view_height);
}
//----------------------------------------------------------------------------
int Canvas::getViewWidth() const
{
return _view_width;
}
//----------------------------------------------------------------------------
int Canvas::getViewHeight() const
{
return _view_height;
}
//----------------------------------------------------------------------------
bool Canvas::handleMouseEvent(const MouseEventPtr& event)
{

View File

@ -114,6 +114,9 @@ namespace canvas
void setViewWidth(int w);
void setViewHeight(int h);
int getViewWidth() const;
int getViewHeight() const;
bool handleMouseEvent(const MouseEventPtr& event);
virtual void childAdded( SGPropertyNode * parent,

View File

@ -24,9 +24,13 @@
#include <osg/Drawable>
#include <osg/Geode>
#include <osg/Scissor>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include <boost/tokenizer.hpp>
#include <cassert>
#include <cstring>
@ -303,6 +307,71 @@ namespace canvas
return true;
}
//----------------------------------------------------------------------------
void Element::setClip(const std::string& clip)
{
if( clip.empty() || clip == "auto" )
{
getOrCreateStateSet()->removeAttribute(osg::StateAttribute::SCISSOR);
return;
}
// TODO generalize CSS property parsing
const std::string RECT("rect(");
if( !boost::ends_with(clip, ")")
|| !boost::starts_with(clip, RECT) )
{
SG_LOG(SG_GENERAL, SG_WARN, "Canvas: invalid clip: " << clip);
return;
}
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
const boost::char_separator<char> del(", \t\npx");
tokenizer tokens(clip.begin() + RECT.size(), clip.end() - 1, del);
int comp = 0;
int values[4];
for( tokenizer::const_iterator tok = tokens.begin();
tok != tokens.end() && comp < 4;
++tok, ++comp )
{
values[comp] = boost::lexical_cast<int>(*tok);
}
if( comp < 4 )
{
SG_LOG(SG_GENERAL, SG_WARN, "Canvas: invalid clip: " << clip);
return;
}
float scale_x = 1,
scale_y = 1;
CanvasPtr canvas = _canvas.lock();
if( canvas )
{
// The scissor rectangle isn't affected by any transformation, so we need
// to convert to image/canvas coordinates on our selves.
scale_x = canvas->getSizeX()
/ static_cast<float>(canvas->getViewWidth());
scale_y = canvas->getSizeY()
/ static_cast<float>(canvas->getViewHeight());
}
osg::Scissor* scissor = new osg::Scissor();
// <top>, <right>, <bottom>, <left>
scissor->x() = scale_x * values[3];
scissor->y() = scale_y * values[0];
scissor->width() = scale_x * (values[1] - values[3]);
scissor->height() = scale_y * (values[2] - values[0]);
if( canvas )
// Canvas has y axis upside down
scissor->y() = canvas->getSizeY() - scissor->y() - scissor->height();
getOrCreateStateSet()->setAttributeAndModes(scissor);
}
//----------------------------------------------------------------------------
void Element::setBoundingBox(const osg::BoundingBox& bb)
{
@ -347,6 +416,8 @@ namespace canvas
SG_DEBUG,
"New canvas element " << node->getPath()
);
addStyle("clip", &Element::setClip, this);
}
//----------------------------------------------------------------------------
@ -360,6 +431,13 @@ namespace canvas
_transform->addChild(geode);
}
//----------------------------------------------------------------------------
osg::StateSet* Element::getOrCreateStateSet()
{
return _drawable ? _drawable->getOrCreateStateSet()
: _transform->getOrCreateStateSet();
}
//----------------------------------------------------------------------------
void Element::setupStyle()
{

View File

@ -92,6 +92,14 @@ namespace canvas
virtual bool setStyle(const SGPropertyNode* child);
/**
* Set clipping shape
*
* @note Only "rect(<top>, <right>, <bottom>, <left>)" is supported
* @see http://www.w3.org/TR/CSS21/visufx.html#propdef-clip
*/
void setClip(const std::string& clip);
/**
* Write the given bounding box to the property tree
*/
@ -182,6 +190,11 @@ namespace canvas
void setDrawable(osg::Drawable* drawable);
/**
* Get stateset of drawable if available or use transform otherwise
*/
osg::StateSet* getOrCreateStateSet();
void setupStyle();
private:

View File

@ -137,6 +137,10 @@ namespace canvas
//----------------------------------------------------------------------------
bool Group::setStyle(const SGPropertyNode* style)
{
// Don't propagate styles directly applicable to this group
if( Element::setStyle(style) )
return true;
if( style->getParent() != _node
&& _style.find(style->getNameString()) != _style.end() )
return false;
@ -192,8 +196,12 @@ namespace canvas
return;
}
_style[ child->getNameString() ] = child;
setStyle(child);
if( !Element::setStyle(child) )
{
// Only add style if not applicable to group itself
_style[ child->getNameString() ] = child;
setStyle(child);
}
}
//----------------------------------------------------------------------------