Revisiting GAL:

- VIEW_ITEM::ViewUpdate() does not update items immediately. Now it marks them to be updated and the real update occurs on the next rendering frame.
- VIEW::InvalidateItem() made private.
- VIEW_LAYER::enabled -> visible
- Some functions moved to header files.
This commit is contained in:
Maciej Suminski 2014-02-21 16:57:18 +01:00
parent 87785441bc
commit 5ac699776d
6 changed files with 187 additions and 152 deletions

View File

@ -124,17 +124,22 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
{
m_drawing = true;
m_view->UpdateItems();
m_gal->BeginDrawing();
m_gal->SetBackgroundColor( KIGFX::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) );
m_gal->ClearScreen();
m_view->ClearTargets();
// Grid has to be redrawn only when the NONCACHED target is redrawn
if( m_view->IsTargetDirty( KIGFX::TARGET_NONCACHED ) )
m_gal->DrawGrid();
m_view->Redraw();
m_gal->DrawCursor( m_viewControls->GetCursorPosition() );
if( m_view->IsDirty() )
{
m_view->ClearTargets();
// Grid has to be redrawn only when the NONCACHED target is redrawn
if( m_view->IsTargetDirty( KIGFX::TARGET_NONCACHED ) )
m_gal->DrawGrid();
m_view->Redraw();
}
m_gal->DrawCursor( m_viewControls->GetCursorPosition() );
m_gal->EndDrawing();
m_drawing = false;
@ -215,6 +220,7 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )
wxSize size = GetClientSize();
m_gal->ResizeScreen( size.GetX(), size.GetY() );
m_gal->SetBackgroundColor( KIGFX::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) );
if( m_painter )
m_painter->SetGAL( m_gal );

View File

@ -49,28 +49,24 @@ VIEW::VIEW( bool aIsDynamic ) :
m_scaleLimits( 15000.0, 1.0 )
{
m_panBoundary.SetMaximum();
m_needsUpdate.reserve( 32768 );
// Redraw everything at the beginning
for( int i = 0; i < TARGETS_NUMBER; ++i )
MarkTargetDirty( i );
MarkDirty();
// View uses layers to display EDA_ITEMs (item may be displayed on several layers, for example
// pad may be shown on pad, pad hole and solder paste layers). There are usual copper layers
// (eg. F.Cu, B.Cu, internal and so on) and layers for displaying objects such as texts,
// silkscreen, pads, vias, etc.
for( int i = 0; i < VIEW_MAX_LAYERS; i++ )
{
AddLayer( i );
}
}
VIEW::~VIEW()
{
BOOST_FOREACH( LAYER_MAP::value_type& l, m_layers )
{
delete l.second.items;
}
}
@ -82,7 +78,7 @@ void VIEW::AddLayer( int aLayer, bool aDisplayOnly )
m_layers[aLayer].id = aLayer;
m_layers[aLayer].items = new VIEW_RTREE();
m_layers[aLayer].renderingOrder = aLayer;
m_layers[aLayer].enabled = true;
m_layers[aLayer].visible = true;
m_layers[aLayer].displayOnly = aDisplayOnly;
m_layers[aLayer].target = TARGET_CACHED;
}
@ -172,12 +168,12 @@ struct queryVisitor
};
int VIEW::Query( const BOX2I& aRect, std::vector<LAYER_ITEM_PAIR>& aResult )
int VIEW::Query( const BOX2I& aRect, std::vector<LAYER_ITEM_PAIR>& aResult ) const
{
if( m_orderedLayers.empty() )
return 0;
std::vector<VIEW_LAYER*>::reverse_iterator i;
std::vector<VIEW_LAYER*>::const_reverse_iterator i;
// execute queries in reverse direction, so that items that are on the top of
// the rendering stack are returned first.
@ -257,12 +253,6 @@ void VIEW::SetGAL( GAL* aGal )
}
void VIEW::SetPainter( PAINTER* aPainter )
{
m_painter = aPainter;
}
BOX2D VIEW::GetViewport() const
{
BOX2D rect;
@ -293,12 +283,6 @@ void VIEW::SetMirror( bool aMirrorX, bool aMirrorY )
}
void VIEW::SetScale( double aScale )
{
SetScale( aScale, m_center );
}
void VIEW::SetScale( double aScale, const VECTOR2D& aAnchor )
{
if( aScale > m_scaleLimits.x )
@ -578,8 +562,8 @@ void VIEW::UpdateAllLayersOrder()
struct VIEW::drawItem
{
drawItem( VIEW* aView, const VIEW_LAYER* aCurrentLayer ) :
currentLayer( aCurrentLayer ), view( aView )
drawItem( VIEW* aView, int aLayer ) :
view( aView ), layer( aLayer )
{
}
@ -587,18 +571,17 @@ struct VIEW::drawItem
{
// Conditions that have te be fulfilled for an item to be drawn
bool drawCondition = aItem->ViewIsVisible() &&
aItem->ViewGetLOD( currentLayer->id ) < view->m_scale;
aItem->ViewGetLOD( layer ) < view->m_scale;
if( !drawCondition )
return true;
view->draw( aItem, currentLayer->id );
view->draw( aItem, layer );
return true;
}
const VIEW_LAYER* currentLayer;
VIEW* view;
int layersCount, layers[VIEW_MAX_LAYERS];
int layer, layersCount, layers[VIEW_MAX_LAYERS];
};
@ -606,9 +589,9 @@ void VIEW::redrawRect( const BOX2I& aRect )
{
BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers )
{
if( l->enabled && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) )
if( l->visible && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) )
{
drawItem drawFunc( this, l );
drawItem drawFunc( this, l->id );
m_gal->SetTarget( l->target );
m_gal->SetLayerDepth( l->renderingOrder );
@ -618,7 +601,7 @@ void VIEW::redrawRect( const BOX2I& aRect )
}
void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate ) const
void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate )
{
if( IsCached( aLayer ) && !aImmediate )
{
@ -649,11 +632,12 @@ void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate ) const
}
void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate ) const
void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate )
{
int layers[VIEW_MAX_LAYERS], layers_count;
aItem->ViewGetLayers( layers, layers_count );
// Sorting is needed for drawing order dependent GALs (like Cairo)
SortLayers( layers, layers_count );
@ -665,26 +649,12 @@ void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate ) const
}
void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate ) const
void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate )
{
std::set<VIEW_ITEM*>::const_iterator it;
for( it = aGroup->Begin(); it != aGroup->End(); ++it )
{
draw( *it, aImmediate );
}
}
bool VIEW::IsDirty() const
{
for( int i = 0; i < TARGETS_NUMBER; ++i )
{
if( IsTargetDirty( i ) )
return true;
}
return false;
}
@ -709,14 +679,14 @@ struct VIEW::recacheItem
bool operator()( VIEW_ITEM* aItem )
{
// Remove previously cached group
int prevGroup = aItem->getGroup( layer );
int group = aItem->getGroup( layer );
if( prevGroup >= 0 )
gal->DeleteGroup( prevGroup );
if( group >= 0 )
gal->DeleteGroup( group );
if( immediately )
{
int group = gal->BeginGroup();
group = gal->BeginGroup();
aItem->setGroup( layer, group );
if( !view->m_painter->Draw( aItem, layer ) )
@ -791,13 +761,13 @@ void VIEW::Redraw()
redrawRect( rect );
// All targets were redrawn, so nothing is dirty
clearTargetDirty( TARGET_CACHED );
clearTargetDirty( TARGET_NONCACHED );
clearTargetDirty( TARGET_OVERLAY );
markTargetClean( TARGET_CACHED );
markTargetClean( TARGET_NONCACHED );
markTargetClean( TARGET_OVERLAY );
}
VECTOR2D VIEW::GetScreenPixelSize() const
const VECTOR2D& VIEW::GetScreenPixelSize() const
{
return m_gal->GetScreenPixelSize();
}
@ -839,7 +809,7 @@ void VIEW::clearGroupCache()
}
void VIEW::InvalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )
void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )
{
// updateLayers updates geometry too, so we do not have to update both of them at the same time
if( aUpdateFlags & VIEW_ITEM::LAYERS )
@ -851,24 +821,23 @@ void VIEW::InvalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )
aItem->ViewGetLayers( layers, layers_count );
// Iterate through layers used by the item and recache it immediately
for( int i = 0; i < layers_count; i++ )
for( int i = 0; i < layers_count; ++i )
{
int layerId = layers[i];
if( aUpdateFlags & ( VIEW_ITEM::GEOMETRY | VIEW_ITEM::LAYERS ) )
if( IsCached( layerId ) )
{
// Redraw
if( IsCached( layerId ) )
if( aUpdateFlags & ( VIEW_ITEM::GEOMETRY | VIEW_ITEM::LAYERS ) )
updateItemGeometry( aItem, layerId );
}
else if( aUpdateFlags & VIEW_ITEM::COLOR )
{
updateItemColor( aItem, layerId );
else if( aUpdateFlags & VIEW_ITEM::COLOR )
updateItemColor( aItem, layerId );
}
// Mark those layers as dirty, so the VIEW will be refreshed
MarkTargetDirty( m_layers[layerId].target );
}
aItem->clearUpdateFlags();
}
@ -890,6 +859,7 @@ void VIEW::sortLayers()
void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer )
{
wxASSERT( (unsigned) aLayer < m_layers.size() );
wxASSERT( IsCached( aLayer ) );
// Obtain the color that should be used for coloring the item on the specific layerId
const COLOR4D color = m_painter->GetSettings()->GetColor( aItem, aLayer );
@ -904,18 +874,20 @@ void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer )
void VIEW::updateItemGeometry( VIEW_ITEM* aItem, int aLayer )
{
wxASSERT( (unsigned) aLayer < m_layers.size() );
wxASSERT( IsCached( aLayer ) );
VIEW_LAYER& l = m_layers.at( aLayer );
m_gal->SetTarget( l.target );
m_gal->SetLayerDepth( l.renderingOrder );
// Redraw the item from scratch
int prevGroup = aItem->getGroup( aLayer );
int group = aItem->getGroup( aLayer );
if( prevGroup >= 0 )
m_gal->DeleteGroup( prevGroup );
if( group >= 0 )
m_gal->DeleteGroup( group );
int group = m_gal->BeginGroup();
group = m_gal->BeginGroup();
aItem->setGroup( aLayer, group );
m_painter->Draw( static_cast<EDA_ITEM*>( aItem ), aLayer );
m_gal->EndGroup();
@ -951,11 +923,17 @@ void VIEW::updateLayers( VIEW_ITEM* aItem )
l.items->Remove( aItem );
MarkTargetDirty( l.target );
// Redraw the item from scratch
int prevGroup = aItem->getGroup( layers[i] );
if( IsCached( l.id ) )
{
// Redraw the item from scratch
int prevGroup = aItem->getGroup( layers[i] );
if( prevGroup >= 0 )
m_gal->DeleteGroup( prevGroup );
if( prevGroup >= 0 )
{
m_gal->DeleteGroup( prevGroup );
aItem->setGroup( l.id, -1 );
}
}
}
// Add the item to new layer set
@ -981,7 +959,7 @@ bool VIEW::areRequiredLayersEnabled( int aLayerId ) const
it_end = m_layers.at( aLayerId ).requiredLayers.end(); it != it_end; ++it )
{
// That is enough if just one layer is not enabled
if( !m_layers.at( *it ).enabled )
if( !m_layers.at( *it ).visible )
return false;
}
@ -1023,13 +1001,15 @@ void VIEW::RecacheAllItems( bool aImmediately )
}
bool VIEW::IsTargetDirty( int aTarget ) const
void VIEW::UpdateItems()
{
wxASSERT( aTarget < TARGETS_NUMBER );
// Update items that need this
BOOST_FOREACH( VIEW_ITEM* item, m_needsUpdate )
{
assert( item->viewRequiredUpdate() != VIEW_ITEM::NONE );
// Check the target status
if( m_dirtyTargets[aTarget] )
return true;
invalidateItem( item, item->viewRequiredUpdate() );
}
return false;
m_needsUpdate.clear();
}

View File

@ -31,25 +31,12 @@ using namespace KIGFX;
void VIEW_ITEM::ViewSetVisible( bool aIsVisible )
{
bool update = false;
if( m_visible != aIsVisible )
update = true;
m_visible = aIsVisible;
// update only if the visibility has really changed
if( update )
if( m_visible != aIsVisible )
{
m_visible = aIsVisible;
ViewUpdate( APPEARANCE );
}
void VIEW_ITEM::ViewUpdate( int aUpdateFlags )
{
if( !m_view )
return;
m_view->InvalidateItem( this, aUpdateFlags );
}
}

View File

@ -94,7 +94,7 @@ public:
* first).
* @return Number of found items.
*/
int Query( const BOX2I& aRect, std::vector<LAYER_ITEM_PAIR>& aResult );
int Query( const BOX2I& aRect, std::vector<LAYER_ITEM_PAIR>& aResult ) const;
/**
* Function SetRequired()
@ -140,7 +140,10 @@ public:
* Function SetPainter()
* Sets the painter object used by the view for drawing VIEW_ITEMS.
*/
void SetPainter( PAINTER* aPainter );
void SetPainter( PAINTER* aPainter )
{
m_painter = aPainter;
}
/**
* Function GetPainter()
@ -181,7 +184,10 @@ public:
* (depending on correct GAL unit length & DPI settings).
* @param aScale: the scalefactor
*/
void SetScale( double aScale );
void SetScale( double aScale )
{
SetScale( aScale, m_center );
}
/**
* Function SetScale()
@ -247,7 +253,7 @@ public:
* Returns the size of the our rendering area, in pixels.
* @return viewport screen size
*/
VECTOR2D GetScreenPixelSize() const;
const VECTOR2D& GetScreenPixelSize() const;
/**
* Function AddLayer()
@ -279,11 +285,11 @@ public:
*/
inline void SetLayerVisible( int aLayer, bool aVisible = true )
{
if( m_layers[aLayer].enabled != aVisible )
if( m_layers[aLayer].visible != aVisible )
{
// Target has to be redrawn after changing its visibility
MarkTargetDirty( m_layers[aLayer].target );
m_layers[aLayer].enabled = aVisible;
m_layers[aLayer].visible = aVisible;
}
}
@ -294,7 +300,7 @@ public:
*/
inline bool IsLayerVisible( int aLayer ) const
{
return m_layers.at( aLayer ).enabled;
return m_layers.at( aLayer ).visible;
}
/**
@ -402,18 +408,11 @@ public:
*/
void Redraw();
/**
* Function PartialRedraw()
* Redraws only the parts of the view that have been affected by items
* for which ViewUpdate() function has been called since last redraw.
*/
void PartialRedraw();
/**
* Function RecacheAllItems()
* Rebuilds GAL display lists.
* @param aForceNow decides if every item should be instantly recached. Otherwise items are
* going to be recached when they become visible.
* going to be recached when they become visible.
*/
void RecacheAllItems( bool aForceNow = false );
@ -432,7 +431,16 @@ public:
* Returns true if any of the VIEW layers needs to be refreshened.
* @return True in case if any of layers is marked as dirty.
*/
bool IsDirty() const;
bool IsDirty() const
{
for( int i = 0; i < TARGETS_NUMBER; ++i )
{
if( IsTargetDirty( i ) )
return true;
}
return false;
}
/**
* Function IsTargetDirty()
@ -440,7 +448,12 @@ public:
* redrawn.
* @return True if the above condition is fulfilled.
*/
bool IsTargetDirty( int aTarget ) const;
bool IsTargetDirty( int aTarget ) const
{
wxASSERT( aTarget < TARGETS_NUMBER );
return m_dirtyTargets[aTarget];
}
/**
* Function MarkTargetDirty()
@ -470,6 +483,22 @@ public:
m_dirtyTargets[i] = true;
}
/**
* Function MarkForUpdate()
* Adds an item to a list of items that are going to be refreshed upon the next frame rendering.
* @param aItem is the item to be refreshed.
*/
void MarkForUpdate( VIEW_ITEM* aItem )
{
m_needsUpdate.push_back( aItem );
}
/**
* Function UpdateItems()
* Iterates through the list of items that asked for updating and updates them.
*/
void UpdateItems();
/**
* Function SetPanBoundary()
* Sets limits for panning area.
@ -493,26 +522,18 @@ public:
m_scaleLimits = VECTOR2D( aMaximum, aMinimum );
}
/**
* Function InvalidateItem()
* Manages dirty flags & redraw queueing when updating an item.
* @param aItem is the item to be updated.
* @param aUpdateFlags determines the way an item is refreshed.
*/
void InvalidateItem( VIEW_ITEM* aItem, int aUpdateFlags );
static const int VIEW_MAX_LAYERS = 128; ///* maximum number of layers that may be shown
static const int VIEW_MAX_LAYERS = 128; ///< maximum number of layers that may be shown
private:
struct VIEW_LAYER
{
bool enabled; ///* is the layer to be rendered?
bool displayOnly; ///* is the layer display only?
VIEW_RTREE* items; ///* R-tree indexing all items on this layer.
int renderingOrder; ///* rendering order of this layer
int id; ///* layer ID
RENDER_TARGET target; ///* where the layer should be rendered
std::set<int> requiredLayers; ///* layers that have to be enabled to show the layer
bool visible; ///< is the layer to be rendered?
bool displayOnly; ///< is the layer display only?
VIEW_RTREE* items; ///< R-tree indexing all items on this layer.
int renderingOrder; ///< rendering order of this layer
int id; ///< layer ID
RENDER_TARGET target; ///< where the layer should be rendered
std::set<int> requiredLayers; ///< layers that have to be enabled to show the layer
};
// Convenience typedefs
@ -532,7 +553,7 @@ private:
///* Redraws contents within rect aRect
void redrawRect( const BOX2I& aRect );
inline void clearTargetDirty( int aTarget )
inline void markTargetClean( int aTarget )
{
wxASSERT( aTarget < TARGETS_NUMBER );
@ -549,7 +570,7 @@ private:
* @param aImmediate dictates the way of drawing - it allows to force immediate drawing mode
* for cached items.
*/
void draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate = false ) const;
void draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate = false );
/**
* Function draw()
@ -559,7 +580,7 @@ private:
* @param aImmediate dictates the way of drawing - it allows to force immediate drawing mode
* for cached items.
*/
void draw( VIEW_ITEM* aItem, bool aImmediate = false ) const;
void draw( VIEW_ITEM* aItem, bool aImmediate = false );
/**
* Function draw()
@ -569,7 +590,7 @@ private:
* @param aImmediate dictates the way of drawing - it allows to force immediate drawing mode
* for cached items.
*/
void draw( VIEW_GROUP* aGroup, bool aImmediate = false ) const;
void draw( VIEW_GROUP* aGroup, bool aImmediate = false );
///* Sorts m_orderedLayers when layer rendering order has changed
void sortLayers();
@ -578,6 +599,14 @@ private:
///* used by GAL)
void clearGroupCache();
/**
* Function InvalidateItem()
* Manages dirty flags & redraw queueing when updating an item.
* @param aItem is the item to be updated.
* @param aUpdateFlags determines the way an item is refreshed.
*/
void invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags );
/// Updates colors that are used for an item to be drawn
void updateItemColor( VIEW_ITEM* aItem, int aLayer );
@ -638,6 +667,9 @@ private:
/// Zoom limits
VECTOR2D m_scaleLimits;
/// Items to be updated
std::vector<VIEW_ITEM*> m_needsUpdate;
};
} // namespace KIGFX

View File

@ -157,12 +157,16 @@ public:
/**
* Enum VIEW_UPDATE_FLAGS.
* Defines the how severely the shape/appearance of the item has been changed:
* - NONE: TODO
* - APPEARANCE: shape or layer set of the item have not been affected,
* only colors or visibility.
* - COLOR:
* - GEOMETRY: shape or layer set of the item have changed, VIEW may need to reindex it.
* - ALL: all flags above */
* - LAYERS: TODO
* - ALL: all the flags above */
enum VIEW_UPDATE_FLAGS {
NONE = 0x00, /// No updates are required
APPEARANCE = 0x01, /// Visibility flag has changed
COLOR = 0x02, /// Color has changed
GEOMETRY = 0x04, /// Position or shape has changed
@ -170,7 +174,8 @@ public:
ALL = 0xff
};
VIEW_ITEM() : m_view( NULL ), m_visible( true ), m_groups( NULL ), m_groupsSize( 0 ) {}
VIEW_ITEM() : m_view( NULL ), m_visible( true ), m_requiredUpdate( NONE ),
m_groups( NULL ), m_groupsSize( 0 ) {}
/**
* Destructor. For dynamic views, removes the item from the view.
@ -262,9 +267,15 @@ public:
* For dynamic VIEWs, informs the associated VIEW that the graphical representation of
* this item has changed. For static views calling has no effect.
*
* @param aUpdateFlags: how much the object has changed
* @param aUpdateFlags: how much the object has changed.
*/
virtual void ViewUpdate( int aUpdateFlags = ALL );
virtual void ViewUpdate( int aUpdateFlags = ALL )
{
if( m_view && m_requiredUpdate == NONE )
m_view->MarkForUpdate( this );
m_requiredUpdate |= aUpdateFlags;
}
/**
* Function ViewRelease()
@ -298,8 +309,9 @@ protected:
deleteGroups();
}
VIEW* m_view; ///* Current dynamic view the item is assigned to.
bool m_visible; ///* Are we visible in the current dynamic VIEW.
VIEW* m_view; ///< Current dynamic view the item is assigned to.
bool m_visible; ///< Are we visible in the current dynamic VIEW.
int m_requiredUpdate; ///< Flag required for updating
///* Helper for storing cached items group ids
typedef std::pair<int, int> GroupPair;
@ -374,6 +386,24 @@ protected:
m_layers.set( aLayers[i] );
}
}
/**
* Function viewRequiredUpdate()
* Returns current update flag for an item.
*/
virtual int viewRequiredUpdate() const
{
return m_requiredUpdate;
}
/**
* Function clearUpdateFlags()
* Marks an item as already updated, so it is not going to be redrawn.
*/
void clearUpdateFlags()
{
m_requiredUpdate = NONE;
}
};
} // namespace KIGFX

View File

@ -746,20 +746,20 @@ void MODULE::ViewUpdate( int aUpdateFlags )
if( !m_view )
return;
// Update the module itself
VIEW_ITEM::ViewUpdate( aUpdateFlags );
// Update pads
for( D_PAD* pad = m_Pads.GetFirst(); pad; pad = pad->Next() )
m_view->InvalidateItem( pad, aUpdateFlags );
pad->ViewUpdate( aUpdateFlags );
// Update module's drawing (mostly silkscreen)
for( BOARD_ITEM* drawing = m_Drawings.GetFirst(); drawing; drawing = drawing->Next() )
m_view->InvalidateItem( drawing, aUpdateFlags );
drawing->ViewUpdate( aUpdateFlags );
// Update module's texts
m_view->InvalidateItem( m_Reference, aUpdateFlags );
m_view->InvalidateItem( m_Value, aUpdateFlags );
// Update the module itself
m_view->InvalidateItem( this, aUpdateFlags );
m_Reference->ViewUpdate( aUpdateFlags );
m_Value->ViewUpdate( aUpdateFlags );
}