Files
2025-11-30 08:35:03 +02:00

148 lines
4.0 KiB
C#

using System;
using System.IO;
using Needle.Engine.Core;
using Needle.Engine.Core.References.ReferenceResolvers;
using Needle.Engine.Projects;
using Needle.Engine.Utils;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Needle.Engine.Gltf
{
public static class Export
{
private static string GetTargetPath(string projectDirectory, Object obj, string extension)
{
if (NeedleProjectConfig.TryLoad(projectDirectory, out var config))
{
return projectDirectory + "/" + config.assetsDirectory + "/" + obj.name.ToFileName() + extension;
}
return projectDirectory + "/assets/" + obj.name.ToFileName() + extension;
}
public static bool AsGlb(Object obj, out string path, bool force, string projectDirectory = null)
{
if (projectDirectory != null)
{
if (!Directory.Exists(projectDirectory))
{
Debug.LogError($"Can not export to {projectDirectory} because it does not exist.");
path = null;
return false;
}
}
else
{
// If we are saving in a prefab we can try to get the path from the scene that might be still open
var info = ExportInfo.Get();
if (info)
projectDirectory = Path.GetFullPath(info.GetProjectDirectory());
}
if (string.IsNullOrWhiteSpace(projectDirectory) || !Directory.Exists(projectDirectory))
{
if (ProjectsData.TryGetBuilderProjectInfo(out var proj))
{
projectDirectory = proj.ProjectPath;
}
else if (ProcessUtils.TryFindCurrentProjectDirectory(out var dir))
{
Debug.Log($"Needle Project directory found from currently running process".LowContrast());
projectDirectory = dir;
}
}
if (!string.IsNullOrEmpty(projectDirectory) && Directory.Exists(projectDirectory))
{
using var @lock = new NeedleLock(projectDirectory);
var extension = ".glb";
var targetFilePath = GetTargetPath(projectDirectory, obj, extension);
var buildContext = BuildContext.LocalDevelopment;
var ctx = new ObjectExportContext(buildContext, obj, projectDirectory, targetFilePath, extension);
if (force || File.Exists(targetFilePath))
{
return AsGlb(ctx, obj, out path, null, force);
}
}
path = null;
return false;
}
public static bool AsGlb(IExportContext ctx, Object obj, out string path, object owner = null, bool force = false)
{
path = null;
Action afterExport = default;
try
{
if (ctx is ObjectExportContext objExport)
{
path = objExport.Path;
}
// TODO: move calculating the output path into this method
// if (ctx.TryGetAssetDependencyInfo(obj, out var dep))
// {
// if (dep.HasChanged == false)
// {
// // TODO: check if the file needs to be exported
// }
// }
var original = obj;
if (!SceneExportUtils.TryGetInstanceForExport(obj, out var instance, out afterExport))
return false;
// For example when exporting some part of the hierarchy via context click
var isRootExport = ctx.ParentContext == null;
if (isRootExport || !instance.transform.parent)
{
if (!instance.TryGetComponent(out IExportableObject exp))
{
exp = new ExportableObject(instance.transform);
}
if (GltfReferenceResolver.ExportReferencedObject(owner, original, instance, exp, ctx, ref path, force))
{
return true;
}
}
}
finally
{
afterExport?.Invoke();
}
return false;
}
/// <summary>
/// Used to export gltf from transforms without having to have a GltfObject component
/// </summary>
private class ExportableObject : IExportableObject
{
private readonly Transform root;
public string name { get; set; }
public ExportableObject(Transform root)
{
this.name = root.name;
this.root = root;
}
public bool Export(string path, bool force, IExportContext context)
{
var handler = GltfExportHandlerFactory.CreateHandler();
var task = handler.OnExport(root, path, context);
var res = AsyncHelper.RunSync(() => task);
return res;
}
}
}
}