mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Merge branch 'refs/heads/adamm789/model-export'
This commit is contained in:
commit
b2860c1047
3 changed files with 202 additions and 74 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit f6dff467c7dad6b1213a7d7b65d40a56450f0672
|
Subproject commit b4a0806e00be4ce8cf3103fd526e4a412b4770b7
|
||||||
|
|
@ -7,7 +7,6 @@ using Penumbra.GameData.Files;
|
||||||
using Penumbra.GameData.Files.ModelStructs;
|
using Penumbra.GameData.Files.ModelStructs;
|
||||||
using SharpGLTF.Geometry;
|
using SharpGLTF.Geometry;
|
||||||
using SharpGLTF.Geometry.VertexTypes;
|
using SharpGLTF.Geometry.VertexTypes;
|
||||||
using SharpGLTF.IO;
|
|
||||||
using SharpGLTF.Materials;
|
using SharpGLTF.Materials;
|
||||||
using SharpGLTF.Scenes;
|
using SharpGLTF.Scenes;
|
||||||
|
|
||||||
|
|
@ -84,9 +83,12 @@ public class MeshExporter
|
||||||
_boneIndexMap = BuildBoneIndexMap(skeleton.Value);
|
_boneIndexMap = BuildBoneIndexMap(skeleton.Value);
|
||||||
|
|
||||||
var usages = _mdl.VertexDeclarations[_meshIndex].VertexElements
|
var usages = _mdl.VertexDeclarations[_meshIndex].VertexElements
|
||||||
|
.GroupBy(ele => (MdlFile.VertexUsage)ele.Usage, ele => ele)
|
||||||
.ToImmutableDictionary(
|
.ToImmutableDictionary(
|
||||||
element => (MdlFile.VertexUsage)element.Usage,
|
g => g.Key,
|
||||||
element => (MdlFile.VertexType)element.Type
|
g => g.OrderBy(ele => ele.UsageIndex) // OrderBy UsageIndex is probably unnecessary as they're probably already be in order
|
||||||
|
.Select(ele => (MdlFile.VertexType)ele.Type)
|
||||||
|
.ToList()
|
||||||
);
|
);
|
||||||
|
|
||||||
_geometryType = GetGeometryType(usages);
|
_geometryType = GetGeometryType(usages);
|
||||||
|
|
@ -112,6 +114,7 @@ public class MeshExporter
|
||||||
|
|
||||||
var indexMap = new Dictionary<ushort, int>();
|
var indexMap = new Dictionary<ushort, int>();
|
||||||
// #TODO @ackwell maybe fix for V6 Models, I think this works fine.
|
// #TODO @ackwell maybe fix for V6 Models, I think this works fine.
|
||||||
|
|
||||||
foreach (var (xivBoneIndex, tableIndex) in xivBoneTable.BoneIndex.Take((int)xivBoneTable.BoneCount).WithIndex())
|
foreach (var (xivBoneIndex, tableIndex) in xivBoneTable.BoneIndex.Take((int)xivBoneTable.BoneCount).WithIndex())
|
||||||
{
|
{
|
||||||
var boneName = _mdl.Bones[xivBoneIndex];
|
var boneName = _mdl.Bones[xivBoneIndex];
|
||||||
|
|
@ -278,18 +281,22 @@ public class MeshExporter
|
||||||
|
|
||||||
var sortedElements = _mdl.VertexDeclarations[_meshIndex].VertexElements
|
var sortedElements = _mdl.VertexDeclarations[_meshIndex].VertexElements
|
||||||
.OrderBy(element => element.Offset)
|
.OrderBy(element => element.Offset)
|
||||||
.Select(element => ((MdlFile.VertexUsage)element.Usage, element))
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var vertices = new List<IVertexBuilder>();
|
var vertices = new List<IVertexBuilder>();
|
||||||
|
|
||||||
var attributes = new Dictionary<MdlFile.VertexUsage, object>();
|
var attributes = new Dictionary<MdlFile.VertexUsage, List<object>>();
|
||||||
for (var vertexIndex = 0; vertexIndex < XivMesh.VertexCount; vertexIndex++)
|
for (var vertexIndex = 0; vertexIndex < XivMesh.VertexCount; vertexIndex++)
|
||||||
{
|
{
|
||||||
attributes.Clear();
|
attributes.Clear();
|
||||||
|
attributes = sortedElements
|
||||||
foreach (var (usage, element) in sortedElements)
|
.GroupBy(element => element.Usage)
|
||||||
attributes[usage] = ReadVertexAttribute((MdlFile.VertexType)element.Type, streams[element.Stream]);
|
.ToDictionary(
|
||||||
|
x => (MdlFile.VertexUsage)x.Key,
|
||||||
|
x => x.OrderBy(ele => ele.UsageIndex) // Once again, OrderBy UsageIndex is probably unnecessary
|
||||||
|
.Select(ele => ReadVertexAttribute((MdlFile.VertexType)ele.Type, streams[ele.Stream]))
|
||||||
|
.ToList()
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
var vertexGeometry = BuildVertexGeometry(attributes);
|
var vertexGeometry = BuildVertexGeometry(attributes);
|
||||||
var vertexMaterial = BuildVertexMaterial(attributes);
|
var vertexMaterial = BuildVertexMaterial(attributes);
|
||||||
|
|
@ -320,7 +327,7 @@ public class MeshExporter
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Get the vertex geometry type for this mesh's vertex usages. </summary>
|
/// <summary> Get the vertex geometry type for this mesh's vertex usages. </summary>
|
||||||
private Type GetGeometryType(IReadOnlyDictionary<MdlFile.VertexUsage, MdlFile.VertexType> usages)
|
private Type GetGeometryType(IReadOnlyDictionary<MdlFile.VertexUsage, List<MdlFile.VertexType>> usages)
|
||||||
{
|
{
|
||||||
if (!usages.ContainsKey(MdlFile.VertexUsage.Position))
|
if (!usages.ContainsKey(MdlFile.VertexUsage.Position))
|
||||||
throw _notifier.Exception("Mesh does not contain position vertex elements.");
|
throw _notifier.Exception("Mesh does not contain position vertex elements.");
|
||||||
|
|
@ -335,28 +342,28 @@ public class MeshExporter
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Build a geometry vertex from a vertex's attributes. </summary>
|
/// <summary> Build a geometry vertex from a vertex's attributes. </summary>
|
||||||
private IVertexGeometry BuildVertexGeometry(IReadOnlyDictionary<MdlFile.VertexUsage, object> attributes)
|
private IVertexGeometry BuildVertexGeometry(IReadOnlyDictionary<MdlFile.VertexUsage, List<object>> attributes)
|
||||||
{
|
{
|
||||||
if (_geometryType == typeof(VertexPosition))
|
if (_geometryType == typeof(VertexPosition))
|
||||||
return new VertexPosition(
|
return new VertexPosition(
|
||||||
ToVector3(attributes[MdlFile.VertexUsage.Position])
|
ToVector3(GetFirstSafe(attributes, MdlFile.VertexUsage.Position))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_geometryType == typeof(VertexPositionNormal))
|
if (_geometryType == typeof(VertexPositionNormal))
|
||||||
return new VertexPositionNormal(
|
return new VertexPositionNormal(
|
||||||
ToVector3(attributes[MdlFile.VertexUsage.Position]),
|
ToVector3(GetFirstSafe(attributes, MdlFile.VertexUsage.Position)),
|
||||||
ToVector3(attributes[MdlFile.VertexUsage.Normal])
|
ToVector3(GetFirstSafe(attributes, MdlFile.VertexUsage.Normal))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_geometryType == typeof(VertexPositionNormalTangent))
|
if (_geometryType == typeof(VertexPositionNormalTangent))
|
||||||
{
|
{
|
||||||
// (Bi)tangents are universally stored as ByteFloat4, which uses 0..1 to represent the full -1..1 range.
|
// (Bi)tangents are universally stored as ByteFloat4, which uses 0..1 to represent the full -1..1 range.
|
||||||
// TODO: While this assumption is safe, it would be sensible to actually check.
|
// TODO: While this assumption is safe, it would be sensible to actually check.
|
||||||
var bitangent = ToVector4(attributes[MdlFile.VertexUsage.Tangent1]) * 2 - Vector4.One;
|
var bitangent = ToVector4(GetFirstSafe(attributes, MdlFile.VertexUsage.Tangent1)) * 2 - Vector4.One;
|
||||||
|
|
||||||
return new VertexPositionNormalTangent(
|
return new VertexPositionNormalTangent(
|
||||||
ToVector3(attributes[MdlFile.VertexUsage.Position]),
|
ToVector3(GetFirstSafe(attributes, MdlFile.VertexUsage.Position)),
|
||||||
ToVector3(attributes[MdlFile.VertexUsage.Normal]),
|
ToVector3(GetFirstSafe(attributes, MdlFile.VertexUsage.Normal)),
|
||||||
bitangent
|
bitangent
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -365,18 +372,23 @@ public class MeshExporter
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Get the vertex material type for this mesh's vertex usages. </summary>
|
/// <summary> Get the vertex material type for this mesh's vertex usages. </summary>
|
||||||
private Type GetMaterialType(IReadOnlyDictionary<MdlFile.VertexUsage, MdlFile.VertexType> usages)
|
private Type GetMaterialType(IReadOnlyDictionary<MdlFile.VertexUsage, List<MdlFile.VertexType>> usages)
|
||||||
{
|
{
|
||||||
var uvCount = 0;
|
var uvCount = 0;
|
||||||
if (usages.TryGetValue(MdlFile.VertexUsage.UV, out var type))
|
if (usages.TryGetValue(MdlFile.VertexUsage.UV, out var list))
|
||||||
uvCount = type switch
|
{
|
||||||
|
foreach (var type in list)
|
||||||
{
|
{
|
||||||
MdlFile.VertexType.Half2 => 1,
|
uvCount += type switch
|
||||||
MdlFile.VertexType.Half4 => 2,
|
{
|
||||||
MdlFile.VertexType.Single2 => 1,
|
MdlFile.VertexType.Half2 => 1,
|
||||||
MdlFile.VertexType.Single4 => 2,
|
MdlFile.VertexType.Half4 => 2,
|
||||||
_ => throw _notifier.Exception($"Unexpected UV vertex type {type}."),
|
MdlFile.VertexType.Single2 => 1,
|
||||||
};
|
MdlFile.VertexType.Single4 => 2,
|
||||||
|
_ => throw _notifier.Exception($"Unexpected UV vertex type {type}."),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var materialUsages = (
|
var materialUsages = (
|
||||||
uvCount,
|
uvCount,
|
||||||
|
|
@ -385,6 +397,8 @@ public class MeshExporter
|
||||||
|
|
||||||
return materialUsages switch
|
return materialUsages switch
|
||||||
{
|
{
|
||||||
|
(3, true) => typeof(VertexTexture3ColorFfxiv),
|
||||||
|
(3, false) => typeof(VertexTexture3),
|
||||||
(2, true) => typeof(VertexTexture2ColorFfxiv),
|
(2, true) => typeof(VertexTexture2ColorFfxiv),
|
||||||
(2, false) => typeof(VertexTexture2),
|
(2, false) => typeof(VertexTexture2),
|
||||||
(1, true) => typeof(VertexTexture1ColorFfxiv),
|
(1, true) => typeof(VertexTexture1ColorFfxiv),
|
||||||
|
|
@ -392,33 +406,33 @@ public class MeshExporter
|
||||||
(0, true) => typeof(VertexColorFfxiv),
|
(0, true) => typeof(VertexColorFfxiv),
|
||||||
(0, false) => typeof(VertexEmpty),
|
(0, false) => typeof(VertexEmpty),
|
||||||
|
|
||||||
_ => throw new Exception("Unreachable."),
|
_ => throw _notifier.Exception($"Unhandled UV count of {uvCount} encountered."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Build a material vertex from a vertex's attributes. </summary>
|
/// <summary> Build a material vertex from a vertex's attributes. </summary>
|
||||||
private IVertexMaterial BuildVertexMaterial(IReadOnlyDictionary<MdlFile.VertexUsage, object> attributes)
|
private IVertexMaterial BuildVertexMaterial(IReadOnlyDictionary<MdlFile.VertexUsage, List<object>> attributes)
|
||||||
{
|
{
|
||||||
if (_materialType == typeof(VertexEmpty))
|
if (_materialType == typeof(VertexEmpty))
|
||||||
return new VertexEmpty();
|
return new VertexEmpty();
|
||||||
|
|
||||||
if (_materialType == typeof(VertexColorFfxiv))
|
if (_materialType == typeof(VertexColorFfxiv))
|
||||||
return new VertexColorFfxiv(ToVector4(attributes[MdlFile.VertexUsage.Color]));
|
return new VertexColorFfxiv(ToVector4(GetFirstSafe(attributes, MdlFile.VertexUsage.Color)));
|
||||||
|
|
||||||
if (_materialType == typeof(VertexTexture1))
|
if (_materialType == typeof(VertexTexture1))
|
||||||
return new VertexTexture1(ToVector2(attributes[MdlFile.VertexUsage.UV]));
|
return new VertexTexture1(ToVector2(GetFirstSafe(attributes, MdlFile.VertexUsage.UV)));
|
||||||
|
|
||||||
if (_materialType == typeof(VertexTexture1ColorFfxiv))
|
if (_materialType == typeof(VertexTexture1ColorFfxiv))
|
||||||
return new VertexTexture1ColorFfxiv(
|
return new VertexTexture1ColorFfxiv(
|
||||||
ToVector2(attributes[MdlFile.VertexUsage.UV]),
|
ToVector2(GetFirstSafe(attributes, MdlFile.VertexUsage.UV)),
|
||||||
ToVector4(attributes[MdlFile.VertexUsage.Color])
|
ToVector4(GetFirstSafe(attributes, MdlFile.VertexUsage.Color))
|
||||||
);
|
);
|
||||||
|
|
||||||
// XIV packs two UVs into a single vec4 attribute.
|
// XIV packs two UVs into a single vec4 attribute.
|
||||||
|
|
||||||
if (_materialType == typeof(VertexTexture2))
|
if (_materialType == typeof(VertexTexture2))
|
||||||
{
|
{
|
||||||
var uv = ToVector4(attributes[MdlFile.VertexUsage.UV]);
|
var uv = ToVector4(GetFirstSafe(attributes, MdlFile.VertexUsage.UV));
|
||||||
return new VertexTexture2(
|
return new VertexTexture2(
|
||||||
new Vector2(uv.X, uv.Y),
|
new Vector2(uv.X, uv.Y),
|
||||||
new Vector2(uv.Z, uv.W)
|
new Vector2(uv.Z, uv.W)
|
||||||
|
|
@ -427,11 +441,34 @@ public class MeshExporter
|
||||||
|
|
||||||
if (_materialType == typeof(VertexTexture2ColorFfxiv))
|
if (_materialType == typeof(VertexTexture2ColorFfxiv))
|
||||||
{
|
{
|
||||||
var uv = ToVector4(attributes[MdlFile.VertexUsage.UV]);
|
var uv = ToVector4(GetFirstSafe(attributes, MdlFile.VertexUsage.UV));
|
||||||
return new VertexTexture2ColorFfxiv(
|
return new VertexTexture2ColorFfxiv(
|
||||||
new Vector2(uv.X, uv.Y),
|
new Vector2(uv.X, uv.Y),
|
||||||
new Vector2(uv.Z, uv.W),
|
new Vector2(uv.Z, uv.W),
|
||||||
ToVector4(attributes[MdlFile.VertexUsage.Color])
|
ToVector4(GetFirstSafe(attributes, MdlFile.VertexUsage.Color))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (_materialType == typeof(VertexTexture3))
|
||||||
|
{
|
||||||
|
// Not 100% sure about this
|
||||||
|
var uv0 = ToVector4(attributes[MdlFile.VertexUsage.UV][0]);
|
||||||
|
var uv1 = ToVector4(attributes[MdlFile.VertexUsage.UV][1]);
|
||||||
|
return new VertexTexture3(
|
||||||
|
new Vector2(uv0.X, uv0.Y),
|
||||||
|
new Vector2(uv0.Z, uv0.W),
|
||||||
|
new Vector2(uv1.X, uv1.Y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_materialType == typeof(VertexTexture3ColorFfxiv))
|
||||||
|
{
|
||||||
|
var uv0 = ToVector4(attributes[MdlFile.VertexUsage.UV][0]);
|
||||||
|
var uv1 = ToVector4(attributes[MdlFile.VertexUsage.UV][1]);
|
||||||
|
return new VertexTexture3ColorFfxiv(
|
||||||
|
new Vector2(uv0.X, uv0.Y),
|
||||||
|
new Vector2(uv0.Z, uv0.W),
|
||||||
|
new Vector2(uv1.X, uv1.Y),
|
||||||
|
ToVector4(GetFirstSafe(attributes, MdlFile.VertexUsage.Color))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,25 +476,20 @@ public class MeshExporter
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Get the vertex skinning type for this mesh's vertex usages. </summary>
|
/// <summary> Get the vertex skinning type for this mesh's vertex usages. </summary>
|
||||||
private static Type GetSkinningType(IReadOnlyDictionary<MdlFile.VertexUsage, MdlFile.VertexType> usages)
|
private Type GetSkinningType(IReadOnlyDictionary<MdlFile.VertexUsage, List<MdlFile.VertexType>> usages)
|
||||||
{
|
{
|
||||||
if (usages.ContainsKey(MdlFile.VertexUsage.BlendWeights) && usages.ContainsKey(MdlFile.VertexUsage.BlendIndices))
|
if (usages.ContainsKey(MdlFile.VertexUsage.BlendWeights) && usages.ContainsKey(MdlFile.VertexUsage.BlendIndices))
|
||||||
{
|
{
|
||||||
if (usages[MdlFile.VertexUsage.BlendWeights] == MdlFile.VertexType.UShort4)
|
return GetFirstSafe(usages, MdlFile.VertexUsage.BlendWeights) == MdlFile.VertexType.UShort4
|
||||||
{
|
? typeof(VertexJoints8)
|
||||||
return typeof(VertexJoints8);
|
: typeof(VertexJoints4);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return typeof(VertexJoints4);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeof(VertexEmpty);
|
return typeof(VertexEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Build a skinning vertex from a vertex's attributes. </summary>
|
/// <summary> Build a skinning vertex from a vertex's attributes. </summary>
|
||||||
private IVertexSkinning BuildVertexSkinning(IReadOnlyDictionary<MdlFile.VertexUsage, object> attributes)
|
private IVertexSkinning BuildVertexSkinning(IReadOnlyDictionary<MdlFile.VertexUsage, List<object>> attributes)
|
||||||
{
|
{
|
||||||
if (_skinningType == typeof(VertexEmpty))
|
if (_skinningType == typeof(VertexEmpty))
|
||||||
return new VertexEmpty();
|
return new VertexEmpty();
|
||||||
|
|
@ -467,8 +499,8 @@ public class MeshExporter
|
||||||
if (_boneIndexMap == null)
|
if (_boneIndexMap == null)
|
||||||
throw _notifier.Exception("Tried to build skinned vertex but no bone mappings are available.");
|
throw _notifier.Exception("Tried to build skinned vertex but no bone mappings are available.");
|
||||||
|
|
||||||
var indiciesData = attributes[MdlFile.VertexUsage.BlendIndices];
|
var indiciesData = GetFirstSafe(attributes, MdlFile.VertexUsage.BlendIndices);
|
||||||
var weightsData = attributes[MdlFile.VertexUsage.BlendWeights];
|
var weightsData = GetFirstSafe(attributes, MdlFile.VertexUsage.BlendWeights);
|
||||||
var indices = ToByteArray(indiciesData);
|
var indices = ToByteArray(indiciesData);
|
||||||
var weights = ToFloatArray(weightsData);
|
var weights = ToFloatArray(weightsData);
|
||||||
|
|
||||||
|
|
@ -495,6 +527,17 @@ public class MeshExporter
|
||||||
throw _notifier.Exception($"Unknown skinning type {_skinningType}");
|
throw _notifier.Exception($"Unknown skinning type {_skinningType}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Check that the list has length 1 for any case where this is expected and return the one entry. </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
private T GetFirstSafe<T>(IReadOnlyDictionary<MdlFile.VertexUsage, List<T>> attributes, MdlFile.VertexUsage usage)
|
||||||
|
{
|
||||||
|
var list = attributes[usage];
|
||||||
|
if (list.Count != 1)
|
||||||
|
throw _notifier.Exception($"Multiple usage indices encountered for {usage}.");
|
||||||
|
|
||||||
|
return list[0];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Convert a vertex attribute value to a Vector2. Supported inputs are Vector2, Vector3, and Vector4. </summary>
|
/// <summary> Convert a vertex attribute value to a Vector2. Supported inputs are Vector2, Vector3, and Vector4. </summary>
|
||||||
private static Vector2 ToVector2(object data)
|
private static Vector2 ToVector2(object data)
|
||||||
=> data switch
|
=> data switch
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using SharpGLTF.Geometry.VertexTypes;
|
using SharpGLTF.Geometry.VertexTypes;
|
||||||
using SharpGLTF.Memory;
|
using SharpGLTF.Memory;
|
||||||
using SharpGLTF.Schema2;
|
using SharpGLTF.Schema2;
|
||||||
|
|
@ -11,7 +10,7 @@ Realistically, it will need to stick around until transforms/mutations are built
|
||||||
and there's reason to overhaul the export pipeline.
|
and there's reason to overhaul the export pipeline.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public struct VertexColorFfxiv : IVertexCustom
|
public struct VertexColorFfxiv(Vector4 ffxivColor) : IVertexCustom
|
||||||
{
|
{
|
||||||
public IEnumerable<KeyValuePair<string, AttributeFormat>> GetEncodingAttributes()
|
public IEnumerable<KeyValuePair<string, AttributeFormat>> GetEncodingAttributes()
|
||||||
{
|
{
|
||||||
|
|
@ -20,7 +19,7 @@ public struct VertexColorFfxiv : IVertexCustom
|
||||||
new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, true));
|
new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector4 FfxivColor;
|
public Vector4 FfxivColor = ffxivColor;
|
||||||
|
|
||||||
public int MaxColors
|
public int MaxColors
|
||||||
=> 0;
|
=> 0;
|
||||||
|
|
@ -33,9 +32,6 @@ public struct VertexColorFfxiv : IVertexCustom
|
||||||
public IEnumerable<string> CustomAttributes
|
public IEnumerable<string> CustomAttributes
|
||||||
=> CustomNames;
|
=> CustomNames;
|
||||||
|
|
||||||
public VertexColorFfxiv(Vector4 ffxivColor)
|
|
||||||
=> FfxivColor = ffxivColor;
|
|
||||||
|
|
||||||
public void Add(in VertexMaterialDelta delta)
|
public void Add(in VertexMaterialDelta delta)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
@ -88,7 +84,7 @@ public struct VertexColorFfxiv : IVertexCustom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct VertexTexture1ColorFfxiv : IVertexCustom
|
public struct VertexTexture1ColorFfxiv(Vector2 texCoord0, Vector4 ffxivColor) : IVertexCustom
|
||||||
{
|
{
|
||||||
public IEnumerable<KeyValuePair<string, AttributeFormat>> GetEncodingAttributes()
|
public IEnumerable<KeyValuePair<string, AttributeFormat>> GetEncodingAttributes()
|
||||||
{
|
{
|
||||||
|
|
@ -98,9 +94,9 @@ public struct VertexTexture1ColorFfxiv : IVertexCustom
|
||||||
new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, true));
|
new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 TexCoord0;
|
public Vector2 TexCoord0 = texCoord0;
|
||||||
|
|
||||||
public Vector4 FfxivColor;
|
public Vector4 FfxivColor = ffxivColor;
|
||||||
|
|
||||||
public int MaxColors
|
public int MaxColors
|
||||||
=> 0;
|
=> 0;
|
||||||
|
|
@ -113,12 +109,6 @@ public struct VertexTexture1ColorFfxiv : IVertexCustom
|
||||||
public IEnumerable<string> CustomAttributes
|
public IEnumerable<string> CustomAttributes
|
||||||
=> CustomNames;
|
=> CustomNames;
|
||||||
|
|
||||||
public VertexTexture1ColorFfxiv(Vector2 texCoord0, Vector4 ffxivColor)
|
|
||||||
{
|
|
||||||
TexCoord0 = texCoord0;
|
|
||||||
FfxivColor = ffxivColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(in VertexMaterialDelta delta)
|
public void Add(in VertexMaterialDelta delta)
|
||||||
{
|
{
|
||||||
TexCoord0 += delta.TexCoord0Delta;
|
TexCoord0 += delta.TexCoord0Delta;
|
||||||
|
|
@ -182,7 +172,7 @@ public struct VertexTexture1ColorFfxiv : IVertexCustom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct VertexTexture2ColorFfxiv : IVertexCustom
|
public struct VertexTexture2ColorFfxiv(Vector2 texCoord0, Vector2 texCoord1, Vector4 ffxivColor) : IVertexCustom
|
||||||
{
|
{
|
||||||
public IEnumerable<KeyValuePair<string, AttributeFormat>> GetEncodingAttributes()
|
public IEnumerable<KeyValuePair<string, AttributeFormat>> GetEncodingAttributes()
|
||||||
{
|
{
|
||||||
|
|
@ -194,9 +184,9 @@ public struct VertexTexture2ColorFfxiv : IVertexCustom
|
||||||
new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, true));
|
new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 TexCoord0;
|
public Vector2 TexCoord0 = texCoord0;
|
||||||
public Vector2 TexCoord1;
|
public Vector2 TexCoord1 = texCoord1;
|
||||||
public Vector4 FfxivColor;
|
public Vector4 FfxivColor = ffxivColor;
|
||||||
|
|
||||||
public int MaxColors
|
public int MaxColors
|
||||||
=> 0;
|
=> 0;
|
||||||
|
|
@ -209,13 +199,6 @@ public struct VertexTexture2ColorFfxiv : IVertexCustom
|
||||||
public IEnumerable<string> CustomAttributes
|
public IEnumerable<string> CustomAttributes
|
||||||
=> CustomNames;
|
=> CustomNames;
|
||||||
|
|
||||||
public VertexTexture2ColorFfxiv(Vector2 texCoord0, Vector2 texCoord1, Vector4 ffxivColor)
|
|
||||||
{
|
|
||||||
TexCoord0 = texCoord0;
|
|
||||||
TexCoord1 = texCoord1;
|
|
||||||
FfxivColor = ffxivColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(in VertexMaterialDelta delta)
|
public void Add(in VertexMaterialDelta delta)
|
||||||
{
|
{
|
||||||
TexCoord0 += delta.TexCoord0Delta;
|
TexCoord0 += delta.TexCoord0Delta;
|
||||||
|
|
@ -282,3 +265,105 @@ public struct VertexTexture2ColorFfxiv : IVertexCustom
|
||||||
throw new ArgumentOutOfRangeException(nameof(FfxivColor));
|
throw new ArgumentOutOfRangeException(nameof(FfxivColor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct VertexTexture3ColorFfxiv(Vector2 texCoord0, Vector2 texCoord1, Vector2 texCoord2, Vector4 ffxivColor)
|
||||||
|
: IVertexCustom
|
||||||
|
{
|
||||||
|
public IEnumerable<KeyValuePair<string, AttributeFormat>> GetEncodingAttributes()
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_0",
|
||||||
|
new AttributeFormat(DimensionType.VEC2, EncodingType.FLOAT, false));
|
||||||
|
yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_1",
|
||||||
|
new AttributeFormat(DimensionType.VEC2, EncodingType.FLOAT, false));
|
||||||
|
yield return new KeyValuePair<string, AttributeFormat>("TEXCOORD_2",
|
||||||
|
new AttributeFormat(DimensionType.VEC2, EncodingType.FLOAT, false));
|
||||||
|
yield return new KeyValuePair<string, AttributeFormat>("_FFXIV_COLOR",
|
||||||
|
new AttributeFormat(DimensionType.VEC4, EncodingType.UNSIGNED_SHORT, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 TexCoord0 = texCoord0;
|
||||||
|
public Vector2 TexCoord1 = texCoord1;
|
||||||
|
public Vector2 TexCoord2 = texCoord2;
|
||||||
|
public Vector4 FfxivColor = ffxivColor;
|
||||||
|
|
||||||
|
public int MaxColors
|
||||||
|
=> 0;
|
||||||
|
|
||||||
|
public int MaxTextCoords
|
||||||
|
=> 3;
|
||||||
|
|
||||||
|
private static readonly string[] CustomNames = ["_FFXIV_COLOR"];
|
||||||
|
|
||||||
|
public IEnumerable<string> CustomAttributes
|
||||||
|
=> CustomNames;
|
||||||
|
|
||||||
|
public void Add(in VertexMaterialDelta delta)
|
||||||
|
{
|
||||||
|
TexCoord0 += delta.TexCoord0Delta;
|
||||||
|
TexCoord1 += delta.TexCoord1Delta;
|
||||||
|
TexCoord2 += delta.TexCoord2Delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VertexMaterialDelta Subtract(IVertexMaterial baseValue)
|
||||||
|
=> new(Vector4.Zero, Vector4.Zero, TexCoord0 - baseValue.GetTexCoord(0), TexCoord1 - baseValue.GetTexCoord(1));
|
||||||
|
|
||||||
|
public Vector2 GetTexCoord(int index)
|
||||||
|
=> index switch
|
||||||
|
{
|
||||||
|
0 => TexCoord0,
|
||||||
|
1 => TexCoord1,
|
||||||
|
2 => TexCoord2,
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(index)),
|
||||||
|
};
|
||||||
|
|
||||||
|
public void SetTexCoord(int setIndex, Vector2 coord)
|
||||||
|
{
|
||||||
|
if (setIndex == 0)
|
||||||
|
TexCoord0 = coord;
|
||||||
|
if (setIndex == 1)
|
||||||
|
TexCoord1 = coord;
|
||||||
|
if (setIndex == 2)
|
||||||
|
TexCoord2 = coord;
|
||||||
|
if (setIndex >= 3)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(setIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetCustomAttribute(string attributeName, out object? value)
|
||||||
|
{
|
||||||
|
switch (attributeName)
|
||||||
|
{
|
||||||
|
case "_FFXIV_COLOR":
|
||||||
|
value = FfxivColor;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCustomAttribute(string attributeName, object value)
|
||||||
|
{
|
||||||
|
if (attributeName == "_FFXIV_COLOR" && value is Vector4 valueVector4)
|
||||||
|
FfxivColor = valueVector4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector4 GetColor(int index)
|
||||||
|
=> throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
|
||||||
|
public void SetColor(int setIndex, Vector4 color)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public void Validate()
|
||||||
|
{
|
||||||
|
var components = new[]
|
||||||
|
{
|
||||||
|
FfxivColor.X,
|
||||||
|
FfxivColor.Y,
|
||||||
|
FfxivColor.Z,
|
||||||
|
FfxivColor.W,
|
||||||
|
};
|
||||||
|
if (components.Any(component => component is < 0f or > 1f))
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(FfxivColor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue