mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
i should probably commit now
This commit is contained in:
1 parent
9cc94635a8
commit
667d8c8f7c
7 files changed
+325
-354
No files matched your search
@@ -0,0 +1 @@
|
||||
indentSize: 2
|
||||
+2
-1
@@ -9,7 +9,8 @@
|
||||
"webp",
|
||||
"hocs",
|
||||
"cooldown",
|
||||
"Lods"
|
||||
"Lods",
|
||||
"Skia"
|
||||
],
|
||||
"userWords": [
|
||||
"WOTB",
|
||||
|
||||
@@ -12,6 +12,7 @@ using CUE4Parse.UE4.Assets.Objects;
|
||||
using CUE4Parse.UE4.Objects.Engine;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using Microsoft.JavaScript.NodeApi;
|
||||
using SharpGLTF.Materials;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace BlitzKit.Game.JSExport;
|
||||
@@ -19,134 +20,129 @@ namespace BlitzKit.Game.JSExport;
|
||||
[JSExport]
|
||||
public partial class GameInterface
|
||||
{
|
||||
private readonly BlitzFileProvider provider;
|
||||
private readonly BlitzFileProvider provider;
|
||||
|
||||
public HashSet<string> files;
|
||||
public HashSet<string> files;
|
||||
|
||||
public GameInterface(string directory, string map, string temp)
|
||||
public GameInterface(string directory, string map, string temp)
|
||||
{
|
||||
provider = new(directory, map, temp);
|
||||
|
||||
files = [.. provider.Files.Keys];
|
||||
}
|
||||
|
||||
public HashSet<string> Files => files;
|
||||
|
||||
public byte[] TankBigIcon(string tag)
|
||||
{
|
||||
var pda = provider.Discovered<UPrimaryDataAsset>(tag);
|
||||
var icon = pda.Get<FSoftObjectPath>("BigIcon");
|
||||
return provider.Image(icon);
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"T_UI_Flag_(\w+)_S")]
|
||||
private static partial Regex FlagNameRegex();
|
||||
|
||||
public byte[] Flag(string nation)
|
||||
{
|
||||
var flagsBase = "Blitz/Content/UI/Textures/Flag/TankCard/";
|
||||
|
||||
foreach (var path in provider.Files.Keys)
|
||||
{
|
||||
provider = new(directory, map, temp);
|
||||
if (!path.StartsWith(flagsBase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
files = [.. provider.Files.Keys];
|
||||
}
|
||||
var fileName = Path.GetFileNameWithoutExtension(path);
|
||||
var match = FlagNameRegex().Match(fileName);
|
||||
|
||||
public HashSet<string> Files => files;
|
||||
|
||||
public byte[] TankBigIcon(string tag)
|
||||
{
|
||||
var pda = provider.Discovered<UPrimaryDataAsset>(tag);
|
||||
var icon = pda.Get<FSoftObjectPath>("BigIcon");
|
||||
return provider.Image(icon);
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"T_UI_Flag_(\w+)_S")]
|
||||
private static partial Regex FlagNameRegex();
|
||||
|
||||
public byte[] Flag(string nation)
|
||||
{
|
||||
var flagsBase = "Blitz/Content/UI/Textures/Flag/TankCard/";
|
||||
|
||||
foreach (var path in provider.Files.Keys)
|
||||
if (
|
||||
match.Success
|
||||
&& match.Groups[1].Value.Equals(nation, StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
{
|
||||
if (provider.TryLoadPackageObject<UTexture2D>($"{path}.{fileName}", out var uTexture))
|
||||
{
|
||||
if (!path.StartsWith(flagsBase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
CTexture? cTexture = uTexture.Decode(ETexturePlatform.DesktopMobile);
|
||||
|
||||
var fileName = Path.GetFileNameWithoutExtension(path);
|
||||
var match = FlagNameRegex().Match(fileName);
|
||||
if (cTexture is null)
|
||||
{
|
||||
Console.WriteLine($"No flag found for {nation}");
|
||||
return [];
|
||||
}
|
||||
|
||||
if (
|
||||
match.Success
|
||||
&& match.Groups[1].Value.Equals(nation, StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
{
|
||||
if (
|
||||
provider.TryLoadPackageObject<UTexture2D>(
|
||||
$"{path}.{fileName}",
|
||||
out var uTexture
|
||||
)
|
||||
)
|
||||
{
|
||||
CTexture? cTexture = uTexture.Decode(ETexturePlatform.DesktopMobile);
|
||||
SKBitmap bitmap = cTexture.ToSkBitmap();
|
||||
SKData data = bitmap.Encode(SKEncodedImageFormat.Webp, 80);
|
||||
|
||||
if (cTexture is null)
|
||||
{
|
||||
Console.WriteLine($"No flag found for {nation}");
|
||||
return [];
|
||||
}
|
||||
|
||||
SKBitmap bitmap = cTexture.ToSkBitmap();
|
||||
SKData data = bitmap.Encode(SKEncodedImageFormat.Webp, 80);
|
||||
|
||||
return data.ToArray();
|
||||
}
|
||||
|
||||
Console.WriteLine($"No flag found for {nation}");
|
||||
return [];
|
||||
}
|
||||
return data.ToArray();
|
||||
}
|
||||
|
||||
Console.WriteLine($"No flag found for {nation}");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ConsumableIcon(string tag)
|
||||
Console.WriteLine($"No flag found for {nation}");
|
||||
return [];
|
||||
}
|
||||
|
||||
public byte[] ConsumableIcon(string tag)
|
||||
{
|
||||
var pda = provider.Discovered<UPrimaryDataAsset>(tag);
|
||||
var icon = pda.Get<FSoftObjectPath>("Icon");
|
||||
return provider.Image(icon);
|
||||
}
|
||||
|
||||
public byte[] EquipmentIcon(string tag)
|
||||
{
|
||||
var pda = provider.Discovered<UPrimaryDataAsset>(tag);
|
||||
var icon = pda.Get<FSoftObjectPath>("Icon");
|
||||
return provider.Image(icon);
|
||||
}
|
||||
|
||||
readonly Dictionary<string, string> tankPartPrefixes = new()
|
||||
{
|
||||
{ "chassis", "DT_Chassis" },
|
||||
{ "hull", "DT_Hulls" },
|
||||
{ "turret", "DT_Turrets" },
|
||||
{ "gun", "DT_Guns" },
|
||||
};
|
||||
|
||||
public MappedGltf TankPart(string tag, string part)
|
||||
{
|
||||
var pda = provider.Discovered<UPrimaryDataAsset>(tag);
|
||||
UDataTable? dataTable = null;
|
||||
|
||||
foreach (var (prefix, name) in tankPartPrefixes)
|
||||
{
|
||||
var pda = provider.Discovered<UPrimaryDataAsset>(tag);
|
||||
var icon = pda.Get<FSoftObjectPath>("Icon");
|
||||
return provider.Image(icon);
|
||||
if (!part.StartsWith(prefix))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
dataTable = pda.Get<UDataTable>(name);
|
||||
break;
|
||||
}
|
||||
|
||||
public byte[] EquipmentIcon(string tag)
|
||||
if (dataTable == null)
|
||||
{
|
||||
var pda = provider.Discovered<UPrimaryDataAsset>(tag);
|
||||
var icon = pda.Get<FSoftObjectPath>("Icon");
|
||||
return provider.Image(icon);
|
||||
throw new ArgumentException($"Unknown tank part: {part}");
|
||||
}
|
||||
|
||||
readonly Dictionary<string, string> tankPartPrefixes = new()
|
||||
dataTable.TryGetDataTableRow(part, StringComparison.Ordinal, out var row);
|
||||
|
||||
if (row == null)
|
||||
{
|
||||
{ "chassis", "DT_Chassis" },
|
||||
{ "hull", "DT_Hulls" },
|
||||
{ "turret", "DT_Turrets" },
|
||||
{ "gun", "DT_Guns" },
|
||||
};
|
||||
|
||||
public byte[] TankPart(string tag, string part)
|
||||
{
|
||||
var pda = provider.Discovered<UPrimaryDataAsset>(tag);
|
||||
UDataTable? dataTable = null;
|
||||
|
||||
foreach (var (prefix, name) in tankPartPrefixes)
|
||||
{
|
||||
if (!part.StartsWith(prefix))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
dataTable = pda.Get<UDataTable>(name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dataTable == null)
|
||||
{
|
||||
throw new ArgumentException($"Unknown tank part: {part}");
|
||||
}
|
||||
|
||||
dataTable.TryGetDataTableRow(part, StringComparison.Ordinal, out var row);
|
||||
|
||||
if (row == null)
|
||||
{
|
||||
throw new ArgumentException($"Unknown tank part: {part}");
|
||||
}
|
||||
|
||||
var visualData = row.Get<UObject>("VisualData");
|
||||
var meshSettings = visualData.Get<FStructFallback>("MeshSettings");
|
||||
// var collisionMesh = meshSettings.Get<UStaticMesh>("CollisionMesh");
|
||||
var mesh = meshSettings.Get<UStaticMesh>("GunMesh");
|
||||
var gltf = new MonoGltf(mesh);
|
||||
|
||||
return [.. gltf.Write()];
|
||||
throw new ArgumentException($"Unknown tank part: {part}");
|
||||
}
|
||||
|
||||
var visualData = row.Get<UObject>("VisualData");
|
||||
var meshSettings = visualData.Get<FStructFallback>("MeshSettings");
|
||||
// var collisionMesh = meshSettings.Get<UStaticMesh>("CollisionMesh");
|
||||
var mesh = meshSettings.Get<UStaticMesh>("Mesh");
|
||||
var gltf = new MonoGltf(mesh);
|
||||
|
||||
return gltf.Write();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Microsoft.JavaScript.NodeApi;
|
||||
using SharpGLTF.Materials;
|
||||
|
||||
namespace BlitzKit.Game.JSExport;
|
||||
|
||||
[JSExport]
|
||||
public readonly struct MappedGltf
|
||||
{
|
||||
public string Json { get; }
|
||||
public Dictionary<string, Dictionary<KnownChannel, string>> TextureMap { get; }
|
||||
|
||||
public MappedGltf(string json, Dictionary<string, Dictionary<KnownChannel, string>> textureMap)
|
||||
{
|
||||
Json = json;
|
||||
TextureMap = textureMap;
|
||||
}
|
||||
}
|
||||
+199
-243
@@ -1,4 +1,6 @@
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using BlitzKit.Game.JSExport;
|
||||
using CUE4Parse_Conversion;
|
||||
using CUE4Parse_Conversion.Materials;
|
||||
using CUE4Parse_Conversion.Meshes;
|
||||
@@ -13,270 +15,224 @@ using CUE4Parse.UE4.Objects.Meshes;
|
||||
using SharpGLTF.Geometry;
|
||||
using SharpGLTF.Geometry.VertexTypes;
|
||||
using SharpGLTF.Materials;
|
||||
using SharpGLTF.Memory;
|
||||
using SharpGLTF.Scenes;
|
||||
using SharpGLTF.Schema2;
|
||||
using SharpGLTF.Validation;
|
||||
|
||||
namespace BlitzKit.Game.Models;
|
||||
|
||||
using ConfiguredMeshBuilder = MeshBuilder<
|
||||
VertexPositionNormalTangent,
|
||||
VertexColorXTextureX,
|
||||
VertexEmpty
|
||||
VertexPositionNormalTangent,
|
||||
VertexColorXTextureX,
|
||||
VertexEmpty
|
||||
>;
|
||||
|
||||
public class MonoGltf
|
||||
{
|
||||
readonly SceneBuilder Scene;
|
||||
readonly SceneBuilder scene;
|
||||
readonly Dictionary<string, Dictionary<KnownChannel, string>> textureMap = [];
|
||||
|
||||
public MonoGltf(UStaticMesh staticMesh)
|
||||
readonly Dictionary<string, KnownChannel> knownChannels = new()
|
||||
{
|
||||
{ "BaseColor", KnownChannel.BaseColor },
|
||||
{ "Normal", KnownChannel.Normal },
|
||||
{ "RMAO", KnownChannel.MetallicRoughness },
|
||||
// { "CDE", ?? },
|
||||
};
|
||||
|
||||
public MonoGltf(UStaticMesh staticMesh)
|
||||
{
|
||||
scene = new(staticMesh.Name);
|
||||
var options = new ExporterOptions() { TextureFormat = ETextureFormat.Jpeg };
|
||||
|
||||
staticMesh.TryConvert(out var convertedMesh);
|
||||
var lod =
|
||||
convertedMesh.LODs.Find(lod => !lod.SkipLod) ?? throw new Exception("Failed to find lod0");
|
||||
|
||||
MaterialBuilder emptyMaterial = new("empty_material");
|
||||
Dictionary<string, MaterialBuilder> materialMap = [];
|
||||
|
||||
int sectionIndex = 0;
|
||||
foreach (var section in lod.Sections.Value)
|
||||
{
|
||||
Scene = new(staticMesh.Name);
|
||||
ExporterOptions options = new() { TextureFormat = ETextureFormat.Jpeg };
|
||||
staticMesh.TryConvert(out var convertedMesh);
|
||||
var lod =
|
||||
convertedMesh.LODs.Find(lod => !lod.SkipLod)
|
||||
?? throw new Exception("Failed to find lod0");
|
||||
ConfiguredMeshBuilder meshBuilder = new($"{staticMesh.Name}_section_{sectionIndex}");
|
||||
MaterialBuilder materialBuilder;
|
||||
|
||||
MaterialBuilder emptyMaterial = new("empty_material");
|
||||
Dictionary<string, MaterialBuilder> namedMaterials = [];
|
||||
if (section.Material == null || section.MaterialName == null)
|
||||
{
|
||||
materialBuilder = emptyMaterial;
|
||||
}
|
||||
else if (materialMap.TryGetValue(section.MaterialName, out MaterialBuilder? value))
|
||||
{
|
||||
materialBuilder = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var materialInterface = section.Material.Load<UMaterialInterface>()!;
|
||||
var materialData = new MaterialData() { Parameters = new() };
|
||||
|
||||
Console.WriteLine(lod.Sections.Value.Length);
|
||||
materialInterface.GetParams(materialData.Parameters, options.MaterialFormat);
|
||||
materialBuilder = new(section.MaterialName);
|
||||
|
||||
int sectionIndex = 0;
|
||||
foreach (var section in lod.Sections.Value)
|
||||
var textures = new Dictionary<KnownChannel, string>();
|
||||
|
||||
materialMap.Add(section.MaterialName, materialBuilder);
|
||||
textureMap.Add(section.MaterialName, textures);
|
||||
|
||||
foreach (var parameterTexture in materialData.Parameters.Textures)
|
||||
{
|
||||
Console.WriteLine(section.MaterialName);
|
||||
if (knownChannels.TryGetValue(parameterTexture.Key, out var channel))
|
||||
{
|
||||
var texture = parameterTexture.Value;
|
||||
var name = Path.GetFileNameWithoutExtension(texture.GetPathName());
|
||||
var path = $"/textures/{name}";
|
||||
// var path = texture.GetPathName();
|
||||
|
||||
ConfiguredMeshBuilder meshBuilder = new($"{staticMesh.Name}_section_{sectionIndex}");
|
||||
MaterialBuilder materialBuilder;
|
||||
|
||||
if (section.Material == null || section.MaterialName == null)
|
||||
{
|
||||
materialBuilder = emptyMaterial;
|
||||
}
|
||||
else if (namedMaterials.TryGetValue(section.MaterialName, out MaterialBuilder? value))
|
||||
{
|
||||
materialBuilder = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var materialInterface = section.Material.Load<UMaterialInterface>()!;
|
||||
MaterialData materialData = new() { Textures = [], Parameters = new() };
|
||||
materialInterface.GetParams(materialData.Parameters, options.MaterialFormat);
|
||||
materialBuilder = new(section.MaterialName);
|
||||
|
||||
foreach (var parameterTexture in materialData.Parameters.Textures)
|
||||
{
|
||||
var texture = parameterTexture.Value;
|
||||
|
||||
if (
|
||||
texture is not UTexture2D texture2d
|
||||
|| texture2d.Decode(options.Platform) is not { } bitmap
|
||||
)
|
||||
{
|
||||
Console.WriteLine($"Failed to decode texture: {texture?.Name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (parameterTexture.Key)
|
||||
{
|
||||
case "BaseColor":
|
||||
{
|
||||
var encoded = bitmap.Encode(options.TextureFormat, false, out var _);
|
||||
var bytes = encoded.ToArray();
|
||||
materialBuilder.WithBaseColor(bytes);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "Normal":
|
||||
{
|
||||
var encoded = bitmap.Encode(options.TextureFormat, false, out var _);
|
||||
var bytes = encoded.ToArray();
|
||||
materialBuilder.WithNormal(bytes);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "RMAO":
|
||||
{
|
||||
var encoded = bitmap.Encode(options.TextureFormat, false, out var _);
|
||||
|
||||
// for (int y = 0; y < bitmap.Height; y++)
|
||||
// {
|
||||
// for (int x = 0; x < bitmap.Width; x++)
|
||||
// {
|
||||
// var index = y * bitmap.Width + x;
|
||||
// var color = bitmap.Pixels[index];
|
||||
// bitmap.Pixels[index] = new(
|
||||
// color.Blue,
|
||||
// color.Red,
|
||||
// color.Green,
|
||||
// color.Alpha
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
var bytes = encoded.ToArray();
|
||||
materialBuilder.WithBaseColor(bytes);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "CDE":
|
||||
{
|
||||
// idk wtf this is
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Console.WriteLine($"Unsupported texture type: {parameterTexture.Key}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var primitive = meshBuilder.UsePrimitive(materialBuilder);
|
||||
|
||||
Console.WriteLine($"faces: {section.NumFaces}");
|
||||
|
||||
for (int faceIndex = 0; faceIndex < section.NumFaces; faceIndex++)
|
||||
{
|
||||
var wedgeIndex = new int[3];
|
||||
for (var k = 0; k < wedgeIndex.Length; k++)
|
||||
{
|
||||
wedgeIndex[k] = (int)lod.Indices.Value[section.FirstIndex + faceIndex * 3 + k];
|
||||
}
|
||||
|
||||
var vertex1 = lod.Verts[wedgeIndex[0]];
|
||||
var vertex2 = lod.Verts[wedgeIndex[1]];
|
||||
var vertex3 = lod.Verts[wedgeIndex[2]];
|
||||
|
||||
var (v1, v2, v3) = PrepareTris(vertex1, vertex2, vertex3);
|
||||
var (c1, c2, c3) = PrepareUVsAndTexCoords(
|
||||
lod,
|
||||
vertex1,
|
||||
vertex2,
|
||||
vertex3,
|
||||
wedgeIndex
|
||||
);
|
||||
|
||||
primitive.AddTriangle((v1, c1), (v2, c2), (v3, c3));
|
||||
}
|
||||
|
||||
Scene.AddRigidMesh(meshBuilder, Matrix4x4.Identity);
|
||||
textures.Add(channel, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Console.WriteLine($"Unsupported texture type: {parameterTexture.Key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ArraySegment<byte> Write()
|
||||
{
|
||||
return Scene.ToGltf2().WriteGLB();
|
||||
}
|
||||
var primitive = meshBuilder.UsePrimitive(materialBuilder);
|
||||
|
||||
private static (
|
||||
VertexPositionNormalTangent,
|
||||
VertexPositionNormalTangent,
|
||||
VertexPositionNormalTangent
|
||||
) PrepareTris(CMeshVertex vert1, CMeshVertex vert2, CMeshVertex vert3)
|
||||
{
|
||||
VertexPositionNormalTangent v1 = new(
|
||||
SwapYZ(vert1.Position * 0.01f),
|
||||
SwapYZAndNormalize((FVector)vert1.Normal),
|
||||
SwapYZAndNormalize((Vector4)vert1.Tangent)
|
||||
);
|
||||
VertexPositionNormalTangent v2 = new(
|
||||
SwapYZ(vert2.Position * 0.01f),
|
||||
SwapYZAndNormalize((FVector)vert2.Normal),
|
||||
SwapYZAndNormalize((Vector4)vert2.Tangent)
|
||||
);
|
||||
VertexPositionNormalTangent v3 = new(
|
||||
SwapYZ(vert3.Position * 0.01f),
|
||||
SwapYZAndNormalize((FVector)vert3.Normal),
|
||||
SwapYZAndNormalize((Vector4)vert3.Tangent)
|
||||
);
|
||||
|
||||
return (v1, v2, v3);
|
||||
}
|
||||
|
||||
public static FVector SwapYZ(FVector vec)
|
||||
{
|
||||
var res = new FVector(vec.X, vec.Z, vec.Y);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static FVector SwapYZAndNormalize(FVector vec)
|
||||
{
|
||||
var res = SwapYZ(vec);
|
||||
res.Normalize();
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Vector4 SwapYZAndNormalize(Vector4 vec)
|
||||
{
|
||||
return Vector4.Normalize(new Vector4(vec.X, vec.Z, vec.Y, vec.W));
|
||||
}
|
||||
|
||||
public static (
|
||||
VertexColorXTextureX,
|
||||
VertexColorXTextureX,
|
||||
VertexColorXTextureX
|
||||
) PrepareUVsAndTexCoords(
|
||||
CBaseMeshLod lod,
|
||||
CMeshVertex vert1,
|
||||
CMeshVertex vert2,
|
||||
CMeshVertex vert3,
|
||||
int[] indices
|
||||
)
|
||||
{
|
||||
return PrepareUVsAndTexCoords(
|
||||
lod.VertexColors ?? new FColor[lod.NumVerts],
|
||||
vert1,
|
||||
vert2,
|
||||
vert3,
|
||||
lod.ExtraUV.Value,
|
||||
indices
|
||||
);
|
||||
}
|
||||
|
||||
public static (
|
||||
VertexColorXTextureX,
|
||||
VertexColorXTextureX,
|
||||
VertexColorXTextureX
|
||||
) PrepareUVsAndTexCoords(
|
||||
FColor[] colors,
|
||||
CMeshVertex vert1,
|
||||
CMeshVertex vert2,
|
||||
CMeshVertex vert3,
|
||||
FMeshUVFloat[][] uvs,
|
||||
int[] indices
|
||||
)
|
||||
{
|
||||
var (uvs1, uvs2, uvs3) = PrepareUVs(vert1, vert2, vert3, uvs, indices);
|
||||
var c1 = new VertexColorXTextureX((Vector4)colors[indices[0]] / 255, uvs1);
|
||||
var c2 = new VertexColorXTextureX((Vector4)colors[indices[1]] / 255, uvs2);
|
||||
var c3 = new VertexColorXTextureX((Vector4)colors[indices[2]] / 255, uvs3);
|
||||
return (c1, c2, c3);
|
||||
}
|
||||
|
||||
private static (List<Vector2>, List<Vector2>, List<Vector2>) PrepareUVs(
|
||||
CMeshVertex vert1,
|
||||
CMeshVertex vert2,
|
||||
CMeshVertex vert3,
|
||||
FMeshUVFloat[][] uvs,
|
||||
int[] indices
|
||||
)
|
||||
{
|
||||
var uvs1 = new List<Vector2>() { (Vector2)vert1.UV };
|
||||
var uvs2 = new List<Vector2>() { (Vector2)vert2.UV };
|
||||
var uvs3 = new List<Vector2>() { (Vector2)vert3.UV };
|
||||
foreach (var uv in uvs)
|
||||
for (int faceIndex = 0; faceIndex < section.NumFaces; faceIndex++)
|
||||
{
|
||||
var wedgeIndex = new int[3];
|
||||
for (var k = 0; k < wedgeIndex.Length; k++)
|
||||
{
|
||||
uvs1.Add((Vector2)uv[indices[0]]);
|
||||
uvs2.Add((Vector2)uv[indices[1]]);
|
||||
uvs3.Add((Vector2)uv[indices[2]]);
|
||||
wedgeIndex[k] = (int)lod.Indices.Value[section.FirstIndex + faceIndex * 3 + k];
|
||||
}
|
||||
|
||||
return (uvs1, uvs2, uvs3);
|
||||
var vertex1 = lod.Verts[wedgeIndex[0]];
|
||||
var vertex2 = lod.Verts[wedgeIndex[1]];
|
||||
var vertex3 = lod.Verts[wedgeIndex[2]];
|
||||
|
||||
var (v1, v2, v3) = PrepareTris(vertex1, vertex2, vertex3);
|
||||
var (c1, c2, c3) = PrepareUVsAndTexCoords(lod, vertex1, vertex2, vertex3, wedgeIndex);
|
||||
|
||||
primitive.AddTriangle((v1, c1), (v2, c2), (v3, c3));
|
||||
}
|
||||
|
||||
scene.AddRigidMesh(meshBuilder, Matrix4x4.Identity);
|
||||
}
|
||||
}
|
||||
|
||||
public MappedGltf Write()
|
||||
{
|
||||
var model = scene.ToGltf2();
|
||||
var json = model.GetJSON(false);
|
||||
|
||||
return new MappedGltf(json, textureMap);
|
||||
}
|
||||
|
||||
private static (
|
||||
VertexPositionNormalTangent,
|
||||
VertexPositionNormalTangent,
|
||||
VertexPositionNormalTangent
|
||||
) PrepareTris(CMeshVertex vert1, CMeshVertex vert2, CMeshVertex vert3)
|
||||
{
|
||||
VertexPositionNormalTangent v1 = new(
|
||||
SwapYZ(vert1.Position * 0.01f),
|
||||
SwapYZAndNormalize((FVector)vert1.Normal),
|
||||
SwapYZAndNormalize((Vector4)vert1.Tangent)
|
||||
);
|
||||
VertexPositionNormalTangent v2 = new(
|
||||
SwapYZ(vert2.Position * 0.01f),
|
||||
SwapYZAndNormalize((FVector)vert2.Normal),
|
||||
SwapYZAndNormalize((Vector4)vert2.Tangent)
|
||||
);
|
||||
VertexPositionNormalTangent v3 = new(
|
||||
SwapYZ(vert3.Position * 0.01f),
|
||||
SwapYZAndNormalize((FVector)vert3.Normal),
|
||||
SwapYZAndNormalize((Vector4)vert3.Tangent)
|
||||
);
|
||||
|
||||
return (v1, v2, v3);
|
||||
}
|
||||
|
||||
public static FVector SwapYZ(FVector vec)
|
||||
{
|
||||
var res = new FVector(vec.X, vec.Z, vec.Y);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static FVector SwapYZAndNormalize(FVector vec)
|
||||
{
|
||||
var res = SwapYZ(vec);
|
||||
res.Normalize();
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Vector4 SwapYZAndNormalize(Vector4 vec)
|
||||
{
|
||||
return Vector4.Normalize(new Vector4(vec.X, vec.Z, vec.Y, vec.W));
|
||||
}
|
||||
|
||||
public static (
|
||||
VertexColorXTextureX,
|
||||
VertexColorXTextureX,
|
||||
VertexColorXTextureX
|
||||
) PrepareUVsAndTexCoords(
|
||||
CBaseMeshLod lod,
|
||||
CMeshVertex vert1,
|
||||
CMeshVertex vert2,
|
||||
CMeshVertex vert3,
|
||||
int[] indices
|
||||
)
|
||||
{
|
||||
return PrepareUVsAndTexCoords(
|
||||
lod.VertexColors ?? new FColor[lod.NumVerts],
|
||||
vert1,
|
||||
vert2,
|
||||
vert3,
|
||||
lod.ExtraUV.Value,
|
||||
indices
|
||||
);
|
||||
}
|
||||
|
||||
public static (
|
||||
VertexColorXTextureX,
|
||||
VertexColorXTextureX,
|
||||
VertexColorXTextureX
|
||||
) PrepareUVsAndTexCoords(
|
||||
FColor[] colors,
|
||||
CMeshVertex vert1,
|
||||
CMeshVertex vert2,
|
||||
CMeshVertex vert3,
|
||||
FMeshUVFloat[][] uvs,
|
||||
int[] indices
|
||||
)
|
||||
{
|
||||
var (uvs1, uvs2, uvs3) = PrepareUVs(vert1, vert2, vert3, uvs, indices);
|
||||
var c1 = new VertexColorXTextureX((Vector4)colors[indices[0]] / 255, uvs1);
|
||||
var c2 = new VertexColorXTextureX((Vector4)colors[indices[1]] / 255, uvs2);
|
||||
var c3 = new VertexColorXTextureX((Vector4)colors[indices[2]] / 255, uvs3);
|
||||
return (c1, c2, c3);
|
||||
}
|
||||
|
||||
private static (List<Vector2>, List<Vector2>, List<Vector2>) PrepareUVs(
|
||||
CMeshVertex vert1,
|
||||
CMeshVertex vert2,
|
||||
CMeshVertex vert3,
|
||||
FMeshUVFloat[][] uvs,
|
||||
int[] indices
|
||||
)
|
||||
{
|
||||
var uvs1 = new List<Vector2>() { (Vector2)vert1.UV };
|
||||
var uvs2 = new List<Vector2>() { (Vector2)vert2.UV };
|
||||
var uvs3 = new List<Vector2>() { (Vector2)vert3.UV };
|
||||
foreach (var uv in uvs)
|
||||
{
|
||||
uvs1.Add((Vector2)uv[indices[0]]);
|
||||
uvs2.Add((Vector2)uv[indices[1]]);
|
||||
uvs3.Add((Vector2)uv[indices[2]]);
|
||||
}
|
||||
|
||||
return (uvs1, uvs2, uvs3);
|
||||
}
|
||||
}
|
||||
@@ -35,8 +35,8 @@ export async function GET({
|
||||
const item = api.metadata.item(params.id);
|
||||
const assetDiscovery = item.BlitzStaticAssetsDiscovery();
|
||||
const tag = assertDiscoveryTag(assetDiscovery);
|
||||
const part = game!.tankPart(tag, params.part);
|
||||
const array = new Uint8Array(part);
|
||||
const asd = game!.tankPart(tag, params.part);
|
||||
// const array = new Uint8Array(part);
|
||||
|
||||
return new Response(array);
|
||||
return Response.json(asd);
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 886 KiB |
Reference in new issue
Block a user