Compare commits
4 Commits
2365f09931
...
05e90c1a30
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | 05e90c1a30 | |
Jarrod Doyle | b6a65fc10b | |
Jarrod Doyle | e313ca58a7 | |
Jarrod Doyle | 0d7ff677de |
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue