Compare commits
11 Commits
d7fcf7a2d8
...
7ec7f71239
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | 7ec7f71239 | |
Jarrod Doyle | 47d95307b5 | |
Jarrod Doyle | 69b29c15f6 | |
Jarrod Doyle | 93410a46d5 | |
Jarrod Doyle | 6efceff852 | |
Jarrod Doyle | 067cd2cc00 | |
Jarrod Doyle | b57d15f6f0 | |
Jarrod Doyle | bd72554b9a | |
Jarrod Doyle | 46fe99bbfc | |
Jarrod Doyle | 8b7ffcd7a3 | |
Jarrod Doyle | bcc60eff52 |
|
@ -330,6 +330,112 @@ public class PropLight : Property
|
|||
}
|
||||
}
|
||||
|
||||
public class PropAnimLight : Property
|
||||
{
|
||||
public enum AnimMode
|
||||
{
|
||||
FlipMinMax,
|
||||
SlideSmoothly,
|
||||
Random,
|
||||
MinBrightness,
|
||||
MaxBrightness,
|
||||
ZeroBrightness,
|
||||
SmoothlyBrighten,
|
||||
SmoothlyDim,
|
||||
RandomButCoherent,
|
||||
FlickerMinMax,
|
||||
}
|
||||
|
||||
// Standard light props
|
||||
public float Brightness;
|
||||
public Vector3 Offset;
|
||||
public float Radius;
|
||||
public float InnerRadius;
|
||||
public bool QuadLit;
|
||||
public bool Dynamic;
|
||||
|
||||
// Animation
|
||||
public AnimMode Mode;
|
||||
public int MsToBrighten;
|
||||
public int MsToDim;
|
||||
public float MinBrightness;
|
||||
public float MaxBrightness;
|
||||
|
||||
// Start state
|
||||
public float CurrentBrightness;
|
||||
public bool Rising;
|
||||
public int Timer;
|
||||
public bool Inactive;
|
||||
|
||||
// World rep info
|
||||
public bool Refresh; // Not relevant to us. It's used to tell dromed it needs to relight
|
||||
public ushort LightTableMapIndex;
|
||||
public ushort LightTableLightIndex;
|
||||
public ushort CellsReached;
|
||||
|
||||
private int _unknown;
|
||||
|
||||
public override void Read(BinaryReader reader)
|
||||
{
|
||||
base.Read(reader);
|
||||
Brightness = reader.ReadSingle();
|
||||
Offset = reader.ReadVec3();
|
||||
Refresh = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
LightTableMapIndex = reader.ReadUInt16();
|
||||
CellsReached = reader.ReadUInt16();
|
||||
LightTableLightIndex = reader.ReadUInt16();
|
||||
Mode = (AnimMode)reader.ReadUInt16();
|
||||
MsToBrighten = reader.ReadInt32();
|
||||
MsToDim = reader.ReadInt32();
|
||||
MinBrightness = reader.ReadSingle();
|
||||
MaxBrightness = reader.ReadSingle();
|
||||
CurrentBrightness = reader.ReadSingle();
|
||||
Rising = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
Timer = reader.ReadInt32();
|
||||
Inactive = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
Radius = reader.ReadSingle();
|
||||
_unknown = reader.ReadInt32();
|
||||
QuadLit = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
InnerRadius = reader.ReadSingle();
|
||||
Dynamic = reader.ReadBoolean();
|
||||
reader.ReadBytes(3);
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter writer)
|
||||
{
|
||||
base.Write(writer);
|
||||
writer.Write(Brightness);
|
||||
writer.WriteVec3(Offset);
|
||||
writer.Write(Refresh);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(LightTableMapIndex);
|
||||
writer.Write(CellsReached);
|
||||
writer.Write(LightTableLightIndex);
|
||||
writer.Write((ushort)Mode);
|
||||
writer.Write(MsToBrighten);
|
||||
writer.Write(MsToDim);
|
||||
writer.Write(MinBrightness);
|
||||
writer.Write(MaxBrightness);
|
||||
writer.Write(CurrentBrightness);
|
||||
writer.Write(Rising);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(Timer);
|
||||
writer.Write(Inactive);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(Radius);
|
||||
writer.Write(_unknown);
|
||||
writer.Write(QuadLit);
|
||||
writer.Write(new byte[3]);
|
||||
writer.Write(InnerRadius);
|
||||
writer.Write(Dynamic);
|
||||
writer.Write(new byte[3]);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropLightColor : Property
|
||||
{
|
||||
public float Hue;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
|
||||
namespace KeepersCompound.LGS.Database.Chunks;
|
||||
|
@ -419,9 +417,179 @@ public class WorldRep : IChunk
|
|||
}
|
||||
}
|
||||
|
||||
public struct BspTree
|
||||
{
|
||||
public struct Node
|
||||
{
|
||||
int parentIndex; // TODO: Split the flags out of this
|
||||
int cellId;
|
||||
int planeId;
|
||||
uint insideIndex;
|
||||
uint outsideIndex;
|
||||
|
||||
public Node(BinaryReader reader)
|
||||
{
|
||||
parentIndex = reader.ReadInt32();
|
||||
cellId = reader.ReadInt32();
|
||||
planeId = reader.ReadInt32();
|
||||
insideIndex = reader.ReadUInt32();
|
||||
outsideIndex = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(parentIndex);
|
||||
writer.Write(cellId);
|
||||
writer.Write(planeId);
|
||||
writer.Write(insideIndex);
|
||||
writer.Write(outsideIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public uint PlaneCount;
|
||||
public uint NodeCount;
|
||||
public Plane[] Planes;
|
||||
public Node[] Nodes;
|
||||
|
||||
public BspTree(BinaryReader reader)
|
||||
{
|
||||
PlaneCount = reader.ReadUInt32();
|
||||
Planes = new Plane[PlaneCount];
|
||||
for (var i = 0; i < PlaneCount; i++)
|
||||
{
|
||||
Planes[i] = new Plane(reader.ReadVec3(), reader.ReadSingle());
|
||||
}
|
||||
|
||||
NodeCount = reader.ReadUInt32();
|
||||
Nodes = new Node[NodeCount];
|
||||
for (var i = 0; i < NodeCount; i++)
|
||||
{
|
||||
Nodes[i] = new Node(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(PlaneCount);
|
||||
foreach (var plane in Planes)
|
||||
{
|
||||
writer.WriteVec3(plane.Normal);
|
||||
writer.Write(plane.D);
|
||||
}
|
||||
writer.Write(NodeCount);
|
||||
foreach (var node in Nodes)
|
||||
{
|
||||
node.Write(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct LightTable
|
||||
{
|
||||
public struct LightData
|
||||
{
|
||||
public Vector3 Location;
|
||||
public Vector3 Direction;
|
||||
public Vector3 Color;
|
||||
float InnerAngle; // I'm pretty sure these are the spotlight angles
|
||||
float OuterAngle;
|
||||
float Radius;
|
||||
|
||||
public LightData(BinaryReader reader)
|
||||
{
|
||||
Location = reader.ReadVec3();
|
||||
Direction = reader.ReadVec3();
|
||||
Color = reader.ReadVec3();
|
||||
InnerAngle = reader.ReadSingle();
|
||||
OuterAngle = reader.ReadSingle();
|
||||
Radius = reader.ReadSingle();
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.WriteVec3(Location);
|
||||
writer.WriteVec3(Direction);
|
||||
writer.WriteVec3(Color);
|
||||
writer.Write(InnerAngle);
|
||||
writer.Write(OuterAngle);
|
||||
writer.Write(Radius);
|
||||
}
|
||||
}
|
||||
|
||||
public struct AnimCellMap
|
||||
{
|
||||
public ushort CellIndex;
|
||||
public ushort LightIndex;
|
||||
|
||||
public AnimCellMap(BinaryReader reader)
|
||||
{
|
||||
CellIndex = reader.ReadUInt16();
|
||||
LightIndex = reader.ReadUInt16();
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(CellIndex);
|
||||
writer.Write(LightIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public int LightCount;
|
||||
public int DynamicLightCount;
|
||||
public int AnimMapCount;
|
||||
public LightData[] Lights;
|
||||
public LightData[] ScratchpadLights;
|
||||
public AnimCellMap[] AnimCellMaps;
|
||||
|
||||
// TODO: Support olddark
|
||||
public LightTable(BinaryReader reader)
|
||||
{
|
||||
LightCount = reader.ReadInt32();
|
||||
DynamicLightCount = reader.ReadInt32();
|
||||
Lights = new LightData[LightCount + DynamicLightCount];
|
||||
for (var i = 0; i < Lights.Length; i++)
|
||||
{
|
||||
Lights[i] = new LightData(reader);
|
||||
}
|
||||
ScratchpadLights = new LightData[32];
|
||||
for (var i = 0; i < ScratchpadLights.Length; i++)
|
||||
{
|
||||
ScratchpadLights[i] = new LightData(reader);
|
||||
}
|
||||
AnimMapCount = reader.ReadInt32();
|
||||
AnimCellMaps = new AnimCellMap[AnimMapCount];
|
||||
for (var i = 0; i < AnimCellMaps.Length; i++)
|
||||
{
|
||||
AnimCellMaps[i] = new AnimCellMap(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(LightCount);
|
||||
writer.Write(DynamicLightCount);
|
||||
foreach (var light in Lights)
|
||||
{
|
||||
light.Write(writer);
|
||||
}
|
||||
foreach (var light in ScratchpadLights)
|
||||
{
|
||||
light.Write(writer);
|
||||
}
|
||||
writer.Write(AnimMapCount);
|
||||
foreach (var map in AnimCellMaps)
|
||||
{
|
||||
map.Write(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkHeader Header { get; set; }
|
||||
public WrHeader DataHeader { get; set; }
|
||||
public Cell[] Cells { get; set; }
|
||||
public BspTree Bsp { get; set; }
|
||||
public LightTable LightingTable { get; set; }
|
||||
private byte[] _unknown;
|
||||
private byte[] _unreadData;
|
||||
|
||||
public void ReadData(BinaryReader reader, DbFile.TableOfContents.Entry entry)
|
||||
|
@ -435,6 +603,12 @@ public class WorldRep : IChunk
|
|||
Cells[i] = new Cell(reader, bpp);
|
||||
}
|
||||
|
||||
Bsp = new BspTree(reader);
|
||||
|
||||
// TODO: Work out what this is
|
||||
_unknown = reader.ReadBytes(Cells.Length);
|
||||
LightingTable = new LightTable(reader);
|
||||
|
||||
// TODO: All the other info lol
|
||||
var length = entry.Offset + entry.Size + 24 - reader.BaseStream.Position;
|
||||
_unreadData = reader.ReadBytes((int)length);
|
||||
|
@ -447,6 +621,9 @@ public class WorldRep : IChunk
|
|||
{
|
||||
cell.Write(writer);
|
||||
}
|
||||
Bsp.Write(writer);
|
||||
writer.Write(_unknown);
|
||||
LightingTable.Write(writer);
|
||||
writer.Write(_unreadData);
|
||||
}
|
||||
}
|
|
@ -32,13 +32,13 @@ public class DbFile
|
|||
}
|
||||
}
|
||||
|
||||
public readonly struct TableOfContents
|
||||
public struct TableOfContents
|
||||
{
|
||||
public readonly struct Entry
|
||||
public struct Entry
|
||||
{
|
||||
public string Name { get; }
|
||||
public uint Offset { get; }
|
||||
public uint Size { get; }
|
||||
public string Name;
|
||||
public uint Offset;
|
||||
public uint Size;
|
||||
|
||||
public Entry(BinaryReader reader)
|
||||
{
|
||||
|
@ -47,10 +47,9 @@ public class DbFile
|
|||
Size = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public override readonly string ToString()
|
||||
{
|
||||
// return $"Name: {Name}, Offset: {O}"
|
||||
return base.ToString();
|
||||
return $"Name: {Name}, Offset: {Offset}, Size: {Size}";
|
||||
}
|
||||
|
||||
public readonly void Write(BinaryWriter writer)
|
||||
|
@ -110,18 +109,28 @@ public class DbFile
|
|||
|
||||
public void Save(string filename)
|
||||
{
|
||||
// !HACK: Right now we don't need to adjust TOC offset or anything because we're only
|
||||
// overwriting data, not writing new lengths of data
|
||||
|
||||
using var stream = File.Open(filename, FileMode.Create);
|
||||
using var writer = new BinaryWriter(stream, Encoding.UTF8, false);
|
||||
|
||||
Header.Write(writer);
|
||||
foreach (var (name, chunk) in Chunks)
|
||||
for (var i = 0; i < Toc.ItemCount; i++)
|
||||
{
|
||||
var item = Toc.Items[i];
|
||||
var pos = stream.Position;
|
||||
|
||||
var chunk = Chunks[item.Name];
|
||||
chunk.Write(writer);
|
||||
var size = stream.Position - pos - 24;
|
||||
|
||||
item.Offset = (uint)pos;
|
||||
item.Size = (uint)size;
|
||||
Toc.Items[i] = item;
|
||||
}
|
||||
var tocOffset = (uint)stream.Position;
|
||||
Toc.Write(writer);
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
writer.Write(tocOffset);
|
||||
}
|
||||
|
||||
private static IChunk NewChunk(string entryName)
|
||||
|
@ -143,6 +152,7 @@ public class DbFile
|
|||
"P$OTxtRepr2" => new PropertyChunk<PropString>(),
|
||||
"P$OTxtRepr3" => new PropertyChunk<PropString>(),
|
||||
"P$Light" => new PropertyChunk<PropLight>(),
|
||||
"P$AnimLight" => new PropertyChunk<PropAnimLight>(),
|
||||
"P$LightColo" => new PropertyChunk<PropLightColor>(),
|
||||
"P$Spotlight" => new PropertyChunk<PropSpotlight>(),
|
||||
"P$RenderAlp" => new PropertyChunk<PropFloat>(),
|
||||
|
|
|
@ -101,11 +101,13 @@ public class ObjectHierarchy
|
|||
AddProp<PropString>("P$OTxtRepr3");
|
||||
AddProp<PropFloat>("P$RenderAlp");
|
||||
AddProp<PropLight>("P$Light");
|
||||
AddProp<PropAnimLight>("P$AnimLight");
|
||||
AddProp<PropLightColor>("P$LightColo");
|
||||
AddProp<PropSpotlight>("P$Spotlight");
|
||||
}
|
||||
|
||||
public T GetProperty<T>(int objectId, string propName) where T : Property
|
||||
// TODO: Work out if there's some nice way to automatically decide if we inherit
|
||||
public T GetProperty<T>(int objectId, string propName, bool inherit = true) where T : Property
|
||||
{
|
||||
if (!_objects.ContainsKey(objectId))
|
||||
{
|
||||
|
@ -121,7 +123,7 @@ public class ObjectHierarchy
|
|||
}
|
||||
|
||||
var prop = obj.GetProperty<T>(propName);
|
||||
if (prop != null)
|
||||
if (prop != null || !inherit)
|
||||
{
|
||||
return prop;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@ class Program
|
|||
public Vector3 spotlightDir;
|
||||
public float spotlightInnerAngle;
|
||||
public float spotlightOuterAngle;
|
||||
|
||||
public bool anim;
|
||||
public int animLightTableIndex;
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
|
@ -33,18 +36,16 @@ class Program
|
|||
var campaignName = "JAYRUDE_Tests";
|
||||
var missionName = "lm_test.cow";
|
||||
|
||||
// campaignName = "TDP20AC_a_burrick_in_a_room";
|
||||
// missionName = "miss20.mis";
|
||||
|
||||
// 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(campaign, misPath));
|
||||
|
||||
Timing.LogAll();
|
||||
|
@ -132,56 +133,64 @@ class Program
|
|||
{
|
||||
// TODO: Handle PropSpotlightAndAmbient
|
||||
var id = (int)brush.brushInfo;
|
||||
var propLight = hierarchy.GetProperty<PropLight>(id, "P$Light");
|
||||
var propAnimLight = hierarchy.GetProperty<PropAnimLight>(id, "P$AnimLight", false);
|
||||
var propLight = hierarchy.GetProperty<PropLight>(id, "P$Light", false);
|
||||
var propLightColor = hierarchy.GetProperty<PropLightColor>(id, "P$LightColo");
|
||||
var propSpotlight = hierarchy.GetProperty<PropSpotlight>(id, "P$Spotlight");
|
||||
var propModelname = hierarchy.GetProperty<PropLabel>(id, "P$ModelName");
|
||||
|
||||
propLightColor ??= new PropLightColor { Hue = 0, Saturation = 0 };
|
||||
|
||||
var baseLight = new Light
|
||||
{
|
||||
position = brush.position,
|
||||
spotlightDir = -Vector3.UnitZ,
|
||||
};
|
||||
|
||||
if (propModelname != null)
|
||||
{
|
||||
var resName = $"{propModelname.value.ToLower()}.bin";
|
||||
var modelPath = campaign.GetResourcePath(ResourceType.Object, resName);
|
||||
if (modelPath != null)
|
||||
{
|
||||
// TODO: Handle failing to find model more gracefully
|
||||
var model = new ModelFile(modelPath);
|
||||
if (model.TryGetVhot(ModelFile.VhotId.LightPosition, out var vhot))
|
||||
{
|
||||
baseLight.position += vhot.Position;
|
||||
}
|
||||
if (model.TryGetVhot(ModelFile.VhotId.LightDirection, out vhot))
|
||||
{
|
||||
baseLight.spotlightDir = vhot.Position;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (propSpotlight != null)
|
||||
{
|
||||
var rot = Matrix4x4.Identity;
|
||||
rot *= Matrix4x4.CreateRotationX(float.DegreesToRadians(brush.angle.X));
|
||||
rot *= Matrix4x4.CreateRotationY(float.DegreesToRadians(brush.angle.Y));
|
||||
rot *= Matrix4x4.CreateRotationZ(float.DegreesToRadians(brush.angle.Z));
|
||||
|
||||
baseLight.spotlight = true;
|
||||
baseLight.spotlightDir = Vector3.Transform(baseLight.spotlightDir, rot);
|
||||
baseLight.spotlightInnerAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.InnerAngle));
|
||||
baseLight.spotlightOuterAngle = (float)Math.Cos(float.DegreesToRadians(propSpotlight.OuterAngle));
|
||||
}
|
||||
|
||||
if (propLight != null)
|
||||
{
|
||||
propLightColor ??= new PropLightColor { Hue = 0, Saturation = 0 };
|
||||
|
||||
// TODO: There's still some lights that aren't positioned right such as Streetlamp.
|
||||
// Perhaps there's a light point specified in model files?
|
||||
var light = new Light
|
||||
{
|
||||
position = brush.position + propLight.Offset,
|
||||
position = baseLight.position + propLight.Offset,
|
||||
color = HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propLight.Brightness),
|
||||
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
|
||||
var rot = Matrix4x4.Identity;
|
||||
rot *= Matrix4x4.CreateRotationX(float.DegreesToRadians(brush.angle.X));
|
||||
rot *= Matrix4x4.CreateRotationY(float.DegreesToRadians(brush.angle.Y));
|
||||
rot *= Matrix4x4.CreateRotationZ(float.DegreesToRadians(brush.angle.Z));
|
||||
|
||||
light.spotlight = true;
|
||||
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));
|
||||
}
|
||||
|
||||
if (propLight.Radius == 0)
|
||||
{
|
||||
light.radius = float.MaxValue;
|
||||
|
@ -190,6 +199,27 @@ class Program
|
|||
|
||||
lights.Add(light);
|
||||
}
|
||||
|
||||
if (propAnimLight != null)
|
||||
{
|
||||
var light = new Light
|
||||
{
|
||||
position = baseLight.position + propAnimLight.Offset,
|
||||
color = HsbToRgb(propLightColor.Hue, propLightColor.Saturation, propAnimLight.MaxBrightness),
|
||||
innerRadius = propAnimLight.InnerRadius,
|
||||
radius = propAnimLight.Radius,
|
||||
r2 = propAnimLight.Radius * propAnimLight.Radius,
|
||||
anim = true,
|
||||
animLightTableIndex = propAnimLight.LightTableLightIndex,
|
||||
};
|
||||
if (propAnimLight.Radius == 0)
|
||||
{
|
||||
light.radius = float.MaxValue;
|
||||
light.r2 = float.MaxValue;
|
||||
}
|
||||
|
||||
lights.Add(light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,6 +353,28 @@ class Program
|
|||
|
||||
foreach (var light in lights)
|
||||
{
|
||||
var layer = 0;
|
||||
if (light.anim)
|
||||
{
|
||||
var paletteIdx = -1;
|
||||
for (var i = 0; i < cell.AnimLightCount; i++)
|
||||
{
|
||||
var id = cell.AnimLights[i];
|
||||
if (id == light.animLightTableIndex)
|
||||
{
|
||||
paletteIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (paletteIdx == -1 || (info.AnimLightBitmask & (1 << paletteIdx)) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var mask = info.AnimLightBitmask & ((1 << (paletteIdx + 1)) - 1);
|
||||
layer = BitOperations.PopCount((uint)mask);
|
||||
}
|
||||
|
||||
// Check if plane normal is facing towards the light
|
||||
// If it's not then we're never going to be (directly) lit by this
|
||||
// light.
|
||||
|
@ -391,7 +443,7 @@ class Program
|
|||
if (hit)
|
||||
{
|
||||
var strength = CalculateLightStrengthAtPoint(light, pos, plane);
|
||||
lightmap.AddLight(0, x, y, light.color, strength, hdr);
|
||||
lightmap.AddLight(layer, x, y, light.color, strength, hdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue