Esempio n. 1
0
 public SurPart ToSurHierarchy(out Dictionary <Part, SurPart> surParts)
 {
     surParts = new Dictionary <Part, SurPart>();
     foreach (var part in Parts)
     {
         var sp = new SurPart()
         {
             Children = new List <SurPart>(), Hash = CrcTool.FLModelCrc(part.ObjectName)
         };
         surParts.Add(part, sp);
     }
     foreach (var part in Parts)
     {
         if (part.Construct != null)
         {
             var p = Parts.FirstOrDefault((x) =>
                                          x.ObjectName.Equals(part.Construct.ParentName, StringComparison.OrdinalIgnoreCase));
             if (p != null)
             {
                 surParts[p].Children.Add(surParts[part]);
             }
         }
     }
     return(surParts[GetRootPart()]);
 }
Esempio n. 2
0
        public byte[] VMeshRef(string nodename)
        {
            using (var stream = new MemoryStream())
            {
                var writer = new BinaryWriter(stream);

                writer.Write((uint)60); //HeaderSize
                writer.Write(CrcTool.FLModelCrc(nodename));
                //Fields used for referencing sections of VMeshData
                writer.Write((ushort)0);                //StartVertex - BaseVertex in drawcall
                writer.Write((ushort)Vertices.Length);  //VertexCount (idk?)
                writer.Write((ushort)0);                //StartIndex
                writer.Write((ushort)Indices.Length);   //IndexCount
                writer.Write((ushort)0);                //StartMesh
                writer.Write((ushort)Drawcalls.Length); //MeshCount
                //Write rendering things
                writer.Write(Max.X);
                writer.Write(Min.X);
                writer.Write(Max.Y);
                writer.Write(Min.Y);
                writer.Write(Max.Z);
                writer.Write(Min.Z);


                writer.Write(Center.X);
                writer.Write(Center.Y);
                writer.Write(Center.Z);

                writer.Write(Radius);
                return(stream.ToArray());
            }
        }
Esempio n. 3
0
        public RigidModel CreateRigidModel(bool drawable)
        {
            var model = new RigidModel();
            var part  = new RigidModelPart();
            var dcs   = new List <MeshDrawcall>();
            var scale = Matrix4x4.CreateScale(Radius);

            if (drawable && SideMaterials.Length >= 6)
            {
                for (int i = 0; i < 6; i++)
                {
                    int     start, count;
                    Vector3 pos;
                    sphere.GetDrawParameters(faces[i], out start, out count, out pos);
                    var dc = new MeshDrawcall();
                    dc.Buffer         = sphere.VertexBuffer;
                    dc.MaterialCrc    = CrcTool.FLModelCrc(sideMaterialNames[i]);
                    dc.BaseVertex     = 0;
                    dc.StartIndex     = start;
                    dc.PrimitiveCount = count;
                    dc.HasScale       = true;
                    dc.Scale          = scale;
                    dcs.Add(dc);
                }

                if (SideMaterials.Length > 6)
                {
                    var crc = CrcTool.FLModelCrc(sideMaterialNames[6]);
                    for (int i = 0; i < 6; i++)
                    {
                        int     start, count;
                        Vector3 pos;
                        sphere.GetDrawParameters(faces[i], out start, out count, out pos);
                        var dc = new MeshDrawcall();
                        dc.Buffer         = sphere.VertexBuffer;
                        dc.MaterialCrc    = crc;
                        dc.BaseVertex     = 0;
                        dc.StartIndex     = start;
                        dc.PrimitiveCount = count;
                        dc.HasScale       = true;
                        dc.Scale          = scale;
                        dcs.Add(dc);
                    }
                }
            }
            var vmesh = new VisualMesh();

            vmesh.Radius      = Radius;
            vmesh.BoundingBox = BoundingBox.CreateFromSphere(new BoundingSphere(Vector3.Zero, Radius));
            vmesh.Levels      = new[] { dcs.ToArray() };
            part.Hardpoints   = new List <Hardpoint>();
            part.Mesh         = vmesh;
            model.Root        = part;
            model.AllParts    = new[] { part };
            return(model);
        }
 void ProcessSur(LibreLancer.Physics.Sur.SurFile surfile)
 {
     if (surs != null)
     {
         foreach (var mdl in surs)
         {
             mdl.Vertices.Dispose();
             mdl.Elements.Dispose();
         }
     }
     surs = new List <SurModel>();
     if ((drawable is ModelFile))
     {
         surs.Add(GetSurModel(surfile.GetMesh(0, false), null, surPart));
         foreach (var hpid in surfile.HardpointIds)
         {
             surs.Add(GetSurModel(surfile.GetMesh(hpid, true), null, surHardpoint));
         }
     }
     else
     {
         Dictionary <Part, SurPart> surParts;
         var surHierarchy = ((CmpFile)drawable).ToSurHierarchy(out surParts);
         surfile.FillMeshHierarchy(surHierarchy);
         foreach (var kv in surParts)
         {
             var mdl = new SurModel()
             {
                 Part = kv.Key
             };
             foreach (var hp in kv.Key.Model.Hardpoints)
             {
                 var crc = CrcTool.FLModelCrc(hp.Name);
                 if (surfile.HardpointIds.Contains(crc))
                 {
                     surs.Add(GetSurModel(surfile.GetMesh(crc, true), kv.Key, surHardpoint));
                 }
             }
             if (kv.Value.DisplayMeshes != null)
             {
                 foreach (var msh in kv.Value.DisplayMeshes)
                 {
                     AddVertices(mdl, msh);
                 }
             }
             mdl.Vertices = new VertexBuffer(typeof(VertexPositionColor), mdl.BuildVertices.Count);
             mdl.Vertices.SetData(mdl.BuildVertices.ToArray());
             mdl.BuildVertices = null;
             mdl.Elements      = new ElementBuffer(mdl.BuildIndices.Count);
             mdl.Elements.SetData(mdl.BuildIndices.ToArray());
             mdl.Vertices.SetElementBuffer(mdl.Elements);
             mdl.BuildIndices = null;
             surs.Add(mdl);
         }
     }
 }
Esempio n. 5
0
 void CheckNullArray()
 {
     if (sph.sideMaterials == null)
     {
         sph.sideMaterials = new Material[sph.sideMaterialNames.Count];
         for (int i = 0; i < sph.sideMaterialNames.Count; i++)
         {
             sph.sideMaterials[i] = sph.library.FindMaterial(CrcTool.FLModelCrc(sph.sideMaterialNames[i]));
         }
     }
 }
Esempio n. 6
0
 private void setMeshes(IntermediateNode vMeshLibrary, ILibFile materialLibrary)
 {
     foreach (IntermediateNode vmsNode in vMeshLibrary)
     {
         if (vmsNode.Count != 1)
         {
             throw new Exception("Invalid VMeshLibrary: More than one child or zero elements: " + vmsNode.Name);
         }
         LeafNode vMeshDataNode = vmsNode[0] as LeafNode;
         Meshes.Add(CrcTool.FLModelCrc(vmsNode.Name), new VMeshData(vMeshDataNode.ByteArrayData, materialLibrary, vmsNode.Name));
     }
 }
Esempio n. 7
0
 public Material this[int i]
 {
     get
     {
         CheckNullArray();
         if (sph.sideMaterials[i] == null)
         {
             var crc = CrcTool.FLModelCrc(sph.sideMaterialNames[i]);
             sph.sideMaterials[i] = sph.library.FindMaterial(CrcTool.FLModelCrc(sph.sideMaterialNames[i]));
         }
         return(sph.sideMaterials[i]);
     }
     set
     {
         CheckNullArray();
         sph.sideMaterials[i] = value;
     }
 }
Esempio n. 8
0
 private void setMaterials(IntermediateNode materialLibraryNode)
 {
     //TODO: int count = 0;
     foreach (Node materialNode in materialLibraryNode)
     {
         if (materialNode is IntermediateNode)
         {
             uint materialId = CrcTool.FLModelCrc(materialNode.Name);
             if (!Materials.ContainsKey(materialId))
             {
                 Materials.Add(materialId, Material.FromNode(materialNode as IntermediateNode, this));
             }
         }
         //else if (subNode.Name.Equals("material count", StringComparison.OrdinalIgnoreCase))
         //count = (subNode as LeafNode).getIntegerBlaBLubb;
     }
     //if (count != materials.Count)
     //throw new Exception("Invalid material count: " + count + " != " + materials.Count);
 }
Esempio n. 9
0
 public static void DetectDrawable(string name, IDrawable drawable, ResourceManager res, List <MissingReference> missing, List <uint> matrefs, List <string> texrefs)
 {
     if (drawable is CmpFile)
     {
         var cmp = (CmpFile)drawable;
         foreach (var part in cmp.ModelParts())
         {
             DetectResourcesModel(part.Model, name + ", " + part.Model.Path, res, missing, matrefs, texrefs);
         }
     }
     if (drawable is ModelFile)
     {
         DetectResourcesModel((ModelFile)drawable, name, res, missing, matrefs, texrefs);
     }
     if (drawable is SphFile)
     {
         var sph = (SphFile)drawable;
         for (int i = 0; i < sph.SideMaterials.Length; i++)
         {
             if (sph.SideMaterials[i] != null && !sph.SideMaterials[i].Loaded)
             {
                 sph.SideMaterials[i] = null;
             }
             if (sph.SideMaterials[i] == null)
             {
                 var str = "Material: " + sph.SideMaterialNames[i];
                 if (!HasMissing(missing, str))
                 {
                     missing.Add(new MissingReference(str, string.Format("{0} M{1}", name, i)));
                 }
             }
             else
             {
                 var crc = CrcTool.FLModelCrc(sph.SideMaterialNames[i]);
                 if (!matrefs.Contains(crc))
                 {
                     matrefs.Add(crc);
                 }
                 DoMaterialRefs(sph.SideMaterials[i], res, missing, texrefs, string.Format(" - {0} M{1}", name, i));
             }
         }
     }
 }
Esempio n. 10
0
 private void setMeshes(IntermediateNode vMeshLibrary, ILibFile materialLibrary)
 {
     foreach (IntermediateNode vmsNode in vMeshLibrary)
     {
         var vMeshDataNode =
             vmsNode.FirstOrDefault(x => x.Name.Equals("VMeshData", StringComparison.OrdinalIgnoreCase));
         if (vMeshDataNode == null)
         {
             FLLog.Error("VMS", "Invalid VMeshLibrary: No VMeshData: " + vmsNode.Name);
             continue;
         }
         LeafNode vmsdat = vmsNode[0] as LeafNode;
         if (vmsdat == null)
         {
             FLLog.Error("VMS", "Invalid VMeshLibrary: VMeshData has no bytes: " + vmsNode.Name);
         }
         else
         {
             Meshes.Add(CrcTool.FLModelCrc(vmsNode.Name),
                        new VMeshData(vmsdat.DataSegment, materialLibrary, vmsNode.Name));
         }
     }
 }
Esempio n. 11
0
        public byte[] VMeshData()
        {
            using (var stream = new MemoryStream())
            {
                var writer = new BinaryWriter(stream);
                writer.Write((uint)0x01);                 //MeshType
                writer.Write((uint)0x04);                 //SurfaceType
                writer.Write((ushort)(Drawcalls.Length)); //MeshCount
                writer.Write((ushort)(Indices.Length));   //IndexCount
                writer.Write((ushort)FVF);                //FVF
                writer.Write((ushort)Vertices.Length);    //VertexCount

                int startTri = 0;
                foreach (var dc in Drawcalls)
                {
                    //drawcalls must be sequential (start index isn't in VMeshData)
                    //this error shouldn't ever throw
                    if (startTri != dc.StartIndex)
                    {
                        throw new Exception("Invalid start index");
                    }
                    //write TMeshHeader
                    var crc = dc.Material != null?CrcTool.FLModelCrc(dc.Material.Name) : 0;

                    writer.Write(crc);
                    writer.Write((ushort)dc.StartVertex);
                    writer.Write((ushort)dc.EndVertex);
                    writer.Write((ushort)(dc.TriCount * 3)); //NumRefVertices
                    writer.Write((ushort)0);                 //Padding
                    //validation
                    startTri += dc.TriCount * 3;
                }

                foreach (var idx in Indices)
                {
                    writer.Write(idx);
                }
                foreach (var v in Vertices)
                {
                    writer.Write(v.Position.X);
                    writer.Write(v.Position.Y);
                    writer.Write(v.Position.Z);
                    if ((FVF & D3DFVF.NORMAL) == D3DFVF.NORMAL)
                    {
                        writer.Write(v.Normal.X);
                        writer.Write(v.Normal.Y);
                        writer.Write(v.Normal.Z);
                    }
                    if ((FVF & D3DFVF.DIFFUSE) == D3DFVF.DIFFUSE)
                    {
                        writer.Write(v.Diffuse);
                    }
                    //Librelancer stores texture coordinates flipped internally
                    if ((FVF & D3DFVF.TEX2) == D3DFVF.TEX2)
                    {
                        writer.Write(v.TextureCoordinate.X);
                        writer.Write(1 - v.TextureCoordinate.Y);
                        writer.Write(v.TextureCoordinateTwo.X);
                        writer.Write(1 - v.TextureCoordinateTwo.Y);
                    }
                    else if ((FVF & D3DFVF.TEX1) == D3DFVF.TEX1)
                    {
                        writer.Write(v.TextureCoordinate.X);
                        writer.Write(1 - v.TextureCoordinate.Y);
                    }
                }
                return(stream.ToArray());
            }
        }
Esempio n. 12
0
 void DoNodeMenu(string id, LUtfNode node, LUtfNode parent)
 {
     if (ImGui.BeginPopupContextItem(id))
     {
         ImGui.MenuItem(node.Name, false);
         ImGui.MenuItem(string.Format("CRC: 0x{0:X}", CrcTool.FLModelCrc(node.Name)), false);
         ImGui.Separator();
         if (Theme.IconMenuItem(Icons.Edit, "Rename", node != Utf.Root))
         {
             text.SetText(node.Name);
             renameNode = node;
             popups.OpenPopup("Rename Node");
         }
         if (Theme.IconMenuItem(Icons.TrashAlt, "Delete", node != Utf.Root))
         {
             deleteParent = parent;
             deleteNode   = node;
             Confirm("Are you sure you want to delete: '" + node.Name + "'?", () =>
             {
                 if (selectedNode == deleteNode)
                 {
                     selectedNode = null;
                 }
                 deleteParent.Children.Remove(deleteNode);
             });
         }
         if (Theme.IconMenuItem(Icons.Eraser, "Clear", node.Children != null || node.Data != null))
         {
             clearNode = node;
             Confirm("Clearing this node will delete all data and children. Continue?", () =>
             {
                 clearNode.Data = null;
                 if (clearNode == Utf.Root)
                 {
                     clearNode.Children = new List <LUtfNode>();
                 }
                 else
                 {
                     clearNode.Children = null;
                 }
             });
         }
         ImGui.Separator();
         if (Theme.BeginIconMenu(Icons.PlusCircle, "Add"))
         {
             if (ImGui.MenuItem("Child"))
             {
                 text.SetText("");
                 addParent = null;
                 addNode   = node;
                 if (node.Data != null)
                 {
                     Confirm("Adding a node will clear data. Continue?", () =>
                     {
                         popups.OpenPopup("New Node");
                     });
                 }
                 else
                 {
                     popups.OpenPopup("New Node");
                 }
             }
             if (ImGui.MenuItem("Before", node != Utf.Root))
             {
                 text.SetText("");
                 addParent = parent;
                 addNode   = node;
                 addOffset = 0;
                 popups.OpenPopup("New Node");
             }
             if (ImGui.MenuItem("After", node != Utf.Root))
             {
                 text.SetText("");
                 addParent = parent;
                 addNode   = node;
                 addOffset = 1;
                 popups.OpenPopup("New Node");
             }
             ImGui.EndMenu();
         }
         ImGui.Separator();
         if (Theme.IconMenuItem(Icons.Cut, "Cut", node != Utf.Root))
         {
             parent.Children.Remove(node);
             main.ClipboardCopy = false;
             main.Clipboard     = node;
         }
         if (Theme.IconMenuItem(Icons.Copy, "Copy", node != Utf.Root))
         {
             main.ClipboardCopy = true;
             main.Clipboard     = node.MakeCopy();
         }
         if (main.Clipboard != null)
         {
             if (Theme.BeginIconMenu(Icons.Paste, "Paste"))
             {
                 if (ImGui.MenuItem("Before", node != Utf.Root))
                 {
                     if (main.ClipboardCopy)
                     {
                         var cpy = main.Clipboard.MakeCopy();
                         cpy.Parent = parent;
                         parent.Children.Insert(parent.Children.IndexOf(node), cpy);
                     }
                     else
                     {
                         main.Clipboard.Parent = parent;
                         parent.Children.Insert(parent.Children.IndexOf(node), main.Clipboard);
                         main.Clipboard = null;
                     }
                 }
                 if (ImGui.MenuItem("After", node != Utf.Root))
                 {
                     if (main.ClipboardCopy)
                     {
                         var cpy = main.Clipboard.MakeCopy();
                         cpy.Parent = parent;
                         parent.Children.Insert(parent.Children.IndexOf(node) + 1, cpy);
                     }
                     else
                     {
                         main.Clipboard.Parent = parent;
                         parent.Children.Insert(parent.Children.IndexOf(node) + 1, main.Clipboard);
                         main.Clipboard = null;
                     }
                 }
                 if (ImGui.MenuItem("Into"))
                 {
                     if (node.Data == null)
                     {
                         if (node.Children == null)
                         {
                             node.Children = new List <LUtfNode>();
                         }
                         if (main.ClipboardCopy)
                         {
                             var cpy = main.Clipboard.MakeCopy();
                             cpy.Parent = node;
                             node.Children.Add(cpy);
                         }
                         else
                         {
                             main.Clipboard.Parent = node;
                             node.Children.Add(main.Clipboard);
                             main.Clipboard = null;
                         }
                     }
                     else
                     {
                         pasteInto = node;
                         Confirm("Adding children will delete this node's data. Continue?", () =>
                         {
                             pasteInto.Data     = null;
                             pasteInto.Children = new List <LUtfNode>();
                             if (main.ClipboardCopy)
                             {
                                 var cpy    = main.Clipboard.MakeCopy();
                                 cpy.Parent = pasteInto;
                                 pasteInto.Children.Add(cpy);
                             }
                             else
                             {
                                 main.Clipboard.Parent = pasteInto;
                                 pasteInto.Children.Add(main.Clipboard);
                                 main.Clipboard = null;
                             }
                         });
                     }
                 }
                 ImGui.EndMenu();
             }
         }
         else
         {
             Theme.IconMenuItem(Icons.Paste, "Paste", false);
         }
         ImGui.EndPopup();
     }
 }
Esempio n. 13
0
 public void DrawBuffer(CommandBuffer buffer, Matrix4 world, ref Lighting lighting, Material overrideMat = null)
 {
     if (SideMaterials.Length < 6)
     {
         return;
     }
     if (ready)
     {
         for (int i = 0; i < SideMaterials.Length; i++)
         {
             if (SideMaterials[i] != null && !SideMaterials[i].Loaded)
             {
                 SideMaterials[i].Loaded = false;
             }
         }
         for (int i = 0; i < 6; i++)
         {
             int     start, count;
             Vector3 pos;
             sphere.GetDrawParameters(faces[i], out start, out count, out pos);
             if (SideMaterials[i] == null)
             {
                 SideMaterials[i] = library.FindMaterial(CrcTool.FLModelCrc(sideMaterialNames[i]));
             }
             var mat = SideMaterials[i] ?? defaultMaterial;
             mat = overrideMat ?? mat;
             mat.Render.Camera = _camera;
             var transform = Matrix4.CreateScale(Radius) * world;
             buffer.AddCommand(
                 mat.Render,
                 null,
                 transform,
                 lighting,
                 sphere.VertexBuffer,
                 PrimitiveTypes.TriangleList,
                 0,
                 start,
                 count,
                 SortLayers.OBJECT
                 );
         }
         //Draw atmosphere
         if (SideMaterials.Length > 6 && overrideMat == null)
         {
             if (SideMaterials[6] == null)
             {
                 SideMaterials[6] = library.FindMaterial(CrcTool.FLModelCrc(sideMaterialNames[6]));
                 if (SideMaterials[6] == null)
                 {
                     return;
                 }
             }
             var mat       = (AtmosphereMaterial)SideMaterials[6].Render;
             var transform = Matrix4.CreateScale(Radius * mat.Scale) * world;
             for (int i = 0; i < 6; i++)
             {
                 int     start, count;
                 Vector3 pos;
                 sphere.GetDrawParameters(faces[i], out start, out count, out pos);
                 SideMaterials[6].Render.Camera = _camera;
                 buffer.AddCommand(
                     SideMaterials[6].Render,
                     null,
                     transform,
                     lighting,
                     sphere.VertexBuffer,
                     PrimitiveTypes.TriangleList,
                     0,
                     start,
                     count,
                     SortLayers.OBJECT,
                     RenderHelpers.GetZ(transform, _camera.Position, pos)
                     );
             }
         }
     }
     else
     {
         throw new Exception();
     }
 }
 void ProcessSur(LibreLancer.Physics.Sur.SurFile surfile)
 {
     if (surs != null)
     {
         foreach (var mdl in surs)
         {
             mdl.Vertices.Dispose();
             mdl.Elements.Dispose();
         }
     }
     surs = new List <SurModel>();
     if ((drawable is ModelFile))
     {
         surs.Add(GetSurModel(surfile.GetMesh(0, false), null, surPart));
         foreach (var hpid in surfile.HardpointIds)
         {
             surs.Add(GetSurModel(surfile.GetMesh(hpid, true), null, surHardpoint));
         }
     }
     else
     {
         Dictionary <uint, SurModel> crcLookup = new Dictionary <uint, SurModel>();
         foreach (var part in ((CmpFile)drawable).Parts)
         {
             crcLookup.Add(CrcTool.FLModelCrc(part.ObjectName), new SurModel()
             {
                 Part = part
             });
         }
         foreach (var part in ((CmpFile)drawable).Parts)
         {
             var crc = CrcTool.FLModelCrc(part.ObjectName);
             foreach (var msh in surfile.GetMesh(crc, false))
             {
                 AddVertices(crcLookup[msh.ParentCrc], msh);
             }
             foreach (var hp in part.Model.Hardpoints)
             {
                 crc = CrcTool.FLModelCrc(hp.Name);
                 Color4 c = surHardpoint;
                 if (hp.Name.Equals("hpmount", StringComparison.OrdinalIgnoreCase))
                 {
                     c = surShield;
                 }
                 if (surfile.HardpointIds.Contains(crc))
                 {
                     surs.Add(GetSurModel(surfile.GetMesh(crc, true), null, c));
                 }
             }
         }
         foreach (var mdl in crcLookup.Values)
         {
             mdl.Vertices = new VertexBuffer(typeof(VertexPositionColor), mdl.BuildVertices.Count);
             mdl.Vertices.SetData(mdl.BuildVertices.ToArray());
             mdl.BuildVertices = null;
             mdl.Elements      = new ElementBuffer(mdl.BuildIndices.Count);
             mdl.Elements.SetData(mdl.BuildIndices.ToArray());
             mdl.Vertices.SetElementBuffer(mdl.Elements);
             mdl.BuildIndices = null;
             surs.Add(mdl);
         }
     }
 }
Esempio n. 15
0
        public static byte[] VMeshData(Geometry g)
        {
            using (var stream = new MemoryStream())
            {
                var writer = new BinaryWriter(stream);
                writer.Write((uint)0x01);                 //MeshType
                writer.Write((uint)0x04);                 //SurfaceType
                writer.Write((ushort)(g.Groups.Length));  //MeshCount
                writer.Write((ushort)(g.Indices.Length)); //IndexCount
                D3DFVF fvf = FVF(g);
                writer.Write((ushort)fvf);                //FVF
                writer.Write((ushort)g.Vertices.Length);  //VertexCount

                int startTri = 0;
                foreach (var dc in g.Groups)
                {
                    //drawcalls must be sequential (start index isn't in VMeshData)
                    //this error shouldn't ever throw
                    if (startTri != dc.StartIndex)
                    {
                        throw new Exception("Invalid start index");
                    }
                    //write TMeshHeader
                    var crc = dc.Material != null?CrcTool.FLModelCrc(dc.Material.Name) : 0;

                    writer.Write(crc);
                    writer.Write((ushort)dc.BaseVertex);
                    int max = 0;
                    for (int i = 0; i < dc.IndexCount; i++)
                    {
                        max = Math.Max(max, g.Indices.Indices16[i + dc.StartIndex]);
                    }

                    max += dc.BaseVertex;
                    writer.Write((ushort)max);
                    writer.Write((ushort)dc.IndexCount); //NumRefVertices
                    writer.Write((ushort)0);             //Padding
                    //validation
                    startTri += dc.IndexCount;
                }

                foreach (var idx in g.Indices.Indices16)
                {
                    writer.Write(idx);
                }
                foreach (var v in g.Vertices)
                {
                    writer.Write(v.Position.X);
                    writer.Write(v.Position.Y);
                    writer.Write(v.Position.Z);
                    if ((fvf & D3DFVF.NORMAL) == D3DFVF.NORMAL)
                    {
                        writer.Write(v.Normal.X);
                        writer.Write(v.Normal.Y);
                        writer.Write(v.Normal.Z);
                    }
                    if ((fvf & D3DFVF.DIFFUSE) == D3DFVF.DIFFUSE)
                    {
                        writer.Write(((Color4)v.Diffuse).ToAbgr());
                    }
                    //Librelancer stores texture coordinates flipped internally
                    if ((fvf & D3DFVF.TEX2) == D3DFVF.TEX2)
                    {
                        writer.Write(v.Texture1.X);
                        writer.Write(1 - v.Texture1.Y);
                        writer.Write(v.Texture2.X);
                        writer.Write(1 - v.Texture2.Y);
                    }
                    else if ((fvf & D3DFVF.TEX1) == D3DFVF.TEX1)
                    {
                        writer.Write(v.Texture1.X);
                        writer.Write(1 - v.Texture1.Y);
                    }
                }
                return(stream.ToArray());
            }
        }