source: binary-improvements/7dtd-server-fixes/src/MapRendering/MapRendering.cs@ 137

Last change on this file since 137 was 136, checked in by alloc, 10 years ago

Fixes

File size: 7.9 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Threading;
5using UnityEngine;
6
7namespace AllocsFixes.MapRendering
8{
9 public class MapRendering
10 {
11 private static MapRendering instance;
12
13 public static MapRendering Instance {
14 get {
15 if (instance == null) {
16 instance = new MapRendering ();
17 }
18 return instance;
19 }
20 }
21
22 private RegionFileManager rfm;
23 private Texture2D fullMapTexture = null;
24 private MapRenderBlockBuffer[] zoomLevelBuffers = new MapRenderBlockBuffer[Constants.ZOOMLEVELS];
25 private Color[] chunkColors = new Color[Constants.MAP_CHUNK_SIZE * Constants.MAP_CHUNK_SIZE];
26 private System.Timers.Timer chunkSaveTimer = new System.Timers.Timer (500);
27 private bool renderingFullMap = false;
28
29 private MapRendering ()
30 {
31 Constants.MAP_DIRECTORY = StaticDirectories.GetSaveGameDir () + "/map";
32
33 for (int i = 0; i < Constants.ZOOMLEVELS; i++) {
34 zoomLevelBuffers [i] = new MapRenderBlockBuffer (i);
35 }
36
37 chunkSaveTimer.AutoReset = false;
38 chunkSaveTimer.Elapsed += new System.Timers.ElapsedEventHandler (SaveAllBlockMaps);
39 }
40
41 public static void RenderSingleChunk (Chunk chunk)
42 {
43 ThreadPool.QueueUserWorkItem ((o) =>
44 {
45 try {
46 if (!Instance.renderingFullMap) {
47 Chunk c = (Chunk)o;
48 Vector3i cPos = c.GetWorldPos ();
49 Vector2i cPos2 = new Vector2i (cPos.x / Constants.MAP_CHUNK_SIZE, cPos.z / Constants.MAP_CHUNK_SIZE);
50 Instance.RenderChunk (c, cPos2);
51 Instance.chunkSaveTimer.Stop ();
52 Instance.chunkSaveTimer.Start ();
53 }
54 } catch (Exception e) {
55 Log.Out ("Exception in MapRendering.RenderSingleChunk(): " + e);
56 }
57 }, chunk);
58 }
59
60 public void RenderFullMap ()
61 {
62 MicroStopwatch microStopwatch = new MicroStopwatch ();
63
64 string regionSaveDir = StaticDirectories.GetSaveGameRegionDir ();
65 rfm = new RegionFileManager (regionSaveDir, regionSaveDir, 1, false);
66
67 if (Directory.Exists (Constants.MAP_DIRECTORY))
68 Directory.Delete (Constants.MAP_DIRECTORY, true);
69
70 renderingFullMap = true;
71
72 Vector2i minChunk, maxChunk;
73 Vector2i minPos, maxPos;
74 int widthChunks, heightChunks, widthPix, heightPix;
75 getWorldExtent (out minChunk, out maxChunk, out minPos, out maxPos, out widthChunks, out heightChunks, out widthPix, out heightPix);
76
77 Log.Out (String.Format ("RenderMap: min: {0}, max: {1}, minPos: {2}, maxPos: {3}, w/h: {4}/{5}, wP/hP: {6}/{7}",
78 minChunk.ToString (), maxChunk.ToString (),
79 minPos.ToString (), maxPos.ToString (),
80 widthChunks, heightChunks,
81 widthPix, heightPix)
82 );
83
84 if (widthPix <= 8000 && heightPix <= 8000)
85 fullMapTexture = new Texture2D (widthPix, heightPix);
86
87 Vector2i curFullMapPos;
88 Vector2i curChunkPos;
89 for (curFullMapPos.x = 0; curFullMapPos.x < widthPix; curFullMapPos.x += Constants.MAP_CHUNK_SIZE) {
90 for (curFullMapPos.y = 0; curFullMapPos.y < heightPix; curFullMapPos.y += Constants.MAP_CHUNK_SIZE) {
91 curChunkPos.x = (curFullMapPos.x / Constants.MAP_CHUNK_SIZE) + minChunk.x;
92 curChunkPos.y = (curFullMapPos.y / Constants.MAP_CHUNK_SIZE) + minChunk.y;
93
94 RenderChunk (curChunkPos, curFullMapPos);
95 }
96 Log.Out (String.Format ("RenderMap: {0}/{1} ({2}%)", curFullMapPos.x, widthPix, (int)((float)curFullMapPos.x / widthPix * 100)));
97 }
98 SaveAllBlockMaps (null, null);
99
100 rfm = null;
101
102 if (fullMapTexture != null) {
103 byte[] array = fullMapTexture.EncodeToPNG ();
104 File.WriteAllBytes (Constants.MAP_DIRECTORY + "/map.png", array);
105 Texture2D.Destroy (fullMapTexture);
106 fullMapTexture = null;
107 }
108
109 renderingFullMap = false;
110
111 Log.Out ("Generating map took: " + microStopwatch.ElapsedMilliseconds + " ms");
112 Log.Out ("World extent: " + minPos + " - " + maxPos);
113 }
114
115 private int saveCount = 0;
116
117 private void SaveAllBlockMaps (object source, System.Timers.ElapsedEventArgs e)
118 {
119 Monitor.Enter (zoomLevelBuffers);
120 try {
121 Log.Out ("------- SaveAllBlockMaps " + ++saveCount);
122 for (int i = 0; i < Constants.ZOOMLEVELS; i++) {
123 zoomLevelBuffers [i].SaveBlock ();
124 }
125 } finally {
126 Monitor.Exit (zoomLevelBuffers);
127 }
128 }
129
130 private bool RenderChunk (Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
131 {
132 long chunkKey = WorldChunkCache.MakeChunkKey (chunkPos.x, chunkPos.y);
133 if (rfm.ContainsChunkSync (chunkKey)) {
134 Chunk chunk = rfm.GetChunkSync (chunkKey);
135 return RenderChunk (chunk, chunkPos, fullMapPos);
136 }
137 return false;
138 }
139
140 private bool RenderChunk (Chunk chunk, Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
141 {
142 Monitor.Enter (zoomLevelBuffers);
143 try {
144 ushort[] mapColors = chunk.GetMapColors ();
145 if (mapColors != null) {
146 Vector2i block, blockOffset;
147 getBlockNumber (chunkPos, out block, out blockOffset, Constants.MAP_BLOCK_TO_CHUNK_DIV, Constants.MAP_CHUNK_SIZE);
148
149 for (int i_colors = 0; i_colors < mapColors.Length; i_colors++) {
150 chunkColors [i_colors] = shortColorToColor (mapColors [i_colors]);
151 }
152
153 zoomLevelBuffers [Constants.ZOOMLEVELS - 1].LoadBlock (block);
154 zoomLevelBuffers [Constants.ZOOMLEVELS - 1].SetPart (blockOffset, Constants.MAP_CHUNK_SIZE, chunkColors);
155
156 if (renderingFullMap && fullMapTexture != null)
157 fullMapTexture.SetPixels (fullMapPos.x, fullMapPos.y, Constants.MAP_CHUNK_SIZE, Constants.MAP_CHUNK_SIZE, chunkColors);
158
159 RenderZoomLevel (Constants.ZOOMLEVELS - 1, block);
160
161 return true;
162 }
163 return false;
164 } finally {
165 Monitor.Exit (zoomLevelBuffers);
166 }
167 }
168
169 private void RenderZoomLevel (int level, Vector2i innerBlock)
170 {
171 if (level > 0) {
172 Vector2i block, blockOffset;
173 getBlockNumber (innerBlock, out block, out blockOffset, 2, Constants.MAP_BLOCK_SIZE / 2);
174
175 zoomLevelBuffers [level - 1].LoadBlock (block);
176 zoomLevelBuffers [level - 1].SetPart (blockOffset, Constants.MAP_BLOCK_SIZE / 2, zoomLevelBuffers [level].GetHalfScaled ());
177
178 RenderZoomLevel (level - 1, block);
179 }
180 }
181
182 private void getBlockNumber (Vector2i innerPos, out Vector2i block, out Vector2i blockOffset, int scaleFactor, int offsetSize)
183 {
184 block.x = ((innerPos.x + 16777216) / scaleFactor) - (16777216 / scaleFactor);
185 block.y = ((innerPos.y + 16777216) / scaleFactor) - (16777216 / scaleFactor);
186 blockOffset.x = ((innerPos.x + 16777216) % scaleFactor) * offsetSize;
187 blockOffset.y = ((innerPos.y + 16777216) % scaleFactor) * offsetSize;
188 }
189
190 private void getWorldExtent (out Vector2i minChunk, out Vector2i maxChunk,
191 out Vector2i minPos, out Vector2i maxPos,
192 out int widthChunks, out int heightChunks,
193 out int widthPix, out int heightPix)
194 {
195 long[] keys = rfm.GetAllChunkKeys ();
196 int minX = Int32.MaxValue;
197 int minY = Int32.MaxValue;
198 int maxX = Int32.MinValue;
199 int maxY = Int32.MinValue;
200 foreach (long key in keys) {
201 int x = WorldChunkCache.extractX (key);
202 int y = WorldChunkCache.extractZ (key);
203
204 if (x < minX)
205 minX = x;
206 if (x > maxX)
207 maxX = x;
208 if (y < minY)
209 minY = y;
210 if (y > maxY)
211 maxY = y;
212 }
213
214 minChunk.x = minX;
215 minChunk.y = minY;
216
217 maxChunk.x = maxX;
218 maxChunk.y = maxY;
219
220 minPos.x = minX * Constants.MAP_CHUNK_SIZE;
221 minPos.y = minY * Constants.MAP_CHUNK_SIZE;
222
223 maxPos.x = maxX * Constants.MAP_CHUNK_SIZE;
224 maxPos.y = maxY * Constants.MAP_CHUNK_SIZE;
225
226 widthChunks = maxX - minX + 1;
227 heightChunks = maxY - minY + 1;
228
229 widthPix = widthChunks * Constants.MAP_CHUNK_SIZE;
230 heightPix = heightChunks * Constants.MAP_CHUNK_SIZE;
231 }
232
233 private Color32 shortColorToColor32 (ushort col)
234 {
235 return new Color32 ((byte)((float)(col >> 10 & 31) / 31f * 255f), (byte)((float)(col >> 5 & 31) / 31f * 255f), (byte)((float)(col & 31) / 31f * 255f), 255);
236 }
237
238 private Color shortColorToColor (ushort col)
239 {
240 return new Color (((float)(col >> 10 & 31) / 31f), ((float)(col >> 5 & 31) / 31f), ((float)(col & 31) / 31f), 255);
241 }
242
243 }
244}
Note: See TracBrowser for help on using the repository browser.