Compare commits
10 Commits
4bc55b9130
...
3a445ef6d8
Author | SHA1 | Date |
---|---|---|
Jarrod Doyle | 3a445ef6d8 | |
Jarrod Doyle | 8bde33ebf2 | |
Jarrod Doyle | f4c4237306 | |
Jarrod Doyle | 6a9aac972d | |
Jarrod Doyle | b55d58b9fe | |
Jarrod Doyle | 6c143058e9 | |
Jarrod Doyle | 7c786a5f4c | |
Jarrod Doyle | e6d3489b11 | |
Jarrod Doyle | fe3f13e372 | |
Jarrod Doyle | 45ad76855f |
|
@ -142,6 +142,8 @@ public class DbFile
|
|||
"P$OTxtRepr1" => new PropertyChunk<PropString>(),
|
||||
"P$OTxtRepr2" => new PropertyChunk<PropString>(),
|
||||
"P$OTxtRepr3" => new PropertyChunk<PropString>(),
|
||||
"P$Light" => new PropertyChunk<PropLight>(),
|
||||
"P$LightColo" => new PropertyChunk<PropLightColor>(),
|
||||
"P$RenderAlp" => new PropertyChunk<PropFloat>(),
|
||||
"LD$MetaProp" => new LinkDataMetaProp(),
|
||||
_ when entryName.StartsWith("L$") => new LinkChunk(),
|
||||
|
|
|
@ -99,6 +99,8 @@ public class ObjectHierarchy
|
|||
AddProp<PropString>("P$OTxtRepr2");
|
||||
AddProp<PropString>("P$OTxtRepr3");
|
||||
AddProp<PropFloat>("P$RenderAlp");
|
||||
AddProp<PropLight>("P$Light");
|
||||
AddProp<PropLightColor>("P$LightColo");
|
||||
}
|
||||
|
||||
public T GetProperty<T>(int objectId, string propName) where T : Property
|
||||
|
|
|
@ -13,6 +13,7 @@ class Program
|
|||
public Vector3 position;
|
||||
public Vector3 color;
|
||||
public float radius;
|
||||
public float r2;
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
|
@ -34,13 +35,35 @@ class Program
|
|||
lights.Add(new Light
|
||||
{
|
||||
position = brush.position,
|
||||
color = HsbToRgb(360 * sz.Y, sz.Z, Math.Min(sz.X, 255.0f)),
|
||||
radius = float.MaxValue
|
||||
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");
|
||||
|
||||
// TODO: object lights
|
||||
if (light != null)
|
||||
{
|
||||
lightColor ??= new PropLightColor { Hue = 0, Saturation = 0 };
|
||||
lights.Add(new Light
|
||||
{
|
||||
position = brush.position,
|
||||
color = HsbToRgb(lightColor.Hue, lightColor.Saturation, light.Brightness),
|
||||
radius = light.Radius,
|
||||
r2 = light.Radius * light.Radius,
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"no light prop apparently");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build embree mesh
|
||||
|
@ -60,12 +83,15 @@ class Program
|
|||
var dir = Path.GetDirectoryName(misPath);
|
||||
var filename = Path.GetFileNameWithoutExtension(misPath);
|
||||
mis.Save(Path.Join(dir, $"{filename}-lit.cow"));
|
||||
|
||||
Console.WriteLine($"Lit {lights.Count} light");
|
||||
}
|
||||
|
||||
// Expects Hue to be 0-360, saturation 0-1, brightness 0-255
|
||||
// Expects Hue and Saturation are 0-1, Brightness 0-255
|
||||
// https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
|
||||
private static Vector3 HsbToRgb(float hue, float saturation, float brightness)
|
||||
{
|
||||
hue *= 360;
|
||||
var hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
|
||||
var f = hue / 60 - Math.Floor(hue / 60);
|
||||
|
||||
|
@ -140,7 +166,6 @@ class Program
|
|||
for (var j = 0; j < numPolyVertices; j++)
|
||||
{
|
||||
var vertex = cell.Vertices[cell.Indices[cellIdxOffset + j]];
|
||||
// Console.WriteLine($"Cell: {cellIdx}, Poly: {polyIdx}, V: {j}, Vert: {vertex}");
|
||||
vertices.Add(vertex);
|
||||
}
|
||||
|
||||
|
@ -163,18 +188,22 @@ class Program
|
|||
var cells = wr.Cells;
|
||||
for (var cellIdx = 0; cellIdx < cells.Length; cellIdx++)
|
||||
{
|
||||
Console.Write($"\rLighting cell... {cellIdx + 1}/{cells.Length}\n");
|
||||
|
||||
var cell = cells[cellIdx];
|
||||
var numPolys = cell.PolyCount;
|
||||
var numRenderPolys = cell.RenderPolyCount;
|
||||
var numPortalPolys = cell.PortalPolyCount;
|
||||
|
||||
// There's nothing to render
|
||||
// Portal polys can be render polys (e.g. water) but we're ignoring them for now
|
||||
if (numRenderPolys == 0 || numPortalPolys >= numPolys)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var maxPolyIdx = Math.Min(numRenderPolys, numPolys - numPortalPolys);
|
||||
var cellIdxOffset = 0;
|
||||
for (int polyIdx = 0; polyIdx < maxPolyIdx; polyIdx++)
|
||||
{
|
||||
var poly = cell.Polys[polyIdx];
|
||||
|
@ -183,60 +212,78 @@ class Program
|
|||
var info = cell.LightList[polyIdx];
|
||||
var lightmap = cell.Lightmaps[polyIdx];
|
||||
|
||||
// Clear existing lightmap data
|
||||
for (var i = 0; i < lightmap.Pixels.Length; i++)
|
||||
{
|
||||
lightmap.Pixels[i] = 0;
|
||||
}
|
||||
ResetLightmap(ambientLight, lightmap);
|
||||
|
||||
for (var y = 0; y < lightmap.Height; y++)
|
||||
{
|
||||
for (var x = 0; x < lightmap.Width; x++)
|
||||
{
|
||||
lightmap.AddLight(0, x, y, (byte)ambientLight.X, (byte)ambientLight.Y, (byte)ambientLight.Z);
|
||||
}
|
||||
}
|
||||
// Get world position of lightmap (0, 0) (+0.5 so we cast from the center of a pixel)
|
||||
var topLeft = cell.Vertices[cell.Indices[cellIdxOffset]];
|
||||
topLeft -= renderPoly.TextureVectors.Item1 * (renderPoly.TextureBases.Item1 - info.Bases.Item1 * 0.25f);
|
||||
topLeft -= renderPoly.TextureVectors.Item2 * (renderPoly.TextureBases.Item2 - info.Bases.Item2 * 0.25f);
|
||||
|
||||
foreach (var light in lights)
|
||||
{
|
||||
Console.WriteLine("Doing a light...");
|
||||
// Check if plane normal is facing towards the light
|
||||
var direction = renderPoly.Center - light.position;
|
||||
Console.WriteLine($"Light Pos: {light.position}, poly center: {renderPoly.Center}");
|
||||
Console.WriteLine($"Dir: {direction}");
|
||||
// if (Vector3.Dot(plane.Normal, direction) < 0)
|
||||
// If it's not then we're never going to be (directly) lit by this
|
||||
// light.
|
||||
var centerDirection = renderPoly.Center - light.position;
|
||||
if (Vector3.Dot(plane.Normal, centerDirection) >= 0)
|
||||
{
|
||||
// Cast from the light to the center (later each pixel)
|
||||
var hit = scene.Trace(new Ray
|
||||
{
|
||||
Origin = light.position,
|
||||
Direction = Vector3.Normalize(direction)
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// cheeky epsilon
|
||||
var goodHit = hit && Math.Abs(hit.Distance - direction.Length()) < 0.001;
|
||||
Console.WriteLine($"Did we hit? {goodHit}");
|
||||
Console.WriteLine($"Distance: {hit.Distance}, target dist: {direction.Length()}");
|
||||
Console.WriteLine($"Pos: {hit.Position}, Target Pos: {renderPoly.Center}");
|
||||
|
||||
// Iterate all pixels
|
||||
var color = goodHit ? light.color : ambientLight;
|
||||
for (var y = 0; y < lightmap.Height; y++)
|
||||
for (var y = 0; y < lightmap.Height; y++)
|
||||
{
|
||||
for (var x = 0; x < lightmap.Width; x++)
|
||||
{
|
||||
for (var x = 0; x < lightmap.Width; x++)
|
||||
var pos = topLeft;
|
||||
pos += x * 0.25f * renderPoly.TextureVectors.Item1;
|
||||
pos += y * 0.25f * renderPoly.TextureVectors.Item2;
|
||||
|
||||
// If we're out of range there's no point casting a ray
|
||||
// There's probably a better way to discard the entire lightmap
|
||||
// if we're massively out of range
|
||||
var direction = pos - light.position;
|
||||
if (direction.LengthSquared() > light.r2)
|
||||
{
|
||||
lightmap.AddLight(0, x, y, (byte)color.X, (byte)color.Y, (byte)color.Z);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We cast from the light to the pixel because the light has
|
||||
// no mesh in the scene to hit
|
||||
var hitResult = scene.Trace(new Ray
|
||||
{
|
||||
Origin = light.position,
|
||||
Direction = Vector3.Normalize(direction),
|
||||
});
|
||||
|
||||
// cheeky epsilon
|
||||
var hit = hitResult && Math.Abs(hitResult.Distance - direction.Length()) < 0.001;
|
||||
if (hit)
|
||||
{
|
||||
lightmap.AddLight(0, x, y, (byte)light.color.X, (byte)light.color.Y, (byte)light.color.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cellIdxOffset += poly.VertexCount;
|
||||
}
|
||||
}
|
||||
|
||||
// // TODO: Get world position of each pixel?
|
||||
Console.Write("\n");
|
||||
}
|
||||
|
||||
// var poly = cell.Polys[polyIdx];
|
||||
private static void ResetLightmap(Vector3 ambientLight, WorldRep.Cell.Lightmap lightmap)
|
||||
{
|
||||
for (var i = 0; i < lightmap.Pixels.Length; i++)
|
||||
{
|
||||
lightmap.Pixels[i] = 0;
|
||||
}
|
||||
|
||||
// poly.
|
||||
for (var y = 0; y < lightmap.Height; y++)
|
||||
{
|
||||
for (var x = 0; x < lightmap.Width; x++)
|
||||
{
|
||||
lightmap.AddLight(0, x, y, (byte)ambientLight.X, (byte)ambientLight.Y, (byte)ambientLight.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue