/// <summary> /// Optimization phase /// </summary> /// <param name="commands"></param> /// <param name="count"></param> /// <param name="disjoint"></param> private void DisplayListOptimization(List <PrimitiveInfo> commands, int count, bool disjoint) { #if DEBUG Console.WriteLine(); Console.WriteLine("Start 3: Display list optimization"); Console.WriteLine(); #endif List <int> [] oldUnderlay = null; if (!disjoint) // If not in a subtree which needs full flattening { // The following optimization may change PrimitiveInfo.underlay, but this is needed // for cluster calcuation. So we make a copy of it for use within this routine only oldUnderlay = CopyUnderlay(count, commands); // These optimizations need to run in a seperate pass, because they may affect other primitives for (int i = 0; i < count; i++) { repeat: PrimitiveInfo pi = commands[i]; if (pi == null) { continue; } // Optimization: If a primitive is covered by an opaque primtive, delete it if (pi.overlap != null) { bool deleted = false; for (int j = 0; j < pi.overlap.Count; j++) { PrimitiveInfo qi = commands[pi.overlap[j]]; if (qi.primitive.IsOpaque && qi.FullyCovers(pi)) { DeleteCommand(i); deleted = true; break; } } if (deleted) { continue; } } // Optimization: If a primitive is covered by overlap[0], blend brush and switch order // This results in smaller area being rendered as blending of two brushes. if ((pi.overlap != null) && (pi.overlap.Count != 0)) { int j = pi.overlap[0]; // first overlapping primitive PrimitiveInfo pj = commands[j]; // Do not attempt to blend if both primitives cover exactly same area, since blending // one into the other provides no benefits. if ((pj.underlay[pj.underlay.Count - 1] == i) && pj.FullyCovers(pi) && !pi.FullyCovers(pj)) { if (BlendCommands(pi, pj)) { SwitchCommands(commands, i, pi, j, pj, true); goto repeat; // pj at position i needs to be processed } } } // Optimization: Delete white primitives with nothing underneath if ((pi.underlay == null) && DisplayList.IsWhitePrimitive(pi.primitive)) { DeleteCommand(i); continue; } // Optimization: If a transparent primitive is covered underneath by an opaque primitive, cut its ties with all primitives before it ReduceTie(pi, commands, i); // Transparent primitive if (!pi.primitive.IsOpaque) { // Optimization: If a transparent primitive is covered underneath immediately by an opaque primitive, // or has nothing underneath, convert it to opaque primitive if (!ConvertTransparentOnOpaque(commands, i)) { PushTransparencyDown(commands, i); } } } for (int i = 0; i < count; i++) { PrimitiveInfo pi = commands[i]; if (pi == null) { continue; } // Optimization: If a primitive is covered by all opaque primitives, cut its ties with primitive on top of it. // This check is also implemented in PrimitiveRender.FindIntersection, // in which it is on a remaing items in overlapping list. // With overlapHasTransparency flag, it can be moved forward. if ((pi.overlap != null) && (pi.overlapHasTransparency == 0)) { foreach (int j in pi.overlap) { commands[j].underlay.Remove(i); } pi.overlap = null; } // Optimization: If an opaque primitive is covered by all opaque primitives, cut its ties with primitives under it. if ((pi.underlay != null) && (pi.overlapHasTransparency == 0) && pi.primitive.IsOpaque) { foreach (int j in pi.underlay) { commands[j].overlap.Remove(i); } pi.underlay = null; } } } List <Cluster> transparentCluster = Cluster.CalculateCluster(commands, count, disjoint, oldUnderlay); Cluster.CheckForRasterization(transparentCluster, commands); #if DEBUG if (HasUnmanagedCodePermission()) { LogInterestingPrimitives(commands, count, transparentCluster); SaveInterestingPrimitives(commands, count, transparentCluster); } #endif }