public static void ExportSvg(PLGObject o, string savePath, int pad = 0) { // create basic svg doc XNamespace svgNs = XNamespace.Get("http://www.w3.org/2000/svg"); XDocument svgDoc = new XDocument( new XDeclaration("1.0", "UTF-8", "yes"), new XElement(svgNs + "svg", new XAttribute("width", o.Width), new XAttribute("height", o.Height), new XAttribute("viewBox", $"{o.xmin} {o.ymin} {o.Width} {o.Height}"), new XElement("title", o.Name))); XElement f = new XElement("g", new XAttribute("name", "faces")); XElement v = new XElement("g", new XAttribute("name", "verts")); // create faces foreach (PLGPoint[] face in o.Faces) { XElement xef = new XElement("polygon", new XAttribute("points", string.Join(" ", face.Select(pt => $"{pt.x},{pt.y}")))); f.Add(xef); } // create verts foreach (PLGPoint p in o.Verts) { XElement xep = new XElement("circle", new XAttribute("cx", p.x), new XAttribute("cy", p.y), new XAttribute("r", 0.5), new XAttribute("fill", $"#{p.RGBA:x8}"), new XAttribute("unk", $"{p._field_0c:x8}"), new XAttribute("stroke", "#80808080"), new XAttribute("stroke-width", 0.2)); v.Add(xep); } svgDoc.Root.Add(f); svgDoc.Root.Add(v); // apply the same xmlns to all elements foreach (XElement e in svgDoc.Descendants()) { if (e.Name.Namespace == string.Empty) { e.Name = svgNs + e.Name.LocalName; } } svgDoc.Save($"{savePath}.svg"); }
public static void ExportPng(PLGObject o, string savePath, int pad = 40) { Image img = new Bitmap((int)o.Width + pad, (int)o.Height + pad); Graphics g = Graphics.FromImage(img); g.Clear(Color.Transparent); g.SmoothingMode = SmoothingMode.AntiAlias; foreach (PLGPoint[] face in o.Faces) { PointF[] pf = face.Select(v => new PointF(v.x - o.xmin + pad / 2, v.y - o.ymin + pad / 2)).ToArray(); g.FillPolygon(Brushes.Black, pf); g.DrawPolygon(Pens.Black, pf); } img.Save($"{savePath}.png"); }
static void ExportPly(PLGObject o, string savePath) { // ply header StringBuilder ply = new StringBuilder() .AppendLine("ply") .AppendLine("format ascii 1.0") .AppendLine($"element vertex {o.vert_count}") .AppendLine("property float x") .AppendLine("property float y") .AppendLine("property float z") .AppendLine("property uchar red") .AppendLine("property uchar green") .AppendLine("property uchar blue") .AppendLine("property uchar alpha") .AppendLine("property uint _field_0c") .AppendLine($"element face {o.Faces.Count}") .AppendLine("property list uchar int vertex_index") .AppendLine("end_header"); // add verts foreach (PLGPoint v in o.Verts) { // x y 0 r g b a ply.AppendFormat($"{v.x} {v.y} 0 {v.r} {v.g} {v.b} {v.a} {v._field_0c}") .AppendLine(); } // add faces foreach (PLGPoint[] face in o.Faces) { ply.Append($"{o.n_gon} "); foreach (PLGPoint v in face) { ply.Append($"{v.ID} "); } ply.AppendLine(); } File.WriteAllText($"{savePath}.ply", ply.ToString()); }
public PLGFile Read(BinaryReader br) { // parse header this.Header = new PLGHeader().Read(br); // parse objects for (int i = 0; i < Header.obj_count; i++) { int size = Header.obj_data_offset == 0x38 ? 0x48 : 0x40; PLGObject o = new PLGObject(size, i); this.Objects.Add(o.Read(br)); } // backup vert/face data offsets uint vdo = this.Header.vert_data_offset - this.Header.obj_data_offset; uint fdo = this.Header.faceidx_data_offset - this.Header.obj_data_offset; // parse verts and faces for (int i = 0; i < Header.obj_count; i++) { PLGObject o = Objects[i]; // workaround, all of the objects in p5's fclItem.plg have this set to 0 if (o.vert_data_offset == 0) { o.vert_data_offset = vdo; } vdo += 0x10u * o.vert_count - (uint)o.Size; // workaround, all of the objects in p5's fclItem.plg have this set to 0 if (o.faceidx_data_offset == 0) { o.faceidx_data_offset = fdo; } fdo += 0x02u * o.faceidx_count - (uint)o.Size; long currObjOffset = Header.obj_data_offset + o.Size * i; // parse verts br.BaseStream.Seek(currObjOffset + o.vert_data_offset, SeekOrigin.Begin); for (int j = 0; j < o.vert_count; j++) { o.Verts.Add(new PLGPoint(j).Read(br)); } // parse face idx br.BaseStream.Seek(currObjOffset + o.faceidx_data_offset, SeekOrigin.Begin); for (int j = 0; j < o.faceidx_count; j++) { o.FaceIdx.Add(br.ReadInt16()); } // create faces o.CreateFaceList(); if (i < this.Header.obj_count - 1) { br.BaseStream.Seek(currObjOffset + o.Size, SeekOrigin.Begin); } } return(this); }