CharacterKit/BuiltInFaces.cs

Static helper for built-in face presets used by the character editor. It defines entries for native and additional faces, creates PhotoFace objects from embedded JSON, finds/selects faces on a CharacterBaseShape, and applies fantasy face morph weights to a SkinnedModelRenderer.

File Access
using System;
using System.Text.Json;

namespace CharacterEditor;
/// <summary>Additional standard blend entries reuse the portable fitted-face basis.
/// Original seven-element native arrays and saved photo faces keep their meaning.</summary>
public static partial class BuiltInFaces
{
	public sealed record Entry(int Index, string Key, string Label, string Id);
	public const int NativeCount = 7, AdditionalCount = 6, Count = NativeCount + AdditionalCount;
	public static IReadOnlyList<Entry> Entries { get; } = CreateEntries();

	public static bool IsAvailableInRegion(int index, string region) => region != "ears" || index < NativeCount || Entries.Single(entry => entry.Index == index).Key is not ("goblin" or "bovine" or "orc");
	public static bool Contains(PhotoFace face) => face is not null && Entries.Any(e => e.Id == face.Id);
	public static int CustomCount(CharacterBaseShape shape) => shape?.PhotoFaces.Count(f => !Contains(f)) ?? 0;
	public static PhotoFace Get(CharacterBaseShape shape, int index, bool create = false)
	{
		var entry = Entries.Single(e => e.Index == index);
		var face = shape.PhotoFaces.FirstOrDefault(f => f.Id == entry.Id);
		if (face is null && create)
		{
			face = Create(entry.Key);
			face.Influence = 0;
			shape.PhotoFaces.Add(face);
		}

		return face;
	}

	public static PhotoFace Create(string key)
	{
		var entry = Entries.Single(e => e.Key == key);
		var face = JsonSerializer.Deserialize<PhotoFace>(Data(key));
		face.Id = entry.Id;
		face.Name = entry.Label;
		face.Influence = 1;
		face.Strength = 1;
		return face;
	}

	public static void Select(CharacterAppearanceData appearance, string key)
	{
		UnifiedHuman.Enable(appearance);
		Array.Fill(appearance.BaseShape.HeadWeights, 0);
		appearance.BaseShape.PhotoFaces.Clear();
		appearance.BaseShape.Regions.Clear();
		appearance.BaseShape.PhotoFaces.Add(Create(key));
	}

	public static void Apply(SkinnedModelRenderer body, CharacterBaseShape shape)
	{
		foreach (var key in new[]
		{
			"goblin",
			"bovine",
			"orc"
		}

		)
		{
			var entry = Entries.Single(e => e.Key == key);
			var face = shape.PhotoFaces.FirstOrDefault(f => f.Id == entry.Id);
			foreach (var region in FaceRegions.Ids)
			{
				float amount = face is null ? 0 : Math.Clamp(FaceRegions.PhotoShare(shape, face, region) * face.Strength, 0, 1);
				body.Morphs.Set($"ce_fantasy_{key}_{FaceRegions.MorphRegion(region)}", amount, 0);
			}
		}
	}
}