X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fcanvas%2FCanvas.cxx;h=c7898b4535df604b07de4b0ccda9fa545af708af;hb=23413b47818b042620eeeaf306ffe6d1ae81852d;hp=ef8f266d1ae7d21a91414781b85544a00441b287;hpb=fd27e7bd43d51956ef810e7493a205c48d7bf64a;p=simgear.git diff --git a/simgear/canvas/Canvas.cxx b/simgear/canvas/Canvas.cxx index ef8f266d..c7898b45 100644 --- a/simgear/canvas/Canvas.cxx +++ b/simgear/canvas/Canvas.cxx @@ -19,8 +19,8 @@ #include "Canvas.hxx" #include "CanvasEventManager.hxx" #include "CanvasEventVisitor.hxx" -#include -#include +#include "CanvasPlacement.hxx" +#include #include #include @@ -31,7 +31,6 @@ #include #include -#include namespace simgear { @@ -49,8 +48,12 @@ namespace canvas void Canvas::CullCallback::operator()( osg::Node* node, osg::NodeVisitor* nv ) { - if( (nv->getTraversalMask() & simgear::MODEL_BIT) && !_canvas.expired() ) - _canvas.lock()->enableRendering(); + if( (nv->getTraversalMask() & simgear::MODEL_BIT) ) + { + CanvasPtr canvas = _canvas.lock(); + if( canvas ) + canvas->enableRendering(); + } traverse(node, nv); } @@ -66,15 +69,6 @@ namespace canvas _view_height(-1), _status(node, "status"), _status_msg(node, "status-msg"), - _mouse_x(node, "mouse/x"), - _mouse_y(node, "mouse/y"), - _mouse_dx(node, "mouse/dx"), - _mouse_dy(node, "mouse/dy"), - _mouse_button(node, "mouse/button"), - _mouse_state(node, "mouse/state"), - _mouse_mod(node, "mouse/mod"), - _mouse_scroll(node, "mouse/scroll"), - _mouse_event(node, "mouse/event"), _sampling_dirty(false), _render_dirty(true), _visible(true), @@ -82,25 +76,29 @@ namespace canvas { _status = 0; setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y); - } - //---------------------------------------------------------------------------- - Canvas::~Canvas() - { + _root_group.reset( new Group(this, _node) ); + // Remove automatically created property listener as we forward them on our + // own + _root_group->removeListener(); + _cull_callback = new CullCallback(this); } //---------------------------------------------------------------------------- - void Canvas::setSystemAdapter(const SystemAdapterPtr& system_adapter) + Canvas::~Canvas() { - _system_adapter = system_adapter; - _texture.setSystemAdapter(system_adapter); + } //---------------------------------------------------------------------------- - SystemAdapterPtr Canvas::getSystemAdapter() const + void Canvas::onDestroy() { - return _system_adapter; + if( _root_group ) + { + _root_group->clearEventListener(); + _root_group->onDestroy(); + } } //---------------------------------------------------------------------------- @@ -116,7 +114,31 @@ namespace canvas } //---------------------------------------------------------------------------- - void Canvas::addDependentCanvas(const CanvasWeakPtr& canvas) + bool Canvas::isInit() const + { + return _texture.serviceable(); + } + + //---------------------------------------------------------------------------- + void Canvas::addParentCanvas(const CanvasWeakPtr& canvas) + { + if( canvas.expired() ) + { + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "Canvas::addParentCanvas(" << _node->getPath(true) << "): " + "got an expired parent!" + ); + return; + } + + _parent_canvases.insert(canvas); + } + + //---------------------------------------------------------------------------- + void Canvas::addChildCanvas(const CanvasWeakPtr& canvas) { if( canvas.expired() ) { @@ -124,28 +146,57 @@ namespace canvas ( SG_GENERAL, SG_WARN, - "Canvas::addDependentCanvas: got an expired Canvas dependent on " - << _node->getPath() + "Canvas::addChildCanvas(" << _node->getPath(true) << "): " + " got an expired child!" ); return; } - _dependent_canvases.insert(canvas); + _child_canvases.insert(canvas); + } + + //---------------------------------------------------------------------------- + void Canvas::removeParentCanvas(const CanvasWeakPtr& canvas) + { + _parent_canvases.erase(canvas); } //---------------------------------------------------------------------------- - void Canvas::removeDependentCanvas(const CanvasWeakPtr& canvas) + void Canvas::removeChildCanvas(const CanvasWeakPtr& canvas) { - _dependent_canvases.erase(canvas); + _child_canvases.erase(canvas); } //---------------------------------------------------------------------------- GroupPtr Canvas::createGroup(const std::string& name) { - return boost::dynamic_pointer_cast - ( - _root_group->createChild("group", name) - ); + return _root_group->createChild(name); + } + + //---------------------------------------------------------------------------- + GroupPtr Canvas::getGroup(const std::string& name) + { + return _root_group->getChild(name); + } + + //---------------------------------------------------------------------------- + GroupPtr Canvas::getOrCreateGroup(const std::string& name) + { + return _root_group->getOrCreateChild(name); + } + + //---------------------------------------------------------------------------- + GroupPtr Canvas::getRootGroup() + { + return _root_group; + } + + //---------------------------------------------------------------------------- + void Canvas::setLayout(const LayoutRef& layout) + { + _layout = layout; + _layout->setCanvas(this); + _status |= LAYOUT_DIRTY; } //---------------------------------------------------------------------------- @@ -159,30 +210,43 @@ namespace canvas //---------------------------------------------------------------------------- void Canvas::update(double delta_time_sec) { - if( !_texture.serviceable() ) - { - if( _status != STATUS_OK ) - return; + if( _status & (CREATE_FAILED | MISSING_SIZE) ) + return; + if( _status & STATUS_DIRTY ) + { _texture.setSize(_size_x, _size_y); - _texture.useImageCoords(true); - _texture.useStencil(true); - _texture.allocRT(/*_camera_callback*/); + + if( !_texture.serviceable() ) + { + _texture.useImageCoords(true); + _texture.useStencil(true); + _texture.allocRT(/*_camera_callback*/); + } + else + { + // Resizing causes a new texture to be created so we need to reapply all + // existing placements + reloadPlacements(); + } osg::Camera* camera = _texture.getCamera(); + // TODO Allow custom render order? For now just keep in order with + // property tree. + camera->setRenderOrder(osg::Camera::PRE_RENDER, _node->getIndex()); + osg::Vec4 clear_color(0.0f, 0.0f, 0.0f , 1.0f); parseColor(_node->getStringValue("background"), clear_color); camera->setClearColor(clear_color); camera->addChild(_root_group->getMatrixTransform()); - // Ensure objects are drawn in order of traversal - camera->getOrCreateStateSet()->setBinName("TraversalOrderBin"); - if( _texture.serviceable() ) { setStatusFlags(STATUS_OK); + setStatusFlags(STATUS_DIRTY, false); + _render_dirty = true; } else { @@ -191,15 +255,36 @@ namespace canvas } } + if( _layout ) + { + if( (_status & LAYOUT_DIRTY) ) + { + _layout->setGeometry(SGRecti(0, 0, _view_width, _view_height)); + _status &= ~LAYOUT_DIRTY; + } + else + _layout->update(); + } + if( _visible || _render_always ) { + BOOST_FOREACH(CanvasWeakPtr canvas_weak, _child_canvases) + { + // TODO should we check if the image the child canvas is displayed + // within is really visible? + CanvasPtr canvas = canvas_weak.lock(); + if( canvas ) + canvas->_visible = true; + } + if( _render_dirty ) { - // Also mark all dependent (eg. recursively used) canvases as dirty - BOOST_FOREACH(CanvasWeakPtr canvas, _dependent_canvases) + // Also mark all canvases this canvas is displayed within as dirty + BOOST_FOREACH(CanvasWeakPtr canvas_weak, _parent_canvases) { - if( !canvas.expired() ) - canvas.lock()->_render_dirty = true; + CanvasPtr canvas = canvas_weak.lock(); + if( canvas ) + canvas->_render_dirty = true; } } @@ -242,11 +327,7 @@ namespace canvas if( placement_factory != _placement_factories.end() ) { Placements& placements = _placements[ node->getIndex() ] = - placement_factory->second - ( - node, - boost::static_pointer_cast(_self.lock()) - ); + placement_factory->second(node, this); node->setStringValue ( "status-msg", @@ -259,12 +340,22 @@ namespace canvas } //---------------------------------------------------------------------------- - naRef Canvas::addEventListener(const nasal::CallContext& ctx) + bool Canvas::addEventListener( const std::string& type, + const EventListener& cb ) + { + if( !_root_group.get() ) + throw std::runtime_error("Canvas::addEventListener: no root group!"); + + return _root_group->addEventListener(type, cb); + } + + //---------------------------------------------------------------------------- + bool Canvas::dispatchEvent(const EventPtr& event) { if( !_root_group.get() ) - naRuntimeError(ctx.c, "Canvas: No root group!"); + throw std::runtime_error("Canvas::dispatchEvent: no root group!"); - return _root_group->addEventListener(ctx); + return _root_group->dispatchEvent(event); } //---------------------------------------------------------------------------- @@ -273,8 +364,7 @@ namespace canvas if( _size_x == sx ) return; _size_x = sx; - - // TODO resize if texture already allocated + setStatusFlags(STATUS_DIRTY); if( _size_x <= 0 ) setStatusFlags(MISSING_SIZE_X); @@ -291,8 +381,7 @@ namespace canvas if( _size_y == sy ) return; _size_y = sy; - - // TODO resize if texture already allocated + setStatusFlags(STATUS_DIRTY); if( _size_y <= 0 ) setStatusFlags(MISSING_SIZE_Y); @@ -321,6 +410,7 @@ namespace canvas if( _view_width == w ) return; _view_width = w; + _status |= LAYOUT_DIRTY; _texture.setViewSize(_view_width, _view_height); } @@ -331,6 +421,7 @@ namespace canvas if( _view_height == h ) return; _view_height = h; + _status |= LAYOUT_DIRTY; _texture.setViewSize(_view_width, _view_height); } @@ -338,41 +429,43 @@ namespace canvas //---------------------------------------------------------------------------- int Canvas::getViewWidth() const { - return _view_width; + return _texture.getViewSize().x(); } //---------------------------------------------------------------------------- int Canvas::getViewHeight() const { - return _view_height; + return _texture.getViewSize().y(); } //---------------------------------------------------------------------------- - bool Canvas::handleMouseEvent(const MouseEventPtr& event) + SGRect Canvas::getViewport() const { - _mouse_x = event->pos.x(); - _mouse_y = event->pos.y(); - _mouse_dx = event->delta.x(); - _mouse_dy = event->delta.y(); - _mouse_button = event->button; - _mouse_state = event->state; - _mouse_mod = event->mod; - //_mouse_scroll = event.scroll; - // Always set event type last because all listeners are attached to it - _mouse_event = event->type; + return SGRect(0, 0, getViewWidth(), getViewHeight()); + } - if( !_root_group.get() ) + //---------------------------------------------------------------------------- + bool Canvas::handleMouseEvent(const MouseEventPtr& event) + { + if( !_root_group ) return false; EventVisitor visitor( EventVisitor::TRAVERSE_DOWN, - event->getPos(), - event->getDelta() ); + event->getClientPos(), + _root_group ); if( !_root_group->accept(visitor) ) return false; return _event_manager->handleEvent(event, visitor.getPropagationPath()); } + //---------------------------------------------------------------------------- + bool Canvas::propagateEvent( EventPtr const& event, + EventPropagationPath const& path ) + { + return _event_manager->propagateEvent(event, path); + } + //---------------------------------------------------------------------------- void Canvas::childAdded( SGPropertyNode * parent, SGPropertyNode * child ) @@ -404,8 +497,10 @@ namespace canvas //---------------------------------------------------------------------------- void Canvas::valueChanged(SGPropertyNode* node) { - if( boost::starts_with(node->getNameString(), "status") - || node->getParent()->getNameString() == "bounding-box" ) + const std::string& name = node->getNameString(); + + if( boost::starts_with(name, "status") + || boost::starts_with(name, "data-") ) return; _render_dirty = true; @@ -413,21 +508,26 @@ namespace canvas if( node->getParent()->getParent() == _node && node->getParent()->getNameString() == "placement" ) { - bool placement_dirty = false; - BOOST_FOREACH(Placements& placements, _placements) + size_t index = node->getIndex(); + if( index < _placements.size() ) { - BOOST_FOREACH(PlacementPtr& placement, placements) + Placements& placements = _placements[index]; + if( !placements.empty() ) { - // check if change can be directly handled by placement - if( placement->getProps() == node->getParent() - && !placement->childChanged(node) ) - placement_dirty = true; + bool placement_dirty = false; + BOOST_FOREACH(PlacementPtr& placement, placements) + { + // check if change can be directly handled by placement + if( placement->getProps() == node->getParent() + && !placement->childChanged(node) ) + placement_dirty = true; + } + + if( !placement_dirty ) + return; } } - if( !placement_dirty ) - return; - // prevent double updates... for( size_t i = 0; i < _dirty_placements.size(); ++i ) { @@ -439,7 +539,7 @@ namespace canvas } else if( node->getParent() == _node ) { - if( node->getNameString() == "background" ) + if( name == "background" ) { osg::Vec4 color; if( _texture.getCamera() && parseColor(node->getStringValue(), color) ) @@ -448,31 +548,41 @@ namespace canvas _render_dirty = true; } } - else if( node->getNameString() == "mipmapping" - || node->getNameString() == "coverage-samples" - || node->getNameString() == "color-samples" ) + else if( name == "mipmapping" + || name == "coverage-samples" + || name == "color-samples" ) { _sampling_dirty = true; } - else if( node->getNameString() == "render-always" ) + else if( name == "additive-blend" ) + { + _texture.useAdditiveBlend( node->getBoolValue() ); + } + else if( name == "render-always" ) { _render_always = node->getBoolValue(); } - else if( node->getNameString() == "size" ) + else if( name == "size" ) { if( node->getIndex() == 0 ) setSizeX( node->getIntValue() ); else if( node->getIndex() == 1 ) setSizeY( node->getIntValue() ); } - else if( node->getNameString() == "view" ) + else if( name == "update" ) + { + if( _root_group ) + _root_group->update(0); + return update(0); + } + else if( name == "view" ) { if( node->getIndex() == 0 ) setViewWidth( node->getIntValue() ); else if( node->getIndex() == 1 ) setViewHeight( node->getIntValue() ); } - else if( node->getNameString() == "freeze" ) + else if( name == "freeze" ) _texture.setRender( node->getBoolValue() ); else handled = false; @@ -496,6 +606,24 @@ namespace canvas return _cull_callback; } + //---------------------------------------------------------------------------- + void Canvas::reloadPlacements(const std::string& type) + { + for(size_t i = 0; i < _placements.size(); ++i) + { + if( _placements[i].empty() ) + continue; + + SGPropertyNode* child = _placements[i].front()->getProps(); + if( type.empty() + // reload if type matches or no type specified + || child->getStringValue("type", type.c_str()) == type ) + { + _dirty_placements.push_back(child); + } + } + } + //---------------------------------------------------------------------------- void Canvas::addPlacementFactory( const std::string& type, PlacementFactory factory ) @@ -505,37 +633,47 @@ namespace canvas ( SG_GENERAL, SG_WARN, - "Canvas::addPlacementFactory: replace existing factor for type " << type + "Canvas::addPlacementFactory: replace existing factory '" << type << "'" ); _placement_factories[type] = factory; } //---------------------------------------------------------------------------- - void Canvas::setSelf(const PropertyBasedElementPtr& self) + void Canvas::removePlacementFactory(const std::string& type) { - PropertyBasedElement::setSelf(self); - - CanvasPtr canvas = boost::static_pointer_cast(self); + PlacementFactoryMap::iterator it = _placement_factories.find(type); + if( it == _placement_factories.end() ) + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "Canvas::removePlacementFactory: no such factory '" << type << "'" + ); + else + _placement_factories.erase(it); + } - _root_group.reset( new Group(canvas, _node) ); - _root_group->setSelf(_root_group); - // Remove automatically created property listener as we forward them on our - // own - _root_group->removeListener(); + //---------------------------------------------------------------------------- + void Canvas::setSystemAdapter(const SystemAdapterPtr& system_adapter) + { + _system_adapter = system_adapter; + } - _cull_callback = new CullCallback(canvas); + //---------------------------------------------------------------------------- + SystemAdapterPtr Canvas::getSystemAdapter() + { + return _system_adapter; } //---------------------------------------------------------------------------- void Canvas::setStatusFlags(unsigned int flags, bool set) { if( set ) - _status = _status | flags; + _status |= flags; else - _status = _status & ~flags; - // TODO maybe extend simgear::PropertyObject to allow |=, &= etc. + _status &= ~flags; if( (_status & MISSING_SIZE_X) && (_status & MISSING_SIZE_Y) ) _status_msg = "Missing size"; @@ -545,7 +683,7 @@ namespace canvas _status_msg = "Missing size-y"; else if( _status & CREATE_FAILED ) _status_msg = "Creating render target failed"; - else if( _status == STATUS_OK && !_texture.serviceable() ) + else if( _status & STATUS_DIRTY ) _status_msg = "Creation pending..."; else _status_msg = "Ok"; @@ -553,6 +691,7 @@ namespace canvas //---------------------------------------------------------------------------- Canvas::PlacementFactoryMap Canvas::_placement_factories; + SystemAdapterPtr Canvas::_system_adapter; } // namespace canvas } // namespace simgear