Skip to content

Commit e00b2ae

Browse files
authored
[FEATURE] Procedural Texture2D/Sprite Generation (#621)
* Update for Texture2D/Sprite Generation Given the choice to generate Texture2D based on patterns and color, also introduce pipeline to turn Texture2D direct to Sprite. Update CLI command to include this too. * Texture Size Set Set texture size to 1024X1024 to avoid too large texture set * Add image input * Update to release direct error with large tex2d * Fix for AI advice * Update on action fetch line
1 parent 67dda7f commit e00b2ae

File tree

15 files changed

+2797
-6
lines changed

15 files changed

+2797
-6
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using Newtonsoft.Json.Linq;
5+
using UnityEngine;
6+
7+
namespace MCPForUnity.Editor.Helpers
8+
{
9+
public static class TextureOps
10+
{
11+
public static byte[] EncodeTexture(Texture2D texture, string assetPath)
12+
{
13+
if (texture == null)
14+
return null;
15+
16+
string extension = Path.GetExtension(assetPath);
17+
if (string.IsNullOrEmpty(extension))
18+
{
19+
McpLog.Warn($"[TextureOps] No file extension for '{assetPath}', defaulting to PNG.");
20+
return texture.EncodeToPNG();
21+
}
22+
23+
switch (extension.ToLowerInvariant())
24+
{
25+
case ".png":
26+
return texture.EncodeToPNG();
27+
case ".jpg":
28+
case ".jpeg":
29+
return texture.EncodeToJPG();
30+
default:
31+
McpLog.Warn($"[TextureOps] Unsupported extension '{extension}' for '{assetPath}', defaulting to PNG.");
32+
return texture.EncodeToPNG();
33+
}
34+
}
35+
36+
public static void FillTexture(Texture2D texture, Color32 color)
37+
{
38+
if (texture == null)
39+
return;
40+
41+
Color32[] pixels = new Color32[texture.width * texture.height];
42+
for (int i = 0; i < pixels.Length; i++)
43+
{
44+
pixels[i] = color;
45+
}
46+
texture.SetPixels32(pixels);
47+
}
48+
49+
public static Color32 ParseColor32(JArray colorArray)
50+
{
51+
if (colorArray == null || colorArray.Count < 3)
52+
return new Color32(255, 255, 255, 255);
53+
54+
byte r = (byte)Mathf.Clamp(colorArray[0].ToObject<int>(), 0, 255);
55+
byte g = (byte)Mathf.Clamp(colorArray[1].ToObject<int>(), 0, 255);
56+
byte b = (byte)Mathf.Clamp(colorArray[2].ToObject<int>(), 0, 255);
57+
byte a = colorArray.Count > 3 ? (byte)Mathf.Clamp(colorArray[3].ToObject<int>(), 0, 255) : (byte)255;
58+
59+
return new Color32(r, g, b, a);
60+
}
61+
62+
public static List<Color32> ParsePalette(JArray paletteArray)
63+
{
64+
if (paletteArray == null)
65+
return null;
66+
67+
List<Color32> palette = new List<Color32>();
68+
foreach (var item in paletteArray)
69+
{
70+
if (item is JArray colorArray)
71+
{
72+
palette.Add(ParseColor32(colorArray));
73+
}
74+
}
75+
return palette.Count > 0 ? palette : null;
76+
}
77+
78+
public static void ApplyPixelData(Texture2D texture, JToken pixelsToken, int width, int height)
79+
{
80+
ApplyPixelDataToRegion(texture, pixelsToken, 0, 0, width, height);
81+
}
82+
83+
public static void ApplyPixelDataToRegion(Texture2D texture, JToken pixelsToken, int offsetX, int offsetY, int regionWidth, int regionHeight)
84+
{
85+
if (texture == null || pixelsToken == null)
86+
return;
87+
88+
int textureWidth = texture.width;
89+
int textureHeight = texture.height;
90+
91+
if (pixelsToken is JArray pixelArray)
92+
{
93+
int index = 0;
94+
for (int y = 0; y < regionHeight && index < pixelArray.Count; y++)
95+
{
96+
for (int x = 0; x < regionWidth && index < pixelArray.Count; x++)
97+
{
98+
var pixelColor = pixelArray[index] as JArray;
99+
if (pixelColor != null)
100+
{
101+
int px = offsetX + x;
102+
int py = offsetY + y;
103+
if (px >= 0 && px < textureWidth && py >= 0 && py < textureHeight)
104+
{
105+
texture.SetPixel(px, py, ParseColor32(pixelColor));
106+
}
107+
}
108+
index++;
109+
}
110+
}
111+
112+
int expectedCount = regionWidth * regionHeight;
113+
if (pixelArray.Count != expectedCount)
114+
{
115+
McpLog.Warn($"[TextureOps] Pixel array size mismatch: expected {expectedCount} entries, got {pixelArray.Count}");
116+
}
117+
}
118+
else if (pixelsToken.Type == JTokenType.String)
119+
{
120+
string pixelString = pixelsToken.ToString();
121+
string base64 = pixelString.StartsWith("base64:") ? pixelString.Substring(7) : pixelString;
122+
if (!pixelString.StartsWith("base64:"))
123+
{
124+
McpLog.Warn("[TextureOps] Base64 pixel data missing 'base64:' prefix; attempting to decode.");
125+
}
126+
127+
byte[] rawData = Convert.FromBase64String(base64);
128+
129+
// Assume RGBA32 format: 4 bytes per pixel
130+
int expectedBytes = regionWidth * regionHeight * 4;
131+
if (rawData.Length == expectedBytes)
132+
{
133+
int pixelIndex = 0;
134+
for (int y = 0; y < regionHeight; y++)
135+
{
136+
for (int x = 0; x < regionWidth; x++)
137+
{
138+
int px = offsetX + x;
139+
int py = offsetY + y;
140+
if (px >= 0 && px < textureWidth && py >= 0 && py < textureHeight)
141+
{
142+
int byteIndex = pixelIndex * 4;
143+
Color32 color = new Color32(
144+
rawData[byteIndex],
145+
rawData[byteIndex + 1],
146+
rawData[byteIndex + 2],
147+
rawData[byteIndex + 3]
148+
);
149+
texture.SetPixel(px, py, color);
150+
}
151+
pixelIndex++;
152+
}
153+
}
154+
}
155+
else
156+
{
157+
McpLog.Warn($"[TextureOps] Base64 data size mismatch: expected {expectedBytes} bytes, got {rawData.Length}");
158+
}
159+
}
160+
}
161+
}
162+
}

MCPForUnity/Editor/Helpers/TextureOps.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MCPForUnity/Editor/Tools/ManageAsset.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public static class ManageAsset
4545

4646
public static object HandleCommand(JObject @params)
4747
{
48-
string action = @params["action"]?.ToString().ToLower();
48+
string action = @params["action"]?.ToString()?.ToLowerInvariant();
4949
if (string.IsNullOrEmpty(action))
5050
{
5151
return new ErrorResponse("Action parameter is required.");

MCPForUnity/Editor/Tools/ManageEditor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static class ManageEditor
2424
/// </summary>
2525
public static object HandleCommand(JObject @params)
2626
{
27-
string action = @params["action"]?.ToString().ToLower();
27+
string action = @params["action"]?.ToString()?.ToLowerInvariant();
2828
// Parameters for specific actions
2929
string tagName = @params["tagName"]?.ToString();
3030
string layerName = @params["layerName"]?.ToString();

MCPForUnity/Editor/Tools/ManageMaterial.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public static class ManageMaterial
1313
{
1414
public static object HandleCommand(JObject @params)
1515
{
16-
string action = @params["action"]?.ToString();
16+
string action = @params["action"]?.ToString()?.ToLowerInvariant();
1717
if (string.IsNullOrEmpty(action))
1818
{
1919
return new ErrorResponse("Action is required");

MCPForUnity/Editor/Tools/ManageShader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static class ManageShader
2121
public static object HandleCommand(JObject @params)
2222
{
2323
// Extract parameters
24-
string action = @params["action"]?.ToString().ToLower();
24+
string action = @params["action"]?.ToString()?.ToLowerInvariant();
2525
string name = @params["name"]?.ToString();
2626
string path = @params["path"]?.ToString(); // Relative to Assets/
2727
string contents = null;

0 commit comments

Comments
 (0)