2 // Radegast Metaverse Client
3 // Copyright (c) 2009-2014, Radegast Development Team
4 // All rights reserved.
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 // * Neither the name of the application "Radegast", nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 using System.Collections.Generic;
37 using OpenMetaverse.Rendering;
38 using OpenMetaverse.Imaging;
39 using OpenMetaverse.Assets;
43 public class DAEExport : IDisposable
45 public string FileName { get; set; }
46 public Primitive RootPrim { get; set; }
47 public List<Primitive> Prims = new List<Primitive>();
48 public List<FacetedMesh> MeshedPrims = new List<FacetedMesh>();
49 public List<UUID> Textures = new List<UUID>();
50 public string[] TextureNames;
51 public int ExportablePrims { get; set; }
52 public int ExportableTextures { get; set; }
53 public bool ExportTextures { get; set; }
54 public string ImageFormat { get; set; }
55 public bool ConsolidateMaterials { get; set; }
56 public bool SkipTransparentFaces { get; set; }
58 public static readonly List<UUID> BuiltInTextures = new List<UUID>() {
59 new UUID("89556747-24cb-43ed-920b-47caed15465f"), // default
60 new UUID("be293869-d0d9-0a69-5989-ad27f1946fd4"), // default sculpt
61 new UUID("5748decc-f629-461c-9a36-a35a221fe21f"), // blank
62 new UUID("38b86f85-2575-52a9-a531-23108d8da837"), // invisible
63 new UUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"), // tranparent
66 RadegastInstance Instance;
67 GridClient Client { get { return Instance.Client; } }
68 System.Globalization.CultureInfo invariant = System.Globalization.CultureInfo.InvariantCulture;
72 public event EventHandler<DAEStatutsEventArgs> Progress;
74 void OnProgress(string message)
78 Progress(this, new DAEStatutsEventArgs(message));
82 public DAEExport(RadegastInstance instance, Primitive requestedPrim)
86 ConsolidateMaterials = true;
87 SkipTransparentFaces = true;
88 Mesher = new MeshmerizerR();
89 Init(Client.Network.CurrentSim, requestedPrim);
96 public void Init(Simulator sim, Primitive requestedPrim)
98 if (requestedPrim == null || !Client.Network.Connected) return;
100 RootPrim = requestedPrim;
102 if (requestedPrim.ParentID != 0)
105 if (sim.ObjectsPrimitives.TryGetValue(requestedPrim.ParentID, out parent))
112 Primitive root = new Primitive(RootPrim);
113 root.Position = Vector3.Zero;
116 sim.ObjectsPrimitives
117 .FindAll(p => p.ParentID == RootPrim.LocalID)
120 var child = new Primitive(p);
121 child.Position = root.Position + child.Position * root.Rotation;
122 child.Rotation = root.Rotation * child.Rotation;
125 List<uint> select = new List<uint>(Prims.Count);
126 Prims.ForEach(p => select.Add(p.LocalID));
127 Client.Objects.SelectObjects(sim, select.ToArray(), true);
129 OnProgress("Checking permissions");
131 for (int i = 0; i < Prims.Count; i++)
133 if (!CanExport(Prims[i])) continue;
136 var defaultTexture = Prims[i].Textures.DefaultTexture;
137 if (defaultTexture != null && !Textures.Contains(defaultTexture.TextureID))
139 Textures.Add(defaultTexture.TextureID);
141 for (int j = 0; j < Prims[i].Textures.FaceTextures.Length; j++)
143 var te = Prims[i].Textures.FaceTextures[j];
144 if (te == null) continue;
145 UUID id = te.TextureID;
146 if (!Textures.Contains(id))
153 TextureNames = new string[Textures.Count];
154 ExportableTextures = 0;
155 for (int i = 0; i < Textures.Count; i++)
158 if (CanExportTexture(Textures[i], out name))
160 ExportableTextures++;
161 TextureNames[i] = RadegastInstance.SafeFileName(name).Replace(' ', '_');
166 public void Export(string Filename)
168 this.FileName = Filename;
172 if (string.IsNullOrEmpty(FileName))
177 WorkPool.QueueUserWorkItem(sync =>
183 for (int i = 0; i < Prims.Count; i++)
185 if (!CanExport(Prims[i])) continue;
187 FacetedMesh mesh = MeshPrim(Prims[i]);
188 if (mesh == null) continue;
190 for (int j = 0; j < mesh.Faces.Count; j++)
192 Face face = mesh.Faces[j];
194 Primitive.TextureEntryFace teFace = mesh.Faces[j].TextureFace;
195 if (teFace == null) continue;
198 // Sculpt UV vertically flipped compared to prims. Flip back
199 if (Prims[i].Sculpt != null && Prims[i].Sculpt.SculptTexture != UUID.Zero && Prims[i].Sculpt.Type != SculptType.Mesh)
201 teFace = (Primitive.TextureEntryFace)teFace.Clone();
202 teFace.RepeatV *= -1;
205 // Texture transform for this face
206 Mesher.TransformTexCoords(face.Vertices, face.Center, teFace, Prims[i].Scale);
209 MeshedPrims.Add(mesh);
213 if (MeshedPrims.Count == 0)
215 msg = string.Format("Can export 0 out of {0} prims.{1}{1}Skipping.", Prims.Count, Environment.NewLine);
219 msg = string.Format("Exported {0} out of {1} objects to{2}{2}{3}", MeshedPrims.Count, Prims.Count, Environment.NewLine, FileName);
222 File.WriteAllText(FileName, DocToString(Doc));
229 OnProgress("Exporting textures...");
230 for (int i = 0; i < Textures.Count; i++)
232 var id = Textures[i];
233 if (TextureNames[i] == null)
235 OnProgress("Skipping " + id.ToString() + " due to insufficient permissions");
239 string filename = TextureNames[i] + "." + ImageFormat.ToLower();
241 OnProgress("Fetching texture" + id);
243 ManagedImage mImage = null;
245 byte[] jpegData = null;
249 System.Threading.AutoResetEvent gotImage = new System.Threading.AutoResetEvent(false);
250 Client.Assets.RequestImage(id, ImageType.Normal, (state, asset) =>
252 if (state == TextureRequestState.Finished && asset != null)
254 jpegData = asset.AssetData;
255 OpenJPEG.DecodeToImage(jpegData, out mImage, out wImage);
258 else if (state != TextureRequestState.Pending && state != TextureRequestState.Started && state != TextureRequestState.Progress)
263 gotImage.WaitOne(120 * 1000, false);
267 string fullFileName = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(FileName), filename);
271 wImage.Save(fullFileName, System.Drawing.Imaging.ImageFormat.Png);
274 wImage.Save(fullFileName, System.Drawing.Imaging.ImageFormat.Jpeg);
277 wImage.Save(fullFileName, System.Drawing.Imaging.ImageFormat.Bmp);
280 File.WriteAllBytes(fullFileName, jpegData);
283 File.WriteAllBytes(fullFileName, mImage.ExportTGA());
286 throw new Exception("Unsupported image format");
288 OnProgress("Saved to " + fullFileName);
292 throw new Exception("Failed to decode image");
298 OnProgress("Failed: " + ex.ToString());
299 TextureNames[i] = null;
305 public static bool IsFullPerm(Permissions Permissions)
308 ((Permissions.OwnerMask & PermissionMask.Modify) != 0) &&
309 ((Permissions.OwnerMask & PermissionMask.Copy) != 0) &&
310 ((Permissions.OwnerMask & PermissionMask.Transfer) != 0)
321 bool CanExport(Primitive prim)
323 if (prim.Properties == null) return false;
325 return (prim.Properties.OwnerID == Client.Self.AgentID) &&
326 (prim.Properties.CreatorID == Client.Self.AgentID) ||
327 (Instance.Netcom.LoginOptions.Grid.Platform != "SecondLife"
328 && prim.Properties.OwnerID == Client.Self.AgentID
329 && IsFullPerm(prim.Properties.Permissions)) ||
330 Instance.advancedDebugging;
333 bool CanExportTexture(UUID id, out string name)
335 name = id.ToString();
336 if (BuiltInTextures.Contains(id) || Instance.Netcom.LoginOptions.Grid.Platform != "SecondLife")
341 InventoryItem item = null;
342 foreach (var pair in Client.Inventory.Store.Items)
344 if (pair.Value.Data is InventoryItem)
346 var i = (InventoryItem)pair.Value.Data;
347 if (i.AssetUUID == id && (InventoryConsole.IsFullPerm(i) || Instance.advancedDebugging))
360 else if (Instance.advancedDebugging)
370 FacetedMesh MeshPrim(Primitive prim)
372 FacetedMesh mesh = null;
373 if (prim.Sculpt == null || prim.Sculpt.SculptTexture == UUID.Zero)
375 mesh = Mesher.GenerateFacetedMesh(prim, DetailLevel.Highest);
377 else if (prim.Sculpt.Type != SculptType.Mesh)
380 if (LoadTexture(prim.Sculpt.SculptTexture, ref img, true))
382 mesh = Mesher.GenerateFacetedSculptMesh(prim, (Bitmap)img, DetailLevel.Highest);
387 var gotMesh = new System.Threading.AutoResetEvent(false);
389 Client.Assets.RequestMesh(prim.Sculpt.SculptTexture, (success, meshAsset) =>
391 if (!success || !FacetedMesh.TryDecodeFromAsset(prim, meshAsset, DetailLevel.Highest, out mesh))
393 Logger.Log("Failed to fetch or decode the mesh asset", Helpers.LogLevel.Warning, Client);
398 gotMesh.WaitOne(20 * 1000, false);
403 bool LoadTexture(UUID textureID, ref Image texture, bool removeAlpha)
405 var gotImage = new System.Threading.ManualResetEvent(false);
412 Client.Assets.RequestImage(textureID, (TextureRequestState state, AssetTexture assetTexture) =>
415 if (state == TextureRequestState.Finished && OpenJPEG.DecodeToImage(assetTexture.AssetData, out mi))
420 if ((mi.Channels & ManagedImage.ImageChannels.Alpha) != 0)
422 mi.ConvertChannels(mi.Channels & ~ManagedImage.ImageChannels.Alpha);
425 tgaData = mi.ExportTGA();
426 img = LoadTGAClass.LoadTGA(new MemoryStream(tgaData));
430 gotImage.WaitOne(30 * 1000, false);
441 Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e);
446 XmlNode ColladaInit()
448 Doc = new XmlDocument();
449 var root = Doc.AppendChild(Doc.CreateElement("COLLADA"));
450 root.Attributes.Append(Doc.CreateAttribute("xmlns")).Value = "http://www.collada.org/2005/11/COLLADASchema";
451 root.Attributes.Append(Doc.CreateAttribute("version")).Value = "1.4.1";
453 var asset = root.AppendChild(Doc.CreateElement("asset"));
454 var contributor = asset.AppendChild(Doc.CreateElement("contributor"));
455 contributor.AppendChild(Doc.CreateElement("author")).InnerText = "Radegast User";
456 contributor.AppendChild(Doc.CreateElement("authoring_tool")).InnerText = "Radegast Collada Export";
458 asset.AppendChild(Doc.CreateElement("created")).InnerText = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss");
459 asset.AppendChild(Doc.CreateElement("modified")).InnerText = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss");
461 var unit = asset.AppendChild(Doc.CreateElement("unit"));
462 unit.Attributes.Append(Doc.CreateAttribute("name")).Value = "meter";
463 unit.Attributes.Append(Doc.CreateAttribute("meter")).Value = "1";
465 asset.AppendChild(Doc.CreateElement("up_axis")).InnerText = "Z_UP";
470 void AddSource(XmlNode mesh, string src_id, string param, List<float> vals)
472 var source = mesh.AppendChild(Doc.CreateElement("source"));
473 source.Attributes.Append(Doc.CreateAttribute("id")).InnerText = src_id;
474 var src_array = source.AppendChild(Doc.CreateElement("float_array"));
476 src_array.Attributes.Append(Doc.CreateAttribute("id")).InnerText = string.Format("{0}-{1}", src_id, "array");
477 src_array.Attributes.Append(Doc.CreateAttribute("count")).InnerText = vals.Count.ToString();
479 StringBuilder sb = new StringBuilder();
480 for (int i = 0; i < vals.Count; i++)
482 sb.Append(vals[i].ToString(invariant));
483 if (i != vals.Count - 1)
488 src_array.InnerText = sb.ToString();
490 var acc = source.AppendChild(Doc.CreateElement("technique_common"))
491 .AppendChild(Doc.CreateElement("accessor"));
492 acc.Attributes.Append(Doc.CreateAttribute("source")).InnerText = string.Format("#{0}-{1}", src_id, "array");
493 acc.Attributes.Append(Doc.CreateAttribute("count")).InnerText = ((int)(vals.Count / param.Length)).ToString();
494 acc.Attributes.Append(Doc.CreateAttribute("stride")).InnerText = param.Length.ToString();
496 foreach (char c in param)
498 var pX = acc.AppendChild(Doc.CreateElement("param"));
499 pX.Attributes.Append(Doc.CreateAttribute("name")).InnerText = c.ToString();
500 pX.Attributes.Append(Doc.CreateAttribute("type")).InnerText = "float";
505 void AddPolygons(XmlNode mesh, string geomID, string materialID, FacetedMesh obj, List<int> faces_to_include)
507 var polylist = mesh.AppendChild(Doc.CreateElement("polylist"));
508 polylist.Attributes.Append(Doc.CreateAttribute("material")).InnerText = materialID;
512 var input = polylist.AppendChild(Doc.CreateElement("input"));
513 input.Attributes.Append(Doc.CreateAttribute("semantic")).InnerText = "VERTEX";
514 input.Attributes.Append(Doc.CreateAttribute("offset")).InnerText = "0";
515 input.Attributes.Append(Doc.CreateAttribute("source")).InnerText = string.Format("#{0}-{1}", geomID, "vertices");
520 var input = polylist.AppendChild(Doc.CreateElement("input"));
521 input.Attributes.Append(Doc.CreateAttribute("semantic")).InnerText = "NORMAL";
522 input.Attributes.Append(Doc.CreateAttribute("offset")).InnerText = "0";
523 input.Attributes.Append(Doc.CreateAttribute("source")).InnerText = string.Format("#{0}-{1}", geomID, "normals");
528 var input = polylist.AppendChild(Doc.CreateElement("input"));
529 input.Attributes.Append(Doc.CreateAttribute("semantic")).InnerText = "TEXCOORD";
530 input.Attributes.Append(Doc.CreateAttribute("offset")).InnerText = "0";
531 input.Attributes.Append(Doc.CreateAttribute("source")).InnerText = string.Format("#{0}-{1}", geomID, "map0");
535 var vcount = polylist.AppendChild(Doc.CreateElement("vcount"));
536 var p = polylist.AppendChild(Doc.CreateElement("p"));
537 int index_offset = 0;
539 StringBuilder pBuilder = new StringBuilder();
540 StringBuilder vcountBuilder = new StringBuilder();
542 for (int face_num = 0; face_num < obj.Faces.Count; face_num++)
544 var face = obj.Faces[face_num];
545 if (faces_to_include == null || faces_to_include.Contains(face_num))
547 for (int i = 0; i < face.Indices.Count; i++)
549 int index = index_offset + face.Indices[i];
550 pBuilder.Append(index);
551 pBuilder.Append(" ");
554 vcountBuilder.Append("3 ");
559 index_offset += face.Vertices.Count;
562 p.InnerText = pBuilder.ToString().TrimEnd();
563 vcount.InnerText = vcountBuilder.ToString().TrimEnd();
564 polylist.Attributes.Append(Doc.CreateAttribute("count")).InnerText = num_tris.ToString();
567 void GenerateImagesSection(XmlNode images)
569 for (int i = 0; i < TextureNames.Length; i++)
571 string name = TextureNames[i];
572 if (name == null) continue;
573 string colladaName = name + "_" + ImageFormat.ToLower();
574 var image = images.AppendChild(Doc.CreateElement("image"));
575 image.Attributes.Append(Doc.CreateAttribute("id")).InnerText = colladaName;
576 image.Attributes.Append(Doc.CreateAttribute("name")).InnerText = colladaName;
577 image.AppendChild(Doc.CreateElement("init_from")).InnerText = System.Web.HttpUtility.UrlEncode(name + "." + ImageFormat.ToLower());
583 public UUID TextureID;
587 public bool Matches(Primitive.TextureEntryFace TextureEntry)
589 return TextureID == TextureEntry.TextureID && Color == TextureEntry.RGBA;
593 List<MaterialInfo> AllMeterials = new List<MaterialInfo>();
595 MaterialInfo GetMaterial(Primitive.TextureEntryFace te)
597 MaterialInfo ret = null;
598 foreach (var mat in AllMeterials)
609 ret = new MaterialInfo()
611 TextureID = te.TextureID,
614 ret.Name = string.Format("Material{0}", AllMeterials.Count);
615 AllMeterials.Add(ret);
621 List<MaterialInfo> GetMaterials(FacetedMesh obj)
623 var ret = new List<MaterialInfo>();
625 for (int face_num = 0; face_num < obj.Faces.Count; face_num++)
627 var te = obj.Faces[(int)face_num].TextureFace;
628 if (SkipTransparentFaces && te.RGBA.A < 0.01f)
632 var mat = GetMaterial(te);
633 if (!ret.Contains(mat))
641 List<int> GetFacesWithMaterial(FacetedMesh obj, MaterialInfo mat)
643 var ret = new List<int>();
644 for (int face_num = 0; face_num < obj.Faces.Count; face_num++)
646 if (mat == GetMaterial(obj.Faces[(int)face_num].TextureFace))
654 void GenerateEffects(XmlNode effects)
656 // Effects (face color, alpha)
657 foreach (var mat in AllMeterials)
659 var color = mat.Color;
660 var effect = effects.AppendChild(Doc.CreateElement("effect"));
661 effect.Attributes.Append(Doc.CreateAttribute("id")).InnerText = mat.Name + "-fx";
662 var profile = effect.AppendChild(Doc.CreateElement("profile_COMMON"));
663 string colladaName = null;
666 UUID textID = UUID.Zero;
668 for (; i < Textures.Count; i++)
670 if (mat.TextureID == Textures[i])
672 textID = mat.TextureID;
677 if (textID != UUID.Zero && TextureNames[i] != null)
679 colladaName = TextureNames[i] + "_" + ImageFormat.ToLower();
680 var newparam = profile.AppendChild(Doc.CreateElement("newparam"));
681 newparam.Attributes.Append(Doc.CreateAttribute("sid")).InnerText = colladaName + "-surface";
682 var surface = newparam.AppendChild(Doc.CreateElement("surface"));
683 surface.Attributes.Append(Doc.CreateAttribute("type")).InnerText = "2D";
684 surface.AppendChild(Doc.CreateElement("init_from")).InnerText = colladaName;
685 newparam = profile.AppendChild(Doc.CreateElement("newparam"));
686 newparam.Attributes.Append(Doc.CreateAttribute("sid")).InnerText = colladaName + "-sampler";
687 newparam.AppendChild(Doc.CreateElement("sampler2D"))
688 .AppendChild(Doc.CreateElement("source"))
689 .InnerText = colladaName + "-surface";
693 var t = profile.AppendChild(Doc.CreateElement("technique"));
694 t.Attributes.Append(Doc.CreateAttribute("sid")).InnerText = "common";
695 var phong = t.AppendChild(Doc.CreateElement("phong"));
697 var diffuse = phong.AppendChild(Doc.CreateElement("diffuse"));
698 // Only one <color> or <texture> can appear inside diffuse element
699 if (colladaName != null)
701 var txtr = diffuse.AppendChild(Doc.CreateElement("texture"));
702 txtr.Attributes.Append(Doc.CreateAttribute("texture")).InnerText = colladaName + "-sampler";
703 txtr.Attributes.Append(Doc.CreateAttribute("texcoord")).InnerText = colladaName;
707 var diffuseColor = diffuse.AppendChild(Doc.CreateElement("color"));
708 diffuseColor.Attributes.Append(Doc.CreateAttribute("sid")).InnerText = "diffuse";
709 diffuseColor.InnerText = string.Format("{0} {1} {2} {3}",
710 color.R.ToString(invariant),
711 color.G.ToString(invariant),
712 color.B.ToString(invariant),
713 color.A.ToString(invariant));
716 phong.AppendChild(Doc.CreateElement("transparency"))
717 .AppendChild(Doc.CreateElement("float"))
718 .InnerText = color.A.ToString(invariant);
723 void GenerateCollada()
725 AllMeterials.Clear();
726 var root = ColladaInit();
727 var images = root.AppendChild(Doc.CreateElement("library_images"));
728 var geomLib = root.AppendChild(Doc.CreateElement("library_geometries"));
729 var effects = root.AppendChild(Doc.CreateElement("library_effects"));
730 var materials = root.AppendChild(Doc.CreateElement("library_materials"));
731 var scene = root.AppendChild(Doc.CreateElement("library_visual_scenes"))
732 .AppendChild(Doc.CreateElement("visual_scene"));
733 scene.Attributes.Append(Doc.CreateAttribute("id")).InnerText = "Scene";
734 scene.Attributes.Append(Doc.CreateAttribute("name")).InnerText = "Scene";
737 GenerateImagesSection(images);
741 foreach (var obj in MeshedPrims)
743 int total_num_vertices = 0;
744 string name = string.Format("prim{0}", prim_nr++);
745 string geomID = name;
747 var geom = geomLib.AppendChild(Doc.CreateElement("geometry"));
748 geom.Attributes.Append(Doc.CreateAttribute("id")).InnerText = string.Format("{0}-{1}", geomID, "mesh");
749 var mesh = geom.AppendChild(Doc.CreateElement("mesh"));
751 List<float> position_data = new List<float>();
752 List<float> normal_data = new List<float>();
753 List<float> uv_data = new List<float>();
755 int num_faces = obj.Faces.Count;
757 for (int face_num = 0; face_num < num_faces; face_num++)
759 var face = obj.Faces[face_num];
760 total_num_vertices += face.Vertices.Count;
762 for (int i = 0; i < face.Vertices.Count; i++)
764 var v = face.Vertices[i];
765 position_data.Add(v.Position.X);
766 position_data.Add(v.Position.Y);
767 position_data.Add(v.Position.Z);
769 normal_data.Add(v.Normal.X);
770 normal_data.Add(v.Normal.Y);
771 normal_data.Add(v.Normal.Z);
773 uv_data.Add(v.TexCoord.X);
774 uv_data.Add(v.TexCoord.Y);
778 AddSource(mesh, string.Format("{0}-{1}", geomID, "positions"), "XYZ", position_data);
779 AddSource(mesh, string.Format("{0}-{1}", geomID, "normals"), "XYZ", normal_data);
780 AddSource(mesh, string.Format("{0}-{1}", geomID, "map0"), "ST", uv_data);
782 // Add the <vertices> element
784 var verticesNode = mesh.AppendChild(Doc.CreateElement("vertices"));
785 verticesNode.Attributes.Append(Doc.CreateAttribute("id")).InnerText = string.Format("{0}-{1}", geomID, "vertices");
786 var verticesInput = verticesNode.AppendChild(Doc.CreateElement("input"));
787 verticesInput.Attributes.Append(Doc.CreateAttribute("semantic")).InnerText = "POSITION";
788 verticesInput.Attributes.Append(Doc.CreateAttribute("source")).InnerText = string.Format("#{0}-{1}", geomID, "positions");
791 var objMaterials = GetMaterials(obj);
794 foreach (var objMaterial in objMaterials)
796 AddPolygons(mesh, geomID, objMaterial.Name + "-material", obj, GetFacesWithMaterial(obj, objMaterial));
799 var node = scene.AppendChild(Doc.CreateElement("node"));
800 node.Attributes.Append(Doc.CreateAttribute("type")).InnerText = "NODE";
801 node.Attributes.Append(Doc.CreateAttribute("id")).InnerText = geomID;
802 node.Attributes.Append(Doc.CreateAttribute("name")).InnerText = geomID;
804 // Set tranform matrix (node position, rotation and scale)
805 var matrix = node.AppendChild(Doc.CreateElement("matrix"));
807 var srt = Radegast.Rendering.Math3D.CreateSRTMatrix(obj.Prim.Scale, obj.Prim.Rotation, obj.Prim.Position);
808 string matrixVal = "";
809 for (int i = 0; i < 4; i++)
811 for (int j = 0; j < 4; j++)
813 matrixVal += srt[j * 4 + i].ToString(invariant) + " ";
816 matrix.InnerText = matrixVal.TrimEnd();
818 // Geometry of the node
819 var nodeGeometry = node.AppendChild(Doc.CreateElement("instance_geometry"));
822 var tq = nodeGeometry.AppendChild(Doc.CreateElement("bind_material"))
823 .AppendChild(Doc.CreateElement("technique_common"));
824 foreach (var objMaterial in objMaterials)
826 var instanceMaterial = tq.AppendChild(Doc.CreateElement("instance_material"));
827 instanceMaterial.Attributes.Append(Doc.CreateAttribute("symbol")).InnerText = string.Format("{0}-{1}", objMaterial.Name, "material");
828 instanceMaterial.Attributes.Append(Doc.CreateAttribute("target")).InnerText = string.Format("#{0}-{1}", objMaterial.Name, "material");
831 nodeGeometry.Attributes.Append(Doc.CreateAttribute("url")).InnerText = string.Format("#{0}-{1}", geomID, "mesh");
834 GenerateEffects(effects);
837 foreach (var objMaterial in AllMeterials)
839 var mat = materials.AppendChild(Doc.CreateElement("material"));
840 mat.Attributes.Append(Doc.CreateAttribute("id")).InnerText = objMaterial.Name + "-material";
841 var matEffect = mat.AppendChild(Doc.CreateElement("instance_effect"));
842 matEffect.Attributes.Append(Doc.CreateAttribute("url")).InnerText = string.Format("#{0}-{1}", objMaterial.Name, "fx");
845 root.AppendChild(Doc.CreateElement("scene"))
846 .AppendChild(Doc.CreateElement("instance_visual_scene"))
847 .Attributes.Append(Doc.CreateAttribute("url")).InnerText = "#Scene";
851 string DocToString(XmlDocument doc)
853 string ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + Environment.NewLine;
856 using (MemoryStream outs = new MemoryStream())
858 using (XmlTextWriter writter = new XmlTextWriter(outs, Encoding.UTF8))
860 writter.Formatting = Formatting.Indented;
861 doc.WriteContentTo(writter);
865 using (StreamReader sr = new StreamReader(outs))
867 ret += sr.ReadToEnd();
878 public class DAEStatutsEventArgs : EventArgs
880 public string Message;
882 public DAEStatutsEventArgs(string message)