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 : IChunkRenderer
+ public class StandardRenderer : AChunkRenderer
{
- private readonly int chunkSize;
-
/// <summary>
/// Renders shards similar to the Default VS version, plus P.O.I. markings.
/// </summary>
/// <param name="clientAPI">Client API.</param>
/// <param name="logger">Logger.</param>
- public StandardRenderer(ICoreClientAPI clientAPI, ILogger logger) : base(clientAPI, logger)
+ public StandardRenderer(ICoreClientAPI clientAPI, ILogger logger, bool seasonalColor) : base(clientAPI, logger, seasonalColor)
{
- chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
+
}
- public override void GenerateChunkPngShard(Vec2i chunkPos, IMapChunk mc, ColumnMeta metaData, PngWriter pngWriter, out uint pixelCount)
+ 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();
+ pixelCount = 0;
+ BlockPos tmpPos = new BlockPos( );
+ Vec2i localpos = new Vec2i( );
- var chunksColumn = new IWorldChunk[ClientAPI.World.BlockAccessor.MapSizeY / chunkSize];
+ var chunksColumn = new IWorldChunk[ClientAPI.World.BlockAccessor.MapSizeY / chunkSize];
- int topChunkY = mc.YMax / chunkSize;//Heywaitaminute -- this isn't a highest FEATURE, if Rainmap isn't accurate!
+ //pre-create PNG line slices...
+ ImageLine[ ] lines = Enumerable.Repeat(new object( ), chunkSize).Select(l => new ImageLine(this.PngWriter.ImgInfo)).ToArray( );
- for (int chunkY = 0; chunkY <= topChunkY; chunkY++)
- {
- chunksColumn[chunkY] = ClientAPI.World.BlockAccessor.GetChunk(chunkPos.X, chunkY, chunkPos.Y);
- //What to do if chunk is a void? invalid?
- }
+ int topChunkY = targetColMeta.YMax / chunkSize;
- // Prefetch map chunks, in pattern
- IMapChunk[] mapChunks = new IMapChunk[]
- {
- ClientAPI.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y - 1),
- ClientAPI.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y),
- ClientAPI.World.BlockAccessor.GetMapChunk(chunkPos.X, chunkPos.Y - 1)
- };
+ 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;
+ }
+ }
- //pre-create PNG line slices...
- ImageLine[] lines = Enumerable.Repeat(new object(), chunkSize).Select(l => new ImageLine(pngWriter.ImgInfo)).ToArray();
+ // Prefetch map chunks, in pattern
+ var mapCornerChunks = new List<ColumnMeta>(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 posIndex = 0; posIndex < (chunkSize * chunkSize); posIndex++)
- {
- int mapY = mc.RainHeightMap[posIndex];
- int localChunkY = mapY / chunkSize;
- if (localChunkY >= (chunksColumn.Length)) continue;//Out of range!
-
- MapUtil.PosInt2d(posIndex, chunkSize, localpos);
- int localX = localpos.X;
- int localZ = localpos.Y;
-
- float b = 1;
- int leftTop, rightTop, leftBot;
-
- IMapChunk leftTopMapChunk = mc;
- IMapChunk rightTopMapChunk = mc;
- IMapChunk leftBotMapChunk = mc;
-
- int topX = localX - 1;
- int botX = localX;
- int leftZ = localZ - 1;
- int rightZ = localZ;
-
- if (topX < 0 && leftZ < 0)
- {
- leftTopMapChunk = mapChunks[0];
- rightTopMapChunk = mapChunks[1];
- leftBotMapChunk = mapChunks[2];
- }
- else
- {
- if (topX < 0)
- {
- leftTopMapChunk = mapChunks[1];
- rightTopMapChunk = mapChunks[1];
- }
- if (leftZ < 0)
- {
- leftTopMapChunk = mapChunks[2];
- leftBotMapChunk = mapChunks[2];
- }
- }
-
- topX = GameMath.Mod(topX, chunkSize);
- leftZ = GameMath.Mod(leftZ, chunkSize);
-
- leftTop = leftTopMapChunk == null ? 0 : Math.Sign(mapY - leftTopMapChunk.RainHeightMap[leftZ * chunkSize + topX]);
- rightTop = rightTopMapChunk == null ? 0 : Math.Sign(mapY - rightTopMapChunk.RainHeightMap[rightZ * chunkSize + topX]);
- leftBot = leftBotMapChunk == null ? 0 : Math.Sign(mapY - leftBotMapChunk.RainHeightMap[leftZ * chunkSize + botX]);
-
- float slopeness = (leftTop + rightTop + leftBot);
-
- if (slopeness > 0) b = 1.2f;
- if (slopeness < 0) b = 0.8f;
-
- b -= 0.15f; //Slope boost value
-
- if (chunksColumn[localChunkY] == null)
- {
-
- continue;
- }
-
- chunksColumn[localChunkY].Unpack();
- int blockId = chunksColumn[localChunkY].Blocks[MapUtil.Index3d(localpos.X, mapY % chunkSize, localpos.Y, chunkSize, chunkSize)];
-
- Block block = ClientAPI.World.Blocks[blockId];
-
- tmpPos.Set(chunkSize * chunkPos.X + localpos.X, mapY, chunkSize * chunkPos.Y + localpos.Y);
-
- int avgCol = block.GetColor(ClientAPI, tmpPos);
- int rndCol = block.GetRandomColor(ClientAPI, tmpPos, BlockFacing.UP);
- int col = ColorUtil.ColorOverlay(avgCol, rndCol, 0.125f);
- var packedFormat = ColorUtil.ColorMultiply3Clamped(col, b);
-
- int red = ColorUtil.ColorB(packedFormat);
- int green = ColorUtil.ColorG(packedFormat);
- int blue = ColorUtil.ColorR(packedFormat);
-
-
- //============ 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);
-
- //chunkImage.SetPixel(localX, localZ, pixelColor);
- pixelCount++;
- }
- for (int row = 0; row < pngWriter.ImgInfo.Rows; row++)
+ 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)
{
- pngWriter.WriteRow(lines[row], row);
+ red = desig.OverwriteColor.R;
+ green = desig.OverwriteColor.G;
+ blue = desig.OverwriteColor.B;
}
+ }
- pngWriter.End();
+ 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( );
+ }
+ }
+}
\ No newline at end of file