Compare commits

..

4 Commits

4 changed files with 165 additions and 29 deletions

View File

@ -17,6 +17,7 @@ public class ResourcePathManager
private bool _initialised = false; private bool _initialised = false;
private readonly string _extractionPath; private readonly string _extractionPath;
private string _fmsDir;
private CampaignResources _omResources; private CampaignResources _omResources;
private Dictionary<string, CampaignResources> _fmResources; private Dictionary<string, CampaignResources> _fmResources;
@ -74,6 +75,7 @@ public class ResourcePathManager
objectPathMap = objectPathMap, objectPathMap = objectPathMap,
}; };
_fmResources.Add(campaign, resource); _fmResources.Add(campaign, resource);
_fmsDir = fmsDir;
} }
} }
@ -162,28 +164,65 @@ public class ResourcePathManager
return null; return null;
} }
public string GetObjectPath(string objectName)
{
if (!_initialised) return null;
objectName = objectName.ToLower();
if (_omResources.objectPathMap.TryGetValue(objectName, out var path))
{
return path;
}
return null;
}
public string GetObjectPath(string campaignName, string objectName) public string GetObjectPath(string campaignName, string objectName)
{ {
if (!_initialised) return null; if (!_initialised) return null;
objectName = objectName.ToLower(); objectName = objectName.ToLower();
if (_fmResources.TryGetValue(campaignName, out var campaign) && if (campaignName == null || campaignName == "")
campaign.objectPathMap.TryGetValue(objectName, out var path))
{ {
return path; if (_omResources.objectPathMap.TryGetValue(objectName, out var omPath))
{
return omPath;
}
} }
if (_fmResources.TryGetValue(campaignName, out var campaign))
{
if (campaign.objectPathMap.TryGetValue(objectName, out var fmPath))
{
return fmPath;
}
else if (_omResources.objectPathMap.TryGetValue(objectName, out var omPath))
{
return omPath;
}
}
return null;
}
// TODO: Store these as part of the resources
public string GetObjectTexturePath(string campaignName, string textureName)
{
var options = new EnumerationOptions
{
MatchCasing = MatchCasing.CaseInsensitive,
RecurseSubdirectories = true,
};
textureName = textureName.ToLower();
var omDir = Path.Join(_extractionPath, "obj");
var omPaths = Directory.GetFiles(omDir, textureName, options);
if (campaignName == null || campaignName == "")
{
if (omPaths.Length > 0)
{
return omPaths[0];
}
}
else if (_fmResources.TryGetValue(campaignName, out var campaign))
{
var fmDir = Path.Join(_fmsDir, campaignName);
var fmPaths = Directory.GetFiles(Path.Join(fmDir, "obj"), textureName, options);
if (fmPaths.Length > 0)
{
return fmPaths[0];
}
else if (omPaths.Length > 0)
{
return omPaths[0];
}
}
return null; return null;
} }

View File

@ -164,25 +164,18 @@ public partial class Mission : Node3D
// Let's try and place an object :) // Let's try and place an object :)
var modelName = modelNameProp.modelName + ".bin"; var modelName = modelNameProp.modelName + ".bin";
var fmName = FileName.GetBaseDir().GetFile(); // TODO: Doesn't work for OMs
var objPath = _installPaths.GetObjectPath(fmName, modelName);
objPath ??= _installPaths.GetObjectPath(modelName);
var pos = brush.position.ToGodotVec3(); var pos = brush.position.ToGodotVec3();
var rawRot = brush.angle; var rawRot = brush.angle;
var rot = new Vector3(rawRot.Y, rawRot.Z, rawRot.X) * 360 / ushort.MaxValue; var rot = new Vector3(rawRot.Y, rawRot.Z, rawRot.X) * 360 / ushort.MaxValue;
var scale = scaleProp == null ? Vector3.One : scaleProp.scale.ToGodotVec3(false); var scale = scaleProp == null ? Vector3.One : scaleProp.scale.ToGodotVec3(false);
var model = new Model var model = ModelLoader.LoadModel(_installPaths, _campaignName, modelName);
if (model != null)
{ {
Position = pos, model.Position = pos;
RotationDegrees = rot, model.RotationDegrees = rot;
Scale = scale, model.Scale = scale;
}; AddChild(model);
if (objPath != null)
{
model.BuildModel("", objPath);
} }
AddChild(model);
} }
} }

View File

@ -29,7 +29,7 @@ public partial class Model : Node3D
} }
// TODO: Remove this disgusting hack. Not only is it a hack, it doesn't support custom models // TODO: Remove this disgusting hack. Not only is it a hack, it doesn't support custom models
var baseDir = ProjectSettings.GlobalizePath($"user://objects/tmp"); var baseDir = Path.GetDirectoryName(modelPath);
var options = new EnumerationOptions var options = new EnumerationOptions
{ {
MatchCasing = MatchCasing.CaseInsensitive, MatchCasing = MatchCasing.CaseInsensitive,

View File

@ -0,0 +1,104 @@
using System.Collections.Generic;
using System.IO;
using Godot;
using KeepersCompound.LGS;
namespace KeepersCompound.TMV;
public static class ModelLoader
{
public static MeshInstance3D LoadModel(ResourcePathManager pathManager, string campaignName, string modelName)
{
var modelPath = pathManager.GetObjectPath(campaignName, modelName);
if (modelPath == null)
{
return null;
}
var modelFile = new ModelFile(modelPath);
if (modelFile == null)
{
GD.Print($"Failed to load model file: {modelPath}");
return null;
}
var materials = new List<StandardMaterial3D>();
foreach (var material in modelFile.Materials)
{
if (material.Type == 0)
{
var path = pathManager.GetObjectTexturePath(campaignName, material.Name);
if (path == null)
{
GD.Print($"Failed to load model texture: {material.Name}");
continue;
}
materials.Add(new StandardMaterial3D
{
AlbedoTexture = TextureLoader.LoadTexture(path)
});
}
else
{
var b = (material.Handle) & 0xff;
var g = (material.Handle >> 8) & 0xff;
var r = (material.Handle >> 16) & 0xff;
var colour = new Color(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
materials.Add(new StandardMaterial3D
{
AlbedoColor = colour
});
}
}
var surfaceDataMap = new Dictionary<int, MeshSurfaceData>();
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);
}
}
if (!surfaceDataMap.ContainsKey(poly.Data))
{
surfaceDataMap.Add(poly.Data, new MeshSurfaceData());
}
surfaceDataMap[poly.Data].AddPolygon(vertices, normal, uvs, uvs);
}
var mesh = new ArrayMesh();
foreach (var (materialId, surfaceData) in surfaceDataMap)
{
var array = surfaceData.BuildSurfaceArray();
var surfaceIdx = mesh.GetSurfaceCount();
mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, array);
for (var i = 0; i < materials.Count; i++)
{
var m = modelFile.Materials[i];
if (m.Slot == materialId)
{
mesh.SurfaceSetMaterial(surfaceIdx, materials[i]);
break;
}
}
}
var pos = -modelFile.Header.Center.ToGodotVec3();
var meshInstance = new MeshInstance3D { Mesh = mesh, Position = pos };
return meshInstance;
}
}