Esempio n. 1
0
 /// <summary>
 /// Checks if the asset has the contents of the format to import, fetching them if need be; then imports
 /// the asset.
 /// </summary>
 /// <param name="asset">The asset who's format is being imported.</param>
 /// <param name="format">The format to import.</param>
 /// <param name="options">The import options for this asset.</param>
 /// <param name="callback">The callback to call when this is finished.</param>
 private void FetchAndImportFormat(PolyAsset asset, PolyFormat format, PolyImportOptions options,
                                   PolyApi.ImportCallback callback = null)
 {
     if (format.root.contents != null)
     {
         // If asset already has the gltf package, proceed directly to importing it.
         ImportFormat(asset, format, options, callback);
     }
     else
     {
         // Otherwise, first fetch the package and then import the model.
         FetchFormatFiles(asset, format.formatType, (PolyAsset resultAsset, PolyStatus status) => {
             PolyFormat fetchedFormat = resultAsset.GetFormatIfExists(format.formatType);
             if (fetchedFormat != null)
             {
                 ImportFormat(asset, fetchedFormat, options, callback);
             }
             else
             {
                 if (callback != null)
                 {
                     callback(asset, new PolyStatusOr <PolyImportResult>(
                                  PolyStatus.Error("Could not fetch format files for asset")));
                 }
             }
         });
     }
 }
Esempio n. 2
0
        private void UnpackPackageToFolder(PolyFormat package, string destFolder, string mainFileName)
        {
            // First write the resources, then the main file, so that when the main file is imported
            // all the necessary resources are already in place.

            // Maintain a mapping of original file names to their corresponding hash.
            StringBuilder fileMapSb = new StringBuilder();

            foreach (PolyFile file in package.resources)
            {
                // In order to avoid having to replicate the original directory structure of the
                // asset (which might be incompatible with our file system, or even maliciously constructed),
                // we replace the original path of each resource file with the MD5 hash of the path.
                // That maintains uniqueness of paths and flattens the structure so that every resource
                // can live in the same directory.
                string path = Path.Combine(destFolder, PolyInternalUtils.ConvertFilePathToHash(file.relativePath));
                if (file.contents != null)
                {
                    File.WriteAllBytes(path, file.contents);
                    fileMapSb.AppendFormat("{0} -> {1}\n", file.relativePath,
                                           PolyInternalUtils.ConvertFilePathToHash(file.relativePath));
                }
            }
            // Lastly, write the main file.
            File.WriteAllBytes(Path.Combine(destFolder, mainFileName), package.root.contents);
            // Write the file mapping.
            File.WriteAllText(Path.Combine(destFolder, "FileNameMapping.txt"), fileMapSb.ToString());
        }
Esempio n. 3
0
        /// <summary>
        /// Processes the result of fetching an individual file.
        /// </summary>
        /// <param name="state">Indicates the state of the ongoing fetch operation (as set up in FetchObj).</param>
        /// <param name="index">If ROOT_FILE_INDEX, then this is a result for the main file; else this is a result for
        /// the resource file with that index.</param>
        /// <param name="status">The status indicating if the download succeed</param>
        /// <param name="data">The data that was downloaded.</param>
        private void ProcessFileFetchResult(FetchOperationState state, int index, PolyStatus status, byte[] data)
        {
            if (state.pendingFiles == 0)
            {
                // Another request for this format failed, so we ignore any further responses.
                return;
            }

            if (!status.ok)
            {
                // This request failed, so we set pendingFiles to 0 so we ignore any further responses, and callback with
                // an error message.
                state.pendingFiles = 0;
                state.completionCallback(state.asset, PolyStatus.Error(status, "Failed to fetch file #{0}", index));
                return;
            }

            PolyFormat package = state.packageBeingFetched;
            PolyFile   file    = index == ROOT_FILE_INDEX ? package.root : package.resources[index];

            file.contents = data;

            --state.pendingFiles;
            if (state.progressCallback != null)
            {
                state.progressCallback(state.asset, 1.0f - ((float)state.pendingFiles / state.totalFiles));
            }
            if (state.pendingFiles <= 0)
            {
                // All files done, call callback indicating success.
                state.completionCallback(state.asset, PolyStatus.Success());
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Imports the given format of the given asset, asynchronously in a background thread.
        /// Calls the supplied callback when done.
        /// </summary>
        public void ImportAsync(PolyAsset asset, PolyFormat format, PolyImportOptions options,
                                AsyncImportCallback callback = null)
        {
            ImportOperation operation = new ImportOperation();

            operation.instance = this;
            operation.asset    = asset;
            operation.format   = format;
            operation.options  = options;
            operation.callback = callback;
            operation.status   = PolyStatus.Success();
            operation.loader   = new FormatLoader(format);
            if (Application.isPlaying)
            {
                Task.Run(() => BackgroundThreadProc(operation));
                //ThreadPool.QueueUserWorkItem(new WaitCallback(BackgroundThreadProc), operation);
            }
            else
            {
                // If we are in the editor, don't do this in a background thread. Do it directly
                // here on the main thread.
                BackgroundThreadProc(operation);
                Update();
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Parses a single asset.
        /// </summary>
        public static PolyStatus ParseAsset(JObject asset, out PolyAsset polyAsset)
        {
            polyAsset = new PolyAsset();

            if (asset["visibility"] == null)
            {
                return(PolyStatus.Error("Asset has no visibility set."));
            }

            polyAsset.name       = asset["name"].ToString();
            polyAsset.authorName = asset["authorName"].ToString();
            if (asset["thumbnail"] != null)
            {
                var thumbnailElements = asset["thumbnail"].ToObject <JObject>();
                //IJEnumerable<JToken> thumbnailElements = asset["thumbnail"].AsJEnumerable();
                polyAsset.thumbnail = new PolyFile(thumbnailElements["relativePath"].ToString(),
                                                   thumbnailElements["url"].ToString(), thumbnailElements["contentType"].ToString());
            }

            if (asset["formats"] == null)
            {
                Debug.LogError("No formats found");
            }
            else
            {
                foreach (var format in asset["formats"].ToObject <List <JObject> >())
                //foreach (JToken format in asset["formats"])
                {
                    PolyFormat newFormat = ParseAssetsPackage(format);
                    newFormat.formatType = ParsePolyFormatType(format["formatType"]);
                    if (newFormat.formatType == PolyFormatType.UNKNOWN)
                    {
                        PtDebug.Log("Did not recognize format type: " + format["formatType"].ToString());
                    }
                    polyAsset.formats.Add(newFormat);
                }
            }
            polyAsset.displayName = asset["displayName"].ToString();
            polyAsset.createTime  = DateTime.Parse(asset["createTime"].ToString());
            polyAsset.updateTime  = DateTime.Parse(asset["updateTime"].ToString());
            polyAsset.visibility  = ParsePolyVisibility(asset["visibility"]);
            polyAsset.license     = ParsePolyAssetLicense(asset["license"]);
            if (asset["isCurated"] != null)
            {
                polyAsset.isCurated = bool.Parse(asset["isCurated"].ToString());
            }
            return(PolyStatus.Success());
        }
Esempio n. 6
0
 /// <summary>
 /// Imports the relevant format and corrects that the designated glTF format if need be.
 /// </summary>
 private void ImportFormat(PolyAsset asset, PolyFormat format, PolyImportOptions options,
                           PolyApi.ImportCallback callback)
 {
     asyncImporter.ImportAsync(asset, format, options,
                               (PolyStatus status, GameObject root, IEnumerable meshCreator) => {
         if (!status.ok)
         {
             // Failed.
             callback(asset, new PolyStatusOr <PolyImportResult>(status));
             return;
         }
         PolyImportResult result    = new PolyImportResult(root);
         result.mainThreadThrottler = meshCreator;
         callback(asset, new PolyStatusOr <PolyImportResult>(result));
     });
 }
Esempio n. 7
0
        public void FetchFormatFiles(PolyAsset asset, PolyFormatType formatType,
                                     PolyApi.FetchFormatFilesCallback completionCallback, FetchProgressCallback progressCallback = null)
        {
            PolyUtils.AssertNotNull(asset, "Asset can't be null.");
            PolyUtils.AssertNotNull(formatType, "formatType can't be null.");
            PolyFormat packageToFetch = asset.GetFormatIfExists(formatType);

            if (packageToFetch == null)
            {
                if (completionCallback != null)
                {
                    completionCallback(asset, PolyStatus.Error("Format type not present in asset"));
                }
                return;
            }

            PolyUtils.AssertNotNull(packageToFetch.root, "packageToFetch.root can't be null.");
            PolyUtils.AssertNotNull(packageToFetch.root.url, "packageToFetch.root.url can't be null.");
            PolyUtils.AssertNotNull(packageToFetch.resources, "packageToFetch.resources can't be null.");

            string accessToken = GetAccessToken();

            FetchOperationState state = new FetchOperationState();

            state.asset = asset;
            state.completionCallback  = completionCallback;
            state.progressCallback    = progressCallback;
            state.packageBeingFetched = packageToFetch;

            // Indicates how many files are pending download (1 for main file + 1 for each resource).
            state.totalFiles = state.pendingFiles = 1 + packageToFetch.resources.Count;

            // Note that the callbacks are asynchronous so they may complete in any order.  What we do know is that they
            // will all be called on the main thread, so they won't be called concurrently.

            long maxCacheAge = asset.IsMutable ? MUTABLE_ASSET_MAX_CACHE_AGE : IMMUTABLE_ASSET_MAX_CACHE_AGE;

            PolyClientUtils.GetRawFileBytes(packageToFetch.root.url, accessToken, maxCacheAge,
                                            (PolyStatus status, byte[] data) => { ProcessFileFetchResult(state, ROOT_FILE_INDEX, status, data); });

            for (int i = 0; i < packageToFetch.resources.Count; i++)
            {
                int thisIndex = i; // copy of variable, for closure below.
                PolyClientUtils.GetRawFileBytes(packageToFetch.resources[i].url, accessToken, maxCacheAge,
                                                (status, data) => { ProcessFileFetchResult(state, thisIndex, status, data); });
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Starts downloading and importing the given asset (in the background). When done, the asset will
        /// be saved to the user's Assets folder.
        /// </summary>
        /// <param name="asset">The asset to download and import.</param>
        /// <param name="ptAssetLocalPath">Path to the PtAsset that should be created (or replaced).</param>
        /// <param name="options">Import options.</param>
        public void StartDownloadAndImport(PolyAsset asset, string ptAssetLocalPath, EditTimeImportOptions options)
        {
            if (!assetsBeingDownloaded.Add(asset))
            {
                return;
            }
            PtDebug.LogFormat("ABM: starting to fetch asset {0} ({1}) -> {2}", asset.name, asset.displayName,
                              ptAssetLocalPath);

            // Prefer glTF1 to glTF2.
            // It used to be that no Poly assets had both formats, so the ordering did not matter.
            // Blocks assets now have both glTF1 and glTF2. PT does not understand the glTF2 version,
            // so the ordering matters a great deal.
            PolyFormat glTF2format = asset.GetFormatIfExists(PolyFormatType.GLTF_2);
            PolyFormat glTFformat  = asset.GetFormatIfExists(PolyFormatType.GLTF);

            PolyMainInternal.FetchProgressCallback progressCallback = (PolyAsset assetBeingFetched, float progress) => {
                EditorUtility.DisplayProgressBar(DOWNLOAD_PROGRESS_TITLE, DOWNLOAD_PROGRESS_TEXT, progress);
            };

            if (glTFformat != null)
            {
                EditorUtility.DisplayProgressBar(DOWNLOAD_PROGRESS_TITLE, DOWNLOAD_PROGRESS_TEXT, 0.0f);
                PolyMainInternal.Instance.FetchFormatFiles(asset, PolyFormatType.GLTF,
                                                           (PolyAsset resultAsset, PolyStatus status) => {
                    EditorUtility.ClearProgressBar();
                    OnFetchFinished(status, resultAsset, /*isGltf2*/ false, ptAssetLocalPath, options);
                }, progressCallback);
            }
            else if (glTF2format != null)
            {
                EditorUtility.DisplayProgressBar(DOWNLOAD_PROGRESS_TITLE, DOWNLOAD_PROGRESS_TEXT, 0.0f);
                PolyMainInternal.Instance.FetchFormatFiles(asset, PolyFormatType.GLTF_2,
                                                           (PolyAsset resultAsset, PolyStatus status) => {
                    EditorUtility.ClearProgressBar();
                    OnFetchFinished(status, resultAsset, /*isGltf2*/ true, ptAssetLocalPath, options);
                }, progressCallback);
            }
            else
            {
                Debug.LogError("Asset not in GLTF_2 or GLTF format. Can't import.");
                PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_FAILED, "Unsupported format");
            }
        }
Esempio n. 9
0
        public void Import(PolyAsset asset, PolyImportOptions options, PolyApi.ImportCallback callback = null)
        {
            PolyFormat gltfFormat  = asset.GetFormatIfExists(PolyFormatType.GLTF);
            PolyFormat gltf2Format = asset.GetFormatIfExists(PolyFormatType.GLTF_2);

            if (gltf2Format != null && gltfFormat == null)
            {
                FetchAndImportFormat(asset, gltf2Format, options, callback);
            }
            else if (gltfFormat != null)
            {
                FetchAndImportFormat(asset, gltfFormat, options, callback);
            }
            else
            {
                callback(asset, new PolyStatusOr <PolyImportResult>(
                             PolyStatus.Error("Neither glTF or glTF_2 format was present in asset")));
            }
        }
Esempio n. 10
0
        private static PolyFormat ParseAssetsPackage(JToken token)
        {
            PolyFormat package = new PolyFormat();

            package.root = new PolyFile(token["root"]["relativePath"].ToString(),
                                        token["root"]["url"].ToString(), token["root"]["contentType"].ToString());
            // Get the supporting files (resources).
            // Supporting files (including MTL files) are listed under /resource:
            package.resources = new List <PolyFile>();
            if (token["resources"] != null)
            {
                var resourceTags = token["resources"].ToObject <List <JObject> >();
                //IJEnumerable<JToken> resourceTags = token["resources"].AsJEnumerable();
                if (resourceTags != null)
                {
                    foreach (var resourceTag in resourceTags)
                    {
                        if (resourceTag["url"] != null)
                        {
                            package.resources.Add(new PolyFile(
                                                      resourceTag["relativePath"].ToString(),
                                                      resourceTag["url"].ToString(),
                                                      resourceTag["contentType"].ToString()));
                        }
                    }
                }
            }
            // Get the format complexity
            if (token["formatComplexity"] != null)
            {
                package.formatComplexity = new PolyFormatComplexity();
                if (token["formatComplexity"]["triangleCount"] != null)
                {
                    package.formatComplexity.triangleCount = int.Parse(token["formatComplexity"]["triangleCount"].ToString());
                }
                if (token["formatComplexity"]["lodHint"] != null)
                {
                    package.formatComplexity.lodHint = int.Parse(token["formatComplexity"]["lodHint"].ToString());
                }
            }
            return(package);
        }
Esempio n. 11
0
 public FormatLoader(PolyFormat format)
 {
     this.format = format;
 }
Esempio n. 12
0
 public abstract void Dereference(IUriLoader uriLoader = null, PolyFormat gltfFormat = null);
 /// Map glTFid values (ie, string names) names to the objects they refer to
 public override void Dereference(IUriLoader uriLoader = null, PolyFormat gltfFormat = null)
 {
     // "dereference" all the names
     scenePtr = scenes[scene];
     foreach (var pair in buffers)
     {
         pair.Value.gltfId = pair.Key;
         Gltf1Buffer buffer = pair.Value;
         if (uriLoader != null)
         {
             Debug.Assert(buffer.type == "arraybuffer");
             buffer.data = uriLoader.Load(buffer.uri);
         }
         else if (gltfFormat != null)
         {
             // Runtime import case; the uris refer to resource files in the PolyFormat.
             Debug.Assert(buffer.type == "arraybuffer");
             foreach (PolyFile resource in gltfFormat.resources)
             {
                 if (resource.relativePath == buffer.uri)
                 {
                     buffer.data = new Reader(resource.contents);
                     break;
                 }
             }
         }
     }
     foreach (var pair in accessors)
     {
         pair.Value.gltfId        = pair.Key;
         pair.Value.bufferViewPtr = bufferViews[pair.Value.bufferView];
     }
     foreach (var pair in bufferViews)
     {
         pair.Value.gltfId    = pair.Key;
         pair.Value.bufferPtr = buffers[pair.Value.buffer];
     }
     foreach (var pair in meshes)
     {
         pair.Value.gltfId = pair.Key;
         foreach (var prim in pair.Value.primitives)
         {
             prim.attributePtrs = prim.attributes.ToDictionary(
                 elt => elt.Key,
                 elt => accessors[elt.Value]);
             prim.indicesPtr  = accessors[prim.indices];
             prim.materialPtr = materials[prim.material];
         }
     }
     if (shaders != null)
     {
         foreach (var pair in shaders)
         {
             pair.Value.gltfId = pair.Key;
         }
     }
     if (programs != null)
     {
         foreach (var pair in programs)
         {
             pair.Value.gltfId = pair.Key;
             var program = pair.Value;
             if (program.vertexShader != null)
             {
                 program.vertexShaderPtr = shaders[program.vertexShader];
             }
             if (program.fragmentShader != null)
             {
                 program.fragmentShaderPtr = shaders[program.fragmentShader];
             }
         }
     }
     if (techniques != null)
     {
         foreach (var pair in techniques)
         {
             pair.Value.gltfId = pair.Key;
             var technique = pair.Value;
             if (technique.program != null)
             {
                 technique.programPtr = programs[technique.program];
             }
         }
     }
     if (images != null)
     {
         foreach (var pair in images)
         {
             pair.Value.gltfId = pair.Key;
         }
         foreach (var pair in textures)
         {
             pair.Value.gltfId = pair.Key;
             var texture = pair.Value;
             if (texture.source != null)
             {
                 texture.sourcePtr = images[texture.source];
             }
         }
     }
     if (materials != null)
     {
         foreach (var pair in materials)
         {
             pair.Value.gltfId = pair.Key;
             var material = pair.Value;
             if (material.technique != null)
             {
                 material.techniquePtr = techniques[material.technique];
             }
             if (material.values != null)
             {
                 if (material.values.BaseColorTex != null)
                 {
                     material.values.BaseColorTexPtr = textures[material.values.BaseColorTex];
                 }
             }
         }
     }
     foreach (var pair in nodes)
     {
         pair.Value.gltfId = pair.Key;
         var node = pair.Value;
         if (node.meshes != null)
         {
             node.meshPtrs = node.meshes.Select(id => meshes[id]).ToList();
         }
         if (node.children != null)
         {
             node.childPtrs = node.children.Select(id => nodes[id]).ToList();
         }
     }
     foreach (var pair in scenes)
     {
         pair.Value.gltfId = pair.Key;
         var scene2 = pair.Value;
         if (scene2.nodes != null)
         {
             scene2.nodePtrs = scene2.nodes.Select(name => nodes[name]).ToList();
         }
     }
 }
 /// Map gltfIndex values (ie, int indices) names to the objects they refer to
 public override void Dereference(IUriLoader uriLoader = null, PolyFormat gltfFormat = null)
 {
     // "dereference" all the indices
     scenePtr = scenes[scene];
     for (int i = 0; i < buffers.Count; i++)
     {
         Gltf2Buffer buffer = buffers[i];
         buffer.gltfIndex = i;
         if (uriLoader != null)
         {
             buffer.data = uriLoader.Load(buffer.uri);
         }
         else if (gltfFormat != null)
         {
             // Runtime import case; the uris refer to resource files in the PolyFormat.
             foreach (PolyFile resource in gltfFormat.resources)
             {
                 if (resource.relativePath == buffer.uri)
                 {
                     buffer.data = new Reader(resource.contents);
                     break;
                 }
             }
         }
     }
     for (int i = 0; i < accessors.Count; i++)
     {
         accessors[i].gltfIndex     = i;
         accessors[i].bufferViewPtr = bufferViews[accessors[i].bufferView];
     }
     for (int i = 0; i < bufferViews.Count; i++)
     {
         bufferViews[i].gltfIndex = i;
         bufferViews[i].bufferPtr = buffers[bufferViews[i].buffer];
     }
     for (int i = 0; i < meshes.Count; i++)
     {
         meshes[i].gltfIndex = i;
         foreach (var prim in meshes[i].primitives)
         {
             prim.attributePtrs = prim.attributes.ToDictionary(
                 elt => elt.Key,
                 elt => accessors[elt.Value]);
             prim.indicesPtr  = accessors[prim.indices];
             prim.materialPtr = materials[prim.material];
         }
     }
     if (images != null)
     {
         for (int i = 0; i < images.Count; i++)
         {
             images[i].gltfIndex = i;
         }
     }
     if (textures != null)
     {
         for (int i = 0; i < textures.Count; i++)
         {
             textures[i].gltfIndex = i;
             textures[i].sourcePtr = images[textures[i].source];
         }
     }
     for (int i = 0; i < materials.Count; i++)
     {
         Gltf2Material mat = materials[i];
         mat.gltfIndex = i;
         DereferenceTextureInfo(mat.emissiveTexture);
         DereferenceTextureInfo(mat.normalTexture);
         if (mat.pbrMetallicRoughness != null)
         {
             DereferenceTextureInfo(mat.pbrMetallicRoughness.baseColorTexture);
             DereferenceTextureInfo(mat.pbrMetallicRoughness.metallicRoughnessTexture);
         }
     }
     for (int i = 0; i < nodes.Count; i++)
     {
         nodes[i].gltfIndex = i;
         Gltf2Node node = nodes[i];
         if (node.mesh >= 0)
         {
             node.meshPtr = meshes[node.mesh];
         }
         if (node.children != null)
         {
             node.childPtrs = node.children.Select(id => nodes[id]).ToList();
         }
     }
     for (int i = 0; i < scenes.Count; i++)
     {
         scenes[i].gltfIndex = i;
         var thisScene = scenes[i];
         if (thisScene.nodes != null)
         {
             thisScene.nodePtrs = thisScene.nodes.Select(index => nodes[index]).ToList();
         }
     }
 }