Giter Club home page Giter Club logo

assimp.net's People

Contributors

bsy-nicholasw avatar martoko avatar rjvs avatar starnick avatar tyoungsl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

assimp.net's Issues

A lot of errors

Why you make things so complicated?
please release a working version

image

Assimp version 5.2.3

Hi,

I'm using this plugin to load fbx files in Unity during runtime.
There seems to be an issue introduced in assimp version 5.2.4 that messes the bind poses.
Would it be possible to have a release for version 5.2.3?

Thanks,
Hugo

Support for net4.8?

Hi
Can you please add support for net4.8?

The previous version of Assimp 4.1.0 of Nicholas Woodfield works fine but it is old and can't read many new formats.

Native binaries are not being copied to the output

I'm developing a .NET 6.0 application for Windows 64-bit.

I have added the StirlingLabs.Assimp.Net Nuget package to the project, and StirlingLabs.assimp.native.xin-x64 is added automatically.

Unfortunately, no native libraries are being copied to the output folder, and calls to Assimp.Net cause "Error loading unmanaged library from path: Z:\MyProject\bin\Debug\runtimes\win-x64\native\assimp.dll"

After adding the native binaries manually to my project, everything works fine.

Error building solution

I get the following error when trying to build (I replace machine specific paths with ):
Project "
\Assimp.Net\StirlingLabs.Version\Version.proj" was not imported by "*\Assimp.Net\Version.proj" at (21,9), due to the file not existing.

Package as unity dependency

Can I add this package as a dependency in my unity project. If yes, can you please point me to the instructions or docs to do so?

MacOS Silicon M2 `Error loading unmanaged library from path: libassimp.dylib`

https://github.com/michaelsakharov/Prowl/tree/NewUI-PersistentLayout

using Prowl.Runtime;
using Prowl.Runtime.Utils;
using Debug = Prowl.Runtime.Debug;

namespace Prowl.Editor.Assets
{
    [FilePath("Library/LastWriteTimes.cache", FilePathAttribute.Location.Data)]
    public class LastWriteTimesCache : ScriptableSingleton<LastWriteTimesCache>
    {
        public readonly Dictionary<string, DateTime> fileLastWriteTimes = [];
    }

    public static partial class AssetDatabase
    {
        #region Properties
        public static Guid LastLoadedAssetID { get; private set; } = Guid.Empty;
        public static string TempAssetDirectory => Path.Combine(Project.ProjectDirectory, "Library/AssetDatabase");

        #endregion

        #region Events

        public static event Action<Guid, FileInfo>? AssetRemoved;
        public static event Action<FileInfo>? Pinged;

        #endregion

        #region Private Fields

        static readonly List<(DirectoryInfo, AssetDirectoryCache)> rootFolders = [];
        static double RefreshTimer = 0f;
        static bool lastFocused = false;
        static readonly Dictionary<string, MetaFile> assetPathToMeta = new(StringComparer.OrdinalIgnoreCase);
        static readonly Dictionary<Guid, MetaFile> assetGuidToMeta = [];
        static readonly Dictionary<Guid, SerializedAsset> guidToAssetData = [];

        #endregion


        #region Public Methods

        internal static void InternalUpdate()
        {
            if (Window.IsFocused)
            {
                RefreshTimer += Time.deltaTime;
                if (!lastFocused || RefreshTimer > 5f)
                    Update();
            }
            lastFocused = Window.IsFocused;
        }

        /// <summary>
        /// Gets the root folder cache at the specified index.
        /// </summary>
        public static AssetDirectoryCache GetRootFolderCache(int index)
        {
            if (index < 0 || index >= rootFolders.Count)
                throw new IndexOutOfRangeException("Index out of range");
            return rootFolders[index].Item2;
        }

        /// <summary>
        /// Gets the list of root folders in the AssetDatabase.
        /// </summary>
        /// <returns>List of root folders.</returns>
        public static List<DirectoryInfo> GetRootFolders() => rootFolders.Select(x => x.Item1).ToList();

        /// <summary>
        /// Adds a root folder to the AssetDatabase.
        /// </summary>
        /// <param name="rootFolder">The path to the root folder.</param>
        public static void AddRootFolder(string rootFolder)
        {
            ArgumentNullException.ThrowIfNullOrEmpty(rootFolder);

            var rootPath = Path.Combine(Project.ProjectDirectory, rootFolder);
            var info = new DirectoryInfo(rootPath);

            if (!info.Exists)
                info.Create();

            if (rootFolders.Any(x => x.Item1.FullName.Equals(info.FullName, StringComparison.OrdinalIgnoreCase)))
                throw new ArgumentException("Root Folder already exists in the Asset Database");

            rootFolders.Add((info, new AssetDirectoryCache(info)));
        }

        /// <summary>
        /// Checks for changes in the AssetDatabase.
        /// Call manually when you make changes to the asset files to ensure the changes are loaded
        /// </summary>
        public static void Update(bool doUnload = true, bool forceCacheUpdate = false)
        {
            if (!Project.HasProject) return;

            RefreshTimer = 0f;

            HashSet<string> currentFiles = [];
            List<string> toReimport = [];
            bool cacheModified = false;
            foreach (var root in rootFolders)
            {
                var files = Directory.GetFiles(root.Item1.FullName, "*", SearchOption.AllDirectories)
                    .Where(file => !file.EndsWith(".meta"));

                foreach (var file in files)
                {
                    // Only process files that are supported by an importer, the rest are ignored
                    if (ImporterAttribute.SupportsExtension(Path.GetExtension(file)))
                    {
                        currentFiles.Add(file);

                        if (!LastWriteTimesCache.Instance.fileLastWriteTimes.TryGetValue(file, out var lastWriteTime)
                            || !MetaFile.HasMeta(new FileInfo(file)))
                        {
                            // New file
                            Debug.Log("Asset Added: " + file);
                            lastWriteTime = File.GetLastWriteTime(file);
                            LastWriteTimesCache.Instance.fileLastWriteTimes[file] = lastWriteTime;
                            cacheModified = true;
                            if (ProcessFile(file, out _))
                                toReimport.Add(file);
                        }
                        else if (File.GetLastWriteTime(file) != lastWriteTime)
                        {
                            // File modified
                            Debug.Log("Asset Updated: " + file);
                            lastWriteTime = File.GetLastWriteTime(file);
                            LastWriteTimesCache.Instance.fileLastWriteTimes[file] = lastWriteTime;
                            cacheModified = true;
                            if (ProcessFile(file, out _))
                                toReimport.Add(file);
                        }
                        else if (!assetPathToMeta.TryGetValue(file, out var meta))
                        {
                            // File hasent changed but we dont have it in the cache, process it but dont reimport
                            Debug.Log("Asset Found: " + file);
                            ProcessFile(file, out var metaOutdated);
                            if (metaOutdated)
                                toReimport.Add(file);
                        }
                    }
                }
            }

            // Defer the Reimports untill after all Meta files are loaded/updated
            foreach (var file in toReimport)
            {
                Reimport(new(file));
                Debug.Log("Imported: " + $"{ToRelativePath(new(file))}!");
            }

            if (doUnload)
            {
                // Check for missing paths
                var missingPaths = LastWriteTimesCache.Instance.fileLastWriteTimes.Keys.Except(currentFiles).ToList();
                foreach (var file in missingPaths)
                {
                    LastWriteTimesCache.Instance.fileLastWriteTimes.Remove(file);
                    cacheModified = true;
                    bool hasMeta = assetPathToMeta.TryGetValue(file, out var meta);

                    if (hasMeta)
                    {
                        assetPathToMeta.Remove(file);

                        // The asset could have moved, in which case that's all we need todo
                        // But, if the guid leads to a meta file which has THIS asset path, then no new asset exists
                        // As it would have been updated from the code above and ProcessFile()
                        // Which means it didn't just move somewhere else, its gone
                        if (assetGuidToMeta.TryGetValue(meta.guid, out var existingMeta))
                        {
                            if (existingMeta.AssetPath.FullName.Equals(file, StringComparison.OrdinalIgnoreCase))
                            {
                                assetGuidToMeta.Remove(meta.guid);
                                DestroyStoredAsset(meta.guid);

                                Debug.Log("Asset Deleted: " + file);
                                AssetRemoved?.Invoke(meta.guid, new FileInfo(file));
                            }
                        }
                    }

                }
            }

            // If anything changed update DirectoryCaches for Editor UI
            if (forceCacheUpdate || cacheModified || toReimport.Count > 0)
                foreach (var root in rootFolders)
                    root.Item2.Refresh();

            if (cacheModified)
                LastWriteTimesCache.Instance.Save();

        }

        /// <summary>
        /// Process a File Change
        /// </summary>
        /// <param name="file"></param>
        /// <returns>True if a reimport is needed</returns>
        static bool ProcessFile(string file, out bool metaOutdated)
        {
            ArgumentNullException.ThrowIfNullOrEmpty(file);
            var fileInfo = new FileInfo(file);
            metaOutdated = false;

            var meta = MetaFile.Load(fileInfo);
            if (meta != null)
            {
                // Update the cache to record this new Meta file, Guid and Path
                bool hasMetaAlready = assetGuidToMeta.ContainsKey(meta.guid);
                assetGuidToMeta[meta.guid] = meta;
                assetPathToMeta[fileInfo.FullName] = meta;

                if (meta.version != MetaFile.MetaVersion)
                {
                    metaOutdated = true;
                    return true; // Meta version is outdated
                }

                if (hasMetaAlready)
                {
                    if (meta.lastModified != fileInfo.LastWriteTimeUtc)
                    {
                        // File modified, reimport
                        return true;
                    }
                }
                else
                {
                    // New file with meta, import
                    return false;
                }
            }
            else
            {
                // No meta file, create and import
                var newMeta = new MetaFile(fileInfo);
                if (newMeta.importer == null)
                {
                    Debug.LogError($"No importer found for file:\n{fileInfo.FullName}");
                    return false;
                }
                newMeta.Save();

                assetGuidToMeta[newMeta.guid] = newMeta;
                assetPathToMeta[fileInfo.FullName] = newMeta;
                return true;
            }
            return false; // No need to reimport, nothing changed
        }

        /// <summary>
        /// Tries to get the GUID of a file.
        /// </summary>
        /// <param name="file">The file to get the GUID for.</param>
        /// <param name="guid">The GUID of the file.</param>
        /// <returns>True if the GUID was found, false otherwise.</returns>
        public static bool TryGetGuid(FileInfo file, out Guid guid)
        {
            guid = Guid.Empty;
            ArgumentNullException.ThrowIfNull(file);
            if (!File.Exists(file.FullName)) return false;
            if (assetPathToMeta.TryGetValue(file.FullName, out var meta))
            {
                guid = meta.guid;
                return true;
            }
            return false;
        }

        /// <summary>
        /// Tries to get the file with the specified GUID.
        /// </summary>
        /// <param name="guid">The GUID of the file.</param>
        /// <param name="file">The file with the specified GUID.</param>
        /// <returns>True if the file was found, false otherwise.</returns>
        public static bool TryGetFile(Guid guid, out FileInfo? file)
        {
            file = null;
            if (guid == Guid.Empty) throw new ArgumentException("Asset Guid cannot be empty", nameof(guid));
            if (assetGuidToMeta.TryGetValue(guid, out var meta))
            {
                file = new FileInfo(meta.AssetPath.FullName);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Reimports all assets in the AssetDatabase.
        /// </summary>
        public static void ReimportAll()
        {
            foreach (var root in rootFolders)
                ReimportFolder(root.Item1);
        }

        /// <summary>
        /// Reimports all assets in the specified directory.
        /// </summary>
        /// <param name="directory">The directory to reimport assets from.</param>
        public static void ReimportFolder(DirectoryInfo directory)
        {
            ArgumentNullException.ThrowIfNull(directory);
            var files = directory.GetFiles("*", SearchOption.AllDirectories)
                .Where(file => !file.FullName.EndsWith(".meta"));
            foreach (var file in files)
                if (ImporterAttribute.SupportsExtension(file.Extension))
                    Reimport(file);
        }

        /// <summary>
        /// Reimports an asset from the specified file.
        /// </summary>
        /// <param name="assetFile">The asset file to reimport.</param>
        /// <param name="disposeExisting">Whether to dispose the existing asset in memory before reimporting.</param>
        /// <returns>True if the asset was reimported successfully, false otherwise.</returns>
        public static bool Reimport(FileInfo assetFile, bool disposeExisting = true)
        {
            Debug.Log($"Attempting to Import {Path.GetRelativePath(Project.ProjectDirectory, assetFile.FullName)}!");
            ArgumentNullException.ThrowIfNull(assetFile);

            // Dispose if we already have it
            if (disposeExisting)
                if (TryGetGuid(assetFile, out var assetGuid))
                    DestroyStoredAsset(assetGuid);

            // make sure path exists
            if (!File.Exists(assetFile.FullName))
            {
                Debug.LogError($"Failed to import {ToRelativePath(assetFile)}. Asset does not exist.");
                return false;
            }

            var meta = MetaFile.Load(assetFile);
            if (meta == null)
            {
                Debug.LogError($"No valid meta file found for asset: {ToRelativePath(assetFile)}");
                return false;
            }
            if (meta.importer == null)
            {
                Debug.LogError($"No valid importer found for asset: {ToRelativePath(assetFile)}");
                return false;
            }

            // Import the asset
            SerializedAsset ctx = new(meta.guid);
            try
            {
                meta.importer.Import(ctx, assetFile);
            }
            catch (Exception e)
            {
                Debug.LogError($"Failed to import {ToRelativePath(assetFile)}. Reason: {e.Message}");
                return false; // Import failed
            }

            if (!ctx.HasMain)
            {
                Debug.LogError($"Failed to import {ToRelativePath(assetFile)}. No main object found.");
                return false; // Import failed no Main Object
            }

            // Delete the old imported asset if it exists
            var serialized = GetSerializedFile(meta.guid);
            if (File.Exists(serialized.FullName))
                serialized.Delete();

            // Save the asset
            ctx.SaveToFile(serialized, out var dependencies);

            // Update the meta file (LastModified is set by MetaFile.Load)
            meta.assetTypes = new string[ctx.SubAssets.Count + 1];
            meta.assetTypes[0] = ctx.Main.GetType().FullName!;
            for (int i = 0; i < ctx.SubAssets.Count; i++)
                meta.assetTypes[i + 1] = ctx.SubAssets[i].GetType().FullName!;

            meta.assetNames = new string[ctx.SubAssets.Count + 1];
            meta.assetNames[0] = ctx.Main.Name;
            for (int i = 0; i < ctx.SubAssets.Count; i++)
                meta.assetNames[i + 1] = ctx.SubAssets[i].Name;

            meta.dependencies = dependencies.ToList();
            meta.Save();
            return true;
        }

        /// <summary>
        /// Loads an asset of the specified type from the specified file path and file ID.
        /// </summary>
        /// <typeparam name="T">The type of the asset to load.</typeparam>
        /// <param name="assetPath">The file path of the asset to load.</param>
        /// <param name="fileID">The file ID of the asset to load.</param>
        /// <returns>The loaded asset, or null if the asset could not be loaded.</returns>
        public static T? LoadAsset<T>(FileInfo assetPath, ushort fileID) where T : EngineObject
        {
            ArgumentNullException.ThrowIfNull(assetPath);
            if (TryGetGuid(assetPath, out var guid))
                return LoadAsset<T>(guid, fileID);
            return null;
        }

        /// <summary>
        /// Loads an asset of the specified type from the specified GUID and file ID.
        /// </summary>
        /// <typeparam name="T">The type of the asset to load.</typeparam>
        /// <param name="assetGuid">The GUID of the asset to load.</param>
        /// <param name="fileID">The file ID of the asset to load.</param>
        /// <returns>The loaded asset, or null if the asset could not be loaded.</returns>
        public static T? LoadAsset<T>(Guid assetGuid, ushort fileID) where T : EngineObject
        {
            if (assetGuid == Guid.Empty) throw new ArgumentException("Asset Guid cannot be empty", nameof(assetGuid));

            try
            {
                var serialized = LoadAsset(assetGuid);
                if (serialized == null) return null;
                T? asset = null;
                if (fileID == 0)
                {
                    // Main Asset
                    if (serialized.Main is not T) return null;
                    asset = (T)serialized.Main;
                }
                else
                {
                    // Sub Asset
                    if (serialized.SubAssets[fileID - 1] is not T) return null;
                    asset = (T)serialized.SubAssets[fileID - 1];
                }
                asset.AssetID = assetGuid;
                asset.FileID = (ushort)fileID;
                return asset;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                throw new InvalidCastException($"Something went wrong loading asset.");
            }
        }

        /// <summary>
        /// Loads a serialized asset from the specified file path.
        /// </summary>
        /// <param name="assetPath">The file path of the serialized asset to load.</param>
        /// <returns>The loaded serialized asset, or null if the asset could not be loaded.</returns>
        public static SerializedAsset? LoadAsset(FileInfo assetPath)
        {
            ArgumentNullException.ThrowIfNull(assetPath);
            if (TryGetGuid(assetPath, out var guid))
                return LoadAsset(guid);
            return null;
        }

        /// <summary>
        /// Loads a serialized asset from the specified GUID.
        /// </summary>
        /// <param name="assetGuid">The GUID of the serialized asset to load.</param>
        /// <returns>The loaded serialized asset, or null if the asset could not be loaded.</returns>
        public static SerializedAsset? LoadAsset(Guid assetGuid)
        {
            if (assetGuid == Guid.Empty) throw new ArgumentException("Asset Guid cannot be empty", nameof(assetGuid));

            if (guidToAssetData.TryGetValue(assetGuid, out SerializedAsset? value))
                return value;

            if (!TryGetFile(assetGuid, out var asset))
                return null;

            if (!File.Exists(asset!.FullName)) throw new FileNotFoundException("Asset file does not exist.", asset.FullName);

            FileInfo serializedAssetPath = GetSerializedFile(assetGuid);
            if (!File.Exists(serializedAssetPath.FullName))
                if (!Reimport(asset))
                {
                    Debug.LogError($"Failed to import {serializedAssetPath.FullName}!");
                    throw new Exception($"Failed to import {serializedAssetPath.FullName}");
                }
            try
            {
                var serializedAsset = SerializedAsset.FromSerializedAsset(serializedAssetPath.FullName);
                serializedAsset.Guid = assetGuid;
                serializedAsset.Main.AssetID = assetGuid;
                serializedAsset.Main.FileID = 0;
                for (int i = 0; i < serializedAsset.SubAssets.Count; i++)
                {
                    serializedAsset.SubAssets[i].AssetID = assetGuid;
                    serializedAsset.SubAssets[i].FileID = (ushort)(i + 1);
                }
                guidToAssetData[assetGuid] = serializedAsset;
                return serializedAsset;
            }
            catch
            {
                Debug.LogError($"Failed to load serialized asset {serializedAssetPath.FullName}!");
                return null; // Failed file might be in use?
            }
        }

        #endregion

        #region Private Methods

        private static void DestroyStoredAsset(Guid guid)
        {
            if (guidToAssetData.TryGetValue(guid, out SerializedAsset? value))
            {
                value.Destroy();
                guidToAssetData.Remove(guid);
            }
        }

        #endregion
    }
}

Screenshot 2024-06-20 at 9 58 54 PM

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.