/// <summary> /// Smooths the provided vertexsequence. Will iterate round all the vertices in the contour /// and will average out vertex positions based on thepositions of its neighbours. This will /// smooth out the edges of the contour and remove sharp angles. /// </summary> /// <param name="vs">The vertex sequence to smooth</param> private void SmoothContour(VertexSequence vs) { VertexSequence smooth = new VertexSequence(); for (int i = 0; i < vs.Count; i++) { float x = 0; float y = 0; int w = 0; for (int j = -m_smoothWeights.Length / 2; j <= m_smoothWeights.Length / 2; j++) { x += vs[i + j].x * m_smoothWeights[j + (m_smoothWeights.Length / 2)]; y += vs[i + j].y * m_smoothWeights[j + (m_smoothWeights.Length / 2)]; w += m_smoothWeights[j + (m_smoothWeights.Length / 2)]; } x /= w; y /= w; smooth.Add(new Vector2() { x = x, y = y }); } vs.CopyFrom(smooth); }
public VCGenStroke() { m_stroker = new MathStroke <T>(); m_src_vertices = new VertexSequence <T>(); m_out_vertices = new PointDVector <T>(); m_status = Status.Initial; }
public StrokeGenerator() { m_stroker = new StrokeMath(); m_src_vertices = new VertexSequence(); m_out_vertices = new Vector2Container(); m_status = StrokeMath.status_e.initial; }
public ContourGenerator() { m_stroker = new StrokeMath(); m_width = 1; m_src_vertices = new VertexSequence(); m_out_vertices = new Vector2Container(); m_status = StrokeMath.status_e.initial; m_src_vertex = 0; m_closed = false; m_orientation = 0; m_auto_detect = false; }
public ContourGenerator() { m_stroker = new StrokeMath(); m_width = 1; m_src_vertices = new VertexSequence(); m_out_vertices = new Vector2Container(); m_status = StrokeMath.status_e.initial; m_src_vertex = 0; m_closed = false; m_orientation = 0; m_auto_detect = false; }
/// <summary> /// Removes vertices from the provided vertex sequence. This will scan round all vertices in the contour /// and if the vector to and from each vertex to its neighbours is the same (i.e. 3 vertices are in a straight /// line), then the center vertex is culled. Reducing the amount of vertices in the contour but retaining the shape. /// </summary> /// <param name="vs">The vertex sequence to cull vertices from.</param> private void RemoveVertices(VertexSequence vs) { int count = 0; for (int i = 0; i < vs.Count; i++) { Vector2 a = vs[i - 1]; Vector2 b = vs[i]; Vector2 c = vs[i + 1]; //Remove b if its the same X or same Y as a and c bool abX = UnityEngine.Mathf.Approximately(a.x, b.x); bool bcX = UnityEngine.Mathf.Approximately(b.x, c.x); bool abY = UnityEngine.Mathf.Approximately(a.y, b.y); bool bcY = UnityEngine.Mathf.Approximately(b.y, c.y); if ((abX && bcX) || (abY && bcY)) { count++; vs.Remove(b); i--; } } }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolNode[] { this }); var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); // Get a list of all methods that have a method body and metadata from the metadata manager. foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping()) { MethodDesc method = mappingEntry.Entity; // The current format requires us to have an EEType for the owning type. We might want to lift this. if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType)) continue; // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail. if (!factory.MetadataManager.HasReflectionInvokeStub(method)) continue; InvokeTableFlags flags = 0; if (method.HasInstantiation) flags |= InvokeTableFlags.IsGenericMethod; if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) flags |= InvokeTableFlags.RequiresInstArg; // TODO: better check for default public(!) constructor if (method.IsConstructor && method.Signature.Length == 0) flags |= InvokeTableFlags.IsDefaultConstructor; // TODO: HasVirtualInvoke if (!method.IsAbstract) flags |= InvokeTableFlags.HasEntrypoint; // Once we have a true multi module compilation story, we'll need to start emitting entries where this is not set. flags |= InvokeTableFlags.HasMetadataHandle; // TODO: native signature for P/Invokes and NativeCallable methods if (method.IsRawPInvoke() || method.IsNativeCallable) continue; // Grammar of an entry in the hash table: // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs] Vertex vertex = writer.GetUnsignedConstant((uint)flags); if ((flags & InvokeTableFlags.HasMetadataHandle) != 0) { // Only store the offset portion of the metadata handle to get better integer compression vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataGeneration.MetadataOffsetMask))); } else { // TODO: no MD handle case } // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol))); if ((flags & InvokeTableFlags.HasEntrypoint) != 0) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex( factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific))))); } // TODO: data to generate the generic dictionary with the type loader MethodDesc invokeStubMethod = factory.MetadataManager.GetReflectionInvokeStub(method); MethodDesc canonInvokeStubMethod = invokeStubMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); if (invokeStubMethod != canonInvokeStubMethod) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.FatFunctionPointer(invokeStubMethod), FatFunctionPointerConstants.Offset) << 1)); } else { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(invokeStubMethod)) << 1)); } if ((flags & InvokeTableFlags.IsGenericMethod) != 0) { if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0) { VertexSequence args = new VertexSequence(); for (int i = 0; i < method.Instantiation.Length; i++) { uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i])); args.Append(writer.GetUnsignedConstant(argId)); } vertex = writer.GetTuple(vertex, args); } else { uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId)); } } int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } MemoryStream ms = new MemoryStream(); writer.Save(ms); byte[] hashTableBytes = ms.ToArray(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolNode[] { this, _endSymbol }); }
protected override void BuildLipForContour(GroundChunk chunk, VertexSequence contour, Material material) { //Prepare Unity Gameobject data Mesh lip = new Mesh(); lip.name = "GroundChunkLipMesh"; List <IntPoint> outerLipPath = new List <IntPoint>(); List <IntPoint> innerLipPath = new List <IntPoint>(); GameObject lipObjt = new GameObject("GroundChunkLip"); MeshFilter mf = lipObjt.AddComponent <MeshFilter>(); MeshRenderer mr = lipObjt.AddComponent <MeshRenderer>(); mf.mesh = lip; mr.material = Materials_Lips[chunk.GroundType]; //Each point the contour has 3 verts connected to the next point on the contour. The verts are in an L-Shape //It sits over the edge of the main contour mesh int totalVerts = contour.Count * 3; int totalTris = contour.Count * 4; Vector3[] verts = new Vector3[totalVerts]; Vector3[] norms = new Vector3[totalVerts]; Vector2[] uvs = new Vector2[totalVerts]; //The L-Shape has 4 tris per segment. 2 forming the rectangle on the face, 2 forming the rectangle on the "floor/roof/depth" //Everything is multiplied by 3 as its 3 verts per tri...(the verts are index) int[] tris = new int[totalTris * 3]; int t = 0; int v = 0; Vector2 previousNorm = new Vector2(); for (int i = 0; i < contour.Count; i++) { Vector2 p = contour[i - 1]; Vector2 q = contour[i]; Vector2 r = contour[i + 1]; //TODO Rotation, use p and r to work out the "normal" direciton of q so we rotate the lip correctly... Vector2 qp = (p - q).normalized; Vector2 qr = (r - q).normalized; Vector2 norm = (qp + qr).normalized; norm *= sLipSize; //Convex/Concave flip var cross = Vector2DExtensionMethods.Cross(qp, qr); if (cross < 0) { norm = -norm; } //If we have a perfectly straight line, then the normal (or bisect) will be 0,0 //So as a simple fix for this, we just copy the lip vector from the previous lip if (Mathf.Approximately(qp.x, -qr.x) && Mathf.Approximately(qp.y, -qr.y)) { norm = previousNorm; } previousNorm = norm; //Add top surface verts[v++] = new Vector3(q.x, q.y, sLipOverhang); verts[v++] = new Vector3(q.x, q.y, sLipDepth); verts[v++] = new Vector3(q.x + norm.x, q.y + norm.y, sLipOverhang); //Add outer lip point outerLipPath.Add(new IntPoint(q.x, q.y)); //Add inner lip point innerLipPath.Add(new IntPoint(q.x + norm.x, q.y + norm.y)); //Add tris to the next indices //Note - Last segment wraps round to the first indices... if (i == contour.Count - 1) { //TOP tris[t++] = v - 3; tris[t++] = v - 2; tris[t++] = 0; tris[t++] = v - 2; tris[t++] = 1; tris[t++] = 0; //LIP tris[t++] = v - 3; tris[t++] = 0; tris[t++] = 2; tris[t++] = v - 1; tris[t++] = v - 3; tris[t++] = 2; } else { //TOP tris[t++] = v - 3; tris[t++] = v - 2; tris[t++] = v; tris[t++] = v - 2; tris[t++] = v + 1; tris[t++] = v; //LIP tris[t++] = v - 3; tris[t++] = v; tris[t++] = v + 2; tris[t++] = v - 1; tris[t++] = v - 3; tris[t++] = v + 2; } } //Clipper union on the lip face in the XY-axis innerLipPath.Reverse(); var polys = Clipper.SimplifyPolygons(new List <List <IntPoint> > { outerLipPath, innerLipPath }); //Triangulate using Poly2Tri lip.vertices = verts; lip.normals = norms; lip.triangles = tris; lip.uv = uvs; lip.RecalculateNormals(); chunk.Lips.Add(lipObjt); chunk.LipMeshes.Add(lip); }
public void March(int xx, int yy, int ww, int hh, Ground ground, out Dictionary <int, GroundChunk> chunks) { chunks = new Dictionary <int, GroundChunk>(); for (int y = yy; y < yy + hh; y++) { for (int x = xx; x < xx + ww; x++) { int g = ground.Dots[y, x].Value; int c = ground.Dots[y, x].Chunk; if (g == 0 || c != 0) { continue; } //Get Left, Below and Left/Below Diag values to see if they are the same //This is used to check holes and know which chunk to assign holes too int lg = ground.Dots[y, x - 1].Value; int bg = ground.Dots[y - 1, x].Value; int lbg = ground.Dots[y - 1, x - 1].Value; bool neighbourSame = lg == g || bg == g || lbg == g; //Is this an edge int marchVal = MarchingValue(x, y, g, ground.Dots); if (marchVal != 0 && marchVal != 15) { //New edge....get the contour and either make a new Ground Chunk or assign it as a Hole to an existing one GroundChunk owner = null; int cID = 0; if (neighbourSame) { if (lg == g) { cID = ground.Dots[y, x - 1].Chunk; } else if (bg == g) { cID = ground.Dots[y - 1, x].Chunk; } else if (lbg == g) { cID = ground.Dots[y - 1, x - 1].Chunk; } else { UnityEngine.Debug.LogWarning("NO NEIGHBOUR FOUND"); } owner = ground.Chunks[cID]; } else { owner = new GroundChunk(); owner.GroundType = g; cID = owner.ID; ground.Chunks.Add(cID, owner); chunks.Add(cID, owner); } //Get Contour VertexSequence contour = FindContour(x, y, g, owner, ground); if (neighbourSame) { owner.Holes.Add(contour); } else { owner.Edge = contour; } } else if (neighbourSame) { //Mark this non edge as being "owned" by the neighbouring chunk (i.e. its inside a chunk) if (lg == g) { ground.Dots[y, x].Chunk = ground.Dots[y, x - 1].Chunk; } else if (bg == g) { ground.Dots[y, x].Chunk = ground.Dots[y - 1, x].Chunk; } else if (lbg == g) { ground.Dots[y, x].Chunk = ground.Dots[y - 1, x - 1].Chunk; } } } } }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } Dictionary <EcmaMethod, HashSet <EcmaMethod> > inlineeToInliners = new Dictionary <EcmaMethod, HashSet <EcmaMethod> >(); // Build a map from inlinee to the list of inliners // We are only interested in the generic definitions of these. foreach (MethodWithGCInfo methodNode in factory.EnumerateCompiledMethods()) { MethodDesc[] inlinees = methodNode.InlinedMethods; MethodDesc inliner = methodNode.Method; MethodDesc inlinerDefinition = inliner.GetTypicalMethodDefinition(); foreach (MethodDesc inlinee in inlinees) { MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition(); if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition)) { // We don't record non-ECMA methods because they don't have tokens that // diagnostic tools could reason about anyway. continue; } if (!inlineeToInliners.TryGetValue(ecmaInlineeDefinition, out HashSet <EcmaMethod> inliners)) { inliners = new HashSet <EcmaMethod>(); inlineeToInliners.Add(ecmaInlineeDefinition, inliners); } inliners.Add((EcmaMethod)inlinerDefinition); } } // Serialize the map as a hash table NativeWriter writer = new NativeWriter(); Section section = writer.NewSection(); VertexHashtable hashtable = new VertexHashtable(); section.Place(hashtable); foreach (var inlineeWithInliners in inlineeToInliners) { EcmaMethod inlinee = inlineeWithInliners.Key; int inlineeRid = MetadataTokens.GetRowNumber(inlinee.Handle); int hashCode = ReadyToRunHashCode.ModuleNameHashCode(inlinee.Module); hashCode ^= inlineeRid; // Format of the sequence: // Inlinee RID with flag in the lowest bit // - if flag is set, followed by module ID // Followed by inliner RIDs deltas with flag in the lowest bit // - if flag is set, followed by module ID var sig = new VertexSequence(); bool isForeignInlinee = inlinee.Module != _globalContext; sig.Append(new UnsignedConstant((uint)(inlineeRid << 1 | (isForeignInlinee ? 1 : 0)))); if (isForeignInlinee) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module))); } List <EcmaMethod> sortedInliners = new List <EcmaMethod>(inlineeWithInliners.Value); sortedInliners.Sort((a, b) => { if (a == b) { return(0); } int aRid = MetadataTokens.GetRowNumber(a.Handle); int bRid = MetadataTokens.GetRowNumber(b.Handle); if (aRid < bRid) { return(-1); } else if (aRid > bRid) { return(1); } int result = a.Module.CompareTo(b.Module); Debug.Assert(result != 0); return(result); }); int baseRid = 0; foreach (EcmaMethod inliner in sortedInliners) { int inlinerRid = MetadataTokens.GetRowNumber(inliner.Handle); int ridDelta = inlinerRid - baseRid; baseRid = inlinerRid; Debug.Assert(ridDelta >= 0); bool isForeignInliner = inliner.Module != _globalContext; sig.Append(new UnsignedConstant((uint)(ridDelta << 1 | (isForeignInliner ? 1 : 0)))); if (isForeignInliner) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module))); } } hashtable.Append((uint)hashCode, section.Place(sig)); } MemoryStream writerContent = new MemoryStream(); writer.Save(writerContent); return(new ObjectData( data: writerContent.ToArray(), relocs: null, alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this })); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } // Ensure the native layout blob has been saved factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory); var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); // Get a list of all methods that have a method body and metadata from the metadata manager. foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping(factory)) { MethodDesc method = mappingEntry.Entity; // The current format requires us to have an EEType for the owning type. We might want to lift this. if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType)) { continue; } // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail. if (!factory.MetadataManager.IsReflectionInvokable(method)) { continue; } InvokeTableFlags flags = 0; if (method.HasInstantiation) { flags |= InvokeTableFlags.IsGenericMethod; } if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) { flags |= InvokeTableFlags.RequiresInstArg; } if (method.IsDefaultConstructor) { flags |= InvokeTableFlags.IsDefaultConstructor; } if (ReflectionVirtualInvokeMapNode.NeedsVirtualInvokeInfo(method)) { flags |= InvokeTableFlags.HasVirtualInvoke; } if (!method.IsAbstract) { flags |= InvokeTableFlags.HasEntrypoint; } if (mappingEntry.MetadataHandle != 0) { flags |= InvokeTableFlags.HasMetadataHandle; } if (!factory.MetadataManager.HasReflectionInvokeStubForInvokableMethod(method)) { flags |= InvokeTableFlags.NeedsParameterInterpretation; } if (method.IsCanonicalMethod(CanonicalFormKind.Universal)) { flags |= InvokeTableFlags.IsUniversalCanonicalEntry; } // TODO: native signature for P/Invokes and NativeCallable methods if (method.IsRawPInvoke() || method.IsNativeCallable) { continue; } // Grammar of an entry in the hash table: // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs] Vertex vertex = writer.GetUnsignedConstant((uint)flags); if ((flags & InvokeTableFlags.HasMetadataHandle) != 0) { // Only store the offset portion of the metadata handle to get better integer compression vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataManager.MetadataOffsetMask))); } else { var nameAndSig = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition())); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSig.SavedVertex.VertexOffset)); } // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol))); if ((flags & InvokeTableFlags.HasEntrypoint) != 0) { bool useUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic; vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex( factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific), useUnboxingStub)))); } if ((flags & InvokeTableFlags.NeedsParameterInterpretation) == 0) { MethodDesc canonInvokeStubMethod = factory.MetadataManager.GetCanonicalReflectionInvokeStub(method); if (canonInvokeStubMethod.IsSharedByGenericInstantiations) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(((uint)factory.MetadataManager.DynamicInvokeTemplateData.GetIdForMethod(canonInvokeStubMethod) << 1) | 1)); } else { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(canonInvokeStubMethod)) << 1)); } } if ((flags & InvokeTableFlags.IsGenericMethod) != 0) { if ((flags & InvokeTableFlags.IsUniversalCanonicalEntry) != 0) { var nameAndSigGenericMethod = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSigGenericMethod.SavedVertex.VertexOffset)); } else if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0) { VertexSequence args = new VertexSequence(); for (int i = 0; i < method.Instantiation.Length; i++) { uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i])); args.Append(writer.GetUnsignedConstant(argId)); } vertex = writer.GetTuple(vertex, args); } else { uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId)); } } int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } byte[] hashTableBytes = writer.Save(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol })); }
private VertexSequence FindContour(int x, int y, int g, GroundChunk owner, Ground ground) { //Contour VertexSequence contour = new VertexSequence(); //Found a dot to trace int startx = x; int starty = y; int curx = x; int cury = y; int prevx = -1; int prevy = -1; int nextx = -1; int nexty = -1; int bits = 0; bool addPoint = true; //Predict an error with Marching Squares here bits = MarchingValue(curx, cury, g, ground.Dots); if (bits == 6 || bits == 9) { UnityEngine.Debug.LogWarning("MARCHING MIGHT CRASH"); } if (bits == 15) { UnityEngine.Debug.LogWarning("MARCHING IS STARTING IN ERROR!!!"); } do { nextx = curx; nexty = cury; bits = MarchingValue(curx, cury, g, ground.Dots); addPoint = true; switch (bits) { case 1: nexty -= 1; break; case 2: nextx += 1; break; case 3: nextx += 1; break; case 4: nextx -= 1; break; case 5: nexty -= 1; break; case 6: if (prevx == curx && prevy == cury + 1) { nextx -= 1; } else { nextx += 1; } break; //What if prev is null as we have just started, we could actually go the wrong way case 7: nextx += 1; break; case 8: nexty += 1; break; case 9: if (prevx == curx - 1 && prevy == cury) { nexty -= 1; } else { nexty += 1; } break; //What if prev is null as we have just started, we could actually go the wrong way case 10: nexty += 1; break; case 11: nexty += 1; break; case 12: nextx -= 1; break; case 13: nexty -= 1; break; case 14: nextx -= 1; break; case 15: nextx -= 1; addPoint = false; break; default: throw new ArgumentException(string.Format("Value was {0} prev was {1}, {2}", bits, prevx, prevy)); } if (addPoint) { if (contour.Count == 0) { startx = curx; starty = cury; } if (ground.Dots[cury, curx].Value == g) { ground.Dots[cury, curx].Chunk = owner.ID; } contour.Add(new Vector2() { x = curx - 0.5f, y = cury - 0.5f }); prevx = curx; prevy = cury; } curx = nextx; cury = nexty; }while (curx != startx || cury != starty); return(contour); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // Dependencies for this node are tracked by the method code nodes if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } // Ensure the native layout data has been saved, in order to get valid Vertex offsets for the signature Vertices factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory); NativeWriter nativeWriter = new NativeWriter(); VertexHashtable hashtable = new VertexHashtable(); Section nativeSection = nativeWriter.NewSection(); nativeSection.Place(hashtable); foreach (MethodDesc method in factory.MetadataManager.GetCompiledMethods()) { if (!IsMethodEligibleForTracking(method)) { continue; } // Get the method pointer vertex bool getUnboxingStub = method.OwningType.IsValueType && !method.Signature.IsStatic; IMethodNode methodEntryPointNode = factory.MethodEntrypoint(method, getUnboxingStub); Vertex methodPointer = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(methodEntryPointNode)); // Get native layout vertices for the declaring type ISymbolNode declaringTypeNode = factory.NecessaryTypeSymbol(method.OwningType); Vertex declaringType = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(declaringTypeNode)); // Get a vertex sequence for the method instantiation args if any VertexSequence arguments = new VertexSequence(); foreach (var arg in method.Instantiation) { ISymbolNode argNode = factory.NecessaryTypeSymbol(arg); arguments.Append(nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(argNode))); } // Get the name and sig of the method. // Note: the method name and signature are stored in the NativeLayoutInfo blob, not in the hashtable we build here. NativeLayoutMethodNameAndSignatureVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); NativeLayoutPlacedSignatureVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig); Debug.Assert(placedNameAndSig.SavedVertex != null); Vertex placedNameAndSigOffsetSig = nativeWriter.GetOffsetSignature(placedNameAndSig.SavedVertex); // Get the vertex for the completed method signature Vertex methodSignature = nativeWriter.GetTuple(declaringType, placedNameAndSigOffsetSig, arguments); // Make the generic method entry vertex Vertex entry = nativeWriter.GetTuple(methodSignature, methodPointer); // Add to the hash table, hashed by the containing type's hashcode uint hashCode = (uint)method.OwningType.GetHashCode(); hashtable.Append(hashCode, nativeSection.Place(entry)); } byte[] streamBytes = nativeWriter.Save(); _endSymbol.SetSymbolOffset(streamBytes.Length); return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol })); }
// TODO would be nice for this to actually review poly surface area....but for now lets keep // it super simple and just cull any contours under a certain vertex length...as we can assume they // will be too small. private bool ContourIsTooSmall(VertexSequence seq) { return((seq == null) ? true : seq.Count < cMinVertexCount); }
//-------------------------------------------------------calc_polygon_area public static double calc_polygon_area(VertexSequence st) { int i; double sum = 0.0; double x = st[0].x; double y = st[0].y; double xs = x; double ys = y; for (i = 1; i < st.size(); i++) { VertexDistance v = st[i]; sum += x * v.y - y * v.x; x = v.x; y = v.y; } return (sum + x * ys - y * xs) * 0.5; }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } Dictionary <EcmaMethod, HashSet <EcmaMethod> > inlineeToInliners = new Dictionary <EcmaMethod, HashSet <EcmaMethod> >(); // Build a map from inlinee to the list of inliners // We are only interested in the generic definitions of these. foreach (MethodWithGCInfo methodNode in factory.EnumerateCompiledMethods(_module, CompiledMethodCategory.All)) { MethodDesc[] inlinees = methodNode.InlinedMethods; MethodDesc inliner = methodNode.Method; EcmaMethod inlinerDefinition = (EcmaMethod)inliner.GetTypicalMethodDefinition(); if (inlinerDefinition.IsNonVersionable()) { // Non-versionable methods don't need to be reported continue; } // Only encode inlining info for inliners within the active module, or if cross module inline format is in use Debug.Assert(AllowCrossModuleInlines || (inlinerDefinition.Module == _module)); bool inlinerReportAllVersionsWithInlinee = !AllowCrossModuleInlines || factory.CompilationModuleGroup.CrossModuleCompileable(inlinerDefinition); foreach (MethodDesc inlinee in inlinees) { MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition(); if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition)) { // We don't record non-ECMA methods because they don't have tokens that // diagnostic tools could reason about anyway. continue; } if (inlinee.IsNonVersionable()) { // Non-versionable methods don't need to be reported continue; } if (ReportAllInlinesInSearch) { // We'll definitely track this inline } else if (factory.CompilationModuleGroup.VersionsWithMethodBody(inlineeDefinition)) { if (!inlinerReportAllVersionsWithInlinee) { // We'll won't report this method continue; } } else { Debug.Assert(factory.CompilationModuleGroup.CrossModuleInlineable(inlineeDefinition)); if (_inlineInfoType != InfoType.CrossModuleInliningForCrossModuleDataOnly) { // We'll won't report this method continue; } } if (!inlineeToInliners.TryGetValue(ecmaInlineeDefinition, out HashSet <EcmaMethod> inliners)) { inliners = new HashSet <EcmaMethod>(); inlineeToInliners.Add(ecmaInlineeDefinition, inliners); } inliners.Add((EcmaMethod)inlinerDefinition); } } // Serialize the map as a hash table NativeWriter writer = new NativeWriter(); Section section = writer.NewSection(); VertexHashtable hashtable = new VertexHashtable(); section.Place(hashtable); foreach (var inlineeWithInliners in inlineeToInliners) { EcmaMethod inlinee = inlineeWithInliners.Key; int inlineeRid = MetadataTokens.GetRowNumber(inlinee.Handle); int hashCode; if (AllowCrossModuleInlines) { // CrossModuleInlineInfo format hashCode = ReadyToRunHashCode.MethodHashCode(inlinee); } else { // InliningInfo2 format hashCode = ReadyToRunHashCode.ModuleNameHashCode(inlinee.Module); hashCode ^= inlineeRid; } var sig = new VertexSequence(); if (!AllowCrossModuleInlines) { // Format of the sequence: // FOR InliningInfo2 table format // Inlinee RID with flag in the lowest bit // - if flag is set, followed by module ID // Followed by inliner RIDs deltas with flag in the lowest bit // - if flag is set, followed by module ID Debug.Assert(_module != null); bool isForeignInlinee = inlinee.Module != _module; sig.Append(new UnsignedConstant((uint)(inlineeRid << 1 | (isForeignInlinee ? 1 : 0)))); if (isForeignInlinee) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module))); } List <EcmaMethod> sortedInliners = new List <EcmaMethod>(inlineeWithInliners.Value); sortedInliners.MergeSort((a, b) => { if (a == b) { return(0); } int aRid = MetadataTokens.GetRowNumber(a.Handle); int bRid = MetadataTokens.GetRowNumber(b.Handle); if (aRid < bRid) { return(-1); } else if (aRid > bRid) { return(1); } int result = a.Module.CompareTo(b.Module); Debug.Assert(result != 0); return(result); }); int baseRid = 0; foreach (EcmaMethod inliner in sortedInliners) { int inlinerRid = MetadataTokens.GetRowNumber(inliner.Handle); int ridDelta = inlinerRid - baseRid; baseRid = inlinerRid; Debug.Assert(ridDelta >= 0); bool isForeignInliner = inliner.Module != _module; sig.Append(new UnsignedConstant((uint)(ridDelta << 1 | (isForeignInliner ? 1 : 0)))); if (isForeignInliner) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module))); } } } else { // Format of the sequence: // FOR CrossModuleInlineInfo format // Index with 2 flags field in lowest 2 bits to define the inlinee // - If flags & 1 == 0 then index is a MethodDef RID, and if the module is a composite image, a module index of the method follows // - If flags & 1 == 1, then index is an index into the ILBody import section // - If flags & 2 == 0 then what follows is: // - Inliner RID deltas - See definition below // - if flags & 2 == 2 then what follows is: // - count of delta encoded indices into the ILBody import section // - the sequence of delta encoded indices into the ILBody import section // - Inliner RID deltas - See definition below // // Inliner RID deltas (for multi-module version bubble images (specified by the module having the READYTORUN_FLAG_MULTIMODULE_VERSION_BUBBLE flag set) // - a sequence of inliner RID deltas with flag in the lowest bit // - if flag is set, the inliner RID is followed by a module ID // - otherwise the module is the same as the module of the inlinee method // // Inliner RID deltas (for single module version bubble images) // - a sequence of inliner RID deltas bool crossModuleMultiModuleFormat = (factory.CompilationModuleGroup.GetReadyToRunFlags() & ReadyToRunFlags.READYTORUN_FLAG_MultiModuleVersionBubble) != 0; Debug.Assert(_module == null); bool isCrossModuleInlinee = !factory.CompilationModuleGroup.VersionsWithMethodBody(inlinee); Debug.Assert(!isCrossModuleInlinee || factory.CompilationModuleGroup.CrossModuleInlineable(inlinee)); EcmaMethod[] sortedInliners = new EcmaMethod[inlineeWithInliners.Value.Count]; inlineeWithInliners.Value.CopyTo(sortedInliners); sortedInliners.MergeSort((a, b) => { if (a == b) { return(0); } bool isCrossModuleInlinerA = !factory.CompilationModuleGroup.VersionsWithMethodBody(a); bool isCrossModuleInlinerB = !factory.CompilationModuleGroup.VersionsWithMethodBody(b); if (isCrossModuleInlinerA != isCrossModuleInlinerB) { if (isCrossModuleInlinerA) { return(-1); } else { return(1); } } int result; if (isCrossModuleInlinerA) { int indexA = _symbolNodeFactory.CheckILBodyFixupSignature(a).IndexFromBeginningOfArray; int indexB = _symbolNodeFactory.CheckILBodyFixupSignature(b).IndexFromBeginningOfArray; Debug.Assert(indexA != indexB); result = indexA.CompareTo(indexB); } else { int aRid = MetadataTokens.GetRowNumber(a.Handle); int bRid = MetadataTokens.GetRowNumber(b.Handle); if (aRid < bRid) { return(-1); } else if (aRid > bRid) { return(1); } result = a.Module.CompareTo(b.Module); } Debug.Assert(result != 0); return(result); }); uint crossModuleInlinerCount = 0; foreach (var method in sortedInliners) { if (factory.CompilationModuleGroup.VersionsWithMethodBody(method)) { break; } Debug.Assert(factory.CompilationModuleGroup.CrossModuleInlineable(method)); crossModuleInlinerCount++; } uint encodedInlinee; checked { uint indexOfInlinee; if (isCrossModuleInlinee) { indexOfInlinee = (uint)_symbolNodeFactory.CheckILBodyFixupSignature(inlinee).IndexFromBeginningOfArray; } else { indexOfInlinee = (uint)MetadataTokens.GetRowNumber(inlinee.Handle); } encodedInlinee = indexOfInlinee << (int)ReadyToRunCrossModuleInlineFlags.CrossModuleInlinerIndexShift; if (isCrossModuleInlinee) { encodedInlinee |= (uint)ReadyToRunCrossModuleInlineFlags.CrossModuleInlinee; } if (crossModuleInlinerCount > 0) { encodedInlinee |= (uint)ReadyToRunCrossModuleInlineFlags.HasCrossModuleInliners; } sig.Append(new UnsignedConstant(encodedInlinee)); if (crossModuleMultiModuleFormat && !isCrossModuleInlinee) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module))); } int inlinerIndex = 0; if (crossModuleInlinerCount > 0) { sig.Append(new UnsignedConstant(crossModuleInlinerCount)); uint baseIndex = 0; for (; inlinerIndex < crossModuleInlinerCount; inlinerIndex++) { var inliner = sortedInliners[inlinerIndex]; uint ilBodyIndex = (uint)_symbolNodeFactory.CheckILBodyFixupSignature(inliner).IndexFromBeginningOfArray; uint ridDelta = ilBodyIndex - baseIndex; sig.Append(new UnsignedConstant(ridDelta)); } } uint baseRid = 0; for (; inlinerIndex < sortedInliners.Length; inlinerIndex++) { var inliner = sortedInliners[inlinerIndex]; uint inlinerRid = (uint)MetadataTokens.GetRowNumber(inliner.Handle); uint ridDelta = inlinerRid - baseRid; baseRid = inlinerRid; bool isForeignInliner = inliner.Module != inlinee.Module; Debug.Assert(!isForeignInliner || crossModuleMultiModuleFormat); if (crossModuleMultiModuleFormat) { uint encodedRid = ridDelta << (int)ReadyToRunCrossModuleInlineFlags.InlinerRidShift; if (isForeignInliner) { encodedRid |= (uint)ReadyToRunCrossModuleInlineFlags.InlinerRidHasModule; } sig.Append(new UnsignedConstant(encodedRid)); if (isForeignInliner) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module))); } } else { sig.Append(new UnsignedConstant(ridDelta)); } } } } hashtable.Append((uint)hashCode, section.Place(sig)); } MemoryStream writerContent = new MemoryStream(); writer.Save(writerContent); return(new ObjectData( data: writerContent.ToArray(), relocs: null, alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this })); }
static public void shorten_path(VertexSequence vs, double s, int closed) { if (s > 0.0 && vs.size() > 1) { double d; int n = (int)(vs.size() - 2); while (n != 0) { d = vs[n].dist; if (d > s) break; vs.RemoveLast(); s -= d; --n; } if (vs.size() < 2) { vs.remove_all(); } else { n = (int)vs.size() - 1; VertexDistance prev = vs[n - 1]; VertexDistance last = vs[n]; d = (prev.dist - s) / prev.dist; double x = prev.x + (last.x - prev.x) * d; double y = prev.y + (last.y - prev.y) * d; last.x = x; last.y = y; if (!prev.IsEqual(last)) vs.RemoveLast(); vs.close(closed != 0); } } }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this })); } var writer = new NativeWriter(); var typeMapHashTable = new VertexHashtable(); Section hashTableSection = writer.NewSection(); hashTableSection.Place(typeMapHashTable); // Get a list of all methods that have a method body and metadata from the metadata manager. foreach (var mappingEntry in factory.MetadataManager.GetMethodMapping()) { MethodDesc method = mappingEntry.Entity; // The current format requires us to have an EEType for the owning type. We might want to lift this. if (!factory.MetadataManager.TypeGeneratesEEType(method.OwningType)) { continue; } // We have a method body, we have a metadata token, but we can't get an invoke stub. Bail. if (!factory.MetadataManager.HasReflectionInvokeStub(method)) { continue; } InvokeTableFlags flags = 0; if (method.HasInstantiation) { flags |= InvokeTableFlags.IsGenericMethod; } if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) { flags |= InvokeTableFlags.RequiresInstArg; } // TODO: better check for default public(!) constructor if (method.IsConstructor && method.Signature.Length == 0) { flags |= InvokeTableFlags.IsDefaultConstructor; } // TODO: HasVirtualInvoke if (!method.IsAbstract) { flags |= InvokeTableFlags.HasEntrypoint; } // Once we have a true multi module compilation story, we'll need to start emitting entries where this is not set. flags |= InvokeTableFlags.HasMetadataHandle; // TODO: native signature for P/Invokes and NativeCallable methods if (method.IsRawPInvoke() || method.IsNativeCallable) { continue; } // Grammar of an entry in the hash table: // Flags + DeclaringType + MetadataHandle/NameAndSig + Entrypoint + DynamicInvokeMethod + [NumGenericArgs + GenericArgs] Vertex vertex = writer.GetUnsignedConstant((uint)flags); if ((flags & InvokeTableFlags.HasMetadataHandle) != 0) { // Only store the offset portion of the metadata handle to get better integer compression vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)(mappingEntry.MetadataHandle & MetadataGeneration.MetadataOffsetMask))); } else { // TODO: no MD handle case } // Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted. IEETypeNode owningTypeSymbol = factory.NecessaryTypeSymbol(method.OwningType); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(owningTypeSymbol))); if ((flags & InvokeTableFlags.HasEntrypoint) != 0) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex( factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific))))); } // TODO: data to generate the generic dictionary with the type loader MethodDesc invokeStubMethod = factory.MetadataManager.GetReflectionInvokeStub(method); MethodDesc canonInvokeStubMethod = invokeStubMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); if (invokeStubMethod != canonInvokeStubMethod) { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.FatFunctionPointer(invokeStubMethod), FatFunctionPointerConstants.Offset) << 1)); } else { vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.MethodEntrypoint(invokeStubMethod)) << 1)); } if ((flags & InvokeTableFlags.IsGenericMethod) != 0) { if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0) { VertexSequence args = new VertexSequence(); for (int i = 0; i < method.Instantiation.Length; i++) { uint argId = _externalReferences.GetIndex(factory.NecessaryTypeSymbol(method.Instantiation[i])); args.Append(writer.GetUnsignedConstant(argId)); } vertex = writer.GetTuple(vertex, args); } else { uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method)); vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId)); } } int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode(); typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex)); } MemoryStream ms = new MemoryStream(); writer.Save(ms); byte[] hashTableBytes = ms.ToArray(); _endSymbol.SetSymbolOffset(hashTableBytes.Length); return(new ObjectData(hashTableBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol })); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolNode[] { this })); } // Ensure the native layout data has been saved, in order to get valid Vertex offsets for the signature Vertices factory.MetadataManager.NativeLayoutInfo.SaveNativeLayoutInfoWriter(factory); NativeWriter nativeWriter = new NativeWriter(); VertexHashtable hashtable = new VertexHashtable(); Section nativeSection = nativeWriter.NewSection(); nativeSection.Place(hashtable); foreach (var dictionaryNode in factory.MetadataManager.GetCompiledGenericDictionaries()) { MethodGenericDictionaryNode methodDictionary = dictionaryNode as MethodGenericDictionaryNode; if (methodDictionary == null) { continue; } MethodDesc method = methodDictionary.OwningMethod; Debug.Assert(method.HasInstantiation && !method.IsCanonicalMethod(CanonicalFormKind.Any)); Vertex fullMethodSignature; { // Method's containing type IEETypeNode containingTypeNode = factory.NecessaryTypeSymbol(method.OwningType); Vertex containingType = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(containingTypeNode)); // Method's instantiation arguments VertexSequence arguments = new VertexSequence(); for (int i = 0; i < method.Instantiation.Length; i++) { IEETypeNode argNode = factory.NecessaryTypeSymbol(method.Instantiation[i]); arguments.Append(nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(argNode))); } // Method name and signature NativeLayoutVertexNode nameAndSig = factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()); NativeLayoutSavedVertexNode placedNameAndSig = factory.NativeLayout.PlacedSignatureVertex(nameAndSig); Vertex placedNameAndSigVertexOffset = nativeWriter.GetUnsignedConstant((uint)placedNameAndSig.SavedVertex.VertexOffset); fullMethodSignature = nativeWriter.GetTuple(containingType, placedNameAndSigVertexOffset, arguments); } // Method's dictionary pointer Vertex dictionaryVertex = nativeWriter.GetUnsignedConstant(_externalReferences.GetIndex(dictionaryNode)); Vertex entry = nativeWriter.GetTuple(dictionaryVertex, fullMethodSignature); hashtable.Append((uint)method.GetHashCode(), nativeSection.Place(entry)); } byte[] streamBytes = nativeWriter.Save(); _endSymbol.SetSymbolOffset(streamBytes.Length); return(new ObjectData(streamBytes, Array.Empty <Relocation>(), 1, new ISymbolNode[] { this, _endSymbol })); }