]> git.mxchange.org Git - simgear.git/commitdiff
Canvas: basic support for rectangular clipping (like CSS clip property)
authorThomas Geymayer <tomgey@gmail.com>
Fri, 7 Dec 2012 17:36:37 +0000 (18:36 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Fri, 7 Dec 2012 17:36:37 +0000 (18:36 +0100)
simgear/canvas/Canvas.cxx
simgear/canvas/Canvas.hxx
simgear/canvas/elements/CanvasElement.cxx
simgear/canvas/elements/CanvasElement.hxx
simgear/canvas/elements/CanvasGroup.cxx

index c5c8f1a54953619ee3f6280cba23a0cf477fe9a3..ef8f266d1ae7d21a91414781b85544a00441b287 100644 (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)
   {
index ca897c268bd331b5c2399e3e22cdfa62b8afeb64..4a3187fff4d68c4d73820463d6e9ae5c9f2a2b45 100644 (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,
index 9395eec7e51c628561ca57d66977860c7ba3834a..fff667d7f4313d53d94cc0a5af8a8b7bf43381e3 100644 (file)
 
 #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()
   {
index d3a5bfa9e01f417c52f6d24c59b7d046b3cdf994..28a04e020a2ffa155f78402565f5fac392dbaa05 100644 (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:
index 5cd403ccd2b5876bca04cbd22154ad88b6edf6e3..a65cb2cb5c8db49f64b4b2123403be2bba3978f4 100644 (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);
+    }
   }
 
   //----------------------------------------------------------------------------