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( );
}
}
}