Example #1
0
        private static string GetFontPath(SpriteFontAsset asset, AssetCompilerResult result)
        {
            using (var factory = new Factory())
            {
                Font font;

                using (var fontCollection = factory.GetSystemFontCollection(false))
                {
                    int index;
                    if (!fontCollection.FindFamilyName(asset.FontName, out index))
                    {
                        result.Error("Can't find font '{0}'.", asset.FontName);
                        return(null);
                    }

                    using (var fontFamily = fontCollection.GetFontFamily(index))
                    {
                        var weight = FontWeight.Regular;
                        var style  = SharpDX.DirectWrite.FontStyle.Normal;
                        switch (asset.Style)
                        {
                        case FontStyle.Bold:
                            weight = FontWeight.Bold;
                            break;

                        case FontStyle.Italic:
                            weight = FontWeight.Regular;
                            style  = SharpDX.DirectWrite.FontStyle.Italic;
                            break;

                        case FontStyle.Regular:
                            weight = FontWeight.Regular;
                            break;
                        }

                        font = fontFamily.GetFirstMatchingFont(weight, FontStretch.Normal, style);
                        if (font == null)
                        {
                            result.Error("Cannot find style '{0}' for font family {1}.", asset.Style, asset.FontName);
                            return(null);
                        }
                    }
                }

                var fontFace = new FontFace(font);

                // get the font path on the hard drive
                var file           = fontFace.GetFiles().First();
                var referenceKey   = file.GetReferenceKey();
                var originalLoader = (FontFileLoaderNative)file.Loader;
                var loader         = originalLoader.QueryInterface <LocalFontFileLoader>();
                return(loader.GetFilePath(referenceKey));
            }
        }
Example #2
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, SpriteFontAsset asset, AssetCompilerResult result)
        {
            var colorSpace = context.GetColorSpace();

            if (asset.IsDynamic)
            {
                UFile fontPathOnDisk;

                if (!string.IsNullOrEmpty(asset.Source))
                {
                    var assetDirectory = assetAbsolutePath.GetParent();
                    fontPathOnDisk = UPath.Combine(assetDirectory, asset.Source);
                    if (!File.Exists(fontPathOnDisk))
                    {
                        result.Error("The font source '{0}' does not exist on the PC.", asset.FontName);
                        return;
                    }
                    // set the source filename as font name instead of the font family.
                    asset.FontName = fontPathOnDisk.GetFileName();
                }
                else
                {
                    fontPathOnDisk = GetFontPath(asset, result);
                    if (fontPathOnDisk == null)
                    {
                        result.Error("The font named '{0}' could not be located on the PC.", asset.FontName);
                        return;
                    }
                }
                var fontImportLocation = FontHelper.GetFontPath(asset.FontName, asset.Style);

                result.BuildSteps = new AssetBuildStep(AssetItem)
                {
                    new ImportStreamCommand {
                        SourcePath = fontPathOnDisk, Location = fontImportLocation
                    },
                    new DynamicFontCommand(urlInStorage, asset)
                };
            }
            else
            {
                // copy the asset and transform the source and character set file path to absolute paths
                var assetClone     = (SpriteFontAsset)AssetCloner.Clone(asset);
                var assetDirectory = assetAbsolutePath.GetParent();
                assetClone.Source       = !string.IsNullOrEmpty(asset.Source) ? UPath.Combine(assetDirectory, asset.Source): null;
                assetClone.CharacterSet = !string.IsNullOrEmpty(asset.CharacterSet) ? UPath.Combine(assetDirectory, asset.CharacterSet): null;

                result.BuildSteps = new AssetBuildStep(AssetItem)
                {
                    new StaticFontCommand(urlInStorage, assetClone, colorSpace)
                };
            }
        }
Example #3
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, EntityAsset asset, AssetCompilerResult result)
        {
            foreach (var entityData in asset.Hierarchy.Entities)
            {
                // TODO: How to make this code pluggable?
                var modelComponent  = entityData.Components.Get(ModelComponent.Key);
                var spriteComponent = entityData.Components.Get(SpriteComponent.Key);
                var scriptComponent = entityData.Components.Get(ScriptComponent.Key);

                // determine the underlying source asset exists
                if (modelComponent != null)
                {
                    if (modelComponent.Model == null)
                    {
                        result.Warning(string.Format("The entity [{0}:{1}] has a model component that does not reference any model.", urlInStorage, entityData.Name));
                        continue;
                    }

                    var modelAttachedReference = AttachedReferenceManager.GetAttachedReference(modelComponent.Model);
                    var modelId = modelAttachedReference.Id;

                    // compute the full path to the source asset.
                    var assetItem = AssetItem.Package.Session.FindAsset(modelId);
                    if (assetItem == null)
                    {
                        result.Error(string.Format("The entity [{0}:{1}] is referencing an unreachable model.", urlInStorage, entityData.Name));
                        continue;
                    }
                }
                if (spriteComponent != null && spriteComponent.SpriteProvider == null)
                {
                    result.Warning(string.Format("The entity [{0}:{1}] has a sprite component that does not reference any sprite group.", urlInStorage, entityData.Name));
                }
                if (scriptComponent != null)
                {
                    foreach (var script in scriptComponent.Scripts)
                    {
                        if (script is UnloadableScript)
                        {
                            result.Error(string.Format("The entity [{0}:{1}] reference an invalid script '{2}'.", urlInStorage, entityData.Name, script.GetType().Name));
                        }
                    }
                }
            }

            result.BuildSteps = new AssetBuildStep(AssetItem)
            {
                new EntityCombineCommand(urlInStorage, AssetItem.Package, context, asset)
            };
        }
Example #4
0
        protected override void Prepare(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var asset       = (SkeletonAsset)assetItem.Asset;
            var assetSource = GetAbsolutePath(assetItem, asset.Source);
            var extension   = assetSource.GetFileExtension();
            var buildStep   = new AssetBuildStep(assetItem);

            var importModelCommand = ImportModelCommand.Create(extension);

            if (importModelCommand == null)
            {
                result.Error($"No importer found for model extension '{extension}. The model '{assetSource}' can't be imported.");
                return;
            }

            importModelCommand.SourcePath    = assetSource;
            importModelCommand.Location      = targetUrlInStorage;
            importModelCommand.Mode          = ImportModelCommand.ExportMode.Skeleton;
            importModelCommand.ScaleImport   = asset.ScaleImport;
            importModelCommand.PivotPosition = asset.PivotPosition;
            importModelCommand.SkeletonNodesWithPreserveInfo = asset.NodesWithPreserveInfo;

            buildStep.Add(importModelCommand);

            result.BuildSteps = buildStep;
        }
        /// <inheritdoc />
        protected override void CompileThumbnail(ThumbnailCompilerContext context, string thumbnailStorageUrl, AssetItem assetItem, Package originalPackage, AssetCompilerResult result)
        {
            var   thumbnailSize = context.ThumbnailResolution;
            UFile assetSource   = null;

            var sourceValid = !string.IsNullOrEmpty(Asset.Source);

            if (sourceValid)
            {
                // Get absolute path of asset source on disk
                var assetDirectory = assetItem.FullPath.GetParent();
                assetSource = UPath.Combine(assetDirectory, Asset.Source);
                sourceValid = File.Exists(assetSource);
            }

            if (sourceValid)
            {
                result.BuildSteps.Add(new ThumbnailBuildStep(new TextureThumbnailBuildCommand(context, thumbnailStorageUrl, assetItem, originalPackage, new TextureThumbnailParameters(Asset, assetSource, thumbnailStorageUrl, thumbnailSize))));
            }
            else
            {
                var gameSettings = context.GetGameSettingsAsset();
                result.Error($"Source is null or unreachable for Texture Asset [{Asset}]");
                result.BuildSteps.Add(new StaticThumbnailCommand <TextureAsset>(thumbnailStorageUrl, DefaultThumbnails.TextureNoSource, thumbnailSize, gameSettings.GetOrCreate <RenderingSettings>().ColorSpace == ColorSpace.Linear, assetItem.Package));
            }
        }
Example #6
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, SkeletonAsset asset, AssetCompilerResult result)
        {
            if (!EnsureSourcesExist(result, asset, assetAbsolutePath))
            {
                return;
            }

            var assetSource = GetAbsolutePath(assetAbsolutePath, asset.Source);
            var extension   = assetSource.GetFileExtension();
            var buildStep   = new AssetBuildStep(AssetItem);

            var importModelCommand = ImportModelCommand.Create(extension);

            if (importModelCommand == null)
            {
                result.Error("No importer found for model extension '{0}. The model '{1}' can't be imported.", extension, assetSource);
                return;
            }

            importModelCommand.SourcePath    = assetSource;
            importModelCommand.Location      = urlInStorage;
            importModelCommand.Mode          = ImportModelCommand.ExportMode.Skeleton;
            importModelCommand.ScaleImport   = asset.ScaleImport;
            importModelCommand.PivotPosition = asset.PivotPosition;
            importModelCommand.SkeletonNodesWithPreserveInfo = asset.NodesWithPreserveInfo;

            buildStep.Add(importModelCommand);

            result.BuildSteps = buildStep;
        }
Example #7
0
        protected override void Prepare(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var   asset             = (SpriteFontAsset)assetItem.Asset;
            UFile assetAbsolutePath = assetItem.FullPath;
            var   colorSpace        = context.GetColorSpace();

            var fontTypeSdf = asset.FontType as SignedDistanceFieldSpriteFontType;

            if (fontTypeSdf != null)
            {
                // copy the asset and transform the source and character set file path to absolute paths
                var assetClone     = AssetCloner.Clone(asset);
                var assetDirectory = assetAbsolutePath.GetParent();
                assetClone.FontSource    = asset.FontSource;
                fontTypeSdf.CharacterSet = !string.IsNullOrEmpty(fontTypeSdf.CharacterSet) ? UPath.Combine(assetDirectory, fontTypeSdf.CharacterSet) : null;

                result.BuildSteps = new AssetBuildStep(assetItem);
                result.BuildSteps.Add(new SignedDistanceFieldFontCommand(targetUrlInStorage, assetClone, assetItem.Package));
            }
            else
            if (asset.FontType is RuntimeRasterizedSpriteFontType)
            {
                UFile fontPathOnDisk = asset.FontSource.GetFontPath(result);
                if (fontPathOnDisk == null)
                {
                    result.Error($"Runtime rasterized font compilation failed. Font {asset.FontSource.GetFontName()} was not found on this machine.");
                    result.BuildSteps = new AssetBuildStep(assetItem);
                    result.BuildSteps.Add(new FailedFontCommand());
                    return;
                }

                var fontImportLocation = FontHelper.GetFontPath(asset.FontSource.GetFontName(), asset.FontSource.Style);

                result.BuildSteps = new AssetBuildStep(assetItem);
                result.BuildSteps.Add(new ImportStreamCommand {
                    SourcePath = fontPathOnDisk, Location = fontImportLocation
                });
                result.BuildSteps.Add(new RuntimeRasterizedFontCommand(targetUrlInStorage, asset, assetItem.Package));
            }
            else
            {
                var fontTypeStatic = asset.FontType as OfflineRasterizedSpriteFontType;
                if (fontTypeStatic == null)
                {
                    throw new ArgumentException("Tried to compile a non-offline rasterized sprite font with the compiler for offline resterized fonts!");
                }

                // copy the asset and transform the source and character set file path to absolute paths
                var assetClone     = AssetCloner.Clone(asset);
                var assetDirectory = assetAbsolutePath.GetParent();
                assetClone.FontSource       = asset.FontSource;
                fontTypeStatic.CharacterSet = !string.IsNullOrEmpty(fontTypeStatic.CharacterSet) ? UPath.Combine(assetDirectory, fontTypeStatic.CharacterSet): null;

                result.BuildSteps = new AssetBuildStep(assetItem);
                result.BuildSteps.Add(new OfflineRasterizedFontCommand(targetUrlInStorage, assetClone, colorSpace, assetItem.Package)
                {
                    InputFilesGetter = () => GetInputFiles(assetItem)
                });
            }
        }
 /// <inheritdoc/>
 public override string GetFontPath(AssetCompilerResult result = null)
 {
     if (!File.Exists(Source))
     {
         result?.Error($"Cannot find font file '{Source}'. Make sure it exists and is referenced correctly.");
     }
     return(Source);
 }
Example #9
0
        protected override void Prepare(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var asset = (ModelAsset)assetItem.Asset;

            // Get absolute path of asset source on disk
            var assetDirectory = assetItem.FullPath.GetParent();
            var assetSource    = UPath.Combine(assetDirectory, asset.Source);

            var gameSettingsAsset         = context.GetGameSettingsAsset();
            var renderingSettings         = gameSettingsAsset.GetOrCreate <RenderingSettings>();
            var allow32BitIndex           = true;
            var maxInputSlots             = 32;
            var allowUnsignedBlendIndices = true;
            var extension = asset.Source.GetFileExtension();

            // Find skeleton asset, if any
            AssetItem skeleton = null;

            if (asset.Skeleton != null)
            {
                skeleton = assetItem.Package.FindAssetFromProxyObject(asset.Skeleton);
            }

            var importModelCommand = ImportModelCommand.Create(extension);

            if (importModelCommand is null)
            {
                result.Error($"No importer found for model extension '{extension}'. The model '{assetSource}' can't be imported.");
                return;
            }

            importModelCommand.InputFilesGetter          = () => GetInputFiles(assetItem);
            importModelCommand.Mode                      = ImportModelCommand.ExportMode.Model;
            importModelCommand.SourcePath                = assetSource;
            importModelCommand.Location                  = targetUrlInStorage;
            importModelCommand.Allow32BitIndex           = allow32BitIndex;
            importModelCommand.MaxInputSlots             = maxInputSlots;
            importModelCommand.AllowUnsignedBlendIndices = allowUnsignedBlendIndices;
            importModelCommand.Materials                 = asset.Materials;
            importModelCommand.ScaleImport               = asset.ScaleImport;
            importModelCommand.PivotPosition             = asset.PivotPosition;
            importModelCommand.MergeMeshes               = asset.MergeMeshes;
            importModelCommand.DeduplicateMaterials      = asset.DeduplicateMaterials;
            importModelCommand.ModelModifiers            = asset.Modifiers;

            if (skeleton != null)
            {
                importModelCommand.SkeletonUrl = skeleton.Location;
                // NOTE: Skeleton override values
                importModelCommand.ScaleImport   = ((SkeletonAsset)skeleton.Asset).ScaleImport;
                importModelCommand.PivotPosition = ((SkeletonAsset)skeleton.Asset).PivotPosition;
            }

            importModelCommand.Package = assetItem.Package;

            result.BuildSteps = new AssetBuildStep(assetItem);
            result.BuildSteps.Add(importModelCommand);
        }
Example #10
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, TGroupAsset asset, AssetCompilerResult result)
        {
            result.BuildSteps = new ListBuildStep();

            // Evaluate if we need to use a separate the alpha texture
            SeparateAlphaTexture = TextureCommandHelper.ShouldSeparateAlpha(asset.Alpha, asset.Format, context.Platform, context.GetGraphicsProfile());

            // create the registry containing the sprite assets texture index association
            SpriteToTextureIndex = new Dictionary <TImageInfo, int>();

            // create and add import texture commands
            if (asset.Images != null)
            {
                // return compilation error if one or more of the sprite does not have a valid texture
                var noSourceAsset = asset.Images.FirstOrDefault(x => !TextureFileIsValid(x.Source));
                if (noSourceAsset != null)
                {
                    result.Error("The texture of image '{0}' either does not exist or is invalid", noSourceAsset.Name);
                    return;
                }

                // sort sprites by referenced texture.
                var spriteByTextures = asset.Images.GroupBy(x => x.Source).ToArray();
                for (int i = 0; i < spriteByTextures.Length; i++)
                {
                    var spriteAssetArray = spriteByTextures[i].ToArray();
                    foreach (var spriteAsset in spriteAssetArray)
                    {
                        SpriteToTextureIndex[spriteAsset] = i;
                    }

                    // create an texture asset.
                    var textureAsset = new TextureAsset
                    {
                        Id               = Guid.Empty, // CAUTION: It is important to use an empty GUID here, as we don't want the command to be rebuilt (by default, a new asset is creating a new guid)
                        Alpha            = asset.Alpha,
                        Format           = asset.Format,
                        GenerateMipmaps  = asset.GenerateMipmaps,
                        PremultiplyAlpha = asset.PremultiplyAlpha,
                        ColorKeyColor    = asset.ColorKeyColor,
                        ColorKeyEnabled  = asset.ColorKeyEnabled,
                    };

                    // Get absolute path of asset source on disk
                    var assetDirectory = assetAbsolutePath.GetParent();
                    var assetSource    = UPath.Combine(assetDirectory, spriteAssetArray[0].Source);

                    // add the texture build command.
                    result.BuildSteps.Add(
                        new TextureAssetCompiler.TextureConvertCommand(
                            ImageGroupAsset.BuildTextureUrl(urlInStorage, i),
                            new TextureConvertParameters(assetSource, textureAsset, context.Platform, context.GetGraphicsPlatform(), context.GetGraphicsProfile(), context.GetTextureQuality(), SeparateAlphaTexture)));
                }

                result.BuildSteps.Add(new WaitBuildStep()); // wait the textures to be imported
            }
        }
Example #11
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, ModelAsset asset, AssetCompilerResult result)
        {
            if (!EnsureSourceExists(result, asset, assetAbsolutePath))
            {
                return;
            }

            // Get absolute path of asset source on disk
            var assetDirectory = assetAbsolutePath.GetParent();
            var assetSource    = UPath.Combine(assetDirectory, asset.Source);

            var gameSettingsAsset         = context.GetGameSettingsAsset();
            var allow32BitIndex           = gameSettingsAsset.DefaultGraphicsProfile >= GraphicsProfile.Level_9_2;
            var allowUnsignedBlendIndices = context.GetGraphicsPlatform() != GraphicsPlatform.OpenGLES;
            var extension = asset.Source.GetFileExtension();

            if (ImportFbxCommand.IsSupportingExtensions(extension))
            {
                result.BuildSteps = new AssetBuildStep(AssetItem)
                {
                    new ImportFbxCommand
                    {
                        SourcePath                = assetSource,
                        Location                  = urlInStorage,
                        Allow32BitIndex           = allow32BitIndex,
                        AllowUnsignedBlendIndices = allowUnsignedBlendIndices,
                        Compact        = asset.Compact,
                        PreservedNodes = asset.PreservedNodes,
                        Materials      = asset.Materials,
                        ScaleImport    = asset.ScaleImport,
                    },
                };
            }
            else if (ImportAssimpCommand.IsSupportingExtensions(extension))
            {
                result.BuildSteps = new AssetBuildStep(AssetItem)
                {
                    new ImportAssimpCommand
                    {
                        SourcePath                = assetSource,
                        Location                  = urlInStorage,
                        Allow32BitIndex           = allow32BitIndex,
                        AllowUnsignedBlendIndices = allowUnsignedBlendIndices,
                        Compact        = asset.Compact,
                        PreservedNodes = asset.PreservedNodes,
                        Materials      = asset.Materials,
                        ScaleImport    = asset.ScaleImport,
                    },
                };
            }
            else
            {
                result.Error("No importer found for model extension '{0}. The model '{1}' can't be imported.", extension, assetSource);
            }
        }
Example #12
0
        public override string GetFontPath(AssetCompilerResult result = null)
        {
            using (var factory = new Factory())
            {
                Font font;

                using (var fontCollection = factory.GetSystemFontCollection(false))
                {
                    int index;
                    if (!fontCollection.FindFamilyName(FontName, out index))
                    {
                        result?.Error($"Cannot find system font '{FontName}'. Make sure it is installed on this machine.");
                        return(null);
                    }

                    using (var fontFamily = fontCollection.GetFontFamily(index))
                    {
                        var weight = Style.IsBold() ? FontWeight.Bold : FontWeight.Regular;
                        var style  = Style.IsItalic() ? SharpDX.DirectWrite.FontStyle.Italic : SharpDX.DirectWrite.FontStyle.Normal;
                        font = fontFamily.GetFirstMatchingFont(weight, FontStretch.Normal, style);
                        if (font == null)
                        {
                            result?.Error($"Cannot find style '{Style}' for font family {FontName}. Make sure it is installed on this machine.");
                            return(null);
                        }
                    }
                }

                var fontFace = new FontFace(font);

                // get the font path on the hard drive
                var file           = fontFace.GetFiles().First();
                var referenceKey   = file.GetReferenceKey();
                var originalLoader = (FontFileLoaderNative)file.Loader;
                var loader         = originalLoader.QueryInterface <LocalFontFileLoader>();
                return(loader.GetFilePath(referenceKey));
            }
        }
Example #13
0
        private void WriteResult(AssetCompilerResult result, string componentName, string targetUrlInStorage, string entityName, string memberName, MemberRequiredReportType reportType)
        {
            var logMsg = $"The component {componentName} on entity [{targetUrlInStorage}:{entityName}] is missing a value on a required field '{memberName}'.";

            switch (reportType)
            {
            case MemberRequiredReportType.Warning:
                result.Warning(logMsg);
                break;

            case MemberRequiredReportType.Error:
                result.Error(logMsg);
                break;
            }
        }
Example #14
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, ModelAsset asset, AssetCompilerResult result)
        {
            if (!EnsureSourcesExist(result, asset, assetAbsolutePath))
            {
                return;
            }

            // Get absolute path of asset source on disk
            var assetDirectory = assetAbsolutePath.GetParent();
            var assetSource    = UPath.Combine(assetDirectory, asset.Source);

            var gameSettingsAsset         = context.GetGameSettingsAsset();
            var renderingSettings         = gameSettingsAsset.Get <RenderingSettings>();
            var allow32BitIndex           = renderingSettings.DefaultGraphicsProfile >= GraphicsProfile.Level_9_2;
            var allowUnsignedBlendIndices = context.GetGraphicsPlatform(AssetItem.Package) != GraphicsPlatform.OpenGLES;
            var extension = asset.Source.GetFileExtension();

            // Find skeleton asset, if any
            AssetItem skeleton = null;

            if (asset.Skeleton != null)
            {
                skeleton = AssetItem.Package.FindAssetFromAttachedReference(asset.Skeleton);
            }

            var importModelCommand = ImportModelCommand.Create(extension);

            if (importModelCommand == null)
            {
                result.Error("No importer found for model extension '{0}. The model '{1}' can't be imported.", extension, assetSource);
                return;
            }

            importModelCommand.Mode                      = ImportModelCommand.ExportMode.Model;
            importModelCommand.SourcePath                = assetSource;
            importModelCommand.Location                  = urlInStorage;
            importModelCommand.Allow32BitIndex           = allow32BitIndex;
            importModelCommand.AllowUnsignedBlendIndices = allowUnsignedBlendIndices;
            importModelCommand.Materials                 = asset.Materials;
            importModelCommand.ScaleImport               = asset.ScaleImport;
            importModelCommand.PivotPosition             = asset.PivotPosition;
            importModelCommand.SkeletonUrl               = skeleton?.Location;

            result.BuildSteps = new AssetBuildStep(AssetItem)
            {
                importModelCommand
            };
        }
Example #15
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, TextureAsset asset, AssetCompilerResult result)
        {
            if (asset.Source == null)
            {
                result.Error("Source cannot be null for Texture Asset [{0}]", asset);
                return;
            }

            // Get absolute path of asset source on disk
            var assetDirectory = assetAbsolutePath.GetParent();
            var assetSource    = UPath.Combine(assetDirectory, asset.Source);

            result.BuildSteps = new ListBuildStep {
                new TextureConvertCommand(urlInStorage,
                                          new TextureConvertParameters(assetSource, asset, context.Platform, context.GetGraphicsPlatform(), context.GetGraphicsProfile(), context.GetTextureQuality(), false))
            };
        }
Example #16
0
        protected override void Compile(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var asset = (ModelAsset)assetItem.Asset;
            // Get absolute path of asset source on disk
            var assetDirectory = assetItem.FullPath.GetParent();
            var assetSource    = UPath.Combine(assetDirectory, asset.Source);

            var gameSettingsAsset         = context.GetGameSettingsAsset();
            var renderingSettings         = gameSettingsAsset.Get <RenderingSettings>();
            var allow32BitIndex           = renderingSettings.DefaultGraphicsProfile >= GraphicsProfile.Level_9_2;
            var maxInputSlots             = renderingSettings.DefaultGraphicsProfile >= GraphicsProfile.Level_10_1 ? 32 : 16;
            var allowUnsignedBlendIndices = context.GetGraphicsPlatform(assetItem.Package) != GraphicsPlatform.OpenGLES;
            var extension = asset.Source.GetFileExtension();

            // Find skeleton asset, if any
            AssetItem skeleton = null;

            if (asset.Skeleton != null)
            {
                skeleton = assetItem.Package.FindAssetFromProxyObject(asset.Skeleton);
            }

            var importModelCommand = ImportModelCommand.Create(extension);

            if (importModelCommand == null)
            {
                result.Error($"No importer found for model extension '{extension}. The model '{assetSource}' can't be imported.");
                return;
            }

            importModelCommand.Mode                      = ImportModelCommand.ExportMode.Model;
            importModelCommand.SourcePath                = assetSource;
            importModelCommand.Location                  = targetUrlInStorage;
            importModelCommand.Allow32BitIndex           = allow32BitIndex;
            importModelCommand.MaxInputSlots             = maxInputSlots;
            importModelCommand.AllowUnsignedBlendIndices = allowUnsignedBlendIndices;
            importModelCommand.Materials                 = asset.Materials;
            importModelCommand.ScaleImport               = asset.ScaleImport;
            importModelCommand.PivotPosition             = asset.PivotPosition;
            importModelCommand.SkeletonUrl               = skeleton?.Location;

            result.BuildSteps = new AssetBuildStep(assetItem)
            {
                importModelCommand
            };
        }
Example #17
0
        protected override void CompileThumbnail(ThumbnailCompilerContext context, string thumbnailStorageUrl, AssetItem assetItem, Package originalPackage, AssetCompilerResult result)
        {
            UFile fontPathOnDisk = Asset.FontSource.GetFontPath();
            bool  sourceIsValid  = (fontPathOnDisk != null && File.Exists(fontPathOnDisk));

            if (sourceIsValid)
            {
                result.BuildSteps.Add(new ThumbnailBuildStep(new FontThumbnailBuildCommand(context, thumbnailStorageUrl, assetItem, originalPackage,
                                                                                           new ThumbnailCommandParameters(assetItem.Asset, thumbnailStorageUrl, context.ThumbnailResolution))));
            }
            else
            {
                var thumbnailSize = context.ThumbnailResolution;
                var isLinear      = context.GetGameSettingsAsset().GetOrCreate <RenderingSettings>().ColorSpace == ColorSpace.Linear;
                result.Error($"Source is null or unreachable for Texture Asset [{Asset}]");
                result.BuildSteps.Add(new StaticThumbnailCommand <SpriteFontAsset>(thumbnailStorageUrl, DefaultThumbnails.AssetBrokenThumbnail, thumbnailSize, isLinear, assetItem.Package));
            }
        }
Example #18
0
        protected override void Prepare(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var asset = (T)assetItem.Asset;

            foreach (var entityData in asset.Hierarchy.Parts.Values)
            {
                // TODO: How to make this code pluggable?
                var modelComponent = entityData.Entity.Components.Get <ModelComponent>();
                if (modelComponent != null)
                {
                    if (modelComponent.Model == null)
                    {
                        result.Warning($"The entity [{targetUrlInStorage}:{entityData.Entity.Name}] has a model component that does not reference any model.");
                    }
                    else
                    {
                        var modelAttachedReference = AttachedReferenceManager.GetAttachedReference(modelComponent.Model);
                        var modelId = modelAttachedReference.Id;

                        // compute the full path to the source asset.
                        var modelAssetItem = assetItem.Package.Session.FindAsset(modelId);
                        if (modelAssetItem == null)
                        {
                            result.Error($"The entity [{targetUrlInStorage}:{entityData.Entity.Name}] is referencing an unreachable model.");
                        }
                    }
                }

                var nodeLinkComponent = entityData.Entity.Components.Get <ModelNodeLinkComponent>();
                if (nodeLinkComponent != null)
                {
                    nodeLinkComponent.ValidityCheck();
                    if (!nodeLinkComponent.IsValid)
                    {
                        result.Warning($"The Model Node Link between {entityData.Entity.Name} and {nodeLinkComponent.Target?.Entity.Name} is invalid.");
                        nodeLinkComponent.Target = null;
                    }
                }
            }

            result.BuildSteps = new AssetBuildStep(assetItem);
            result.BuildSteps.Add(Create(targetUrlInStorage, asset, assetItem.Package));
        }
Example #19
0
        /// <inheritdoc/>
        public void Check(EntityComponent component, Entity entity, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var modelComponent = component as ModelComponent;
            if (modelComponent.Model == null)
            {
                result.Warning($"The entity [{targetUrlInStorage}:{entity.Name}] has a model component that does not reference any model.");
            }
            else
            {
                var modelAttachedReference = AttachedReferenceManager.GetAttachedReference(modelComponent.Model);
                var modelId = modelAttachedReference.Id;

                // compute the full path to the source asset.
                var modelAssetItem = assetItem.Package.Session.FindAsset(modelId);
                if (modelAssetItem == null)
                {
                    result.Error($"The entity [{targetUrlInStorage}:{entity.Name}] is referencing an unreachable model.");
                }
            }
        }
Example #20
0
        protected override void Compile(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var asset = (T)assetItem.Asset;

            foreach (var entityData in asset.Hierarchy.Parts)
            {
                // TODO: How to make this code pluggable?
                var modelComponent  = entityData.Entity.Components.Get <ModelComponent>();
                var spriteComponent = entityData.Entity.Components.Get <SpriteComponent>();

                // determine the underlying source asset exists
                if (modelComponent != null)
                {
                    if (modelComponent.Model == null)
                    {
                        result.Warning($"The entity [{targetUrlInStorage}:{entityData.Entity.Name}] has a model component that does not reference any model.");
                        continue;
                    }

                    var modelAttachedReference = AttachedReferenceManager.GetAttachedReference(modelComponent.Model);
                    var modelId = modelAttachedReference.Id;

                    // compute the full path to the source asset.
                    var modelAssetItem = assetItem.Package.Session.FindAsset(modelId);
                    if (modelAssetItem == null)
                    {
                        result.Error($"The entity [{targetUrlInStorage}:{entityData.Entity.Name}] is referencing an unreachable model.");
                        continue;
                    }
                }
                if (spriteComponent != null && spriteComponent.SpriteProvider == null)
                {
                    result.Warning($"The entity [{targetUrlInStorage}:{entityData.Entity.Name}] has a sprite component that does not reference any sprite group.");
                }
            }

            result.BuildSteps = new AssetBuildStep(assetItem)
            {
                Create(targetUrlInStorage, asset)
            };
        }
Example #21
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, ModelAsset asset, AssetCompilerResult result)
        {
            if (asset.Source == null)
            {
                result.Error("Source cannot be null for Texture Asset [{0}]", asset);
                return;
            }

            // Get absolute path of asset source on disk
            var assetDirectory = assetAbsolutePath.GetParent();
            var assetSource    = UPath.Combine(assetDirectory, asset.Source);

            var allow32BitIndex           = context.GetGraphicsProfile() >= GraphicsProfile.Level_9_2;
            var allowUnsignedBlendIndices = context.GetGraphicsPlatform() != GraphicsPlatform.OpenGLES;
            var extension = asset.Source.GetFileExtension();

            // compute material and lighting configuration dictionaries here because some null reference can occur
            var materials = new Dictionary <string, Tuple <Guid, string> >();
            var lightings = new Dictionary <string, Tuple <Guid, string> >();

            foreach (var meshParam in asset.MeshParameters)
            {
                if (meshParam.Value.Material != null)
                {
                    materials.Add(meshParam.Key, new Tuple <Guid, string>(meshParam.Value.Material.Id, meshParam.Value.Material.Location));
                }

                // Transform AssetReference to Tuple<Guid,UFile> as AssetReference or ContentReference is not serializable (to generate the command hash)
                // TODO: temporary while the LightingParameters is a Member of MeshMaterialParameter class
                // TODO: should be passed directly in the Parameters of the mesh - no extra case is required
                if (meshParam.Value.LightingParameters != null)
                {
                    lightings.Add(meshParam.Key, new Tuple <Guid, string>(meshParam.Value.LightingParameters.Id, meshParam.Value.LightingParameters.Location));
                }
            }

            if (ImportFbxCommand.IsSupportingExtensions(extension))
            {
                result.BuildSteps = new ListBuildStep
                {
                    new ImportFbxCommand
                    {
                        SourcePath                = assetSource,
                        Location                  = urlInStorage,
                        Allow32BitIndex           = allow32BitIndex,
                        AllowUnsignedBlendIndices = allowUnsignedBlendIndices,
                        Compact        = asset.Compact,
                        PreservedNodes = asset.PreservedNodes,
                        Materials      = materials,
                        Lightings      = lightings,    // TODO: remove when lighting parameters will be behind a key
                        Parameters     = asset.MeshParameters.ToDictionary(pair => pair.Key, pair => pair.Value.Parameters),
                        ViewDirectionForTransparentZSort = asset.ViewDirectionForTransparentZSort.HasValue ? asset.ViewDirectionForTransparentZSort.Value : -Vector3.UnitZ,
                    },
                    new WaitBuildStep(),
                };
            }
            else if (ImportAssimpCommand.IsSupportingExtensions(extension))
            {
                result.BuildSteps = new ListBuildStep
                {
                    new ImportAssimpCommand
                    {
                        SourcePath                = assetSource,
                        Location                  = urlInStorage,
                        Allow32BitIndex           = allow32BitIndex,
                        AllowUnsignedBlendIndices = allowUnsignedBlendIndices,
                        Compact        = asset.Compact,
                        PreservedNodes = asset.PreservedNodes,
                        Materials      = materials,
                        Lightings      = lightings,    // TODO: remove when lighting parameters will be behind a key
                        Parameters     = asset.MeshParameters.ToDictionary(pair => pair.Key, pair => pair.Value.Parameters),
                    },
                    new WaitBuildStep(),
                };
            }
            else
            {
                result.Error("No importer found for model extension '{0}. The model '{1}' can't be imported.", extension, assetSource);
            }
        }
Example #22
0
        protected override void Prepare(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var asset             = (AnimationAsset)assetItem.Asset;
            var assetAbsolutePath = assetItem.FullPath;
            // Get absolute path of asset source on disk
            var assetDirectory = assetAbsolutePath.GetParent();
            var assetSource    = GetAbsolutePath(assetItem, asset.Source);
            var extension      = assetSource.GetFileExtension();
            var buildStep      = new AssetBuildStep(assetItem);

            // Find skeleton asset, if any
            AssetItem skeleton = null;

            if (asset.Skeleton != null)
            {
                skeleton = assetItem.Package.FindAssetFromProxyObject(asset.Skeleton);
            }

            var sourceBuildCommand = ImportModelCommand.Create(extension);

            if (sourceBuildCommand == null)
            {
                result.Error($"No importer found for model extension '{extension}. The model '{assetSource}' can't be imported.");
                return;
            }

            sourceBuildCommand.Mode                   = ImportModelCommand.ExportMode.Animation;
            sourceBuildCommand.SourcePath             = assetSource;
            sourceBuildCommand.Location               = targetUrlInStorage;
            sourceBuildCommand.AnimationRepeatMode    = asset.RepeatMode;
            sourceBuildCommand.AnimationRootMotion    = asset.RootMotion;
            sourceBuildCommand.ImportCustomAttributes = asset.ImportCustomAttributes;
            if (asset.ClipDuration.Enabled)
            {
                sourceBuildCommand.StartFrame = asset.ClipDuration.StartAnimationTime;
                sourceBuildCommand.EndFrame   = asset.ClipDuration.EndAnimationTime;
            }
            else
            {
                sourceBuildCommand.StartFrame = TimeSpan.Zero;
                sourceBuildCommand.EndFrame   = AnimationAsset.LongestTimeSpan;
            }
            sourceBuildCommand.ScaleImport   = asset.ScaleImport;
            sourceBuildCommand.PivotPosition = asset.PivotPosition;

            if (skeleton != null)
            {
                sourceBuildCommand.SkeletonUrl = skeleton.Location;
                // Note: skeleton override values
                sourceBuildCommand.ScaleImport   = ((SkeletonAsset)skeleton.Asset).ScaleImport;
                sourceBuildCommand.PivotPosition = ((SkeletonAsset)skeleton.Asset).PivotPosition;
            }

            if (asset.Type.Type == AnimationAssetTypeEnum.AnimationClip)
            {
                // Import the main animation
                buildStep.Add(sourceBuildCommand);
            }
            else if (asset.Type.Type == AnimationAssetTypeEnum.DifferenceClip)
            {
                var diffAnimationAsset = ((DifferenceAnimationAssetType)asset.Type);
                var referenceClip      = diffAnimationAsset.BaseSource;
                var rebaseMode         = diffAnimationAsset.Mode;

                var baseUrlInStorage   = targetUrlInStorage + RefClipSuffix;
                var sourceUrlInStorage = targetUrlInStorage + SrcClipSuffix;

                var baseAssetSource = UPath.Combine(assetDirectory, referenceClip);
                var baseExtension   = baseAssetSource.GetFileExtension();

                sourceBuildCommand.Location = sourceUrlInStorage;

                var baseBuildCommand = ImportModelCommand.Create(extension);
                if (baseBuildCommand == null)
                {
                    result.Error($"No importer found for model extension '{baseExtension}. The model '{baseAssetSource}' can't be imported.");
                    return;
                }

                baseBuildCommand.FailOnEmptyAnimation = false;
                baseBuildCommand.Mode                = ImportModelCommand.ExportMode.Animation;
                baseBuildCommand.SourcePath          = baseAssetSource;
                baseBuildCommand.Location            = baseUrlInStorage;
                baseBuildCommand.AnimationRepeatMode = asset.RepeatMode;
                baseBuildCommand.AnimationRootMotion = asset.RootMotion;

                if (diffAnimationAsset.ClipDuration.Enabled)
                {
                    baseBuildCommand.StartFrame = diffAnimationAsset.ClipDuration.StartAnimationTimeBox;
                    baseBuildCommand.EndFrame   = diffAnimationAsset.ClipDuration.EndAnimationTimeBox;
                }
                else
                {
                    baseBuildCommand.StartFrame = TimeSpan.Zero;
                    baseBuildCommand.EndFrame   = AnimationAsset.LongestTimeSpan;
                }

                baseBuildCommand.ScaleImport   = asset.ScaleImport;
                baseBuildCommand.PivotPosition = asset.PivotPosition;

                if (skeleton != null)
                {
                    baseBuildCommand.SkeletonUrl = skeleton.Location;
                    // Note: skeleton override values
                    baseBuildCommand.ScaleImport   = ((SkeletonAsset)skeleton.Asset).ScaleImport;
                    baseBuildCommand.PivotPosition = ((SkeletonAsset)skeleton.Asset).PivotPosition;
                }

                // Import base and main animation
                var sourceStep = new CommandBuildStep(sourceBuildCommand);
                buildStep.Add(sourceStep);
                var baseStep = new CommandBuildStep(baseBuildCommand);
                buildStep.Add(baseStep);

                IEnumerable <ObjectUrl> InputFilesGetter()
                {
                    yield return(new ObjectUrl(UrlType.File, GetAbsolutePath(assetItem, diffAnimationAsset.BaseSource)));
                }

                var diffCommand = new AdditiveAnimationCommand(targetUrlInStorage, new AdditiveAnimationParameters(baseUrlInStorage, sourceUrlInStorage, rebaseMode), assetItem.Package)
                {
                    InputFilesGetter = InputFilesGetter
                };

                var diffStep = new CommandBuildStep(diffCommand);

                BuildStep.LinkBuildSteps(sourceStep, diffStep);
                BuildStep.LinkBuildSteps(baseStep, diffStep);

                // Generate the diff of those two animations
                buildStep.Add(diffStep);
            }
            else
            {
                throw new NotImplementedException("This type of animation asset is not supported yet!");
            }

            result.BuildSteps = buildStep;
        }
Example #23
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, AnimationAsset asset, AssetCompilerResult result)
        {
            if (!EnsureSourceExists(result, asset, assetAbsolutePath))
            {
                return;
            }

            // Get absolute path of asset source on disk
            var assetDirectory = assetAbsolutePath.GetParent();
            var assetSource    = GetAbsolutePath(assetAbsolutePath, asset.Source);
            var extension      = assetSource.GetFileExtension();
            var buildStep      = new AssetBuildStep(AssetItem);

            // Find skeleton asset, if any
            AssetItem skeleton = null;

            if (asset.Skeleton != null)
            {
                skeleton = AssetItem.Package.FindAssetFromAttachedReference(asset.Skeleton);
            }

            var sourceBuildStep = ImportModelCommand.Create(extension);

            if (sourceBuildStep == null)
            {
                result.Error("No importer found for model extension '{0}. The model '{1}' can't be imported.", extension, assetSource);
                return;
            }

            sourceBuildStep.Mode                = ImportModelCommand.ExportMode.Animation;
            sourceBuildStep.SourcePath          = assetSource;
            sourceBuildStep.Location            = urlInStorage;
            sourceBuildStep.AnimationRepeatMode = asset.RepeatMode;
            sourceBuildStep.AnimationRootMotion = asset.RootMotion;
            sourceBuildStep.ScaleImport         = asset.ScaleImport;
            sourceBuildStep.SkeletonUrl         = skeleton?.Location;

            var additiveAnimationAsset = asset as AdditiveAnimationAsset;

            if (additiveAnimationAsset != null)
            {
                var baseUrlInStorage   = urlInStorage + "_animation_base";
                var sourceUrlInStorage = urlInStorage + "_animation_source";

                var baseAssetSource = UPath.Combine(assetDirectory, additiveAnimationAsset.BaseSource);
                var baseExtension   = baseAssetSource.GetFileExtension();

                sourceBuildStep.Location = sourceUrlInStorage;

                var baseBuildStep = ImportModelCommand.Create(extension);
                if (baseBuildStep == null)
                {
                    result.Error("No importer found for model extension '{0}. The model '{1}' can't be imported.", baseExtension, baseAssetSource);
                    return;
                }

                baseBuildStep.Mode                = ImportModelCommand.ExportMode.Animation;
                baseBuildStep.SourcePath          = baseAssetSource;
                baseBuildStep.Location            = baseUrlInStorage;
                baseBuildStep.AnimationRepeatMode = asset.RepeatMode;
                baseBuildStep.AnimationRootMotion = asset.RootMotion;
                baseBuildStep.ScaleImport         = asset.ScaleImport;
                baseBuildStep.SkeletonUrl         = skeleton?.Location;

                // Import base and main animation
                buildStep.Add(sourceBuildStep);
                buildStep.Add(baseBuildStep);

                // Wait for both import fbx commands to be completed
                buildStep.Add(new WaitBuildStep());

                // Generate the diff of those two animations
                buildStep.Add(new AdditiveAnimationCommand(urlInStorage, new AdditiveAnimationParameters(baseUrlInStorage, sourceUrlInStorage, additiveAnimationAsset.Mode)));
            }
            else
            {
                // Import the main animation
                buildStep.Add(sourceBuildStep);
            }

            result.BuildSteps = buildStep;
        }
Example #24
0
        public AssetCompilerResult Prepare(AssetCompilerContext context, AssetItem assetItem)
        {
            var compilerResult = new AssetCompilerResult();

            Asset = (T)assetItem.Asset;
            var thumbnailCompilerContext = (ThumbnailCompilerContext)context;

            // Build the path of the thumbnail in the storage
            var thumbnailStorageUrl = BuildThumbnailStoreName(assetItem.Location);

            // Check if this asset produced any error
            // (dependent assets errors are generally ignored as long as thumbnail could be generated,
            // but we will add a thumbnail overlay to indicate the state is not good)
            var currentAssetHasErrors = false;

            try
            {
                CompileThumbnail(thumbnailCompilerContext, thumbnailStorageUrl, assetItem, assetItem.Package, compilerResult);
            }
            catch (Exception)
            {
                // If an exception occurs, ensure that the build of thumbnail will fail.
                compilerResult.Error($"An exception occurred while compiling the asset [{assetItem.Location}]");
            }

            foreach (var logMessage in compilerResult.Messages)
            {
                // Ignore anything less than error
                if (!logMessage.IsAtLeast(LogMessageType.Error))
                {
                    continue;
                }

                // Check if there is any non-asset log message
                // (they are probably just emitted by current compiler, so they concern current asset)
                // TODO: Maybe we should wrap every message in AssetLogMessage before copying them in compilerResult?
                var assetLogMessage = logMessage as AssetLogMessage;
                if (assetLogMessage == null)
                {
                    currentAssetHasErrors = true;
                    break;
                }

                // If it was an asset log message, check it concerns current asset
                if (assetLogMessage.AssetReference != null && assetLogMessage.AssetReference.Location == assetItem.Location)
                {
                    currentAssetHasErrors = true;
                    break;
                }
            }
            if (currentAssetHasErrors)
            {
                // if a problem occurs while compiling, we add a special build step that will always fail.
                compilerResult.BuildSteps.Add(new ThumbnailFailureBuildStep(compilerResult.Messages));
            }

            var currentAsset = assetItem; // copy the current asset item and embrace it in the callback

            compilerResult.BuildSteps.StepProcessed += (_, buildStepArgs) => OnThumbnailStepProcessed(thumbnailCompilerContext, currentAsset, thumbnailStorageUrl, buildStepArgs);

            return(compilerResult);
        }
Example #25
0
        protected override void Compile(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
        {
            var asset             = (AnimationAsset)assetItem.Asset;
            var assetAbsolutePath = assetItem.FullPath;
            // Get absolute path of asset source on disk
            var assetDirectory = assetAbsolutePath.GetParent();
            var assetSource    = GetAbsolutePath(assetItem, asset.Source);
            var extension      = assetSource.GetFileExtension();
            var buildStep      = new AssetBuildStep(assetItem);

            // Find skeleton asset, if any
            AssetItem skeleton = null;

            if (asset.Skeleton != null)
            {
                skeleton = assetItem.Package.FindAssetFromProxyObject(asset.Skeleton);
            }

            var sourceBuildStep = ImportModelCommand.Create(extension);

            if (sourceBuildStep == null)
            {
                result.Error($"No importer found for model extension '{extension}. The model '{assetSource}' can't be imported.");
                return;
            }

            sourceBuildStep.Mode                = ImportModelCommand.ExportMode.Animation;
            sourceBuildStep.SourcePath          = assetSource;
            sourceBuildStep.Location            = targetUrlInStorage;
            sourceBuildStep.AnimationRepeatMode = asset.RepeatMode;
            sourceBuildStep.AnimationRootMotion = asset.RootMotion;
            if (asset.ClipDuration.Enabled)
            {
                sourceBuildStep.StartFrame = asset.ClipDuration.StartAnimationTime;
                sourceBuildStep.EndFrame   = asset.ClipDuration.EndAnimationTime;
            }
            else
            {
                sourceBuildStep.StartFrame = TimeSpan.Zero;
                sourceBuildStep.EndFrame   = AnimationAsset.LongestTimeSpan;
            }
            sourceBuildStep.ScaleImport   = asset.ScaleImport;
            sourceBuildStep.PivotPosition = asset.PivotPosition;
            sourceBuildStep.SkeletonUrl   = skeleton?.Location;

            if (asset.Type.Type == AnimationAssetTypeEnum.AnimationClip)
            {
                // Import the main animation
                buildStep.Add(sourceBuildStep);
            }
            else if (asset.Type.Type == AnimationAssetTypeEnum.DifferenceClip)
            {
                var diffAnimationAsset = ((DifferenceAnimationAssetType)asset.Type);
                var referenceClip      = diffAnimationAsset.BaseSource;
                var rebaseMode         = diffAnimationAsset.Mode;

                var baseUrlInStorage   = targetUrlInStorage + RefClipSuffix;
                var sourceUrlInStorage = targetUrlInStorage + SrcClipSuffix;

                var baseAssetSource = UPath.Combine(assetDirectory, referenceClip);
                var baseExtension   = baseAssetSource.GetFileExtension();

                sourceBuildStep.Location = sourceUrlInStorage;

                var baseBuildStep = ImportModelCommand.Create(extension);
                if (baseBuildStep == null)
                {
                    result.Error($"No importer found for model extension '{baseExtension}. The model '{baseAssetSource}' can't be imported.");
                    return;
                }

                baseBuildStep.Mode                = ImportModelCommand.ExportMode.Animation;
                baseBuildStep.SourcePath          = baseAssetSource;
                baseBuildStep.Location            = baseUrlInStorage;
                baseBuildStep.AnimationRepeatMode = asset.RepeatMode;
                baseBuildStep.AnimationRootMotion = asset.RootMotion;

                if (diffAnimationAsset.ClipDuration.Enabled)
                {
                    baseBuildStep.StartFrame = diffAnimationAsset.ClipDuration.StartAnimationTimeBox;
                    baseBuildStep.EndFrame   = diffAnimationAsset.ClipDuration.EndAnimationTimeBox;
                }
                else
                {
                    baseBuildStep.StartFrame = TimeSpan.Zero;
                    baseBuildStep.EndFrame   = AnimationAsset.LongestTimeSpan;
                }

                baseBuildStep.ScaleImport   = asset.ScaleImport;
                baseBuildStep.PivotPosition = asset.PivotPosition;
                baseBuildStep.SkeletonUrl   = skeleton?.Location;

                // Import base and main animation
                buildStep.Add(sourceBuildStep);
                buildStep.Add(baseBuildStep);

                // Wait for both import fbx commands to be completed
                buildStep.Add(new WaitBuildStep());

                // Generate the diff of those two animations
                buildStep.Add(new AdditiveAnimationCommand(targetUrlInStorage, new AdditiveAnimationParameters(baseUrlInStorage, sourceUrlInStorage, rebaseMode)));
            }
            else
            {
                throw new NotImplementedException("This type of animation asset is not supported yet!");
            }


            result.BuildSteps = buildStep;
        }