From 05600f7bc1bae3687f0e5102249f51f266a514b0 Mon Sep 17 00:00:00 2001 From: Chromium <62724067+Chromum@users.noreply.github.com> Date: Tue, 29 Apr 2025 06:53:17 +0100 Subject: [PATCH] Implimented RGBA buttons --- .../Image/Utilities/ViewNode/ViewImageNode.cs | 115 ++++++++++++++++-- .../Utilities/ViewNode/ViewImageNodeEditor.cs | 69 ++++++----- 2 files changed, 145 insertions(+), 39 deletions(-) diff --git a/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/ViewNode/ViewImageNode.cs b/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/ViewNode/ViewImageNode.cs index 1fd2955..556fd08 100644 --- a/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/ViewNode/ViewImageNode.cs +++ b/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/ViewNode/ViewImageNode.cs @@ -1,27 +1,35 @@ using ImageProcessingGraph.Editor.Nodes.NodeAttributes; using UnityEngine; +using Unity.Collections; +using Unity.Jobs; +using Unity.Burst; namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode { [NodeInfo("View Texture", "Utility/View Texture", false, null ,typeof(ViewTextureNodeEditor))] - public class ViewTextureNode : BaseImageNode + public partial class ViewTextureNode : BaseImageNode { [NodeAttributes.Input("Texture")] public Texture2D texture; [NodeAttributes.Input("Image Data")] public ImageData imageData; public delegate void OnImageUpdated(); public OnImageUpdated onImageUpdated; - + + public Texture2D cachedRGB; + public Texture2D cachedR; + public Texture2D cachedG; + public Texture2D cachedB; + public Texture2D cachedA; + public override void Process() { if (texture == null) { texture = imageData.ToTexture2D(); } - - //CHANGE NPOT SETTING - - + + GenerateChannelTextures(texture); + onImageUpdated?.Invoke(); } @@ -30,5 +38,98 @@ namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode texture = null; imageData = default; } + + private void GenerateChannelTextures(Texture2D source) + { + var pixels = source.GetPixels(); + int length = pixels.Length; + + NativeArray inputPixels = new NativeArray(pixels, Allocator.TempJob); + + NativeArray outputR = new NativeArray(length, Allocator.TempJob); + NativeArray outputG = new NativeArray(length, Allocator.TempJob); + NativeArray outputB = new NativeArray(length, Allocator.TempJob); + NativeArray outputA = new NativeArray(length, Allocator.TempJob); + + var jobR = new ChannelJob(ChannelType.R, inputPixels, outputR); + var jobG = new ChannelJob(ChannelType.G, inputPixels, outputG); + var jobB = new ChannelJob(ChannelType.B, inputPixels, outputB); + var jobA = new ChannelJob(ChannelType.A, inputPixels, outputA); + + JobHandle handleR = jobR.Schedule(length, 64); + JobHandle handleG = jobG.Schedule(length, 64); + JobHandle handleB = jobB.Schedule(length, 64); + JobHandle handleA = jobA.Schedule(length, 64); + + var handles = new NativeArray(4, Allocator.Temp); + handles[0] = handleR; + handles[1] = handleG; + handles[2] = handleB; + handles[3] = handleA; + + JobHandle.CompleteAll(handles); + handles.Dispose(); + + + cachedRGB = source; + cachedR = CreateTexture(source.width, source.height, outputR); + cachedG = CreateTexture(source.width, source.height, outputG); + cachedB = CreateTexture(source.width, source.height, outputB); + cachedA = CreateTexture(source.width, source.height, outputA); + + inputPixels.Dispose(); + outputR.Dispose(); + outputG.Dispose(); + outputB.Dispose(); + outputA.Dispose(); + } + + private Texture2D CreateTexture(int width, int height, NativeArray colors) + { + Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false); + tex.SetPixels(colors.ToArray()); + tex.Apply(); + return tex; + } + + [BurstCompile] + private struct ChannelJob : IJobParallelFor + { + public ChannelType channelType; + [ReadOnly] public NativeArray input; + public NativeArray output; + + public ChannelJob(ChannelType type, NativeArray input, NativeArray output) + { + this.channelType = type; + this.input = input; + this.output = output; + } + + public void Execute(int index) + { + Color c = input[index]; + switch (channelType) + { + case ChannelType.R: + output[index] = new Color(c.r, c.r, c.r, 1f); + break; + case ChannelType.G: + output[index] = new Color(c.g, c.g, c.g, 1f); + break; + case ChannelType.B: + output[index] = new Color(c.b, c.b, c.b, 1f); + break; + case ChannelType.A: + output[index] = new Color(c.a, c.a, c.a, 1f); + break; + } + } + } + + private enum ChannelType + { + R, G, B, A + } } -} \ No newline at end of file +} diff --git a/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/ViewNode/ViewImageNodeEditor.cs b/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/ViewNode/ViewImageNodeEditor.cs index 5ec0050..4cae66d 100644 --- a/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/ViewNode/ViewImageNodeEditor.cs +++ b/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/ViewNode/ViewImageNodeEditor.cs @@ -9,7 +9,7 @@ namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode private UnityEngine.UIElements.Image viewableImage; private Foldout foldout; private VisualElement buttonRow; - + public ViewTextureNodeEditor(BaseImageNode node, ImageProcessingGraphViewWindow window) : base(node, window) { //Port 0 is Texture2D @@ -18,30 +18,18 @@ namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode IPTPort tex2DPort = InputPorts[0] as IPTPort; IPTPort imageDataPort = InputPorts[1] as IPTPort; - tex2DPort.OnPortConnected += () => - { - imageDataPort.style.display = DisplayStyle.None; - }; + tex2DPort.OnPortConnected += () => { imageDataPort.style.display = DisplayStyle.None; }; - tex2DPort.OnPortDisconnected += () => - { - imageDataPort.style.display = DisplayStyle.Flex; - }; + tex2DPort.OnPortDisconnected += () => { imageDataPort.style.display = DisplayStyle.Flex; }; + + imageDataPort.OnPortConnected += () => { tex2DPort.style.display = DisplayStyle.None; }; + + imageDataPort.OnPortDisconnected += () => { tex2DPort.style.display = DisplayStyle.Flex; }; - imageDataPort.OnPortConnected += () => - { - tex2DPort.style.display = DisplayStyle.None; - }; - - imageDataPort.OnPortDisconnected += () => - { - tex2DPort.style.display = DisplayStyle.Flex; - }; - this.Q("output").style.display = DisplayStyle.None; - + ViewTextureNode viewImageNode = node as ViewTextureNode; - + foldout = new Foldout { text = "Texture Viewer", @@ -50,7 +38,7 @@ namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode foldout.style.backgroundColor = new Color(63f / 255f, 63f / 255f, 63f / 255f, 205f / 255f); foldout.contentContainer.style.justifyContent = Justify.Center; Add(foldout); - + viewableImage = new UnityEngine.UIElements.Image { scaleMode = ScaleMode.ScaleToFit @@ -59,12 +47,9 @@ namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode viewableImage.style.height = 256; viewableImage.style.backgroundColor = Color.black; foldout.Add(viewableImage); - - viewImageNode.onImageUpdated += () => - { - viewableImage.image = viewImageNode.texture; - }; - + + viewImageNode.onImageUpdated += () => { viewableImage.image = viewImageNode.texture; }; + buttonRow = new VisualElement { style = @@ -76,7 +61,7 @@ namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode marginBottom = 8, } }; - + string[] channels = { "RGB", "R", "G", "B", "A" }; foreach (var channel in channels) { @@ -87,13 +72,33 @@ namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode btn.style.flexGrow = 1; buttonRow.Add(btn); } - + foldout.Add(buttonRow); } - + private void OnChannelClicked(ViewTextureNode viewNode, string channel) { - Debug.Log($"[ViewTextureNodeEditor] Channel Selected: {channel}"); + switch (channel) + { + case "RGB": + viewableImage.image = viewNode.cachedRGB; + break; + case "R": + viewableImage.image = viewNode.cachedR; + break; + case "G": + viewableImage.image = viewNode.cachedG; + break; + case "B": + viewableImage.image = viewNode.cachedB; + break; + case "A": + viewableImage.image = viewNode.cachedA; + break; + default: + Debug.LogError("[ViewTextureNodeEditor] Unknown channel clicked! Did you hack reality again?"); + break; + } } } }