forked from ReFuel/ReFuel.Gltf
251 lines
8.0 KiB
C#
251 lines
8.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text.Json;
|
|
|
|
namespace ReFuel.Gltf
|
|
{
|
|
public record struct GltfMeshAttribute
|
|
{
|
|
private GltfSmartId<GltfAccessor> accessor;
|
|
|
|
public GltfAccessor Accessor
|
|
{
|
|
get => accessor.Value;
|
|
set => accessor.Value = value;
|
|
}
|
|
|
|
public string Name { get; }
|
|
public int Index { get; }
|
|
public GltfAttributeType Type { get; }
|
|
|
|
public GltfMeshAttribute(GltfDocument document, string name, int accessorIndex)
|
|
{
|
|
accessor = new GltfSmartId<GltfAccessor>(document.Accessors)
|
|
{
|
|
Id = accessorIndex,
|
|
};
|
|
|
|
ReadOnlySpan<char> full = name.AsSpan();
|
|
ReadOnlySpan<char> head;
|
|
ReadOnlySpan<char> tail;
|
|
|
|
int indexOfUnderscore = name.IndexOf('_');
|
|
if (indexOfUnderscore == -1)
|
|
{
|
|
head = full;
|
|
tail = ReadOnlySpan<char>.Empty;
|
|
}
|
|
else
|
|
{
|
|
head = full.Slice(0, indexOfUnderscore);
|
|
tail = full.Slice(indexOfUnderscore+1);
|
|
}
|
|
|
|
switch (head.ToString())
|
|
{
|
|
case "POSITION":
|
|
Name = "POSITION";
|
|
Index = 0;
|
|
Type = GltfAttributeType.Position;
|
|
break;
|
|
case "NORMAL":
|
|
Name = "NORMAL";
|
|
Index = 0;
|
|
Type = GltfAttributeType.Normal;
|
|
break;
|
|
case "TANGENT":
|
|
Name = "TANGENT";
|
|
Index = 0;
|
|
Type = GltfAttributeType.Tangent;
|
|
break;
|
|
case "TEXCOORD":
|
|
Name = "TEXCOORD";
|
|
Index = int.Parse(tail);
|
|
Type = GltfAttributeType.TexCoord;
|
|
break;
|
|
case "COLOR":
|
|
Name = "COLOR";
|
|
Index = int.Parse(tail);
|
|
Type = GltfAttributeType.Color;
|
|
break;
|
|
case "JOINTS":
|
|
Name = "JOINTS";
|
|
Index = int.Parse(tail);
|
|
Type = GltfAttributeType.Joints;
|
|
break;
|
|
case "WEIGHTS":
|
|
Name = "WEIGHTS";
|
|
Index = int.Parse(tail);
|
|
Type = GltfAttributeType.Weights;
|
|
break;
|
|
default:
|
|
Name = tail.ToString();
|
|
Index = 0;
|
|
Type = GltfAttributeType.Custom;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class GltfMeshPrimitive : GltfObject
|
|
{
|
|
public override GltfObjectKind Kind => GltfObjectKind.MeshPrimitive;
|
|
private GltfSmartId<GltfAccessor> index;
|
|
private GltfSmartId<GltfMaterial> material;
|
|
|
|
public List<GltfMeshAttribute> Attributes { get; } = new List<GltfMeshAttribute>();
|
|
|
|
public GltfAccessor? Index
|
|
{
|
|
get => index.IsSet ? index : null;
|
|
set
|
|
{
|
|
if (value is null)
|
|
index.Reset();
|
|
else
|
|
index.Value = value;
|
|
}
|
|
}
|
|
|
|
public GltfMaterial? Material
|
|
{
|
|
get => material.IsSet ? material : null;
|
|
set
|
|
{
|
|
if (value is null)
|
|
material.Reset();
|
|
else
|
|
material.Value = value;
|
|
}
|
|
}
|
|
|
|
public GltfMeshMode Mode { get; set; } = GltfMeshMode.Triangles;
|
|
|
|
public GltfRefList<GltfIdObject> Targets { get; private set; }
|
|
|
|
internal GltfMeshPrimitive(GltfDocument document) : base(document)
|
|
{
|
|
Targets = new GltfRefList<GltfIdObject>(null!);
|
|
index = new GltfSmartId<GltfAccessor>(document.Accessors);
|
|
material = new GltfSmartId<GltfMaterial>(document.Materials);
|
|
}
|
|
|
|
internal override void Deserialize(JsonElement element)
|
|
{
|
|
AssertObject(element);
|
|
|
|
if (!element.TryGetProperty("attributes", out JsonElement attributesElement))
|
|
RequiredProperty("attributes");
|
|
else if (attributesElement.ValueKind != JsonValueKind.Object)
|
|
PropertyFormatFail("attributes", "expected a dictionary.");
|
|
|
|
foreach (JsonProperty property in attributesElement.EnumerateObject())
|
|
{
|
|
if (!property.Value.TryGetInt32(out int i))
|
|
{
|
|
PropertyFormatFail("attributes", "expected dictionary values to be integers.");
|
|
}
|
|
|
|
Attributes.Add(new GltfMeshAttribute(Document, property.Name, i));
|
|
}
|
|
|
|
if (element.TryGetProperty("indices", out JsonElement indicesElement))
|
|
{
|
|
if (!indicesElement.TryGetInt32(out int index))
|
|
PropertyFormatFail("indices", "expected an integer value.");
|
|
|
|
this.index.Id = index;
|
|
}
|
|
|
|
if (element.TryGetProperty("material", out JsonElement materialElement))
|
|
{
|
|
if (!materialElement.TryGetInt32(out int index))
|
|
PropertyFormatFail("material", "expected an integer value.");
|
|
|
|
this.material.Id = index;
|
|
}
|
|
|
|
// TODO: materials.
|
|
// TODO: morph targets.
|
|
|
|
if (element.TryGetProperty("mode", out JsonElement modeElement))
|
|
{
|
|
if (!modeElement.TryGetInt32(out int mode))
|
|
PropertyFormatFail("mode", "expected integer value.");
|
|
|
|
Mode = (GltfMeshMode)mode;
|
|
}
|
|
|
|
DeserializeCommon(element);
|
|
}
|
|
|
|
internal override void Serialize(Utf8JsonWriter writer)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public class GltfMesh : GltfIdObject
|
|
{
|
|
public override GltfObjectKind Kind => GltfObjectKind.Mesh;
|
|
|
|
public string? Name { get; set; }
|
|
public float[]? Weights { get; set; }
|
|
public List<GltfMeshPrimitive> Primitives { get; } = new List<GltfMeshPrimitive>();
|
|
|
|
internal GltfMesh(GltfDocument document) : base(document)
|
|
{
|
|
}
|
|
|
|
internal override void Deserialize(JsonElement element)
|
|
{
|
|
if (element.ValueKind != JsonValueKind.Object)
|
|
throw new Exception("Expected an object.");
|
|
|
|
if (element.TryGetProperty("name", out JsonElement nameElement))
|
|
{
|
|
Name = nameElement.GetString();
|
|
}
|
|
|
|
if (element.TryGetProperty("weights", out JsonElement weightsArray))
|
|
{
|
|
if (weightsArray.ValueKind != JsonValueKind.Array)
|
|
throw new Exception("Expected an array.");
|
|
|
|
List<float> values = new List<float>();
|
|
foreach (JsonElement item in weightsArray.EnumerateArray())
|
|
{
|
|
if (!item.TryGetSingle(out float v))
|
|
throw new Exception("expected a number");
|
|
|
|
values.Add(v);
|
|
}
|
|
|
|
Weights = values.ToArray();
|
|
}
|
|
else
|
|
{
|
|
Weights = null;
|
|
}
|
|
|
|
if (element.TryGetProperty("primitives", out JsonElement primitivesElement))
|
|
{
|
|
if (primitivesElement.ValueKind != JsonValueKind.Array)
|
|
PropertyFormatFail("primitives", "expected an array.");
|
|
|
|
foreach (JsonElement child in primitivesElement.EnumerateArray())
|
|
{
|
|
GltfMeshPrimitive primitive = new GltfMeshPrimitive(Document);
|
|
primitive.Deserialize(child);
|
|
Primitives.Add(primitive);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal override void Serialize(Utf8JsonWriter writer)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
}
|