Compare commits
5 Commits
68eed0a821
...
10a8a31520
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | 10a8a31520 | |
Jarrod Doyle | e004292e53 | |
Jarrod Doyle | 63133da6a4 | |
Jarrod Doyle | 94286e134f | |
Jarrod Doyle | d5664b2614 |
|
@ -44,7 +44,8 @@ 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;
|
||||||
chunk.Merge(gamChunk);
|
gamChunk.Merge(chunk);
|
||||||
|
return gamChunk;
|
||||||
}
|
}
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,66 +18,44 @@ 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";
|
||||||
var mis = new DbFile(misPath);
|
misPath = "/stuff/Games/thief/drive_c/GOG Games/TG ND 1.27 (MAPPING)/FMs/AtdV/miss20.mis";
|
||||||
var hierarchy = BuildHierarchy(misPath, mis);
|
Timing.TimeStage("Total", () => LightmapMission(misPath));
|
||||||
|
|
||||||
// Get list of brush lights, and object lights (ignore anim lights for now)
|
Timing.LogAll();
|
||||||
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");
|
|
||||||
|
|
||||||
if (light != null)
|
private static void LightmapMission(string misPath)
|
||||||
{
|
{
|
||||||
lightColor ??= new PropLightColor { Hue = 0, Saturation = 0 };
|
var mis = Timing.TimeStage("Parse DB", () => new DbFile(misPath));
|
||||||
lights.Add(new Light
|
var hierarchy = Timing.TimeStage("Build Hierarchy", () => BuildHierarchy(misPath, mis));
|
||||||
{
|
|
||||||
position = brush.position,
|
var lights = Timing.TimeStage("Gather Lights", () => BuildLightList(mis, hierarchy));
|
||||||
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 = new Raytracer();
|
var scene = Timing.TimeStage("Build Scene", () =>
|
||||||
scene.AddMesh(BuildWrMesh(worldRep));
|
{
|
||||||
scene.CommitScene();
|
var rt = new Raytracer();
|
||||||
|
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;
|
||||||
CastScene(scene, worldRep, [.. lights], ambient);
|
Timing.TimeStage("Light", () => 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);
|
||||||
mis.Save(Path.Join(dir, $"{filename}-lit.cow"));
|
var savePath = 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");
|
||||||
}
|
}
|
||||||
|
@ -106,6 +84,60 @@ 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;
|
||||||
|
@ -183,7 +215,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}\n");
|
Console.Write($"\rLighting cell... {cellIdx + 1}/{cells.Length}");
|
||||||
|
|
||||||
var cell = cells[cellIdx];
|
var cell = cells[cellIdx];
|
||||||
var numPolys = cell.PolyCount;
|
var numPolys = cell.PolyCount;
|
||||||
|
@ -254,7 +286,16 @@ 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)
|
||||||
{
|
{
|
||||||
lightmap.AddLight(0, x, y, (byte)light.color.X, (byte)light.color.Y, (byte)light.color.Z);
|
// TODO: This isn't perfectly accurate, but it's pretty fucking close tbh
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue