/// <summary> /// Check if the whole cluster is complex enough such that rasterizing the whole thing is better than flattening it /// </summary> /// <param name="commands"></param> /// <returns></returns> private bool BetterRasterize(List <PrimitiveInfo> commands) { double clustersize = m_bounds.Width * m_bounds.Height; double diff = -Configuration.RasterizationCost(m_bounds.Width, m_bounds.Height); // Estimate cost of geometry operations (intersecting) double pathComplexity = 1; foreach (int i in m_primitives) { PrimitiveInfo pi = commands[i]; Primitive p = pi.primitive; GeometryPrimitive gp = p as GeometryPrimitive; Rect bounds = pi.GetClippedBounds(); bool rasterize = true; if (gp != null) { double complexity = 1; Geometry geo = gp.Geometry; if (geo != null) { complexity = Utility.GetGeometryPointCount(geo); // weight down the complexity of small region complexity *= bounds.Width * bounds.Height / clustersize; } BrushProxy bp = gp.Brush; if (bp == null) { bp = gp.Pen.StrokeBrush; // Widen path would at least double the points complexity *= 3; } if (complexity > 1) { pathComplexity *= complexity; if (pathComplexity > 100000) // 333 x 333 { return(true); } } if (bp != null) { Brush b = bp.Brush; if ((b != null) && ((b is SolidColorBrush) || (b is LinearGradientBrush))) { // SolidColorBrush does not need full rasterization // Vertical/Horizontal linear gradient brush does not need full rasterization rasterize = false; } } } if (rasterize) { diff += Configuration.RasterizationCost(bounds.Width, bounds.Height); if (diff > 0) { break; } } } return(diff > 0); }
/// <summary> /// Calculates list of transparent clusters, returning true if clusters added or bounding rectangles changed. /// </summary> private static bool CalculateClusterCore( List <PrimitiveInfo> commands, int count, bool disjoint, List <int> [] oldUnderlay, List <Cluster> transparentCluster, bool[] addedPrimitives // primitives added to clusters ) { bool clusterBoundsChanged = false; // Build clusters of transparent primitives for (int i = 0; i < count; i++) { PrimitiveInfo pi = commands[i]; // When disjoint is true (flattening a subtree), add all primitives to a single cluster if ((pi != null) && (disjoint || !pi.primitive.IsOpaque) && !addedPrimitives[i]) { Rect bounds = pi.GetClippedBounds(); Cluster home = null; for (int j = 0; j < transparentCluster.Count; j++) { Cluster c = transparentCluster[j]; if (disjoint || bounds.IntersectsWith(c.m_bounds)) { home = c; break; } } if (home == null) { home = new Cluster(); transparentCluster.Add(home); } Rect oldClusterBounds = home.m_bounds; home.Add(i, oldUnderlay, commands, addedPrimitives); if (!clusterBoundsChanged && oldClusterBounds != home.m_bounds) { // cluster bounds have changed clusterBoundsChanged = true; } } } // Merges clusters which touch each other bool changed; do { changed = false; for (int i = 0; i < transparentCluster.Count; i++) { for (int j = i + 1; j < transparentCluster.Count; j++) { if (transparentCluster[i].m_bounds.IntersectsWith(transparentCluster[j].m_bounds)) { transparentCluster[i].MergeWith(transparentCluster[j]); // cluster bounds have changed since merging two clusters clusterBoundsChanged = true; transparentCluster.RemoveAt(j); changed = true; break; } } } }while (changed); return(clusterBoundsChanged); }
public static List <Cluster> CalculateCluster(List <PrimitiveInfo> commands, int count, bool disjoint, List <int>[] oldUnderlay) { List <Cluster> transparentCluster = new List <Cluster>(); // indicates which primitives have been added to any cluster bool[] addedPrimitives = new bool[commands.Count]; // calculate clusters until cluster bounds stabilize while (true) { bool clusterBoundsChanged = CalculateClusterCore( commands, count, disjoint, oldUnderlay, transparentCluster, addedPrimitives ); if (!clusterBoundsChanged || GetPrimitiveIntersectAction() != PrimitiveIntersectAction.AddToCluster) { break; } // // Cluster bounds have changed somewhere, need to examine all primitives that haven't // been added to a cluster and test for intersection with cluster. We add primitives // that intersect and rendered before the cluster. // // Note that here we check even opaque primitives, since they might get covered // by a transparent cluster, and thus need to be rasterized with a cluster if intersection // exists. // for (int primIndex = 0; primIndex < addedPrimitives.Length; primIndex++) { if (!addedPrimitives[primIndex] && commands[primIndex] != null) { PrimitiveInfo primitive = commands[primIndex]; for (int clusterIndex = 0; clusterIndex < transparentCluster.Count; clusterIndex++) { Cluster cluster = transparentCluster[clusterIndex]; if (primitive.GetClippedBounds().IntersectsWith(cluster.m_bounds) && primIndex < cluster.m_lowestPrimitive) { // primitive intersects this cluster, add to cluster cluster.Add( primIndex, oldUnderlay, commands, addedPrimitives ); } } } } } return(transparentCluster); }