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

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

Fixes

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