Worldwind public release 0.2
[worldwind-tracker.git] / gov / nasa / worldwind / DDSConverter.java
blob71587dd3d991419c12e259d0a098206562902b0e
1 /*
2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
5 All Rights Reserved.
6 */
7 package gov.nasa.worldwind;
9 /**
10 * @author Tom Gaskins
11 * @version $Id: DDSConverter.java 1614 2007-04-23 22:38:20Z garakl $
13 public class DDSConverter
15 static final int DDSD_CAPS = 0x0001;
16 static final int DDSD_HEIGHT = 0x0002;
17 static final int DDSD_WIDTH = 0x0004;
18 static final int DDSD_PIXELFORMAT = 0x1000;
19 static final int DDSD_MIPMAPCOUNT = 0x20000;
20 static final int DDSD_LINEARSIZE = 0x80000;
21 static final int DDPF_FOURCC = 0x0004;
22 static final int DDSCAPS_TEXTURE = 0x1000;
24 protected static class Color
26 private int r, g, b;
28 public Color()
30 this.r = this.g = this.b = 0;
33 public Color(int r, int g, int b)
35 this.r = r;
36 this.g = g;
37 this.b = b;
40 public boolean equals(Object o)
42 if (this == o)
43 return true;
44 if (o == null || getClass() != o.getClass())
45 return false;
47 final gov.nasa.worldwind.DDSConverter.Color color = (gov.nasa.worldwind.DDSConverter.Color) o;
49 if (b != color.b)
50 return false;
51 if (g != color.g)
52 return false;
53 //noinspection RedundantIfStatement
54 if (r != color.r)
55 return false;
57 return true;
60 public int hashCode()
62 int result;
63 result = r;
64 result = 29 * result + g;
65 result = 29 * result + b;
66 return result;
70 /**
71 * @param image
72 * @param mimeType
73 * @return
74 * @throws IllegalArgumentException if either <code>image</code> or <code>mimeType</code> is null or if
75 * <code>mimeType</code> does not yield a valid suffix
76 * @throws java.io.IOException
78 public static java.nio.ByteBuffer convertToDxt1NoTransparency(java.nio.ByteBuffer image, String mimeType)
79 throws java.io.IOException
81 if (image == null)
83 String message = WorldWind.retrieveErrMsg("nullValue.ByteBufferIsNull");
84 WorldWind.logger().log(java.util.logging.Level.FINE, message);
85 throw new IllegalArgumentException(message);
88 if (mimeType == null)
90 String message = WorldWind.retrieveErrMsg("nullValue.MimeTypeIsNull");
91 gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message);
92 throw new IllegalArgumentException(message);
95 String suffix = WWIO.getSuffixForMimeType(mimeType);
96 if (suffix == null)
98 String message = WorldWind.retrieveErrMsg("DDSConverter.UnsupportedMimeType") + mimeType;
99 WorldWind.logger().log(java.util.logging.Level.FINE, message);
100 throw new IllegalArgumentException(message);
103 java.io.File tempFile = WWIO.saveBufferToTempFile(image, suffix);
105 return convertToDxt1NoTransparency(tempFile);
109 * @param file
110 * @return
111 * @throws IllegalArgumentException if either <code>file</code> is null, does not exist, or cannot be read
112 * @throws java.io.IOException
114 public static java.nio.ByteBuffer convertToDxt1NoTransparency(java.io.File file) throws java.io.IOException
116 if (file == null)
117 { //
118 String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull");
119 WorldWind.logger().log(java.util.logging.Level.FINE, message);
120 throw new IllegalArgumentException(message);
123 if (!file.exists() || !file.canRead())
125 String message = WorldWind.retrieveErrMsg("DDSConverter.NoFileOrNoPermission");
126 WorldWind.logger().log(java.util.logging.Level.FINE, message);
127 throw new IllegalArgumentException(message);
130 java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(file);
132 if (image == null)
134 return null;
137 // // Change its orientation to that of OpenGL.
138 // java.awt.geom.AffineTransform xform = java.awt.geom.AffineTransform.getScaleInstance(1, -1);
139 // xform.translate(0, -image.getHeight(null));
140 // java.awt.image.AffineTransformOp op = new java.awt.image.AffineTransformOp(
141 // xform, java.awt.image.AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
142 // image = op.filter(image, null);
144 int[] pixels = new int[16];
145 int bufferSize = 128 + image.getWidth() * image.getHeight() / 2;
146 java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(bufferSize);
147 buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
148 buildHeaderDxt1(buffer, image.getWidth(), image.getHeight());
150 int numTilesWide = image.getWidth() / 4;
151 int numTilesHigh = image.getHeight() / 4;
152 for (int i = 0; i < numTilesHigh; i++)
154 for (int j = 0; j < numTilesWide; j++)
156 java.awt.image.BufferedImage originalTile = image.getSubimage(j * 4, i * 4, 4, 4);
157 originalTile.getRGB(0, 0, 4, 4, pixels, 0, 4);
158 Color[] colors = getColors888(pixels);
160 for (int k = 0; k < pixels.length; k++)
162 pixels[k] = getPixel565(colors[k]);
163 colors[k] = getColor565(pixels[k]);
166 int[] extremaIndices = determineExtremeColors(colors);
167 if (pixels[extremaIndices[0]] < pixels[extremaIndices[1]])
169 int t = extremaIndices[0];
170 extremaIndices[0] = extremaIndices[1];
171 extremaIndices[1] = t;
174 buffer.putShort((short) pixels[extremaIndices[0]]);
175 buffer.putShort((short) pixels[extremaIndices[1]]);
177 long bitmask = computeBitMask(colors, extremaIndices);
178 buffer.putInt((int) bitmask);
182 return buffer;
186 * @param image
187 * @param mimeType
188 * @return
189 * @throws IllegalArgumentException if either <code>image</code> or <code>mimeType</code> is null, or if
190 * <code>mimeType</code> does not yield a valid suffix
191 * @throws java.io.IOException
193 public static java.nio.ByteBuffer convertToDxt1WithTransparency(java.nio.ByteBuffer image, String mimeType)
194 throws java.io.IOException
196 if (image == null)
198 String message = WorldWind.retrieveErrMsg("nullValue.ByteBufferIsNull");
199 WorldWind.logger().log(java.util.logging.Level.FINE, message);
200 throw new IllegalArgumentException(message);
203 if (mimeType == null)
205 String message = WorldWind.retrieveErrMsg("nullValue.MimeTypeIsNull");
206 gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message);
207 throw new IllegalArgumentException(message);
210 String suffix = WWIO.getSuffixForMimeType(mimeType);
211 if (suffix == null)
213 String message = WorldWind.retrieveErrMsg("DDSConverter.UnsupportedMimeType") + mimeType;
214 WorldWind.logger().log(java.util.logging.Level.FINE, message);
215 throw new IllegalArgumentException(message);
218 java.io.File tempFile = WWIO.saveBufferToTempFile(image, suffix);
220 return convertToDxt1WithTransparency(tempFile);
224 * @param image
225 * @param mimeType
226 * @return
227 * @throws IllegalArgumentException if either <code>image</code> or <code>mimeType</code> is null, or if
228 * <code>mimeType</code> does not yield a valid suffix
229 * @throws java.io.IOException
231 public static java.nio.ByteBuffer convertToDxt3(java.nio.ByteBuffer image, String mimeType)
232 throws java.io.IOException
234 if (image == null)
236 String message = WorldWind.retrieveErrMsg("nullValue.ByteBufferIsNull");
237 WorldWind.logger().log(java.util.logging.Level.FINE, message);
238 throw new IllegalArgumentException(message);
241 if (mimeType == null)
243 String message = WorldWind.retrieveErrMsg("nullValue.MimeTypeIsNull");
244 gov.nasa.worldwind.WorldWind.logger().log(java.util.logging.Level.FINE, message);
245 throw new IllegalArgumentException(message);
248 String suffix = WWIO.getSuffixForMimeType(mimeType);
249 if (suffix == null)
251 String message = WorldWind.retrieveErrMsg("DDSConverter.UnsupportedMimeType") + mimeType;
252 WorldWind.logger().log(java.util.logging.Level.FINE, message);
253 throw new IllegalArgumentException(message);
256 java.io.File tempFile = WWIO.saveBufferToTempFile(image, suffix);
258 return convertToDxt3(tempFile);
262 * @param file
263 * @return
264 * @throws IllegalArgumentException if either <code>file</code> is null, does not exist, or cannot be read
265 * @throws java.io.IOException
267 public static java.nio.ByteBuffer convertToDxt3(java.io.File file) throws java.io.IOException
269 if (file == null)
271 String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull");
272 WorldWind.logger().log(java.util.logging.Level.FINE, message);
273 throw new IllegalArgumentException(message);
276 if (!file.exists() || !file.canRead())
278 String message = WorldWind.retrieveErrMsg("DDSConverter.NoFileOrNoPermission");
279 WorldWind.logger().log(java.util.logging.Level.FINE, message);
280 throw new IllegalArgumentException(message);
283 java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(file);
284 if (image == null)
286 return null;
289 // // Change its orientation to that of OpenGL.
290 // java.awt.geom.AffineTransform xform = java.awt.geom.AffineTransform.getScaleInstance(1, -1);
291 // xform.translate(0, -image.getHeight(null));
292 // java.awt.image.AffineTransformOp op = new java.awt.image.AffineTransformOp(
293 // xform, java.awt.image.AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
294 // image = op.filter(image, null);
296 int[] pixels = new int[16];
297 int bufferSize = 128 + image.getWidth() * image.getHeight() / 2;
298 bufferSize *= 2;
299 java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(bufferSize);
300 buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
301 buildHeaderDxt3(buffer, image.getWidth(), image.getHeight());
303 int numTilesWide = image.getWidth() / 4;
304 int numTilesHigh = image.getHeight() / 4;
305 for (int i = 0; i < numTilesHigh; i++)
307 for (int j = 0; j < numTilesWide; j++)
309 long alphas = makeAlphas(pixels);
310 buffer.putLong(alphas);
312 java.awt.image.BufferedImage originalTile = image.getSubimage(j * 4, i * 4, 4, 4);
313 originalTile.getRGB(0, 0, 4, 4, pixels, 0, 4);
314 Color[] colors = getColors888(pixels);
316 for (int k = 0; k < pixels.length; k++)
318 pixels[k] = getPixel565(colors[k]);
319 colors[k] = getColor565(pixels[k]);
322 int[] extremaIndices = determineExtremeColors(colors);
323 if (pixels[extremaIndices[0]] < pixels[extremaIndices[1]])
325 int t = extremaIndices[0];
326 extremaIndices[0] = extremaIndices[1];
327 extremaIndices[1] = t;
330 buffer.putShort((short) pixels[extremaIndices[0]]);
331 buffer.putShort((short) pixels[extremaIndices[1]]);
333 long bitmask = computeBitMask(colors, extremaIndices);
334 buffer.putInt((int) bitmask);
338 return buffer;
341 private static long makeAlphas(int[] pixels)
343 long sol = 0;
344 for (int i = 0; i < pixels.length; i++)
346 sol |= (pixels[i] & 0xC0000000) >> (i * 2);
349 return sol;
352 protected static void buildHeaderDxt1(java.nio.ByteBuffer buffer, int width, int height)
354 buffer.rewind();
355 buffer.put((byte) 'D');
356 buffer.put((byte) 'D');
357 buffer.put((byte) 'S');
358 buffer.put((byte) ' ');
359 buffer.putInt(124);
360 int flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT | DDSD_LINEARSIZE;
361 buffer.putInt(flag);
362 buffer.putInt(height);
363 buffer.putInt(width);
364 buffer.putInt(width * height / 2);
365 buffer.putInt(0); // depth
366 buffer.putInt(0); // mipmap count
367 buffer.position(buffer.position() + 44); // 11 unused double-words
368 buffer.putInt(32); // pixel format size
369 buffer.putInt(DDPF_FOURCC);
370 buffer.put((byte) 'D');
371 buffer.put((byte) 'X');
372 buffer.put((byte) 'T');
373 buffer.put((byte) '1');
374 buffer.putInt(0); // bits per pixel for RGB (non-compressed) formats
375 buffer.putInt(0); // rgb bit masks for RGB formats
376 buffer.putInt(0); // rgb bit masks for RGB formats
377 buffer.putInt(0); // rgb bit masks for RGB formats
378 buffer.putInt(0); // alpha mask for RGB formats
379 buffer.putInt(DDSCAPS_TEXTURE);
380 buffer.putInt(0); // ddsCaps2
381 buffer.position(buffer.position() + 12); // 3 unused double-words
384 protected static void buildHeaderDxt3(java.nio.ByteBuffer buffer, int width, int height)
386 buffer.rewind();
387 buffer.put((byte) 'D');
388 buffer.put((byte) 'D');
389 buffer.put((byte) 'S');
390 buffer.put((byte) ' ');
391 buffer.putInt(124);
392 int flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT | DDSD_LINEARSIZE;
393 buffer.putInt(flag);
394 buffer.putInt(height);
395 buffer.putInt(width);
396 buffer.putInt(width * height / 2);
397 buffer.putInt(0); // depth
398 buffer.putInt(0); // mipmap count
399 buffer.position(buffer.position() + 44); // 11 unused double-words
400 buffer.putInt(32); // pixel format size
401 buffer.putInt(DDPF_FOURCC);
402 buffer.put((byte) 'D');
403 buffer.put((byte) 'X');
404 buffer.put((byte) 'T');
405 buffer.put((byte) '3');
406 buffer.putInt(0); // bits per pixel for RGB (non-compressed) formats
407 buffer.putInt(0); // rgb bit masks for RGB formats
408 buffer.putInt(0); // rgb bit masks for RGB formats
409 buffer.putInt(0); // rgb bit masks for RGB formats
410 buffer.putInt(0); // alpha mask for RGB formats
411 buffer.putInt(DDSCAPS_TEXTURE);
412 buffer.putInt(0); // ddsCaps2
413 buffer.position(buffer.position() + 12); // 3 unused double-words
416 protected static int[] determineExtremeColors(Color[] colors)
418 int farthest = Integer.MIN_VALUE;
419 int[] ex = new int[2];
421 for (int i = 0; i < colors.length - 1; i++)
423 for (int j = i + 1; j < colors.length; j++)
425 int d = distance(colors[i], colors[j]);
426 if (d > farthest)
428 farthest = d;
429 ex[0] = i;
430 ex[1] = j;
435 return ex;
438 protected static long computeBitMask(Color[] colors, int[] extremaIndices)
440 Color[] colorPoints = new Color[] {null, null, new Color(), new Color()};
441 colorPoints[0] = colors[extremaIndices[0]];
442 colorPoints[1] = colors[extremaIndices[1]];
443 if (colorPoints[0].equals(colorPoints[1]))
444 return 0;
446 // colorPoints[0].r = (colorPoints[0].r & 0xF8) | (colorPoints[0].r >> 5 );
447 // colorPoints[0].g = (colorPoints[0].g & 0xFC) | (colorPoints[0].g >> 6 );
448 // colorPoints[0].b = (colorPoints[0].b & 0xF8) | (colorPoints[0].b >> 5 );
450 // colorPoints[1].r = (colorPoints[1].r & 0xF8) | (colorPoints[1].r >> 5 );
451 // colorPoints[1].g = (colorPoints[1].g & 0xFC) | (colorPoints[1].g >> 6 );
452 // colorPoints[1].b = (colorPoints[1].b & 0xF8) | (colorPoints[1].b >> 5 );
454 colorPoints[2].r = (2 * colorPoints[0].r + colorPoints[1].r + 1) / 3;
455 colorPoints[2].g = (2 * colorPoints[0].g + colorPoints[1].g + 1) / 3;
456 colorPoints[2].b = (2 * colorPoints[0].b + colorPoints[1].b + 1) / 3;
457 colorPoints[3].r = (colorPoints[0].r + 2 * colorPoints[1].r + 1) / 3;
458 colorPoints[3].g = (colorPoints[0].g + 2 * colorPoints[1].g + 1) / 3;
459 colorPoints[3].b = (colorPoints[0].b + 2 * colorPoints[1].b + 1) / 3;
461 long bitmask = 0;
462 for (int i = 0; i < colors.length; i++)
464 int closest = Integer.MAX_VALUE;
465 int mask = 0;
466 for (int j = 0; j < colorPoints.length; j++)
468 int d = distance(colors[i], colorPoints[j]);
469 if (d < closest)
471 closest = d;
472 mask = j;
475 bitmask |= mask << i * 2;
478 return bitmask;
484 protected static int getPixel565(Color color)
486 int r = color.r >> 3;
487 int g = color.g >> 2;
488 int b = color.b >> 3;
489 return r << 11 | g << 5 | b;
492 protected static Color getColor565(int pixel)
494 Color color = new Color();
496 color.r = (int) (((long) pixel) & 0xf800) >> 11;
497 color.g = (int) (((long) pixel) & 0x07e0) >> 5;
498 color.b = (int) (((long) pixel) & 0x001f);
500 return color;
503 protected static Color getColor888(int r8g8b8)
505 return new Color(
506 (int) (((long) r8g8b8) & 0xff0000) >> 16,
507 (int) (((long) r8g8b8) & 0x00ff00) >> 8,
508 (int) (((long) r8g8b8) & 0x0000ff)
513 protected static Color[] getColors888(int[] pixels)
515 Color[] colors = new Color[pixels.length];
517 for (int i = 0; i < pixels.length; i++)
519 colors[i] = new Color();
520 colors[i].r = (int) (((long) pixels[i]) & 0xff0000) >> 16;
521 colors[i].g = (int) (((long) pixels[i]) & 0x00ff00) >> 8;
522 colors[i].b = (int) (((long) pixels[i]) & 0x0000ff);
525 return colors;
528 protected static int distance(Color ca, Color cb)
530 return (cb.r - ca.r) * (cb.r - ca.r) + (cb.g - ca.g) * (cb.g - ca.g) + (cb.b - ca.b) * (cb.b - ca.b);
534 * @param file
535 * @return
536 * @throws IllegalArgumentException if either <code>file</code> is null, does not exist, or cannot be read
537 * @throws java.io.IOException
539 public static java.nio.ByteBuffer convertToDxt1WithTransparency(java.io.File file) throws java.io.IOException
541 /*java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(file);
543 int bufferSize = 128 + image.getWidth() * image.getHeight() / 2;
544 java.nio.ByteBuffer testBuffer = java.nio.ByteBuffer.allocate(bufferSize);
545 testBuffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
546 buildHeaderDxt1(testBuffer, image.getWidth(), image.getHeight());
548 int numTilesWide = image.getWidth() / 4;
549 int numTilesHigh = image.getHeight() / 4;
551 for (int i = 0; i < numTilesHigh; i++)
553 for (int j = 0; j < numTilesWide; j++)
555 short min = 255;
556 short max = 127;
558 testBuffer.putShort(min);
559 testBuffer.putShort(max);
561 int bitmask = 0x012345678;//0xffff43cf;
562 testBuffer.putInt(bitmask);
566 return testBuffer;
569 if (file == null)
570 { //
571 String message = WorldWind.retrieveErrMsg("nullValue.FileIsNull");
572 WorldWind.logger().log(java.util.logging.Level.FINE, message);
573 throw new IllegalArgumentException(message);
576 if (!file.exists() || !file.canRead())
578 String message = WorldWind.retrieveErrMsg("DDSConverter.NoFileOrNoPermission");
579 WorldWind.logger().log(java.util.logging.Level.FINE, message);
580 throw new IllegalArgumentException(message);
583 java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(file);
585 if (image == null)
586 return null;
588 int[] pixels = new int[16];
589 int bufferSize = 128 + image.getWidth() * image.getHeight() / 2;
590 java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(bufferSize);
591 buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
592 buildHeaderDxt1(buffer, image.getWidth(), image.getHeight());
594 int numTilesWide = image.getWidth() / 4;
595 int numTilesHigh = image.getHeight() / 4;
596 for (int i = 0; i < numTilesHigh; i++)
598 for (int j = 0; j < numTilesWide; j++)
600 java.awt.image.BufferedImage originalTile = image.getSubimage(j * 4, i * 4, 4, 4);
601 originalTile.getRGB(0, 0, 4, 4, pixels, 0, 4); // these are in format "TYPE_INT_ARGB" 16,5,6,5
603 TransparentColor[] colors = getColors5551(pixels);
605 int[] extremaIndices = determineExtremeColors(colors);
607 // we want extremaIndices[0] to be greater than extremaIndices[1]
608 short min = getShort5551(colors[extremaIndices[0]]);
609 short max = getShort5551(colors[extremaIndices[1]]);
610 if (min > max)
612 // we want min to be less than max.
613 int t = extremaIndices[0];
614 extremaIndices[0] = extremaIndices[1];
615 extremaIndices[1] = t;
617 short temp = min;
618 min = max;
619 max = temp;
621 else if (min == max)
623 // because of this case, we don't get transparency.
624 equalTransparentCase(colors, extremaIndices, min);
626 min = getShort5551(colors[extremaIndices[0]]);
627 max = getShort5551(colors[extremaIndices[1]]);
630 buffer.putShort(min);
631 buffer.putShort(max);
633 long bitmask = computeBitMask(colors, extremaIndices);
634 buffer.putInt((int) bitmask);
638 return buffer;
641 protected static void equalTransparentCase(TransparentColor[] colors, int[] extremaIndices, short value)
643 // we want extremaIndices[0] to be greater than extremaIndices[1]
645 if (value == 0)
647 // transparent
648 colors[extremaIndices[0]] = TransparentColor.OFF_TRANSPARENT;
650 /*else
652 // not transparent anywhere - it's all one colour, so we don't need to bother making changes
657 protected static int distance(TransparentColor ca, TransparentColor cb)
659 return (cb.r - ca.r) * (cb.r - ca.r) + (cb.g - ca.g) * (cb.g - ca.g) + (cb.b - ca.b) * (cb.b - ca.b)
660 + (cb.a - ca.a) * (cb.a - ca.a);
663 // public static void main(String[] args)
664 // {
665 // try
666 // {
667 // String fileName = "testdata/0000_0001";
668 // java.nio.ByteBuffer buffer = convertToDxt1NoTransparency(new java.io.File(fileName + ".jpg"));
669 // buffer.rewind();
670 // java.io.FileOutputStream fos = new java.io.FileOutputStream(fileName + ".dds");
671 // java.nio.channels.FileChannel channel = fos.getChannel();
672 // channel.write(buffer);
673 // }
674 // catch (java.io.IOException e)
675 // {
676 // e.printStackTrace();
677 // }
679 // return;
680 // }
682 protected static long computeBitMask(TransparentColor[] colors, int[] extremaIndices)
684 TransparentColor[] colorPoints = {null, null, new TransparentColor(), new TransparentColor()};
686 colorPoints[0] = colors[extremaIndices[0]];
687 colorPoints[1] = colors[extremaIndices[1]];
689 colorPoints[2].r = (byte) ((colorPoints[0].r + colorPoints[1].r) / 2);
690 colorPoints[2].g = (byte) ((colorPoints[0].g + colorPoints[1].g) / 2);
691 colorPoints[2].b = (byte) ((colorPoints[0].b + colorPoints[1].b) / 2);
692 colorPoints[2].a = 1;
694 colorPoints[3].r = 0;
695 colorPoints[3].g = 0;
696 colorPoints[3].b = 0;
697 colorPoints[3].a = 0;
699 long bitmask = 0;
700 for (int i = 0; i < colors.length; i++)
702 int closest = Integer.MAX_VALUE;
703 int mask = 0;
704 if (colors[i].a == 0)
706 mask = 3;
708 else
710 for (int j = 0; j < colorPoints.length; j++)
712 int d = distance(colors[i], colorPoints[j]);
713 if (d < closest)
715 closest = d;
716 mask = j;
720 bitmask |= mask << i * 2;
723 return bitmask;
726 protected static short getShort5551(TransparentColor color)
728 short s = 0;
729 s |= ((color.r & 0x0f8) << 8) | ((color.g & 0x0f8) << 4) | ((color.b & 0x0f8) >> 3) | ((color.a & 0x0f8) >> 7);
730 // System.out.println(Integer.toBinaryString(s));
731 return s;
734 protected static int[] determineExtremeColors(TransparentColor[] colors)
736 int farthest = Integer.MIN_VALUE;
737 int[] ex = {0, 0};
739 for (int i = 0; i < colors.length - 1; i++)
741 for (int j = i + 1; j < colors.length; j++)
743 int d = distance(colors[i], colors[j]);
744 if (d > farthest)
746 farthest = d;
747 ex[0] = i;
748 ex[1] = j;
753 return ex;
756 protected static TransparentColor[] getColors5551(int[] pixels)
758 TransparentColor colors[] = new TransparentColor[pixels.length];
760 for (int i = 0; i < pixels.length; i++)
762 colors[i] = generateColor5551(pixels[i]);
764 return colors;
767 protected static TransparentColor generateColor5551(int pixel)
769 short alpha = (short) (pixel >> 24);
770 if ((alpha & 0xf0) == 0)
772 return TransparentColor.TRANSPARENT;
775 // ok, it's not transparent - that's already been ruled out.
777 TransparentColor tc = new TransparentColor();
778 tc.a = (byte) 0x000000ff;
779 tc.r = (byte) ((pixel & 0x00ff0000) >> 16);
780 tc.g = (byte) ((pixel & 0x0000ff00) >> 8);
781 tc.b = (byte) (pixel & 0x000000ff);
783 return tc;
786 protected static class TransparentColor
788 private static final TransparentColor TRANSPARENT = new TransparentColor((byte) 0, (byte) 0, (byte) 0,
789 (byte) 0);
790 private static final TransparentColor OFF_TRANSPARENT = new TransparentColor((byte) 0, (byte) 0, (byte) 1,
791 (byte) 0);
792 private byte r, g, b, a;
794 private TransparentColor()
798 private TransparentColor(byte r, byte g, byte b, byte a)
800 this.r = r;
801 this.g = g;
802 this.b = b;
803 this.a = a;
806 public boolean equals(Object o)
808 if (this == o)
809 return true;
810 if (o == null || getClass() != o.getClass())
811 return false;
813 final gov.nasa.worldwind.DDSConverter.TransparentColor that =
814 (gov.nasa.worldwind.DDSConverter.TransparentColor) o;
816 if (a != that.a)
817 return false;
818 if (b != that.b)
819 return false;
820 if (g != that.g)
821 return false;
822 //noinspection RedundantIfStatement
823 if (r != that.r)
824 return false;
826 return true;
829 public int hashCode()
831 int result;
832 result = r;
833 result = 29 * result + g;
834 result = 29 * result + b;
835 result = 29 * result + a;
836 return result;
839 public String toString()
841 return "TransColor argb: " + this.a + ", " + this.r + ", " + this.g + ", " + this.b;