From fd27e7bd43d51956ef810e7493a205c48d7bf64a Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 7 Dec 2012 18:36:37 +0100 Subject: [PATCH] Canvas: basic support for rectangular clipping (like CSS clip property) --- simgear/canvas/Canvas.cxx | 12 ++++ simgear/canvas/Canvas.hxx | 3 + simgear/canvas/elements/CanvasElement.cxx | 78 +++++++++++++++++++++++ simgear/canvas/elements/CanvasElement.hxx | 13 ++++ simgear/canvas/elements/CanvasGroup.cxx | 12 +++- 5 files changed, 116 insertions(+), 2 deletions(-) diff --git a/simgear/canvas/Canvas.cxx b/simgear/canvas/Canvas.cxx index c5c8f1a5..ef8f266d 100644 --- a/simgear/canvas/Canvas.cxx +++ b/simgear/canvas/Canvas.cxx @@ -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) { diff --git a/simgear/canvas/Canvas.hxx b/simgear/canvas/Canvas.hxx index ca897c26..4a3187ff 100644 --- a/simgear/canvas/Canvas.hxx +++ b/simgear/canvas/Canvas.hxx @@ -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, diff --git a/simgear/canvas/elements/CanvasElement.cxx b/simgear/canvas/elements/CanvasElement.cxx index 9395eec7..fff667d7 100644 --- a/simgear/canvas/elements/CanvasElement.cxx +++ b/simgear/canvas/elements/CanvasElement.cxx @@ -24,9 +24,13 @@ #include #include +#include +#include #include +#include #include +#include #include #include @@ -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 > tokenizer; + const boost::char_separator 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(*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(canvas->getViewWidth()); + scale_y = canvas->getSizeY() + / static_cast(canvas->getViewHeight()); + } + + osg::Scissor* scissor = new osg::Scissor(); + // , , , + 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() { diff --git a/simgear/canvas/elements/CanvasElement.hxx b/simgear/canvas/elements/CanvasElement.hxx index d3a5bfa9..28a04e02 100644 --- a/simgear/canvas/elements/CanvasElement.hxx +++ b/simgear/canvas/elements/CanvasElement.hxx @@ -92,6 +92,14 @@ namespace canvas virtual bool setStyle(const SGPropertyNode* child); + /** + * Set clipping shape + * + * @note Only "rect(, , , )" 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: diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx index 5cd403cc..a65cb2cb 100644 --- a/simgear/canvas/elements/CanvasGroup.cxx +++ b/simgear/canvas/elements/CanvasGroup.cxx @@ -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); + } } //---------------------------------------------------------------------------- -- 2.39.5