Compare commits
10 Commits
b5d3a3c275
...
6db4d75a37
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | 6db4d75a37 | |
Jarrod Doyle | 20cf0f7292 | |
Jarrod Doyle | 5aafab148b | |
Jarrod Doyle | 30db43eac8 | |
Jarrod Doyle | 2db83a827e | |
Jarrod Doyle | 6340a4c545 | |
Jarrod Doyle | 8a22defe17 | |
Jarrod Doyle | d9a54b65d5 | |
Jarrod Doyle | 66c324be53 | |
Jarrod Doyle | 2c9958a64a |
|
@ -8,5 +8,6 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="rectpacksharp" Version="1.2.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -129,19 +129,38 @@ public class ModelFile
|
|||
UvIndices = new ushort[Type == 0x1B ? VertexCount : 0];
|
||||
for (var i = 0; i < UvIndices.Length; i++)
|
||||
{
|
||||
LightIndices[i] = reader.ReadUInt16();
|
||||
UvIndices[i] = reader.ReadUInt16();
|
||||
}
|
||||
|
||||
Material = version == 4 ? reader.ReadByte() : (byte)0;
|
||||
}
|
||||
}
|
||||
|
||||
public struct Material
|
||||
{
|
||||
public string Name;
|
||||
public byte Type;
|
||||
public byte Slot;
|
||||
public uint Handle;
|
||||
public float Uv;
|
||||
|
||||
public Material(BinaryReader reader)
|
||||
{
|
||||
Name = Encoding.UTF8.GetString(reader.ReadBytes(16)).Replace("\0", string.Empty);
|
||||
Type = reader.ReadByte();
|
||||
Slot = reader.ReadByte();
|
||||
Handle = reader.ReadUInt32();
|
||||
Uv = reader.ReadSingle();
|
||||
}
|
||||
}
|
||||
|
||||
public BHeader BinHeader { get; set; }
|
||||
public MHeader Header { get; set; }
|
||||
public Vector3[] Vertices { get; }
|
||||
public Vector2[] Uvs { get; }
|
||||
public Vector3[] Normals { get; }
|
||||
public Polygon[] Polygons { get; }
|
||||
public Material[] Materials { get; }
|
||||
|
||||
public ModelFile(string filename)
|
||||
{
|
||||
|
@ -178,5 +197,11 @@ public class ModelFile
|
|||
{
|
||||
Polygons[i] = new Polygon(reader, BinHeader.Version);
|
||||
}
|
||||
stream.Seek(Header.MaterialOffset, SeekOrigin.Begin);
|
||||
Materials = new Material[Header.MaterialCount];
|
||||
for (var i = 0; i < Materials.Length; i++)
|
||||
{
|
||||
Materials[i] = new Material(reader);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,19 +12,19 @@ public class MeshSurfaceData
|
|||
private readonly List<Vector3> _vertices = new();
|
||||
private readonly List<Vector3> _normals = new();
|
||||
private readonly List<int> _indices = new();
|
||||
private readonly List<Vector2> _textureUvs = new();
|
||||
private readonly List<Vector2> _lightmapUvs = new();
|
||||
private readonly List<Vector2> _uv1s = new();
|
||||
private readonly List<Vector2> _uv2s = new();
|
||||
|
||||
public MeshSurfaceData()
|
||||
{
|
||||
Empty = true;
|
||||
}
|
||||
|
||||
public void TransformLightmapUvs(int start, int end, Func<Vector2, Vector2> f)
|
||||
public void TransformUv2s(int start, int end, Func<Vector2, Vector2> f)
|
||||
{
|
||||
for (var i = start; i < end; i++)
|
||||
{
|
||||
_lightmapUvs[i] = f(_lightmapUvs[i]);
|
||||
_uv2s[i] = f(_uv2s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,8 @@ public class MeshSurfaceData
|
|||
public (int, int) AddPolygon(
|
||||
List<Vector3> vertices,
|
||||
Vector3 normal,
|
||||
List<Vector2> textureUvs,
|
||||
List<Vector2> lightmapUvs)
|
||||
List<Vector2> uv1s,
|
||||
List<Vector2> uv2s)
|
||||
{
|
||||
Empty = false;
|
||||
|
||||
|
@ -54,11 +54,11 @@ public class MeshSurfaceData
|
|||
_indices.Add(indexOffset + j + 1);
|
||||
}
|
||||
|
||||
_textureUvs.AddRange(textureUvs);
|
||||
_lightmapUvs.AddRange(lightmapUvs);
|
||||
_uv1s.AddRange(uv1s);
|
||||
_uv2s.AddRange(uv2s);
|
||||
|
||||
var end = _lightmapUvs.Count;
|
||||
var start = end - lightmapUvs.Count;
|
||||
var end = _uv2s.Count;
|
||||
var start = end - uv2s.Count;
|
||||
return (start, end);
|
||||
}
|
||||
|
||||
|
@ -69,8 +69,8 @@ public class MeshSurfaceData
|
|||
array[(int)Mesh.ArrayType.Vertex] = _vertices.ToArray();
|
||||
array[(int)Mesh.ArrayType.Normal] = _normals.ToArray();
|
||||
array[(int)Mesh.ArrayType.Index] = _indices.ToArray();
|
||||
array[(int)Mesh.ArrayType.TexUV] = _textureUvs.ToArray();
|
||||
array[(int)Mesh.ArrayType.TexUV2] = _lightmapUvs.ToArray();
|
||||
array[(int)Mesh.ArrayType.TexUV] = _uv1s.ToArray();
|
||||
array[(int)Mesh.ArrayType.TexUV2] = _uv2s.ToArray();
|
||||
|
||||
return array;
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ public partial class Mission : Node3D
|
|||
}
|
||||
|
||||
if (!surfaceDataMap.ContainsKey(info.textureId)) GD.Print("Invalid SurfaceDataMap key");
|
||||
surfaceDataMap[info.textureId].TransformLightmapUvs(info.uvStart, info.uvEnd, (uv) =>
|
||||
surfaceDataMap[info.textureId].TransformUv2s(info.uvStart, info.uvEnd, (uv) =>
|
||||
{
|
||||
var u = uv.X;
|
||||
var v = uv.Y;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using KeepersCompound.LGS;
|
||||
using KeepersCompound.TMV.UI;
|
||||
|
||||
|
@ -24,34 +24,80 @@ public partial class Model : Node3D
|
|||
var modelFile = new ModelFile(modelPath);
|
||||
if (modelFile == null)
|
||||
{
|
||||
GD.Print("UH OH");
|
||||
GD.Print($"Failed to load model file: {modelPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
var vertices = new List<Vector3>();
|
||||
var indices = new List<int>();
|
||||
|
||||
foreach (var v in modelFile.Vertices)
|
||||
// TODO: Remove this disgusting hack
|
||||
var baseDir = ProjectSettings.GlobalizePath($"user://objects/tmp");
|
||||
var options = new EnumerationOptions
|
||||
{
|
||||
vertices.Add(v.ToGodotVec3());
|
||||
}
|
||||
|
||||
foreach (var poly in modelFile.Polygons)
|
||||
MatchCasing = MatchCasing.CaseInsensitive,
|
||||
RecurseSubdirectories = true,
|
||||
};
|
||||
var materials = new List<StandardMaterial3D>();
|
||||
foreach (var material in modelFile.Materials)
|
||||
{
|
||||
for (var i = 1; i < poly.VertexCount - 1; i++)
|
||||
if (material.Type == 0)
|
||||
{
|
||||
indices.Add(poly.VertexIndices[0]);
|
||||
indices.Add(poly.VertexIndices[i]);
|
||||
indices.Add(poly.VertexIndices[i + 1]);
|
||||
var paths = Directory.GetFiles(baseDir, material.Name, options);
|
||||
if (paths.IsEmpty()) continue;
|
||||
|
||||
materials.Add(new StandardMaterial3D
|
||||
{
|
||||
AlbedoTexture = TextureLoader.LoadTexture(paths[0])
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var b = (material.Handle) & 0xff;
|
||||
var g = (material.Handle >> 8) & 0xff;
|
||||
var r = (material.Handle >> 16) & 0xff;
|
||||
GD.Print($"Handle: {material.Handle}, R: {r}, G: {g}, B: {b}");
|
||||
var colour = new Color(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
|
||||
materials.Add(new StandardMaterial3D
|
||||
{
|
||||
AlbedoColor = colour
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var array = new Array();
|
||||
array.Resize((int)Mesh.ArrayType.Max);
|
||||
array[(int)Mesh.ArrayType.Vertex] = vertices.ToArray();
|
||||
array[(int)Mesh.ArrayType.Index] = indices.ToArray();
|
||||
|
||||
var mesh = new ArrayMesh();
|
||||
mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, array);
|
||||
foreach (var poly in modelFile.Polygons)
|
||||
{
|
||||
var vertices = new List<Vector3>();
|
||||
var normal = modelFile.Normals[poly.Normal].ToGodotVec3();
|
||||
var uvs = new List<Vector2>();
|
||||
for (var i = 0; i < poly.VertexCount; i++)
|
||||
{
|
||||
var vertex = modelFile.Vertices[poly.VertexIndices[i]];
|
||||
vertices.Add(vertex.ToGodotVec3());
|
||||
if (i < poly.UvIndices.Length)
|
||||
{
|
||||
var uv = modelFile.Uvs[poly.UvIndices[i]];
|
||||
uvs.Add(new Vector2(uv.X, uv.Y));
|
||||
}
|
||||
else
|
||||
{
|
||||
uvs.Add(Vector2.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
var surfaceData = new MeshSurfaceData();
|
||||
surfaceData.AddPolygon(vertices, normal, uvs, uvs);
|
||||
var array = surfaceData.BuildSurfaceArray();
|
||||
mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, array);
|
||||
|
||||
for (var i = 0; i < materials.Count; i++)
|
||||
{
|
||||
var m = modelFile.Materials[i];
|
||||
if (m.Slot == poly.Data)
|
||||
{
|
||||
mesh.SurfaceSetMaterial(poly.Index, materials[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var meshInstance = new MeshInstance3D { Mesh = mesh };
|
||||
AddChild(meshInstance);
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
using Godot;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace KeepersCompound.TMV;
|
||||
|
||||
public partial class TextureLoader
|
||||
{
|
||||
// TODO: Replace this with my own implementation lol
|
||||
// References:
|
||||
// - https://www.w3.org/Graphics/GIF/spec-gif89a.txt
|
||||
private static ImageTexture LoadGif(string path)
|
||||
{
|
||||
using var gifImage = SixLabors.ImageSharp.Image.Load<Rgba32>(path);
|
||||
|
||||
var width = gifImage.Width;
|
||||
var height = gifImage.Height;
|
||||
var image = Image.Create(width, height, false, Image.Format.Rgba8);
|
||||
for (var y = 0; y < height; y++)
|
||||
{
|
||||
for (var x = 0; x < width; x++)
|
||||
{
|
||||
var pixel = gifImage[x, y].ToVector4();
|
||||
image.SetPixel(x, y, new Color(pixel.X, pixel.Y, pixel.Z, pixel.W));
|
||||
}
|
||||
}
|
||||
|
||||
return ImageTexture.CreateFromImage(image);
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@ public partial class TextureLoader
|
|||
private static void RegisterTexturePaths(string rootDir, Dictionary<string, string> map)
|
||||
{
|
||||
// TODO: Load DDS BMP GIF CEL
|
||||
string[] validExtensions = { "png", "tga", "pcx" };
|
||||
string[] validExtensions = { "png", "tga", "pcx", "gif" };
|
||||
|
||||
var famOptions = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive };
|
||||
var textureOptions = new EnumerationOptions
|
||||
|
@ -98,12 +98,13 @@ public partial class TextureLoader
|
|||
return loaded;
|
||||
}
|
||||
|
||||
private static ImageTexture LoadTexture(string path)
|
||||
public static ImageTexture LoadTexture(string path)
|
||||
{
|
||||
var ext = path.GetExtension().ToLower();
|
||||
var texture = ext switch
|
||||
{
|
||||
"pcx" => LoadPcx(path),
|
||||
"gif" => LoadGif(path),
|
||||
_ => ImageTexture.CreateFromImage(Image.LoadFromFile(path)),
|
||||
};
|
||||
return texture;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
[ext_resource type="PackedScene" uid="uid://c366p056f8dlu" path="res://project/scenes/ui/model_selector.tscn" id="3_ovrmo"]
|
||||
|
||||
[sub_resource type="Environment" id="Environment_e4172"]
|
||||
ambient_light_source = 2
|
||||
ambient_light_color = Color(1, 1, 1, 1)
|
||||
ssao_enabled = true
|
||||
|
||||
[node name="ModelViewer" type="Node3D"]
|
||||
|
|
Loading…
Reference in New Issue