mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-25 22:18:34 +01:00
Compare commits
6 commits
73a02dfe19
...
c5f4fd27bd
Author | SHA1 | Date | |
---|---|---|---|
c5f4fd27bd | |||
44388c0ebd | |||
cdc4756a6a | |||
3fc42143d5 | |||
c4bd03ff04 | |||
a6a34c3937 |
10 changed files with 167 additions and 66 deletions
24
.github/workflows/main.yml
vendored
24
.github/workflows/main.yml
vendored
|
@ -20,32 +20,10 @@ jobs:
|
||||||
uses: android-actions/setup-android@v3
|
uses: android-actions/setup-android@v3
|
||||||
- name: Restore tools
|
- name: Restore tools
|
||||||
run: dotnet tool restore
|
run: dotnet tool restore
|
||||||
- name: Run cake
|
- name: Run Publish
|
||||||
uses: coactions/setup-xvfb@v1
|
uses: coactions/setup-xvfb@v1
|
||||||
with:
|
with:
|
||||||
run: dotnet cake --target Publish --ref ${{ github.ref }} --buildNum ${{ github.run_number }}
|
run: dotnet cake --target Publish --ref ${{ github.ref }} --buildNum ${{ github.run_number }}
|
||||||
env:
|
env:
|
||||||
NUGET_KEY: ${{ secrets.NUGET_KEY }}
|
NUGET_KEY: ${{ secrets.NUGET_KEY }}
|
||||||
BAGET_KEY: ${{ secrets.BAGET_KEY }}
|
BAGET_KEY: ${{ secrets.BAGET_KEY }}
|
||||||
docs:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Clone repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
- name: Setup .NET
|
|
||||||
uses: actions/setup-dotnet@v3
|
|
||||||
with:
|
|
||||||
dotnet-version: '8.0.x'
|
|
||||||
- name: Restore tools
|
|
||||||
run: dotnet tool restore
|
|
||||||
- name: Run cake
|
|
||||||
run: dotnet cake --target Document --ref ${{ github.ref }} --buildNum ${{ github.run_number }}
|
|
||||||
- name: Deploy
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
# this is a beautiful way to deploy a website and i will not take any criticism
|
|
||||||
run: |
|
|
||||||
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb && sudo dpkg -i cloudflared.deb
|
|
||||||
mkdir ~/.ssh && echo "${{ secrets.ELLBOT_KEY }}" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
|
|
||||||
rsync -rv --delete -e 'ssh -o "ProxyCommand cloudflared access ssh --hostname %h" -o "StrictHostKeyChecking=no"' Docs/_site/. ellbot@ssh.ellpeck.de:/var/www/MLEM
|
|
||||||
|
|
78
.github/workflows/web.yml
vendored
Normal file
78
.github/workflows/web.yml
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
on: [push, pull_request]
|
||||||
|
jobs:
|
||||||
|
build-demo:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: Clone repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Setup .NET
|
||||||
|
uses: actions/setup-dotnet@v3
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
- name: Restore tools
|
||||||
|
run: dotnet tool restore
|
||||||
|
- name: Run PublishWeb
|
||||||
|
run: dotnet cake --target PublishWeb --ref ${{ github.ref }} --buildNum ${{ github.run_number }}
|
||||||
|
- name: Upload demo artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: Demos.Web/bin/Release/net8.0/publish/wwwroot
|
||||||
|
name: demo
|
||||||
|
include-hidden-files: true
|
||||||
|
if-no-files-found: error
|
||||||
|
build-docs:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Clone repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Setup .NET
|
||||||
|
uses: actions/setup-dotnet@v3
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
- name: Restore tools
|
||||||
|
run: dotnet tool restore
|
||||||
|
- name: Run Document
|
||||||
|
run: dotnet cake --target Document --ref ${{ github.ref }} --buildNum ${{ github.run_number }}
|
||||||
|
- name: Upload docs artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: Docs/_site
|
||||||
|
name: docs
|
||||||
|
include-hidden-files: true
|
||||||
|
if-no-files-found: error
|
||||||
|
deploy:
|
||||||
|
needs: [build-demo, build-docs]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download demo artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: demo
|
||||||
|
path: demo
|
||||||
|
- name: Download docs artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: docs
|
||||||
|
path: docs
|
||||||
|
- name: Combine sites
|
||||||
|
run: |
|
||||||
|
mv docs _site
|
||||||
|
mv demo _site/demo
|
||||||
|
- name: Upload combined artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: _site
|
||||||
|
name: site
|
||||||
|
include-hidden-files: true
|
||||||
|
if-no-files-found: error
|
||||||
|
- name: Deploy
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
# this is a beautiful way to deploy a website and i will not take any criticism
|
||||||
|
run: |
|
||||||
|
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb && sudo dpkg -i cloudflared.deb
|
||||||
|
mkdir ~/.ssh && echo "${{ secrets.ELLBOT_KEY }}" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
|
||||||
|
rsync -rv --delete -e 'ssh -o "ProxyCommand cloudflared access ssh --hostname %h" -o "StrictHostKeyChecking=no"' _site/. ellbot@ssh.ellpeck.de:/var/www/MLEM
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -2,7 +2,8 @@
|
||||||
MLEM tries to adhere to [semantic versioning](https://semver.org/). Potentially breaking changes are written in **bold**.
|
MLEM tries to adhere to [semantic versioning](https://semver.org/). Potentially breaking changes are written in **bold**.
|
||||||
|
|
||||||
Jump to version:
|
Jump to version:
|
||||||
- [7.1.1](#711-in-development)
|
- [7.1.2](#712-in-development)
|
||||||
|
- [7.1.1](#711)
|
||||||
- [7.1.0](#710)
|
- [7.1.0](#710)
|
||||||
- [7.0.0](#700)
|
- [7.0.0](#700)
|
||||||
- [6.3.1](#631)
|
- [6.3.1](#631)
|
||||||
|
@ -15,10 +16,21 @@ Jump to version:
|
||||||
- [5.1.0](#510)
|
- [5.1.0](#510)
|
||||||
- [5.0.0](#500)
|
- [5.0.0](#500)
|
||||||
|
|
||||||
## 7.1.1 (In Development)
|
## 7.1.2 (In Development)
|
||||||
|
|
||||||
No code changes
|
No code changes
|
||||||
|
|
||||||
|
## 7.1.1
|
||||||
|
|
||||||
|
### MLEM
|
||||||
|
Additions
|
||||||
|
- Added TextureExtensions.PremultipliedCopy for textures
|
||||||
|
|
||||||
|
### MLEM.Ui
|
||||||
|
Improvements
|
||||||
|
- Construct images in UiParser.ParseImage on the main thread to support usage with KNI
|
||||||
|
- Create a premultiplied copy of UiParser images to support usage with KNI
|
||||||
|
|
||||||
## 7.1.0
|
## 7.1.0
|
||||||
|
|
||||||
### MLEM
|
### MLEM
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
"**/MLEM**.csproj"
|
"**/MLEM**.csproj"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"**.FNA.**"
|
"**.FNA.**",
|
||||||
|
"**.KNI.**"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -6,3 +6,5 @@
|
||||||
href: api/
|
href: api/
|
||||||
- name: Changelog
|
- name: Changelog
|
||||||
href: ../CHANGELOG.md
|
href: ../CHANGELOG.md
|
||||||
|
- name: Web Demo
|
||||||
|
href: demo/
|
||||||
|
|
|
@ -17,18 +17,8 @@ namespace MLEM.Data.Content {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// premultiply the texture's color to be in line with the pipeline's texture reader
|
// premultiply the texture's color to be in line with the pipeline's texture reader
|
||||||
using (var texture = Texture2D.FromStream(manager.GraphicsDevice, stream)) {
|
using (var texture = Texture2D.FromStream(manager.GraphicsDevice, stream))
|
||||||
var ret = new Texture2D(manager.GraphicsDevice, texture.Width, texture.Height);
|
return texture.PremultipliedCopy();
|
||||||
using (var textureData = texture.GetTextureData()) {
|
|
||||||
using (var retData = ret.GetTextureData()) {
|
|
||||||
for (var x = 0; x < ret.Width; x++) {
|
|
||||||
for (var y = 0; y < ret.Height; y++)
|
|
||||||
retData[x, y] = Color.FromNonPremultiplied(textureData[x, y].ToVector4());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
@ -10,7 +10,6 @@ using MLEM.Ui.Style;
|
||||||
|
|
||||||
#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER
|
#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
using System.Net;
|
using System.Net;
|
||||||
#endif
|
#endif
|
||||||
|
@ -139,43 +138,61 @@ namespace MLEM.Ui.Parsers {
|
||||||
/// This method invokes an asynchronouns action, meaning the <see cref="Image"/>'s <see cref="Image.Texture"/> will likely not have loaded in when this method returns.
|
/// This method invokes an asynchronouns action, meaning the <see cref="Image"/>'s <see cref="Image.Texture"/> will likely not have loaded in when this method returns.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The absolute, relative or web path to the image.</param>
|
/// <param name="path">The absolute, relative or web path to the image.</param>
|
||||||
/// <param name="onImageFetched">An action that is invoked with the loaded image once it is fetched. Note that this action will be invoked asynchronously.</param>
|
/// <param name="onImageFetched">An action that is invoked with the loaded image once it is fetched. Note that this action will be invoked synchronously.</param>
|
||||||
/// <returns>The loaded image.</returns>
|
/// <returns>The loaded image.</returns>
|
||||||
/// <exception cref="NullReferenceException">Thrown if <see cref="GraphicsDevice"/> is null, or if there is an <see cref="Exception"/> loading the image and <see cref="ImageExceptionHandler"/> is unset.</exception>
|
/// <exception cref="NullReferenceException">Thrown if <see cref="GraphicsDevice"/> is null, or if there is an <see cref="Exception"/> loading the image and <see cref="ImageExceptionHandler"/> is unset.</exception>
|
||||||
protected Image ParseImage(string path, Action<TextureRegion> onImageFetched = null) {
|
protected Image ParseImage(string path, Action<TextureRegion> onImageFetched = null) {
|
||||||
if (this.GraphicsDevice == null)
|
if (this.GraphicsDevice == null)
|
||||||
throw new NullReferenceException("A UI parser requires a GraphicsDevice for parsing images");
|
throw new NullReferenceException("A UI parser requires a GraphicsDevice for parsing images");
|
||||||
|
|
||||||
var imageLock = new object();
|
var bytesLock = new object();
|
||||||
|
byte[] bytes = null;
|
||||||
TextureRegion image = null;
|
TextureRegion image = null;
|
||||||
return new Image(Anchor.AutoLeft, Vector2.One, _ => {
|
return new Image(Anchor.AutoLeft, Vector2.One, _ => {
|
||||||
lock (imageLock)
|
if (image == null) {
|
||||||
|
bool bytesNull;
|
||||||
|
lock (bytesLock)
|
||||||
|
bytesNull = bytes == null;
|
||||||
|
if (!bytesNull) {
|
||||||
|
Texture2D tex;
|
||||||
|
lock (bytesLock) {
|
||||||
|
using (var stream = new MemoryStream(bytes)) {
|
||||||
|
using (var read = Texture2D.FromStream(this.GraphicsDevice, stream))
|
||||||
|
tex = read.PremultipliedCopy();
|
||||||
|
}
|
||||||
|
bytes = null;
|
||||||
|
}
|
||||||
|
image = new TextureRegion(tex);
|
||||||
|
onImageFetched?.Invoke(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
return image;
|
return image;
|
||||||
}) {
|
}) {
|
||||||
SetHeightBasedOnAspect = true,
|
SetHeightBasedOnAspect = true,
|
||||||
OnAddedToUi = e => {
|
OnAddedToUi = e => {
|
||||||
bool imageNull;
|
if (image == null) {
|
||||||
lock (imageLock)
|
bool bytesNull;
|
||||||
imageNull = image == null;
|
lock (bytesLock)
|
||||||
if (imageNull)
|
bytesNull = bytes == null;
|
||||||
LoadImageAsync();
|
if (bytesNull)
|
||||||
|
LoadImageStream();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
OnRemovedFromUi = e => {
|
OnRemovedFromUi = e => {
|
||||||
lock (imageLock) {
|
lock (bytesLock)
|
||||||
|
bytes = null;
|
||||||
image?.Texture.Dispose();
|
image?.Texture.Dispose();
|
||||||
image = null;
|
image = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
async void LoadImageAsync() {
|
async void LoadImageStream() {
|
||||||
// only apply the base path for relative files
|
// only apply the base path for relative files
|
||||||
if (this.ImageBasePath != null && !path.StartsWith("http") && !Path.IsPathRooted(path))
|
if (this.ImageBasePath != null && !path.StartsWith("http") && !Path.IsPathRooted(path))
|
||||||
path = $"{this.ImageBasePath}/{path}";
|
path = $"{this.ImageBasePath}/{path}";
|
||||||
try {
|
try {
|
||||||
Texture2D tex;
|
|
||||||
if (path.StartsWith("http")) {
|
|
||||||
byte[] src;
|
byte[] src;
|
||||||
|
if (path.StartsWith("http")) {
|
||||||
#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER
|
#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER
|
||||||
using (var client = new HttpClient())
|
using (var client = new HttpClient())
|
||||||
src = await client.GetByteArrayAsync(path);
|
src = await client.GetByteArrayAsync(path);
|
||||||
|
@ -183,18 +200,16 @@ namespace MLEM.Ui.Parsers {
|
||||||
using (var client = new WebClient())
|
using (var client = new WebClient())
|
||||||
src = await client.DownloadDataTaskAsync(path);
|
src = await client.DownloadDataTaskAsync(path);
|
||||||
#endif
|
#endif
|
||||||
using (var memory = new MemoryStream(src))
|
|
||||||
tex = Texture2D.FromStream(this.GraphicsDevice, memory);
|
|
||||||
} else {
|
} else {
|
||||||
using (var stream = Path.IsPathRooted(path) ? File.OpenRead(path) : TitleContainer.OpenStream(path))
|
using (var fileStream = Path.IsPathRooted(path) ? File.OpenRead(path) : TitleContainer.OpenStream(path)) {
|
||||||
tex = Texture2D.FromStream(this.GraphicsDevice, stream);
|
using (var memStream = new MemoryStream()) {
|
||||||
}
|
await fileStream.CopyToAsync(memStream);
|
||||||
lock (imageLock) {
|
src = memStream.ToArray();
|
||||||
if (image == null) {
|
|
||||||
image = new TextureRegion(tex);
|
|
||||||
onImageFetched?.Invoke(image);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
lock (bytesLock)
|
||||||
|
bytes = src;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (this.ImageExceptionHandler != null) {
|
if (this.ImageExceptionHandler != null) {
|
||||||
this.ImageExceptionHandler.Invoke(path, e);
|
this.ImageExceptionHandler.Invoke(path, e);
|
||||||
|
|
|
@ -18,6 +18,24 @@ namespace MLEM.Textures {
|
||||||
return new TextureData(texture);
|
return new TextureData(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates and returns a copy of the given <paramref name="texture"/> with all colors converted to premultiplied alpha, which is the format that MonoGame's content pipeline loads textures in. This method uses <see cref="Color.FromNonPremultiplied(Microsoft.Xna.Framework.Vector4)"/> for all pixels in the <paramref name="texture"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="texture">The texture of which to create a premultiplied copy.</param>
|
||||||
|
/// <returns>The premultiplied copy of the <paramref name="texture"/>.</returns>
|
||||||
|
public static Texture2D PremultipliedCopy(this Texture2D texture) {
|
||||||
|
var ret = new Texture2D(texture.GraphicsDevice, texture.Width, texture.Height);
|
||||||
|
using (var textureData = texture.GetTextureData()) {
|
||||||
|
using (var retData = ret.GetTextureData()) {
|
||||||
|
for (var x = 0; x < ret.Width; x++) {
|
||||||
|
for (var y = 0; y < ret.Height; y++)
|
||||||
|
retData[x, y] = Color.FromNonPremultiplied(textureData[x, y].ToVector4());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A struct that represents the data of a texture, accessed through <see cref="TextureExtensions.GetTextureData"/>.
|
/// A struct that represents the data of a texture, accessed through <see cref="TextureExtensions.GetTextureData"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -9,7 +9,7 @@ MLEM is platform-agnostic and multi-targets .NET Standard 2.0, .NET 8.0 and .NET
|
||||||
- Get prerelease builds on [BaGet](https://nuget.ellpeck.de/?q=mlem)
|
- Get prerelease builds on [BaGet](https://nuget.ellpeck.de/?q=mlem)
|
||||||
- See the source code on [GitHub](https://github.com/Ellpeck/MLEM)
|
- See the source code on [GitHub](https://github.com/Ellpeck/MLEM)
|
||||||
- See tutorials and API documentation on [the website](https://mlem.ellpeck.de/)
|
- See tutorials and API documentation on [the website](https://mlem.ellpeck.de/)
|
||||||
- Check out [the demos](https://github.com/Ellpeck/MLEM/tree/main/Demos) on [Desktop](https://github.com/Ellpeck/MLEM/tree/main/Demos.DesktopGL) or [Android](https://github.com/Ellpeck/MLEM/tree/main/Demos.Android)
|
- Check out [the demos](https://github.com/Ellpeck/MLEM/tree/main/Demos) on [Desktop](https://github.com/Ellpeck/MLEM/tree/main/Demos.DesktopGL), [Android](https://github.com/Ellpeck/MLEM/tree/main/Demos.Android) or [Web](https://mlem.ellpeck.de/demo)
|
||||||
- See [the changelog](https://mlem.ellpeck.de/CHANGELOG.html) for information on updates
|
- See [the changelog](https://mlem.ellpeck.de/CHANGELOG.html) for information on updates
|
||||||
- Join [the Discord server](https://link.ellpeck.de/discordweb) to ask questions
|
- Join [the Discord server](https://link.ellpeck.de/discordweb) to ask questions
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#tool dotnet:?package=docfx&version=2.75.3
|
#tool dotnet:?package=docfx&version=2.75.3
|
||||||
|
|
||||||
// this is the upcoming version, for prereleases
|
// this is the upcoming version, for prereleases
|
||||||
var version = Argument("version", "7.1.1");
|
var version = Argument("version", "7.1.2");
|
||||||
var target = Argument("target", "Default");
|
var target = Argument("target", "Default");
|
||||||
var gitRef = Argument("ref", "refs/heads/main");
|
var gitRef = Argument("ref", "refs/heads/main");
|
||||||
var buildNum = Argument("buildNum", "");
|
var buildNum = Argument("buildNum", "");
|
||||||
|
@ -83,6 +83,13 @@ Task("Document").Does(() => {
|
||||||
DocFxServe("Docs/_site");
|
DocFxServe("Docs/_site");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Task("PublishWeb").Does(() => {
|
||||||
|
DotNetPublish("Demos.Web/Demos.Web.KNI.csproj", new DotNetPublishSettings {
|
||||||
|
Configuration = config,
|
||||||
|
ArgumentCustomization = args => args.Append($"/p:Version={version}")
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Task("Default").IsDependentOn("Pack");
|
Task("Default").IsDependentOn("Pack");
|
||||||
Task("Publish").IsDependentOn("Push");
|
Task("Publish").IsDependentOn("Push");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue