Пример #1
0
        /// <summary>
        ///   Return a subvolume of this PixelBox.
        /// </summary>
        /// <param name="def"> Defines the bounds of the subregion to return </param>
        /// <returns> A pixel box describing the region and the data in it </returns>
        /// <remarks>
        ///   This function does not copy any data, it just returns a PixelBox object with a data pointer pointing somewhere inside the data of object. Throws an Exception if def is not fully contained.
        /// </remarks>
        public PixelBox GetSubVolume(BasicBox def)
        {
            if (Compressed(this.format))
            {
                if (def.Left == left && def.Top == top && def.Front == front && def.Right == right && def.Bottom == bottom &&
                    def.Back == back)
                {
                    // Entire buffer is being queried
                    return(this);
                }
                throw new Exception("Cannot return subvolume of compressed PixelBuffer, in PixelBox.GetSubVolume");
            }
            if (!Contains(def))
            {
                throw new Exception("Bounds out of range, in PixelBox.GetSubVolume");
            }

            var elemSize = PixelUtil.GetNumElemBytes(this.format);
            // Calculate new data origin
            var rval = new PixelBox(def, this.format, this.data);

            rval.offset = (((def.Left - left) * elemSize) + ((def.Top - top) * this.rowPitch * elemSize) +
                           ((def.Front - front) * this.slicePitch * elemSize));
            rval.rowPitch   = this.rowPitch;
            rval.slicePitch = this.slicePitch;
            rval.format     = this.format;
            return(rval);
        }
Пример #2
0
            public static void Convert(PixelBox src, PixelBox dst, IPixelConverter pixelConverter)
            {
                {
                    var srcptr       = (BufferBase)src.Data.Clone();
                    var dstptr       = (BufferBase)dst.Data.Clone();
                    var srcSliceSkip = src.SliceSkip;
                    var dstSliceSkip = dst.SliceSkip;
                    var k            = src.Right - src.Left;

                    for (var z = src.Front; z < src.Back; z++)
                    {
                        for (var y = src.Top; y < src.Bottom; y++)
                        {
                            for (var x = 0; x < k; x++)
                            {
                                pixelConverter.Convert(srcptr, dstptr, x);
                            }
                            srcptr.Ptr += src.RowPitch * PixelUtil.GetNumElemBytes(src.Format);
                            dstptr.Ptr += dst.RowPitch * PixelUtil.GetNumElemBytes(dst.Format);
                        }
                        srcptr.Ptr += srcSliceSkip;
                        dstptr.Ptr += dstSliceSkip;
                    }
                }
            }
Пример #3
0
        public void FlipAroundX()
        {
            if (this.buffer == null)
            {
                throw new AxiomException("Can not flip an unitialized texture");
            }

            var bytes = PixelUtil.GetNumElemBytes(this.format);

            this.numMipMaps = 0; // Image operations lose precomputed mipmaps
            var rowSpan = this.width * bytes;

            var tempBuffer = new byte[rowSpan * this.height];

            int srcOffset = 0, dstOffset = tempBuffer.Length - rowSpan;

            for (short y = 0; y < this.height; y++)
            {
                Array.Copy(this.buffer, srcOffset, tempBuffer, dstOffset, rowSpan);

                srcOffset += rowSpan;
                dstOffset -= rowSpan;
            }

            Array.Copy(tempBuffer, this.buffer, tempBuffer.Length);
        }
Пример #4
0
        /// <summary>
        ///   Loads raw image data from memory.
        /// </summary>
        /// <param name="stream"> Stream containing the raw image data. </param>
        /// <param name="width"> Width of this image data (in pixels). </param>
        /// <param name="height"> Height of this image data (in pixels). </param>
        /// <param name="depth"> </param>
        /// <param name="format"> Pixel format used in this texture. </param>
        /// <returns> A new instance of Image containing the raw data supplied. </returns>
        public static Image FromRawStream(Stream stream, int width, int height, int depth, PixelFormat format)
        {
            // create a new buffer and write the image data directly to it
            var size   = width * height * depth * PixelUtil.GetNumElemBytes(format);
            var buffer = new byte[size];

            stream.Read(buffer, 0, size);
            return((new Image()).FromDynamicImage(buffer, width, height, depth, format));
        }
Пример #5
0
        /// <summary>
        ///    Loads raw image data from a byte array.
        /// </summary>
        /// <param name="buffer">Raw image buffer.</param>
        /// <param name="width">Width of this image data (in pixels).</param>
        /// <param name="height">Height of this image data (in pixels).</param>
        /// <param name="format">Pixel format used in this texture.</param>
        /// <returns>A new instance of Image containing the raw data supplied.</returns>
        public static Image FromDynamicImage(byte[] buffer, int width, int height, int depth, PixelFormat format)
        {
            Image image = new Image();

            image.width  = width;
            image.height = height;
            image.depth  = depth;
            image.format = format;
            image.size   = width * height * depth * PixelUtil.GetNumElemBytes(format);
            image.SetBuffer(buffer);

            return(image);
        }
Пример #6
0
        public void FlipAroundY()
        {
            if (this.buffer == null)
            {
                throw new AxiomException("Can not flip an unitialized texture");
            }

            this.numMipMaps = 0; // Image operations lose precomputed mipmaps

            int src = 0, dst = 0;

            var bytes      = PixelUtil.GetNumElemBytes(this.format);
            var tempBuffer = new byte[this.width * this.height * bytes];

            if (bytes > 4 || bytes < 1)
            {
                throw new AxiomException("Unknown pixel depth");
            }

            else if (bytes == 3)
            {
                for (int y = 0; y < this.height; y++)
                {
                    dst = ((y * this.width) + this.width - 1) * 3;
                    for (int x = 0; x < this.width; x++)
                    {
                        Array.Copy(this.buffer, src, tempBuffer, dst, bytes);
                        src += 3;
                        dst -= 3;
                    }
                }
            }

            else
            {
                for (int y = 0; y < this.height; y++)
                {
                    dst = ((y * this.width) + this.width - 1);
                    for (int x = 0; x < this.width; x++)
                    {
                        Array.Copy(this.buffer, src++, tempBuffer, dst--, bytes);
                    }
                }
            }

            Array.Copy(tempBuffer, this.buffer, tempBuffer.Length);
        }
Пример #7
0
        public PixelBox GetPixelBox(int face, int mipmap)
        {
            if (mipmap > numMipMaps)
            {
                throw new IndexOutOfRangeException();
            }
            if (face > this.NumFaces)
            {
                throw new IndexOutOfRangeException();
            }
            // Calculate mipmap offset and size
            int width    = this.Width;
            int height   = this.Height;
            int depth    = this.Depth;
            int faceSize = 0; // Size of one face of the image
            int offset   = 0;

            for (int mip = 0; mip < mipmap; ++mip)
            {
                faceSize = PixelUtil.GetMemorySize(width, height, depth, this.Format);
                /// Skip all faces of this mipmap
                offset += faceSize * this.NumFaces;
                /// Half size in each dimension
                if (width != 1)
                {
                    width /= 2;
                }
                if (height != 1)
                {
                    height /= 2;
                }
                if (depth != 1)
                {
                    depth /= 2;
                }
            }
            // We have advanced to the desired mipmap, offset to right face
            faceSize = PixelUtil.GetMemorySize(width, height, depth, this.Format);
            offset  += faceSize * face;
            // Return subface as pixelbox
            IntPtr newBufPtr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset);

            return(new PixelBox(width, height, depth, this.Format, newBufPtr));
        }
Пример #8
0
        /// <summary>
        ///		Flips this image around the X axis.
        ///     This will invalidate any
        /// </summary>
        public void FlipAroundX()
        {
            int bytes   = PixelUtil.GetNumElemBytes(format);
            int rowSpan = width * bytes;

            byte[] tempBuffer = new byte[rowSpan * height];

            int srcOffset = 0, dstOffset = tempBuffer.Length - rowSpan;

            for (short y = 0; y < height; y++)
            {
                Array.Copy(buffer, srcOffset, tempBuffer, dstOffset, rowSpan);

                srcOffset += rowSpan;
                dstOffset -= rowSpan;
            }

            Array.Copy(tempBuffer, buffer, tempBuffer.Length);
        }
Пример #9
0
        private PixelFormat _convertPixelFormat(int rgbBits, int rMask, int gMask, int bMask, int aMask)
        {
            // General search through pixel formats
            for (var i = (int)PixelFormat.Unknown + 1; i < (int)PixelFormat.Count; ++i)
            {
                var pf = (PixelFormat)i;
                if (PixelUtil.GetNumElemBits(pf) == rgbBits)
                {
                    var testMasks = PixelUtil.GetBitMasks(pf);
                    var testBits  = PixelUtil.GetBitDepths(pf);

                    if (testMasks[0] == rMask && testMasks[1] == gMask && testMasks[2] == bMask &&
                        // for alpha, deal with 'X8' formats by checking bit counts
                        (testMasks[3] == aMask || (aMask == 0 && testBits[3] == 0)))
                    {
                        return(pf);
                    }
                }
            }

            throw new AxiomException("Cannot determine pixel format");
        }
Пример #10
0
        public static int CalculateSize(int mipmaps, int faces, int width, int height, int depth, PixelFormat format)
        {
            int size = 0;

            for (int mip = 0; mip <= mipmaps; ++mip)
            {
                size += PixelUtil.GetMemorySize(width, height, depth, format) * faces;
                if (width != 1)
                {
                    width /= 2;
                }
                if (height != 1)
                {
                    height /= 2;
                }
                if (depth != 1)
                {
                    depth /= 2;
                }
            }
            return(size);
        }
        ///<summary>
        ///    Convert pixels from one format to another. No dithering or filtering is being done. Converting
        ///    from RGB to luminance takes the R channel.
        ///</summary>
        ///<param name="src">PixelBox containing the source pixels, pitches and format</param>
        ///<param name="dst">PixelBox containing the destination pixels, pitches and format</param>
        ///<remarks>
        ///    The source and destination boxes must have the same
        ///    dimensions. In case the source and destination format match, a plain copy is done.
        ///</remarks>
        public static void BulkPixelConversion(PixelBox src, PixelBox dst)
        {
            Debug.Assert(src.Width == dst.Width && src.Height == dst.Height && src.Depth == dst.Depth);

            // Check for compressed formats, we don't support decompression, compression or recoding
            if (PixelBox.Compressed(src.Format) || PixelBox.Compressed(dst.Format))
            {
                if (src.Format == dst.Format)
                {
                    CopyBytes(dst.Data, dst.Offset, src.Data, src.Offset, src.ConsecutiveSize);
                    return;
                }
                else
                {
                    throw new Exception("This method can not be used to compress or decompress images, in PixelBox.BulkPixelConversion");
                }
            }

            // The easy case
            if (src.Format == dst.Format)
            {
                // Everything consecutive?
                if (src.Consecutive && dst.Consecutive)
                {
                    CopyBytes(dst.Data, dst.Offset, src.Data, src.Offset, src.ConsecutiveSize);
                    return;
                }
                unsafe {
                    byte *srcBytes     = (byte *)src.Data.ToPointer();
                    byte *dstBytes     = (byte *)dst.Data.ToPointer();
                    byte *srcptr       = srcBytes + src.Offset;
                    byte *dstptr       = dstBytes + dst.Offset;
                    int   srcPixelSize = PixelUtil.GetNumElemBytes(src.Format);
                    int   dstPixelSize = PixelUtil.GetNumElemBytes(dst.Format);

                    // Calculate pitches+skips in bytes
                    int srcRowPitchBytes = src.RowPitch * srcPixelSize;
                    //int srcRowSkipBytes = src.RowSkip * srcPixelSize;
                    int srcSliceSkipBytes = src.SliceSkip * srcPixelSize;

                    int dstRowPitchBytes = dst.RowPitch * dstPixelSize;
                    //int dstRowSkipBytes = dst.RowSkip * dstPixelSize;
                    int dstSliceSkipBytes = dst.SliceSkip * dstPixelSize;

                    // Otherwise, copy per row
                    int rowSize = src.Width * srcPixelSize;
                    for (int z = src.Front; z < src.Back; z++)
                    {
                        for (int y = src.Top; y < src.Bottom; y++)
                        {
                            byte *s = srcptr;
                            byte *d = dstptr;
                            for (int i = 0; i < rowSize; i++)
                            {
                                *d++ = *s++;
                            }
                            srcptr += srcRowPitchBytes;
                            dstptr += dstRowPitchBytes;
                        }
                        srcptr += srcSliceSkipBytes;
                        dstptr += dstSliceSkipBytes;
                    }
                }
                return;
            }

            if (PixelConversionLoops.DoOptimizedConversion(src, dst))
            {
                // If so, good
                return;
            }

            unsafe {
                byte *srcBytes     = (byte *)src.Data.ToPointer();
                byte *dstBytes     = (byte *)dst.Data.ToPointer();
                byte *srcptr       = srcBytes + src.Offset;
                byte *dstptr       = dstBytes + dst.Offset;
                int   srcPixelSize = PixelUtil.GetNumElemBytes(src.Format);
                int   dstPixelSize = PixelUtil.GetNumElemBytes(dst.Format);

                // Calculate pitches+skips in bytes
                int srcRowSkipBytes   = src.RowSkip * srcPixelSize;
                int srcSliceSkipBytes = src.SliceSkip * srcPixelSize;
                int dstRowSkipBytes   = dst.RowSkip * dstPixelSize;
                int dstSliceSkipBytes = dst.SliceSkip * dstPixelSize;

                // The brute force fallback
                float r, g, b, a;
                for (int z = src.Front; z < src.Back; z++)
                {
                    for (int y = src.Top; y < src.Bottom; y++)
                    {
                        for (int x = src.Left; x < src.Right; x++)
                        {
                            UnpackColor(out r, out g, out b, out a, src.Format, srcptr);
                            PackColor(r, g, b, a, dst.Format, dstptr);
                            srcptr += srcPixelSize;
                            dstptr += dstPixelSize;
                        }
                        srcptr += srcRowSkipBytes;
                        dstptr += dstRowSkipBytes;
                    }
                    srcptr += srcSliceSkipBytes;
                    dstptr += dstSliceSkipBytes;
                }
            }
        }
Пример #12
0
        public override Codec.DecodeResult Decode(Stream input)
        {
            using (var br = new BinaryReader(input))
            {
                // Read 4 character code
                var fileType = br.ReadInt32();
                using (var wrap = BufferBase.Wrap(fileType, 2))
                {
                    _flipEndian(wrap, sizeof(uint), 1);
                }

                if (FOURCC('D', 'D', 'S', ' ') != fileType)
                {
                    throw new AxiomException("This is not a DDS file!");
                }

                // Read header in full
                var header = DDSHeader.Read(br);

                // Endian flip if required, all 32-bit values
                using (var wrap = BufferBase.Wrap(header, Memory.SizeOf(typeof(DDSHeader))))
                {
                    _flipEndian(wrap, 4, Memory.SizeOf(typeof(DDSHeader)) / 4);
                }

                // Check some sizes
                if (header.size != DDS_HEADER_SIZE)
                {
                    throw new AxiomException("DDS header size mismatch!");
                }

                if (header.pixelFormat.size != DDS_PIXELFORMAT_SIZE)
                {
                    throw new AxiomException("DDS header size mismatch!");
                }

                var imgData = new ImageData();

                imgData.depth  = 1; // (deal with volume later)
                imgData.width  = header.width;
                imgData.height = header.height;
                var numFaces = 1; // assume one face until we know otherwise

                if ((header.caps.caps1 & DDSCAPS_MIPMAP) != 0)
                {
                    imgData.numMipMaps = header.mipMapCount - 1;
                }
                else
                {
                    imgData.numMipMaps = 0;
                }

                imgData.flags = 0;

                var decompressDXT = false;
                // Figure out basic image type
                if ((header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0)
                {
                    imgData.flags |= ImageFlags.CubeMap;
                    numFaces       = 6;
                }
                else if ((header.caps.caps2 & DDSCAPS2_VOLUME) != 0)
                {
                    imgData.flags |= ImageFlags.Volume;
                    imgData.depth  = header.depth;
                }
                // Pixel format
                var sourceFormat = PixelFormat.Unknown;

                if ((header.pixelFormat.flags & DDPF_FOURCC) != 0)
                {
                    sourceFormat = _convertFourCCFormat(header.pixelFormat.fourCC);
                }
                else
                {
                    sourceFormat = _convertPixelFormat(header.pixelFormat.rgbBits, header.pixelFormat.redMask,
                                                       header.pixelFormat.greenMask, header.pixelFormat.blueMask,
                                                       (header.pixelFormat.flags & DDPF_ALPHAPIXELS) != 0
                                                            ? header.pixelFormat.alphaMask
                                                            : 0);
                }

                if (PixelUtil.IsCompressed(sourceFormat))
                {
                    if (!Root.Instance.RenderSystem.Capabilities.HasCapability(Capabilities.TextureCompressionDXT))
                    {
                        // We'll need to decompress
                        decompressDXT = true;
                        // Convert format
                        switch (sourceFormat)
                        {
                        case PixelFormat.DXT1:
                            // source can be either 565 or 5551 depending on whether alpha present
                            // unfortunately you have to read a block to figure out which
                            // Note that we upgrade to 32-bit pixel formats here, even
                            // though the source is 16-bit; this is because the interpolated
                            // values will benefit from the 32-bit results, and the source
                            // from which the 16-bit samples are calculated may have been
                            // 32-bit so can benefit from this.
                            var block = DXTColorBlock.Read(br);
                            using (var wrap = BufferBase.Wrap(block.colour_0, sizeof(ushort)))
                            {
                                _flipEndian(wrap, sizeof(ushort), 1);
                            }

                            using (var wrap = BufferBase.Wrap(block.colour_1, sizeof(ushort)))
                            {
                                _flipEndian(wrap, sizeof(ushort), 1);
                            }
                            // skip back since we'll need to read this again
                            br.BaseStream.Seek(0 - (long)Memory.SizeOf(typeof(DXTColorBlock)), SeekOrigin.Current);
                            // colour_0 <= colour_1 means transparency in DXT1
                            if (block.colour_0 <= block.colour_1)
                            {
                                imgData.format = PixelFormat.BYTE_RGBA;
                            }
                            else
                            {
                                imgData.format = PixelFormat.BYTE_RGB;
                            }
                            break;

                        case PixelFormat.DXT2:
                        case PixelFormat.DXT3:
                        case PixelFormat.DXT4:
                        case PixelFormat.DXT5:
                            // full alpha present, formats vary only in encoding
                            imgData.format = PixelFormat.BYTE_RGBA;
                            break;

                        default:
                            // all other cases need no special format handling
                            break;
                        }
                    }
                    else
                    {
                        // Use original format
                        imgData.format = sourceFormat;
                        // Keep DXT data compressed
                        imgData.flags |= ImageFlags.Compressed;
                    }
                }
                else // not compressed
                {
                    // Don't test against DDPF_RGB since greyscale DDS doesn't set this
                    // just derive any other kind of format
                    imgData.format = sourceFormat;
                }

                // Calculate total size from number of mipmaps, faces and size
                imgData.size = Image.CalculateSize(imgData.numMipMaps, numFaces, imgData.width, imgData.height, imgData.depth, imgData.format);

                // Now deal with the data
                var dest       = new byte[imgData.size];
                var destBuffer = BufferBase.Wrap(dest);

                // all mips for a face, then each face
                for (var i = 0; i < numFaces; ++i)
                {
                    var width  = imgData.width;
                    var height = imgData.height;
                    var depth  = imgData.depth;

                    for (var mip = 0; mip <= imgData.numMipMaps; ++mip)
                    {
                        var dstPitch = width * PixelUtil.GetNumElemBytes(imgData.format);

                        if (PixelUtil.IsCompressed(sourceFormat))
                        {
                            // Compressed data
                            if (decompressDXT)
                            {
                                DXTColorBlock             col;
                                DXTInterpolatedAlphaBlock iAlpha;
                                DXTExplicitAlphaBlock     eAlpha;
                                // 4x4 block of decompressed colour
                                var tempColours     = new ColorEx[16];
                                var destBpp         = PixelUtil.GetNumElemBytes(imgData.format);
                                var sx              = Utility.Min(width, 4);
                                var sy              = Utility.Min(height, 4);
                                var destPitchMinus4 = dstPitch - destBpp * sx;
                                // slices are done individually
                                for (var z = 0; z < depth; ++z)
                                {
                                    // 4x4 blocks in x/y
                                    for (var y = 0; y < height; y += 4)
                                    {
                                        for (var x = 0; x < width; x += 4)
                                        {
                                            if (sourceFormat == PixelFormat.DXT2 || sourceFormat == PixelFormat.DXT3)
                                            {
                                                // explicit alpha
                                                eAlpha = DXTExplicitAlphaBlock.Read(br);
                                                using (var wrap = BufferBase.Wrap(eAlpha.alphaRow, eAlpha.alphaRow.Length * sizeof(ushort)))
                                                {
                                                    _flipEndian(wrap, sizeof(ushort), 4);
                                                }
                                                _unpackDXTAlpha(eAlpha, tempColours);
                                            }
                                            else if (sourceFormat == PixelFormat.DXT4 || sourceFormat == PixelFormat.DXT5)
                                            {
                                                // interpolated alpha
                                                iAlpha = DXTInterpolatedAlphaBlock.Read(br);
                                                using (var wrap = BufferBase.Wrap(iAlpha.alpha_0, 1))
                                                {
                                                    _flipEndian(wrap, sizeof(ushort), 1);
                                                }

                                                using (var wrap = BufferBase.Wrap(iAlpha.alpha_1, 1))
                                                {
                                                    _flipEndian(wrap, sizeof(ushort), 1);
                                                }
                                                _unpackDXTAlpha(iAlpha, tempColours);
                                            }
                                            // always read colour
                                            col = DXTColorBlock.Read(br);

                                            using (var wrap = BufferBase.Wrap(col.colour_0, sizeof(ushort)))
                                            {
                                                _flipEndian(wrap, sizeof(ushort), 1);
                                            }

                                            using (var wrap = BufferBase.Wrap(col.colour_1, sizeof(ushort)))
                                            {
                                                _flipEndian(wrap, sizeof(ushort), 1);
                                            }
                                            _unpackDXTColor(sourceFormat, col, tempColours);

                                            // write 4x4 block to uncompressed version
                                            for (var by = 0; by < sy; ++by)
                                            {
                                                for (var bx = 0; bx < sx; ++bx)
                                                {
                                                    PixelConverter.PackColor(tempColours[by * 4 + bx], imgData.format, destBuffer);
                                                    destBuffer += destBpp;
                                                }
                                                // advance to next row
                                                destBuffer += destPitchMinus4;
                                            }
                                            // next block. Our dest pointer is 4 lines down
                                            // from where it started
                                            if (x + 4 >= width)
                                            {
                                                // Jump back to the start of the line
                                                destBuffer += -destPitchMinus4;
                                            }
                                            else
                                            {
                                                // Jump back up 4 rows and 4 pixels to the
                                                // right to be at the next block to the right
                                                destBuffer += -(dstPitch * sy + destBpp * sx);
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                // load directly
                                // DDS format lies! sizeOrPitch is not always set for DXT!!
                                var dxtSize = PixelUtil.GetMemorySize(width, height, depth, imgData.format);
                                using (var src = BufferBase.Wrap(br.ReadBytes(dxtSize)))
                                {
                                    Memory.Copy(src, destBuffer, dxtSize);
                                }
                                destBuffer += dxtSize;
                            }
                        }
                        else
                        {
                            // Final data - trim incoming pitch
                            int srcPitch;
                            if ((header.flags & DDSD_PITCH) != 0)
                            {
                                srcPitch = header.sizeOrPitch / Utility.Max(1, mip * 2);
                            }
                            else
                            {
                                // assume same as final pitch
                                srcPitch = dstPitch;
                            }
                            Contract.Requires(dstPitch <= srcPitch);
                            var srcAdvance = (long)(srcPitch - dstPitch);

                            for (var z = 0; z < imgData.depth; ++z)
                            {
                                for (var y = 0; y < imgData.height; ++y)
                                {
                                    using (var src = BufferBase.Wrap(br.ReadBytes(dstPitch)))
                                    {
                                        Memory.Copy(src, destBuffer, dstPitch);
                                    }

                                    if (srcAdvance > 0)
                                    {
                                        br.BaseStream.Seek(srcAdvance, SeekOrigin.Current);
                                    }

                                    destBuffer += dstPitch;
                                }
                            }
                        }

                        // Next mip
                        if (width != 1)
                        {
                            width /= 2;
                        }

                        if (height != 1)
                        {
                            height /= 2;
                        }

                        if (depth != 1)
                        {
                            depth /= 2;
                        }
                    }
                }

                destBuffer.Dispose();
                return(new DecodeResult(new MemoryStream(dest), imgData));
            }
        }
Пример #13
0
        /// <summary>
        /// </summary>
        /// <param name="src"> </param>
        /// <param name="dst"> </param>
        public void Scale(PixelBox src, PixelBox dst)
        {
            var srcelemsize = PixelUtil.GetNumElemBytes(src.Format);
            var dstelemsize = PixelUtil.GetNumElemBytes(dst.Format);

            var dstOffset = 0;

            // sx_48,sy_48,sz_48 represent current position in source
            // using 16/48-bit fixed precision, incremented by steps
            var stepx = ((UInt64)src.Width << 48) / (UInt64)dst.Width;
            var stepy = ((UInt64)src.Height << 48) / (UInt64)dst.Height;
            var stepz = ((UInt64)src.Depth << 48) / (UInt64)dst.Depth;
            // temp is 16/16 bit fixed precision, used to adjust a source
            // coordinate (x, y, or z) backwards by half a pixel so that the
            // integer bits represent the first sample (eg, sx1) and the
            // fractional bits are the blend weight of the second sample
            uint temp;
            // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
            // for the center of the destination pixel, not the top-left corner
            var sz_48 = (stepz >> 1) - 1;

            for (var z = dst.Front; z < dst.Back; z++, sz_48 += stepz)
            {
                temp = (uint)(sz_48 >> 32);
                temp = (temp > 0x8000) ? temp - 0x8000 : 0;
                var sz1 = (int)(temp >> 16);
                var sz2 = System.Math.Min(sz1 + 1, src.Depth - 1);
                var szf = (temp & 0xFFFF) / 65536f;

                var sy_48 = (stepy >> 1) - 1;
                for (var y = dst.Top; y < dst.Bottom; y++, sy_48 += stepy)
                {
                    temp = (uint)(sy_48 >> 32);
                    temp = (temp > 0x8000) ? temp - 0x8000 : 0;
                    var sy1 = (int)(temp >> 16);                        // src x #1
                    var sy2 = System.Math.Min(sy1 + 1, src.Height - 1); // src x #2
                    var syf = (temp & 0xFFFF) / 65536f;                 // weight of #2

                    var sx_48 = (stepx >> 1) - 1;
                    for (var x = dst.Left; x < dst.Right; x++, sx_48 += stepx)
                    {
                        temp = (uint)(sy_48 >> 32);
                        temp = (temp > 0x8000) ? temp - 0x8000 : 0;
                        var     sx1 = (int)(temp >> 16);                       // src x #1
                        var     sx2 = System.Math.Min(sx1 + 1, src.Width - 1); // src x #2
                        var     sxf = (temp & 0xFFFF) / 65536f;                // weight of #2
                        ColorEx x1y1z1 = ColorEx.White, x2y1z1 = ColorEx.White, x1y2z1 = ColorEx.White, x2y2z1 = ColorEx.White;
                        ColorEx x1y1z2 = ColorEx.White, x2y1z2 = ColorEx.White, x1y2z2 = ColorEx.White, x2y2z2 = ColorEx.White;
                        Unpack(ref x1y1z1, sx1, sy1, sz1, src.Format, src.Data, src, srcelemsize);
                        Unpack(ref x2y1z1, sx2, sy1, sz1, src.Format, src.Data, src, srcelemsize);
                        Unpack(ref x1y2z1, sx1, sy2, sz1, src.Format, src.Data, src, srcelemsize);
                        Unpack(ref x2y2z1, sx2, sy2, sz1, src.Format, src.Data, src, srcelemsize);
                        Unpack(ref x1y1z2, sx1, sy1, sz2, src.Format, src.Data, src, srcelemsize);
                        Unpack(ref x2y1z2, sx2, sy1, sz2, src.Format, src.Data, src, srcelemsize);
                        Unpack(ref x1y2z2, sx1, sy2, sz2, src.Format, src.Data, src, srcelemsize);
                        Unpack(ref x2y2z2, sx2, sy2, sz2, src.Format, src.Data, src, srcelemsize);

                        var accum = x1y1z1 * ((1.0f - sxf) * (1.0f - syf) * (1.0f - szf)) + x2y1z1 * (sxf * (1.0f - syf) * (1.0f - szf)) +
                                    x1y2z1 * ((1.0f - sxf) * syf * (1.0f - szf)) + x2y2z1 * (sxf * syf * (1.0f - szf)) +
                                    x1y1z2 * ((1.0f - sxf) * (1.0f - syf) * szf) + x2y1z2 * (sxf * (1.0f - syf) * szf) +
                                    x1y2z2 * ((1.0f - sxf) * syf * szf) + x2y2z2 * (sxf * syf * szf);

                        PixelConverter.PackColor(accum, dst.Format, dst.Data + dstOffset);
                        dstOffset += dstelemsize;
                    }
                    dstOffset += dstelemsize * dst.RowSkip;
                }
                dstOffset += dstelemsize * dst.SliceSkip;
            }
        }
Пример #14
0
        //-----------------------------------------------------------------------
        public static void ToAxiom(PixelBox dst)
        {
            if (!dst.Consecutive)
            {
                throw new NotImplementedException("Destination must currently be consecutive");
            }
            if (dst.Width != Il.ilGetInteger(Il.IL_IMAGE_WIDTH) ||
                dst.Height != Il.ilGetInteger(Il.IL_IMAGE_HEIGHT) ||
                dst.Depth != Il.ilGetInteger(Il.IL_IMAGE_DEPTH))
            {
                throw new AxiomException("Destination dimensions must equal IL dimension");
            }

            int ilfmt = Il.ilGetInteger(Il.IL_IMAGE_FORMAT);
            int iltp  = Il.ilGetInteger(Il.IL_IMAGE_TYPE);

            // Check if in-memory format just matches
            // If yes, we can just copy it and save conversion
            ILFormat ifmt = ILUtil.ConvertToILFormat(dst.Format);

            if (ifmt.format == ilfmt && ILabs(ifmt.type) == ILabs(iltp))
            {
                int size = Il.ilGetInteger(Il.IL_IMAGE_SIZE_OF_DATA);
                // Copy from the IL structure to our buffer
                PixelUtil.CopyBytes(dst.Data, dst.Offset, Il.ilGetData(), 0, size);
                return;
            }
            // Try if buffer is in a known OGRE format so we can use OGRE its
            // conversion routines
            PixelFormat bufFmt = ILUtil.ConvertFromILFormat(ilfmt, iltp);

            ifmt = ILUtil.ConvertToILFormat(bufFmt);

            if (ifmt.format == ilfmt && ILabs(ifmt.type) == ILabs(iltp))
            {
                // IL format matches another OGRE format
                PixelBox src = new PixelBox(dst.Width, dst.Height, dst.Depth, bufFmt, Il.ilGetData());
                PixelUtil.BulkPixelConversion(src, dst);
                return;
            }

#if NOT
            // The extremely slow method
            if (iltp == Il.IL_UNSIGNED_BYTE || iltp == Il.IL_BYTE)
            {
                ilToOgreInternal(static_cast <uint8 *>(dst.data), dst.format, (uint8)0x00, (uint8)0x00, (uint8)0x00, (uint8)0xFF);
            }
            else if (iltp == IL_FLOAT)
            {
                ilToOgreInternal(static_cast <uint8 *>(dst.data), dst.format, 0.0f, 0.0f, 0.0f, 1.0f);
            }
            else if (iltp == IL_SHORT || iltp == IL_UNSIGNED_SHORT)
            {
                ilToOgreInternal(static_cast <uint8 *>(dst.data), dst.format,
                                 (uint16)0x0000, (uint16)0x0000, (uint16)0x0000, (uint16)0xFFFF);
            }
            else
            {
                OGRE_EXCEPT(Exception::UNIMPLEMENTED_FEATURE,
                            "Cannot convert this DevIL type",
                            "ILUtil::ilToOgre");
            }
#else
            throw new NotImplementedException("Cannot convert this DevIL type");
#endif
        }
Пример #15
0
 /// <summary>
 /// </summary>
 /// <param name="src"> </param>
 /// <param name="temp"> </param>
 public static void Scale(PixelBox src, PixelBox temp)
 {
     Scale(src, temp, PixelUtil.GetNumElemBytes(src.Format));
 }
        public override object Decode(Stream input, Stream output, params object[] args)
        {
            ImageData data = new ImageData();

            int imageID;
            int format, bytesPerPixel, imageType;

            // create and bind a new image
            Il.ilGenImages(1, out imageID);
            Il.ilBindImage(imageID);

            // Put it right side up
            Il.ilEnable(Il.IL_ORIGIN_SET);
            Il.ilSetInteger(Il.IL_ORIGIN_MODE, Il.IL_ORIGIN_UPPER_LEFT);

            // Keep DXTC(compressed) data if present
            Il.ilSetInteger(Il.IL_KEEP_DXTC_DATA, Il.IL_TRUE);

            // create a temp buffer and write the stream into it
            byte[] buffer = new byte[input.Length];
            input.Read(buffer, 0, buffer.Length);

            // load the data into DevIL
            Il.ilLoadL(this.ILType, buffer, buffer.Length);

            // check for an error
            int ilError = Il.ilGetError();

            if (ilError != Il.IL_NO_ERROR)
            {
                throw new AxiomException("Error while decoding image data: '{0}'", Ilu.iluErrorString(ilError));
            }

            format    = Il.ilGetInteger(Il.IL_IMAGE_FORMAT);
            imageType = Il.ilGetInteger(Il.IL_IMAGE_TYPE);
            //bytesPerPixel = Math.Max(Il.ilGetInteger(Il.IL_IMAGE_BPC),
            //                         Il.ilGetInteger(Il.IL_IMAGE_BYTES_PER_PIXEL));

            // Convert image if ImageType is incompatible with us (double or long)
            if (imageType != Il.IL_BYTE && imageType != Il.IL_UNSIGNED_BYTE &&
                imageType != Il.IL_FLOAT &&
                imageType != Il.IL_UNSIGNED_SHORT && imageType != Il.IL_SHORT)
            {
                Il.ilConvertImage(format, Il.IL_FLOAT);
                imageType = Il.IL_FLOAT;
            }
            // Converted paletted images
            if (format == Il.IL_COLOUR_INDEX)
            {
                Il.ilConvertImage(Il.IL_BGRA, Il.IL_UNSIGNED_BYTE);
                format    = Il.IL_BGRA;
                imageType = Il.IL_UNSIGNED_BYTE;
            }

            bytesPerPixel = Il.ilGetInteger(Il.IL_IMAGE_BYTES_PER_PIXEL);

            // populate the image data
            data.format     = ILUtil.ConvertFromILFormat(format, imageType);
            data.width      = Il.ilGetInteger(Il.IL_IMAGE_WIDTH);
            data.height     = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT);
            data.depth      = Il.ilGetInteger(Il.IL_IMAGE_DEPTH);
            data.numMipMaps = Il.ilGetInteger(Il.IL_NUM_MIPMAPS);
            data.flags      = 0;

            if (data.format == PixelFormat.Unknown)
            {
                Il.ilDeleteImages(1, ref imageID);
                throw new AxiomException("Unsupported DevIL format: ImageFormat = {0:x} ImageType = {1:x}", format, imageType);
            }

            // Check for cubemap
            // int cubeflags = Il.ilGetInteger(Il.IL_IMAGE_CUBEFLAGS);
            int numFaces = Il.ilGetInteger(Il.IL_NUM_IMAGES) + 1;

            if (numFaces == 6)
            {
                data.flags |= ImageFlags.CubeMap;
            }
            else
            {
                numFaces = 1; // Support only 1 or 6 face images for now
            }
            // Keep DXT data (if present at all and the GPU supports it)
            int dxtFormat = Il.ilGetInteger(Il.IL_DXTC_DATA_FORMAT);

            if (dxtFormat != Il.IL_DXT_NO_COMP &&
                Root.Instance.RenderSystem.Caps.CheckCap(Axiom.Graphics.Capabilities.TextureCompressionDXT))
            {
                data.format = ILUtil.ConvertFromILFormat(dxtFormat, imageType);
                data.flags |= ImageFlags.Compressed;

                // Validate that this devil version saves DXT mipmaps
                if (data.numMipMaps > 0)
                {
                    Il.ilBindImage(imageID);
                    Il.ilActiveMipmap(1);
                    if (Il.ilGetInteger(Il.IL_DXTC_DATA_FORMAT) != dxtFormat)
                    {
                        data.numMipMaps = 0;
                        LogManager.Instance.Write("Warning: Custom mipmaps for compressed image were ignored because they are not loaded by this DevIL version");
                    }
                }
            }

            // Calculate total size from number of mipmaps, faces and size
            data.size = Image.CalculateSize(data.numMipMaps, numFaces,
                                            data.width, data.height,
                                            data.depth, data.format);

            // set up buffer for the decoded data
            buffer = new byte[data.size];
            // Pin the buffer, so we can use our PixelBox methods on it
            GCHandle bufGCHandle = new GCHandle();

            bufGCHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            IntPtr bufPtr = bufGCHandle.AddrOfPinnedObject();

            int offset = 0;

            // Dimensions of current mipmap
            int width  = data.width;
            int height = data.height;
            int depth  = data.depth;

            // Transfer data
            for (int mip = 0; mip <= data.numMipMaps; ++mip)
            {
                for (int i = 0; i < numFaces; ++i)
                {
                    Il.ilBindImage(imageID);
                    if (numFaces > 1)
                    {
                        Il.ilActiveImage(i);
                    }
                    if (data.numMipMaps > 0)
                    {
                        Il.ilActiveMipmap(mip);
                    }
                    /// Size of this face
                    int imageSize = PixelUtil.GetMemorySize(width, height, depth, data.format);
                    if ((data.flags & ImageFlags.Compressed) != 0)
                    {
                        // Compare DXT size returned by DevIL with our idea of the compressed size
                        if (imageSize == Il.ilGetDXTCData(IntPtr.Zero, 0, dxtFormat))
                        {
                            // Retrieve data from DevIL
                            byte[] tmpBuffer = new byte[imageSize];
                            Il.ilGetDXTCData(tmpBuffer, imageSize, dxtFormat);
                            // Copy the data into our output buffer
                            Array.Copy(tmpBuffer, 0, buffer, offset, tmpBuffer.Length);
                        }
                        else
                        {
                            LogManager.Instance.Write("Warning: compressed image size mismatch, devilsize={0} oursize={1}",
                                                      Il.ilGetDXTCData(IntPtr.Zero, 0, dxtFormat), imageSize);
                        }
                    }
                    else
                    {
                        /// Retrieve data from DevIL
                        PixelBox dst = new PixelBox(width, height, depth, data.format, bufPtr);
                        dst.Offset = offset;
                        ILUtil.ToAxiom(dst);
                    }
                    offset += imageSize;
                }

                /// Next mip
                if (width != 1)
                {
                    width /= 2;
                }
                if (height != 1)
                {
                    height /= 2;
                }
                if (depth != 1)
                {
                    depth /= 2;
                }
            }

            // Restore IL state
            Il.ilDisable(Il.IL_ORIGIN_SET);
            Il.ilDisable(Il.IL_FORMAT_SET);

            // we won't be needing this anymore
            Il.ilDeleteImages(1, ref imageID);

            output.Write(buffer, 0, buffer.Length);


            // Free the buffer we allocated for the conversion.
            // I used bufPtr to store my data while I converted it.
            // I need to free it here.  This invalidates bufPtr.
            // My data has already been copied to output.
            if (bufGCHandle.IsAllocated)
            {
                bufGCHandle.Free();
            }

            return(data);
        }