Esempio n. 1
0
        private void _unpackDXTColor(PixelFormat pf, DXTColorBlock block, ColorEx[] pCol)
        {
            // Note - we assume all values have already been endian swapped

            // Colour lookup table
            var derivedColours = new ColorEx[4];

            using (var src = BufferBase.Wrap(block.colour_0, 1))
            {
                derivedColours[0] = PixelConverter.UnpackColor(PixelFormat.R5G6B5, src);
            }

            using (var src = BufferBase.Wrap(block.colour_1, 1))
            {
                derivedColours[1] = PixelConverter.UnpackColor(PixelFormat.R5G6B5, src);
            }

            if (pf == PixelFormat.DXT1 && block.colour_0 <= block.colour_1)
            {
                // 1-bit alpha

                // one intermediate colour, half way between the other two
                derivedColours[2] = (derivedColours[0] + derivedColours[1]) / 2;
                // transparent colour
                derivedColours[3] = new ColorEx(0, 0, 0, 0);
            }
            else
            {
                // first interpolated colour, 1/3 of the way along
                derivedColours[2] = (derivedColours[0] * 2 + derivedColours[1]) / 3;
                // second interpolated colour, 2/3 of the way along
                derivedColours[3] = (derivedColours[0] + derivedColours[1] * 2) / 3;
            }

            // Process 4x4 block of texels
            for (var row = 0; row < 4; ++row)
            {
                for (var x = 0; x < 4; ++x)
                {
                    // LSB come first
                    var colIdx = (byte)block.indexRow[row] >> (x * 2) & 0x3;
                    if (pf == PixelFormat.DXT1)
                    {
                        // Overwrite entire colour
                        pCol[(row * 4) + x] = derivedColours[colIdx];
                    }
                    else
                    {
                        // alpha has already been read (alpha precedes colour)
                        var col = pCol[(row * 4) + x];
                        col.r = derivedColours[colIdx].r;
                        col.g = derivedColours[colIdx].g;
                        col.b = derivedColours[colIdx].b;
                    }
                }
            }
        }
Esempio n. 2
0
            public byte[] indexRow; // length = 4

            internal static DXTColorBlock Read(BinaryReader br)
            {
                var cBlock = new DXTColorBlock();

                cBlock.colour_0 = br.ReadUInt16();
                cBlock.colour_1 = br.ReadUInt16();

                cBlock.indexRow = br.ReadBytes(4);

                return(cBlock);
            }
Esempio n. 3
0
		private void _unpackDXTColor( PixelFormat pf, DXTColorBlock block, ColorEx[] pCol )
		{
			// Note - we assume all values have already been endian swapped

			// Colour lookup table
			var derivedColours = new ColorEx[4];

			using ( var src = BufferBase.Wrap( block.colour_0, 1 ) )
			{
				derivedColours[ 0 ] = PixelConverter.UnpackColor( PixelFormat.R5G6B5, src );
			}

			using ( var src = BufferBase.Wrap( block.colour_1, 1 ) )
			{
				derivedColours[ 1 ] = PixelConverter.UnpackColor( PixelFormat.R5G6B5, src );
			}

			if ( pf == PixelFormat.DXT1 && block.colour_0 <= block.colour_1 )
			{
				// 1-bit alpha

				// one intermediate colour, half way between the other two
				derivedColours[ 2 ] = ( derivedColours[ 0 ] + derivedColours[ 1 ] )/2;
				// transparent colour
				derivedColours[ 3 ] = new ColorEx( 0, 0, 0, 0 );
			}
			else
			{
				// first interpolated colour, 1/3 of the way along
				derivedColours[ 2 ] = ( derivedColours[ 0 ]*2 + derivedColours[ 1 ] )/3;
				// second interpolated colour, 2/3 of the way along
				derivedColours[ 3 ] = ( derivedColours[ 0 ] + derivedColours[ 1 ]*2 )/3;
			}

			// Process 4x4 block of texels
			for ( var row = 0; row < 4; ++row )
			{
				for ( var x = 0; x < 4; ++x )
				{
					// LSB come first
					var colIdx = (byte)block.indexRow[ row ] >> ( x*2 ) & 0x3;
					if ( pf == PixelFormat.DXT1 )
					{
						// Overwrite entire colour
						pCol[ ( row*4 ) + x ] = derivedColours[ colIdx ];
					}
					else
					{
						// alpha has already been read (alpha precedes colour)
						var col = pCol[ ( row*4 ) + x ];
						col.r = derivedColours[ colIdx ].r;
						col.g = derivedColours[ colIdx ].g;
						col.b = derivedColours[ colIdx ].b;
					}
				}
			}
		}
Esempio n. 4
0
			public byte[] indexRow; // length = 4

			internal static DXTColorBlock Read( BinaryReader br )
			{
				var cBlock = new DXTColorBlock();

				cBlock.colour_0 = br.ReadUInt16();
				cBlock.colour_1 = br.ReadUInt16();

				cBlock.indexRow = br.ReadBytes( 4 );

				return cBlock;
			}
Esempio n. 5
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));
            }
        }
Esempio n. 6
0
    	/// Unpack DXT colours into array of 16 colour values
		private void UnpackDXTColour(PixelFormat pf, DXTColorBlock block, ColorEx[] pCol)
    	{
    		// Note - we assume all values have already been endian swapped

    		// Colour lookup table
    		ColorEx[] derivedColours = new ColorEx[4];

    		IntPtr color0 = Memory.PinObject( block.Color0 );
    		IntPtr color1 = Memory.PinObject( block.Color1 );
    		if ( pf == PixelFormat.DXT1 && block.Color0 <= block.Color1 )
    		{
    			// 1-bit alpha
    			derivedColours[ 0 ] = PixelConverter.UnpackColor( PixelFormat.R5G6B5, color0 );
    			derivedColours[ 1 ] = PixelConverter.UnpackColor( PixelFormat.R5G6B5, color1 );
    			// one intermediate colour, half way between the other two
    			derivedColours[ 2 ] = ( derivedColours[ 0 ] + derivedColours[ 1 ] ) / 2;
    			// transparent colour
    			derivedColours[ 3 ] = ColorEx.Black;
    		}
    		else
    		{
    			derivedColours[ 0 ] = PixelConverter.UnpackColor( PixelFormat.R5G6B5, color0 );
    			derivedColours[ 1 ] = PixelConverter.UnpackColor( PixelFormat.R5G6B5, color1 );
    			// first interpolated colour, 1/3 of the way along
    			derivedColours[ 2 ] = ( derivedColours[ 0 ] * 2f + derivedColours[ 1 ] ) / 3;
    			// second interpolated colour, 2/3 of the way along
    			derivedColours[ 3 ] = ( derivedColours[ 0 ] + derivedColours[ 1 ] * 2f ) / 3;
    		}
    		Memory.UnpinObject( block.Color0 );
    		Memory.UnpinObject( block.Color1 );

    		// Process 4x4 block of texels
    		for ( int row = 0; row < 4; ++row )
    		{
    			for ( int x = 0; x < 4; ++x )
    			{
    				// LSB come first
    				int colIdx = ( block.IndexRow[ row ] >> ( x * 2 ) & 0x3 );
    				if ( pf == PixelFormat.DXT1 )
    				{
    					// Overwrite entire colour
    					pCol[ ( row * 4 ) + x ] = derivedColours[ colIdx ];
    				}
    				else
    				{
    					// alpha has already been read (alpha precedes color)
    					ColorEx col = pCol[ ( row * 4 ) + x ];
    					col.r = derivedColours[ colIdx ].r;
    					col.g = derivedColours[ colIdx ].g;
    					col.b = derivedColours[ colIdx ].b;
    				}
    			}

    		}
    	}