Compare commits

..

No commits in common. "10a8a31520349b24f6bdeb3d6b1f87ff42713431" and "68eed0a821addf8c7a8b348019ea7f6458efcd31" have entirely different histories.

3 changed files with 48 additions and 137 deletions

View File

@ -44,8 +44,7 @@ public class ObjectHierarchy
if (gam != null && gam.Chunks.TryGetValue(name, out var rawGamChunk)) if (gam != null && gam.Chunks.TryGetValue(name, out var rawGamChunk))
{ {
var gamChunk = (T)rawGamChunk; var gamChunk = (T)rawGamChunk;
gamChunk.Merge(chunk); chunk.Merge(gamChunk);
return gamChunk;
} }
return chunk; return chunk;
} }

View File

@ -1,4 +1,4 @@
using System.Numerics; using System.Numerics;
using KeepersCompound.LGS.Database; using KeepersCompound.LGS.Database;
using KeepersCompound.LGS.Database.Chunks; using KeepersCompound.LGS.Database.Chunks;
using TinyEmbree; using TinyEmbree;
@ -18,44 +18,66 @@ class Program
static void Main(string[] args) static void Main(string[] args)
{ {
Timing.Reset();
var misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/JAYRUDE_Tests/lm_test.cow"; var 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"; var mis = new DbFile(misPath);
Timing.TimeStage("Total", () => LightmapMission(misPath)); var hierarchy = BuildHierarchy(misPath, mis);
Timing.LogAll(); // Get list of brush lights, and object lights (ignore anim lights for now)
} var lights = new List<Light>();
if (mis.Chunks.TryGetValue("BRLIST", out var brListRaw))
{
var brList = (BrList)brListRaw;
foreach (var brush in brList.Brushes)
{
if (brush.media == BrList.Brush.Media.Light)
{
var sz = brush.size;
lights.Add(new Light
{
position = brush.position,
color = HsbToRgb(sz.Y, sz.Z, Math.Min(sz.X, 255.0f)),
radius = float.MaxValue,
r2 = float.MaxValue
});
}
else if (brush.media == BrList.Brush.Media.Object)
{
var id = (int)brush.brushInfo;
var light = hierarchy.GetProperty<PropLight>(id, "P$Light");
var lightColor = hierarchy.GetProperty<PropLightColor>(id, "P$LightColo");
private static void LightmapMission(string misPath) if (light != null)
{ {
var mis = Timing.TimeStage("Parse DB", () => new DbFile(misPath)); lightColor ??= new PropLightColor { Hue = 0, Saturation = 0 };
var hierarchy = Timing.TimeStage("Build Hierarchy", () => BuildHierarchy(misPath, mis)); lights.Add(new Light
{
var lights = Timing.TimeStage("Gather Lights", () => BuildLightList(mis, hierarchy)); position = brush.position,
color = HsbToRgb(lightColor.Hue, lightColor.Saturation, light.Brightness),
radius = light.Radius,
r2 = light.Radius * light.Radius,
});
}
}
}
}
// Build embree mesh // Build embree mesh
if (!mis.Chunks.TryGetValue("WREXT", out var wrRaw)) if (!mis.Chunks.TryGetValue("WREXT", out var wrRaw))
return; return;
var worldRep = (WorldRep)wrRaw; var worldRep = (WorldRep)wrRaw;
var scene = Timing.TimeStage("Build Scene", () => var scene = new Raytracer();
{ scene.AddMesh(BuildWrMesh(worldRep));
var rt = new Raytracer(); scene.CommitScene();
rt.AddMesh(BuildWrMesh(worldRep));
rt.CommitScene();
return rt;
});
// For each lightmap pixel cast against all the brush and object lights // For each lightmap pixel cast against all the brush and object lights
if (!mis.Chunks.TryGetValue("RENDPARAMS", out var rendParamsRaw)) if (!mis.Chunks.TryGetValue("RENDPARAMS", out var rendParamsRaw))
return; return;
var ambient = ((RendParams)rendParamsRaw).ambientLight * 255; var ambient = ((RendParams)rendParamsRaw).ambientLight * 255;
Timing.TimeStage("Light", () => CastScene(scene, worldRep, [.. lights], ambient)); CastScene(scene, worldRep, [.. lights], ambient);
var dir = Path.GetDirectoryName(misPath); var dir = Path.GetDirectoryName(misPath);
var filename = Path.GetFileNameWithoutExtension(misPath); var filename = Path.GetFileNameWithoutExtension(misPath);
var savePath = Path.Join(dir, $"{filename}-lit.cow"); mis.Save(Path.Join(dir, $"{filename}-lit.cow"));
Timing.TimeStage("Save DB", () => mis.Save(savePath));
Console.WriteLine($"Lit {lights.Count} light"); Console.WriteLine($"Lit {lights.Count} light");
} }
@ -84,60 +106,6 @@ class Program
}; };
} }
// Get list of brush lights, and object lights (ignore anim lights for now)
private static List<Light> BuildLightList(DbFile mis, ObjectHierarchy hierarchy)
{
var lights = new List<Light>();
if (mis.Chunks.TryGetValue("BRLIST", out var brListRaw))
{
var brList = (BrList)brListRaw;
foreach (var brush in brList.Brushes)
{
if (brush.media == BrList.Brush.Media.Light)
{
var sz = brush.size;
lights.Add(new Light
{
position = brush.position,
color = HsbToRgb(sz.Y, sz.Z, Math.Min(sz.X, 255.0f)),
radius = float.MaxValue,
r2 = float.MaxValue
});
}
else if (brush.media == BrList.Brush.Media.Object)
{
var id = (int)brush.brushInfo;
var propLight = hierarchy.GetProperty<PropLight>(id, "P$Light");
var propLightColor = hierarchy.GetProperty<PropLightColor>(id, "P$LightColo");
if (propLight != null)
{
propLightColor ??= new PropLightColor { Hue = 0, Saturation = 0 };
var light = new Light
{
position = brush.position,
color = HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propLight.Brightness),
radius = propLight.Radius,
r2 = propLight.Radius * propLight.Radius,
};
if (propLight.Radius == 0)
{
light.radius = float.MaxValue;
light.r2 = float.MaxValue;
}
lights.Add(light);
}
}
}
}
return lights;
}
private static ObjectHierarchy BuildHierarchy(string misPath, DbFile misFile) private static ObjectHierarchy BuildHierarchy(string misPath, DbFile misFile)
{ {
ObjectHierarchy objHierarchy; ObjectHierarchy objHierarchy;
@ -215,7 +183,7 @@ class Program
var cells = wr.Cells; var cells = wr.Cells;
for (var cellIdx = 0; cellIdx < cells.Length; cellIdx++) for (var cellIdx = 0; cellIdx < cells.Length; cellIdx++)
{ {
Console.Write($"\rLighting cell... {cellIdx + 1}/{cells.Length}"); Console.Write($"\rLighting cell... {cellIdx + 1}/{cells.Length}\n");
var cell = cells[cellIdx]; var cell = cells[cellIdx];
var numPolys = cell.PolyCount; var numPolys = cell.PolyCount;
@ -286,16 +254,7 @@ class Program
var hit = hitResult && Math.Abs(hitResult.Distance - direction.Length()) < 0.001; var hit = hitResult && Math.Abs(hitResult.Distance - direction.Length()) < 0.001;
if (hit) if (hit)
{ {
// TODO: This isn't perfectly accurate, but it's pretty fucking close tbh lightmap.AddLight(0, x, y, (byte)light.color.X, (byte)light.color.Y, (byte)light.color.Z);
var dir = light.position - pos;
var angle = Vector3.Dot(Vector3.Normalize(dir), plane.Normal);
var len = dir.Length();
var slen = len / 4.0f;
var strength = (angle + 1.0f) / slen;
strength = Math.Min(1.0f, strength);
var c = light.color * strength;
lightmap.AddLight(0, x, y, (byte)c.X, (byte)c.Y, (byte)c.Z);
} }
} }
} }

View File

@ -1,47 +0,0 @@
using System.Diagnostics;
namespace KeepersCompound.Lightmapper;
public static class Timing
{
static readonly Dictionary<string, TimeSpan> _stages = new();
public static void Reset()
{
_stages.Clear();
}
public static void TimeStage(string stagename, Action action)
{
var watch = Stopwatch.StartNew();
action();
watch.Stop();
AddOrIncrement(stagename, watch.Elapsed);
}
public static T TimeStage<T>(string stagename, Func<T> action)
{
var watch = Stopwatch.StartNew();
var value = action();
watch.Stop();
AddOrIncrement(stagename, watch.Elapsed);
return value;
}
public static void LogAll()
{
foreach (var (stagename, time) in _stages)
{
Console.WriteLine($"[{stagename}]: {time:g}");
}
}
private static void AddOrIncrement(string stagename, TimeSpan elapsed)
{
if (_stages.TryGetValue(stagename, out var time))
{
elapsed += time;
}
_stages[stagename] = elapsed;
}
}