Add model vhots and model light offset/dir

This commit is contained in:
Jarrod Doyle 2024-09-26 20:22:01 +01:00
parent 2420bbef4f
commit d7fcf7a2d8
Signed by: Jayrude
GPG Key ID: 38B57B16E7C0ADF7
2 changed files with 83 additions and 6 deletions

View File

@ -153,6 +153,30 @@ public class ModelFile
}
}
public enum VhotId
{
LightPosition = 1,
LightDirection = 8,
Anchor = 2,
Particle1 = 3,
Particle2 = 4,
Particle3 = 5,
Particle4 = 6,
Particle5 = 7,
}
public struct VHot
{
public int Id;
public Vector3 Position;
public VHot(BinaryReader reader)
{
Id = reader.ReadInt32();
Position = reader.ReadVec3();
}
}
public BHeader BinHeader { get; set; }
public MHeader Header { get; set; }
public Vector3[] Vertices { get; }
@ -160,6 +184,7 @@ public class ModelFile
public Vector3[] Normals { get; }
public Polygon[] Polygons { get; }
public Material[] Materials { get; }
public VHot[] VHots { get; }
public ModelFile(string filename)
{
@ -202,5 +227,25 @@ public class ModelFile
{
Materials[i] = new Material(reader);
}
stream.Seek(Header.VHotOffset, SeekOrigin.Begin);
VHots = new VHot[Header.VHotCount];
for (var i = 0; i < VHots.Length; i++)
{
VHots[i] = new VHot(reader);
}
}
public bool TryGetVhot(VhotId id, out VHot vhot)
{
foreach (var v in VHots)
{
if (v.Id == (int)id)
{
vhot = v;
return true;
}
}
vhot = new VHot();
return false;
}
}

View File

@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Numerics;
using KeepersCompound.LGS;
using KeepersCompound.LGS.Database;
using KeepersCompound.LGS.Database.Chunks;
using TinyEmbree;
@ -27,20 +28,34 @@ class Program
{
Timing.Reset();
var misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/JAYRUDE_Tests/lm_test.cow";
// TODO: Read this from args
var installPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/";
var campaignName = "JAYRUDE_Tests";
var missionName = "lm_test.cow";
// Setup extract path
var tmpDir = Directory.CreateTempSubdirectory("KCLightmapper");
Console.WriteLine(tmpDir.FullName);
var resPathManager = new ResourcePathManager(tmpDir.FullName);
resPathManager.Init(installPath);
var campaign = resPathManager.GetCampaign(campaignName);
var misPath = campaign.GetResourcePath(ResourceType.Mission, missionName);
// misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/JAYRUDE_Tests/lm_test.cow";
// misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/AtdV/miss20.mis";
// misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/TDP20AC_a_burrick_in_a_room/miss20.mis";
Timing.TimeStage("Total", () => LightmapMission(misPath));
Timing.TimeStage("Total", () => LightmapMission(campaign, misPath));
Timing.LogAll();
}
private static void LightmapMission(string misPath)
private static void LightmapMission(ResourcePathManager.CampaignResources campaign, string misPath)
{
var mis = Timing.TimeStage("Parse DB", () => new DbFile(misPath));
var hierarchy = Timing.TimeStage("Build Hierarchy", () => BuildHierarchy(misPath, mis));
var lights = Timing.TimeStage("Gather Lights", () => BuildLightList(mis, hierarchy));
var lights = Timing.TimeStage("Gather Lights", () => BuildLightList(mis, hierarchy, campaign));
// Build embree mesh
if (!mis.Chunks.TryGetValue("WREXT", out var wrRaw))
@ -93,7 +108,7 @@ class Program
}
// Get list of brush lights, and object lights (ignore anim lights for now)
private static List<Light> BuildLightList(DbFile mis, ObjectHierarchy hierarchy)
private static List<Light> BuildLightList(DbFile mis, ObjectHierarchy hierarchy, ResourcePathManager.CampaignResources campaign)
{
var lights = new List<Light>();
@ -120,6 +135,7 @@ class Program
var propLight = hierarchy.GetProperty<PropLight>(id, "P$Light");
var propLightColor = hierarchy.GetProperty<PropLightColor>(id, "P$LightColo");
var propSpotlight = hierarchy.GetProperty<PropSpotlight>(id, "P$Spotlight");
var propModelname = hierarchy.GetProperty<PropLabel>(id, "P$ModelName");
if (propLight != null)
{
@ -134,8 +150,24 @@ class Program
innerRadius = propLight.InnerRadius,
radius = propLight.Radius,
r2 = propLight.Radius * propLight.Radius,
spotlightDir = -Vector3.UnitZ,
};
if (propModelname != null)
{
var resName = $"{propModelname.value.ToLower()}.bin";
var modelPath = campaign.GetResourcePath(ResourceType.Object, resName);
var model = new ModelFile(modelPath);
if (model.TryGetVhot(ModelFile.VhotId.LightPosition, out var vhot))
{
light.position += vhot.Position;
}
if (model.TryGetVhot(ModelFile.VhotId.LightDirection, out vhot))
{
light.spotlightDir = vhot.Position;
}
}
if (propSpotlight != null)
{
// TODO: Some objects seem to have spotlight direction embedded in the model file
@ -145,7 +177,7 @@ class Program
rot *= Matrix4x4.CreateRotationZ(float.DegreesToRadians(brush.angle.Z));
light.spotlight = true;
light.spotlightDir = Vector3.Transform(-Vector3.UnitZ, rot);
light.spotlightDir = Vector3.Transform(light.spotlightDir, rot);
light.spotlightInnerAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.InnerAngle));
light.spotlightOuterAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.OuterAngle));
}