Example #1
0
        public TextureMetadataCollection(DestinationFolder urhoDataFolder)
        {
            var allMaterials = AssetDatabase.FindAssets("").Select(_ => AssetContext.Create(_, urhoDataFolder))
                               .Where(_ => _.Type == typeof(Material));

            foreach (var asset in allMaterials)
            {
                var material    = AssetDatabase.LoadAssetAtPath <Material>(asset.AssetPath);
                var description = new MaterialDescription(material);
                if (description.MetallicRoughness != null)
                {
                    var metallicRoughness = description.MetallicRoughness;
                    if (metallicRoughness.MetallicGloss != null)
                    {
                        var meta = AddTexture(metallicRoughness.MetallicGloss, new TextureReferences(
                                                  TextureSemantic.PBRMetallicGlossiness, 1.0f,
                                                  metallicRoughness.SmoothnessTextureChannel ==
                                                  SmoothnessTextureChannel.MetallicOrSpecularAlpha
                                ? metallicRoughness.MetallicGloss
                                : metallicRoughness.BaseColor, metallicRoughness.SmoothnessTextureChannel));
                    }

                    AddTexture(metallicRoughness.BaseColor, new TextureReferences(TextureSemantic.PBRBaseColor));
                    AddTexture(metallicRoughness.DetailBaseColor,
                               new TextureReferences(TextureSemantic.MainTextureDetail));
                }
                else if (description.SpecularGlossiness != null)
                {
                    var specularGlossiness = description.SpecularGlossiness;
                    if (specularGlossiness.PBRSpecular != null)
                    {
                        AddTexture(specularGlossiness.PBRSpecular, new TextureReferences(
                                       TextureSemantic.PBRSpecularGlossiness, 1.0f,
                                       specularGlossiness.Diffuse, specularGlossiness.SmoothnessTextureChannel));
                        AddTexture(specularGlossiness.Diffuse,
                                   new TextureReferences(TextureSemantic.PBRDiffuse, 1.0f, specularGlossiness.PBRSpecular,
                                                         specularGlossiness.SmoothnessTextureChannel));
                    }
                    else
                    {
                        AddTexture(specularGlossiness.Diffuse,
                                   new TextureReferences(TextureSemantic.PBRDiffuse, 1.0f, specularGlossiness.PBRSpecular,
                                                         specularGlossiness.SmoothnessTextureChannel));
                    }

                    AddTexture(specularGlossiness.DetailDiffuse,
                               new TextureReferences(TextureSemantic.MainTextureDetail));
                }
                else
                {
                    var legacy = description.Legacy;
                    AddTexture(legacy.Diffuse, new TextureReferences(TextureSemantic.MainTexture));
                    AddTexture(legacy.Specular, new TextureReferences(TextureSemantic.Specular));
                    AddCommonTextures(legacy);
                }
            }
        }
Example #2
0
        private static (float min, float max, Vector2 size) WriteHeightMap(AssetContext asset, string heightmapFileName,
                                                                           Terrain terrain)
        {
            var w       = terrain.terrainData.heightmapResolution;
            var h       = terrain.terrainData.heightmapResolution;
            var max     = float.MinValue;
            var min     = float.MaxValue;
            var heights = terrain.terrainData.GetHeights(0, 0, w, h);

            foreach (var height in heights)
            {
                if (height > max)
                {
                    max = height;
                }
                if (height < min)
                {
                    min = height;
                }
            }

            if (max < min)
            {
                max = 1;
                min = 0;
            }
            else if (max == min)
            {
                max = min + 0.1f;
            }

            using (var imageFile = asset.DestinationFolder.Create(heightmapFileName))
            {
                if (imageFile != null)
                {
                    using (var binaryWriter = new BinaryWriter(imageFile))
                    {
                        WriteTgaHeader(binaryWriter, 32, w, h);
                        for (var y = h - 1; y >= 0; --y)
                        {
                            for (var x = 0; x < w; ++x)
                            {
                                var height = (heights[h - y - 1, x] - min) / (max - min) * 255.0f;
                                var msb    = (byte)height;
                                var lsb    = (byte)((height - msb) * 255.0f);
                                binaryWriter.Write((byte)0);   //B - none
                                binaryWriter.Write(lsb);       //G - LSB
                                binaryWriter.Write(msb);       //R - MSB
                                binaryWriter.Write((byte)255); //A - none
                            }
                        }
                    }
                }
            }

            return(min, max, new Vector2(w, h));
        }
Example #3
0
        private static void Process3DAsset(AssetCollection assets, AssetContext assetContext)
        {
            new MeshExporter(assets).ExportAsset(assetContext);

            if (assetContext.Type != typeof(Mesh))
            {
                new PrefabExporter(assets).ExportAsset(assetContext);
            }
        }
Example #4
0
        private void ExportAnimation(AssetContext asset, AnimationClip clipAnimation)
        {
            var name = GetSafeFileName(clipAnimation.name);

            var fileName = Path.Combine(asset.ContentFolder, name + ".ani");

            //_assetCollection.AddAnimationPath(clipAnimation, fileName);

            if (!File.Exists(fileName))
            {
                using (var file = Urho3DExporter.ExportAssets.CreateFile(fileName))
                {
                    using (var writer = new BinaryWriter(file))
                    {
                        writer.Write(new byte[] { 0x55, 0x41, 0x4e, 0x49 });
                        WriteStringSZ(writer, clipAnimation.name);
                        writer.Write(clipAnimation.length);

                        if (clipAnimation.legacy)
                        {
                            WriteTracksAsIs(clipAnimation, writer);
                        }
                        else
                        {
                            var allBindings = AnimationUtility.GetCurveBindings(clipAnimation);
                            var rootBones   =
                                new HashSet <string>(allBindings.Select(_ => GetRootBoneName(_)).Where(_ => _ != null));
                            if (rootBones.Count != 1)
                            {
                                Debug.LogWarning(asset.AssetPath + ": Multiple root bones found (" +
                                                 string.Join(", ", rootBones.ToArray()) +
                                                 "), falling back to curve export");
                                WriteTracksAsIs(clipAnimation, writer);
                            }
                            else
                            {
                                var rootBoneName = rootBones.First();
                                var rootGOs      = _skeletons
                                                   .Select(_ =>
                                                           (_.name == rootBoneName) ? _.transform : _.transform.Find(rootBoneName))
                                                   .Where(_ => _ != null).ToList();
                                if (rootGOs.Count == 1)
                                {
                                    WriteSkelAnimation(clipAnimation, rootGOs.First().gameObject, writer);
                                }
                                else
                                {
                                    Debug.LogWarning(asset.AssetPath +
                                                     ": Multiple game objects found that match root bone name, falling back to curve export");
                                    WriteTracksAsIs(clipAnimation, writer);
                                }
                            }
                        }
                    }
                }
            }
        }
Example #5
0
        //[MenuItem("CONTEXT/Terrain/Export Terrain To Urho3D")]
        //static void ExportTerrain(MenuCommand command)
        //{
        //    if (!ResolveDataPath(out var urhoDataPath)) return;
        //}

        public static void ExportToUrho(string targetPath, bool overrideFiles, bool exportSelected)
        {
            if (string.IsNullOrWhiteSpace(targetPath))
            {
                return;
            }

            var urhoDataPath = new DestinationFolder(targetPath, overrideFiles);

            AssetCollection assets;

            if (Selection.assetGUIDs.Length == 0 || !exportSelected)
            {
                assets = new AssetCollection(urhoDataPath,
                                             AssetDatabase.FindAssets("").Select(_ => AssetContext.Create(_, urhoDataPath))
                                             .Where(_ => _.Type != null));
            }
            else
            {
                var selectedAssets = new HashSet <string>();
                foreach (var assetGuiD in Selection.assetGUIDs)
                {
                    AddSelection(assetGuiD, selectedAssets);
                }

                var enumerable    = selectedAssets.Select(_ => AssetContext.Create(_, urhoDataPath)).ToList();
                var assetContexts = enumerable.Where(_ => _.Type != null).ToList();
                assets = new AssetCollection(urhoDataPath, assetContexts);
            }

            _id = 0;

            var other = Split(assets, _ => _.Is3DAsset, _ => Process3DAsset(assets, _));
            var textureMetadataCollection = new TextureMetadataCollection(urhoDataPath);

            other = Split(other,
                          _ => _.Type == typeof(Texture3D) || _.Type == typeof(Texture2D) || _.Type == typeof(Cubemap),
                          _ => new TextureExporter(assets, textureMetadataCollection).ExportAsset(_));
            other = Split(other, _ => _.Type == typeof(Material),
                          _ => new MaterialExporter(assets, textureMetadataCollection).ExportAsset(_));
            var activeScene = SceneManager.GetActiveScene();

            other = Split(other, _ => _.Type == typeof(SceneAsset), _ =>
            {
                if (_.AssetPath == activeScene.path)
                {
                    ProcessSceneAsset(assets, _, activeScene);
                }
            });
            foreach (var assetContext in other)
            {
                ProcessAsset(assets, assetContext);
            }
        }
Example #6
0
 private static void ProcessAsset(AssetCollection assets, AssetContext assetContext)
 {
     if (assetContext.Type == typeof(GameObject))
     {
         new PrefabExporter(assets).ExportAsset(assetContext);
     }
     else if (assetContext.Type == typeof(SceneAsset))
     {
         //new SceneExporter(assets).ExportAsset(assetContext);
     }
 }
Example #7
0
        private void WriteTerrainWeightsTexture(AssetContext asset, string weightsTextureName, Terrain terrain)
        {
            var layers       = terrain.terrainData.terrainLayers;
            var w            = terrain.terrainData.alphamapWidth;
            var h            = terrain.terrainData.alphamapHeight;
            var alphamaps    = terrain.terrainData.GetAlphamaps(0, 0, w, h);
            var numAlphamaps = alphamaps.GetLength(2);

            //Urho3D doesn't support more than 3 textures
            if (numAlphamaps > 3)
            {
                numAlphamaps = 3;
            }

            using (var imageFile = asset.DestinationFolder.Create(weightsTextureName))
            {
                if (imageFile == null)
                {
                    return;
                }
                using (var binaryWriter = new BinaryWriter(imageFile))
                {
                    var weights = new byte[4];
                    weights[3] = 255;
                    WriteTgaHeader(binaryWriter, weights.Length * 8, w, h);
                    for (var y = h - 1; y >= 0; --y)
                    {
                        for (var x = 0; x < w; ++x)
                        {
                            var sum = 0;
                            for (var i = 0; i < weights.Length; ++i)
                            {
                                if (numAlphamaps > i && layers.Length > i)
                                {
                                    var weight = (byte)(alphamaps[h - y - 1, x, i] * 255.0f);
                                    sum       += weight;
                                    weights[i] = weight;
                                }
                            }

                            if (sum == 0)
                            {
                                weights[0] = 255;
                            }

                            binaryWriter.Write(weights[2]); //B
                            binaryWriter.Write(weights[1]); //G
                            binaryWriter.Write(weights[0]); //R
                            binaryWriter.Write(weights[3]); //A
                        }
                    }
                }
            }
        }
Example #8
0
 public void ExportAsset(AssetContext asset)
 {
     using (var writer = asset.CreateXml())
     {
         if (writer == null)
         {
             return;
         }
         var go = AssetDatabase.LoadAssetAtPath <GameObject>(asset.AssetPath);
         WriteObject(writer, "", go, new HashSet <Renderer>(), asset);
     }
 }
Example #9
0
        private void TransformSpecularGlossiness(AssetContext asset, Texture texture, TextureReferences reference)
        {
            var specularGloss = texture as Texture2D;

            EnsureReadableTexture(specularGloss);
            var diffuse = reference.SmoothnessSource as Texture2D;

            EnsureReadableTexture(diffuse);
            var smoothnessSource =
                reference.SmoothnessTextureChannel == SmoothnessTextureChannel.MetallicOrSpecularAlpha
                    ? specularGloss
                    : diffuse;

            var metallicRoughMapName = GetTextureOutputName(asset.UrhoAssetName, reference);

            using (var fileStream = asset.DestinationFolder.Create(metallicRoughMapName))
            {
                if (fileStream != null)
                {
                    var width      = Math.Max(specularGloss.width, smoothnessSource.width);
                    var height     = Math.Max(specularGloss.height, smoothnessSource.height);
                    var tmpTexture = new Texture2D(width, height, TextureFormat.RGBA32, false);
                    tmpTexture.hideFlags = HideFlags.HideAndDontSave;

                    var metallicColors   = specularGloss.GetPixels32(0);
                    var diffuseColors    = diffuse.GetPixels32(0);
                    var smoothnessColors = specularGloss == smoothnessSource
                        ? metallicColors
                        : smoothnessSource.GetPixels32(0);
                    var pixels = new Color32[width * height];
                    var index  = 0;
                    for (var y = 0; y < height; ++y)
                    {
                        for (var x = 0; x < width; ++x)
                        {
                            var r = 1.0f - Get(smoothnessColors, smoothnessSource.width, smoothnessSource.height, x, y,
                                               width, height).a;
                            var d = GetLuminance(Get(diffuseColors, diffuse.width, diffuse.height, x, y, width, height));
                            var s = GetLuminance(Get(metallicColors, specularGloss.width, specularGloss.height, x, y, width,
                                                     height));
                            var m = s / (d + s);
                            pixels[index] = new Color(r, m, 0, 1);
                            ++index;
                        }
                    }

                    tmpTexture.SetPixels32(pixels, 0);
                    var bytes = tmpTexture.EncodeToPNG();
                    fileStream.Write(bytes, 0, bytes.Length);
                }
            }
        }
Example #10
0
        private static void Process3DAsset(AssetCollection assets, AssetContext assetContext)
        {
            Directory.CreateDirectory(assetContext.ContentFolder);

            new MeshExporter(assets).ExportAsset(assetContext);

            if (File.Exists(assetContext.UrhoFileName))
            {
                return;
            }

            new PrefabExporter(assets).ExportAsset(assetContext);
        }
Example #11
0
        public void ExportAsset(AssetContext asset)
        {
            var go = AssetDatabase.LoadAssetAtPath <SceneAsset>(asset.AssetPath);

            var exclusionSet = new HashSet <Renderer>();

            using (XmlTextWriter writer = CreateXmlFile(asset))
            {
                using (var scene = Element.Start(writer, "scene"))
                {
                }
            }
        }
Example #12
0
        private void TransformSpecularGlossiness(AssetContext asset, Texture texture, TextureReferences reference)
        {
            var specularGloss = texture as Texture2D;

            EnsureReadableTexture(specularGloss);
            var diffuse = reference.SmoothnessSource as Texture2D;

            EnsureReadableTexture(diffuse);
            var smoothnessSource =
                reference.SmoothnessTextureChannel == SmoothnessTextureChannel.MetallicOrSpecularAlpha
                    ? specularGloss
                    : diffuse;

            var metallicRoughMapName = GetTextureOutputName(asset.UrhoAssetName, reference);

            using (var fileStream = asset.DestinationFolder.Create(metallicRoughMapName))
            {
                if (fileStream != null)
                {
                    var tmpTexture     = CreateTargetTexture(specularGloss, diffuse);
                    var specularColors =
                        new PixelSource(specularGloss, tmpTexture.width, tmpTexture.height, Color.black);
                    var diffuseColors    = new PixelSource(diffuse, tmpTexture.width, tmpTexture.height, Color.white);
                    var smoothnessColors = specularGloss == smoothnessSource
                        ? specularColors
                        : diffuseColors;
                    var pixels = new Color32[tmpTexture.width * tmpTexture.height];
                    var index  = 0;
                    for (var y = 0; y < tmpTexture.height; ++y)
                    {
                        for (var x = 0; x < tmpTexture.width; ++x)
                        {
                            var mr = PBRUtils.ConvertToMetallicRoughness(new PBRUtils.SpecularGlossiness
                            {
                                diffuse    = diffuseColors.GetAt(x, y),
                                specular   = specularColors.GetAt(x, y),
                                glossiness = smoothnessColors.GetAt(x, y).a,
                                opacity    = 1.0f
                            });
                            pixels[index] = new Color(mr.roughness, mr.metallic, 0, 1);
                            ++index;
                        }
                    }

                    tmpTexture.SetPixels32(pixels, 0);
                    var bytes = tmpTexture.EncodeToPNG();
                    fileStream.Write(bytes, 0, bytes.Length);
                }
            }
        }
Example #13
0
        public void ExportAsset(AssetContext asset)
        {
            if (!File.Exists(asset.FullPath))
            {
                Debug.LogError("File " + asset.FullPath + " not found");
                return;
            }

            var texture = AssetDatabase.LoadAssetAtPath <Texture>(asset.AssetPath);

            _assets.AddTexturePath(texture, asset.UrhoAssetName);

            var fullCopy = false;

            foreach (var reference in _textureMetadata.ResolveReferences(texture))
            {
                switch (reference.Semantic)
                {
                case TextureSemantic.PBRMetallicGlossiness:
                {
                    TransformMetallicGlossiness(asset, texture, reference);
                    break;
                }

                case TextureSemantic.PBRSpecularGlossiness:
                {
                    TransformSpecularGlossiness(asset, texture, reference);
                    break;
                }

                case TextureSemantic.PBRDiffuse:
                {
                    TransformDiffuse(asset, texture, reference);
                    break;
                }

                default:
                {
                    if (!fullCopy)
                    {
                        asset.DestinationFolder.CopyFile(asset.FullPath, asset.UrhoAssetName);
                        fullCopy = true;
                    }

                    break;
                }
                }
            }
        }
Example #14
0
 private static void ProcessAsset(AssetCollection assets, AssetContext assetContext)
 {
     if (File.Exists(assetContext.UrhoFileName))
     {
         return;
     }
     Directory.CreateDirectory(Path.GetDirectoryName(assetContext.UrhoFileName));
     if (assetContext.Type == typeof(GameObject))
     {
         new PrefabExporter(assets).ExportAsset(assetContext);
     }
     else if (assetContext.Type == typeof(SceneAsset))
     {
         //new SceneExporter(assets).ExportAsset(assetContext);
     }
 }
Example #15
0
        public void ExportAsset(AssetContext asset)
        {
            var go = AssetDatabase.LoadAssetAtPath <SceneAsset>(asset.AssetPath);

            var exclusionSet = new HashSet <Renderer>();

            using (var writer = asset.CreateXml())
            {
                if (writer == null)
                {
                    return;
                }
                using (var scene = Element.Start(writer, "scene"))
                {
                }
            }
        }
Example #16
0
        private void ExportMaterial(AssetContext asset, Material material)
        {
            var mat = new MaterialDescription(material);

            if (mat.SpecularGlossiness != null)
            {
                ExportSpecularGlossiness(asset, mat.SpecularGlossiness);
            }
            else if (mat.MetallicRoughness != null)
            {
                ExportMetallicRoughness(asset, mat.MetallicRoughness);
            }
            else
            {
                ExportLegacy(asset, mat.Legacy ?? new LegacyShaderArguments());
            }
        }
Example #17
0
        private void TransformDiffuse(AssetContext asset, Texture texture, TextureReferences reference)
        {
            var diffuse = texture as Texture2D;

            EnsureReadableTexture(diffuse);
            var specularGlossiness = reference.SmoothnessSource as Texture2D;

            EnsureReadableTexture(specularGlossiness);

            var metallicRoughMapName = GetTextureOutputName(asset.UrhoAssetName, reference);

            using (var fileStream = asset.DestinationFolder.Create(metallicRoughMapName))
            {
                if (fileStream != null)
                {
                    var specWidth        = specularGlossiness?.width ?? 1;
                    var specHeight       = specularGlossiness?.height ?? 1;
                    var smoothnessColors = specularGlossiness?.GetPixels32(0) ?? new[] { new Color32(0, 0, 0, 255) };
                    var width            = Math.Max(diffuse.width, specWidth);
                    var height           = Math.Max(diffuse.height, specHeight);
                    var tmpTexture       = new Texture2D(width, height, TextureFormat.RGBA32, false);
                    tmpTexture.hideFlags = HideFlags.HideAndDontSave;

                    var diffuseColors = diffuse.GetPixels32(0);
                    var pixels        = new Color32[width * height];
                    var index         = 0;
                    for (var y = 0; y < height; ++y)
                    {
                        for (var x = 0; x < width; ++x)
                        {
                            var specular     = Get(smoothnessColors, specWidth, specHeight, x, y, width, height);
                            var diffuseColor = Get(diffuseColors, diffuse.width, diffuse.height, x, y, width, height);
                            pixels[index] = new Color(diffuseColor.r + specular.r, diffuseColor.g + specular.g,
                                                      diffuseColor.b + specular.b, diffuseColor.a);
                            ++index;
                        }
                    }

                    tmpTexture.SetPixels32(pixels, 0);
                    var bytes = tmpTexture.EncodeToPNG();
                    fileStream.Write(bytes, 0, bytes.Length);
                }
            }
        }
Example #18
0
        private void ExportMesh(AssetContext asset, GameObject go)
        {
            var skinnedMeshRenderer = go.GetComponent <SkinnedMeshRenderer>();
            var meshFilter          = go.GetComponent <MeshFilter>();

            //Debug.Log("Game object: "+go.name+", components: "+string.Join(", ", go.GetComponents<Component>().Select(_=>_.GetType().Name).ToArray()));

            Mesh mesh = null;

            if (skinnedMeshRenderer != null)
            {
                mesh = skinnedMeshRenderer.sharedMesh;
            }
            else if (meshFilter != null)
            {
                mesh = meshFilter.sharedMesh;
            }

            if (mesh != null && _meshes.Add(mesh))
            {
                var name = GetSafeFileName(mesh.name);

                var fileName = Path.Combine(asset.ContentFolder, name + ".mdl");

                _assetCollection.AddMeshPath(mesh, fileName);

                if (!File.Exists(fileName))
                {
                    using (var file = Urho3DExporter.ExportAssets.CreateFile(fileName))
                    {
                        using (var writer = new BinaryWriter(file))
                        {
                            WriteMesh(writer, mesh, BuildBones(skinnedMeshRenderer));
                        }
                    }
                }
            }

            for (var i = 0; i < go.transform.childCount; ++i)
            {
                ExportMesh(asset, go.transform.GetChild(i).gameObject);
            }
        }
Example #19
0
        public void ExportAsset(AssetContext asset, Scene scene)
        {
            var exlusion = new HashSet <Renderer>();

            using (XmlTextWriter writer = CreateXmlFile(asset))
            {
                using (var sceneElement = Element.Start(writer, "scene"))
                {
                    WriteAttribute(writer, "\t", "Name", scene.name);
                    StartCompoent(writer, "\t", "Octree");
                    EndElement(writer, "\t");
                    StartCompoent(writer, "\t", "DebugRenderer");
                    EndElement(writer, "\t");
                    foreach (var gameObject in scene.GetRootGameObjects())
                    {
                        WriteObject(writer, "", gameObject, exlusion);
                    }
                }
            }
        }
Example #20
0
        private void TransformMetallicGlossiness(AssetContext asset, Texture texture, TextureReferences reference)
        {
            var metallicGloss = texture as Texture2D;

            EnsureReadableTexture(metallicGloss);
            var smoothnessSource = reference.SmoothnessSource as Texture2D;

            EnsureReadableTexture(smoothnessSource);

            var metallicRoughMapName = GetTextureOutputName(asset.UrhoAssetName, reference);

            using (var fileStream = asset.DestinationFolder.Create(metallicRoughMapName))
            {
                if (fileStream != null)
                {
                    var tmpTexture = CreateTargetTexture(metallicGloss, reference.SmoothnessSource as Texture2D);

                    var metallicColors = new PixelSource(metallicGloss, tmpTexture.width, tmpTexture.height,
                                                         new Color(0, 0, 0, 0));
                    var smoothnessColors = metallicGloss == smoothnessSource
                        ? metallicColors
                        : new PixelSource(smoothnessSource, tmpTexture.width, tmpTexture.height, new Color(0, 0, 0, 0));
                    var pixels = new Color32[tmpTexture.width * tmpTexture.height];
                    var index  = 0;
                    for (var y = 0; y < tmpTexture.height; ++y)
                    {
                        for (var x = 0; x < tmpTexture.width; ++x)
                        {
                            var r = 1.0f - smoothnessColors.GetAt(x, y).a;
                            var m = metallicColors.GetAt(x, y).r;
                            pixels[index] = new Color(r, m, 0, 1);
                            ++index;
                        }
                    }

                    tmpTexture.SetPixels32(pixels, 0);
                    var bytes = tmpTexture.EncodeToPNG();
                    fileStream.Write(bytes, 0, bytes.Length);
                }
            }
        }
Example #21
0
        public static AssetContext Create(string guid, string urhoDataFolder)
        {
            var res = new AssetContext
            {
                Guid = guid
            };

            res.AssetPath = AssetDatabase.GUIDToAssetPath(guid);
            if (!string.IsNullOrEmpty(res.AssetPath))
            {
                res.Type    = AssetDatabase.GetMainAssetTypeAtPath(res.AssetPath);
                res.RelPath = res.AssetPath;
                if (res.RelPath.StartsWith("Assets/", StringComparison.InvariantCultureIgnoreCase))
                {
                    res.RelPath = res.RelPath.Substring("Assets/".Length);
                }
                res.FullPath      = Path.Combine(Application.dataPath, res.RelPath);
                res.FileExtension = System.IO.Path.GetExtension(res.AssetPath).ToLower();
                res.UrhoAssetName = res.RelPath;
                if (res.Type == typeof(Material))
                {
                    res.UrhoAssetName = RepaceExtension(res.UrhoAssetName, ".xml");
                }
                else if (res.Type == typeof(GameObject))
                {
                    res.UrhoAssetName = RepaceExtension(res.UrhoAssetName, ".xml");
                    res.Is3DAsset     = _supported3DFormats.Contains(res.FileExtension);
                }
                else if (res.Type == typeof(SceneAsset))
                {
                    res.UrhoAssetName = RepaceExtension(res.UrhoAssetName, ".xml");
                }
                res.UrhoFileName = System.IO.Path.Combine(urhoDataFolder, res.UrhoAssetName);
                if (res.Is3DAsset)
                {
                    res.ContentFolder = res.UrhoFileName.Substring(0, res.UrhoFileName.Length - ".xml".Length);
                }
            }

            return(res);
        }
Example #22
0
        public void ExportAsset(AssetContext asset)
        {
            var texture = AssetDatabase.LoadAssetAtPath <Texture>(asset.AssetPath);

            _assets.AddTexturePath(texture, asset.UrhoAssetName);

            if (asset.UrhoFileName == null)
            {
                return;
            }
            if (File.Exists(asset.UrhoFileName))
            {
                return;
            }
            if (!File.Exists(asset.FullPath))
            {
                Debug.LogError("File " + asset.FullPath + " not found");
                return;
            }

            Directory.CreateDirectory(Path.GetDirectoryName(asset.UrhoFileName));
            File.Copy(asset.FullPath, asset.UrhoFileName);
        }
Example #23
0
        private void ExportTerrain(XmlWriter writer, GameObject obj, AssetContext asset, Terrain terrain,
                                   string subPrefix,
                                   string subSubPrefix)
        {
            if (terrain == null)
            {
                return;
            }

            var terrainSize = terrain.terrainData.size;

            writer.WriteWhitespace(subPrefix);
            writer.WriteStartElement("node");
            writer.WriteAttributeString("id", (++_id).ToString());
            writer.WriteWhitespace("\n");

            var folderAndName = asset.RelPath + "/" +
                                Path.GetInvalidFileNameChars().Aggregate(obj.name, (_1, _2) => _1.Replace(_2, '_'));
            var heightmapFileName = "Textures/Terrains/" + folderAndName + ".tga";
            var materialFileName  = "Materials/Terrains/" + folderAndName + ".xml";

            var(min, max, size) = WriteHeightMap(asset, heightmapFileName, terrain);

            WriteAttribute(writer, subPrefix, "Position",
                           new Vector3(terrainSize.x * 0.5f, -min, terrainSize.z * 0.5f));

            StartCompoent(writer, subPrefix, "Terrain");

            WriteAttribute(writer, subSubPrefix, "Height Map", "Image;" + heightmapFileName);
            WriteAttribute(writer, subSubPrefix, "Material", "Material;" + materialFileName);
            WriteTerrainMaterial(terrain, asset, materialFileName,
                                 "Textures/Terrains/" + folderAndName + ".Weights.tga");
            WriteAttribute(writer, subSubPrefix, "Vertex Spacing",
                           new Vector3(terrainSize.x / size.x, 2.0f * (max - min), terrainSize.z / size.y));
            EndElement(writer, subPrefix);
            EndElement(writer, subPrefix);
        }
Example #24
0
 private static void ProcessSceneAsset(AssetCollection assets, AssetContext assetContext, Scene scene)
 {
     new SceneExporter(assets).ExportAsset(assetContext, scene);
 }
Example #25
0
        private void ExportLegacy(AssetContext asset, LegacyShaderArguments arguments)
        {
            using (var writer = asset.DestinationFolder.CreateXml(asset.UrhoAssetName))
            {
                if (writer == null)
                {
                    return;
                }
                writer.WriteStartDocument();
                writer.WriteWhitespace(Environment.NewLine);

                var flags = new LegacyTechniqueFlags();
                flags.hasAlpha    = arguments.Transparent;
                flags.hasDiffuse  = arguments.Diffuse != null;
                flags.hasEmissive = arguments.Emission != null;
                flags.hasNormal   = arguments.Bump != null;
                flags.hasSpecular = arguments.Specular != null;
                writer.WriteStartElement("material");
                writer.WriteWhitespace(Environment.NewLine);
                {
                    var bestTechnique         = Techniques[0];
                    var bestTechniqueDistance = bestTechnique.Material - flags;
                    foreach (var technique in Techniques)
                    {
                        if (technique.Material.Fits(flags))
                        {
                            var d = technique.Material - flags;
                            if (d < bestTechniqueDistance)
                            {
                                bestTechnique         = technique;
                                bestTechniqueDistance = d;
                            }
                        }
                    }

                    WriteTechnique(writer, "Techniques/" + bestTechnique.Name);
                }
                if (arguments.Diffuse != null)
                {
                    WriteTexture(arguments.Diffuse, writer, "diffuse");
                }
                if (arguments.Specular != null)
                {
                    WriteTexture(arguments.Specular, writer, "specular");
                }
                if (arguments.Bump != null)
                {
                    WriteTexture(arguments.Bump, writer, "normal");
                }
                if (arguments.Emission != null)
                {
                    WriteTexture(arguments.Bump, writer, "emissive");
                }
                WriteParameter(writer, "MatDiffColor", BaseNodeExporter.Format(arguments.DiffColor));
                if (arguments.HasEmission)
                {
                    WriteParameter(writer, "MatEmissiveColor", BaseNodeExporter.FormatRGB(arguments.EmissiveColor));
                }
                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
        }
Example #26
0
        private void ExportSpecularGlossiness(AssetContext asset, SpecularGlossinessShaderArguments arguments)
        {
            using (var writer = asset.DestinationFolder.CreateXml(asset.UrhoAssetName))
            {
                if (writer == null)
                {
                    return;
                }
                writer.WriteStartDocument();
                writer.WriteWhitespace(Environment.NewLine);
                writer.WriteStartElement("material");
                writer.WriteWhitespace(Environment.NewLine);

                if (arguments.Diffuse != null)
                {
                    // Albedo
                    if (arguments.PBRSpecular != null)
                    {
                        // Albedo, MetallicGloss
                        if (arguments.Bump != null)
                        {
                            // Albedo, MetallicGloss, Normal
                            if (arguments.Emission)
                            {
                                // Albedo, MetallicGloss, Normal, Emission
                                if (arguments.Transparent)
                                {
                                    WriteTechnique(writer,
                                                   "Techniques/PBR/PBRMetallicRoughDiffNormalSpecEmissiveAlpha.xml");
                                }
                                else
                                {
                                    WriteTechnique(writer, "Techniques/PBR/PBRMetallicRoughDiffNormalSpecEmissive.xml");
                                }
                                WriteTexture(arguments.Emission, writer, "emissive");
                            }
                            else
                            {
                                // Albedo, MetallicGloss, Normal, No Emission
                                if (arguments.Transparent)
                                {
                                    WriteTechnique(writer, "Techniques/PBR/PBRMetallicRoughDiffNormalSpecAlpha.xml");
                                }
                                else
                                {
                                    WriteTechnique(writer, "Techniques/PBR/PBRMetallicRoughDiffNormalSpec.xml");
                                }
                            }

                            WriteTexture(arguments.Bump, writer, "normal");
                        }
                        else
                        {
                            // Albedo, MetallicGloss, No Normal
                            if (arguments.Transparent)
                            {
                                WriteTechnique(writer, "Techniques/PBR/PBRMetallicRoughDiffSpecAlpha.xml");
                            }
                            else
                            {
                                WriteTechnique(writer, "Techniques/PBR/PBRMetallicRoughDiffSpec.xml");
                            }
                        }

                        if (_assets.TryGetTexturePath(arguments.PBRSpecular, out var baseAssetName))
                        {
                            var textureReferences = new TextureReferences(TextureSemantic.PBRSpecularGlossiness, 1.0f,
                                                                          arguments.SmoothnessTextureChannel == SmoothnessTextureChannel.AlbedoAlpha
                                    ? arguments.Diffuse
                                    : arguments.PBRSpecular, arguments.SmoothnessTextureChannel);
                            var textureOutputName =
                                TextureExporter.GetTextureOutputName(baseAssetName, textureReferences);
                            WriteTexture(textureOutputName, writer, "specular");
                        }
                    }
                    else
                    {
                        // Albedo, No MetallicGloss
                        if (arguments.Bump != null)
                        {
                            // Albedo, No MetallicGloss, Normal
                            if (arguments.Emission != null)
                            {
                                // Albedo, No MetallicGloss, Normal, Emission
                                if (arguments.Transparent)
                                {
                                    WriteTechnique(writer, "Techniques/PBR/PBRDiffNormalEmissiveAlpha.xml");
                                }
                                else
                                {
                                    WriteTechnique(writer, "Techniques/PBR/PBRDiffNormalEmissive.xml");
                                }
                                WriteTexture(arguments.Emission, writer, "emissive");
                            }
                            else
                            {
                                // Albedo, No MetallicGloss, Normal, No Emission
                                if (arguments.Transparent)
                                {
                                    WriteTechnique(writer, "Techniques/PBR/PBRDiffNormalAlpha.xml");
                                }
                                else
                                {
                                    WriteTechnique(writer, "Techniques/PBR/PBRDiffNormal.xml");
                                }
                            }

                            WriteTexture(arguments.Bump, writer, "normal");
                        }
                        else
                        {
                            // Albedo, No MetallicGloss, No Normal
                            if (arguments.Transparent)
                            {
                                WriteTechnique(writer, "Techniques/PBR/PBRDiffAlpha.xml");
                            }
                            else
                            {
                                WriteTechnique(writer, "Techniques/PBR/PBRDiff.xml");
                            }
                        }
                    }

                    if (_assets.TryGetTexturePath(arguments.Diffuse, out var diffuseName))
                    {
                        var textureReferences = new TextureReferences(TextureSemantic.PBRDiffuse, 1.0f,
                                                                      arguments.PBRSpecular, arguments.SmoothnessTextureChannel);
                        var textureOutputName = TextureExporter.GetTextureOutputName(diffuseName, textureReferences);
                        WriteTexture(textureOutputName, writer, "diffuse");
                    }
                }
                else
                {
                    // No albedo
                    if (arguments.Transparent)
                    {
                        WriteTechnique(writer, "Techniques/PBR/PBRNoTextureAlpha.xml");
                    }
                    else
                    {
                        WriteTechnique(writer, "Techniques/PBR/PBRNoTexture.xml");
                    }
                }

                WriteParameter(writer, "MatDiffColor", BaseNodeExporter.Format(arguments.DiffuseColor));
                if (arguments.HasEmission)
                {
                    WriteParameter(writer, "MatEmissiveColor", BaseNodeExporter.FormatRGB(arguments.EmissiveColor));
                }
                WriteParameter(writer, "MatEnvMapColor", BaseNodeExporter.FormatRGB(Color.white));
                WriteParameter(writer, "MatSpecColor", BaseNodeExporter.Format(Vector4.zero));
                if (arguments.PBRSpecular != null)
                {
                    WriteParameter(writer, "Roughness", BaseNodeExporter.Format(0));
                    WriteParameter(writer, "Metallic", BaseNodeExporter.Format(0));
                }
                else
                {
                    ////TODO: Evaluate correct parameters:
                    WriteParameter(writer, "Roughness", BaseNodeExporter.Format(0.0f));
                    WriteParameter(writer, "Metallic", BaseNodeExporter.Format(0.0f));
                }

                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
        }
Example #27
0
        //private void WriteMaterialAttribute(string subSubPrefix, Material[] meshRendererMaterials)
        //{
        //    var material = new StringBuilder();
        //    material.Append("Material");
        //    for (var i = 0; i < meshRendererMaterials.Length; ++i)
        //    {
        //        var meshRendererMaterial = meshRendererMaterials[i];
        //        var relPath = GetRelAssetPath(meshRendererMaterial);

        //        var outputMaterialName = "Materials/" + relPath + ".xml";

        //        material.Append(";");
        //        material.Append(outputMaterialName);

        //        var materialFileName = Path.Combine(_assetsFolder, outputMaterialName);
        //        if (!File.Exists(materialFileName))
        //            CreateMaterial(materialFileName, meshRendererMaterial);
        //    }
        //    WriteAttribute(subSubPrefix, "Material", material.ToString());
        //}
        protected void WriteObject(XmlWriter writer, string prefix, GameObject obj, HashSet <Renderer> excludeList,
                                   AssetContext asset)
        {
            var localExcludeList = new HashSet <Renderer>(excludeList);

            if (!string.IsNullOrEmpty(prefix))
            {
                writer.WriteWhitespace(prefix);
            }
            writer.WriteStartElement("node");
            writer.WriteAttributeString("id", (++_id).ToString());
            writer.WriteWhitespace("\n");

            var subPrefix    = prefix + "\t";
            var subSubPrefix = subPrefix + "\t";

            WriteAttribute(writer, subPrefix, "Is Enabled", obj.activeSelf);
            WriteAttribute(writer, subPrefix, "Name", obj.name);
            WriteAttribute(writer, subPrefix, "Tags", obj.tag);
            WriteAttribute(writer, subPrefix, "Position", obj.transform.localPosition);
            WriteAttribute(writer, subPrefix, "Rotation", obj.transform.localRotation);
            WriteAttribute(writer, subPrefix, "Scale", obj.transform.localScale);

            var meshFilter          = obj.GetComponent <MeshFilter>();
            var meshRenderer        = obj.GetComponent <MeshRenderer>();
            var skinnedMeshRenderer = obj.GetComponent <SkinnedMeshRenderer>();
            var lodGroup            = obj.GetComponent <LODGroup>();
            var meshCollider        = obj.GetComponent <MeshCollider>();
            var terrain             = obj.GetComponent <Terrain>();
            var light           = obj.GetComponent <Light>();
            var camera          = obj.GetComponent <Camera>();
            var reflectionProbe = obj.GetComponent <ReflectionProbe>();

            //if (reflectionProbe != null)
            //{
            //    StartCompoent(subPrefix, "Zone");

            //    WriteAttribute(subSubPrefix, "Bounding Box Min", -(reflectionProbe.size * 0.5f));
            //    WriteAttribute(subSubPrefix, "Bounding Box Max", (reflectionProbe.size * 0.5f));
            //    var cubemap = reflectionProbe.bakedTexture as Cubemap;
            //    if (cubemap != null)
            //    {
            //        var name = SaveCubemap(cubemap);
            //        WriteAttribute(subSubPrefix, "Zone Texture", "TextureCube;" + name);
            //    }
            //    EndElement(subPrefix);
            //}
            if (camera != null)
            {
                StartCompoent(writer, subPrefix, "Camera");

                WriteAttribute(writer, subSubPrefix, "Near Clip", camera.nearClipPlane);
                WriteAttribute(writer, subSubPrefix, "Far Clip", camera.farClipPlane);

                EndElement(writer, subPrefix);
            }

            if (light != null && light.type != LightType.Area)
            {
                StartCompoent(writer, subPrefix, "Light");
                if (light.type == LightType.Directional)
                {
                    WriteAttribute(writer, subSubPrefix, "Light Type", "Directional");
                }
                else if (light.type == LightType.Spot)
                {
                    WriteAttribute(writer, subSubPrefix, "Light Type", "Spot");
                }
                else if (light.type == LightType.Point)
                {
                    WriteAttribute(writer, subSubPrefix, "Range", light.range);
                }
                WriteAttribute(writer, subSubPrefix, "Color", light.color);
                WriteAttribute(writer, subSubPrefix, "Brightness Multiplier", light.intensity);
                WriteAttribute(writer, subSubPrefix, "Cast Shadows", light.shadows != LightShadows.None);

                EndElement(writer, subPrefix);
            }

            ExportTerrain(writer, obj, asset, terrain, subPrefix, subSubPrefix);

            if (lodGroup != null)
            {
                var lods = lodGroup.GetLODs();
                foreach (var lod in lods.Skip(1))
                {
                    foreach (var renderer in lod.renderers)
                    {
                        localExcludeList.Add(renderer);
                    }
                }
                //lods[0].renderers
            }

            if (meshRenderer != null && !localExcludeList.Contains(meshRenderer))
            {
                if (meshFilter != null)
                {
                    StartCompoent(writer, subPrefix, "StaticModel");

                    var    sharedMesh = meshFilter.sharedMesh;
                    string meshPath;
                    if (_assets.TryGetMeshPath(sharedMesh, out meshPath))
                    {
                        WriteAttribute(writer, subSubPrefix, "Model", "Model;" + meshPath);
                    }

                    var materials = "Material";
                    foreach (var material in meshRenderer.sharedMaterials)
                    {
                        string path;
                        _assets.TryGetMaterialPath(material, out path);
                        materials += ";" + path;
                    }

                    WriteAttribute(writer, subSubPrefix, "Material", materials);

                    WriteAttribute(writer, subSubPrefix, "Cast Shadows",
                                   meshRenderer.shadowCastingMode != ShadowCastingMode.Off);

                    EndElement(writer, subPrefix);
                }
            }

            if (skinnedMeshRenderer != null && !localExcludeList.Contains(skinnedMeshRenderer))
            {
                StartCompoent(writer, subPrefix, "AnimatedModel");

                var    sharedMesh = skinnedMeshRenderer.sharedMesh;
                string meshPath;
                if (_assets.TryGetMeshPath(sharedMesh, out meshPath))
                {
                    WriteAttribute(writer, subSubPrefix, "Model", "Model;" + meshPath);
                }

                var materials = "Material";
                foreach (var material in skinnedMeshRenderer.sharedMaterials)
                {
                    string path;
                    _assets.TryGetMaterialPath(material, out path);
                    materials += ";" + path;
                }

                WriteAttribute(writer, subSubPrefix, "Material", materials);

                WriteAttribute(writer, subSubPrefix, "Cast Shadows",
                               skinnedMeshRenderer.shadowCastingMode != ShadowCastingMode.Off);

                EndElement(writer, subPrefix);
            }

            if (meshCollider != null)
            {
            }

            foreach (Transform childTransform in obj.transform)
            {
                if (childTransform.parent.gameObject == obj)
                {
                    WriteObject(writer, subPrefix, childTransform.gameObject, localExcludeList, asset);
                }
            }

            if (!string.IsNullOrEmpty(prefix))
            {
                writer.WriteWhitespace(prefix);
            }
            writer.WriteEndElement();
            writer.WriteWhitespace("\n");
        }
Example #28
0
        private static void ExportToUrho()
        {
            string urhoDataPath = EditorUtility.SaveFolderPanel("Save assets to Data folder", _prevFolder, "");

            if (string.IsNullOrEmpty(urhoDataPath))
            {
                return;
            }

            if (urhoDataPath.StartsWith(Path.GetDirectoryName(Application.dataPath).Replace('\\', '/'), StringComparison.InvariantCultureIgnoreCase))
            {
                EditorUtility.DisplayDialog("Error",
                                            "Selected path is inside Unity folder. Please select a different folder.", "Ok");
                return;
            }

            _prevFolder = urhoDataPath;

            AssetCollection assets;

            if (Selection.assetGUIDs.Length == 0)
            {
                assets = new AssetCollection(urhoDataPath, AssetDatabase.FindAssets("").Select(_ => AssetContext.Create(_, urhoDataPath)).Where(_ => _.Type != null));
            }
            else
            {
                var selectedAssets = new HashSet <string>();
                foreach (var assetGuiD in Selection.assetGUIDs)
                {
                    AddSelection(assetGuiD, selectedAssets);
                }
                assets = new AssetCollection(urhoDataPath, selectedAssets.Select(_ => AssetContext.Create(_, urhoDataPath)).Where(_ => _.Type != null));
            }
            _id = 0;
            //string urhoDataPath = @"C:\Temp\Data\";

            //foreach (var type in assets.Select(_ => _.Type).Distinct()) Debug.Log(type.FullName);

            List <AssetContext> other = Split(assets, _ => _.Is3DAsset, _ => Process3DAsset(assets, _));

            other = Split(other, _ => _.Type == typeof(Texture3D) || _.Type == typeof(Texture2D) || _.Type == typeof(Cubemap), _ => new TextureExporter(assets).ExportAsset(_));
            other = Split(other, _ => _.Type == typeof(Material), _ => new MaterialExporter(assets).ExportAsset(_));
            var activeScene = EditorSceneManager.GetActiveScene();

            other = Split(other, _ => _.Type == typeof(SceneAsset), _ =>
            {
                if (_.AssetPath == activeScene.path)
                {
                    ProcessSceneAsset(assets, _, activeScene);
                }
            });
            foreach (var assetContext in other)
            {
                ProcessAsset(assets, assetContext);
            }
            //foreach (var s in guids2)
            //{
            //    var path = AssetDatabase.GUIDToAssetPath(s);
            //    if (path.StartsWith(assetsPrefix))
            //    {
            //        path = path.Substring(assetsPrefix.Length);
            //    }

            //    if (path.StartsWith("PolygonSciFiCity"))
            //    {
            //        if (path.EndsWith(".prefab", true, CultureInfo.InvariantCulture))
            //        {
            //            ExportPrefab(s, path, @"C:\Temp\Data\");
            //        }

            //        if (path.EndsWith(".fbx", true, CultureInfo.InvariantCulture))
            //        {
            //            ExportModel(s, path, @"C:\Temp\Data\");
            //        }

            //        if (path.EndsWith(".mat", true, CultureInfo.InvariantCulture))
            //        {
            //            ExportMaterial(s, path, @"C:\Temp\Data\");
            //        }

            //        if (path.EndsWith(".png", true, CultureInfo.InvariantCulture) ||
            //            path.EndsWith(".dds", true, CultureInfo.InvariantCulture) ||
            //            path.EndsWith(".tga", true, CultureInfo.InvariantCulture))
            //        {
            //            CopyFileIfNew(s, path, @"C:\Temp\Data\");
            //        }
            //    }
            //}
        }
Example #29
0
        protected XmlTextWriter CreateXmlFile(AssetContext asset)
        {
            var file = ExportAssets.CreateFile(asset.UrhoFileName);

            return(new XmlTextWriter(file, new UTF8Encoding(false)));
        }
Example #30
0
        private void WriteTerrainMaterial(Terrain terrain, AssetContext asset, string materialPath,
                                          string weightsTextureName)
        {
            using (var writer = asset.DestinationFolder.CreateXml(materialPath))
            {
                if (writer == null)
                {
                    return;
                }

                var layers = terrain.terrainData.terrainLayers;
                if (layers.Length > 3)
                {
                    layers = layers.Take(3).ToArray();
                }

                writer.WriteStartDocument();
                writer.WriteStartElement("material");
                writer.WriteWhitespace(Environment.NewLine);
                {
                    writer.WriteStartElement("technique");
                    writer.WriteAttributeString("name", "Techniques/TerrainBlend.xml");
                    writer.WriteEndElement();
                    writer.WriteWhitespace(Environment.NewLine);
                }
                {
                    writer.WriteStartElement("texture");
                    writer.WriteAttributeString("unit", "0");
                    writer.WriteAttributeString("name", weightsTextureName);
                    writer.WriteEndElement();
                    writer.WriteWhitespace(Environment.NewLine);

                    WriteTerrainWeightsTexture(asset, weightsTextureName, terrain);
                }
                for (var layerIndex = 0; layerIndex < layers.Length; ++layerIndex)
                {
                    var layer = layers[layerIndex];

                    writer.WriteStartElement("texture");
                    writer.WriteAttributeString("unit", (layerIndex + 1).ToString(CultureInfo.InvariantCulture));
                    if (layer.diffuseTexture != null)
                    {
                        string urhoAssetName;
                        if (_assets.TryGetTexturePath(layer.diffuseTexture, out urhoAssetName))
                        {
                            writer.WriteAttributeString("name", urhoAssetName);
                        }
                    }

                    writer.WriteEndElement();
                    writer.WriteWhitespace(Environment.NewLine);
                }

                {
                    writer.WriteStartElement("parameter");
                    writer.WriteAttributeString("name", "MatSpecColor");
                    writer.WriteAttributeString("value", "0.5 0.5 0.5 16");
                    writer.WriteEndElement();
                    writer.WriteWhitespace(Environment.NewLine);
                }
                {
                    writer.WriteStartElement("parameter");
                    writer.WriteAttributeString("name", "DetailTiling");
                    writer.WriteAttributeString("value", "32 32");
                    writer.WriteEndElement();
                    writer.WriteWhitespace(Environment.NewLine);
                }
                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
        }