Skip to content

Commit 1cc9429

Browse files
committed
Implemented coroutines for faster image processing
1 parent 799b9a1 commit 1cc9429

File tree

3 files changed

+112
-35
lines changed

3 files changed

+112
-35
lines changed

.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[*.cs]
2+
3+
# CS8604: Possible null reference argument.
4+
dotnet_diagnostic.CS8604.severity = silent

Unity Mask Map Generator.sln

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
44
VisualStudioVersion = 17.10.35027.167
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity Mask Map Generator", "Unity Mask Map Generator\Unity Mask Map Generator.csproj", "{E9C23C30-B13F-4A16-B7E9-1EE3349220FE}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Unity Mask Map Generator", "Unity Mask Map Generator\Unity Mask Map Generator.csproj", "{E9C23C30-B13F-4A16-B7E9-1EE3349220FE}"
7+
EndProject
8+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C13CDC82-9224-484E-9BDA-035B420B016B}"
9+
ProjectSection(SolutionItems) = preProject
10+
.editorconfig = .editorconfig
11+
EndProjectSection
712
EndProject
813
Global
914
GlobalSection(SolutionConfigurationPlatforms) = preSolution

Unity Mask Map Generator/Form1.cs

Lines changed: 102 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ namespace Unity_Mask_Map_Generator
88
{
99
public partial class Form1 : Form
1010
{
11-
Bitmap metallic, ao, detail, smoothness, maskMap;
12-
bool state1, state2, state3, state4 = false;
13-
bool invertState1, invertState2, invertState3, invertState4 = false;
11+
private static Bitmap metallic, ao, detail, smoothness, maskMap;
12+
private static bool state1, state2, state3, state4 = false;
13+
private static bool invertState1, invertState2, invertState3, invertState4 = false;
1414
int imageCount = 0;
1515
public Form1()
1616
{
@@ -144,7 +144,7 @@ private void button1_Click(object sender, EventArgs e)
144144
if (state1 == true || state2 == true || state3 == true || state4 == true)
145145
{
146146
helpText.Visible = false;
147-
generateMaskMap();
147+
GenerateMaskMap();
148148
}
149149
else if (metallic != null && ao != null && smoothness != null && detail != null && !isBoundsMatching())
150150
{
@@ -258,57 +258,125 @@ private void pictureBox3_DragDrop(object sender, DragEventArgs e)
258258

259259
}
260260

261-
private async void generateMaskMap()
261+
private async void GenerateMaskMap()
262262
{
263263
CheckForIllegalCrossThreadCalls = false;
264+
264265
int width = Math.Max(Math.Max(metallic?.Width ?? 0, ao?.Width ?? 0), Math.Max(smoothness?.Width ?? 0, detail?.Width ?? 0));
265266
int height = Math.Max(Math.Max(metallic?.Height ?? 0, ao?.Height ?? 0), Math.Max(smoothness?.Height ?? 0, detail?.Height ?? 0));
267+
266268
save.Visible = false;
267269
imgSize.Visible = false;
268270
maskMap?.Dispose();
269271
maskMap = null;
270272
resultPictureBox.Image = null;
273+
271274
maskMap = new Bitmap(width, height);
272275
progressBar1.Visible = true;
273276
EnableOrDisableCheckBoxes(false);
274-
Stopwatch stopwatch = new Stopwatch();
275-
stopwatch.Start();
276-
await GlobalScope.Launch(() =>
277+
278+
generate.Enabled = false;
279+
generate.Text = "Generating...";
280+
helpText2.Visible = true;
281+
progressLabel.Visible = true;
282+
283+
byte[] maskMapData = new byte[width * height * 4];
284+
byte[]? metallicData = metallic != null ? ConvertBitmapToByteArray(metallic) : null;
285+
byte[]? aoData = ao != null ? ConvertBitmapToByteArray(ao) : null;
286+
byte[]? detailData = detail != null ? ConvertBitmapToByteArray(detail) : null;
287+
byte[]? smoothnessData = smoothness != null ? ConvertBitmapToByteArray(smoothness) : null;
288+
289+
Stopwatch stopwatch = Stopwatch.StartNew();
290+
291+
// Using the CoroutineBuilder to launch multiple coroutines in parallel
292+
await CoroutineBuilder.LaunchAll(new List<Func<Task>>{
293+
() => { ProcessImage(maskMapData, metallicData, aoData, detailData, smoothnessData, width, height, 0, height / 4); return Task.CompletedTask; },
294+
() => { ProcessImage(maskMapData, metallicData, aoData, detailData, smoothnessData, width, height, height / 4, height / 4); return Task.CompletedTask; },
295+
() => { ProcessImage(maskMapData, metallicData, aoData, detailData, smoothnessData, width, height, height / 2, height / 4); return Task.CompletedTask; },
296+
() => { ProcessImage(maskMapData, metallicData, aoData, detailData, smoothnessData, width, height, 3 * height / 4, height / 4); return Task.CompletedTask; }
297+
}, Dispatcher.Main);
298+
299+
maskMap = ConvertToBitmap(maskMapData, width, height);
300+
resultPictureBox.Image = maskMap;
301+
stopwatch.Stop();
302+
imgSize.Text = $"Image Size: {width} x {height} ({stopwatch.ElapsedMilliseconds / 1000f:F2}s)";
303+
imgSize.Visible = true;
304+
progressBar1.Visible = false;
305+
progressLabel.Visible = false;
306+
save.Visible = true;
307+
helpText2.Visible = false;
308+
generate.Text = "Generate";
309+
EnableOrDisableCheckBoxes(true);
310+
generate.Enabled = true;
311+
}
312+
313+
private static byte[] ConvertBitmapToByteArray(Bitmap bitmap)
314+
{
315+
int width = bitmap.Width;
316+
int height = bitmap.Height;
317+
byte[] byteArray = new byte[width * height * 4];
318+
319+
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
320+
System.Runtime.InteropServices.Marshal.Copy(bitmapData.Scan0, byteArray, 0, byteArray.Length);
321+
bitmap.UnlockBits(bitmapData);
322+
323+
return byteArray;
324+
}
325+
326+
private static void ProcessImage(byte[] maskMapData, byte[] metallicData, byte[] aoData, byte[] detailData, byte[] smoothnessData, int width, int height, int startY, int chunkHeight)
327+
{
328+
for (int y = startY; y < startY + chunkHeight; y++)
277329
{
278-
generate.Enabled = false;
279-
generate.Text = "Generating...";
280-
helpText2.Visible = true;
281-
progressLabel.Visible = true;
282-
for (int y = 0; y < height; y++)
330+
for (int x = 0; x < width; x++)
283331
{
284-
for (int x = 0; x < width; x++)
332+
int index = (y * width + x) * 4;
333+
334+
int a = 255, r = 0, g = 0, b = 0;
335+
336+
if (metallicData != null)
285337
{
286-
int r = metallic != null ? metallic.GetPixel(x, y).R : 0;
338+
int metallicIndex = index;
339+
r = metallicData[metallicIndex + 2];
287340
if (invertState1) r = 255 - r;
288-
int g = ao != null ? ao.GetPixel(x, y).G : 0;
341+
}
342+
343+
if (aoData != null)
344+
{
345+
int aoIndex = index;
346+
g = aoData[aoIndex + 1];
289347
if (invertState2) g = 255 - g;
290-
int b = detail != null ? detail.GetPixel(x, y).B : 0;
348+
}
349+
350+
if (detailData != null)
351+
{
352+
int detailIndex = index;
353+
b = detailData[detailIndex];
291354
if (invertState4) b = 255 - b;
292-
int a = smoothness != null ? smoothness.GetPixel(x, y).R : 255;
355+
}
356+
357+
if (smoothnessData != null)
358+
{
359+
int smoothnessIndex = index;
360+
a = smoothnessData[smoothnessIndex + 3];
293361
if (invertState3) a = 255 - a;
294-
maskMap.SetPixel(x, y, Color.FromArgb(a, r, g, b));
295362
}
296-
int progress = (int)((y * 1f) / height * 100);
297-
progressLabel.Text = progress + "%";
298-
progressBar1.Value = progress;
363+
364+
maskMapData[index + 0] = (byte)b;
365+
maskMapData[index + 1] = (byte)g;
366+
maskMapData[index + 2] = (byte)r;
367+
maskMapData[index + 3] = (byte)a;
299368
}
300-
stopwatch.Stop();
301-
imgSize.Text = $"Image Size: {width} x {height} ({stopwatch.ElapsedMilliseconds / 1000f}s)";
302-
imgSize.Visible = true;
303-
progressBar1.Visible = false;
304-
progressLabel.Visible = false;
305-
save.Visible = true;
306-
helpText2.Visible = false;
307-
generate.Text = "Generate";
308-
EnableOrDisableCheckBoxes(true);
309-
generate.Enabled = true;
310-
});
311-
resultPictureBox.Image = maskMap;
369+
}
370+
}
371+
372+
private static Bitmap ConvertToBitmap(byte[] pixelData, int width, int height)
373+
{
374+
Bitmap bitmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
375+
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat);
376+
System.Runtime.InteropServices.Marshal.Copy(pixelData, 0, bitmapData.Scan0, pixelData.Length);
377+
bitmap.UnlockBits(bitmapData);
378+
379+
return bitmap;
312380
}
313381

314382
private void EnableOrDisableCheckBoxes(bool state)

0 commit comments

Comments
 (0)