]> icculus.org git repositories - divverent/nexuiz.git/blob - tools/ImgToMap/src/imgtomap/MapWriter.java
Directly output to a PrintWriter, don't keep the whole map in a BufferedString and...
[divverent/nexuiz.git] / tools / ImgToMap / src / imgtomap / MapWriter.java
1 /*
2  * To change this template, choose Tools | Templates
3  * and open the template in the editor.
4  */
5 package imgtomap;
6
7 import java.awt.image.BufferedImage;
8 import java.awt.image.Raster;
9 import java.io.BufferedOutputStream;
10 import java.io.File;
11 import java.io.FileNotFoundException;
12 import java.io.FileOutputStream;
13 import java.io.IOException;
14 import java.io.PrintWriter;
15 import java.util.logging.Level;
16 import java.util.logging.Logger;
17 import javax.imageio.ImageIO;
18
19 /**
20  *
21  * @author maik
22  */
23 public class MapWriter {
24
25     public int writeMap(Parameters p) {
26         if (!(new File(p.infile).exists())) {
27             return 1;
28         }
29
30         FileOutputStream fos;
31         try {
32             fos = new FileOutputStream(new File(p.outfile));
33         } catch (FileNotFoundException ex) {
34             Logger.getLogger(MapWriter.class.getName()).log(Level.SEVERE, null, ex);
35             return 1;
36         }
37
38         double[][] height = getHeightmap(p.infile);
39         double units = 1d * p.pixelsize;
40         double max = p.height;
41
42         PrintWriter pw = null;
43         try {
44             pw = new PrintWriter(new FileOutputStream(new File(p.outfile)));
45         } catch (FileNotFoundException ex) {
46             Logger.getLogger(MapWriter.class.getName()).log(Level.SEVERE, null, ex);
47             return 1;
48         }
49         
50
51         // worldspawn start
52         pw.print("{\n\"classname\" \"worldspawn\"\n");
53
54         // wander through grid
55         for (int x = 0; x < height.length - 1; ++x) {
56             for (int y = 0; y < height[0].length - 1; ++y) {
57
58                 boolean skip = height[x][y] < 0 || height[x][y + 1] < 0 || height[x + 1][y] < 0 || height[x + 1][y + 1] < 0;
59
60                 if (!skip) {
61
62                     /*
63                      * 
64                      *      a +-------+ b
65                      *       /       /|
66                      *      /       / |
67                      *     /       /  |
68                      *  c +-------+ d + f   (e occluded, unused)
69                      *    |       |  /
70                      *    |       | /
71                      *    |       |/
72                      *  g +-------+ h
73                      * 
74                      */
75
76                     Vector3D a = new Vector3D(x * units, -y * units, height[x][y] * max);
77                     Vector3D b = new Vector3D((x + 1) * units, -y * units, height[x + 1][y] * max);
78                     Vector3D c = new Vector3D(x * units, -(y + 1) * units, height[x][y + 1] * max);
79                     Vector3D d = new Vector3D((x + 1) * units, -(y + 1) * units, height[x + 1][y + 1] * max);
80                     //Vector3D e = new Vector3D(x * units, -y * units, -16.0);
81                     Vector3D f = new Vector3D((x + 1) * units, -y * units, -16.0);
82                     Vector3D g = new Vector3D(x * units, -(y + 1) * units, -16.0);
83                     Vector3D h = new Vector3D((x + 1) * units, -(y + 1) * units, -16.0);
84
85                     pw.print("{\n");
86                     pw.print(getMapPlaneString(a, b, d, p.detail, p.texture, p.texturescale));
87                     pw.print(getMapPlaneString(d, b, f, p.detail, "common/caulk", p.texturescale));
88                     pw.print(getMapPlaneString(f, b, a, p.detail, "common/caulk", p.texturescale));
89                     pw.print(getMapPlaneString(a, d, h, p.detail, "common/caulk", p.texturescale));
90                     pw.print(getMapPlaneString(g, h, f, p.detail, "common/caulk", p.texturescale));
91                     pw.print("}\n");
92
93
94                     pw.print("{\n");
95                     pw.print(getMapPlaneString(d, c, a, p.detail, p.texture, p.texturescale));
96                     pw.print(getMapPlaneString(g, c, d, p.detail, "common/caulk", p.texturescale));
97                     pw.print(getMapPlaneString(c, g, a, p.detail, "common/caulk", p.texturescale));
98                     pw.print(getMapPlaneString(h, d, a, p.detail, "common/caulk", p.texturescale));
99                     pw.print(getMapPlaneString(g, h, f, p.detail, "common/caulk", p.texturescale));
100                     pw.print("}\n");
101                 } else if (p.skyfill) {
102
103                     boolean totalskip = height[x][y] < -5 || height[x][y + 1] < -5 || height[x + 1][y] < -5 || height[x + 1][y + 1] < -5;
104
105                     if (!totalskip) {
106                         // fill skipped blocks with sky
107                         Vector3D p1 = new Vector3D(x * units, -(y + 1) * units, -32.0);
108                         Vector3D p2 = new Vector3D((x + 1) * units, -y * units, p.skyheight);
109
110                         writeBoxBrush(pw, p1, p2, false, p.skytexture, 1.0);
111                     }
112                 }
113             }
114         }
115
116         if (p.sky) {
117             // generate skybox
118             int x = height.length - 1;
119             int y = height[0].length - 1;
120
121             // top
122             Vector3D p1 = new Vector3D(0, -y * units, p.skyheight);
123             Vector3D p2 = new Vector3D(x * units, 0, p.skyheight + 32.0);
124             writeBoxBrush(pw, p1, p2, false, p.skytexture, 1.0);
125
126             // bottom
127             p1 = new Vector3D(0, -y * units, -64.0);
128             p2 = new Vector3D(x * units, 0, -32.0);
129             writeBoxBrush(pw, p1, p2, false, p.skytexture, 1.0);
130
131             // north
132             p1 = new Vector3D(0, 0, -32.0);
133             p2 = new Vector3D(x * units, 32, p.skyheight);
134             writeBoxBrush(pw, p1, p2, false, p.skytexture, 1.0);
135
136             // east
137             p1 = new Vector3D(x * units, -y * units, -32.0);
138             p2 = new Vector3D(x * units + 32.0, 0, p.skyheight);
139             writeBoxBrush(pw, p1, p2, false, p.skytexture, 1.0);
140
141             // south
142             p1 = new Vector3D(0, -y * units - 32, -32.0);
143             p2 = new Vector3D(x * units, -y * units, p.skyheight);
144             writeBoxBrush(pw, p1, p2, false, p.skytexture, 1.0);
145
146
147             // west
148             p1 = new Vector3D(0 - 32.0, -y * units, -32.0);
149             p2 = new Vector3D(0, 0, p.skyheight);
150             writeBoxBrush(pw, p1, p2, false, p.skytexture, 1.0);
151
152         }
153
154         // worldspawn end
155         pw.print("}\n");
156         pw.close();
157         return 0;
158     }
159
160     private void writeBoxBrush(PrintWriter pw, Vector3D p1, Vector3D p2, boolean detail, String texture, double scale) {
161         Vector3D a = new Vector3D(p1.x, p2.y, p2.z);
162         Vector3D b = p2;
163         Vector3D c = new Vector3D(p1.x, p1.y, p2.z);
164         Vector3D d = new Vector3D(p2.x, p1.y, p2.z);
165         //Vector3D e unused
166         Vector3D f = new Vector3D(p2.x, p2.y, p1.z);
167         Vector3D g = p1;
168         Vector3D h = new Vector3D(p2.x, p1.y, p1.z);
169
170         pw.print("{\n");
171         pw.print(getMapPlaneString(a, b, d, detail, texture, scale));
172         pw.print(getMapPlaneString(d, b, f, detail, texture, scale));
173         pw.print(getMapPlaneString(c, d, h, detail, texture, scale));
174         pw.print(getMapPlaneString(a, c, g, detail, texture, scale));
175         pw.print(getMapPlaneString(f, b, a, detail, texture, scale));
176         pw.print(getMapPlaneString(g, h, f, detail, texture, scale));
177         pw.print("}\n");
178
179     }
180
181     private String getMapPlaneString(Vector3D p1, Vector3D p2, Vector3D p3, boolean detail, String material, double scale) {
182         int flag;
183         if (detail) {
184             flag = 134217728;
185         } else {
186             flag = 0;
187         }
188         return "( " + p1.x + " " + p1.y + " " + p1.z + " ) ( " + p2.x + " " + p2.y + " " + p2.z + " ) ( " + p3.x + " " + p3.y + " " + p3.z + " ) " + material + " 0 0 0 " + scale + " " + scale + " " + flag + " 0 0\n";
189     }
190
191     private class Vector3D {
192
193         public double x,  y,  z;
194
195         public Vector3D() {
196             this(0.0, 0.0, 0.0);
197         }
198
199         public Vector3D(double x, double y, double z) {
200             this.x = x;
201             this.y = y;
202             this.z = z;
203         }
204
205         public Vector3D crossproduct(Vector3D p1) {
206             Vector3D result = new Vector3D();
207
208             result.x = this.y * p1.z - this.z * p1.y;
209             result.y = this.z * p1.x - this.x * p1.z;
210             result.z = this.x * p1.y - this.y * p1.x;
211
212             return result;
213         }
214
215         public double dotproduct(Vector3D p1) {
216             return this.x * p1.x + this.y * p1.y + this.z * p1.z;
217         }
218
219         public Vector3D substract(Vector3D p1) {
220             Vector3D result = new Vector3D();
221
222             result.x = this.x - p1.x;
223             result.y = this.y - p1.y;
224             result.z = this.z - p1.z;
225
226             return result;
227         }
228
229         public void scale(double factor) {
230             x *= factor;
231             y *= factor;
232             z *= factor;
233         }
234
235         public double length() {
236             return Math.sqrt((x * x) + (y * y) + (z * z));
237         }
238
239         public void normalize() {
240             double l = length();
241
242             x /= l;
243             y /= l;
244             z /= l;
245         }
246     }
247
248     private double[][] markTotalSkip(double[][] input) {
249         double[][] result = new double[input.length][input[0].length];
250
251         int xmax = input.length - 1;
252         int ymax = input[0].length - 1;
253
254         for (int x = 0; x <= xmax; ++x) {
255             for (int y = 0; y <= ymax; ++y) {
256                 double val;
257                 double max;
258
259                 val = input[x][y];
260                 max = val;
261
262                 if (x - 1 >= 0 && y - 1 >= 0) {
263                     val = input[x - 1][y - 1];
264                     max = val > max ? val : max;
265                 }
266
267                 if (y - 1 >= 0) {
268                     val = input[x][y - 1];
269                     max = val > max ? val : max;
270                 }
271
272                 if (x + 1 <= xmax && y - 1 >= 0) {
273                     val = input[x + 1][y - 1];
274                     max = val > max ? val : max;
275                 }
276
277                 if (x - 1 >= 0) {
278                     val = input[x - 1][y];
279                     max = val > max ? val : max;
280                 }
281
282                 if (x + 1 <= xmax) {
283                     val = input[x + 1][y];
284                     max = val > max ? val : max;
285                 }
286
287                 if (x - 1 >= 0 && y + 1 <= ymax) {
288                     val = input[x - 1][y + 1];
289                     max = val > max ? val : max;
290                 }
291
292                 if (y + 1 <= ymax) {
293                     val = input[x][y + 1];
294                     max = val > max ? val : max;
295                 }
296
297                 if (x + 1 <= xmax && y + 1 <= ymax) {
298                     val = input[x + 1][y + 1];
299                     max = val > max ? val : max;
300                 }
301
302                 if (max < 0) {
303                     result[x][y] = -10.0;
304                 } else {
305                     result[x][y] = input[x][y];
306                 }
307
308             }
309         }
310
311
312         return result;
313     }
314
315     private double[][] getHeightmap(String file) {
316         try {
317             BufferedImage bimg = ImageIO.read(new File(file));
318             Raster raster = bimg.getRaster();
319             int x = raster.getWidth();
320             int y = raster.getHeight();
321
322             double[][] result = new double[x][y];
323
324             for (int xi = 0; xi < x; ++xi) {
325                 for (int yi = 0; yi < y; ++yi) {
326                     float[] pixel = raster.getPixel(xi, yi, (float[]) null);
327
328                     int channels;
329                     boolean alpha;
330                     if (pixel.length == 3) {
331                         // RGB
332                         channels = 3;
333                         alpha = false;
334                     } else if (pixel.length == 4) {
335                         // RGBA
336                         channels = 3;
337                         alpha = true;
338                     } else if (pixel.length == 1) {
339                         // grayscale
340                         channels = 1;
341                         alpha = false;
342                     } else {
343                         // grayscale with alpha
344                         channels = 1;
345                         alpha = true;
346                     }
347
348                     float tmp = 0f;
349                     for (int i = 0; i < channels; ++i) {
350                         tmp += pixel[i];
351                     }
352                     result[xi][yi] = tmp / (channels * 255f);
353
354                     if (alpha) {
355                         // mark this pixel to be skipped
356                         if (pixel[pixel.length - 1] < 64.0) {
357                             result[xi][yi] = -1.0;
358                         }
359                     }
360                 }
361             }
362
363
364             return markTotalSkip(result);
365         } catch (IOException ex) {
366             Logger.getLogger(MapWriter.class.getName()).log(Level.SEVERE, null, ex);
367         }
368
369         return null;
370     }
371 }