OSDN Git Service

Inelegant workaround for Slop-shading issue
[automap/automap.git] / Automap / Renderers / StandardRenderer.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4
5 using Hjg.Pngcs;
6
7 using Vintagestory.API.Client;
8 using Vintagestory.API.Common;
9 using Vintagestory.API.MathTools;
10 using Vintagestory.Common;
11
12 namespace Automap
13 {
14         public class StandardRenderer : AChunkRenderer
15         {
16                 public const string Name = @"Standard";
17
18                 /// <summary>
19                 /// Renders shards similar to the Default VS version, plus P.O.I. markings.
20                 /// </summary>
21                 /// <param name="clientAPI">Client API.</param>
22                 /// <param name="logger">Logger.</param>
23                 public StandardRenderer(ICoreClientAPI clientAPI, ILogger logger, bool seasonalColor) : base(clientAPI, logger, seasonalColor)
24                 {
25                         
26                 }
27
28                 public override void GenerateChunkPngShard(Vec2i chunkPos, IMapChunk mc, ColumnMeta targetColMeta, ref ColumnsMetadata allCols, out uint pixelCount)
29                 {
30                 pixelCount = 0;
31                 BlockPos tmpPos = new BlockPos( );
32                 Vec2i localpos = new Vec2i( );
33
34                 var chunksColumn = new IWorldChunk[ClientAPI.World.BlockAccessor.MapSizeY / chunkSize];
35
36                 //pre-create PNG line slices...
37                 ImageLine[ ] lines = Enumerable.Repeat(new object( ), chunkSize).Select(l => new ImageLine(this.PngWriter.ImgInfo)).ToArray( );
38
39                 int topChunkY = targetColMeta.YMax / chunkSize;
40
41                 for (int chunkY = 0; chunkY <= topChunkY; chunkY++) {
42                 chunksColumn[chunkY] = ClientAPI.World.BlockAccessor.GetChunk(chunkPos.X, chunkY, chunkPos.Y);
43                 WorldChunk ownChunk = chunksColumn[chunkY] as WorldChunk;
44                 if (ownChunk != null) {
45                 if (ownChunk.IsPacked( )) ownChunk.Unpack( );//Gah - probably done already by chunk processor
46                 }
47                 else {
48                 Logger.Warning("CHUNK A.W.O.L. : X{0} Y{1} Z{2} - Missing slice FOR COLUMN", chunkPos.X, chunkY, chunkPos.Y);
49                 //return;
50                 }
51                 }
52
53                 // Prefetch map chunks, in pattern
54                 var mapCornerChunks = new List<ColumnMeta>(3);
55
56                 var south_west = new Vec2i(chunkPos.X - 1, chunkPos.Y - 1);
57                 var west = new Vec2i(chunkPos.X - 1, chunkPos.Y);
58                 var south = new Vec2i(chunkPos.X, chunkPos.Y - 1);
59
60                 bool nullSouthWest = false, nullSouth = false, nullWest = false;
61
62                 /* 
63                 For missing corners / cardinal heightmaps...
64                 make fake heightmap dummy
65                 */
66
67                 if (allCols.Contains(south_west)) {
68                 mapCornerChunks.Add(allCols[south_west]);               
69                 }
70                 else {
71                 nullSouthWest = true;
72                 mapCornerChunks.Add(targetColMeta);//Temporary!
73                 }
74
75                 if (allCols.Contains(south)) {
76                 mapCornerChunks.Add(allCols[south]);
77                 }
78                 else {
79                 nullSouth = true;
80                 mapCornerChunks.Add(targetColMeta);//Temporary!
81                 }
82
83                 if (allCols.Contains(west)) {
84                 mapCornerChunks.Add(allCols[west]);
85                 }
86                 else {
87                 nullWest = true;
88                 mapCornerChunks.Add(targetColMeta);//Temporary!
89                 }
90
91
92                 for (int pixelIndex = 0; pixelIndex < (chunkSize * chunkSize); pixelIndex++) {
93                 MapUtil.PosInt2d(pixelIndex, chunkSize, localpos);
94                 int localX = localpos.X;
95                 int localZ = localpos.Y;
96                 ushort localY = targetColMeta.HeightMap[localX, localZ];
97
98                 int localChunkY = localY / chunkSize;
99                 if (localChunkY >= (chunksColumn.Length)) continue;//Out of range!
100                 if (chunksColumn[localChunkY] == null) continue;//BIG Gaps!
101                 //if (mapCornerChunks.Any(chks => chks == null)) {
102                 //Logger.Warning("mapCornerChunks A.W.O.L. near : X{0} Y{1} Z{2}        - ", localX, localY, localZ);
103                 //continue;
104                 //}
105
106                 float slopeBoost = 1f;
107                 int leftTop, rightTop, leftBot;
108
109                 ColumnMeta leftTopMapChunk = targetColMeta;
110                 ColumnMeta rightTopMapChunk = targetColMeta;
111                 ColumnMeta leftBotMapChunk = targetColMeta;
112
113                 int topX = localX - 1;
114                 int botX = localX;
115                 int leftZ = localZ - 1;
116                 int rightZ = localZ;
117
118                 if (topX < 0 && leftZ < 0) {
119                 leftTopMapChunk = mapCornerChunks[0];
120                 rightTopMapChunk = mapCornerChunks[1];
121                 leftBotMapChunk = mapCornerChunks[2];
122                 }
123                 else {
124                 if (topX < 0) {
125                 leftTopMapChunk = mapCornerChunks[1];
126                 rightTopMapChunk = mapCornerChunks[1];
127                 }
128                 if (leftZ < 0) {
129                 leftTopMapChunk = mapCornerChunks[2];
130                 leftBotMapChunk = mapCornerChunks[2];
131                 }
132                 }
133
134                 topX = GameMath.Mod(topX, chunkSize);
135                 leftZ = GameMath.Mod(leftZ, chunkSize);
136                 
137                 leftTop = nullSouthWest ? 0 : Math.Sign(localY - leftTopMapChunk.HeightMap[topX, leftZ]);
138                 rightTop = nullSouth ? 0 : Math.Sign(localY - rightTopMapChunk.HeightMap[topX, rightZ]);
139                 leftBot = nullWest ? 0 : Math.Sign(localY - leftBotMapChunk.HeightMap[botX, leftZ]);
140
141                 float slopeness = (leftTop + rightTop + leftBot);
142
143                 if (slopeness > 0) slopeBoost = 1.2f;
144                 if (slopeness < 0) slopeBoost = 0.8f;
145                 if (Math.Abs(slopeness) <= float.Epsilon) slopeBoost = 1.0f;//Same height
146                 //slopeBoost -= 0.15f; //Slope boost value 
147
148                 //FIXME: disable slopes on edges...for now
149                 if (localX == 0 || localX == 31) slopeBoost= 1.0f;
150                 if (localZ == 0 || localZ == 31) slopeBoost= 1.0f;
151
152                 int blockId = chunksColumn[localChunkY].MaybeBlocks[MapUtil.Index3d(localX, (localY % chunkSize), localZ, chunkSize, chunkSize)];
153
154                 Block block = ClientAPI.World.Blocks[blockId];
155
156                 tmpPos.Set(chunkSize * chunkPos.X + localpos.X, localY, chunkSize * chunkPos.Y + localpos.Y);
157
158                 int red = 0, green = 0, blue = 0;
159
160                 ExtractBlockColor(tmpPos, block, slopeBoost, out red, out green, out blue);
161
162                 //============ POI Population =================
163                 if (BlockID_Designators.ContainsKey(blockId)) {
164                 var desig = BlockID_Designators[blockId];
165
166                         if (desig.Enabled) 
167                         {
168                         red = desig.OverwriteColor.R;
169                         green = desig.OverwriteColor.G;
170                         blue = desig.OverwriteColor.B;
171                         }
172                 }
173
174                 ImageLineHelper.SetPixel(lines[localZ], localX, red, green, blue);
175                 pixelCount++;
176                 }
177
178                 for (int row = 0; row < this.PngWriter.ImgInfo.Rows; row++) {
179                 this.PngWriter.WriteRow(lines[row], row);
180                 }
181
182                 this.PngWriter.End( );
183                 }
184         }
185 }