Compare commits
	
		
			10 Commits
		
	
	
		
			4bc55b9130
			...
			3a445ef6d8
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
								 | 
						3a445ef6d8 | |
| 
							
							
								
								 | 
						8bde33ebf2 | |
| 
							
							
								
								 | 
						f4c4237306 | |
| 
							
							
								
								 | 
						6a9aac972d | |
| 
							
							
								
								 | 
						b55d58b9fe | |
| 
							
							
								
								 | 
						6c143058e9 | |
| 
							
							
								
								 | 
						7c786a5f4c | |
| 
							
							
								
								 | 
						e6d3489b11 | |
| 
							
							
								
								 | 
						fe3f13e372 | |
| 
							
							
								
								 | 
						45ad76855f | 
| 
						 | 
					@ -142,6 +142,8 @@ public class DbFile
 | 
				
			||||||
            "P$OTxtRepr1" => new PropertyChunk<PropString>(),
 | 
					            "P$OTxtRepr1" => new PropertyChunk<PropString>(),
 | 
				
			||||||
            "P$OTxtRepr2" => new PropertyChunk<PropString>(),
 | 
					            "P$OTxtRepr2" => new PropertyChunk<PropString>(),
 | 
				
			||||||
            "P$OTxtRepr3" => new PropertyChunk<PropString>(),
 | 
					            "P$OTxtRepr3" => new PropertyChunk<PropString>(),
 | 
				
			||||||
 | 
					            "P$Light" => new PropertyChunk<PropLight>(),
 | 
				
			||||||
 | 
					            "P$LightColo" => new PropertyChunk<PropLightColor>(),
 | 
				
			||||||
            "P$RenderAlp" => new PropertyChunk<PropFloat>(),
 | 
					            "P$RenderAlp" => new PropertyChunk<PropFloat>(),
 | 
				
			||||||
            "LD$MetaProp" => new LinkDataMetaProp(),
 | 
					            "LD$MetaProp" => new LinkDataMetaProp(),
 | 
				
			||||||
            _ when entryName.StartsWith("L$") => new LinkChunk(),
 | 
					            _ when entryName.StartsWith("L$") => new LinkChunk(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -99,6 +99,8 @@ public class ObjectHierarchy
 | 
				
			||||||
        AddProp<PropString>("P$OTxtRepr2");
 | 
					        AddProp<PropString>("P$OTxtRepr2");
 | 
				
			||||||
        AddProp<PropString>("P$OTxtRepr3");
 | 
					        AddProp<PropString>("P$OTxtRepr3");
 | 
				
			||||||
        AddProp<PropFloat>("P$RenderAlp");
 | 
					        AddProp<PropFloat>("P$RenderAlp");
 | 
				
			||||||
 | 
					        AddProp<PropLight>("P$Light");
 | 
				
			||||||
 | 
					        AddProp<PropLightColor>("P$LightColo");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public T GetProperty<T>(int objectId, string propName) where T : Property
 | 
					    public T GetProperty<T>(int objectId, string propName) where T : Property
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@ class Program
 | 
				
			||||||
        public Vector3 position;
 | 
					        public Vector3 position;
 | 
				
			||||||
        public Vector3 color;
 | 
					        public Vector3 color;
 | 
				
			||||||
        public float radius;
 | 
					        public float radius;
 | 
				
			||||||
 | 
					        public float r2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static void Main(string[] args)
 | 
					    static void Main(string[] args)
 | 
				
			||||||
| 
						 | 
					@ -34,13 +35,35 @@ class Program
 | 
				
			||||||
                    lights.Add(new Light
 | 
					                    lights.Add(new Light
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        position = brush.position,
 | 
					                        position = brush.position,
 | 
				
			||||||
                        color = HsbToRgb(360 * sz.Y, sz.Z, Math.Min(sz.X, 255.0f)),
 | 
					                        color = HsbToRgb(sz.Y, sz.Z, Math.Min(sz.X, 255.0f)),
 | 
				
			||||||
                        radius = float.MaxValue
 | 
					                        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
 | 
					        // Build embree mesh
 | 
				
			||||||
| 
						 | 
					@ -60,12 +83,15 @@ class Program
 | 
				
			||||||
        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"));
 | 
					        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
 | 
					    // https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
 | 
				
			||||||
    private static Vector3 HsbToRgb(float hue, float saturation, float brightness)
 | 
					    private static Vector3 HsbToRgb(float hue, float saturation, float brightness)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        hue *= 360;
 | 
				
			||||||
        var hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
 | 
					        var hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
 | 
				
			||||||
        var f = hue / 60 - Math.Floor(hue / 60);
 | 
					        var f = hue / 60 - Math.Floor(hue / 60);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,7 +166,6 @@ class Program
 | 
				
			||||||
                for (var j = 0; j < numPolyVertices; j++)
 | 
					                for (var j = 0; j < numPolyVertices; j++)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    var vertex = cell.Vertices[cell.Indices[cellIdxOffset + j]];
 | 
					                    var vertex = cell.Vertices[cell.Indices[cellIdxOffset + j]];
 | 
				
			||||||
                    // Console.WriteLine($"Cell: {cellIdx}, Poly: {polyIdx}, V: {j}, Vert: {vertex}");
 | 
					 | 
				
			||||||
                    vertices.Add(vertex);
 | 
					                    vertices.Add(vertex);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,18 +188,22 @@ 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");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var cell = cells[cellIdx];
 | 
					            var cell = cells[cellIdx];
 | 
				
			||||||
            var numPolys = cell.PolyCount;
 | 
					            var numPolys = cell.PolyCount;
 | 
				
			||||||
            var numRenderPolys = cell.RenderPolyCount;
 | 
					            var numRenderPolys = cell.RenderPolyCount;
 | 
				
			||||||
            var numPortalPolys = cell.PortalPolyCount;
 | 
					            var numPortalPolys = cell.PortalPolyCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // There's nothing to render
 | 
					            // 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)
 | 
					            if (numRenderPolys == 0 || numPortalPolys >= numPolys)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var maxPolyIdx = Math.Min(numRenderPolys, numPolys - numPortalPolys);
 | 
					            var maxPolyIdx = Math.Min(numRenderPolys, numPolys - numPortalPolys);
 | 
				
			||||||
 | 
					            var cellIdxOffset = 0;
 | 
				
			||||||
            for (int polyIdx = 0; polyIdx < maxPolyIdx; polyIdx++)
 | 
					            for (int polyIdx = 0; polyIdx < maxPolyIdx; polyIdx++)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var poly = cell.Polys[polyIdx];
 | 
					                var poly = cell.Polys[polyIdx];
 | 
				
			||||||
| 
						 | 
					@ -183,7 +212,68 @@ class Program
 | 
				
			||||||
                var info = cell.LightList[polyIdx];
 | 
					                var info = cell.LightList[polyIdx];
 | 
				
			||||||
                var lightmap = cell.Lightmaps[polyIdx];
 | 
					                var lightmap = cell.Lightmaps[polyIdx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Clear existing lightmap data
 | 
					                ResetLightmap(ambientLight, lightmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // 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)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    // 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.
 | 
				
			||||||
 | 
					                    var centerDirection = renderPoly.Center - light.position;
 | 
				
			||||||
 | 
					                    if (Vector3.Dot(plane.Normal, centerDirection) >= 0)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for (var y = 0; y < lightmap.Height; y++)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        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)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                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;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Console.Write("\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ResetLightmap(Vector3 ambientLight, WorldRep.Cell.Lightmap lightmap)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        for (var i = 0; i < lightmap.Pixels.Length; i++)
 | 
					        for (var i = 0; i < lightmap.Pixels.Length; i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            lightmap.Pixels[i] = 0;
 | 
					            lightmap.Pixels[i] = 0;
 | 
				
			||||||
| 
						 | 
					@ -196,48 +286,5 @@ class Program
 | 
				
			||||||
                lightmap.AddLight(0, x, y, (byte)ambientLight.X, (byte)ambientLight.Y, (byte)ambientLight.Z);
 | 
					                lightmap.AddLight(0, x, y, (byte)ambientLight.X, (byte)ambientLight.Y, (byte)ambientLight.Z);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
                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)
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        // Cast from the light to the center (later each pixel)
 | 
					 | 
				
			||||||
                        var hit = scene.Trace(new Ray
 | 
					 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            Origin = light.position,
 | 
					 | 
				
			||||||
                            Direction = Vector3.Normalize(direction)
 | 
					 | 
				
			||||||
                        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        // 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 x = 0; x < lightmap.Width; x++)
 | 
					 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                lightmap.AddLight(0, x, y, (byte)color.X, (byte)color.Y, (byte)color.Z);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // // TODO: Get world position of each pixel?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // var poly = cell.Polys[polyIdx];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // poly.
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue