OSDN Git Service

6613555ac1ffc399094cbff25aff6a428d171037
[automap/automap.git] / Automap / Renderers / StandardRenderer.cs
1 using System;
2 using System.Linq;
3
4 using Hjg.Pngcs;
5
6 using Vintagestory.API.Client;
7 using Vintagestory.API.Common;
8 using Vintagestory.API.MathTools;
9 using Vintagestory.Common;
10
11 namespace Automap
12 {
13         public class StandardRenderer : AChunkRenderer
14         {
15
16                 /// <summary>
17                 /// Renders shards similar to the Default VS version, plus P.O.I. markings.
18                 /// </summary>
19                 /// <param name="clientAPI">Client API.</param>
20                 /// <param name="logger">Logger.</param>
21                 public StandardRenderer(ICoreClientAPI clientAPI, ILogger logger, bool seasonalColor) : base(clientAPI, logger, seasonalColor)
22                 {
23
24                 }
25
26                 public override void GenerateChunkPngShard(Vec2i chunkPos, IMapChunk mc, ColumnMeta metaData, out uint pixelCount)
27                 {
28                 pixelCount = 0;
29                 BlockPos tmpPos = new BlockPos( );
30                 Vec2i localpos = new Vec2i( );
31
32                 var chunksColumn = new IWorldChunk[ClientAPI.World.BlockAccessor.MapSizeY / chunkSize];
33
34                 //pre-create PNG line slices...
35                 ImageLine[ ] lines = Enumerable.Repeat(new object( ), chunkSize).Select(l => new ImageLine(this.PngWriter.ImgInfo)).ToArray( );
36
37                 int topChunkY = metaData.YMax / chunkSize;
38
39                 for (int chunkY = 0; chunkY <= topChunkY; chunkY++) 
40                 {
41                         chunksColumn[chunkY] = ClientAPI.World.BlockAccessor.GetChunk(chunkPos.X, chunkY, chunkPos.Y);
42                         WorldChunk ownChunk = chunksColumn[chunkY] as WorldChunk;
43                         if (ownChunk != null) 
44                                 {
45                                 if (ownChunk.IsPacked( )) ownChunk.Unpack( );//Gah - probably done already by chunk processor
46                                 }
47                                 else 
48                                 {
49                                 Logger.Warning("CHUNK A.W.O.L. : X{0} Y{1} Z{2} - Missing slice FOR COLUMN", chunkPos.X, chunkY, chunkPos.Y);
50                                 //return;
51                                 }
52                 }
53
54                 // Prefetch map chunks, in pattern
55                 IMapChunk[ ] mapChunks = new IMapChunk[ ]
56                 {
57                         ClientAPI.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y - 1),
58                         ClientAPI.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y),
59                         ClientAPI.World.BlockAccessor.GetMapChunk(chunkPos.X, chunkPos.Y - 1)
60                 };
61                 
62
63                 for (int pixelIndex = 0; pixelIndex < (chunkSize * chunkSize); pixelIndex++) {
64                 MapUtil.PosInt2d(pixelIndex, chunkSize, localpos);
65                 int localX = localpos.X;
66                 int localZ = localpos.Y;
67                 ushort localY = metaData.HeightMap[localX, localZ];
68
69                 int localChunkY = localY / chunkSize;
70                 if (localChunkY >= (chunksColumn.Length)) continue;//Out of range!
71                 if (chunksColumn[localChunkY] == null) continue;//BIG Gaps!
72                 if (mapChunks.Any(chks => chks == null)) {
73                 //Logger.Warning("MapChunk A.W.O.L. near : X{0} Y{1} Z{2}       - ", localX, localY, localZ);
74                 continue;
75                 }
76
77                 float slopeBoost = 1;
78                 int leftTop, rightTop, leftBot;
79
80                 IMapChunk leftTopMapChunk = mc;
81                 IMapChunk rightTopMapChunk = mc;
82                 IMapChunk leftBotMapChunk = mc;
83
84                 int topX = localX - 1;
85                 int botX = localX;
86                 int leftZ = localZ - 1;
87                 int rightZ = localZ;
88
89                 if (topX < 0 && leftZ < 0) {
90                 leftTopMapChunk = mapChunks[0];
91                 rightTopMapChunk = mapChunks[1];
92                 leftBotMapChunk = mapChunks[2];
93                 }
94                 else {
95                 if (topX < 0) {
96                 leftTopMapChunk = mapChunks[1];
97                 rightTopMapChunk = mapChunks[1];
98                 }
99                 if (leftZ < 0) {
100                 leftTopMapChunk = mapChunks[2];
101                 leftBotMapChunk = mapChunks[2];
102                 }
103                 }
104
105                 topX = GameMath.Mod(topX, chunkSize);
106                 leftZ = GameMath.Mod(leftZ, chunkSize);
107                 //TODO: Replace with Metadata Heightmap?
108                 leftTop = leftTopMapChunk == null ? 0 : Math.Sign(localY - leftTopMapChunk.RainHeightMap[leftZ * chunkSize + topX]);
109                 rightTop = rightTopMapChunk == null ? 0 : Math.Sign(localY - rightTopMapChunk.RainHeightMap[rightZ * chunkSize + topX]);
110                 leftBot = leftBotMapChunk == null ? 0 : Math.Sign(localY - leftBotMapChunk.RainHeightMap[leftZ * chunkSize + botX]);
111
112                 float slopeness = (leftTop + rightTop + leftBot);
113
114                 if (slopeness > 0) slopeBoost = 1.2f;
115                 if (slopeness < 0) slopeBoost = 0.8f;
116
117                 slopeBoost -= 0.15f; //Slope boost value 
118
119                 int blockId = chunksColumn[localChunkY].MaybeBlocks[MapUtil.Index3d(localX, (localY % chunkSize), localZ, chunkSize, chunkSize)];
120
121                 Block block = ClientAPI.World.Blocks[blockId];
122
123                 tmpPos.Set(chunkSize * chunkPos.X + localpos.X, localY, chunkSize * chunkPos.Y + localpos.Y);
124
125                 int red = 0, green = 0, blue = 0;
126
127                 ExtractBlockColor(tmpPos, block, slopeBoost, out red, out green, out blue);
128
129                 //============ POI Population =================
130                 if (BlockID_Designators.ContainsKey(blockId)) {
131                 var desig = BlockID_Designators[blockId];
132
133                         if (desig.Enabled) 
134                         {
135                         red = desig.OverwriteColor.R;
136                         green = desig.OverwriteColor.G;
137                         blue = desig.OverwriteColor.B;
138                         }
139                 }
140
141                 ImageLineHelper.SetPixel(lines[localZ], localX, red, green, blue);
142                 pixelCount++;
143                 }
144
145                 for (int row = 0; row < this.PngWriter.ImgInfo.Rows; row++) {
146                 this.PngWriter.WriteRow(lines[row], row);
147                 }
148
149                 this.PngWriter.End( );
150                 }
151         }
152 }