using System; using System.Collections.Generic; using System.Linq; using Hjg.Pngcs; using Vintagestory.API.Client; using Vintagestory.API.Common; using Vintagestory.API.MathTools; using Vintagestory.Common; namespace Automap { public class StandardRenderer : AChunkRenderer { public const string Name = @"Standard"; /// /// Renders shards similar to the Default VS version, plus P.O.I. markings. /// /// Client API. /// Logger. public StandardRenderer(ICoreClientAPI clientAPI, ILogger logger, bool seasonalColor) : base(clientAPI, logger, seasonalColor) { } public override void GenerateChunkPngShard(Vec2i chunkPos, IMapChunk mc, ColumnMeta targetColMeta, ref ColumnsMetadata allCols, out uint pixelCount) { pixelCount = 0; BlockPos tmpPos = new BlockPos( ); Vec2i localpos = new Vec2i( ); var chunksColumn = new IWorldChunk[ClientAPI.World.BlockAccessor.MapSizeY / chunkSize]; //pre-create PNG line slices... ImageLine[ ] lines = Enumerable.Repeat(new object( ), chunkSize).Select(l => new ImageLine(this.PngWriter.ImgInfo)).ToArray( ); int topChunkY = targetColMeta.YMax / chunkSize; for (int chunkY = 0; chunkY <= topChunkY; chunkY++) { chunksColumn[chunkY] = ClientAPI.World.BlockAccessor.GetChunk(chunkPos.X, chunkY, chunkPos.Y); WorldChunk ownChunk = chunksColumn[chunkY] as WorldChunk; if (ownChunk != null) { if (ownChunk.IsPacked( )) ownChunk.Unpack( );//Gah - probably done already by chunk processor } else { Logger.Warning("CHUNK A.W.O.L. : X{0} Y{1} Z{2} - Missing slice FOR COLUMN", chunkPos.X, chunkY, chunkPos.Y); //return; } } // Prefetch map chunks, in pattern var mapCornerChunks = new List(3); var south_west = new Vec2i(chunkPos.X - 1, chunkPos.Y - 1); var west = new Vec2i(chunkPos.X - 1, chunkPos.Y); var south = new Vec2i(chunkPos.X, chunkPos.Y - 1); bool nullSouthWest = false, nullSouth = false, nullWest = false; /* For missing corners / cardinal heightmaps... make fake heightmap dummy */ if (allCols.Contains(south_west)) { mapCornerChunks.Add(allCols[south_west]); } else { nullSouthWest = true; mapCornerChunks.Add(targetColMeta);//Temporary! } if (allCols.Contains(south)) { mapCornerChunks.Add(allCols[south]); } else { nullSouth = true; mapCornerChunks.Add(targetColMeta);//Temporary! } if (allCols.Contains(west)) { mapCornerChunks.Add(allCols[west]); } else { nullWest = true; mapCornerChunks.Add(targetColMeta);//Temporary! } for (int pixelIndex = 0; pixelIndex < (chunkSize * chunkSize); pixelIndex++) { MapUtil.PosInt2d(pixelIndex, chunkSize, localpos); int localX = localpos.X; int localZ = localpos.Y; ushort localY = targetColMeta.HeightMap[localX, localZ]; int localChunkY = localY / chunkSize; if (localChunkY >= (chunksColumn.Length)) continue;//Out of range! if (chunksColumn[localChunkY] == null) continue;//BIG Gaps! //if (mapCornerChunks.Any(chks => chks == null)) { //Logger.Warning("mapCornerChunks A.W.O.L. near : X{0} Y{1} Z{2} - ", localX, localY, localZ); //continue; //} float slopeBoost = 1; int leftTop, rightTop, leftBot; ColumnMeta leftTopMapChunk = targetColMeta; ColumnMeta rightTopMapChunk = targetColMeta; ColumnMeta leftBotMapChunk = targetColMeta; int topX = localX - 1; int botX = localX; int leftZ = localZ - 1; int rightZ = localZ; if (topX < 0 && leftZ < 0) { leftTopMapChunk = mapCornerChunks[0]; rightTopMapChunk = mapCornerChunks[1]; leftBotMapChunk = mapCornerChunks[2]; } else { if (topX < 0) { leftTopMapChunk = mapCornerChunks[1]; rightTopMapChunk = mapCornerChunks[1]; } if (leftZ < 0) { leftTopMapChunk = mapCornerChunks[2]; leftBotMapChunk = mapCornerChunks[2]; } } topX = GameMath.Mod(topX, chunkSize); leftZ = GameMath.Mod(leftZ, chunkSize); leftTop = nullSouthWest ? 0 : Math.Sign(localY - leftTopMapChunk.HeightMap[topX, leftZ]); rightTop = nullSouth ? 0 : Math.Sign(localY - rightTopMapChunk.HeightMap[topX, rightZ]); leftBot = nullWest ? 0 : Math.Sign(localY - leftBotMapChunk.HeightMap[botX, leftZ]); float slopeness = (leftTop + rightTop + leftBot); if (slopeness > 0) slopeBoost = 1.2f; if (slopeness < 0) slopeBoost = 0.8f; slopeBoost -= 0.15f; //Slope boost value int blockId = chunksColumn[localChunkY].MaybeBlocks[MapUtil.Index3d(localX, (localY % chunkSize), localZ, chunkSize, chunkSize)]; Block block = ClientAPI.World.Blocks[blockId]; tmpPos.Set(chunkSize * chunkPos.X + localpos.X, localY, chunkSize * chunkPos.Y + localpos.Y); int red = 0, green = 0, blue = 0; ExtractBlockColor(tmpPos, block, slopeBoost, out red, out green, out blue); //============ POI Population ================= if (BlockID_Designators.ContainsKey(blockId)) { var desig = BlockID_Designators[blockId]; if (desig.Enabled) { red = desig.OverwriteColor.R; green = desig.OverwriteColor.G; blue = desig.OverwriteColor.B; } } ImageLineHelper.SetPixel(lines[localZ], localX, red, green, blue); pixelCount++; } for (int row = 0; row < this.PngWriter.ImgInfo.Rows; row++) { this.PngWriter.WriteRow(lines[row], row); } this.PngWriter.End( ); } } }