add IRawTextureData asset type
This commit is contained in:
parent
a546fd113f
commit
4708385f69
|
@ -5,6 +5,9 @@
|
||||||
* For players:
|
* For players:
|
||||||
* Added experimental image load rewrite (disabled by default).
|
* Added experimental image load rewrite (disabled by default).
|
||||||
_If you have many content mods installed, enabling `UseExperimentalImageLoading` in `smapi-internal/config.json` may reduce load times or stutters when they load many image files at once._
|
_If you have many content mods installed, enabling `UseExperimentalImageLoading` in `smapi-internal/config.json` may reduce load times or stutters when they load many image files at once._
|
||||||
|
* For mod authors:
|
||||||
|
* Added specialized `IRawTextureData` asset type.
|
||||||
|
_When you're only loading a mod file to patch it into an asset, you can now load it using `helper.ModContent.Load<IRawTextureData>(path)`. This reads the image data from disk without initializing a `Texture2D` instance through the GPU. You can then pass this to SMAPI APIs that accept `Texture2D` instances._
|
||||||
|
|
||||||
* For mod authors:
|
* For mod authors:
|
||||||
* Fixed map edits which change warps sometimes rebuilding the NPC pathfinding cache unnecessarily, which could cause a noticeable delay for players.
|
* Fixed map edits which change warps sometimes rebuilding the NPC pathfinding cache unnecessarily, which could cause a noticeable delay for players.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using StardewValley;
|
using StardewValley;
|
||||||
|
@ -28,74 +29,62 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
public AssetDataForImage(string? locale, IAssetName assetName, Texture2D data, Func<string, string> getNormalizedPath, Action<Texture2D> onDataReplaced)
|
public AssetDataForImage(string? locale, IAssetName assetName, Texture2D data, Func<string, string> getNormalizedPath, Action<Texture2D> onDataReplaced)
|
||||||
: base(locale, assetName, data, getNormalizedPath, onDataReplaced) { }
|
: base(locale, assetName, data, getNormalizedPath, onDataReplaced) { }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void PatchImage(IRawTextureData source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMode patchMode = PatchMode.Replace)
|
||||||
|
{
|
||||||
|
this.GetPatchBounds(ref sourceArea, ref targetArea, source.Width, source.Height);
|
||||||
|
|
||||||
|
// validate source data
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException(nameof(source), "Can't patch from null source data.");
|
||||||
|
|
||||||
|
// get the pixels for the source area
|
||||||
|
Color[] sourceData;
|
||||||
|
{
|
||||||
|
int areaX = sourceArea.Value.X;
|
||||||
|
int areaY = sourceArea.Value.Y;
|
||||||
|
int areaWidth = sourceArea.Value.Width;
|
||||||
|
int areaHeight = sourceArea.Value.Height;
|
||||||
|
|
||||||
|
if (areaX == 0 && areaY == 0 && areaWidth == source.Width && areaHeight == source.Height)
|
||||||
|
sourceData = source.Data;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sourceData = new Color[areaWidth * areaHeight];
|
||||||
|
int i = 0;
|
||||||
|
for (int y = areaY, maxY = areaY + areaHeight - 1; y <= maxY; y++)
|
||||||
|
{
|
||||||
|
for (int x = areaX, maxX = areaX + areaWidth - 1; x <= maxX; x++)
|
||||||
|
{
|
||||||
|
int targetIndex = (y * source.Width) + x;
|
||||||
|
sourceData[i++] = source.Data[targetIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply
|
||||||
|
this.PatchImageImpl(sourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void PatchImage(Texture2D source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMode patchMode = PatchMode.Replace)
|
public void PatchImage(Texture2D source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMode patchMode = PatchMode.Replace)
|
||||||
{
|
{
|
||||||
// get texture
|
this.GetPatchBounds(ref sourceArea, ref targetArea, source.Width, source.Height);
|
||||||
|
|
||||||
|
// validate source texture
|
||||||
if (source == null)
|
if (source == null)
|
||||||
throw new ArgumentNullException(nameof(source), "Can't patch from a null source texture.");
|
throw new ArgumentNullException(nameof(source), "Can't patch from a null source texture.");
|
||||||
Texture2D target = this.Data;
|
|
||||||
|
|
||||||
// get areas
|
|
||||||
sourceArea ??= new Rectangle(0, 0, source.Width, source.Height);
|
|
||||||
targetArea ??= new Rectangle(0, 0, Math.Min(sourceArea.Value.Width, target.Width), Math.Min(sourceArea.Value.Height, target.Height));
|
|
||||||
|
|
||||||
// validate
|
|
||||||
if (!source.Bounds.Contains(sourceArea.Value))
|
if (!source.Bounds.Contains(sourceArea.Value))
|
||||||
throw new ArgumentOutOfRangeException(nameof(sourceArea), "The source area is outside the bounds of the source texture.");
|
throw new ArgumentOutOfRangeException(nameof(sourceArea), "The source area is outside the bounds of the source texture.");
|
||||||
if (!target.Bounds.Contains(targetArea.Value))
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(targetArea), "The target area is outside the bounds of the target texture.");
|
|
||||||
if (sourceArea.Value.Size != targetArea.Value.Size)
|
|
||||||
throw new InvalidOperationException("The source and target areas must be the same size.");
|
|
||||||
|
|
||||||
// get source data
|
// get source data
|
||||||
int pixelCount = sourceArea.Value.Width * sourceArea.Value.Height;
|
int pixelCount = sourceArea.Value.Width * sourceArea.Value.Height;
|
||||||
Color[] sourceData = GC.AllocateUninitializedArray<Color>(pixelCount);
|
Color[] sourceData = GC.AllocateUninitializedArray<Color>(pixelCount);
|
||||||
source.GetData(0, sourceArea, sourceData, 0, pixelCount);
|
source.GetData(0, sourceArea, sourceData, 0, pixelCount);
|
||||||
|
|
||||||
// merge data in overlay mode
|
// apply
|
||||||
if (patchMode == PatchMode.Overlay)
|
this.PatchImageImpl(sourceData, source.Width, source.Height, sourceArea.Value, targetArea.Value, patchMode);
|
||||||
{
|
|
||||||
// get target data
|
|
||||||
Color[] targetData = GC.AllocateUninitializedArray<Color>(pixelCount);
|
|
||||||
target.GetData(0, targetArea, targetData, 0, pixelCount);
|
|
||||||
|
|
||||||
// merge pixels
|
|
||||||
for (int i = 0; i < sourceData.Length; i++)
|
|
||||||
{
|
|
||||||
Color above = sourceData[i];
|
|
||||||
Color below = targetData[i];
|
|
||||||
|
|
||||||
// shortcut transparency
|
|
||||||
if (above.A < MinOpacity)
|
|
||||||
{
|
|
||||||
sourceData[i] = below;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (below.A < MinOpacity)
|
|
||||||
{
|
|
||||||
sourceData[i] = above;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge pixels
|
|
||||||
// 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/.
|
|
||||||
// Note: don't use named arguments here since they're different between
|
|
||||||
// Linux/macOS and Windows.
|
|
||||||
float alphaBelow = 1 - (above.A / 255f);
|
|
||||||
sourceData[i] = new Color(
|
|
||||||
(int)(above.R + (below.R * alphaBelow)), // r
|
|
||||||
(int)(above.G + (below.G * alphaBelow)), // g
|
|
||||||
(int)(above.B + (below.B * alphaBelow)), // b
|
|
||||||
Math.Max(above.A, below.A) // a
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// patch target texture
|
|
||||||
target.SetData(0, targetArea, sourceData, 0, pixelCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -110,5 +99,85 @@ namespace StardewModdingAPI.Framework.Content
|
||||||
this.PatchImage(original);
|
this.PatchImage(original);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** Private methods
|
||||||
|
*********/
|
||||||
|
/// <summary>Get the bounds for an image patch.</summary>
|
||||||
|
/// <param name="sourceArea">The source area to set if needed.</param>
|
||||||
|
/// <param name="targetArea">The target area to set if needed.</param>
|
||||||
|
/// <param name="sourceWidth">The width of the full source image.</param>
|
||||||
|
/// <param name="sourceHeight">The height of the full source image.</param>
|
||||||
|
private void GetPatchBounds([NotNull] ref Rectangle? sourceArea, [NotNull] ref Rectangle? targetArea, int sourceWidth, int sourceHeight)
|
||||||
|
{
|
||||||
|
sourceArea ??= new Rectangle(0, 0, sourceWidth, sourceHeight);
|
||||||
|
targetArea ??= new Rectangle(0, 0, Math.Min(sourceArea.Value.Width, this.Data.Width), Math.Min(sourceArea.Value.Height, this.Data.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Overwrite part of the image.</summary>
|
||||||
|
/// <param name="sourceData">The image data to patch into the content.</param>
|
||||||
|
/// <param name="sourceWidth">The pixel width of the source image.</param>
|
||||||
|
/// <param name="sourceHeight">The pixel height of the source image.</param>
|
||||||
|
/// <param name="sourceArea">The part of the <paramref name="sourceData"/> to copy (or <c>null</c> to take the whole texture). This must be within the bounds of the <paramref name="sourceData"/> texture.</param>
|
||||||
|
/// <param name="targetArea">The part of the content to patch (or <c>null</c> to patch the whole texture). The original content within this area will be erased. This must be within the bounds of the existing spritesheet.</param>
|
||||||
|
/// <param name="patchMode">Indicates how an image should be patched.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">One of the arguments is null.</exception>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">The <paramref name="targetArea"/> is outside the bounds of the spritesheet.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">The content being read isn't an image.</exception>
|
||||||
|
private void PatchImageImpl(Color[] sourceData, int sourceWidth, int sourceHeight, Rectangle sourceArea, Rectangle targetArea, PatchMode patchMode)
|
||||||
|
{
|
||||||
|
// get texture
|
||||||
|
Texture2D target = this.Data;
|
||||||
|
int pixelCount = sourceArea.Width * sourceArea.Height;
|
||||||
|
|
||||||
|
// validate
|
||||||
|
if (sourceArea.X < 0 || sourceArea.Y < 0 || sourceArea.Right > sourceWidth || sourceArea.Bottom > sourceHeight)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(sourceArea), "The source area is outside the bounds of the source texture.");
|
||||||
|
if (!target.Bounds.Contains(targetArea))
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(targetArea), "The target area is outside the bounds of the target texture.");
|
||||||
|
if (sourceArea.Size != targetArea.Size)
|
||||||
|
throw new InvalidOperationException("The source and target areas must be the same size.");
|
||||||
|
|
||||||
|
// merge data
|
||||||
|
if (patchMode == PatchMode.Overlay)
|
||||||
|
{
|
||||||
|
// get target data
|
||||||
|
Color[] mergedData = GC.AllocateUninitializedArray<Color>(pixelCount);
|
||||||
|
target.GetData(0, targetArea, mergedData, 0, pixelCount);
|
||||||
|
|
||||||
|
// merge pixels
|
||||||
|
for (int i = 0; i < pixelCount; i++)
|
||||||
|
{
|
||||||
|
Color above = sourceData[i];
|
||||||
|
Color below = mergedData[i];
|
||||||
|
|
||||||
|
// shortcut transparency
|
||||||
|
if (above.A < MinOpacity)
|
||||||
|
continue;
|
||||||
|
if (below.A < MinOpacity)
|
||||||
|
mergedData[i] = 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[i] = 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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
target.SetData(0, targetArea, sourceData, 0, pixelCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI.Framework.Content
|
||||||
|
{
|
||||||
|
/// <summary>The raw data for an image read from the filesystem.</summary>
|
||||||
|
/// <param name="Width">The image width.</param>
|
||||||
|
/// <param name="Height">The image height.</param>
|
||||||
|
/// <param name="Data">The loaded image data.</param>
|
||||||
|
internal record RawTextureData(int Width, int Height, Color[] Data) : IRawTextureData;
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||||
using StardewModdingAPI.Events;
|
using StardewModdingAPI.Events;
|
||||||
using StardewModdingAPI.Framework.Content;
|
using StardewModdingAPI.Framework.Content;
|
||||||
using StardewModdingAPI.Framework.Deprecations;
|
using StardewModdingAPI.Framework.Deprecations;
|
||||||
|
using StardewModdingAPI.Framework.Exceptions;
|
||||||
using StardewModdingAPI.Framework.Reflection;
|
using StardewModdingAPI.Framework.Reflection;
|
||||||
using StardewModdingAPI.Framework.Utilities;
|
using StardewModdingAPI.Framework.Utilities;
|
||||||
using StardewModdingAPI.Internal;
|
using StardewModdingAPI.Internal;
|
||||||
|
@ -93,6 +94,9 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override T LoadExact<T>(IAssetName assetName, bool useCache)
|
public override T LoadExact<T>(IAssetName assetName, bool useCache)
|
||||||
{
|
{
|
||||||
|
if (typeof(IRawTextureData).IsAssignableFrom(typeof(T)))
|
||||||
|
throw new SContentLoadException(ContentLoadErrorType.Other, $"Can't load {nameof(IRawTextureData)} assets from the game content pipeline. This asset type is only available for mod files.");
|
||||||
|
|
||||||
// raise first-load callback
|
// raise first-load callback
|
||||||
if (GameContentManager.IsFirstLoad)
|
if (GameContentManager.IsFirstLoad)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,7 @@ using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Content;
|
using Microsoft.Xna.Framework.Content;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
using StardewModdingAPI.Framework.Content;
|
||||||
using StardewModdingAPI.Framework.Exceptions;
|
using StardewModdingAPI.Framework.Exceptions;
|
||||||
using StardewModdingAPI.Framework.Reflection;
|
using StardewModdingAPI.Framework.Reflection;
|
||||||
using StardewModdingAPI.Toolkit.Serialization;
|
using StardewModdingAPI.Toolkit.Serialization;
|
||||||
|
@ -188,12 +189,17 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
/// <param name="file">The file to load.</param>
|
/// <param name="file">The file to load.</param>
|
||||||
private T LoadImageFile<T>(IAssetName assetName, FileInfo file)
|
private T LoadImageFile<T>(IAssetName assetName, FileInfo file)
|
||||||
{
|
{
|
||||||
// validate
|
// validate type
|
||||||
|
bool asRawData = false;
|
||||||
if (typeof(T) != typeof(Texture2D))
|
if (typeof(T) != typeof(Texture2D))
|
||||||
throw this.GetLoadError(assetName, ContentLoadErrorType.InvalidData, $"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Texture2D)}'.");
|
{
|
||||||
|
asRawData = typeof(T) == typeof(IRawTextureData);
|
||||||
|
if (!asRawData)
|
||||||
|
throw this.GetLoadError(assetName, ContentLoadErrorType.InvalidData, $"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Texture2D)}' or '{typeof(IRawTextureData)}'.");
|
||||||
|
}
|
||||||
|
|
||||||
// load
|
// load
|
||||||
if (this.UseExperimentalImageLoading)
|
if (asRawData || this.UseExperimentalImageLoading)
|
||||||
{
|
{
|
||||||
// load raw data
|
// load raw data
|
||||||
using FileStream stream = File.OpenRead(file.FullName);
|
using FileStream stream = File.OpenRead(file.FullName);
|
||||||
|
@ -211,10 +217,15 @@ namespace StardewModdingAPI.Framework.ContentManagers
|
||||||
}
|
}
|
||||||
|
|
||||||
// create texture
|
// create texture
|
||||||
|
if (asRawData)
|
||||||
|
return (T)(object)new RawTextureData(bitmap.Width, bitmap.Height, pixels);
|
||||||
|
else
|
||||||
|
{
|
||||||
Texture2D texture = new(Game1.graphics.GraphicsDevice, bitmap.Width, bitmap.Height);
|
Texture2D texture = new(Game1.graphics.GraphicsDevice, bitmap.Width, bitmap.Height);
|
||||||
texture.SetData(pixels);
|
texture.SetData(pixels);
|
||||||
return (T)(object)texture;
|
return (T)(object)texture;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using FileStream stream = File.OpenRead(file.FullName);
|
using FileStream stream = File.OpenRead(file.FullName);
|
||||||
|
|
|
@ -10,6 +10,16 @@ namespace StardewModdingAPI
|
||||||
/*********
|
/*********
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
|
/// <summary>Overwrite part of the image.</summary>
|
||||||
|
/// <param name="source">The image to patch into the content.</param>
|
||||||
|
/// <param name="sourceArea">The part of the <paramref name="source"/> to copy (or <c>null</c> to take the whole texture). This must be within the bounds of the <paramref name="source"/> texture.</param>
|
||||||
|
/// <param name="targetArea">The part of the content to patch (or <c>null</c> to patch the whole texture). The original content within this area will be erased. This must be within the bounds of the existing spritesheet.</param>
|
||||||
|
/// <param name="patchMode">Indicates how an image should be patched.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">One of the arguments is null.</exception>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">The <paramref name="targetArea"/> is outside the bounds of the spritesheet.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">The content being read isn't an image.</exception>
|
||||||
|
void PatchImage(IRawTextureData source, Rectangle? sourceArea = null, Rectangle? targetArea = null, PatchMode patchMode = PatchMode.Replace);
|
||||||
|
|
||||||
/// <summary>Overwrite part of the image.</summary>
|
/// <summary>Overwrite part of the image.</summary>
|
||||||
/// <param name="source">The image to patch into the content.</param>
|
/// <param name="source">The image to patch into the content.</param>
|
||||||
/// <param name="sourceArea">The part of the <paramref name="source"/> to copy (or <c>null</c> to take the whole texture). This must be within the bounds of the <paramref name="source"/> texture.</param>
|
/// <param name="sourceArea">The part of the <paramref name="source"/> to copy (or <c>null</c> to take the whole texture). This must be within the bounds of the <paramref name="source"/> texture.</param>
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace StardewModdingAPI
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Load content from the game folder or mod folder (if not already cached), and return it. When loading a <c>.png</c> file, this must be called outside the game's draw loop.</summary>
|
/// <summary>Load content from the game folder or mod folder (if not already cached), and return it. When loading a <c>.png</c> file, this must be called outside the game's draw loop.</summary>
|
||||||
/// <typeparam name="T">The expected data type. The main supported types are <see cref="Map"/>, <see cref="Texture2D"/>, dictionaries, and lists; other types may be supported by the game's content pipeline.</typeparam>
|
/// <typeparam name="T">The expected data type. The main supported types are <see cref="Map"/>, <see cref="Texture2D"/>, <see cref="IRawTextureData"/> (for mod content only), and data structures; other types may be supported by the game's content pipeline.</typeparam>
|
||||||
/// <param name="key">The asset key to fetch (if the <paramref name="source"/> is <see cref="ContentSource.GameContent"/>), or the local path to a content file relative to the mod folder.</param>
|
/// <param name="key">The asset key to fetch (if the <paramref name="source"/> is <see cref="ContentSource.GameContent"/>), or the local path to a content file relative to the mod folder.</param>
|
||||||
/// <param name="source">Where to search for a matching content asset.</param>
|
/// <param name="source">Where to search for a matching content asset.</param>
|
||||||
/// <exception cref="ArgumentException">The <paramref name="key"/> is empty or contains invalid characters.</exception>
|
/// <exception cref="ArgumentException">The <paramref name="key"/> is empty or contains invalid characters.</exception>
|
||||||
|
|
|
@ -48,7 +48,7 @@ namespace StardewModdingAPI
|
||||||
where TModel : class;
|
where TModel : class;
|
||||||
|
|
||||||
/// <summary>Load content from the content pack folder (if not already cached), and return it. When loading a <c>.png</c> file, this must be called outside the game's draw loop.</summary>
|
/// <summary>Load content from the content pack folder (if not already cached), and return it. When loading a <c>.png</c> file, this must be called outside the game's draw loop.</summary>
|
||||||
/// <typeparam name="T">The expected data type. The main supported types are <see cref="Map"/>, <see cref="Texture2D"/>, and dictionaries; other types may be supported by the game's content pipeline.</typeparam>
|
/// <typeparam name="T">The expected data type. The main supported types are <see cref="Map"/>, <see cref="Texture2D"/>, <see cref="IRawTextureData"/>, and data structures; other types may be supported by the game's content pipeline.</typeparam>
|
||||||
/// <param name="key">The relative file path within the content pack (case-insensitive).</param>
|
/// <param name="key">The relative file path within the content pack (case-insensitive).</param>
|
||||||
/// <exception cref="ArgumentException">The <paramref name="key"/> is empty or contains invalid characters.</exception>
|
/// <exception cref="ArgumentException">The <paramref name="key"/> is empty or contains invalid characters.</exception>
|
||||||
/// <exception cref="ContentLoadException">The content asset couldn't be loaded (e.g. because it doesn't exist).</exception>
|
/// <exception cref="ContentLoadException">The content asset couldn't be loaded (e.g. because it doesn't exist).</exception>
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace StardewModdingAPI
|
||||||
** Public methods
|
** Public methods
|
||||||
*********/
|
*********/
|
||||||
/// <summary>Load content from the mod folder and return it. When loading a <c>.png</c> file, this must be called outside the game's draw loop.</summary>
|
/// <summary>Load content from the mod folder and return it. When loading a <c>.png</c> file, this must be called outside the game's draw loop.</summary>
|
||||||
/// <typeparam name="T">The expected data type. The main supported types are <see cref="Map"/>, <see cref="Texture2D"/>, dictionaries, and lists; other types may be supported by the game's content pipeline.</typeparam>
|
/// <typeparam name="T">The expected data type. The main supported types are <see cref="Map"/>, <see cref="Texture2D"/>, <see cref="IRawTextureData"/>, and data structures; other types may be supported by the game's content pipeline.</typeparam>
|
||||||
/// <param name="relativePath">The local path to a content file relative to the mod folder.</param>
|
/// <param name="relativePath">The local path to a content file relative to the mod folder.</param>
|
||||||
/// <exception cref="ArgumentException">The <paramref name="relativePath"/> is empty or contains invalid characters.</exception>
|
/// <exception cref="ArgumentException">The <paramref name="relativePath"/> is empty or contains invalid characters.</exception>
|
||||||
/// <exception cref="ContentLoadException">The content asset couldn't be loaded (e.g. because it doesn't exist).</exception>
|
/// <exception cref="ContentLoadException">The content asset couldn't be loaded (e.g. because it doesn't exist).</exception>
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace StardewModdingAPI
|
||||||
|
{
|
||||||
|
/// <summary>The raw data for an image read from the filesystem.</summary>
|
||||||
|
public interface IRawTextureData
|
||||||
|
{
|
||||||
|
/// <summary>The image width.</summary>
|
||||||
|
int Width { get; }
|
||||||
|
|
||||||
|
/// <summary>The image height.</summary>
|
||||||
|
int Height { get; }
|
||||||
|
|
||||||
|
/// <summary>The loaded image data.</summary>
|
||||||
|
Color[] Data { get; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue