forked from ReFuel/ReFuel.Gltf
314 lines
10 KiB
C#
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
|
|
};
|
|
}
|
|
}
|