use try..finally to make sure rented arrays are returned
This commit is contained in:
parent
48d0f70ffd
commit
40d5cd7c05
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using StardewValley;
|
using StardewValley;
|
||||||
|
@ -64,20 +63,23 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
{
|
{
|
||||||
int pixelCount = areaWidth * areaHeight;
|
int pixelCount = areaWidth * areaHeight;
|
||||||
sourceData = ArrayPool<Color>.Shared.Rent(pixelCount);
|
sourceData = ArrayPool<Color>.Shared.Rent(pixelCount);
|
||||||
|
try
|
||||||
// slower copying, line by line
|
|
||||||
for (int y = areaY, maxY = areaY + areaHeight; y < maxY; y++)
|
|
||||||
{
|
{
|
||||||
int sourceIndex = (y * source.Width) + areaX;
|
// slower copying, line by line
|
||||||
int targetIndex = (y - areaY) * areaWidth;
|
for (int y = areaY, maxY = areaY + areaHeight; y < maxY; y++)
|
||||||
Array.Copy(source.Data, sourceIndex, sourceData, targetIndex, areaWidth);
|
{
|
||||||
|
int sourceIndex = (y * source.Width) + areaX;
|
||||||
|
int targetIndex = (y - areaY) * areaWidth;
|
||||||
|
Array.Copy(source.Data, sourceIndex, sourceData, targetIndex, areaWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply
|
||||||
|
this.PatchImageImpl(sourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Color>.Shared.Return(sourceData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply
|
|
||||||
this.PatchImageImpl(sourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode);
|
|
||||||
|
|
||||||
// return
|
|
||||||
ArrayPool<Color>.Shared.Return(sourceData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,13 +100,15 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
// get source data
|
// get source data
|
||||||
int pixelCount = sourceArea.Value.Width * sourceArea.Value.Height;
|
int pixelCount = sourceArea.Value.Width * sourceArea.Value.Height;
|
||||||
Color[] sourceData = ArrayPool<Color>.Shared.Rent(pixelCount);
|
Color[] sourceData = ArrayPool<Color>.Shared.Rent(pixelCount);
|
||||||
source.GetData(0, sourceArea, sourceData, 0, pixelCount);
|
try
|
||||||
|
{
|
||||||
// apply
|
source.GetData(0, sourceArea, sourceData, 0, pixelCount);
|
||||||
this.PatchImageImpl(sourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode);
|
this.PatchImageImpl(sourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode);
|
||||||
|
}
|
||||||
// return
|
finally
|
||||||
ArrayPool<Color>.Shared.Return(sourceData);
|
{
|
||||||
|
ArrayPool<Color>.Shared.Return(sourceData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -207,41 +211,47 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
|
|
||||||
// get target data
|
// get target data
|
||||||
Color[] mergedData = ArrayPool<Color>.Shared.Rent(pixelCount);
|
Color[] mergedData = ArrayPool<Color>.Shared.Rent(pixelCount);
|
||||||
target.GetData(0, targetArea, mergedData, 0, pixelCount);
|
try
|
||||||
|
|
||||||
// merge pixels
|
|
||||||
for (int i = startIndex; i <= endIndex; i++)
|
|
||||||
{
|
{
|
||||||
int targetIndex = i - sourceoffset;
|
target.GetData(0, targetArea, mergedData, 0, pixelCount);
|
||||||
|
|
||||||
// ref locals here? Not sure.
|
|
||||||
Color above = sourceData[i];
|
|
||||||
Color below = mergedData[targetIndex];
|
|
||||||
|
|
||||||
// shortcut transparency
|
|
||||||
if (above.A < MinOpacity)
|
|
||||||
continue;
|
|
||||||
if (below.A < MinOpacity || above.A == byte.MaxValue)
|
|
||||||
mergedData[targetIndex] = above;
|
|
||||||
|
|
||||||
// merge pixels
|
// merge pixels
|
||||||
else
|
for (int i = startIndex; i <= endIndex; i++)
|
||||||
{
|
{
|
||||||
// This performs a conventional alpha blend for the pixels, which are already
|
int targetIndex = i - sourceoffset;
|
||||||
// premultiplied by the content pipeline. The formula is derived from
|
|
||||||
// https://blogs.msdn.microsoft.com/shawnhar/2009/11/06/premultiplied-alpha/.
|
|
||||||
float alphaBelow = 1 - (above.A / 255f);
|
|
||||||
mergedData[targetIndex] = new Color(
|
|
||||||
r: (int)(above.R + (below.R * alphaBelow)),
|
|
||||||
g: (int)(above.G + (below.G * alphaBelow)),
|
|
||||||
b: (int)(above.B + (below.B * alphaBelow)),
|
|
||||||
alpha: Math.Max(above.A, below.A)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target.SetData(0, targetArea, mergedData, 0, pixelCount);
|
// ref locals here? Not sure.
|
||||||
ArrayPool<Color>.Shared.Return(mergedData);
|
Color above = sourceData[i];
|
||||||
|
Color below = mergedData[targetIndex];
|
||||||
|
|
||||||
|
// shortcut transparency
|
||||||
|
if (above.A < MinOpacity)
|
||||||
|
continue;
|
||||||
|
if (below.A < MinOpacity || above.A == byte.MaxValue)
|
||||||
|
mergedData[targetIndex] = above;
|
||||||
|
|
||||||
|
// merge pixels
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This performs a conventional alpha blend for the pixels, which are already
|
||||||
|
// premultiplied by the content pipeline. The formula is derived from
|
||||||
|
// https://blogs.msdn.microsoft.com/shawnhar/2009/11/06/premultiplied-alpha/.
|
||||||
|
float alphaBelow = 1 - (above.A / 255f);
|
||||||
|
mergedData[targetIndex] = new Color(
|
||||||
|
r: (int)(above.R + (below.R * alphaBelow)),
|
||||||
|
g: (int)(above.G + (below.G * alphaBelow)),
|
||||||
|
b: (int)(above.B + (below.B * alphaBelow)),
|
||||||
|
alpha: Math.Max(above.A, below.A)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target.SetData(0, targetArea, mergedData, 0, pixelCount);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Color>.Shared.Return(mergedData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,25 +395,30 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
// premultiply pixels
|
// premultiply pixels
|
||||||
int count = texture.Width * texture.Height;
|
int count = texture.Width * texture.Height;
|
||||||
Color[] data = ArrayPool<Color>.Shared.Rent(count);
|
Color[] data = ArrayPool<Color>.Shared.Rent(count);
|
||||||
texture.GetData(data, 0, count);
|
try
|
||||||
|
|
||||||
bool changed = false;
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
{
|
||||||
ref Color pixel = ref data[i];
|
texture.GetData(data, 0, count);
|
||||||
if (pixel.A is (byte.MinValue or byte.MaxValue))
|
|
||||||
continue; // no need to change fully transparent/opaque pixels
|
|
||||||
|
|
||||||
data[i] = new Color(pixel.R * pixel.A / byte.MaxValue, pixel.G * pixel.A / byte.MaxValue, pixel.B * pixel.A / byte.MaxValue, pixel.A); // slower version: Color.FromNonPremultiplied(data[i].ToVector4())
|
bool changed = false;
|
||||||
changed = true;
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
ref Color pixel = ref data[i];
|
||||||
|
if (pixel.A is (byte.MinValue or byte.MaxValue))
|
||||||
|
continue; // no need to change fully transparent/opaque pixels
|
||||||
|
|
||||||
|
data[i] = new Color(pixel.R * pixel.A / byte.MaxValue, pixel.G * pixel.A / byte.MaxValue, pixel.B * pixel.A / byte.MaxValue, pixel.A); // slower version: Color.FromNonPremultiplied(data[i].ToVector4())
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
texture.SetData(data, 0, count);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<Color>.Shared.Return(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed)
|
|
||||||
texture.SetData(data, 0, count);
|
|
||||||
|
|
||||||
// return
|
|
||||||
ArrayPool<Color>.Shared.Return(data);
|
|
||||||
return texture;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Fix custom map tilesheet paths so they can be found by the content manager.</summary>
|
/// <summary>Fix custom map tilesheet paths so they can be found by the content manager.</summary>
|
||||||
|
|
Loading…
Reference in New Issue