Canvas: improved clipping and new property clip-frame.
- Update clipping rect if canvas view or texture size changes. - Add new property "clip-frame" to specify coordinate frame for "clip" coordinates. Coordinates can be global, relative to the parent or relative to the element itself.
This commit is contained in:
parent
353b7e4438
commit
38ddfab1e0
@ -17,7 +17,6 @@
|
|||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
#include "CanvasElement.hxx"
|
#include "CanvasElement.hxx"
|
||||||
#include <simgear/canvas/Canvas.hxx>
|
|
||||||
#include <simgear/canvas/CanvasEventVisitor.hxx>
|
#include <simgear/canvas/CanvasEventVisitor.hxx>
|
||||||
#include <simgear/canvas/MouseEvent.hxx>
|
#include <simgear/canvas/MouseEvent.hxx>
|
||||||
#include <simgear/math/SGMisc.hxx>
|
#include <simgear/math/SGMisc.hxx>
|
||||||
@ -41,6 +40,63 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
const std::string NAME_TRANSFORM = "tf";
|
const std::string NAME_TRANSFORM = "tf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* glScissor with coordinates relative to different reference frames.
|
||||||
|
*/
|
||||||
|
class Element::RelativeScissor:
|
||||||
|
public osg::Scissor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ReferenceFrame _coord_reference;
|
||||||
|
osg::Matrix _parent_inverse;
|
||||||
|
|
||||||
|
RelativeScissor():
|
||||||
|
_coord_reference(GLOBAL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual void apply(osg::State& state) const
|
||||||
|
{
|
||||||
|
const osg::Viewport* vp = state.getCurrentViewport();
|
||||||
|
float w2 = 0.5 * vp->width(),
|
||||||
|
h2 = 0.5 * vp->height();
|
||||||
|
|
||||||
|
osg::Matrix model_view
|
||||||
|
(
|
||||||
|
w2, 0, 0, 0,
|
||||||
|
0, h2, 0, 0,
|
||||||
|
0, 0, 1, 0,
|
||||||
|
w2, h2, 0, 1
|
||||||
|
);
|
||||||
|
model_view.preMult(state.getProjectionMatrix());
|
||||||
|
|
||||||
|
if( _coord_reference != GLOBAL )
|
||||||
|
{
|
||||||
|
model_view.preMult(state.getModelViewMatrix());
|
||||||
|
|
||||||
|
if( _coord_reference == PARENT )
|
||||||
|
model_view.preMult(_parent_inverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
const osg::Vec2 scale( model_view(0,0), model_view(1,1)),
|
||||||
|
offset(model_view(3,0), model_view(3,1));
|
||||||
|
|
||||||
|
// TODO check/warn for rotation?
|
||||||
|
|
||||||
|
GLint x = SGMiscf::roundToInt(scale.x() * _x + offset.x()),
|
||||||
|
y = SGMiscf::roundToInt(scale.y() * _y + offset.y()),
|
||||||
|
w = SGMiscf::roundToInt(std::fabs(scale.x()) * _width),
|
||||||
|
h = SGMiscf::roundToInt(std::fabs(scale.y()) * _height);
|
||||||
|
|
||||||
|
if( scale.x() < 0 )
|
||||||
|
x -= w;
|
||||||
|
if( scale.y() < 0 )
|
||||||
|
y -= h;
|
||||||
|
|
||||||
|
glScissor(x, y, w, h);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
Element::OSGUserData::OSGUserData(ElementPtr element):
|
Element::OSGUserData::OSGUserData(ElementPtr element):
|
||||||
element(element)
|
element(element)
|
||||||
@ -156,6 +212,15 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
_transform->setMatrix(m);
|
_transform->setMatrix(m);
|
||||||
_transform_dirty = false;
|
_transform_dirty = false;
|
||||||
|
_attributes_dirty |= SCISSOR_COORDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( _attributes_dirty & SCISSOR_COORDS )
|
||||||
|
{
|
||||||
|
if( _scissor && _scissor->_coord_reference != GLOBAL )
|
||||||
|
_scissor->_parent_inverse = _transform->getInverseMatrix();
|
||||||
|
|
||||||
|
_attributes_dirty &= ~SCISSOR_COORDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update bounding box on manual update (manual updates pass zero dt)
|
// Update bounding box on manual update (manual updates pass zero dt)
|
||||||
@ -402,6 +467,7 @@ namespace canvas
|
|||||||
if( clip.empty() || clip == "auto" )
|
if( clip.empty() || clip == "auto" )
|
||||||
{
|
{
|
||||||
getOrCreateStateSet()->removeAttribute(osg::StateAttribute::SCISSOR);
|
getOrCreateStateSet()->removeAttribute(osg::StateAttribute::SCISSOR);
|
||||||
|
_scissor = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,32 +513,28 @@ namespace canvas
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float scale_x = 1,
|
_scissor = new RelativeScissor();
|
||||||
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>
|
// <top>, <right>, <bottom>, <left>
|
||||||
scissor->x() = SGMiscf::roundToInt(scale_x * values[3]);
|
_scissor->x() = SGMiscf::roundToInt(values[3]);
|
||||||
scissor->y() = SGMiscf::roundToInt(scale_y * values[0]);
|
_scissor->y() = SGMiscf::roundToInt(values[0]);
|
||||||
scissor->width() = SGMiscf::roundToInt(scale_x * width);
|
_scissor->width() = SGMiscf::roundToInt(width);
|
||||||
scissor->height() = SGMiscf::roundToInt(scale_y * height);
|
_scissor->height() = SGMiscf::roundToInt(height);
|
||||||
|
|
||||||
if( canvas )
|
getOrCreateStateSet()->setAttributeAndModes(_scissor);
|
||||||
// Canvas has y axis upside down
|
|
||||||
scissor->y() = canvas->getSizeY() - scissor->y() - scissor->height();
|
|
||||||
|
|
||||||
getOrCreateStateSet()->setAttributeAndModes(scissor);
|
SGPropertyNode* clip_frame = _node->getChild("clip-frame", 0);
|
||||||
|
if( clip_frame )
|
||||||
|
valueChanged(clip_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Element::setClipFrame(ReferenceFrame rf)
|
||||||
|
{
|
||||||
|
if( _scissor )
|
||||||
|
{
|
||||||
|
_scissor->_coord_reference = rf;
|
||||||
|
_attributes_dirty |= SCISSOR_COORDS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -523,6 +585,7 @@ namespace canvas
|
|||||||
_transform_dirty( false ),
|
_transform_dirty( false ),
|
||||||
_transform( new osg::MatrixTransform ),
|
_transform( new osg::MatrixTransform ),
|
||||||
_style( parent_style ),
|
_style( parent_style ),
|
||||||
|
_scissor( 0 ),
|
||||||
_drawable( 0 )
|
_drawable( 0 )
|
||||||
{
|
{
|
||||||
staticInit();
|
staticInit();
|
||||||
@ -551,6 +614,7 @@ namespace canvas
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
addStyle("clip", "", &Element::setClip, false);
|
addStyle("clip", "", &Element::setClip, false);
|
||||||
|
addStyle("clip-frame", "", &Element::setClipFrame, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -75,6 +75,17 @@ namespace canvas
|
|||||||
/// their parents
|
/// their parents
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coordinate reference frame (eg. "clip" property)
|
||||||
|
*/
|
||||||
|
enum ReferenceFrame
|
||||||
|
{
|
||||||
|
GLOBAL, ///!< Global coordinates
|
||||||
|
PARENT, ///!< Coordinates relative to parent coordinate frame
|
||||||
|
LOCAL ///!< Coordinates relative to local coordinates (parent
|
||||||
|
/// coordinates with local transformations applied)
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -131,6 +142,11 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
void setClip(const std::string& clip);
|
void setClip(const std::string& clip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clipping coordinates reference frame
|
||||||
|
*/
|
||||||
|
void setClipFrame(ReferenceFrame rf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the given bounding box to the property tree
|
* Write the given bounding box to the property tree
|
||||||
*/
|
*/
|
||||||
@ -165,8 +181,9 @@ namespace canvas
|
|||||||
|
|
||||||
enum Attributes
|
enum Attributes
|
||||||
{
|
{
|
||||||
BLEND_FUNC = 0x0001,
|
BLEND_FUNC = 1,
|
||||||
LAST_ATTRIBUTE = BLEND_FUNC << 1
|
SCISSOR_COORDS = BLEND_FUNC << 1,
|
||||||
|
LAST_ATTRIBUTE = SCISSOR_COORDS << 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TransformType
|
enum TransformType
|
||||||
@ -178,6 +195,8 @@ namespace canvas
|
|||||||
TT_SCALE
|
TT_SCALE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RelativeScissor;
|
||||||
|
|
||||||
CanvasWeakPtr _canvas;
|
CanvasWeakPtr _canvas;
|
||||||
Element *_parent;
|
Element *_parent;
|
||||||
|
|
||||||
@ -189,6 +208,7 @@ namespace canvas
|
|||||||
|
|
||||||
Style _style;
|
Style _style;
|
||||||
std::vector<SGPropertyNode_ptr> _bounding_box;
|
std::vector<SGPropertyNode_ptr> _bounding_box;
|
||||||
|
RelativeScissor *_scissor;
|
||||||
|
|
||||||
typedef std::vector<EventListener> Listener;
|
typedef std::vector<EventListener> Listener;
|
||||||
typedef std::map<Event::Type, Listener> ListenerMap;
|
typedef std::map<Event::Type, Listener> ListenerMap;
|
||||||
@ -555,6 +575,27 @@ namespace canvas
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct enum_traits<canvas::Element::ReferenceFrame>
|
||||||
|
{
|
||||||
|
static const char* name()
|
||||||
|
{
|
||||||
|
return "canvas::Element::ReferenceFrame";
|
||||||
|
}
|
||||||
|
|
||||||
|
static canvas::Element::ReferenceFrame defVal()
|
||||||
|
{
|
||||||
|
return canvas::Element::GLOBAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool validate(int frame)
|
||||||
|
{
|
||||||
|
return frame >= canvas::Element::GLOBAL
|
||||||
|
&& frame <= canvas::Element::LOCAL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace simgear
|
} // namespace simgear
|
||||||
|
|
||||||
#endif /* CANVAS_ELEMENT_HXX_ */
|
#endif /* CANVAS_ELEMENT_HXX_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user