/// <summary> /// /// </summary> /// <param name="viewIndex"></param> /// <param name="renderView"></param> /// <param name="lightCount"></param> /// <returns>The number of lights accepted in <see cref="CurrentLights"/>.</returns> public virtual int AddView(int viewIndex, RenderView renderView, int lightCount) { LightRanges[viewIndex] = new LightRange(Lights.Count, Lights.Count + lightCount); LightCurrentCount = Math.Max(LightCurrentCount, ComputeLightCount(lightCount)); return(Math.Min(LightCurrentCount, lightCount)); }
/// <summary> /// /// </summary> /// <param name="viewIndex"></param> /// <param name="renderView"></param> /// <param name="lightCount"></param> /// <returns>The number of lights accepted in <see cref="CurrentLights"/>.</returns> public virtual int AddView(int viewIndex, RenderView renderView, int lightCount) { LightRanges[viewIndex] = new LightRange(Lights.Count, Lights.Count + lightCount); LightCurrentCount = Math.Max(LightCurrentCount, ComputeLightCount(lightCount)); return Math.Min(LightCurrentCount, lightCount); }
public virtual void SetViews(FastList<RenderView> views) { Array.Resize(ref LightRanges, views.Count); // Reset ranges for (var i = 0; i < views.Count; ++i) LightRanges[i] = new LightRange(0, 0); }
public static (LightMap FloorLight, LightMap CeilingLight) Trace( MapData map, LightRange lightRange, IEnumerable <LightDefinition> lights) { var board = map.GetBoard(); return(Trace(map.Dimensions, p => board[p].HasTile, lightRange, lights)); }
public virtual void SetViews(FastList <RenderView> views) { Array.Resize(ref LightRanges, views.Count); // Reset ranges for (var i = 0; i < views.Count; ++i) { LightRanges[i] = new LightRange(0, 0); } }
public static (LightMap FloorLight, LightMap CeilingLight) Trace( Size dimensions, Func <Position, bool> isPositionObscured, LightRange lightRange, IEnumerable <LightDefinition> lights) { var floorLight = new LightMap(lightRange, dimensions).Blackout(); var ceilingLight = new LightMap(lightRange, dimensions).Blackout(); foreach (var light in lights) { // Check a big square around the light. This is very brute force but it doesn't appear to cause any // problems. for (int y = 0; y < light.LengthAffected; y++) { for (int x = 0; x < light.LengthAffected; x++) { var delta = new PositionDelta(x, y) - light.Radius; var location = light.Center + delta; if (!dimensions.Contains(location)) { continue; } // check for line of sight var obscured = DrawingUtil.BresenhamLine( start: light.Center, end: location) .Any(isPositionObscured); if (!obscured) { var(floorIncrement, ceilingIncrement) = light.GetBrightness(location); floorLight.Lighten(location, floorIncrement); ceilingLight.Lighten(location, ceilingIncrement); } } } } return(floorLight, ceilingLight); }
public static IEnumerable <(Position Location, TreasureType Type)> RandomlyPlaceTreasure( ConnectedArea area, IEnumerable <Position> edge, LightMap floorLighting, LightRange lightRange, Random random) { var maxScore = 3 * lightRange.DarkLevels; var cutOff = (int)(0.5 * maxScore); var scoredLocations = edge .Select(p => new { Location = p, Score = area.CountAdjacentWalls(p) * -floorLighting[p] }) .OrderBy(scoredLocation => scoredLocation.Score) .Where(scoredLocation => scoredLocation.Score >= cutOff) .OrderBy(sl => random.Next()) .ToArray(); var numberToTake = scoredLocations.Length / 2; return(scoredLocations.Take(numberToTake).Select(sl => (sl.Location, TreasureType.Medium))); }
public void ShowFloorVsCeilingLighting() { void SaveImage(IFastImage image, string description) => image.Save(Path.Combine(_dirInfo.FullName, $"{description}.png")); var random = new Random(Seed); var board = new CellBoard(new(128, 128)) .Fill(random, probabilityAlive: 0.5) .MakeBorderAlive(thickness: 3) .GenerateStandardCave(); var(largestComponent, dimensions) = ConnectedAreaAnalyzer .FindForegroundAreas(board.Dimensions, p => board[p] == CellType.Dead) .OrderByDescending(component => component.Area) .First() .TrimExcess(border: 1); var interior = largestComponent.DetermineInteriorEdgeDistance(Neighborhood.VonNeumann); // Place some lights var lightRange = new LightRange(DarkLevels: 15, LightLevels: 5); var lights = CaveThingPlacement.RandomlyPlaceLights( interior.Where(pair => pair.Value == 2).Select(pair => pair.Key).ToList(), random, lightRange, percentAreaToCover: 0.05, varyHeight: true) .ToArray(); var(floorLighting, ceilingLight) = LightTracer.Trace(dimensions, p => !largestComponent.Contains(p), lightRange, lights); using var floorImg = LightMapVisualizer.Render(floorLighting, lights, largestComponent, scale: 5); using var ceilingImg = LightMapVisualizer.Render(ceilingLight, lights, largestComponent, scale: 5); SaveImage(floorImg, "Floor"); SaveImage(ceilingImg, "Ceiling"); }
public static IEnumerable <LightDefinition> RandomlyPlaceLights( IReadOnlyList <Position> validPositions, Random random, LightRange lightRange, double percentAreaToCover, bool varyHeight = false) { var numLights = (int)(validPositions.Count * percentAreaToCover); var positions = new List <Position>(); return(Enumerable .Range(0, numLights) .Select(_ => { while (true) { var posIndex = random.Next(0, validPositions.Count); var position = validPositions[posIndex]; var positionIsInvalid = positions.Any(p => p.Touches(position)); if (positionIsInvalid) { continue; } positions.Add(position); return new LightDefinition( position, Brightness: lightRange.DarkLevels, Radius: 10, Height: varyHeight ? random.Next(2) == 0 ? LightHeight.Ceiling : LightHeight.Floor : LightHeight.Middle); } })); }
public static MapData Create(int seed, string texturePrefix, TextureQueue textureQueue) { var random = new Random(seed); var caveBoard = new CellBoard(new Size(128, 128)) .Fill(random, probabilityAlive: 0.5) .MakeBorderAlive(thickness: 3) .GenerateStandardCave(); var(caveArea, size) = ConnectedAreaAnalyzer .FindForegroundAreas(caveBoard.Dimensions, p => caveBoard[p] == CellType.Dead) .OrderByDescending(a => a.Area) .First() .TrimExcess(border: 1); var interior = caveArea.DetermineInteriorEdgeDistance(Neighborhood.VonNeumann); var alternateFloor = new CellBoard(new Size(size.Width + 1, size.Height + 1)) .Fill(random, probabilityAlive: 0.5) .RunGenerations(6); var alternateCeiling = new CellBoard(new Size(size.Width + 1, size.Height + 1)) .Fill(random, probabilityAlive: 0.5) .RunGenerations(6); var lightRange = new LightRange(DarkLevels: 15, LightLevels: 5); var lights = CaveThingPlacement.RandomlyPlaceLights( interior.Where(pair => pair.Value == 2).Select(pair => pair.Key).ToList(), random, lightRange, percentAreaToCover: 0.05, varyHeight: true) .ToArray(); var(floorLighting, ceilingLighting) = LightTracer.Trace(size, p => !caveArea.Contains(p), lightRange, lights); var(planeMap, sectors, tiles) = CreateGeometry( size, caveArea, alternateFloor, alternateCeiling, floorLighting, ceilingLighting, textureQueue, texturePrefix); var playerPosition = caveArea.First(); var things = lights.Select(light => new Thing( Type: light.Height == LightHeight.Ceiling ? "CeilingCrystal" : "FloorCrystal", X: light.Center.X + 0.5, Y: light.Center.Y + 0.5, Z: 0, Angle: 0, Ambush: false, Skill1: true, Skill2: true, Skill3: true, Skill4: true)).ToList(); things.Add(new Thing( Type: Actor.Player1Start.ClassName, X: playerPosition.X + 0.5, Y: playerPosition.Y + 0.5, Z: 0, Angle: 0, Ambush: false, Skill1: true, Skill2: true, Skill3: true, Skill4: true)); return(new MapData( NameSpace: "Wolf3D", TileSize: 64, Name: "Procedural Cave", Width: size.Width, Height: size.Height, Tiles: tiles, Sectors: sectors, Zones: ImmutableArray.Create(new Zone()), Planes: ImmutableArray.Create(new Plane(Depth: 64)), PlaneMaps: ImmutableArray.Create(planeMap), Things: things.ToImmutableArray(), Triggers: ImmutableArray <Trigger> .Empty)); }