Skip to content

Commit 1688d2c

Browse files
committed
Type Resonite texture payload variants
1 parent c601f6e commit 1688d2c

15 files changed

Lines changed: 153 additions & 88 deletions

src/PlateauResoniteLink/Application/Importing/SceneImportContractTypes.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,16 @@ public EncodedImageTexturePayload(
185185
string? colorProfile,
186186
ITextureImportSource source,
187187
string? identity = null)
188-
: base(colorProfile, identity ?? source?.Identity ?? throw new ArgumentNullException(nameof(source)), source!)
188+
: this(width, height, colorProfile, CreateSource(source, identity))
189+
{
190+
}
191+
192+
private EncodedImageTexturePayload(
193+
int? width,
194+
int? height,
195+
string? colorProfile,
196+
(string Identity, ITextureImportSource Source) source)
197+
: base(colorProfile, source.Identity, source.Source)
189198
{
190199
Width = width;
191200
Height = height;
@@ -194,6 +203,14 @@ public EncodedImageTexturePayload(
194203
public int? Width { get; }
195204

196205
public int? Height { get; }
206+
207+
private static (string Identity, ITextureImportSource Source) CreateSource(
208+
ITextureImportSource source,
209+
string? identity)
210+
{
211+
ArgumentNullException.ThrowIfNull(source);
212+
return (identity ?? source.Identity, source);
213+
}
197214
}
198215

199216
public enum TextureSourceKind

src/PlateauResoniteLink/Targets/Resonite/ResoniteTextureImportFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public static ResoniteTexturePayload CreatePayloadFromImage(
3434
RawTexturePayload rawPayload = TextureImportSourceFactory.CreateRawPayloadFromImage(
3535
image,
3636
colorProfile);
37-
return new ResoniteTexturePayload(
37+
return new RawRgba32ResoniteTexturePayload(
3838
image.Width,
3939
image.Height,
4040
colorProfile,

src/PlateauResoniteLink/Targets/Resonite/ResoniteTexturePayload.cs

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,64 +5,119 @@
55

66
namespace PlateauResoniteLink.Targets.Resonite;
77

8-
public enum ResoniteTexturePayloadFormat
8+
public abstract class ResoniteTexturePayload
99
{
10-
RawRgba32,
11-
EncodedImage,
10+
private protected ResoniteTexturePayload(
11+
string? colorProfile,
12+
string identity,
13+
ITextureImportSource source)
14+
{
15+
if (string.IsNullOrWhiteSpace(identity))
16+
{
17+
throw new ArgumentException("Resonite texture payload identity must be provided.", nameof(identity));
18+
}
19+
20+
ColorProfile = colorProfile;
21+
Identity = identity;
22+
Source = source ?? throw new ArgumentNullException(nameof(source));
23+
}
24+
25+
public string? ColorProfile { get; }
26+
27+
public string Identity { get; }
28+
29+
public ITextureImportSource Source { get; }
1230
}
1331

14-
public sealed record ResoniteTexturePayload
32+
public sealed class RawRgba32ResoniteTexturePayload : ResoniteTexturePayload
1533
{
16-
public ResoniteTexturePayload(
34+
public RawRgba32ResoniteTexturePayload(
1735
int width,
1836
int height,
1937
string? colorProfile,
2038
byte[] binaryPayload,
2139
string? identity = null)
22-
{
23-
Width = width;
24-
Height = height;
25-
ColorProfile = colorProfile;
26-
ArgumentNullException.ThrowIfNull(binaryPayload);
27-
BinaryPayload = ImmutableArray.CreateRange(binaryPayload);
28-
Identity = identity;
29-
Format = ResoniteTexturePayloadFormat.RawRgba32;
30-
Source = TextureImportSourceFactory.CreateInMemoryRaw(
40+
: this(
3141
width,
3242
height,
3343
colorProfile,
3444
binaryPayload,
35-
identity ?? Guid.NewGuid().ToString("N"));
45+
CreateSource(width, height, colorProfile, binaryPayload, identity))
46+
{
47+
}
48+
49+
private RawRgba32ResoniteTexturePayload(
50+
int width,
51+
int height,
52+
string? colorProfile,
53+
byte[] binaryPayload,
54+
(string Identity, ITextureImportSource Source) source)
55+
: base(colorProfile, source.Identity, source.Source)
56+
{
57+
ArgumentNullException.ThrowIfNull(binaryPayload);
58+
Width = width;
59+
Height = height;
60+
BinaryPayload = ImmutableArray.CreateRange(binaryPayload);
3661
}
3762

38-
public ResoniteTexturePayload(
63+
public int Width { get; }
64+
65+
public int Height { get; }
66+
67+
public ImmutableArray<byte> BinaryPayload { get; }
68+
69+
private static (string Identity, ITextureImportSource Source) CreateSource(
70+
int width,
71+
int height,
72+
string? colorProfile,
73+
byte[] binaryPayload,
74+
string? identity)
75+
{
76+
ArgumentNullException.ThrowIfNull(binaryPayload);
77+
string effectiveIdentity = identity ?? Guid.NewGuid().ToString("N");
78+
return (
79+
effectiveIdentity,
80+
TextureImportSourceFactory.CreateInMemoryRaw(
81+
width,
82+
height,
83+
colorProfile,
84+
binaryPayload,
85+
effectiveIdentity));
86+
}
87+
}
88+
89+
public sealed class EncodedImageResoniteTexturePayload : ResoniteTexturePayload
90+
{
91+
public EncodedImageResoniteTexturePayload(
3992
int? width,
4093
int? height,
4194
string? colorProfile,
4295
ITextureImportSource source,
4396
string? identity = null)
97+
: this(width, height, colorProfile, CreateSource(source, identity))
98+
{
99+
}
100+
101+
private EncodedImageResoniteTexturePayload(
102+
int? width,
103+
int? height,
104+
string? colorProfile,
105+
(string Identity, ITextureImportSource Source) source)
106+
: base(colorProfile, source.Identity, source.Source)
44107
{
45108
Width = width;
46109
Height = height;
47-
ColorProfile = colorProfile;
48-
ArgumentNullException.ThrowIfNull(source);
49-
BinaryPayload = [];
50-
Identity = identity ?? source.Identity;
51-
Format = ResoniteTexturePayloadFormat.EncodedImage;
52-
Source = source;
53110
}
54111

55112
public int? Width { get; }
56113

57114
public int? Height { get; }
58115

59-
public string? ColorProfile { get; }
60-
61-
public ImmutableArray<byte> BinaryPayload { get; }
62-
63-
public string? Identity { get; }
64-
65-
public ResoniteTexturePayloadFormat Format { get; }
66-
67-
public ITextureImportSource Source { get; }
116+
private static (string Identity, ITextureImportSource Source) CreateSource(
117+
ITextureImportSource source,
118+
string? identity)
119+
{
120+
ArgumentNullException.ThrowIfNull(source);
121+
return (identity ?? source.Identity, source);
122+
}
68123
}

src/PlateauResoniteLink/Targets/Resonite/SceneImportContractMapper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,13 @@ private static ResoniteTexturePayload ToInternal(TexturePayload payload)
141141
{
142142
return payload switch
143143
{
144-
RawRgba32TexturePayload raw => new ResoniteTexturePayload(
144+
RawRgba32TexturePayload raw => new RawRgba32ResoniteTexturePayload(
145145
raw.Width,
146146
raw.Height,
147147
raw.ColorProfile,
148148
raw.BinaryPayload.AsSpan().ToArray(),
149149
raw.Identity),
150-
EncodedImageTexturePayload encoded => new ResoniteTexturePayload(
150+
EncodedImageTexturePayload encoded => new EncodedImageResoniteTexturePayload(
151151
encoded.Width,
152152
encoded.Height,
153153
encoded.ColorProfile,

tests/PlateauResoniteLink.Tests/Targets/NonDemCityObjectBakeMaterialClassifierTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ private static ResoniteMaterialBinding CreateDatasetTextureMaterial()
102102
{
103103
return CreateTexturelessMaterial() with
104104
{
105-
TexturePayload = new ResoniteTexturePayload(
105+
TexturePayload = new RawRgba32ResoniteTexturePayload(
106106
width: 1,
107107
height: 1,
108108
colorProfile: null,

tests/PlateauResoniteLink.Tests/Targets/NonDemCityObjectBakerTests.cs

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,9 @@ public async Task FlushAllAsyncBakesSingleSourceUnitIntoSingleMaterialAndSubmesh
2929
Assert.Single(cityObject.Mesh.Submeshes);
3030
Assert.Equal(6, cityObject.Mesh.Vertices.Count);
3131
Assert.Equal("unit-a.gml", cityObject.SourceFileRelativePath);
32-
ResoniteTexturePayload atlasPayload = Assert.IsType<ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
33-
Assert.Equal(ResoniteTexturePayloadFormat.RawRgba32, atlasPayload.Format);
34-
Assert.NotNull(atlasPayload.Width);
35-
Assert.NotNull(atlasPayload.Height);
36-
Assert.InRange(atlasPayload.Width!.Value, 1, 32);
37-
Assert.InRange(atlasPayload.Height!.Value, 1, 32);
32+
RawRgba32ResoniteTexturePayload atlasPayload = Assert.IsType<RawRgba32ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
33+
Assert.InRange(atlasPayload.Width, 1, 32);
34+
Assert.InRange(atlasPayload.Height, 1, 32);
3835
Assert.Equal(CommonMaterialCatalog.Create().Generic.Uv, cityObject.Materials[0].CommonMaterial);
3936
}
4037

@@ -63,8 +60,7 @@ await AssertBufferedAsync(baker, CreateUvScaledLod2Building(
6360
new ResoniteFloat2(0.5, 0.0)));
6461

6562
ResoniteConstructionCityObject cityObject = Assert.Single(await baker.FlushAllAsync());
66-
ResoniteTexturePayload atlasPayload = Assert.IsType<ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
67-
Assert.Equal(ResoniteTexturePayloadFormat.RawRgba32, atlasPayload.Format);
63+
RawRgba32ResoniteTexturePayload atlasPayload = Assert.IsType<RawRgba32ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
6864
Assert.Equal(1, atlasPayload.Width);
6965
Assert.Equal(1, atlasPayload.Height);
7066
Assert.Null(cityObject.Materials[0].TextureScale);
@@ -152,7 +148,7 @@ await AssertBufferedAsync(
152148
Assert.NotSame(payload, material.TexturePayload);
153149
Assert.NotNull(material.TexturePayload);
154150
Assert.Contains("atlastex-", material.TexturePayload.Identity, StringComparison.Ordinal);
155-
Assert.Equal(ResoniteTexturePayloadFormat.RawRgba32, material.TexturePayload.Format);
151+
Assert.IsType<RawRgba32ResoniteTexturePayload>(material.TexturePayload);
156152
Assert.Null(material.TextureScale);
157153
Assert.Null(material.TextureOffset);
158154
}
@@ -212,7 +208,7 @@ await AssertBufferedAsync(baker, CreateUvScaledLod2Building(
212208
new ResoniteFloat2(0.0, 0.0)));
213209

214210
ResoniteConstructionCityObject cityObject = Assert.Single(await baker.FlushAllAsync());
215-
ResoniteTexturePayload atlasPayload = Assert.IsType<ResoniteTexturePayload>(Assert.Single(cityObject.Materials).TexturePayload);
211+
RawRgba32ResoniteTexturePayload atlasPayload = Assert.IsType<RawRgba32ResoniteTexturePayload>(Assert.Single(cityObject.Materials).TexturePayload);
216212

217213
Assert.Equal(2, atlasPayload.Width);
218214
Assert.Equal(1, atlasPayload.Height);
@@ -261,8 +257,7 @@ await AssertBufferedAsync(baker, CreateUvScaledLod2Building(
261257
null));
262258

263259
ResoniteConstructionCityObject cityObject = Assert.Single(await baker.FlushAllAsync());
264-
ResoniteTexturePayload atlasPayload = Assert.IsType<ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
265-
Assert.Equal(ResoniteTexturePayloadFormat.RawRgba32, atlasPayload.Format);
260+
RawRgba32ResoniteTexturePayload atlasPayload = Assert.IsType<RawRgba32ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
266261
Assert.Equal(4, atlasPayload.Width);
267262
Assert.Equal(1, atlasPayload.Height);
268263
Assert.Equal(new Rgba32(255, 0, 0, 255), ReadPixel(atlasPayload, 0, 0));
@@ -285,7 +280,7 @@ await AssertBufferedAsync(baker, CreateUvScaledLod2Building(
285280

286281
ResoniteConstructionCityObject cityObject = Assert.Single(await baker.FlushAllAsync());
287282
ResoniteMaterialBinding material = Assert.Single(cityObject.Materials);
288-
ResoniteTexturePayload atlasPayload = Assert.IsType<ResoniteTexturePayload>(material.TexturePayload);
283+
RawRgba32ResoniteTexturePayload atlasPayload = Assert.IsType<RawRgba32ResoniteTexturePayload>(material.TexturePayload);
289284

290285
Assert.Null(material.TextureScale);
291286
Assert.Null(material.TextureOffset);
@@ -325,7 +320,7 @@ await AssertBufferedAsync(
325320
"unit-a"));
326321

327322
ResoniteConstructionCityObject cityObject = Assert.Single(await baker.FlushAllAsync());
328-
ResoniteTexturePayload atlasPayload = Assert.IsType<ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
323+
RawRgba32ResoniteTexturePayload atlasPayload = Assert.IsType<RawRgba32ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
329324

330325
Assert.Equal(2, atlasPayload.Width);
331326
Assert.Equal(1, atlasPayload.Height);
@@ -778,7 +773,7 @@ public async Task FlushAllAsyncPacksMixedSizeTexturesIntoSingleAtlasBatch()
778773
await AssertBufferedAsync(baker, CreateLod2Building("building-c", CreateCheckerPayload("textures/c.png", new Rgba32(0, 0, 255, 255), new Rgba32(255, 0, 255, 255), 3, 3), 4, "unit-a"));
779774

780775
ResoniteConstructionCityObject cityObject = Assert.Single(await baker.FlushAllAsync());
781-
ResoniteTexturePayload atlasPayload = Assert.IsType<ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
776+
RawRgba32ResoniteTexturePayload atlasPayload = Assert.IsType<RawRgba32ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
782777
Assert.Equal(16, atlasPayload.Width);
783778
Assert.Equal(8, atlasPayload.Height);
784779
}
@@ -968,7 +963,7 @@ await AssertBufferedAsync(
968963
"unit-a"));
969964

970965
ResoniteConstructionCityObject cityObject = Assert.Single(await baker.FlushAllAsync());
971-
ResoniteTexturePayload atlasPayload = Assert.IsType<ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
966+
RawRgba32ResoniteTexturePayload atlasPayload = Assert.IsType<RawRgba32ResoniteTexturePayload>(cityObject.Materials[0].TexturePayload);
972967
Assert.Equal(512, atlasPayload.Width);
973968
Assert.Equal(512, atlasPayload.Height);
974969
}
@@ -1061,7 +1056,7 @@ await AssertBufferedAsync(
10611056
Assert.Equal("atlasbake-unit-a-bldg-lod2-3", cityObject.SlotKey);
10621057
Assert.Equal(
10631058
"atlastex-unit-a.gml-3",
1064-
Assert.IsType<ResoniteTexturePayload>(Assert.Single(cityObject.Materials).TexturePayload).Identity);
1059+
Assert.IsType<RawRgba32ResoniteTexturePayload>(Assert.Single(cityObject.Materials).TexturePayload).Identity);
10651060
}
10661061

10671062
private static NonDemCityObjectBaker CreateBaker(
@@ -1146,11 +1141,9 @@ private static ResoniteTexturePayload CreateVerticalSplitPayload(string identity
11461141
return ResoniteTextureImportFactory.CreatePayloadFromImage(image, identity: identity);
11471142
}
11481143

1149-
private static Rgba32 ReadPixel(ResoniteTexturePayload payload, int x, int y)
1144+
private static Rgba32 ReadPixel(RawRgba32ResoniteTexturePayload payload, int x, int y)
11501145
{
1151-
Assert.Equal(ResoniteTexturePayloadFormat.RawRgba32, payload.Format);
1152-
Assert.NotNull(payload.Width);
1153-
int width = payload.Width.Value;
1146+
int width = payload.Width;
11541147
int offset = ((y * width) + x) * 4;
11551148
ReadOnlySpan<byte> bytes = payload.BinaryPayload.AsSpan();
11561149
return new Rgba32(

tests/PlateauResoniteLink.Tests/Targets/NonDemPreservedMaterialGroupingTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public void CreateKeyIgnoresCommonMaterialTintButKeepsTextureReference()
1212
{
1313
AssetBinding = ResoniteMaterialAssetBindingTestFactory.SharedGenericUv(),
1414
};
15-
ResoniteTexturePayload texture = new(
15+
ResoniteTexturePayload texture = new RawRgba32ResoniteTexturePayload(
1616
width: 1,
1717
height: 1,
1818
colorProfile: null,
@@ -31,7 +31,7 @@ public void CreateKeyIgnoresCommonMaterialTintButKeepsTextureReference()
3131
});
3232
NonDemPreservedMaterialGroupingKey differentTexture = NonDemPreservedMaterialGrouping.CreateKey(commonMaterial with
3333
{
34-
TexturePayload = new ResoniteTexturePayload(
34+
TexturePayload = new RawRgba32ResoniteTexturePayload(
3535
width: 1,
3636
height: 1,
3737
colorProfile: null,

tests/PlateauResoniteLink.Tests/Targets/ResoniteDynamicMaterialUvNormalizerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ private static ResoniteMaterialBinding CreateDynamicUvMaterial(
289289
return new ResoniteMaterialBinding(
290290
BaseColor: new ResoniteColor(1.0, 1.0, 1.0, 1.0),
291291
MaterialType: ResoniteMaterialType.Standard,
292-
TexturePayload: new ResoniteTexturePayload(1, 1, "srgb", [255, 255, 255, 255], "textures/dynamic-uv.png"),
292+
TexturePayload: new RawRgba32ResoniteTexturePayload(1, 1, "srgb", [255, 255, 255, 255], "textures/dynamic-uv.png"),
293293
TextureSourceKind: ResoniteTextureSourceKind.Dataset,
294294
Projection: ResoniteMaterialProjection.Uv,
295295
DepthOffset: null,

0 commit comments

Comments
 (0)