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

Last change on this file since 135 was 135, checked in by alloc, 11 years ago

Fixes

File size: 7.8 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;
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 fullMapTexture = new Texture2D (widthPix, heightPix);
84
85 Vector2i curFullMapPos;
86 Vector2i curChunkPos;
87 for (curFullMapPos.x = 0; curFullMapPos.x < widthPix; curFullMapPos.x += Constants.MAP_CHUNK_SIZE) {
88 for (curFullMapPos.y = 0; curFullMapPos.y < heightPix; curFullMapPos.y += Constants.MAP_CHUNK_SIZE) {
89 curChunkPos.x = (curFullMapPos.x / Constants.MAP_CHUNK_SIZE) + minChunk.x;
90 curChunkPos.y = (curFullMapPos.y / Constants.MAP_CHUNK_SIZE) + minChunk.y;
91
92 RenderChunk (curChunkPos, curFullMapPos);
93 }
94 Log.Out (String.Format ("RenderMap: {0}/{1} ({2}%)", curFullMapPos.x, widthPix, (int)((float)curFullMapPos.x / widthPix * 100)));
95 }
96 SaveAllBlockMaps (null, null);
97
98 rfm = null;
99
100 byte[] array = fullMapTexture.EncodeToPNG ();
101 File.WriteAllBytes (Constants.MAP_DIRECTORY + "/map.png", array);
102 Texture2D.Destroy (fullMapTexture);
103
104 renderingFullMap = false;
105
106 Log.Out ("Generating map took: " + microStopwatch.ElapsedMilliseconds + " ms");
107 Log.Out ("World extent: " + minPos + " - " + maxPos);
108 }
109
110 private int saveCount = 0;
111
112 private void SaveAllBlockMaps (object source, System.Timers.ElapsedEventArgs e)
113 {
114 Monitor.Enter (zoomLevelBuffers);
115 try {
116 Log.Out ("------- SaveAllBlockMaps " + ++saveCount);
117 for (int i = 0; i < Constants.ZOOMLEVELS; i++) {
118 zoomLevelBuffers [i].SaveBlock ();
119 }
120 } finally {
121 Monitor.Exit (zoomLevelBuffers);
122 }
123 }
124
125 private bool RenderChunk (Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
126 {
127 long chunkKey = WorldChunkCache.MakeChunkKey (chunkPos.x, chunkPos.y);
128 if (rfm.ContainsChunkSync (chunkKey)) {
129 Chunk chunk = rfm.GetChunkSync (chunkKey);
130 return RenderChunk (chunk, chunkPos, fullMapPos);
131 }
132 return false;
133 }
134
135 private bool RenderChunk (Chunk chunk, Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
136 {
137 Monitor.Enter (zoomLevelBuffers);
138 try {
139 ushort[] mapColors = chunk.GetMapColors ();
140 if (mapColors != null) {
141 Vector2i block, blockOffset;
142 getBlockNumber (chunkPos, out block, out blockOffset, Constants.MAP_BLOCK_TO_CHUNK_DIV, Constants.MAP_CHUNK_SIZE);
143
144 for (int i_colors = 0; i_colors < mapColors.Length; i_colors++) {
145 chunkColors [i_colors] = shortColorToColor (mapColors [i_colors]);
146 }
147
148 zoomLevelBuffers [Constants.ZOOMLEVELS - 1].LoadBlock (block);
149 zoomLevelBuffers [Constants.ZOOMLEVELS - 1].SetPart (blockOffset, Constants.MAP_CHUNK_SIZE, chunkColors);
150
151 if (renderingFullMap)
152 fullMapTexture.SetPixels (fullMapPos.x, fullMapPos.y, Constants.MAP_CHUNK_SIZE, Constants.MAP_CHUNK_SIZE, chunkColors);
153
154 RenderZoomLevel (Constants.ZOOMLEVELS - 1, block);
155
156 return true;
157 }
158 return false;
159 } finally {
160 Monitor.Exit (zoomLevelBuffers);
161 }
162 }
163
164 private void RenderZoomLevel (int level, Vector2i innerBlock)
165 {
166 if (level > 0) {
167 Vector2i block, blockOffset;
168 getBlockNumber (innerBlock, out block, out blockOffset, 2, Constants.MAP_BLOCK_SIZE / 2);
169
170 zoomLevelBuffers [level - 1].LoadBlock (block);
171 zoomLevelBuffers [level - 1].SetPart (blockOffset, Constants.MAP_BLOCK_SIZE / 2, zoomLevelBuffers [level].GetHalfScaled ());
172
173 RenderZoomLevel (level - 1, block);
174 }
175 }
176
177 private void getBlockNumber (Vector2i innerPos, out Vector2i block, out Vector2i blockOffset, int scaleFactor, int offsetSize)
178 {
179 block.x = ((innerPos.x + 16777216) / scaleFactor) - (16777216 / scaleFactor);
180 block.y = ((innerPos.y + 16777216) / scaleFactor) - (16777216 / scaleFactor);
181 blockOffset.x = ((innerPos.x + 16777216) % scaleFactor) * offsetSize;
182 blockOffset.y = ((innerPos.y + 16777216) % scaleFactor) * offsetSize;
183 }
184
185 private void getWorldExtent (out Vector2i minChunk, out Vector2i maxChunk,
186 out Vector2i minPos, out Vector2i maxPos,
187 out int widthChunks, out int heightChunks,
188 out int widthPix, out int heightPix)
189 {
190 long[] keys = rfm.GetAllChunkKeys ();
191 int minX = Int32.MaxValue;
192 int minY = Int32.MaxValue;
193 int maxX = Int32.MinValue;
194 int maxY = Int32.MinValue;
195 foreach (long key in keys) {
196 int x = WorldChunkCache.extractX (key);
197 int y = WorldChunkCache.extractZ (key);
198
199 if (x < minX)
200 minX = x;
201 if (x > maxX)
202 maxX = x;
203 if (y < minY)
204 minY = y;
205 if (y > maxY)
206 maxY = y;
207 }
208
209 minChunk.x = minX;
210 minChunk.y = minY;
211
212 maxChunk.x = maxX;
213 maxChunk.y = maxY;
214
215 minPos.x = minX * Constants.MAP_CHUNK_SIZE;
216 minPos.y = minY * Constants.MAP_CHUNK_SIZE;
217
218 maxPos.x = maxX * Constants.MAP_CHUNK_SIZE;
219 maxPos.y = maxY * Constants.MAP_CHUNK_SIZE;
220
221 widthChunks = maxX - minX + 1;
222 heightChunks = maxY - minY + 1;
223
224 widthPix = widthChunks * Constants.MAP_CHUNK_SIZE;
225 heightPix = heightChunks * Constants.MAP_CHUNK_SIZE;
226 }
227
228 private Color32 shortColorToColor32 (ushort col)
229 {
230 return new Color32 ((byte)((float)(col >> 10 & 31) / 31f * 255f), (byte)((float)(col >> 5 & 31) / 31f * 255f), (byte)((float)(col & 31) / 31f * 255f), 255);
231 }
232
233 private Color shortColorToColor (ushort col)
234 {
235 return new Color (((float)(col >> 10 & 31) / 31f), ((float)(col >> 5 & 31) / 31f), ((float)(col & 31) / 31f), 255);
236 }
237
238 }
239}
Note: See TracBrowser for help on using the repository browser.