OSDN Git Service

fix text formating error
[automap/automap.git] / Automap / Renderers / StandardRenderer.cs
1 using System;
2 using System.Collections.Generic;
3 //using System.Drawing;
4 //using System.Drawing.Imaging;
5 //using System.IO;
6 using System.Linq;
7
8 using Hjg.Pngcs;
9
10 using Vintagestory.API.Client;
11 using Vintagestory.API.Common;
12 using Vintagestory.API.MathTools;
13 using Vintagestory.Common;
14
15 namespace Automap
16 {
17         public class StandardRenderer : AChunkRenderer
18         {
19                 public const string Name = @"Standard";
20
21                 /// <summary>
22                 /// Renders shards similar to the Default VS version, plus P.O.I. markings.
23                 /// </summary>
24                 /// <param name="clientAPI">Client API.</param>
25                 /// <param name="logger">Logger.</param>
26                 public StandardRenderer(ICoreClientAPI clientAPI, ILogger logger, bool seasonalColor) : base(clientAPI, logger, seasonalColor)
27                 {
28                         
29                 }
30
31                 public override void GenerateChunkPngShard(Vec2i chunkPos, IMapChunk mapChunk, ColumnMeta targetColMeta, ref ColumnsMetadata allCols, out uint pixelCount)
32                 {
33                 pixelCount = 0;
34                 BlockPos tmpPos = new BlockPos( );
35                 Vec2i localpos = new Vec2i( );
36
37                 var chunksColumn = new IWorldChunk[ClientAPI.World.BlockAccessor.MapSizeY / chunkSize];
38
39                 //pre-create PNG line slices...
40                 ImageLine[ ] lines = Enumerable.Repeat(new object( ), chunkSize).Select(l => new ImageLine(this.PngWriter.ImgInfo)).ToArray( );
41
42                 int topChunkY = targetColMeta.YMax / chunkSize;
43
44                 for (int chunkY = 0; chunkY <= topChunkY; chunkY++) {
45                 chunksColumn[chunkY] = ClientAPI.World.BlockAccessor.GetChunk(chunkPos.X, chunkY, chunkPos.Y);
46                 WorldChunk ownChunk = chunksColumn[chunkY] as WorldChunk;
47                 if (ownChunk != null) {
48                 if (ownChunk.IsPacked( )) ownChunk.Unpack( );//Gah - probably done already by chunk processor
49                 }
50                 else {
51                 Logger.Warning("CHUNK A.W.O.L. : X{0} Y{1} Z{2} - Missing slice FOR COLUMN", chunkPos.X, chunkY, chunkPos.Y);
52                 //return;
53                 }
54                 }
55
56                 // Prefetch map chunks, in pattern              
57                 var corner_pos = new Vec2i(chunkPos.X - 1, chunkPos.Y - 1);
58                 var west_pos = new Vec2i(chunkPos.X, chunkPos.Y - 1);
59                 var north_pos = new Vec2i(chunkPos.X - 1 , chunkPos.Y);
60
61                 uint missingRainmap = 0, missingHeightmap = 0;
62
63                 ColumnMeta north, northWest, west;
64                 /* 
65                   "Overlap" Heightmap for Slope (height) values; covers 1 whole + 2 chunk edges, and corner block,
66                    substitute ZERO with Average Height....better than nothing even if its wrong?
67                 */
68                 var overlapHeightmap = new ushort[chunkSize + 1, chunkSize + 1];
69
70                 //Ofset copy of Heightmap...copied to Bottom, Rightmost
71                 for (int copyX = 0; copyX < chunkSize; copyX++)
72                 {
73                         for (int copyY = 0; copyY < chunkSize; copyY++) {
74                                 overlapHeightmap[copyX + 1, copyY + 1] = targetColMeta.HeightMap[copyX, copyY];
75                         }                       
76                 }
77
78
79
80                 if (allCols.Contains(corner_pos) && allCols[corner_pos].HeightMap != null) {
81                 northWest = allCols[corner_pos];
82                 overlapHeightmap[0, 0] = northWest.HeightMap[chunkSize - 1, chunkSize - 1];
83                 }
84                 else {
85                 missingHeightmap++;
86                 var cornerMC = ClientAPI.World.BlockAccessor.GetMapChunk(corner_pos);
87                 if (cornerMC != null && cornerMC.RainHeightMap != null) 
88                         {
89                         overlapHeightmap[0, 0] = cornerMC.RainHeight2DMap(chunkSize - 1, (chunkSize - 1));
90                         } else missingRainmap++;
91                 } 
92                 
93                 if (allCols.Contains(north_pos) && allCols[north_pos].HeightMap != null) {
94                 north = allCols[north_pos];
95
96                         for (int northEdgeIndex = 0; northEdgeIndex < chunkSize; northEdgeIndex++) 
97                         {
98                         overlapHeightmap[0, northEdgeIndex + 1 ] = north.HeightMap[ (chunkSize - 1), northEdgeIndex];                   
99                         }
100                 }               
101                 else {
102                         missingHeightmap++;
103                         var northMC = ClientAPI.World.BlockAccessor.GetMapChunk(north_pos);
104                         if (northMC != null && northMC.RainHeightMap != null) {
105                                 for (int northEdgeIndex = 0; northEdgeIndex < chunkSize; northEdgeIndex++) 
106                                 {
107                                 overlapHeightmap[0, northEdgeIndex + 1] = northMC.RainHeight2DMap((chunkSize - 1), northEdgeIndex);
108                                 }
109                         } else missingRainmap++;
110                 }
111
112                 if (allCols.Contains(west_pos) && allCols[west_pos].HeightMap != null) {
113                 west = allCols[west_pos];
114
115                         for (int westEdgeIndex = 0; westEdgeIndex < chunkSize; westEdgeIndex++) 
116                         {
117                         overlapHeightmap[westEdgeIndex + 1, 0] = west.HeightMap[westEdgeIndex, chunkSize - 1];
118                         }
119                 }               
120                 else {
121                 missingHeightmap++;
122                 var westMC = ClientAPI.World.BlockAccessor.GetMapChunk(west_pos);
123                 if (westMC != null && westMC.RainHeightMap != null) {
124                 for (int westEdgeIndex = 0; westEdgeIndex < chunkSize; westEdgeIndex++) {
125                 overlapHeightmap[westEdgeIndex + 1, 0] = westMC.RainHeight2DMap(westEdgeIndex, chunkSize - 1);
126                 }
127                 } else missingRainmap++;
128                 }
129                                 
130                 #if DEBUG
131                 var badHeightData = overlapHeightmap.OfType<ushort>( ).Count((ushort arg) => arg == 0); 
132
133                 if (badHeightData > 0)
134                 Logger.VerboseDebug("H.M Zeros# {0} , Missing Rainmaps {1} Heightmaps {2}",badHeightData ,missingRainmap, missingHeightmap);
135
136                 //RenderDebugBitmap(overlapHeightmap, chunkPos);
137                 #endif
138                 
139
140
141                 for (int pixelIndex = 0; pixelIndex < (chunkSize * chunkSize); pixelIndex++) {
142                 /********* PIXEL RENDERING LOOP **********/
143                 MapUtil.PosInt2d(pixelIndex, chunkSize, localpos);
144                 int localX = localpos.X;
145                 int localZ = localpos.Y;
146                 ushort localY = targetColMeta.HeightMap[localX, localZ];
147
148                 int localChunkY = localY / chunkSize;
149                 if (localChunkY >= (chunksColumn.Length)) continue;//Out of range!
150                 if (chunksColumn[localChunkY] == null) 
151                 {
152                 #if DEBUG
153                 Logger.VerboseDebug("Gap in chunk-column at render time Chunk-Y:{0}", localChunkY);
154                 #endif
155                 if (localChunkY == 0 ) break;
156                 continue;
157                 }
158
159                 float slopeBoost = 0.95f;
160                 int northH, northWestH, westH;
161
162                 int north_X = localX + 1;
163                 int north_Z = localZ;
164                 int west_X = localX;
165                 int west_Z = localZ + 1;
166                 int northWest_X = localX;
167                 int northWest_Z = localZ;
168                 bool edge = localX == 0 || localZ == 0;
169                         
170                 northH = Math.Sign(localY - (overlapHeightmap[north_X, north_Z] <= 1 ? localY : overlapHeightmap[north_X, north_Z]));
171                 northWestH = Math.Sign(localY - (overlapHeightmap[northWest_X, northWest_Z] <= 1 ? localY : overlapHeightmap[northWest_X, northWest_Z]));
172                 westH  = Math.Sign(localY - (overlapHeightmap[west_X, west_Z] <= 1 ? localY : overlapHeightmap[west_X, west_Z]));
173
174                 float slopeness = (northH + northWestH + westH);
175                 float tolerance = edge ? 1.0f : 0f;
176
177
178                 if (slopeness > tolerance) slopeBoost = 1.2f;
179                 if (slopeness < tolerance) slopeBoost = 0.8f;
180                 if (Math.Abs(slopeness) <= float.Epsilon) slopeBoost = 1.0f;//Same height
181                 //slopeBoost -= 0.15f; //Slope boost value                                              
182
183                 int blockId = chunksColumn[localChunkY].MaybeBlocks[MapUtil.Index3d(localX, (localY % chunkSize), localZ, chunkSize, chunkSize)];
184
185                 Block block = ClientAPI.World.Blocks[blockId];
186
187                 tmpPos.Set(chunkSize * chunkPos.X + localpos.X, localY, chunkSize * chunkPos.Y + localpos.Y);
188
189                 int red = 0, green = 0, blue = 0;
190
191                 ExtractBlockColor(tmpPos, block, slopeBoost, out red, out green, out blue);
192
193                 //============ POI Population =================
194                 if (BlockID_Designators.ContainsKey(blockId)) {
195                 var desig = BlockID_Designators[blockId];
196
197                         if (desig.Enabled) 
198                         {
199                         red = desig.OverwriteColor.R;
200                         green = desig.OverwriteColor.G;
201                         blue = desig.OverwriteColor.B;
202                         }
203                 }
204
205                 ImageLineHelper.SetPixel(lines[localZ], localX, red, green, blue);
206                 pixelCount++;
207                 }
208
209                 for (int row = 0; row < this.PngWriter.ImgInfo.Rows; row++) {
210                 this.PngWriter.WriteRow(lines[row], row);
211                 }
212
213                 this.PngWriter.End( );
214                 }
215
216                 /*
217                 private void RenderDebugBitmap( ushort[ , ] heightmap, Vec2i chunkOrigin )
218                 {
219                 Bitmap mapBitmap = null;
220                 Graphics gContext = null;
221                 mapBitmap = new Bitmap(33, 33, PixelFormat.Format24bppRgb);             
222                 gContext = Graphics.FromImage(mapBitmap);
223
224                 for (int x = 0; x <= chunkSize; x++) {
225                 for (int y = 0; y <= chunkSize; y++) {
226                 ushort heightCol = heightmap[x, y];
227                 Color color= Color.FromArgb((byte)heightCol,( byte )heightCol,( byte )heightCol);
228                 mapBitmap.SetPixel(x, y, color);
229                 }
230                 }
231                 
232                 gContext.Flush(System.Drawing.Drawing2D.FlushIntention.Sync);
233
234                 var fileName = Path.Combine( ClientAPI.GetOrCreateDataPath("Heightmaps"),$"offhm_{chunkOrigin.X}-{chunkOrigin.Y}.png");                         
235                 mapBitmap.Save(fileName, ImageFormat.Png);
236
237                 }
238                 */
239         }
240 }