/// <summary> /// Carga de contenido gráfico /// </summary> protected override void LoadContent() { base.LoadContent(); // Información del componente BuildingComponentInfo componentInfo = BuildingComponentInfo.Load(this.ComponentsDirectory + this.ComponentInfoName); // Modelo this.m_ModelName = componentInfo.Model; if (!g_ModelDictionary.ContainsKey(componentInfo.Model)) { Model model = Content.Load <Model>(this.ComponentsDirectory + this.m_ModelName); PrimitiveInfo primitives = model.Tag as PrimitiveInfo; GeometryInfo geometry = new GeometryInfo() { Model = model, Primitives = primitives, }; g_ModelDictionary.Add(this.m_ModelName, geometry); } CollisionBox obb = new CollisionBox(this.TriangleInfo.AABB, 1000000f); this.m_CollisionPrimitive = obb; this.m_Offset = Matrix.CreateTranslation(new Vector3(0f, -obb.HalfSize.Y, 0f)); // Controles de animación this.m_AnimationController.AddRange(Animation.CreateAnimationList(this.Model, componentInfo.AnimationControlers)); // Transformaciones iniciales this.m_BoneTransforms = new Matrix[Model.Bones.Count]; }
// Find the next Primitive having intersection with cur in overlapping list private bool FindIntersection(Geometry cur, ref int start, out PrimitiveInfo topPI, out Geometry topBounds, out Geometry inter) { topPI = null; topBounds = null; inter = null; if (_overlapping == null) { return(false); } // If not in a subtree which needs composition, igore overlapping list if all are opaque if (!_disjoint) { bool allopaque = true; for (int s = start; s < _overlapping.Count; s++) { PrimitiveInfo pi = _commands[_overlapping[s]] as PrimitiveInfo; if ((pi != null) && !pi.primitive.IsTransparent && !pi.primitive.IsOpaque) { allopaque = false; break; } } if (allopaque) { return(false); } } // Search for all possible intersections while (start < _overlapping.Count) { topPI = _commands[_overlapping[start]] as PrimitiveInfo; if (!topPI.primitive.IsTransparent) // Skip primitives with nothing to draw { topBounds = topPI.primitive.GetClippedShapeGeometry(); if (topBounds != null) { bool empty; inter = Utility.Intersect(cur, topBounds, Matrix.Identity, out empty); if (inter != null) { return(true); } } } start++; } return(false); }
/// <summary> /// Remove a primitive from display list /// </summary> /// <param name="i"></param> private void DeleteCommand(int i) { #if DEBUG Console.WriteLine("Delete command {0}", i); #endif PrimitiveInfo pi = _dl.Commands[i]; if (pi.overlap != null) { foreach (int j in pi.overlap) { _dl.Commands[j].underlay.Remove(i); } } if (pi.underlay != null) { bool trans = !pi.primitive.IsOpaque; foreach (int j in pi.underlay) { if (trans) { _dl.Commands[j].overlapHasTransparency--; } _dl.Commands[j].overlap.Remove(i); } } _dl.Commands[i] = null; }
/// <summary> /// Optimization: If a transparent primitive is covered underneath by an opaque primitive, cut its ties with all primitives before it /// </summary> /// <param name="pi"></param> /// <param name="commands"></param> /// <param name="i"></param> private static void ReduceTie(PrimitiveInfo pi, List <PrimitiveInfo> commands, int i) { if ((pi.underlay != null) && !pi.primitive.IsOpaque) { int len = pi.underlay.Count; for (int j = len - 1; j >= 0; j--) { PrimitiveInfo qi = commands[pi.underlay[j]]; if (qi.primitive.IsOpaque && qi.FullyCovers(pi)) { for (int k = j - 1; k >= 0; k--) { int under = pi.underlay[k]; commands[under].overlap.Remove(i); commands[under].overlapHasTransparency--; pi.underlay.Remove(under); } break; } } } }
public int GetLiteralIndex(object constant) { int index; if (constant is string text) { var stringInfo = new StringInfo((ushort)GetUtf8Index(text)); if (!_stringInfos.TryGetValue(stringInfo, out index)) { index = AddConstant(stringInfo); _stringInfos.Add(stringInfo, index); } } else { var primitiveInfo = new PrimitiveInfo(constant); if (!_primitiveInfos.TryGetValue(primitiveInfo, out index)) { index = AddConstant(primitiveInfo); _primitiveInfos.Add(primitiveInfo, index); } } return(index); }
/// <summary> /// Switch commands [i] [j], when i is covered by j /// </summary> /// <param name="commands">Display list</param> /// <param name="i">first command</param> /// <param name="pi">commands[i]</param> /// <param name="j">second command</param> /// <param name="pj">command[j]</param> /// <param name="disconnect">Disconnect (i,j) overlap/underlay relationship</param> static private void SwitchCommands(List <PrimitiveInfo> commands, int i, PrimitiveInfo pi, int j, PrimitiveInfo pj, bool disconnect) { if ((pi != null) && (pj != null) && disconnect) { pi.overlap.Remove(j); if (!pj.primitive.IsOpaque) { pi.overlapHasTransparency--; } pj.underlay.Remove(i); } if (pi != null) { if (pi.overlap != null) { foreach (int k in pi.overlap) { commands[k].underlay.Remove(i); commands[k].underlay.Add(j); } } if (pi.underlay != null) { foreach (int k in pi.underlay) { commands[k].overlap.Remove(i); commands[k].overlap.Add(j); } } } if (pj != null) { if (pj.overlap != null) { foreach (int k in pj.overlap) { commands[k].underlay.Remove(j); commands[k].underlay.Add(i); } } if (pj.underlay != null) { foreach (int k in pj.underlay) { commands[k].overlap.Remove(j); commands[k].overlap.Add(i); } } } commands[i] = pj; commands[j] = pi; }
/// <summary> /// Add a primitve to display list /// </summary> /// <param name="p"></param> public void RecordPrimitive(Primitive p) { if (null == _commands) { _commands = new List <PrimitiveInfo>(); } int index = _commands.Count; PrimitiveInfo info = new PrimitiveInfo(p); // Skip empty and totally clipped primitive bool skip = !Utility.IsRenderVisible(info.bounds) || Utility.Disjoint(p.Clip, info.bounds); if (!skip) { if (!m_DisJoint && (index == 0)) { // Skip white objects in the front skip = IsWhitePrimitive(p); } if (!skip) { _commands.Add(info); } } if ((p.Clip != null) && Utility.IsRectangle(p.Clip)) { Rect bounds = p.Clip.Bounds; if ((bounds.Left <= 0) && (bounds.Top <= 0) && (bounds.Right >= m_width) && (bounds.Bottom >= m_height)) { // Remove page full clipping p.Clip = null; } else if ((bounds.Left <= info.bounds.Left) && (bounds.Top <= info.bounds.Top) && (bounds.Right >= info.bounds.Right) && (bounds.Bottom >= info.bounds.Bottom)) { // Remove clipping larger than primitive p.Clip = null; } } #if DEBUG if (skip && (Configuration.Verbose >= 2)) { Console.Write("skip "); PrintPrimitive(info, index, true); } #endif }
public bool Equals(PrimitiveInfo x, PrimitiveInfo y) { if (ReferenceEquals(x, y)) { return(true); } if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) { return(false); } return(x.Value == y.Value); }
public void ReportOverlapping(int one, int two) { if (one > two) { int t = one; one = two; two = t; } PrimitiveInfo pi = _commands[one]; if (pi.overlap == null) { pi.overlap = new List <int>(); } if (OrderedInsert(pi.overlap, two)) { PrimitiveInfo qi = _commands[two]; if (!qi.primitive.IsTransparent && !qi.primitive.IsOpaque) { pi.overlapHasTransparency++; } // if (! qi.primitive.IsOpaque) // Remember primitves covered by a primitive having transparency { if (qi.underlay == null) { qi.underlay = new List <int>(); } OrderedInsert(qi.underlay, one); } } #if DEBUG if (Configuration.Verbose >= 2) { Console.Write(" <{0} {1}>", one, two); overlapcount++; if (overlapcount >= 10) { Console.WriteLine(); overlapcount = 0; } } #endif }
/// <summary> /// Bug 1687865 /// Special optimization for annotation type of visual: lots of glyph runs covered by a single transparency geometry /// t1 ... tn g => t1 ... tn-1 g tn' /// => g t1' ... tn' /// </summary> /// <param name="commands"></param> /// <param name="j"></param> private static void PushTransparencyDown(List <PrimitiveInfo> commands, int j) { PrimitiveInfo pj = commands[j]; GeometryPrimitive gj = pj.primitive as GeometryPrimitive; if ((gj == null) || (pj.underlay == null) || (pj.underlay.Count == 0)) { return; } for (int n = pj.underlay.Count - 1; n >= 0; n--) { int i = pj.underlay[n]; PrimitiveInfo pi = commands[i]; if (pi == null) { continue; } GeometryPrimitive gi = pi.primitive as GeometryPrimitive; if ((gi != null) && (gi.Pen == null) && (pi.overlap.Count == 1) && pj.FullyCovers(pi)) { // c[i] ... c[j] => ... c[j] c[i]' if (BlendCommands(pi, pj)) // pi.Brush = Blend(pi.Brush, pj.Brush) { pj.underlay.Remove(i); pi.overlap = null; pi.overlapHasTransparency = 0; while (i < j) { SwitchCommands(commands, i, commands[i], i + 1, commands[i + 1], false); i++; } j--; } } } }
internal void LogInterestingPrimitives(List <PrimitiveInfo> commands, int count, List <Cluster> transparentCluster) { if (Configuration.Verbose >= 1) { // Display only interesting primitives DisplayList.PrintPrimitive(null, -1, false); Rect target = Rect.Empty; int vip = 0; for (int i = 0; i < count; i++) { PrimitiveInfo pi = commands[i]; if ((pi != null) && ((pi.overlapHasTransparency != 0) || !pi.primitive.IsOpaque)) { if (!pi.primitive.IsOpaque) { target.Union(pi.bounds); } DisplayList.PrintPrimitive(commands[i], i, false); vip++; } } Console.WriteLine(); Console.WriteLine("Interesting primitives: {0}", vip); Console.WriteLine("Area with transparency: {0}", DisplayList.LeftPad(target, 0)); Console.WriteLine(); for (int i = 0; i < transparentCluster.Count; i++) { Console.WriteLine( "Cluster {0}: {1} {2} {3}", i + 1, DisplayList.LeftPad(transparentCluster[i].DebugBounds, 0), DisplayList.LeftPad(transparentCluster[i].DebugPrimitives, 0), transparentCluster[i].DebugRasterize); } Console.WriteLine(); } }
private static bool BlendCommands(PrimitiveInfo pi, PrimitiveInfo pj) { GeometryPrimitive gi = pi.primitive as GeometryPrimitive; GeometryPrimitive gj = pj.primitive as GeometryPrimitive; if ((gi != null) && (gi.Brush != null) && (gj != null) && (gj.Brush != null)) { // get brushes in world space BrushProxy bi = gi.Brush.ApplyTransformCopy(gi.Transform); BrushProxy bj = gj.Brush.ApplyTransformCopy(gj.Transform); gi.Brush = bi.BlendBrush(bj); return(true); } return(false); }
public BVH(Bounds[] bounds, Matrix4x4[] transformPositions, ref List <RayTracingSubscriber> subs) { /* * TODO: 1) Create the primInfo for each mesh 2) create the Tree with pointer and SAH 3) Linearize */ this.subs = subs; primitivesInfo = new List <PrimitiveInfo>(transformPositions.Length); for (int i = 0; i < transformPositions.Length; i++) { PrimitiveInfo info = new PrimitiveInfo() { bounds = bounds[i], primitiveIndex = i }; primitivesInfo.Add(info); } for (int i = 0; i < nBuckets; i++) { buckets[i] = new BucketInfo(); } List <RayTracingSubscriber> orderedInfos = new List <RayTracingSubscriber>(primitivesInfo.Count); root = RecursiveBuild(0, primitivesInfo.Count, ref orderedInfos); // primitivesInfo = orderedInfos; subs.Clear(); subs.AddRange(orderedInfos); flatTree = new LBVH[nodeCreated]; int offset = 0; FlattenTree(root, ref offset); }
public int GetHashCode(PrimitiveInfo obj) { return(obj.GetHashCode()); }
/// <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); }
/// <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); }
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); }
// Recursive // _brush must be in world space private void FillGeometry( PrimitiveInfo topPI, Geometry cur, string desp, Geometry curAlt, string despAlt, int start, Geometry inter, Geometry topBounds ) { Primitive p = topPI.primitive; Geometry diff = Utility.Exclude(cur, topBounds, Matrix.Identity); if (diff != null) { // Render cur [- topBounds] using original brush if (_disjoint) { #if DEBUG FillGeometry(diff, Oper(desp, '-', topPI.id), null, null, start + 1); #else FillGeometry(diff, null, null, null, start + 1); #endif } else { // Only diff = cur - topBounds need to be rendered. But it may generate more // complicated path and gaps between objects if (curAlt != null) { #if DEBUG FillGeometry(diff, Oper(desp, '-', topPI.id), curAlt, despAlt, start + 1); #else FillGeometry(diff, null, curAlt, despAlt, start + 1); #endif } else { #if DEBUG FillGeometry(diff, Oper(desp, '-', topPI.id), cur, desp, start + 1); #else FillGeometry(diff, null, cur, desp, start + 1); #endif } } } //if (_disjoint || ! p.IsOpaque) { if (topPI.primitive is ImagePrimitive) { // If primitve on the top is ImagePrimitive, change it to DrawImage with blended image. // An alternative will be generating an image brush ImagePrimitive ip = topPI.primitive as ImagePrimitive; bool empty; double imageWidth = ip.Image.Image.Width; double imageHeight = ip.Image.Image.Height; // Get clip in world space. Geometry clip = Utility.Intersect(inter, Utility.TransformGeometry(new RectangleGeometry(ip.DstRect), ip.Transform), ip.Transform, out empty); if (!empty) { // Get clip bounds in image space. Geometry clipImageSpace = Utility.TransformGeometry(clip, ReverseMap(ip.Transform, ip.DstRect, imageWidth, imageHeight)); Rect drawBounds = clipImageSpace.Bounds; // Clip image data to the intersection. Resulting draw bounds are in image space. BitmapSource clippedImage = ip.Image.GetClippedImage(drawBounds, out drawBounds); if (clippedImage != null) { // Transform draw bounds back to world space. drawBounds.Scale(ip.DstRect.Width / imageWidth, ip.DstRect.Height / imageHeight); drawBounds.Offset(ip.DstRect.Left, ip.DstRect.Top); ImageProxy image = new ImageProxy(clippedImage); // Blend image with other brush, then render composited image. image.BlendOverBrush(false, _brush, ReverseMap(ip.Transform, drawBounds, image.PixelWidth, image.PixelHeight)); #if DEBUG RenderImage(image, drawBounds, clip, true, start + 1, ip.Transform, Oper(desp, '*', topPI.id)); #else RenderImage(image, drawBounds, clip, true, start + 1, ip.Transform, null); #endif } } } else { // -- If top primitive opaque, skip the intersection // -- If current primitive is completely covered by an opaque object, skip the intersection if (p.IsOpaque) // && Utility.Covers(topBounds, cur)) { cur = null; } else { // Render the intersection using blended brush BrushProxy oldbrush = _brush; _brush = p.BlendBrush(_brush); #if DEBUG FillGeometry(inter, Oper(desp, '*', topPI.id), null, null, start + 1); #else FillGeometry(inter, null, null, null, start + 1); #endif _brush = oldbrush; } } if (cur != null) { bool empty; Geometry geo = Utility.Intersect(cur, _clip, Matrix.Identity, out empty); if (geo != null) { topPI.primitive.Exclude(geo); // exclude cur & _clip #if DEBUG topPI.id = Oper(topPI.id, '-', Oper(desp, '*', Oper(desp, '.', "c"))); #endif } } } }
static internal void PrintPrimitive(PrimitiveInfo info, int index, bool verbose) { if (index < 0) { Console.WriteLine(); Console.WriteLine(" No Type Und Ovr TrO Bounding Box Clipping"); if (verbose) { Console.Write(" Transform"); } Console.WriteLine(); return; } Primitive p = info.primitive; string typ = p.GetType().ToString(); typ = typ.Substring(typ.LastIndexOf('.') + 1); Console.Write(LeftPad(index, 4) + LeftPad(typ, 18) + ":"); List <int> extra = null; if (p.IsOpaque) { Console.Write(' '); } else { Console.Write('@'); } if (info.underlay == null) { Console.Write(" "); } else { extra = info.underlay; Console.Write(LeftPad(info.underlay.Count, 3)); } if (info.overlap != null) { Console.Write(' ' + LeftPad(info.overlap.Count, 3)); if (info.overlapHasTransparency != 0) { Console.Write('$'); Console.Write(LeftPad(info.overlapHasTransparency, 3)); } else { Console.Write(" "); } Console.Write(' '); } else { Console.Write(" "); } Console.Write(LeftPad(info.bounds, 0)); Geometry clip = p.Clip; if (clip != null) { Console.Write(LeftPad(clip.Bounds, 0)); } if (verbose) { Matrix m = p.Transform; Console.Write(" {"); Console.Write(LeftPad(m.M11, 3) + ' '); Console.Write(LeftPad(m.M12, 3) + ' '); Console.Write(LeftPad(m.M21, 3) + ' '); Console.Write(LeftPad(m.M22, 3) + ' '); Console.Write(LeftPad(m.OffsetX, 6) + ' '); Console.Write(LeftPad(m.OffsetY, 6)); Console.Write("} "); } if (verbose) { GlyphPrimitive gp = p as GlyphPrimitive; if (gp != null) { IList <char> chars = gp.GlyphRun.Characters; Console.Write(" \""); for (int i = 0; i < chars.Count; i++) { Console.Write(chars[i]); } Console.Write('"'); } } if (verbose) { GeometryPrimitive gp = p as GeometryPrimitive; if ((gp != null) && (gp.Brush != null) && (gp.Pen == null)) { Brush b = gp.Brush.Brush; if (b != null) { SolidColorBrush sb = b as SolidColorBrush; if (sb != null) { Console.Write(" SolidColorBrush({0})", sb.Color); } } } } if (extra != null) { Console.Write(' '); Console.Write(LeftPad(extra, 0)); } Console.WriteLine(); }
/// <summary> /// Resolve object overlapping in a primitive tree. /// Send broken down drawing primitives to _dc. /// </summary> /// <param name="dc"></param> /// <param name="disjoint">True if all output primitives need to be disjoint</param> public void AlphaFlatten(IProxyDrawingContext dc, bool disjoint) { List <PrimitiveInfo> commands = _dl.Commands; if (commands == null) { return; } int count = commands.Count; _dc = dc; bool needFlattening = true; if (Configuration.BlendAlphaWithWhite || Configuration.ForceAlphaOpaque) { needFlattening = false; } else if (!disjoint) { needFlattening = false; for (int i = 0; i < count; i++) { PrimitiveInfo info = commands[i]; if (!info.primitive.IsOpaque) { needFlattening = true; break; } } } if (needFlattening) { #if DEBUG Console.WriteLine(); Console.WriteLine("Stage 2: Calculating intersections using bounding boxes"); Console.WriteLine(); #endif // Still need all the primitive, for removal by opaque covering and white primitive removal _dl.CalculateIntersections(count); } #if DEBUG if (Configuration.Verbose >= 2) { Console.WriteLine(); Console.WriteLine("Original display list"); Console.WriteLine(); DisplayList.PrintPrimitive(null, -1, true); for (int i = 0; i < count; i++) { DisplayList.PrintPrimitive(commands[i], i, true); } Console.WriteLine(); Console.WriteLine("Primitives in display list: {0}", count); Console.WriteLine(); } #endif if (needFlattening) { DisplayListOptimization(commands, count, disjoint); } #if DEBUG for (int i = 0; i < count; i++) { if (commands[i] != null) { commands[i].SetID(i); } } Console.WriteLine(); Console.WriteLine("Stage 4: Alpha flattening"); Console.WriteLine(); #endif for (int i = 0; i < count; i++) { PrimitiveInfo info = commands[i]; if (info == null) { continue; } String desp = null; #if DEBUG if (Configuration.Verbose >= 2) { Console.Write(i); Console.Write(": "); } desp = info.id; #endif if (info.m_cluster != null) { info.m_cluster.Render(commands, dc); } else { AlphaRender(info.primitive, info.overlap, info.overlapHasTransparency, disjoint, desp); } #if DEBUG if (Configuration.Verbose >= 2) { Console.WriteLine(""); } #endif } _dc = null; }
/// <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 }
/// <summary> /// Optimization: If a transparent primitive is covered underneath immediately by an opaque primitive, /// or has nothing underneath, convert it to opaque primitive /// </summary> /// <param name="commands"></param> /// <param name="i"></param> private static bool ConvertTransparentOnOpaque(List <PrimitiveInfo> commands, int i) { PrimitiveInfo pi = commands[i]; GeometryPrimitive gp = pi.primitive as GeometryPrimitive; if (gp != null) { PrimitiveInfo qi = null; if ((pi.underlay != null) && (pi.underlay.Count != 0)) { qi = commands[pi.underlay[pi.underlay.Count - 1]]; } if ((qi == null) || (qi.primitive.IsOpaque && qi.FullyCovers(pi))) { BrushProxy under = BrushProxy.CreateColorBrush(Colors.White); if (qi != null) { GeometryPrimitive qp = qi.primitive as GeometryPrimitive; if (qp != null) { under = qp.Brush; } } if (under != null) { // Blend it with brush underneath BrushProxy blendedBrush = gp.Brush; BrushProxy blendedPenBrush = gp.Pen == null ? null : gp.Pen.StrokeBrush; if (blendedBrush != null) { blendedBrush = under.BlendBrush(blendedBrush); } else if (blendedPenBrush != null) { blendedPenBrush = under.BlendBrush(blendedPenBrush); } // // Fix bug 1293500: // Allow blending to proceed only if we did not generate pen stroke // brush that is a brush list. Reason: Such a case would have to be // handled during rendering by stroking the object with each brush // in the list. But we're already rendering brushes of underlying // objects, so the optimization is pointless. // bool proceedBlending = true; if (blendedPenBrush != null && blendedPenBrush.BrushList != null) { proceedBlending = false; } if (proceedBlending) { gp.Brush = blendedBrush; if (gp.Pen != null) { gp.Pen.StrokeBrush = blendedPenBrush; } } if (proceedBlending && pi.primitive.IsOpaque) { #if DEBUG Console.WriteLine("Make {0} opaque", i); #endif if (pi.underlay != null) { for (int k = 0; k < pi.underlay.Count; k++) { commands[pi.underlay[k]].overlapHasTransparency--; } } return(true); } } } } return(false); }
/// <summary> /// Carga de contenido gráfico /// </summary> protected override void LoadContent() { base.LoadContent(); // Información del componente VehicleComponentInfo componentInfo = VehicleComponentInfo.Load(Path.Combine(this.AssetsFolder, this.ComponentInfoName)); // Modelo this.m_ModelName = componentInfo.Model; if (!g_ModelDictionary.ContainsKey(componentInfo.Model)) { Model model = Content.Load <Model>(Path.Combine(this.AssetsFolder, this.m_ModelName)); PrimitiveInfo primitives = model.Tag as PrimitiveInfo; GeometryInfo geometry = new GeometryInfo() { Model = model, Primitives = primitives, }; g_ModelDictionary.Add(this.m_ModelName, geometry); } CollisionBox box = new CollisionBox(this.TriangleInfo.AABB, 1000f); this.m_CollisionPrimitive = box; this.m_Offset = Matrix.CreateTranslation(new Vector3(0f, -box.HalfSize.Y, 0f)); // Integridad this.BaseHull = this.Hull = componentInfo.Hull; // Blindaje this.BaseArmor = this.Armor = componentInfo.Armor; // Altura máxima de vuelo this.Engine.InitialMaxFlightHeight = componentInfo.MaxFlightHeight; // Altura mínima de vuelo this.Engine.InitialMinFlightHeight = componentInfo.MinFlightHeight; // Velocidad máxima que puede alcanzar el vehículo hacia delante this.Engine.MaxForwardVelocity = componentInfo.MaxForwardVelocity; // Velocidad máxima que puede alcanzar el vehículo marcha atrás this.Engine.MaxBackwardVelocity = componentInfo.MaxBackwardVelocity; // Modificador de aceleración this.Engine.AccelerationModifier = componentInfo.AccelerationModifier; // Modificador de frenado this.Engine.BrakeModifier = componentInfo.BrakeModifier; // Velocidad angular this.Engine.AngularVelocityModifier = MathHelper.ToRadians(componentInfo.AngularVelocityModifier); // Vehículo volador this.Engine.Skimmer = componentInfo.Skimmer; // Altura máxima this.Engine.MaxFlightHeight = componentInfo.MaxFlightHeight; // Altura mínima this.Engine.MinFlightHeight = componentInfo.MinFlightHeight; // Rotación ascendente del morro this.Engine.AscendingAngle = MathHelper.ToRadians(componentInfo.AscendingAngle); // Rotación descendente del morro this.Engine.DescendingAngle = MathHelper.ToRadians(componentInfo.DescendingAngle); // Controles de animación this.m_AnimationController.AddRange(Animation.Animation.CreateAnimationList(this.Model, componentInfo.AnimationControlers)); // Posiciones this.m_PlayerControlList.AddRange(Animation.PlayerPosition.CreatePlayerPositionList(this.Model, componentInfo.PlayerPositions)); // Armas this.m_WeapontList.AddRange(Weapon.CreateWeaponList(this.Model, componentInfo.Weapons)); // Emisores de partículas this.m_ParticleEmitterList.AddRange(ParticleEmitter.CreateParticleEmitterList(this.Model, componentInfo.ParticleEmitters)); // Transformaciones iniciales this.m_BoneTransforms = new Matrix[this.Model.Bones.Count]; }
internal void SaveInterestingPrimitives(List <PrimitiveInfo> commands, int count, List <Cluster> transparentCluster) { if (Configuration.SerializePrimitives) { // render primitives to DrawingVisual DrawingVisual dv = new DrawingVisual(); using (DrawingContext ctx = dv.RenderOpen()) { Pen black = new Pen(Brushes.Black, 0.8); black.DashStyle = DashStyles.Dash; for (int i = 0; i < count; i++) { PrimitiveInfo pi = commands[i]; if ((pi != null) && ((pi.overlapHasTransparency != 0) || !pi.primitive.IsOpaque)) { pi.primitive.OnRender(ctx); if (!pi.primitive.IsOpaque) { ctx.DrawRectangle(null, black, pi.bounds); } // Rect bounds = pi.bounds; // Console.WriteLine("<RectangleGeometry Canvas.Left=\"{0}\" Canvas.Top=\"{1}\" Width=\"{2}\" Height=\"{3}\" Fill=\"#FFFFFFFF\" />", // bounds.Left, bounds.Top, bounds.Width, bounds.Height); } } Pen pen = new Pen(Brushes.Blue, 0.8); pen.DashStyle = DashStyles.Dot; for (int i = 0; i < transparentCluster.Count; i++) { ctx.DrawRectangle(null, pen, transparentCluster[i].DebugBounds); } } // save visual to xaml string name = "vip.xaml"; for (int i = 0; (name != null) && (i < 10); i++) { try { if (vipID != 0) { name = "vip" + vipID + ".xaml"; } SerializeVisual(dv, _dl.m_width, _dl.m_height, name); Console.WriteLine("Serialized primitives to " + name); name = null; } catch (System.IO.IOException e) { Console.WriteLine(e.ToString()); name = "vip" + vipID + ".xaml"; } vipID++; } } }