Exemplo n.º 1
0
        /**
         * Compress the 4x4 color block into a DXT2/DXT3 block using 16 4 bit alpha values, and four colors. This method
         * compresses the color block exactly as a DXT1 compressor, except that it guarantees that the DXT1 block will use
         * four colors.
         * <p/>
         * Access to this method must be synchronized by the caller. This method is frequently invoked by the DXT
         * compressor, so in order to reduce garbage each instance of this class has unsynchronized properties that are
         * reused during each call.
         *
         * @param colorBlock the 4x4 color block to compress.
         * @param attributes attributes that will control the compression.
         * @param dxtBlock   the DXT2/DXT3 block that will receive the compressed data.
         * @throws ArgumentException if either <code>colorBlock</code> or <code>dxtBlock</code> are null.
         */
        public void compressBlockDXT3(ColorBlock4x4 colorBlock, DXTCompressionAttributes attributes, BlockDXT3 dxtBlock)
        {
            if (colorBlock == null)
            {
                String message = Logging.getMessage("nullValue.ColorBlockIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (attributes == null)
            {
                String message = Logging.getMessage("nullValue.AttributesIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (dxtBlock == null)
            {
                String message = Logging.getMessage("nullValue.DXTBlockIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }

            // The DXT3 color block is compressed exactly like the DXT1 color block, except that the four color palette is
            // always used, no matter the ordering of color0 and color1. At this stage we only consider color values,
            // not alpha.
            this.dxt1Compressor.compressBlockDXT1(colorBlock, attributes, dxtBlock.colorBlock);

            // The DXT3 alpha block can be compressed separately.
            this.compressBlockDXT3a(colorBlock, dxtBlock.alphaBlock);
        }
Exemplo n.º 2
0
        public void compressImage(java.awt.image.BufferedImage image, DXTCompressionAttributes attributes,
                                  java.nio.ByteBuffer buffer)
        {
            if (image == null)
            {
                String message = Logging.getMessage("nullValue.ImageIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (attributes == null)
            {
                String message = Logging.getMessage("nullValue.AttributesIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (buffer == null)
            {
                String message = Logging.getMessage("nullValue.BufferNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }

            // If it is determined that the image and block have no alpha component, then we compress with DXT1 using a
            // four color palette. Otherwise, we use the three color palette (with the fourth color as transparent black).

            ColorBlock4x4       colorBlock          = new ColorBlock4x4();
            ColorBlockExtractor colorBlockExtractor = this.getColorBlockExtractor(image);

            BlockDXT1           dxt1Block      = new BlockDXT1();
            BlockDXT1Compressor dxt1Compressor = new BlockDXT1Compressor();

            int width  = image.getWidth();
            int height = image.getHeight();

            bool imageHasAlpha  = image.getColorModel().hasAlpha();
            bool enableAlpha    = attributes.isEnableDXT1Alpha();
            int  alphaThreshold = attributes.getDXT1AlphaThreshold();

            for (int j = 0; j < height; j += 4)
            {
                for (int i = 0; i < width; i += 4)
                {
                    colorBlockExtractor.extractColorBlock4x4(attributes, i, j, colorBlock);

                    if (enableAlpha && imageHasAlpha && blockHasDXT1Alpha(colorBlock, alphaThreshold))
                    {
                        dxt1Compressor.compressBlockDXT1a(colorBlock, attributes, dxt1Block);
                    }
                    else
                    {
                        dxt1Compressor.compressBlockDXT1(colorBlock, attributes, dxt1Block);
                    }

                    buffer.putShort((short)dxt1Block.color0);
                    buffer.putShort((short)dxt1Block.color1);
                    buffer.putInt((int)dxt1Block.colorIndexMask);
                }
            }
        }
        /**
         * Extracts a 4x4 block of pixel data at the specified coordinate <code>(x, y)</code>, and places the data in the
         * specified <code>colorBlock</code>. If the coordinate <code>(x, y)</code> with the image, but the entire 4x4
         * block is not, this will either truncate the block to fit the image, or copy nearby pixels to fill the block. If
         * the <code>attributes</code> specify that color components should be premultiplied by alpha, this extactor will
         * perform the premultiplication operation on the incoming colors.
         * <p>
         * Access to this method must be synchronized by the caller. This method is frequenty invoked by the DXT
         * compressor, so in order to reduce garbage each instance of this class has unsynchronized properties that are
         * reused during each call.
         *
         * @param attributes the DXT compression attributes which may affect how colors are accessed.
         * @param x horizontal coordinate origin to extract pixel data from.
         * @param y vertical coordainte origin to extract pixel data from.
         * @param colorBlock 4x4 block of pixel data that will receive the data.
         *
         * @throws ArgumentException if either <code>attributes</code> or <code>colorBlock</code> is null.
         */
        public void extractColorBlock4x4(DXTCompressionAttributes attributes, int x, int y, ColorBlock4x4 colorBlock)
        {
            if (attributes == null)
            {
                String message = Logging.getMessage("nullValue.AttributesIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (colorBlock == null)
            {
                String message = Logging.getMessage("nullValue.ColorBlockIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }

            // Image blocks that are smaller than 4x4 are handled by repeating the image pixels that intersect the
            // requested block range.

            int bw = Math.Min(this.width - x, 4);
            int bh = Math.Min(this.height - y, 4);
            int bxOffset = 4 * (bw - 1);
            int byOffset = 4 * (bh - 1);
            int bx, by;
            int blockPos = 0;

            // Extracts color data from the image in INT_ARGB format. So each integer in the buffer is a tightly packed
            // 8888 ARGB int, where the color components are not considered to be premultiplied.
            this.image.getRGB(x, y, bw, bh, this.buffer, 0, 4);

            for (int j = 0; j < 4; j++)
            {
                by = remainder[byOffset + j];

                bx = remainder[bxOffset];
                int32ToColor32(this.buffer[bx + by * 4], colorBlock.color[blockPos++]);

                bx = remainder[bxOffset + 1];
                int32ToColor32(this.buffer[bx + by * 4], colorBlock.color[blockPos++]);

                bx = remainder[bxOffset + 2];
                int32ToColor32(this.buffer[bx + by * 4], colorBlock.color[blockPos++]);

                bx = remainder[bxOffset + 3];
                int32ToColor32(this.buffer[bx + by * 4], colorBlock.color[blockPos++]);
            }

            if (attributes.isPremultiplyAlpha())
            {
                for (int i = 0; i < 16; i++)
                {
                    premultiplyAlpha(colorBlock.color[i]);
                }
            }
        }
Exemplo n.º 4
0
        public void compressImage(java.awt.image.BufferedImage image, DXTCompressionAttributes attributes,
                                  java.nio.ByteBuffer buffer)
        {
            if (image == null)
            {
                String message = Logging.getMessage("nullValue.ImageIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (attributes == null)
            {
                String message = Logging.getMessage("nullValue.AttributesIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (buffer == null)
            {
                String message = Logging.getMessage("nullValue.BufferNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }

            ColorBlock4x4       colorBlock          = new ColorBlock4x4();
            ColorBlockExtractor colorBlockExtractor = this.getColorBlockExtractor(image);

            BlockDXT3           dxt3Block      = new BlockDXT3();
            BlockDXT3Compressor dxt3Compressor = new BlockDXT3Compressor();

            int width  = image.getWidth();
            int height = image.getHeight();

            for (int j = 0; j < height; j += 4)
            {
                for (int i = 0; i < width; i += 4)
                {
                    colorBlockExtractor.extractColorBlock4x4(attributes, i, j, colorBlock);
                    dxt3Compressor.compressBlockDXT3(colorBlock, attributes, dxt3Block);

                    AlphaBlockDXT3 dxtAlphaBlock = dxt3Block.getAlphaBlock();
                    buffer.putLong(dxtAlphaBlock.alphaValueMask);

                    BlockDXT1 dxtColorBlock = dxt3Block.getColorBlock();
                    buffer.putShort((short)dxtColorBlock.color0);
                    buffer.putShort((short)dxtColorBlock.color1);
                    buffer.putInt((int)dxtColorBlock.colorIndexMask);
                }
            }
        }
        protected static long computePaletteIndices3(ColorBlock4x4 block, DXTCompressionAttributes attributes,
                                                     Color32[] palette)
        {
            // This implementation is based on code available in the nvidia-texture-tools project:
            // http://code.google.com/p/nvidia-texture-tools/
            //
            // If the pixel alpha is below the specified threshold, we return index 3. In a three color DXT1 palette,
            // index 3 is interpreted as transparent black. Otherwise, we compare the sums of absolute differences, and
            // choose the nearest color index.

            int alphaThreshold = attributes.getDXT1AlphaThreshold();

            long mask = 0L;
            long index;

            for (int i = 0; i < 16; i++)
            {
                int d0 = colorDistanceSquared(palette[0], block.color[i]);
                int d1 = colorDistanceSquared(palette[1], block.color[i]);
                int d2 = colorDistanceSquared(palette[2], block.color[i]);

                // TODO: implement bit twiddle as in computePaletteIndex4 to avoid conditional branching

                if (block.color[i].a < alphaThreshold)
                {
                    index = 3;
                }
                else if (d0 < d1 && d0 < d2)
                {
                    index = 0;
                }
                else if (d1 < d2)
                {
                    index = 1;
                }
                else
                {
                    index = 2;
                }

                mask |= (index << (i << 1));
            }

            return(mask);
        }
Exemplo n.º 6
0
        public int getCompressedSize(java.awt.image.BufferedImage image, DXTCompressionAttributes attributes)
        {
            if (image == null)
            {
                String message = Logging.getMessage("nullValue.ImageIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (attributes == null)
            {
                String message = Logging.getMessage("nullValue.AttributesIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }

            // TODO: comment, provide documentation reference

            int width  = Math.Max(image.getWidth(), 4);
            int height = Math.Max(image.getHeight(), 4);

            return((width * height) / 2);
        }
        /**
         * Compress the 4x4 color block into a DXT1 block using four colors. This method ignores transparency and
         * guarantees that the DXT1 block will use four colors.
         * <p>
         * Access to this method must be synchronized by the caller. This method is frequently invoked by the DXT
         * compressor, so in order to reduce garbage each instance of this class has unsynchronized properties that are
         * reused during each call.
         *
         * @param colorBlock the 4x4 color block to compress.
         * @param attributes attributes that will control the compression.
         * @param dxtBlock the DXT1 block that will receive the compressed data.
         *
         * @throws ArgumentException if either <code>colorBlock</code> or <code>dxtBlock</code> are null.
         */
        public void compressBlockDXT1(ColorBlock4x4 colorBlock, DXTCompressionAttributes attributes, BlockDXT1 dxtBlock)
        {
            if (colorBlock == null)
            {
                String message = Logging.getMessage("nullValue.ColorBlockIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (attributes == null)
            {
                String message = Logging.getMessage("nullValue.AttributesIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }
            if (dxtBlock == null)
            {
                String message = Logging.getMessage("nullValue.DXTBlockIsNull");
                Logging.logger().severe(message);
                throw new ArgumentException(message);
            }

            this.chooseMinMaxColors(colorBlock, attributes, this.minColor, this.maxColor);
            int color0 = short565FromColor32(this.maxColor);
            int color1 = short565FromColor32(this.minColor);

            if (color0 < color1)
            {
                int tmp = color0;
                color0 = color1;
                color1 = tmp;
            }

            // To get a four color palette with no alpha, the first color must be greater than the second color.
            computeColorPalette4(color0, color1, this.palette);

            dxtBlock.color0         = color0;
            dxtBlock.color1         = color1;
            dxtBlock.colorIndexMask = computePaletteIndices4(colorBlock, this.palette);
        }
 protected void chooseMinMaxColors(ColorBlock4x4 block, DXTCompressionAttributes attributes,
                                   Color32 minColor, Color32 maxColor)
 {
     //noinspection StringEquality
     if (attributes.getColorBlockCompressionType() == DXTCompressionAttributes.COLOR_BLOCK_COMPRESSION_BBOX)
     {
         findMinMaxColorsBox(block, minColor, maxColor);
         selectDiagonal(block, minColor, maxColor);
         insetBox(minColor, maxColor);
     }
     else //noinspection StringEquality
     if (attributes.getColorBlockCompressionType() == DXTCompressionAttributes.COLOR_BLOCK_COMPRESSION_EUCLIDEAN_DISTANCE)
     {
         findMinMaxColorsEuclideanDistance(block, minColor, maxColor);
     }
     else //noinspection StringEquality
     if (attributes.getColorBlockCompressionType() == DXTCompressionAttributes.COLOR_BLOCK_COMPRESSION_LUMINANCE_DISTANCE)
     {
         // Default to using euclidean distance to compute the min and max palette colors.
         findMinMaxColorsLuminanceDistance(block, minColor, maxColor);
     }
 }
Exemplo n.º 9
0
 /**
  * Convenience method to convert the specified image <code>stream</code> to DDS according to the specified
  * compression <code>attributes</code>. The <code>stream</code> must be readable by {@link
  * javax.imageio.ImageIO#read(java.io.InputStream)}. Once the <code>stream</code> is read, this is equivalent to
  * calling {#compressImage(java.awt.image.BufferedImage, SharpEarth.formats.dds.DXTCompressionAttributes)}
  * with the BufferedImage created by ImageIO and the specified <code>attributes</code>. This returns null if the
  * <code>stream</code> is not in a format understood by ImageIO.
  *
  * @param inputStream image stream to convert to the DDS file format.
  * @param attributes  attributes that control the compression.
  *
  * @return little endian ordered ByteBuffer containing the DDS file bytes, or null if the <code>stream</code> is not
  *         in a format understood by ImageIO.
  *
  * @throws java.io.IOException      if <code>stream</code> is in a format understood by ImageIO, but the image data
  *                                  cannot be read by ImageIO.
  * @throws ArgumentException if either the <code>stream</code> or the <code>attributes</code> are null.
  */
 public static java.nio.ByteBuffer compressImageStream(java.io.InputStream inputStream,
                                                       DXTCompressionAttributes attributes) throws java.io.IOException