Files
ReFuel.Gltf/ReFuel.Gltf/GltfMaterial.cs
T
2025-10-12 14:33:16 +03:00

314 lines
10 KiB
C#

using System;
using System.Drawing;
using System.Numerics;
using System.Text.Json;
namespace ReFuel.Gltf
{
public enum GltfMaterialAlphaMode
{
Opaque,
Mask,
Blend,
Other
}
public class GltfMaterialTextureInfo : GtlfMiscObject
{
private GltfSmartId<GltfTexture> _texture;
public GltfTexture? Texture
{
get => _texture.IsSet ? _texture.Value : null;
set
{
if (value is null)
_texture.Reset();
else
_texture.Value = value;
}
}
public int TexCoordIndex { get; set; } = 0;
internal GltfMaterialTextureInfo(GltfDocument document) : base (document)
{
_texture = new GltfSmartId<GltfTexture>(document.Textures);
}
public GltfMaterialTextureInfo(GltfDocument document, GltfTexture? texture, int texCoordIndex) : this(document)
{
Texture = texture;
TexCoordIndex = texCoordIndex;
}
internal override void Deserialize(JsonElement element)
{
if (element.ValueKind != JsonValueKind.Object)
throw new Exception("Expected an object.");
if (element.TryGetProperty("index", out JsonElement indexProp))
{
_texture.Id = indexProp.GetInt32();
}
if (element.TryGetProperty("texCoord", out JsonElement texCoordProp))
{
TexCoordIndex = texCoordProp.GetInt32();
}
DeserializeCommon(element);
}
internal override void Serialize(Utf8JsonWriter writer)
{
throw new NotImplementedException();
}
}
public class GltfMetallicRoughness : GtlfMiscObject
{
public Vector4 BaseColorFactor { get; set; } = new Vector4(1,1,1,1);
public GltfMaterialTextureInfo? BaseColorTexture { get; set; } = null;
public float Metallic { get; set; } = 1;
public float Roughness { get; set; } = 1;
public GltfMaterialTextureInfo? MetallicRoughnessTexture { get; set; } = null;
internal GltfMetallicRoughness(GltfDocument document) : base(document)
{
}
internal override void Deserialize(JsonElement element)
{
if (element.ValueKind != JsonValueKind.Object)
throw new Exception("Expected an object.");
JsonElement child;
if (element.TryGetProperty("baseColorFactor", out child))
{
if (child.ValueKind != JsonValueKind.Array)
{
throw new Exception("Expected a value array.");
}
Vector4 color = Vector4.One;
int i = 0;
foreach (JsonElement item in child.EnumerateArray())
{
float value = item.GetSingle();
switch (i++)
{
case 0: color.X = value; break;
case 1: color.Y = value; break;
case 2: color.Z = value; break;
case 3: color.W = value; break;
default:
goto break_for;
}
continue;
break_for:
break;
}
BaseColorFactor = color;
}
if (element.TryGetProperty("baseColorTexture", out child))
{
BaseColorTexture = new GltfMaterialTextureInfo(Document);
BaseColorTexture.Deserialize(child);
}
if (element.TryGetProperty("metallicFactor", out child))
{
Metallic = child.GetSingle();
}
if (element.TryGetProperty("roughnessFactor", out child))
{
Roughness = child.GetSingle();
}
if (element.TryGetProperty("metallicRoughnessTexture", out child))
{
MetallicRoughnessTexture = new GltfMaterialTextureInfo(Document);
MetallicRoughnessTexture.Deserialize(child);
}
DeserializeCommon(element);
}
internal override void Serialize(Utf8JsonWriter writer)
{
throw new NotImplementedException();
}
}
public class GltfNormalTexture : GltfMaterialTextureInfo
{
public float Scale { get; set; } = 1.0f;
internal GltfNormalTexture(GltfDocument document) : base(document)
{
}
internal override void Deserialize(JsonElement element)
{
base.Deserialize(element);
if (element.TryGetProperty("scale", out JsonElement scale))
{
Scale = scale.GetSingle();
}
}
}
public class GltfOcclusionTexture : GltfMaterialTextureInfo
{
public float Strength { get; set; } = 1;
internal GltfOcclusionTexture(GltfDocument document) : base(document)
{
}
internal override void Deserialize(JsonElement element)
{
base.Deserialize(element);
if (element.TryGetProperty("strength", out JsonElement strength))
{
Strength = strength.GetSingle();
}
}
}
public class GltfMaterial : GltfIdObject
{
public override GltfObjectKind Kind => GltfObjectKind.Material;
private GltfMaterialAlphaMode _alphaMode = GltfMaterialAlphaMode.Opaque;
private string _alphaModeString = "OPAQUE";
public string? Name { get; set; }
public string AlphaModeString
{
get => _alphaModeString;
set
{
_alphaModeString = value;
_alphaMode = GltfMaterialAlphaModeFromString(value);
}
}
public GltfMaterialAlphaMode AlphaMode
{
get => _alphaMode;
set
{
_alphaMode = value;
_alphaModeString = GltfMaterialAlphaModeToString(value);
}
}
public float AlphaCutoff { get; set; } = 0.5f;
public bool DoubleSided { get; set; } = false;
public GltfMetallicRoughness? MetallicRoughness { get; set; } = null;
public GltfNormalTexture? NormalTexture { get; set; } = null;
public GltfOcclusionTexture? OcclusionTexture { get; set; } = null;
public GltfMaterialTextureInfo? EmissiveTexture { get; set; } = null;
public Vector3 EmissiveFactor { get; set; } = Vector3.Zero;
internal GltfMaterial(GltfDocument document) : base(document) { }
internal override void Deserialize(JsonElement element)
{
if (element.ValueKind != JsonValueKind.Object)
throw new Exception("Expected an object.");
DeserializeCommon(element);
foreach (JsonProperty property in element.EnumerateObject())
{
switch (property.Name)
{
case "name":
Name = property.Value.GetString();
break;
case "pbrMetallicRoughness":
MetallicRoughness = new GltfMetallicRoughness(Document);
MetallicRoughness.Deserialize(property.Value);
break;
case "normalTexture":
NormalTexture = new GltfNormalTexture(Document);
NormalTexture.Deserialize(property.Value);
break;
case "occlusionTexture":
OcclusionTexture = new GltfOcclusionTexture(Document);
OcclusionTexture.Deserialize(property.Value);
break;
case "emissiveTexture":
EmissiveTexture = new GltfMaterialTextureInfo(Document);
EmissiveTexture.Deserialize(property.Value);
break;
case "emissiveFactor":
if (property.Value.ValueKind != JsonValueKind.Array)
{
throw new Exception("Expected a value array as emissiveFactor");
}
Vector3 factor = default;
int i = 0;
foreach (JsonElement item in property.Value.EnumerateArray())
{
float value = item.GetSingle();
switch (i++)
{
case 0: factor.X = value; break;
case 1: factor.Y = value; break;
case 2: factor.Z = value; break;
default:
goto break_for;
}
continue;
break_for:
break;
}
break;
case "alphaMode":
AlphaModeString = property.Value.GetString() ?? "OPAQUE";
break;
case "alphaCutoff":
AlphaCutoff = property.Value.GetSingle();
break;
case "doubleSided":
DoubleSided = property.Value.GetBoolean();
break;
}
}
}
internal override void Serialize(Utf8JsonWriter writer)
{
throw new NotImplementedException();
}
private static string GltfMaterialAlphaModeToString(GltfMaterialAlphaMode mode) => mode switch {
GltfMaterialAlphaMode.Opaque => "OPAQUE",
GltfMaterialAlphaMode.Mask => "MASK",
GltfMaterialAlphaMode.Blend => "BLEND",
_ => throw new ArgumentException("GltfMaterialAlphaMode.Other is not a valid target.", nameof(mode)),
};
private static GltfMaterialAlphaMode GltfMaterialAlphaModeFromString(string str) => str switch {
"OPAQUE" => GltfMaterialAlphaMode.Opaque,
"MASK" => GltfMaterialAlphaMode.Mask,
"BLEND" => GltfMaterialAlphaMode.Blend,
_ => GltfMaterialAlphaMode.Other
};
}
}