示例#1
0
文件: DDSCodec.cs 项目: axiom3d/axiom
            public byte[] indexes; // length = 6

            internal static DXTInterpolatedAlphaBlock Read(BinaryReader br)
            {
                var block = new DXTInterpolatedAlphaBlock();

                block.alpha_0 = br.ReadByte();
                block.alpha_1 = br.ReadByte();
                block.indexes = br.ReadBytes(6);

                return(block);
            }
示例#2
0
文件: DDSCodec.cs 项目: axiom3d/axiom
        private void _unpackDXTAlpha(DXTInterpolatedAlphaBlock block, ColorEx[] pCol)
        {
            // 8 derived alpha values to be indexed
            var derivedAlphas = new Real[8];

            // Explicit extremes
            derivedAlphas[0] = block.alpha_0 / (Real)0xFF;
            derivedAlphas[1] = block.alpha_1 / (Real)0xFF;

            if (block.alpha_0 <= block.alpha_1)
            {
                // 4 interpolated alphas, plus zero and one
                // full range including extremes at [0] and [5]
                // we want to fill in [1] through [4] at weights ranging
                // from 1/5 to 4/5
                Real denom = 1.0f / 5.0f;
                for (var i = 0; i < 4; ++i)
                {
                    var factor0 = (4 - i) * denom;
                    var factor1 = (i + 1) * denom;
                    derivedAlphas[i + 2] = (factor0 * block.alpha_0) + (factor1 * block.alpha_1);
                }
                derivedAlphas[6] = 0.0f;
                derivedAlphas[7] = 1.0f;
            }
            else
            {
                // 6 interpolated alphas
                // full range including extremes at [0] and [7]
                // we want to fill in [1] through [6] at weights ranging
                // from 1/7 to 6/7
                Real denom = 1.0f / 7.0f;
                for (var i = 0; i < 6; ++i)
                {
                    var factor0 = (6 - i) * denom;
                    var factor1 = (i + 1) * denom;
                    derivedAlphas[i + 2] = (factor0 * block.alpha_0) + (factor1 * block.alpha_1);
                }
            }

            // Ok, now we've built the reference values, process the indexes
            for (var i = 0; i < 16; ++i)
            {
                var baseByte = (i * 3) / 8;
                var baseBit  = (i * 3) % 8;
                var bits     = (byte)block.indexes[baseByte] >> baseBit & 0x7;
                // do we need to stitch in next byte too?
                if (baseBit > 5)
                {
                    var extraBits = (byte)((block.indexes[baseByte + 1] << (8 - baseBit)) & 0xFF);
                    bits |= extraBits & 0x7;
                }
                pCol[i].a = derivedAlphas[bits];
            }
        }
示例#3
0
		private void _unpackDXTAlpha( DXTInterpolatedAlphaBlock block, ColorEx[] pCol )
		{
			// 8 derived alpha values to be indexed
			var derivedAlphas = new Real[8];

			// Explicit extremes
			derivedAlphas[ 0 ] = block.alpha_0/(Real)0xFF;
			derivedAlphas[ 1 ] = block.alpha_1/(Real)0xFF;

			if ( block.alpha_0 <= block.alpha_1 )
			{
				// 4 interpolated alphas, plus zero and one			
				// full range including extremes at [0] and [5]
				// we want to fill in [1] through [4] at weights ranging
				// from 1/5 to 4/5
				Real denom = 1.0f/5.0f;
				for ( var i = 0; i < 4; ++i )
				{
					var factor0 = ( 4 - i )*denom;
					var factor1 = ( i + 1 )*denom;
					derivedAlphas[ i + 2 ] = ( factor0*block.alpha_0 ) + ( factor1*block.alpha_1 );
				}
				derivedAlphas[ 6 ] = 0.0f;
				derivedAlphas[ 7 ] = 1.0f;
			}
			else
			{
				// 6 interpolated alphas
				// full range including extremes at [0] and [7]
				// we want to fill in [1] through [6] at weights ranging
				// from 1/7 to 6/7
				Real denom = 1.0f/7.0f;
				for ( var i = 0; i < 6; ++i )
				{
					var factor0 = ( 6 - i )*denom;
					var factor1 = ( i + 1 )*denom;
					derivedAlphas[ i + 2 ] = ( factor0*block.alpha_0 ) + ( factor1*block.alpha_1 );
				}
			}

			// Ok, now we've built the reference values, process the indexes
			for ( var i = 0; i < 16; ++i )
			{
				var baseByte = ( i*3 )/8;
				var baseBit = ( i*3 )%8;
				var bits = (byte)block.indexes[ baseByte ] >> baseBit & 0x7;
				// do we need to stitch in next byte too?
				if ( baseBit > 5 )
				{
					var extraBits = (byte)( ( block.indexes[ baseByte + 1 ] << ( 8 - baseBit ) ) & 0xFF );
					bits |= extraBits & 0x7;
				}
				pCol[ i ].a = derivedAlphas[ bits ];
			}
		}
示例#4
0
			public byte[] indexes; // length = 6

			internal static DXTInterpolatedAlphaBlock Read( BinaryReader br )
			{
				var block = new DXTInterpolatedAlphaBlock();

				block.alpha_0 = br.ReadByte();
				block.alpha_1 = br.ReadByte();
				block.indexes = br.ReadBytes( 6 );

				return block;
			}
示例#5
0
文件: DDSCodec.cs 项目: axiom3d/axiom
        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));
            }
        }