Starsector API
Loading...
Searching...
No Matches
BaseTiledTerrain.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.terrain;
2
3import java.util.Arrays;
4import java.util.Random;
5import java.util.zip.DataFormatException;
6import java.util.zip.Deflater;
7import java.util.zip.Inflater;
8
9import java.awt.Color;
10
11import javax.xml.bind.DatatypeConverter;
12
13import org.lwjgl.opengl.GL11;
14import org.lwjgl.util.vector.Vector2f;
15
16import com.fs.starfarer.api.Global;
17import com.fs.starfarer.api.campaign.CampaignEngineLayers;
18import com.fs.starfarer.api.campaign.CampaignFleetAPI;
19import com.fs.starfarer.api.campaign.SectorEntityToken;
20import com.fs.starfarer.api.combat.ViewportAPI;
21import com.fs.starfarer.api.graphics.SpriteAPI;
22import com.fs.starfarer.api.util.Misc;
23
24public abstract class BaseTiledTerrain extends BaseTerrain {
25
26 public static class TileParams {
27 public String tiles;
28 public int w;
29 public int h;
30 public String cat;
31 public String key;
32 public int tW;
33 public int tH;
34 public String name;
35 public TileParams(String tiles, int width, int height,
36 String tileTexCat, String tileTexKey, int tilesWide, int tilesHigh, String name) {
37 this.tiles = tiles;
38 this.w = width;
39 this.h = height;
40 this.cat = tileTexCat;
41 this.key = tileTexKey;
42 this.tW = tilesWide;
43 this.tH = tilesHigh;
44 this.name = name;
45 }
46
47 }
48
49// public static class Tile {
50// public int cellX;
51// public int cellY;
52// public int texCellX;
53// public int texCellY;
54// }
55
56 protected TileParams params;
57 protected transient SpriteAPI texture;
58 protected transient SpriteAPI mapTexture;
59 //protected Tile[][] tiles;
60 protected transient int [][] tiles;
61
62 protected long tileSeed;
63 protected String savedTiles;
64 public void init(String terrainId, SectorEntityToken entity, Object param) {
65 super.init(terrainId, entity, param);
66
67 this.params = (TileParams) param;
68 name = params.name;
69 if (name == null) name = "Unknown";
70
71 tiles = new int [params.w][params.h];
72
73
74 tileSeed = new Random().nextLong();
75// Random random = new Random(tileSeed);
76
77 for (int i = 0; i < tiles.length; i++) {
78 for (int j = 0; j < tiles[0].length; j++) {
79 int index = i + (tiles[0].length - j - 1) * tiles.length;
80 char c = params.tiles.charAt(index);
81 if (!Character.isWhitespace(c)) {
82// int texX = (int) (Math.random() * params.tW);
83// int texY = (int) (Math.random() * params.tH);
84// int texX = (int) (random.nextFloat() * params.tW);
85// int texY = (int) (random.nextFloat() * params.tH);
86// tiles[i][j] = texX + texY * params.tW;
87 tiles[i][j] = 1;
88 } else {
89 tiles[i][j] = -1;
90 }
91 }
92 }
93
95 readResolve();
96
97 params.tiles = null; // don't need to save this
98 }
99
100 protected void regenTiles() {
101 Random random = new Random(tileSeed);
102 for (int i = 0; i < tiles.length; i++) {
103 for (int j = 0; j < tiles[0].length; j++) {
104 if (tiles[i][j] >= 0) {
105 int texX = (int) (random.nextFloat() * params.tW);
106 int texY = (int) (random.nextFloat() * params.tH);
107 tiles[i][j] = texX + texY * params.tW;
108 } else {
109 tiles[i][j] = -1;
110 }
111 }
112 }
113 sampleCache = null;
114 }
115
116
117 public int[][] getTiles() {
118 return tiles;
119 }
120
121 public TileParams getParams() {
122 return params;
123 }
124
125
126 Object readResolve() {
128 mapTexture = Global.getSettings().getSprite(params.cat, params.key + "_map");
129
130 if (savedTiles != null) {
131 try {
133 } catch (DataFormatException e) {
134 throw new RuntimeException("Error decoding tiled terrain tiles", e);
135 }
136 } else {
137 // shouldn't be here, if we are then savedTiles == null and something went badly wrong
138 tiles = new int [params.w][params.h];
139 }
140 regenTiles();
141
142 return this;
143 }
144
145 Object writeReplace() {
146 params.tiles = null;
148 return this;
149 }
150
151 @Override
152 public boolean containsEntity(SectorEntityToken other) {
153 if (other.getContainingLocation() != this.entity.getContainingLocation()) return false;
154 return containsPoint(other.getLocation(), other.getRadius()) && !isPreventedFromAffecting(other);
155 }
156
157 public boolean containsPoint(Vector2f test, float r) {
158
159 float dist = Misc.getDistance(this.entity.getLocation(), test) - r;
160 if (dist > getRenderRange()) return false;
161
162 float x = this.entity.getLocation().x;
163 float y = this.entity.getLocation().y;
164 float size = getTileSize();
165 float containsSize = getTileContainsSize();
166
167 float w = tiles.length * size;
168 float h = tiles[0].length * size;
169
170 x -= w/2f;
171 y -= h/2f;
172
173 float extra = (containsSize - size) / 2f;
174
175 if (test.x + r + extra < x) return false;
176 if (test.y + r + extra < y) return false;
177 if (test.x > x + w + r + extra) return false;
178 if (test.y > y + h + r + extra) return false;
179
180 int xIndex = (int) ((test.x - x) / size);
181 int yIndex = (int) ((test.y - y) / size);
182
183 if (xIndex < 0) xIndex = 0;
184 if (yIndex < 0) yIndex = 0;
185
186 if (xIndex >= tiles.length) xIndex = tiles.length - 1;
187 if (yIndex >= tiles[0].length) yIndex = tiles[0].length - 1;
188
189// if (entity.isPlayerFleet()) {
190// System.out.println(this + " " + xIndex + "," + yIndex);
191// }
192
193 for (float i = Math.max(0, xIndex - 1); i <= xIndex + 1 && i < tiles.length; i++) {
194 for (float j = Math.max(0, yIndex - 1); j <= yIndex + 1 && j < tiles[0].length; j++) {
195 int texIndex = tiles[(int) i][(int) j];
196 if (texIndex >= 0) {
197 float tx = x + i * size + size/2f - containsSize/2f;
198 float ty = y + j * size + size/2f - containsSize/2f;
199
200 if (test.x + r < tx) continue;
201 if (test.y + r < ty) continue;
202 if (test.x > tx + containsSize + r) continue;
203 if (test.y > ty + containsSize + r) continue;
204 return true;
205 }
206 }
207 }
208 return false;
209 }
210
211
212 public abstract float getTileSize();
213 public abstract float getTileRenderSize();
214 public abstract float getTileContainsSize();
215 public abstract void preRender(CampaignEngineLayers layer, float alphaMult);
216 public abstract void preMapRender(float alphaMult);
217 public abstract Color getRenderColor();
218
219 public float getRenderRange() {
220 float size = getTileSize();
221 float renderSize = getTileRenderSize();
222 float w = tiles.length * size * 0.5f + (renderSize - size) * 0.5f;
223 float h = tiles[0].length * size * 0.5f + (renderSize - size) * 0.5f;
224 return Math.max(w, h) * 1.5f;
225 }
226
229 GL11.glEnable(GL11.GL_TEXTURE_2D);
230 //GL11.glDisable(GL11.GL_TEXTURE_2D);
231
232 preRender(layer, v.getAlphaMult());
233 //GL11.glDisable(GL11.GL_TEXTURE_2D);
234
235 float x = this.entity.getLocation().x;
236 float y = this.entity.getLocation().y;
237 float size = getTileSize();
238 float renderSize = getTileRenderSize();
239
240 float w = tiles.length * size;
241 float h = tiles[0].length * size;
242 x -= w/2f;
243 y -= h/2f;
244 float extra = (renderSize - size) / 2f + 100f;
245
246 float llx = v.getLLX();
247 float lly = v.getLLY();
248 float vw = v.getVisibleWidth();
249 float vh = v.getVisibleHeight();
250
251 if (llx > x + w + extra) return;
252 if (lly > y + h + extra) return;
253 if (llx + vw + extra < x) return;
254 if (lly + vh + extra < y) return;
255
256 float xStart = (int)((llx - x - extra) / size);
257 if (xStart < 0) xStart = 0;
258 float yStart = (int)((lly - y - extra) / size);
259 if (yStart < 0) yStart = 0;
260
261 float xEnd = (int)((llx + vw - x + extra) / size) + 1;
262 if (xEnd >= tiles.length) xEnd = tiles.length - 1;
263 float yEnd = (int)((lly + vw - y + extra) / size) + 1;
264 if (yEnd >= tiles.length) yEnd = tiles[0].length - 1;
265
266 renderSubArea(xStart, xEnd, yStart, yEnd, 1f, 1, v.getAlphaMult());
267
268 //renderSubArea(0, tiles.length, 0, tiles[0].length, 1f);
269 }
270
271 public boolean isTileVisible(int i, int j) {
272 float x = this.entity.getLocation().x;
273 float y = this.entity.getLocation().y;
274 float size = getTileSize();
275 float renderSize = getTileRenderSize();
276
277 float w = tiles.length * size;
278 float h = tiles[0].length * size;
279 x -= w/2f;
280 y -= h/2f;
281 float extra = (renderSize - size) / 2f + 100f;
282
284 float llx = v.getLLX();
285 float lly = v.getLLY();
286 float vw = v.getVisibleWidth();
287 float vh = v.getVisibleHeight();
288
289 if (llx > x + w + extra) return false;
290 if (lly > y + h + extra) return false;
291 if (llx + vw + extra < x) return false;
292 if (lly + vh + extra < y) return false;
293
294 float xStart = (int)((llx - x - extra) / size);
295 if (xStart < 0) xStart = 0;
296 float yStart = (int)((lly - y - extra) / size);
297 if (yStart < 0) yStart = 0;
298
299 float xEnd = (int)((llx + vw - x + extra) / size) + 1;
300 if (xEnd >= tiles.length) xEnd = tiles.length - 1;
301 float yEnd = (int)((lly + vw - y + extra) / size) + 1;
302 if (yEnd >= tiles.length) yEnd = tiles[0].length - 1;
303
304 if (i < xStart) return false;
305 if (i > xEnd) return false;
306 if (j < yStart) return false;
307 if (j > yEnd) return false;
308
309 return true;
310 }
311
312 public void renderOnMap(float factor, float alphaMult) {
314 GL11.glEnable(GL11.GL_TEXTURE_2D);
315 preMapRender(alphaMult);
316 renderSubArea(0, tiles.length, 0, tiles[0].length, factor, getNumMapSamples(), alphaMult);
317 }
318
319 public int getNumMapSamples() {
320 return 5;
321 }
322
323 public void renderOnMapAbove(float factor, float alphaMult) {
324
325 }
326
327 public float[] getTileCenter(int i, int j) {
328 float x = entity.getLocation().x;
329 float y = entity.getLocation().y;
330 float size = getTileSize();
331
332 float w = tiles.length * size;
333 float h = tiles[0].length * size;
334
335 float [] result = new float[2];
336 result[0] = x - w / 2f + (float)i * size + size / 2f;
337 result[1] = y - h / 2f + (float)j * size + size / 2f;
338 return result;
339 }
340
341 public static class TileSample {
342 public int texIndex = -1;
343 public float angle = 0;
344 public float xOff = 0;
345 public float yOff = 0;
346 public float weight = 0;
347 }
348
349 protected transient TileSample [][] sampleCache = null;
350 protected transient int samplesForCache = 0;
351
352 public boolean isUseSampleCache() {
353 return false;
354 }
355
356 public void forceClearSampleCache() {
357 sampleCache = null;
358 }
359 public void updateSampleCache(int samples, boolean force) {
360 if (tiles == null) return;
361 if (sampleCache != null && samplesForCache == samples && !force) {
362 return;
363 }
364 samplesForCache = samples;
365
366 //(0, tiles.length, 0, tiles[0].length
367
368 int cacheW = tiles.length / samples + 1;
369 int cacheH = tiles[0].length / samples + 1;
370 sampleCache = new TileSample[cacheW][cacheH];
371
372 float renderSize = getTileRenderSize();
373 renderSize *= samples;
374
375 for (float i = 0; i <= tiles.length; i+=samples) {
376 if (i < 0 || i >= tiles.length) continue;
377 for (float j = 0; j <= tiles[0].length; j+=samples) {
378 if (j < 0 || j >= tiles[0].length) continue;
379 int texIndex = -1;
380 float angle = 0;
381 float xOff = 0;
382 float yOff = 0;
383 float weight = 0;
384 for (int m = 0; m < samples && i + m <= tiles.length; m++) {
385 if (i + m < 0 || i + m >= tiles.length) continue;
386 for (int n = 0; n < samples && j + n < tiles[0].length; n++) {
387 if (j + n < 0 || j + n >= tiles[0].length) continue;
388 int currIndex = tiles[(int) i + m][(int) j + n];
389 if (currIndex >= 0 && texIndex < 0) {
390 texIndex = currIndex;
391 Random rand = new Random((long) (i + j * tiles.length) * 1000000);
392 angle = rand.nextFloat() * 360f;
393 float offRange = renderSize * 0.25f;
394 xOff = -offRange / 2f + offRange * rand.nextFloat();
395 yOff = -offRange / 2f + offRange * rand.nextFloat();
396// if (Keyboard.isKeyDown(Keyboard.KEY_O)) {
397// xOff = yOff = 0f;
398// }
399 }
400 if (currIndex >= 0) {
401 weight++;
402 }
403 }
404 }
405 TileSample sample = new TileSample();
406 sample.texIndex = texIndex;
407 sample.angle = angle;
408 sample.xOff = xOff;
409 sample.yOff = yOff;
410 sample.weight = weight;
411
412 sampleCache[(int)i/samples][(int)j/samples] = sample;
413 }
414 }
415 }
416
417
418
419 protected void renderSubArea(float startColumn, float endColumn, float startRow, float endRow, float factor, int samples, float alphaMult) {
420 float x = entity.getLocation().x;
421 float y = entity.getLocation().y;
422 float size = getTileSize();
423 float renderSize = getTileRenderSize();
424
425 float w = tiles.length * size;
426 float h = tiles[0].length * size;
427 //if (true) return;
428
429 //Random rand = new Random(tiles.length + tiles[0].length);
430 //Random rand = new Random();
431
432 if (samples == 1) {
433 GL11.glBegin(GL11.GL_QUADS);
434 for (float i = startColumn; i <= endColumn; i++) {
435 if (i < 0 || i >= tiles.length) continue;
436 for (float j = startRow; j <= endRow; j++) {
437 if (j < 0 || j >= tiles[0].length) continue;
438 int texIndex = tiles[(int) i][(int) j];
439 if (texIndex >= 0) {
440 int texCellX = texIndex % params.tW;
441 int texCellY = texIndex / params.tW;
442
443 Random rand = new Random((long) (i + j * tiles.length) * 1000000);
444 float angle = rand.nextFloat() * 360f;
445 float offRange = renderSize * 0.25f;
446 float xOff = -offRange / 2f + offRange * rand.nextFloat();
447 float yOff = -offRange / 2f + offRange * rand.nextFloat();
448// if (Keyboard.isKeyDown(Keyboard.KEY_O)) {
449// xOff = yOff = 0f;
450// }
451 // angle += angleOffset;
452 // angle = Misc.normalizeAngle(angle);
453 renderQuad((int)i, (int)j,
454 (x + xOff - w / 2f + i * size + size/2f - renderSize/2f) * factor,
455 (y + yOff - h / 2f + j * size + size/2f - renderSize/2f) * factor,
456 renderSize * factor, renderSize * factor,
457 texCellX * 0.25f, texCellY * 0.25f,
458 0.25f, 0.25f,
459 angle);
460 }
461 }
462 }
463 GL11.glEnd();
464 } else {
465 //renderSize = (size * samples) + (renderSize - size);
466 renderSize *= samples;
467 size *= samples;
468 alphaMult *= 0.67f;
469 //alphaMult = 1f;
470 GL11.glBegin(GL11.GL_QUADS);
471 float max = samples * samples;
472 for (float i = startColumn; i <= endColumn; i+=samples) {
473 if (i < 0 || i >= tiles.length) continue;
474 for (float j = startRow; j <= endRow; j+=samples) {
475 int texIndex = -1;
476 float angle = 0;
477 float xOff = 0;
478 float yOff = 0;
479 float weight = 0;
480
481 boolean usingSample = false;
482 if (isUseSampleCache()) {
483 updateSampleCache(samples, false);
484 if (sampleCache != null) {
485 TileSample sample = null;
486 int sampleI = (int)i/samples;
487 int sampleJ = (int)j/samples;
488 if (sampleI >= 0 && sampleI < sampleCache.length &&
489 sampleJ >= 0 && sampleJ < sampleCache[0].length) {
490 sample = sampleCache[sampleI][sampleJ];
491 if (sample != null) {
492 texIndex = sample.texIndex;
493 angle = sample.angle;
494 xOff = sample.xOff;
495 yOff = sample.yOff;
496 weight = sample.weight;
497 usingSample = true;
498 }
499 }
500 }
501 }
502
503 if (!usingSample) {
504 for (int m = 0; m < samples && i + m <= endColumn; m++) {
505 if (i + m < 0 || i + m >= tiles.length) continue;
506 for (int n = 0; n < samples && j + n < endRow; n++) {
507 if (j + n < 0 || j + n >= tiles[0].length) continue;
508 int currIndex = tiles[(int) i + m][(int) j + n];
509 if (currIndex >= 0 && texIndex < 0) {
510 texIndex = currIndex;
511 Random rand = new Random((long) (i + j * tiles.length) * 1000000);
512 angle = rand.nextFloat() * 360f;
513 float offRange = renderSize * 0.25f;
514 xOff = -offRange / 2f + offRange * rand.nextFloat();
515 yOff = -offRange / 2f + offRange * rand.nextFloat();
516 // if (Keyboard.isKeyDown(Keyboard.KEY_O)) {
517 // xOff = yOff = 0f;
518 // }
519 }
520 if (currIndex >= 0) {
521 weight++;
522 }
523 }
524 }
525 }
526
527 if (texIndex >= 0) {
528 int texCellX = texIndex % params.tW;
529 int texCellY = texIndex / params.tW;
530
531 Color color = getRenderColor();
532 float b = alphaMult * weight / max;
533// if (tiles.length > 30) {
534// b *= weight / max;
535// b *= weight / max;
536// }
537 //b = alphaMult;
538 GL11.glColor4ub((byte)color.getRed(),
539 (byte)color.getGreen(),
540 (byte)color.getBlue(),
541 (byte)((float)color.getAlpha() * b));
542 //xOff = yOff = 0f;
543 renderQuad((int)i, (int)j, (x + xOff - w / 2f + i/samples * size + size/2f - renderSize/2f) * factor,
544 (y + yOff - h / 2f + j/samples * size + size/2f - renderSize/2f) * factor,
545 renderSize * factor, renderSize * factor,
546 texCellX * 0.25f, texCellY * 0.25f,
547 0.25f, 0.25f,
548 angle);
549 }
550 }
551 }
552
553 GL11.glEnd();
554 }
555 }
556
557
558 protected float elapsed = 0f;
559 @Override
560 public void advance(float amount) {
561 super.advance(amount);
562// angleOffset += days * 20f;
563 float days = Global.getSector().getClock().convertToDays(amount);
564 elapsed += days;
565 }
566
567 protected void renderQuad(int i, int j, float x, float y, float width, float height, float texX, float texY, float texW, float texH, float angle) {
568 if (angle != 0) {
569 float vw = width / 2f;
570 float vh = height / 2f;
571 float cx = x + vw;
572 float cy = y + vh;
573
574 float cos = (float) Math.cos(angle * Misc.RAD_PER_DEG);
575 float sin = (float) Math.sin(angle * Misc.RAD_PER_DEG);
576
577 GL11.glTexCoord2f(texX, texY);
578 GL11.glVertex2f(cx + (-vw * cos + vh * sin), cy + (-vw * sin - vh * cos));
579
580 GL11.glTexCoord2f(texX, texY + texH);
581 GL11.glVertex2f(cx + (-vw * cos - vh * sin), cy + (-vw * sin + vh * cos));
582
583 GL11.glTexCoord2f(texX + texW, texY + texH);
584 GL11.glVertex2f(cx + (vw * cos - vh * sin), cy + (vw * sin + vh * cos));
585
586 GL11.glTexCoord2f(texX + texW, texY);
587 GL11.glVertex2f(cx + (vw * cos + vh * sin), cy + (vw * sin - vh * cos));
588
589 } else {
590 GL11.glTexCoord2f(texX, texY);
591 GL11.glVertex2f(x, y);
592
593 GL11.glTexCoord2f(texX, texY + texH);
594 GL11.glVertex2f(x, y + height);
595
596 GL11.glTexCoord2f(texX + texW, texY + texH);
597 GL11.glVertex2f(x + width, y + height);
598
599 GL11.glTexCoord2f(texX + texW, texY);
600 GL11.glVertex2f(x + width, y);
601 }
602 }
603
604 public float getMaxEffectRadius(Vector2f locFrom) {
605 // TODO: do intersection check from locFrom to an actual filled tile?
606
607 float size = getTileSize();
608 float renderSize = getTileRenderSize();
609 float w = tiles.length * size * 0.5f + (renderSize - size) * 0.5f;
610 float h = tiles[0].length * size * 0.5f + (renderSize - size) * 0.5f;
611 return Math.max(w, h) * 1.5f;
612 }
613 public float getMinEffectRadius(Vector2f locFrom) {
614 return 0f;
615 }
616
617 public float getOptimalEffectRadius(Vector2f locFrom) {
618 return getMaxEffectRadius(locFrom);
619 }
620
621
622
623 @Override
624 protected float getExtraSoundRadius() {
625 return 200f;
626 }
627
628
629 public float getProximitySoundFactor() {
631 float r = player.getRadius() + getExtraSoundRadius();
632 Vector2f test = player.getLocation();
633
634 float x = this.entity.getLocation().x;
635 float y = this.entity.getLocation().y;
636 float size = getTileSize();
637 float containsSize = getTileContainsSize();
638
639 float w = tiles.length * size;
640 float h = tiles[0].length * size;
641
642 x -= w/2f;
643 y -= h/2f;
644
645 float extra = (containsSize - size) / 2f;
646
647 if (test.x + r + extra < x) return 0f;
648 if (test.y + r + extra < y) return 0f;
649 if (test.x > x + w + r + extra) return 0f;
650 if (test.y > y + h + r + extra) return 0f;
651
652 int xIndex = (int) ((test.x - x) / size);
653 int yIndex = (int) ((test.y - y) / size);
654
655 if (xIndex < 0) xIndex = 0;
656 if (yIndex < 0) yIndex = 0;
657
658 if (xIndex >= tiles.length) xIndex = tiles.length - 1;
659 if (yIndex >= tiles[0].length) yIndex = tiles[0].length - 1;
660
661
662 float closestDist = Float.MAX_VALUE;
663
664 for (float i = Math.max(0, xIndex - 2); i <= xIndex + 2 && i < tiles.length; i++) {
665 for (float j = Math.max(0, yIndex - 2); j <= yIndex + 2 && j < tiles[0].length; j++) {
666 int texIndex = tiles[(int) i][(int) j];
667 if (texIndex >= 0) {
668 float tx = x + i * size + size/2f - containsSize/2f;
669 float ty = y + j * size + size/2f - containsSize/2f;
670
671 if (test.x + r < tx) continue;
672 if (test.y + r < ty) continue;
673 if (test.x > tx + containsSize + r) continue;
674 if (test.y > ty + containsSize + r) continue;
675
676 //float dist = Misc.getDistance(test, new Vector2f(tx + containsSize/2f, ty + containsSize/2f));
677 float dx = Math.abs(test.x - tx - containsSize / 2f);
678 float dy = Math.abs(test.y - ty - containsSize / 2f);
679 float dist = Math.max(dx, dy);
680 if (dist < closestDist) {
681 closestDist = dist;
682 }
683 }
684 }
685 }
686
687 //System.out.println("Closest: " + closestDist);
688 //float max = containsSize * 0.5f * 1.41f + EXTRA_SOUND_RADIUS;
689 float max = containsSize * 0.5f + getExtraSoundRadius();
690 if (closestDist < containsSize * 0.5f) return 1f;
691
692 float p = (max - closestDist) / (max - containsSize * 0.5f);
693 if (p < 0) p = 0;
694 if (p > 1) p = 1;
695
696 return p;
697 }
698
699
700
701 public static String encodeTiles(int [][] tiles) {
702 int w = tiles.length;
703 int h = tiles[0].length;
704 int total = w * h;
705
706// int [] masks = new int [] {
707// 1,
708// 2,
709// 4,
710// 8,
711// 16,
712// 32,
713// 64,
714// 128,
715// };
716 int [] masks = new int [] {
717 128,
718 64,
719 32,
720 16,
721 8,
722 4,
723 2,
724 1,
725 };
726
727 int bit = 0;
728 int curr = 0;
729 //List<Byte> bytes = new ArrayList<Byte>();
730 byte [] input = new byte [(int) Math.ceil(total / 8f)];
731 for (int i = 0; i < total; i++) {
732 int x = i % w;
733 int y = i / w;
734 int val = tiles[x][y];
735 int mask = masks[bit];
736
737 if (val >= 0) {
738 curr = (curr | mask);
739 }
740
741 bit++;
742 bit %= 8;
743
744 if (bit == 0) {
745 input[i/8] = ((byte) curr);
746 curr = 0;
747 }
748 }
749 if (bit != 0) {
750 input[input.length - 1] = ((byte) curr);
751 curr = 0;
752 }
753
754 /*
755 List<Byte> bytes = new ArrayList<Byte>();
756 String seq = "";
757 for (int i = 0; i < total; i++) {
758 int x = i % w;
759 int y = i / w;
760 int val = tiles[x][y];
761 String curr = "0";
762 if (val >= 0) curr = "1";
763 seq += curr;
764 if (seq.length() == 8) {
765 //byte b = Byte.parseByte(seq, 2);
766 int b = Integer.parseInt(seq, 2);
767 bytes.add((byte) b);
768 seq = "";
769 }
770 }
771 if (seq.length() > 0) {
772 while (seq.length() < 8) {
773 seq = seq + "0";
774 }
775 //byte b = Byte.parseByte(seq, 2);
776 //bytes.add(b);
777 int b = Integer.parseInt(seq, 2);
778 bytes.add((byte) b);
779 }
780
781 byte [] input = new byte [bytes.size()];
782 for (int i = 0; i < bytes.size(); i++) {
783 input[i] = bytes.get(i);
784 }
785 */
786
787 Deflater compressor = new Deflater();
788 //compresser.setLevel(Deflater.BEST_COMPRESSION);
789 //compresser.setStrategy(Deflater.HUFFMAN_ONLY);
790 compressor.setInput(input);
791 compressor.finish();
792
793 StringBuilder result = new StringBuilder();
794 byte [] temp = new byte[100];
795
796 while (!compressor.finished()) {
797 int read = compressor.deflate(temp);
798 result.append(toHexString(Arrays.copyOf(temp, read)));
799 }
800
801// result = new StringBuilder();
802// result.append(toHexString(input));
803
804 compressor.end();
805
806 return result.toString();
807 }
808
809 public static int [][] decodeTiles(String string, int w, int h) throws DataFormatException {
810 byte [] input = toByteArray(string);
811
812 Inflater decompressor = new Inflater();
813 decompressor.setInput(input);
814
815 int [][] tiles = new int [w][h];
816 int total = w * h;
817 int curr = 0;
818
819 byte [] temp = new byte[100];
820 OUTER: while (!decompressor.finished()) {
821 int read = decompressor.inflate(temp);
822 for (int i = 0; i < read; i++) {
823 byte b = temp[i];
824
825 for (int j = 7; j >= 0; j--) {
826 int x = curr % w;
827 int y = curr / w;
828 curr++;
829
830 if (curr > total) break OUTER;
831 //System.out.println("bytes read: " + curr);
832 if ((b & (0x01 << j)) > 0) {
833 tiles[x][y] = 1;
834 } else {
835 tiles[x][y] = -1;
836 }
837 }
838 }
839 }
840
841 decompressor.end();
842
843 return tiles;
844 }
845
846
847 public static String toHexString(byte[] array) {
848 return DatatypeConverter.printBase64Binary(array);
849 }
850
851 public static byte[] toByteArray(String s) {
852 return DatatypeConverter.parseBase64Binary(s);
853 }
854
855
856
857 public static void main(String[] args) throws DataFormatException {
858
859// int [][] tiles = new int[][] {
860// {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
861// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
862// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
863// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1},
864// {1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
865// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
866// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
867// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
868// {1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
869// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
870// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
871// {1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
872// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
873// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
874// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
875// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
876// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1},
877// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
878// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
879// {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
880// };
881
882 int [][] tiles = new int[][] {
883 {-1, 1, 1, 1, -1},
884 {1, 1, 1, 1, 1},
885 {1, 1, 1, 1, -1},
886 {1, 1, 1, -1, 1},
887 };
888
889// int w = 128;
890// int h = 128;
891// int [][] tiles = new int [w][h];
892//
893// for (int i = 0; i < w; i++) {
894// for (int j = 0; j < h; j++) {
895// if ((float) Math.random() > 0.8f) {
896// tiles[i][j] = 0;
897// } else {
898// tiles[i][j] = -1;
899// }
900// }
901// }
902
903
904 System.out.println("Original:");
905 for (int i = 0; i < tiles.length; i++) {
906 for (int j = 0; j < tiles[0].length; j++) {
907 System.out.print(String.format("% 2d,", tiles[i][j]));
908 }
909 System.out.println();
910 }
911
912 String result = encodeTiles(tiles);
913 System.out.println(result);
914 //System.out.println(result.length() + ", would be " + (w * h / 4) + " without compression");
915 int [][] tilesBack = decodeTiles(result, tiles.length, tiles[0].length);
916
917 System.out.println("Decoded:");
918 for (int i = 0; i < tilesBack.length; i++) {
919 for (int j = 0; j < tilesBack[0].length; j++) {
920 System.out.print(String.format("% 2d,", tilesBack[i][j]));
921 }
922 System.out.println();
923 }
924
925 boolean equals = true;
926 for (int i = 0; i < tiles.length; i++) {
927 for (int j = 0; j < tiles[0].length; j++) {
928 if (tiles[i][j] != tilesBack[i][j]) {
929 equals = false;
930 }
931 }
932 }
933
934 System.out.println("Equal: " + equals);
935
936// for (int x = 0; x < tilesBack.length; x++) {
937// for (int y = 0; y < tilesBack.length; y++) {
938// System.out.print(tilesBack[x][y] + " ");
939// }
940// System.out.println();
941// }
942 }
943}
944
945
946
947
948
949
950
static SettingsAPI getSettings()
Definition Global.java:57
static SectorAPI getSector()
Definition Global.java:65
boolean isPreventedFromAffecting(SectorEntityToken other)
void renderQuad(int i, int j, float x, float y, float width, float height, float texX, float texY, float texW, float texH, float angle)
void init(String terrainId, SectorEntityToken entity, Object param)
abstract void preRender(CampaignEngineLayers layer, float alphaMult)
void render(CampaignEngineLayers layer, ViewportAPI v)
static int[][] decodeTiles(String string, int w, int h)
void renderSubArea(float startColumn, float endColumn, float startRow, float endRow, float factor, int samples, float alphaMult)
static float getDistance(SectorEntityToken from, SectorEntityToken to)
Definition Misc.java:599
SpriteAPI getSprite(String filename)