diff --git a/package/Editor/Images/ImagesUI.cs b/package/Editor/Images/ImagesUI.cs index 28ca46d..97de71a 100644 --- a/package/Editor/Images/ImagesUI.cs +++ b/package/Editor/Images/ImagesUI.cs @@ -183,7 +183,7 @@ private void InitializeButtons() }, { "Upscale Image", () => { CommonUtils.FetchTextureFromURL(Images.GetImageDataById(selectedTextureId).Url, response => { - UpscaleEditor.ShowWindow(response, Images.GetImageDataById(selectedTextureId)); + UpscaleEditor.UpscaleEditor.ShowWindow(response, Images.GetImageDataById(selectedTextureId)); }); } }, diff --git a/package/Editor/UpscaleEditor/UpscaleEditor.cs b/package/Editor/UpscaleEditor/UpscaleEditor.cs index b5cc216..ce09b1a 100644 --- a/package/Editor/UpscaleEditor/UpscaleEditor.cs +++ b/package/Editor/UpscaleEditor/UpscaleEditor.cs @@ -1,18 +1,32 @@ +using Newtonsoft.Json; +using System; +using System.Collections; +using System.Collections.Generic; +using Unity.EditorCoroutines.Editor; using UnityEditor; using UnityEngine; -namespace Scenario.Editor +namespace Scenario.Editor.UpscaleEditor { public class UpscaleEditor : EditorWindow { - private static readonly float MinimumWidth = 1650f; + #region Public Fields + #endregion + + #region Private Fields + private static readonly UpscaleEditorUI UpscaleEditorUI = new(); + #endregion + + #region MonoBehaviourCallback + [MenuItem("Scenario/Editors/Upscale Editor", false, 5)] public static void ShowWindow() { var window = EditorWindow.GetWindow(typeof(UpscaleEditor), false, "Upscale Editor") as UpscaleEditor; - window.minSize = new Vector2(MinimumWidth, window.minSize.y); + window.autoRepaintOnSceneChange = true; + window.minSize = new Vector2(720, 540); } public static void ShowWindow(Texture2D selectedTexture, ImageDataStorage.ImageData imageData) @@ -25,11 +39,163 @@ public static void ShowWindow(Texture2D selectedTexture, ImageDataStorage.ImageD private void OnGUI() { UpscaleEditorUI.OnGUI(this.position); + UpscaleEditorUI.UpscaleEditor = this; } private void OnDestroy() { UpscaleEditorUI.currentImage = null; } + + #endregion + + #region Public Methods + + /// + /// Trigger the coroutine to get the upscale result. + /// + /// + /// + public void LaunchProgressUpscale(string _jobId, Action _answer) + { + if (!string.IsNullOrEmpty(_jobId)) + { + EditorCoroutineUtility.StartCoroutineOwnerless(GetProgressUpscale(_jobId, _answer)); + } + } + + #endregion + + #region Private Methods + + /// + /// Editor Coroutine to processing upscale. + /// Get the progress of the job id and wait the success status. + /// + /// JobId to listen + /// Return the result of the content at the end of the process + /// + IEnumerator GetProgressUpscale(string _jobId, Action _response) + { + bool inProgress = true; + + while (inProgress) + { + if (inProgress) + { + ApiClient.RestGet($"jobs/{_jobId}", response => + { + var progressResponse = JsonConvert.DeserializeObject(response.Content); + + if (progressResponse != null) + { + if (!string.IsNullOrEmpty(progressResponse.job.status)) + { + if (!progressResponse.job.status.Equals("success")) + { + switch (progressResponse.job.status) + { + case "warming-up": + Debug.Log("Upscale in preparation... wait..."); + break; + + case "queued": + Debug.Log("Upscale in queue... wait ..."); + break; + + case "in-progress": + Debug.Log("Upscale in progress... wait..."); + break; + + default: + Debug.Log("Upscale... wait..."); + break; + } + inProgress = true; + } + else + { + Debug.Log("Upscale progress done: " + response.Content); + inProgress = false; + _response?.Invoke(response.Content); + return; + } + } + } + }); + yield return new WaitForSecondsRealtime(4); + } + else + { + yield break; + } + } + + yield return null; + } + + #endregion + } + + #region API_DTO + + /// + /// Asset result object + /// + public class Asset + { + public string id { get; set; } + public string url { get; set; } + public string mimeType { get; set; } + public Metadata metadata { get; set; } + public string ownerId { get; set; } + public string authorId { get; set; } + public DateTime createdAt { get; set; } + public DateTime updatedAt { get; set; } + public string privacy { get; set; } + public List tags { get; set; } + public List collectionIds { get; set; } + } + + /// + /// Job result object + /// + public class Job + { + public string jobId { get; set; } + public string jobType { get; set; } + public string status { get; set; } + public float progress { get; set; } + public Metadata metadata { get; set; } + } + + /// + /// Metadata result object + /// + public class Metadata + { + public string type { get; set; } + public string preset { get; set; } + public string parentId { get; set; } + public string rootParentId { get; set; } + public string kind { get; set; } + public string[] assetIds { get; set; } + public int scalingFactor { get; set; } + public bool magic { get; set; } + public bool forceFaceRestoration { get; set; } + public bool photorealist { get; set; } + } + + /// + /// Root object to be deserialized from json. + /// + public class Root + { + public Asset asset { get; set; } + public Job job { get; set; } + public string image { get; set; } + } + + #endregion } \ No newline at end of file diff --git a/package/Editor/UpscaleEditor/UpscaleEditorUI.cs b/package/Editor/UpscaleEditor/UpscaleEditorUI.cs index 3345fae..b5aa1fe 100644 --- a/package/Editor/UpscaleEditor/UpscaleEditorUI.cs +++ b/package/Editor/UpscaleEditor/UpscaleEditorUI.cs @@ -1,36 +1,87 @@ +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; -using Newtonsoft.Json; using UnityEditor; using UnityEngine; -namespace Scenario.Editor +namespace Scenario.Editor.UpscaleEditor { public class UpscaleEditorUI { + #region Public Fields + public static Texture2D currentImage = null; + public static ImageDataStorage.ImageData imageData = null; - + + public UpscaleEditor UpscaleEditor { get { return upscaleEditor; } set { upscaleEditor = value; } } + + #endregion + + #region Private Fields + private static List imageDataList = new(); + /// + /// Reference object to the upscale editor parent class. + /// + private UpscaleEditor upscaleEditor = null; + private List upscaledImages = new(); + private Texture2D selectedTexture = null; + private Vector2 scrollPosition = Vector2.zero; private string imageDataUrl = ""; - private string assetId = ""; + + private string assetId = string.Empty; private bool returnImage = true; - private bool forceFaceRestoration = false; - private bool usePhotorealisticModel = false; - + + /// + /// Default scaling factor + /// private int scalingFactor = 2; + + /// + /// Style selected on the upscale + /// + private string styleSelected = "Standard"; + + /// + /// Preset selected on the upscale + /// + private string presetSelected = "Balanced"; + + /// + /// All style available in upscale + /// + private string[] styleChoices = new string[] + { + "Standard", + "Cartoon", + "Anime", + "Comic", + "Minimalist", + "Photorealistic", + "3D Rendered" + }; + + /// + /// Flag of the style selected + /// + private int styleFlag = 0; + private int itemsPerRow = 1; private readonly float padding = 10f; + private readonly float leftSectionWidth = 150; + #endregion + public void OnGUI(Rect position) { DrawBackground(position); @@ -65,35 +116,76 @@ private void DrawRightSection(Rect position) Rect rect = GUILayoutUtility.GetRect(leftSectionWidth, leftSectionWidth, GUILayout.Width(300), GUILayout.Height(300)); GUI.DrawTexture(rect, currentImage, ScaleMode.ScaleToFit); - EditorStyle.Button("Clear Image", ()=>currentImage = null); + EditorStyle.Button("Clear Image", ()=> + { + currentImage = null; + assetId = string.Empty; + }); } EditorStyle.Label("Upscale Image Options", bold: true); + styleFlag = EditorGUILayout.Popup("Style: ", styleFlag, styleChoices); + styleSelected = styleChoices[styleFlag]; + + EditorStyle.Label("Scaling Factor:"); GUILayout.BeginHorizontal(); { - EditorStyle.Label("Scaling Factor:"); - if (GUILayout.Toggle(scalingFactor == 2, "2", EditorStyles.miniButtonLeft)) + if (GUILayout.Toggle(scalingFactor == 2, "2x", EditorStyles.miniButtonLeft)) { scalingFactor = 2; } - if (GUILayout.Toggle(scalingFactor == 4, "4", EditorStyles.miniButtonRight)) + if (GUILayout.Toggle(scalingFactor == 4, "4x", EditorStyles.miniButtonRight)) { scalingFactor = 4; } + + if (GUILayout.Toggle(scalingFactor == 8, "8x", EditorStyles.miniButtonRight)) + { + scalingFactor = 8; + } + + if (GUILayout.Toggle(scalingFactor == 16, "16x", EditorStyles.miniButtonRight)) + { + scalingFactor = 16; + } } GUILayout.EndHorizontal(); - forceFaceRestoration = EditorGUILayout.Toggle("Force Face Restoration", forceFaceRestoration); - usePhotorealisticModel = EditorGUILayout.Toggle("Use Photorealistic Model", usePhotorealisticModel); + CustomStyle.Space(25); + + EditorStyle.Label("Preset:"); + GUILayout.BeginHorizontal(); + { + + if (GUILayout.Toggle(presetSelected.Equals("Precise"), "Precise", EditorStyles.miniButtonLeft)) + { + presetSelected = "Precise"; + } + + if (GUILayout.Toggle(presetSelected.Equals("Balanced"), "Balanced", EditorStyles.miniButtonRight)) + { + presetSelected = "Balanced"; + } + + if (GUILayout.Toggle(presetSelected.Equals("Creative"), "Creative", EditorStyles.miniButtonRight)) + { + presetSelected = "Creative"; + } + } + GUILayout.EndHorizontal(); EditorStyle.Button("Upscale Image", () => { if (currentImage == null) return; + upscaledImages.Add(null); imageDataUrl = CommonUtils.Texture2DToDataURL(currentImage); - assetId = imageData.Id; + if (imageData != null) + { + assetId = imageData.Id; + } FetchUpscaledImage(imageDataUrl); }); @@ -195,50 +287,140 @@ private void DrawTextureButton(int i) } } + /// + /// Try to get asset of reference to upscale. + /// Then launch the upscale into a job. + /// Get back the result to an asset and download the image resulting of the process. + /// + /// private void FetchUpscaledImage(string imgUrl) { string json = GetJsonPayload(imgUrl); - Debug.Log(json); - - ApiClient.RestPut("images/upscale",json, response => + + if (string.IsNullOrEmpty(assetId)) { - var pixelatedResponse = JsonConvert.DeserializeObject(response.Content); - Texture2D texture = CommonUtils.DataURLToTexture2D(pixelatedResponse.image); - ImageDataStorage.ImageData newImageData = new ImageDataStorage.ImageData + ApiClient.RestPost("assets", json, response => { - Id = pixelatedResponse.asset.id, - Url = pixelatedResponse.image, - InferenceId = pixelatedResponse.asset.ownerId, - }; - upscaledImages.Insert(0, texture); - imageDataList.Insert(0, newImageData); - }); + var jsonResponse = JsonConvert.DeserializeObject(response.Content); + assetId = jsonResponse.asset.id; + + json = GetJsonPayload(imgUrl); + + ApiClient.RestPost("generate/upscale", json, response => + { + var upscaleResponse = JsonConvert.DeserializeObject(response.Content); + + var jobId = upscaleResponse.job.jobId; + + upscaleEditor.LaunchProgressUpscale(jobId, _answer => { + var assetAnswer = JsonConvert.DeserializeObject(_answer); + ApiClient.RestGet($"assets/{assetAnswer.job.metadata.assetIds[0]}", response => + { + var asset = JsonConvert.DeserializeObject(response.Content); + Texture2D texture = new Texture2D(2, 2); + CommonUtils.FetchTextureFromURL(asset.asset.url, response => { + texture = response; + ImageDataStorage.ImageData newImageData = new ImageDataStorage.ImageData + { + Id = asset.asset.id, + Url = asset.asset.url, + }; + if (upscaledImages[0] == null) + { + upscaledImages[0] = texture; + } + else + { + upscaledImages.Insert(0, texture); + } + imageDataList.Insert(0, newImageData); + }); + }); + }); + }); + }, errorAction => { + upscaledImages.RemoveAt(0); + }); + } + else + { + ApiClient.RestPost("generate/upscale", json, response => + { + var upscaleResponse = JsonConvert.DeserializeObject(response.Content); + + var jobId = upscaleResponse.job.jobId; + + upscaleEditor.LaunchProgressUpscale(jobId, _answer => { + var assetAnswer = JsonConvert.DeserializeObject(_answer); + ApiClient.RestGet($"assets/{assetAnswer.job.metadata.assetIds[0]}", response => + { + var asset = JsonConvert.DeserializeObject(response.Content); + Texture2D texture = new Texture2D(2, 2); + CommonUtils.FetchTextureFromURL(asset.asset.url, response => { + texture = response; + ImageDataStorage.ImageData newImageData = new ImageDataStorage.ImageData + { + Id = asset.asset.id, + Url = asset.asset.url, + }; + if (upscaledImages[0] == null) + { + upscaledImages[0] = texture; + } + else + { + upscaledImages.Insert(0, texture); + } + imageDataList.Insert(0, newImageData); + }); + }); + }); + }); + } } + /// + /// Prepare the json payload to the upscale. + /// + /// + /// private string GetJsonPayload(string imgUrl) { string json; - if (assetId == "") + + switch (styleSelected) + { + case "3D Rendered": + styleSelected = "3d-rendered"; + break; + + case "Photorealistic": + styleSelected = "photography"; + break; + } + + if (string.IsNullOrEmpty(assetId)) { var payload = new { image = imgUrl, - forceFaceRestoration = forceFaceRestoration, - photorealist = usePhotorealisticModel, + preset = presetSelected.ToLower(), + style = styleSelected.ToLower(), scalingFactor = scalingFactor, returnImage = returnImage, name = "" }; + json = JsonConvert.SerializeObject(payload); } else { var payload = new { - image = imgUrl, + image = assetId, assetId = assetId, - forceFaceRestoration = forceFaceRestoration, - photorealist = usePhotorealisticModel, + preset = presetSelected.ToLower(), + style = styleSelected.ToLower(), scalingFactor = scalingFactor, returnImage = returnImage, name = CommonUtils.GetRandomImageFileName() @@ -248,42 +430,6 @@ private string GetJsonPayload(string imgUrl) return json; } - - #region API_DTO - - public class Asset - { - public string id { get; set; } - public string url { get; set; } - public string mimeType { get; set; } - public Metadata metadata { get; set; } - public string ownerId { get; set; } - public string authorId { get; set; } - public DateTime createdAt { get; set; } - public DateTime updatedAt { get; set; } - public string privacy { get; set; } - public List tags { get; set; } - public List collectionIds { get; set; } - } - - public class Metadata - { - public string type { get; set; } - public string parentId { get; set; } - public string rootParentId { get; set; } - public string kind { get; set; } - public bool magic { get; set; } - public bool forceFaceRestoration { get; set; } - public bool photorealist { get; set; } - } - - public class Root - { - public Asset asset { get; set; } - public string image { get; set; } - } - - #endregion } }