예제 #1
0
        public static rTexture FromDDSImage(DDSImage image, string fileName, DatumIndex datum, ResourceType fileType, bool isBigEndian)
        {
            // Create a new texture we can populate with info.
            rTexture texture = new rTexture(fileName, datum, fileType, isBigEndian);

            // Fill out the header fields.
            texture.header.Magic       = rTextureHeader.kMagic;
            texture.header.Version     = rTextureHeader.kVersion;
            texture.header.Width       = image.Width;
            texture.header.Height      = image.Height;
            texture.header.MipMapCount = (byte)image.MipMapCount;
            texture.header.Depth       = image.Depth;

            // Check various flags to determine what type of texture this is.
            if (image.Flags.HasFlag(DDSD_FLAGS.DDSD_DEPTH) == true)
            {
                // Set the depthmap texture type.
                texture.header.TextureType = TextureType.Type_DepthMap;

                // Copy the DDS header from the image.
                texture.depthMapHeader = image.header;
            }
            else if (image.Capabilities2.HasFlag(DDSCAPS2.DDSCAPS2_CUBEMAP_ALLFACES) == true)
            {
                texture.header.TextureType = TextureType.Type_CubeMap;
            }
            else
            {
                texture.header.TextureType = TextureType.Type_2D;
            }

            // Check the image's fourcc code to determine the texture format.
            if (image.Format == 0)
            {
                // Check the bit count and color masks to determine the texture format.
                if (image.header.ddspf.dwFlags.HasFlag(DDPF.DDPF_BUMPDUDV) == true || (image.BitCount == 16 && image.RBitMask == 0xFF && image.GBitMask == 0xFF00))
                {
                    texture.header.Format = TextureFormat.Format_R8G8_SNORM;
                }
                else if (image.BitCount == 32)
                {
                    texture.header.Format = TextureFormat.Format_B8G8R8A8_UNORM;
                }

                // TODO: Do we need to re-encode?
            }
            else
            {
                // Use the fourcc code to determine the texture format.
                texture.header.Format = DDSImage.TextureFormatFromFourCC(image.Format);
            }

            // Set the number of faces this texture has based on the texture type.
            if (texture.header.TextureType == TextureType.Type_CubeMap)
            {
                // Cubemap has 6 faces each with n mip map levels.
                texture.FaceCount = 6;
            }
            else
            {
                // All other texture types have 1 face with n mip maps.
                texture.FaceCount = 1;
            }

            // Calculate the total size of the pixel buffer.
            int pixelBufferSize = CalculatePixelBufferSize(texture.header.Width, texture.header.Height, texture.FaceCount,
                                                           texture.header.MipMapCount, texture.header.Format, texture.header.TextureType);

            // Check if we need to pad the pixel buffer from the DDS image.
            byte[] pixelBuffer = image.PixelBuffer;
            if (pixelBufferSize > image.PixelBuffer.Length)
            {
                // Allocate a new array that is the correct size.
                pixelBuffer = new byte[pixelBufferSize];

                // Copy in the pixel buffer from the DDS image and pad the remaining bytes.
                Array.Copy(image.PixelBuffer, pixelBuffer, image.PixelBuffer.Length);
                for (int i = image.PixelBuffer.Length; i < pixelBufferSize; i++)
                {
                    pixelBuffer[i] = 0xCD;
                }
            }

            // Create the datastream using the pixel buffer we prepared.
            texture.PixelDataStream = DataStream.Create(pixelBuffer, true, false);

            // Make sure we are at the start of the pixel data stream.
            texture.PixelDataStream.Seek(0, SeekOrigin.Begin);

            // Allocate the sub resources array and setup for every face the texture has.
            texture.SubResources = new DataBox[texture.FaceCount * texture.header.MipMapCount];
            for (int i = 0; i < texture.FaceCount; i++)
            {
                // Loop for the number of mip maps and read each one.
                for (int x = 0; x < texture.header.MipMapCount; x++)
                {
                    int bytesPerRow    = 0;
                    int numberOfBlocks = 0;

                    // Calculate the pitch values for the current mip level.
                    int mipHeight = texture.header.TextureType == TextureType.Type_CubeMap ? texture.header.Width : texture.header.Height;
                    CalculateMipMapPitch(texture.header.Width, mipHeight, x, texture.header.Format, out bytesPerRow, out numberOfBlocks);

                    // Setup the resource description for this mip map.
                    texture.SubResources[(i * texture.header.MipMapCount) + x] = new DataBox(texture.PixelDataStream.PositionPointer, bytesPerRow, bytesPerRow * numberOfBlocks);
                    texture.PixelDataStream.Seek(bytesPerRow * numberOfBlocks, SeekOrigin.Current);
                }
            }

            // Return the texture.
            return(texture);
        }
예제 #2
0
        public static DDSImage FromGameTexture(rTexture texture)
        {
            // Create a new DDSImage to populate with info.
            DDSImage image = new DDSImage();

            image.header          = new DDS_HEADER();
            image.header.dwMagic  = DDS_HEADER.kMagic;
            image.header.dwSize   = DDS_HEADER.kSizeOf;
            image.header.dwFlags  = DDSD_FLAGS.DDSD_CAPS | DDSD_FLAGS.DDSD_HEIGHT | DDSD_FLAGS.DDSD_WIDTH | DDSD_FLAGS.DDSD_PIXELFORMAT;// | DDSD_FLAGS.DDSD_MIPMAPCOUNT;
            image.header.dwHeight = texture.Height;
            image.header.dwWidth  = texture.Width;
            rTexture.CalculateMipMapPitch(texture.Width, texture.Height, 0, texture.Format, out image.header.dwPitchOrLinearSize, out int blocks);
            image.header.dwDepth        = texture.Depth;
            image.header.dwMipMapCount  = texture.MipMapCount;
            image.header.ddspf          = new DDS_PIXELFORMAT();
            image.header.ddspf.dwSize   = DDS_PIXELFORMAT.kSizeOf;
            image.header.ddspf.dwFourCC = FourCCFromTextureFormat(texture.Format);
            image.header.dwCaps         = DDSCAPS.DDSCAPS_TEXTURE;

            // If there are more than 1 mip maps or this is a cube map set the mip map flags.
            if (texture.MipMapCount > 0 || texture.Type == TextureType.Type_CubeMap)
            {
                // Set additioanl mip map flags.
                image.header.dwFlags |= DDSD_FLAGS.DDSD_MIPMAPCOUNT;
                image.header.dwCaps  |= DDSCAPS.DDSCAPS_MIPMAP | DDSCAPS.DDSCAPS_COMPLEX;

                // Cubemap only flags.
                if (texture.Type == TextureType.Type_CubeMap)
                {
                    image.header.dwCaps2 |= DDSCAPS2.DDSCAPS2_CUBEMAP_ALLFACES;
                }
            }

            // Set additional fields depending on if the texture is a compressed format or not.
            if (texture.Format == TextureFormat.Format_DXT1 || texture.Format == TextureFormat.Format_DXT2 || texture.Format == TextureFormat.Format_DXT5)
            {
                // Pitch field is linear size (pitch of 1 compressed block).
                image.header.dwFlags |= DDSD_FLAGS.DDSD_LINEARSIZE;

                // Set the fourcc format.
                image.header.ddspf.dwFlags |= DDPF.DDPF_FOURCC;
            }
            else
            {
                // Set RGBA bit masks based on the texture format.
                switch (texture.Format)
                {
                case TextureFormat.Format_B8G8R8A8_UNORM:
                {
                    image.header.ddspf.dwFlags      |= DDPF.DDPF_RGB;
                    image.header.ddspf.dwRGBBitCount = 32;
                    image.header.ddspf.dwRBitMask    = 0xFF0000;
                    image.header.ddspf.dwGBitMask    = 0xFF00;
                    image.header.ddspf.dwBBitMask    = 0xFF;
                    image.header.ddspf.dwABitMask    = 0xFF000000;
                    break;
                }

                case TextureFormat.Format_R8G8_SNORM:
                {
                    image.header.ddspf.dwFlags      |= DDPF.DDPF_BUMPDUDV;
                    image.header.ddspf.dwRGBBitCount = 16;
                    image.header.ddspf.dwRBitMask    = 0xFF;
                    image.header.ddspf.dwGBitMask    = 0xFF00;
                    break;
                }

                default:
                {
                    break;
                }
                }

                //// Setup DX10 header with the correct format value.
                //image.dxt10header = new DDS_HEADER_DXT10();
                //image.dxt10header.dxgiFormat = rTexture.DXGIFromTextureFormat(texture.Format);

                //// Set the resource dimensions based on the texture type.
                //if (texture.Type == TextureType.Type_2D || texture.Type == TextureType.Type_CubeMap)
                //    image.dxt10header.resourceDimension = ResourceDimension.Texture2D;
                //else if (texture.Type == TextureType.Type_DepthMap)
                //    image.dxt10header.resourceDimension = ResourceDimension.Texture3D;

                //// Set special cube map flags.
                //if (texture.Type == TextureType.Type_CubeMap)
                //    image.dxt10header.miscFlag = ResourceMiscFlags.DDS_RESOURCE_MISC_TEXTURECUBE;

                //// TODO: miscFlags2
            }

            // If the texture is a depth map add the depth flag.
            if (texture.Type == TextureType.Type_DepthMap)
            {
                image.header.dwFlags |= DDSD_FLAGS.DDSD_DEPTH;
            }

            // Allocate the pixel buffer.
            image.PixelBuffer = new byte[(int)texture.PixelDataStream.Length];

            // Copy the pixel buffer from the texture.
            texture.PixelDataStream.Seek(0, System.IO.SeekOrigin.Begin);
            texture.PixelDataStream.Read(image.PixelBuffer, 0, image.PixelBuffer.Length);

            //// Check if we need to convert the pixel buffer for none DXT formats.
            //switch (texture.Format)
            //{
            //    case TextureFormat.Format_R8G8_SNORM:
            //        {
            //            image.PixelBuffer = DXTDecoder.DecodeR8G8(image.Width, image.Height, image.PixelBuffer, texture.IsBigEndian);
            //            break;
            //        }
            //    default: break;
            //}

            // Return the DDS image.
            return(image);
        }
예제 #3
0
        public static rTexture FromGameResource(byte[] buffer, string fileName, DatumIndex datum, ResourceType fileType, bool isBigEndian)
        {
            // Make sure the buffer is large enough to contain the texture header.
            if (buffer.Length < rTextureHeader.kSizeOf)
            {
                return(null);
            }

            // Create a new texture object to populate with data.
            rTexture texture = new rTexture(fileName, datum, fileType, isBigEndian);

            // Create a new memory stream and binary reader for the buffer.
            MemoryStream ms     = new MemoryStream(buffer);
            EndianReader reader = new EndianReader(isBigEndian == true ? Endianness.Big : Endianness.Little, ms);

            // Parse the header.
            texture.header             = new rTextureHeader();
            texture.header.Magic       = reader.ReadInt32();
            texture.header.Version     = reader.ReadByte();
            texture.header.TextureType = (TextureType)reader.ReadByte();
            texture.header.Flags       = (TextureFlags)reader.ReadByte();
            texture.header.MipMapCount = reader.ReadByte();
            texture.header.Width       = reader.ReadInt32();
            texture.header.Height      = reader.ReadInt32();
            texture.header.Depth       = reader.ReadInt32();
            int fourcc = reader.ReadInt32();

            texture.header.Format = TextureFormatFromFourCC(fourcc);
            texture.Swizzled      = IsXboxFormat(fourcc);
            texture.XboxFormat    = IsXboxFormat(fourcc);

            // Verify the magic is correct.
            if (texture.header.Magic != rTextureHeader.kMagic)
            {
                // Header has invalid magic.
                return(null);
            }

            // Check the version is supported.
            if (texture.header.Version != rTextureHeader.kVersion)
            {
                // Texture is an unsupported version.
                return(null);
            }

            // Make sure the texture format is supported.
            if (texture.header.Format == TextureFormat.Format_Unsupported)
            {
                // Texture is unsupported format.
                return(null);
            }

            // Check if we need to read the background color.
            if (texture.header.Flags.HasFlag(TextureFlags.HasD3DClearColor) == true)
            {
                // Read the RGBA background color.
                texture.BackgroundColor[0] = reader.ReadSingle();
                texture.BackgroundColor[1] = reader.ReadSingle();
                texture.BackgroundColor[2] = reader.ReadSingle();
                texture.BackgroundColor[3] = reader.ReadSingle();
            }

            // Check for some unknown blob.
            if (texture.header.TextureType == TextureType.Type_CubeMap)
            {
                // Read 108 bytes.
                // These could be vertex coordinates for 9 vertices that make up the box the cubemap gets rendered on?
                texture.cubemapData = reader.ReadBytes(108);
            }

            // TODO: Properly handle tiling on xbox 360 textures.
            //if (texture.Swizzled == true)
            //{
            //    //pixelData = Swizzle.ConvertToLinearTexture(pixelData, texture.header.Width, texture.header.Height, texture.header.Format);

            //    int rowPitch = ((texture.header.Width + 3) / 4);// * RowPitchFromTextureFormat(texture.header.Format);
            //    pixelData = Swizzle.XGUntileTextureLevel((uint)texture.header.Width, (uint)texture.header.Height, 0, texture.header.Format,
            //        Swizzle.XGTILE.XGTILE_BORDER, (uint)rowPitch, null, pixelData, null);
            //}

            // If the texture type is a raw DDS file read the DDS header now.
            if (texture.header.TextureType == TextureType.Type_DepthMap)
            {
                // Read the DDS image header.
                texture.depthMapHeader                     = new DDS_HEADER();
                texture.depthMapHeader.dwMagic             = reader.ReadInt32();
                texture.depthMapHeader.dwSize              = reader.ReadInt32();
                texture.depthMapHeader.dwFlags             = (DDSD_FLAGS)reader.ReadInt32();
                texture.depthMapHeader.dwHeight            = reader.ReadInt32();
                texture.depthMapHeader.dwWidth             = reader.ReadInt32();
                texture.depthMapHeader.dwPitchOrLinearSize = reader.ReadInt32();
                texture.depthMapHeader.dwDepth             = reader.ReadInt32();
                texture.depthMapHeader.dwMipMapCount       = reader.ReadInt32();
                reader.BaseStream.Position                += sizeof(int) * 11;
                texture.depthMapHeader.ddspf               = new DDS_PIXELFORMAT();
                texture.depthMapHeader.ddspf.dwSize        = reader.ReadInt32();
                texture.depthMapHeader.ddspf.dwFlags       = (DDPF)reader.ReadInt32();
                texture.depthMapHeader.ddspf.dwFourCC      = reader.ReadInt32();
                texture.depthMapHeader.ddspf.dwRGBBitCount = reader.ReadInt32();
                texture.depthMapHeader.ddspf.dwRBitMask    = reader.ReadUInt32();
                texture.depthMapHeader.ddspf.dwGBitMask    = reader.ReadUInt32();
                texture.depthMapHeader.ddspf.dwBBitMask    = reader.ReadUInt32();
                texture.depthMapHeader.ddspf.dwABitMask    = reader.ReadUInt32();
                texture.depthMapHeader.dwCaps              = (DDSCAPS)reader.ReadInt32();
                texture.depthMapHeader.dwCaps2             = (DDSCAPS2)reader.ReadInt32();
                texture.depthMapHeader.dwCaps3             = reader.ReadInt32();
                texture.depthMapHeader.dwCaps4             = reader.ReadInt32();
                reader.BaseStream.Position                += sizeof(int);
                // BUG: need to check for dx10 header.

                // Check the header magic and structure sizes for sanity.
                if (texture.depthMapHeader.dwMagic != DDS_HEADER.kMagic || texture.depthMapHeader.dwSize != DDS_HEADER.kSizeOf ||
                    texture.depthMapHeader.ddspf.dwSize != DDS_PIXELFORMAT.kSizeOf)
                {
                    // DDS header is invalid.
                    return(null);
                }
            }

            // Read all of the pixel data now and pin it so we can build the sub resources array.
            byte[] pixelData = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
            texture.PixelDataStream = DataStream.Create(pixelData, true, false);

            // Make sure we are at the start of the pixel data stream.
            texture.PixelDataStream.Seek(0, SeekOrigin.Begin);

            // Set the number of faces this texture has based on the texture type.
            if (texture.header.TextureType == TextureType.Type_CubeMap)
            {
                // Cubemap has 6 faces each with n mip map levels.
                texture.FaceCount = 6;
            }
            else
            {
                // All other texture types have 1 face with n mip maps.
                texture.FaceCount = 1;
            }

            // Allocate the sub resources array and setup for every face the texture has.
            texture.SubResources = new DataBox[texture.FaceCount * texture.header.MipMapCount];
            for (int i = 0; i < texture.FaceCount; i++)
            {
                // Loop for the number of mip maps and read each one.
                for (int x = 0; x < texture.header.MipMapCount; x++)
                {
                    int bytesPerRow    = 0;
                    int numberOfBlocks = 0;

                    // Calculate the pitch values for the current mip level.
                    int mipHeight = texture.header.TextureType == TextureType.Type_CubeMap ? texture.header.Width : texture.header.Height;
                    CalculateMipMapPitch(texture.header.Width, mipHeight, x, texture.header.Format, out bytesPerRow, out numberOfBlocks);

                    // Setup the resource description for this mip map.
                    texture.SubResources[(i * texture.header.MipMapCount) + x] = new DataBox(texture.PixelDataStream.PositionPointer, bytesPerRow, bytesPerRow * numberOfBlocks);
                    texture.PixelDataStream.Seek(bytesPerRow * numberOfBlocks, SeekOrigin.Current);
                }
            }

            // Close the binary reader and memory stream.
            reader.Close();
            ms.Close();

            // Return the texture object.
            return(texture);
        }