Пример #1
0
            public override byte[] Encode(byte[] input, int width, int height, VrPixelCodec PixelCodec)
            {
                int offset = 0;

                byte[] output = new byte[width * height * 2];

                for (int y = 0; y < height; y += 4)
                {
                    for (int x = 0; x < width; x += 4)
                    {
                        for (int y2 = 0; y2 < 4; y2++)
                        {
                            for (int x2 = 0; x2 < 4; x2++)
                            {
                                ushort pixel = 0x0000;

                                if (input[((((y + y2) * width) + (x + x2)) * 4) + 3] <= 0xDA) // Argb3444
                                {
                                    pixel |= (ushort)((input[((((y + y2) * width) + (x + x2)) * 4) + 3] >> 5) << 12);
                                    pixel |= (ushort)((input[((((y + y2) * width) + (x + x2)) * 4) + 2] >> 4) << 8);
                                    pixel |= (ushort)((input[((((y + y2) * width) + (x + x2)) * 4) + 1] >> 4) << 4);
                                    pixel |= (ushort)((input[((((y + y2) * width) + (x + x2)) * 4) + 0] >> 4) << 0);
                                    //pixel |= (ushort)(((input[((((y + y2) * width) + (x + x2)) * 4) + 3] * 0x07 / 0xFF) & 0x07) << 12);
                                    //pixel |= (ushort)(((input[((((y + y2) * width) + (x + x2)) * 4) + 2] * 0x0F / 0xFF) & 0x0F) << 8);
                                    //pixel |= (ushort)(((input[((((y + y2) * width) + (x + x2)) * 4) + 1] * 0x0F / 0xFF) & 0x0F) << 4);
                                    //pixel |= (ushort)(((input[((((y + y2) * width) + (x + x2)) * 4) + 0] * 0x0F / 0xFF) & 0x0F) << 0);
                                }
                                else // Rgb555
                                {
                                    pixel |= 0x8000;
                                    pixel |= (ushort)((input[((((y + y2) * width) + (x + x2)) * 4) + 2] >> 3) << 10);
                                    pixel |= (ushort)((input[((((y + y2) * width) + (x + x2)) * 4) + 1] >> 3) << 5);
                                    pixel |= (ushort)((input[((((y + y2) * width) + (x + x2)) * 4) + 0] >> 3) << 0);
                                    //pixel |= (ushort)(((input[((((y + y2) * width) + (x + x2)) * 4) + 2] * 0x1F / 0xFF) & 0x1F) << 10);
                                    //pixel |= (ushort)(((input[((((y + y2) * width) + (x + x2)) * 4) + 1] * 0x1F / 0xFF) & 0x1F) << 5);
                                    //pixel |= (ushort)(((input[((((y + y2) * width) + (x + x2)) * 4) + 0] * 0x1F / 0xFF) & 0x1F) << 0);
                                }

                                PTMethods.GetBytesBE(pixel).CopyTo(output, offset);
                                offset += 2;
                            }
                        }
                    }
                }

                return(output);
            }
Пример #2
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Magic code "TEX0"
            destination.WriteByte((byte)'T');
            destination.WriteByte((byte)'E');
            destination.WriteByte((byte)'X');
            destination.WriteByte((byte)'0');

            // Number of entries in the archive
            PTStream.WriteInt32(destination, entries.Count);

            destination.Position += 8;

            // Write out the header for the archive
            int entryOffset = 16 + (entries.Count * 32);

            for (int i = 0; i < entries.Count; i++)
            {
                // Write out the file extension
                string fileExtension = Path.GetExtension(entries[i].Name);
                if (fileExtension != String.Empty)
                {
                    fileExtension = fileExtension.Substring(1);
                }

                PTStream.WriteCString(destination, fileExtension, 4, Encoding.GetEncoding("Shift_JIS"));

                // Write out the offset, length, and filename (without the extension)
                PTStream.WriteInt32(destination, entryOffset);
                PTStream.WriteInt32(destination, entries[i].Length);
                PTStream.WriteCString(destination, Path.GetFileNameWithoutExtension(entries[i].Name), 20, Encoding.GetEncoding("Shift_JIS"));

                entryOffset += PTMethods.RoundUp(entries[i].Length, 16);
            }

            // Write out the file data for each entry
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, 16, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }
        }
Пример #3
0
        /// <summary>
        /// Determines if this is a PVR texture.
        /// </summary>
        /// <param name="source">Byte array containing the data.</param>
        /// <param name="offset">The offset in the byte array to start at.</param>
        /// <param name="length">Length of the data (in bytes).</param>
        /// <returns>True if this is a PVR texture, false otherwise.</returns>
        public static bool Is(byte[] source, int offset, int length)
        {
            // GBIX and PVRT
            //if (length >= 0x20 &&
            //    PTMethods.Contains(source, offset + 0x00, Encoding.UTF8.GetBytes("GBIX")) &&
            //    PTMethods.Contains(source, offset + 0x10, Encoding.UTF8.GetBytes("PVRT")) &&
            //    source[offset + 0x19] < 0x60 &&
            //    BitConverter.ToUInt32(source, offset + 0x14) == length - 24)
            if (length >= 0x20 &&
                PTMethods.Contains(source, offset + 0x00, Encoding.UTF8.GetBytes("GBIX")) &&
                PTMethods.Contains(source, offset + 0x10, Encoding.UTF8.GetBytes("PVRT")))
            {
                return(true);
            }

            // PVRT (and no GBIX chunk)
            else if (length >= 0x10 &&
                     PTMethods.Contains(source, offset + 0x00, Encoding.UTF8.GetBytes("PVRT")) &&
                     source[offset + 0x09] < 0x60 &&
                     BitConverter.ToUInt32(source, offset + 0x04) == length - 8)
            {
                return(true);
            }

            // GBIX and PVRT with RLE compression
            else if (length >= 0x24 &&
                     PTMethods.Contains(source, offset + 0x04, Encoding.UTF8.GetBytes("GBIX")) &&
                     PTMethods.Contains(source, offset + 0x14, Encoding.UTF8.GetBytes("PVRT")) &&
                     source[offset + 0x1D] < 0x60 &&
                     BitConverter.ToUInt32(source, offset + 0x18) == BitConverter.ToUInt32(source, offset + 0x00) - 24)
            {
                return(true);
            }

            // PVRT (and no GBIX chunk) with RLE compression
            else if (length >= 0x14 &&
                     PTMethods.Contains(source, offset + 0x04, Encoding.UTF8.GetBytes("PVRT")) &&
                     source[offset + 0x0D] < 0x60 &&
                     BitConverter.ToUInt32(source, offset + 0x08) == BitConverter.ToUInt32(source, offset + 0x00) - 8)
            {
                return(true);
            }

            return(false);
        }
Пример #4
0
            public override byte[] Decode(byte[] input, int offset, int width, int height, VrPixelCodec PixelCodec)
            {
                byte[] output = new byte[width * height * 4];

                for (int y = 0; y < height; y += 4)
                {
                    for (int x = 0; x < width; x += 4)
                    {
                        for (int y2 = 0; y2 < 4; y2++)
                        {
                            for (int x2 = 0; x2 < 4; x2++)
                            {
                                ushort pixel = PTMethods.ToUInt16BE(input, offset);

                                if ((pixel & 0x8000) != 0) // Rgb555
                                {
                                    output[((((y + y2) * width) + (x + x2)) * 4) + 3] = 0xFF;
                                    output[((((y + y2) * width) + (x + x2)) * 4) + 2] = (byte)(((pixel >> 10) & 0x1F) * 0xFF / 0x1F);
                                    output[((((y + y2) * width) + (x + x2)) * 4) + 1] = (byte)(((pixel >> 5) & 0x1F) * 0xFF / 0x1F);
                                    output[((((y + y2) * width) + (x + x2)) * 4) + 0] = (byte)(((pixel >> 0) & 0x1F) * 0xFF / 0x1F);
                                    //output[((((y + y2) * width) + (x + x2)) * 4) + 3] = 0xFF;
                                    //output[((((y + y2) * width) + (x + x2)) * 4) + 2] = (byte)(((pixel >> 10) & 0x1F) << 11);
                                    //output[((((y + y2) * width) + (x + x2)) * 4) + 1] = (byte)(((pixel >> 5) & 0x1F) << 11);
                                    //output[((((y + y2) * width) + (x + x2)) * 4) + 0] = (byte)(((pixel >> 0) & 0x1F) << 11);
                                }
                                else // Argb3444
                                {
                                    output[((((y + y2) * width) + (x + x2)) * 4) + 3] = (byte)(((pixel >> 12) & 0x07) * 0xFF / 0x07);
                                    output[((((y + y2) * width) + (x + x2)) * 4) + 2] = (byte)(((pixel >> 8) & 0x0F) * 0xFF / 0x0F);
                                    output[((((y + y2) * width) + (x + x2)) * 4) + 1] = (byte)(((pixel >> 4) & 0x0F) * 0xFF / 0x0F);
                                    output[((((y + y2) * width) + (x + x2)) * 4) + 0] = (byte)(((pixel >> 0) & 0x0F) * 0xFF / 0x0F);
                                    //output[((((y + y2) * width) + (x + x2)) * 4) + 3] = (byte)(((pixel >> 12) & 0x07) << 13);
                                    //output[((((y + y2) * width) + (x + x2)) * 4) + 2] = (byte)(((pixel >> 8) & 0x0F) << 12);
                                    //output[((((y + y2) * width) + (x + x2)) * 4) + 1] = (byte)(((pixel >> 4) & 0x0F) << 12);
                                    //output[((((y + y2) * width) + (x + x2)) * 4) + 0] = (byte)(((pixel >> 0) & 0x0F) << 12);
                                }

                                offset += 2;
                            }
                        }
                    }
                }

                return(output);
            }
Пример #5
0
            public override void DecodePixel(byte[] source, int sourceIndex, byte[] destination, int destinationIndex)
            {
                ushort pixel = PTMethods.ToUInt16BE(source, sourceIndex);

                if ((pixel & 0x8000) != 0) // Rgb555
                {
                    destination[destinationIndex + 3] = 0xFF;
                    destination[destinationIndex + 2] = (byte)(((pixel >> 10) & 0x1F) * 0xFF / 0x1F);
                    destination[destinationIndex + 1] = (byte)(((pixel >> 5) & 0x1F) * 0xFF / 0x1F);
                    destination[destinationIndex + 0] = (byte)(((pixel >> 0) & 0x1F) * 0xFF / 0x1F);
                }
                else // Argb3444
                {
                    destination[destinationIndex + 3] = (byte)(((pixel >> 12) & 0x07) * 0xFF / 0x07);
                    destination[destinationIndex + 2] = (byte)(((pixel >> 8) & 0x0F) * 0xFF / 0x0F);
                    destination[destinationIndex + 1] = (byte)(((pixel >> 4) & 0x0F) * 0xFF / 0x0F);
                    destination[destinationIndex + 0] = (byte)(((pixel >> 0) & 0x0F) * 0xFF / 0x0F);
                }
            }
Пример #6
0
        public override void Flush()
        {
            const int tableStartPtr = 0x10;
            int       dataStartPtr  = PTMethods.RoundUp(tableStartPtr + (entries.Count * 0x30), 0x10); // just to be safe

            PTStream.WriteInt32BE(destination, entries.Count);
            PTStream.WriteInt32BE(destination, tableStartPtr); // pointer to table start
            PTStream.WriteInt32BE(destination, dataStartPtr);  // pointer to data start
            PTStream.WriteInt32BE(destination, 0);             // not 100% sure on this one

            int offset = dataStartPtr;

            using (var compressedStream = new MemoryStream())
            {
                for (int i = 0; i < entries.Count; i++)
                {
                    var entry       = entries[i];
                    var entryStream = entry.Open();
                    _prsCompression.Compress(entryStream, compressedStream);

                    compressedStream.Position = 0;

                    PTStream.WriteCString(destination, entry.Name, 0x20);             // name
                    PTStream.WriteInt32BE(destination, i);                            // index
                    PTStream.WriteInt32BE(destination, offset);                       // offset
                    PTStream.WriteInt32BE(destination, (int)compressedStream.Length); // compressed length
                    PTStream.WriteInt32BE(destination, (int)entryStream.Length);      // uncompressed length

                    Debug.Assert(destination.Position <= dataStartPtr, "Table overrun!");

                    var currentPos = destination.Position;
                    destination.Position = offset;
                    PTStream.CopyTo(compressedStream, destination);
                    destination.Position = currentPos;

                    offset += (int)compressedStream.Length;
                    compressedStream.Position = 0;
                    compressedStream.SetLength(0);

                    OnFileAdded(EventArgs.Empty);
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Checks for the PVRT header and validates it.
        /// <para>See also: <seealso cref="IsValidGbix"/></para>
        /// </summary>
        /// <param name="source">Byte array containing the data.</param>
        /// <param name="offset">The offset in the byte array to start at.</param>
        /// <param name="length">The expected length of the PVR data minus the preceding header sizes.</param>
        /// <returns>True if the header is PVRT and it passes validation, false otherwise.</returns>
        private static bool IsValidPvrt(byte[] source, int offset, uint length)
        {
            if (!PTMethods.Contains(source, offset + 0x00, pvrtFourCC))
            {
                return(false);
            }

            if (source[offset + 0x09] >= 0x60)
            {
                return(false);
            }

            if (BitConverter.ToUInt32(source, offset + 0x04) != length - 8)
            {
                return(false);
            }

            return(true);
        }
Пример #8
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Magic code "\0\0\0\0"
            destination.WriteByte(0);
            destination.WriteByte(0);
            destination.WriteByte(0);
            destination.WriteByte(0);

            // Number of entries in the archive
            PTStream.WriteInt32BE(destination, entries.Count);

            // Write out the header for the archive
            int entryOffset      = PTMethods.RoundUp(8 + (entries.Count * 8), blockSize);
            int firstEntryOffset = entryOffset;

            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32BE(destination, entryOffset);
                PTStream.WriteInt32BE(destination, entries[i].Length);

                entryOffset += PTMethods.RoundUp(entries[i].Length, blockSize);
            }

            // Pad before writing out the file data
            while ((destination.Position - offset) % blockSize != 0)
            {
                destination.WriteByte(0);
            }

            // Write out the file data for each entry
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, blockSize, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }
        }
Пример #9
0
        protected override bool Initalize()
        {
            // Check to see if what we are dealing with is a GVP palette
            if (!Is(encodedData))
            {
                return(false);
            }

            // Get the pixel format and the codec and make sure we can decode using them
            pixelFormat = (PvrPixelFormat)encodedData[0x08];
            pixelCodec  = PvrPixelCodec.GetPixelCodec(pixelFormat);
            if (pixelCodec == null)
            {
                return(false);
            }

            // Get the number of colors contained in the palette
            paletteEntries = PTMethods.ToUInt16(encodedData, 0x0E, true);

            return(true);
        }
Пример #10
0
        /// <summary>
        /// Determines if this is a SVR texture.
        /// </summary>
        /// <param name="source">Byte array containing the data.</param>
        /// <param name="offset">The offset in the byte array to start at.</param>
        /// <param name="length">Length of the data (in bytes).</param>
        /// <returns>True if this is a SVR texture, false otherwise.</returns>
        public static bool Is(byte[] source, int offset, int length)
        {
            // GBIX and PVRT
            if (length >= 0x20 &&
                PTMethods.Contains(source, offset + 0x00, Encoding.UTF8.GetBytes("GBIX")) &&
                PTMethods.Contains(source, offset + 0x10, Encoding.UTF8.GetBytes("PVRT")) &&
                source[offset + 0x19] >= 0x60 && source[offset + 0x19] < 0x70 &&
                BitConverter.ToUInt32(source, offset + 0x14) == length - 24)
            {
                return(true);
            }

            // PVRT (and no GBIX chunk)
            else if (length >= 0x10 &&
                     PTMethods.Contains(source, offset + 0x00, Encoding.UTF8.GetBytes("PVRT")) &&
                     source[offset + 0x19] >= 0x60 && source[offset + 0x19] < 0x70 &&
                     BitConverter.ToUInt32(source, offset + 0x04) == length - 8)
            {
                return(true);
            }

            return(false);
        }
Пример #11
0
 /// <summary>
 /// Checks for the XVRT header and validates it.
 /// </summary>
 /// <param name="source">Byte array containing the data.</param>
 /// <param name="offset">The offset in the byte array to start at.</param>
 /// <param name="length">The expected length of the PVR data minus the preceding header sizes.</param>
 /// <returns>True if the header is XVRT and it passes validation, false otherwise.</returns>
 private static bool IsValidXvrt(byte[] source, int offset, int length)
 {
     return(PTMethods.Contains(source, offset, xvrtFourCC) &&
            BitConverter.ToUInt32(source, offset + 0x04) == length - 8);
 }
Пример #12
0
 /// <summary>
 /// Checks for the PVRT header and validates it.
 /// <para>See also: <seealso cref="IsValidGbix"/></para>
 /// </summary>
 /// <param name="source">Byte array containing the data.</param>
 /// <param name="offset">The offset in the byte array to start at.</param>
 /// <param name="length">The expected length of the PVR data minus the preceding header sizes.</param>
 /// <returns>True if the header is PVRT and it passes validation, false otherwise.</returns>
 private static bool IsValidPvrt(byte[] source, int offset, int length)
 {
     return(PTMethods.Contains(source, offset, pvrtFourCC) &&
            source[offset + 0x09] < 0x60 &&
            PTMethods.ToUInt32(source, offset + 0x04, true) == length - 8);
 }
Пример #13
0
        public override void Flush()
        {
            // Determine the length of each entry in the header
            // and the flags that indicate what is stored in the header
            int    entryLength = 2;
            ushort flags       = 0;

            if (HasFilenames)
            {
                entryLength += 28;
                flags       |= 0x8;
            }
            if (HasFormats)
            {
                entryLength += 2;
                flags       |= 0x4;
            }
            if (HasDimensions)
            {
                entryLength += 2;
                flags       |= 0x2;
            }
            if (HasGlobalIndexes)
            {
                entryLength += 4;
                flags       |= 0x1;
            }

            // Write the start of the header
            destination.WriteByte((byte)'P');
            destination.WriteByte((byte)'V');
            destination.WriteByte((byte)'M');
            destination.WriteByte((byte)'H');

            // Offset of the first texture in the archive
            long entryOffset = PTMethods.RoundUp(12 + (entries.Count * entryLength), 16);

            PTStream.WriteInt32(destination, (int)entryOffset - 8);

            // Write out the flags
            PTStream.WriteUInt16(destination, flags);

            // Write out the number of entries
            PTStream.WriteUInt16(destination, (ushort)entries.Count);

            // We're going to be using this a few times. Might as well do this here
            long oldPosition;

            // Now, let's add the entries
            for (int i = 0; i < entries.Count; i++)
            {
                Stream entryData = entries[i].Open();

                // We need to get some information about the texture.
                // We already checked to make sure this texture is a PVR.
                // No need to check it again.
                oldPosition = entryData.Position;
                VrSharp.PvrTexture.PvrTexture texture = new VrSharp.PvrTexture.PvrTexture(entryData);
                entryData.Position = oldPosition;

                // Write out the entry number
                PTStream.WriteUInt16(destination, (ushort)i);

                // Write the information for this entry in the header
                if (HasFilenames)
                {
                    PTStream.WriteCString(destination, Path.GetFileNameWithoutExtension(entries[i].Name), 28);
                }
                if (HasFormats)
                {
                    destination.WriteByte(0);
                    destination.WriteByte((byte)texture.DataFormat);
                }
                if (HasDimensions)
                {
                    ushort dimensions = 0;
                    dimensions |= (ushort)(((byte)Math.Log(texture.TextureWidth, 2) - 2) & 0xF);
                    dimensions |= (ushort)((((byte)Math.Log(texture.TextureHeight, 2) - 2) & 0xF) << 4);
                    PTStream.WriteUInt16(destination, dimensions);
                }
                if (HasGlobalIndexes)
                {
                    PTStream.WriteUInt32(destination, texture.GlobalIndex);
                }

                // Now write out the entry information
                oldPosition          = destination.Position;
                destination.Position = entryOffset;
                entryData.Position  += texture.PvrtOffset;

                PTStream.CopyToPadded(entryData, destination, 16, 0);

                entryOffset          = destination.Position;
                destination.Position = oldPosition;

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }
        }
Пример #14
0
        protected override void Initalize()
        {
            // Check to see if what we are dealing with is a GVR texture
            if (!Is(encodedData))
            {
                throw new NotAValidTextureException("This is not a valid GVR texture.");
            }

            // Determine the offsets of the GBIX/GCIX (if present) and GCIX header chunks.
            if (PTMethods.Contains(encodedData, 0, Encoding.UTF8.GetBytes("GBIX")) ||
                PTMethods.Contains(encodedData, 0, Encoding.UTF8.GetBytes("GCIX")))
            {
                gbixOffset = 0x00;
                pvrtOffset = 0x10;
            }
            else
            {
                gbixOffset = -1;
                pvrtOffset = 0x00;
            }

            // Read the global index (if it is present). If it is not present, just set it to 0.
            if (gbixOffset != -1)
            {
                globalIndex = PTMethods.ToUInt32BE(encodedData, gbixOffset + 0x08);
            }
            else
            {
                globalIndex = 0;
            }

            // Read information about the texture
            textureWidth  = PTMethods.ToUInt16BE(encodedData, pvrtOffset + 0x0C);
            textureHeight = PTMethods.ToUInt16BE(encodedData, pvrtOffset + 0x0E);

            pixelFormat = (GvrPixelFormat)(encodedData[pvrtOffset + 0x0A] >> 4); // Only the first 4 bits matter
            dataFlags   = (GvrDataFlags)(encodedData[pvrtOffset + 0x0A] & 0x0F); // Only the last 4 bits matter
            dataFormat  = (GvrDataFormat)encodedData[pvrtOffset + 0x0B];

            // Get the codecs and make sure we can decode using them
            dataCodec = GvrDataCodec.GetDataCodec(dataFormat);

            // We need a pixel codec if this is a palettized texture
            if (dataCodec != null && dataCodec.PaletteEntries != 0)
            {
                pixelCodec = GvrPixelCodec.GetPixelCodec(pixelFormat);

                if (pixelCodec != null)
                {
                    dataCodec.PixelCodec = pixelCodec;
                    canDecode            = true;
                }
            }
            else
            {
                pixelFormat = GvrPixelFormat.Unknown;

                if (dataCodec != null)
                {
                    canDecode = true;
                }
            }

            // Set the palette and data offsets
            paletteEntries = dataCodec.PaletteEntries;
            if (!canDecode || paletteEntries == 0 || (paletteEntries != 0 && (dataFlags & GvrDataFlags.ExternalPalette) != 0))
            {
                paletteOffset = -1;
                dataOffset    = pvrtOffset + 0x10;
            }
            else
            {
                paletteOffset = pvrtOffset + 0x10;
                dataOffset    = paletteOffset + (paletteEntries * (pixelCodec.Bpp >> 3));
            }

            // If the texture contains mipmaps, gets the offsets of them
            if (canDecode && paletteEntries == 0 && (dataFlags & GvrDataFlags.Mipmaps) != 0)
            {
                mipmapOffsets = new int[(int)Math.Log(textureWidth, 2) + 1];

                int mipmapOffset = 0;
                for (int i = 0, size = textureWidth; i < mipmapOffsets.Length; i++, size >>= 1)
                {
                    mipmapOffsets[i] = mipmapOffset;
                    mipmapOffset    += Math.Max(size * size * (dataCodec.Bpp >> 3), 32);
                }
            }

            initalized = true;
        }
Пример #15
0
            public override byte[] Decode(byte[] input, int offset, int width, int height, VrPixelCodec PixelCodec)
            {
                byte[] output = new byte[width * height * 4];

                // Palette for each 4x4 block
                byte[][] palette = new byte[4][];
                palette[0] = new byte[4];
                palette[1] = new byte[4];
                palette[2] = new byte[4];
                palette[3] = new byte[4];

                // The two colors that determine the palette
                ushort[] pixel = new ushort[2];

                for (int y = 0; y < height; y += 8)
                {
                    for (int x = 0; x < width; x += 8)
                    {
                        for (int y2 = 0; y2 < 8; y2 += 4)
                        {
                            for (int x2 = 0; x2 < 8; x2 += 4)
                            {
                                // Get the first two colors
                                pixel[0] = PTMethods.ToUInt16BE(input, offset);
                                pixel[1] = PTMethods.ToUInt16BE(input, offset + 2);

                                palette[0][3] = 0xFF;
                                palette[0][2] = (byte)(((pixel[0] >> 11) & 0x1F) * 0xFF / 0x1F);
                                palette[0][1] = (byte)(((pixel[0] >> 5) & 0x3F) * 0xFF / 0x3F);
                                palette[0][0] = (byte)(((pixel[0] >> 0) & 0x1F) * 0xFF / 0x1F);

                                palette[1][3] = 0xFF;
                                palette[1][2] = (byte)(((pixel[1] >> 11) & 0x1F) * 0xFF / 0x1F);
                                palette[1][1] = (byte)(((pixel[1] >> 5) & 0x3F) * 0xFF / 0x3F);
                                palette[1][0] = (byte)(((pixel[1] >> 0) & 0x1F) * 0xFF / 0x1F);

                                // Determine the next two colors based on how the first two are stored
                                if (pixel[0] > pixel[1])
                                {
                                    palette[2][3] = 0xFF;
                                    palette[2][2] = (byte)(((palette[0][2] * 2) + palette[1][2]) / 3);
                                    palette[2][1] = (byte)(((palette[0][1] * 2) + palette[1][1]) / 3);
                                    palette[2][0] = (byte)(((palette[0][0] * 2) + palette[1][0]) / 3);

                                    palette[3][3] = 0xFF;
                                    palette[3][2] = (byte)(((palette[1][2] * 2) + palette[0][2]) / 3);
                                    palette[3][1] = (byte)(((palette[1][1] * 2) + palette[0][1]) / 3);
                                    palette[3][0] = (byte)(((palette[1][0] * 2) + palette[0][0]) / 3);
                                }
                                else
                                {
                                    palette[2][3] = 0xFF;
                                    palette[2][2] = (byte)((palette[0][2] + palette[1][2]) / 2);
                                    palette[2][1] = (byte)((palette[0][1] + palette[1][1]) / 2);
                                    palette[2][0] = (byte)((palette[0][0] + palette[1][0]) / 2);

                                    palette[3][3] = 0x00;
                                    palette[3][2] = 0x00;
                                    palette[3][1] = 0x00;
                                    palette[3][0] = 0x00;
                                }

                                offset += 4;

                                for (int y3 = 0; y3 < 4; y3++)
                                {
                                    for (int x3 = 0; x3 < 4; x3++)
                                    {
                                        output[((((y + y2 + y3) * width) + (x + x2 + x3)) * 4) + 3] = palette[((input[offset] >> (6 - (x3 * 2))) & 0x03)][3];
                                        output[((((y + y2 + y3) * width) + (x + x2 + x3)) * 4) + 2] = palette[((input[offset] >> (6 - (x3 * 2))) & 0x03)][2];
                                        output[((((y + y2 + y3) * width) + (x + x2 + x3)) * 4) + 1] = palette[((input[offset] >> (6 - (x3 * 2))) & 0x03)][1];
                                        output[((((y + y2 + y3) * width) + (x + x2 + x3)) * 4) + 0] = palette[((input[offset] >> (6 - (x3 * 2))) & 0x03)][0];
                                    }

                                    offset++;
                                }
                            }
                        }
                    }
                }

                return(output);
            }
Пример #16
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Puyo Tools is only capable of building U8 archives that do not contain directories.
            // It's just very difficult to do with the way Puyo Tools is structured.

            // First things first, let's get the header size
            int headerSize = ((entries.Count + 1) * 12) + 1;

            for (int i = 0; i < entries.Count; i++)
            {
                headerSize += entries[i].Name.Length + 1;
            }

            // Get the name and data offset
            int nameOffset = 0;
            int dataOffset = PTMethods.RoundUp(0x20 + headerSize, 32);

            // Start writing out the header
            destination.WriteByte((byte)'U');
            destination.WriteByte(0xAA);
            destination.WriteByte((byte)'8');
            destination.WriteByte((byte)'-');

            PTStream.WriteUInt32BE(destination, 0x20);      // Root node offset (always 0x20)
            PTStream.WriteInt32BE(destination, headerSize); // Header size
            PTStream.WriteInt32BE(destination, dataOffset); // Data offset

            // Pad
            while ((destination.Position - offset) % 32 != 0)
            {
                destination.WriteByte(0);
            }

            // Write the root node
            destination.WriteByte(1);
            destination.WriteByte((byte)(nameOffset >> 16));
            PTStream.WriteUInt16BE(destination, (ushort)(nameOffset & 0xFFFF));
            PTStream.WriteInt32BE(destination, 0);
            PTStream.WriteInt32BE(destination, entries.Count + 1);

            nameOffset++;

            // Write out the file nodes
            for (int i = 0; i < entries.Count; i++)
            {
                destination.WriteByte(0);
                destination.WriteByte((byte)(nameOffset >> 16));
                PTStream.WriteUInt16BE(destination, (ushort)(nameOffset & 0xFFFF));
                PTStream.WriteInt32BE(destination, dataOffset);
                PTStream.WriteInt32BE(destination, entries[i].Length);

                nameOffset += entries[i].Name.Length + 1;
                dataOffset += PTMethods.RoundUp(entries[i].Length, 32);
            }

            // Write out the filename table
            PTStream.WriteCString(destination, String.Empty, 1);
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteCString(destination, entries[i].Name, entries[i].Name.Length + 1);
            }

            // Pad
            while ((destination.Position - offset) % 32 != 0)
            {
                destination.WriteByte(0);
            }

            // Write the file data
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, 32, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }
        }
Пример #17
0
        protected override void Initalize()
        {
            // Check to see if what we are dealing with is a PVR texture
            if (!Is(encodedData))
            {
                throw new NotAValidTextureException("This is not a valid PVR texture.");
            }

            // Determine the offsets of the GBIX (if present) and PVRT header chunks.
            if (PTMethods.Contains(encodedData, 0x00, Encoding.UTF8.GetBytes("GBIX")))
            {
                gbixOffset = 0x00;
                pvrtOffset = 0x10;
            }
            else if (PTMethods.Contains(encodedData, 0x04, Encoding.UTF8.GetBytes("GBIX")))
            {
                gbixOffset = 0x04;
                pvrtOffset = 0x14;
            }
            else if (PTMethods.Contains(encodedData, 0x04, Encoding.UTF8.GetBytes("PVRT")))
            {
                gbixOffset = -1;
                pvrtOffset = 0x04;
            }
            else
            {
                gbixOffset = -1;
                pvrtOffset = 0x00;
            }

            // Read the global index (if it is present). If it is not present, just set it to 0.
            if (gbixOffset != -1)
            {
                globalIndex = BitConverter.ToUInt32(encodedData, gbixOffset + 0x08);
            }
            else
            {
                globalIndex = 0;
            }

            // Read information about the texture
            textureWidth  = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0C);
            textureHeight = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0E);

            pixelFormat = (PvrPixelFormat)encodedData[pvrtOffset + 0x08];
            dataFormat  = (PvrDataFormat)encodedData[pvrtOffset + 0x09];

            // Get the codecs and make sure we can decode using them
            pixelCodec = PvrPixelCodec.GetPixelCodec(pixelFormat);
            dataCodec  = PvrDataCodec.GetDataCodec(dataFormat);

            if (dataCodec != null && pixelCodec != null)
            {
                dataCodec.PixelCodec = pixelCodec;
                canDecode            = true;
            }

            // Set the palette and data offsets
            if (!canDecode || dataCodec.PaletteEntries == 0 || dataCodec.NeedsExternalPalette)
            {
                paletteOffset = -1;
                dataOffset    = pvrtOffset + 0x10;
            }
            else
            {
                paletteOffset = pvrtOffset + 0x10;
                dataOffset    = paletteOffset + (dataCodec.PaletteEntries * (pixelCodec.Bpp >> 3));
            }

            // Get the compression format and determine if we need to decompress this texture
            compressionFormat = GetCompressionFormat(encodedData, pvrtOffset, dataOffset);
            compressionCodec  = PvrCompressionCodec.GetCompressionCodec(compressionFormat);

            if (compressionFormat != PvrCompressionFormat.None && compressionCodec != null)
            {
                encodedData = compressionCodec.Decompress(encodedData, dataOffset, pixelCodec, dataCodec);

                // Now place the offsets in the appropiate area
                if (compressionFormat == PvrCompressionFormat.Rle)
                {
                    if (gbixOffset != -1)
                    {
                        gbixOffset -= 4;
                    }
                    pvrtOffset -= 4;
                    if (paletteOffset != -1)
                    {
                        paletteOffset -= 4;
                    }
                    dataOffset -= 4;
                }
            }

            // If the texture contains mipmaps, gets the offsets of them
            if (canDecode && dataCodec.HasMipmaps)
            {
                mipmapOffsets = new int[(int)Math.Log(textureWidth, 2) + 1];

                int mipmapOffset = 0;

                // Calculate the padding for the first mipmap offset
                if (dataFormat == PvrDataFormat.SquareTwiddledMipmaps)
                {
                    // A 1x1 mipmap takes up as much space as a 2x1 mipmap
                    mipmapOffset = (dataCodec.Bpp) >> 3;
                }
                if (dataFormat == PvrDataFormat.SquareTwiddledMipmapsAlt)
                {
                    // A 1x1 mipmap takes up as much space as a 2x2 mipmap
                    mipmapOffset = (3 * dataCodec.Bpp) >> 3;
                }

                for (int i = mipmapOffsets.Length - 1, size = 1; i >= 0; i--, size <<= 1)
                {
                    mipmapOffsets[i] = mipmapOffset;

                    mipmapOffset += Math.Max((size * size * dataCodec.Bpp) >> 3, 1);
                }
            }

            initalized = true;
        }
Пример #18
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Magic code "NSIF/NUIF"
            if (platform == SntPlatform.Ps2)
            {
                destination.WriteByte((byte)'N');
                destination.WriteByte((byte)'S');
                destination.WriteByte((byte)'I');
                destination.WriteByte((byte)'F');
            }
            else
            {
                destination.WriteByte((byte)'N');
                destination.WriteByte((byte)'U');
                destination.WriteByte((byte)'I');
                destination.WriteByte((byte)'F');
            }

            PTStream.WriteInt32(destination, 24); // Unknown
            PTStream.WriteInt32(destination, 1);  // Unknown
            PTStream.WriteInt32(destination, 32); // Offset of the NSTL/NUTL chunk?

            // Calculate the size of the NSTL chunk
            int NSTLLength = 0;

            for (int i = 0; i < entries.Count; i++)
            {
                NSTLLength += PTMethods.RoundUp(entries[i].Length, 8);
            }

            PTStream.WriteInt32(destination, PTMethods.RoundUp(28 + (entries.Count * 28), 8) + NSTLLength);
            PTStream.WriteInt32(destination, PTMethods.RoundUp(60 + (entries.Count * 28), 8) + NSTLLength);
            PTStream.WriteInt32(destination, 24 + (entries.Count * 4));
            PTStream.WriteInt32(destination, 1);

            // NSTL/NUTL chunk
            if (platform == SntPlatform.Ps2)
            {
                destination.WriteByte((byte)'N');
                destination.WriteByte((byte)'S');
                destination.WriteByte((byte)'T');
                destination.WriteByte((byte)'L');
            }
            else
            {
                destination.WriteByte((byte)'N');
                destination.WriteByte((byte)'U');
                destination.WriteByte((byte)'T');
                destination.WriteByte((byte)'L');
            }

            PTStream.WriteInt32(destination, PTMethods.RoundUp(20 + (entries.Count * 28), 8) + NSTLLength);
            PTStream.WriteInt32(destination, 16);
            PTStream.WriteInt32(destination, 0);
            PTStream.WriteInt32(destination, entries.Count);
            PTStream.WriteInt32(destination, 28);
            PTStream.WriteInt32(destination, 28 + (entries.Count * 20));

            // Write out crap bytes
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32(destination, 1);
                PTStream.WriteInt32(destination, 0);
                destination.Write(new byte[] { 1, 0, 1, 0 }, 0, 4);
                PTStream.WriteInt32(destination, i);
                PTStream.WriteInt32(destination, 0);
            }

            // Write out the header for the archive
            int entryOffset = 60 + (entries.Count * 28);

            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32(destination, entries[i].Length);
                PTStream.WriteInt32(destination, entryOffset - 32);

                entryOffset += PTMethods.RoundUp(entries[i].Length, 4);
            }

            // Write out the file data for each entry
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, 4, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }

            // Pad before writing out the NOF0 chunk
            while ((destination.Position - offset) % 8 != 0)
            {
                destination.WriteByte(0);
            }

            // NOF0 chunk
            destination.WriteByte((byte)'N');
            destination.WriteByte((byte)'O');
            destination.WriteByte((byte)'F');
            destination.WriteByte((byte)'0');

            // Write out crap bytes
            PTStream.WriteInt32(destination, PTMethods.RoundUp(28 + (entries.Count * 4), 8));
            PTStream.WriteInt32(destination, entries.Count + 2);
            PTStream.WriteInt32(destination, 0);
            PTStream.WriteInt32(destination, 20);

            // Write out more unknown stuff
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32(destination, 32 + (entries.Count * 20) + (i * 8));
            }

            PTStream.WriteInt32(destination, 24);

            // Pad before we write NEND
            // Finish padding out the archive
            while ((destination.Position - offset) % 16 != 0)
            {
                destination.WriteByte(0);
            }

            destination.WriteByte((byte)'N');
            destination.WriteByte((byte)'E');
            destination.WriteByte((byte)'N');
            destination.WriteByte((byte)'D');

            while ((destination.Position - offset) % 16 != 0)
            {
                destination.WriteByte(0);
            }
        }
Пример #19
0
        protected override void Initalize()
        {
            // Check to see if what we are dealing with is a SVR texture
            if (!Is(encodedData))
            {
                throw new NotAValidTextureException("This is not a valid GVR texture.");
            }

            // Determine the offsets of the GBIX (if present) and PVRT header chunks.
            if (PTMethods.Contains(encodedData, 0, Encoding.UTF8.GetBytes("GBIX")))
            {
                gbixOffset = 0x00;
                pvrtOffset = 0x10;
            }
            else
            {
                gbixOffset = -1;
                pvrtOffset = 0x00;
            }

            // Read the global index (if it is present). If it is not present, just set it to 0.
            if (gbixOffset != -1)
            {
                globalIndex = BitConverter.ToUInt32(encodedData, gbixOffset + 0x08);
            }
            else
            {
                globalIndex = 0;
            }

            // Read information about the texture
            textureWidth  = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0C);
            textureHeight = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0E);

            pixelFormat = (SvrPixelFormat)encodedData[pvrtOffset + 0x08];
            dataFormat  = (SvrDataFormat)encodedData[pvrtOffset + 0x09];

            // Get the codecs and make sure we can decode using them
            pixelCodec = SvrPixelCodec.GetPixelCodec(pixelFormat);
            dataCodec  = SvrDataCodec.GetDataCodec(dataFormat);

            if (dataCodec != null && pixelCodec != null)
            {
                dataCodec.PixelCodec = pixelCodec;
                canDecode            = true;
            }

            // Set the palette and data offsets
            paletteEntries = dataCodec.PaletteEntries;
            if (!canDecode || paletteEntries == 0 || dataCodec.NeedsExternalPalette)
            {
                paletteOffset = -1;
                dataOffset    = pvrtOffset + 0x10;
            }
            else
            {
                paletteOffset = pvrtOffset + 0x10;
                dataOffset    = paletteOffset + (paletteEntries * (pixelCodec.Bpp >> 3));
            }

            initalized = true;
        }
Пример #20
0
        public override void Flush()
        {
            // The start of the archive
            long offset = destination.Position;

            // Magic code "AFS\0"
            destination.WriteByte((byte)'A');
            destination.WriteByte((byte)'F');
            destination.WriteByte((byte)'S');
            destination.WriteByte(0);

            // Number of entries in the archive
            PTStream.WriteInt32(destination, entries.Count);

            // Write out the header for the archive
            int entryOffset      = PTMethods.RoundUp(12 + (entries.Count * 8), blockSize);
            int firstEntryOffset = entryOffset;

            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteInt32(destination, entryOffset);
                PTStream.WriteInt32(destination, entries[i].Length);

                entryOffset += PTMethods.RoundUp(entries[i].Length, blockSize);
            }

            // If this is AFS v1, then the metadata offset is stored at 8 bytes before
            // the first entry offset.
            if (version == AfsVersion.Version1)
            {
                destination.Position = offset + firstEntryOffset - 8;
            }

            // Write out the metadata offset and length
            PTStream.WriteInt32(destination, entryOffset);
            PTStream.WriteInt32(destination, entries.Count * 48);

            destination.Position = offset + firstEntryOffset;

            // Write out the file data for each entry
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.CopyToPadded(entries[i].Open(), destination, blockSize, 0);

                // Call the file added event
                OnFileAdded(EventArgs.Empty);
            }

            // Write out the footer for the archive
            for (int i = 0; i < entries.Count; i++)
            {
                PTStream.WriteCString(destination, entries[i].Name, 32);

                // File timestamp
                if (HasTimestamps && !String.IsNullOrEmpty(entries[i].Path) && File.Exists(entries[i].Path))
                {
                    // File exists, let's read in the file timestamp
                    FileInfo fileInfo = new FileInfo(entries[i].Path);

                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Year);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Month);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Day);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Hour);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Minute);
                    PTStream.WriteInt16(destination, (short)fileInfo.LastWriteTime.Second);
                }
                else
                {
                    // File does not exist, just store all 0s
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                    PTStream.WriteInt16(destination, 0);
                }

                // Write out this data that I have no idea what its purpose is
                long   oldPosition = destination.Position;
                byte[] buffer      = new byte[4];

                if (version == AfsVersion.Version1)
                {
                    destination.Position = offset + 8 + (i * 8);
                }
                else
                {
                    destination.Position = offset + 4 + (i * 4);
                }

                destination.Read(buffer, 0, 4);
                destination.Position = oldPosition;
                destination.Write(buffer, 0, 4);
            }

            // Finish padding out the archive
            while ((destination.Position - offset) % blockSize != 0)
            {
                destination.WriteByte(0);
            }
        }
Пример #21
0
    // Build GAME.DAT using files from the specified directory
    public static void Build(string executable, string inDir, string gameDat)
    {
        Console.Write("\nBuilding ...");

        using (FileStream exeStream = File.Open(executable, FileMode.Open, FileAccess.ReadWrite))
        {
            // Determine the game version
            GameVersion gameVersion = GameVersion.Unknown;
            if (exeStream.Length == 2678816) // Wii version
            {
                gameVersion = GameVersion.Wii;
            }
            else if (exeStream.Length == 2716853) // PSP version
            {
                gameVersion = GameVersion.PSP;
            }
            else
            {
                return;
            }

            uint numFiles = 0;
            if (gameVersion == GameVersion.Wii)
            {
                exeStream.Position = 0x18A058;
            }
            else if (gameVersion == GameVersion.PSP)
            {
                exeStream.Position = 0x1978FC;
            }

            // Get the number of files in the file entry table
            exeStream.Position += 20;
            if (gameVersion == GameVersion.Wii)
            {
                numFiles            = PTStream.ReadUInt32BE(exeStream);
                exeStream.Position += 152; // Now go to the position of the first file in the file entry table
            }
            else if (gameVersion == GameVersion.PSP)
            {
                numFiles            = PTStream.ReadUInt32(exeStream);
                exeStream.Position += 136; // Now go to the position of the first file in the file entry table
            }

            string[] fileList = new string[numFiles];

            Console.WriteLine(" " + numFiles + " files detected.");

            // Now let's make sure all the files exist
            for (uint i = 0; i < numFiles; i++)
            {
                string[] file = Directory.GetFiles(inDir, i.ToString("D4") + ".*");
                if (file.Length == 0)
                {
                    Console.WriteLine("{0} does not exist. Terminating.", i.ToString("D4"));
                    return;
                }
                else if (file.Length > 1)
                {
                    Console.WriteLine("Multiple copies of {0} exist. Terminating.", i.ToString("D4"));
                    return;
                }

                fileList[i] = file[0];
            }

            // Ok, looks like we're good. Let's build GAME.DAT
            using (FileStream gameDatStream = File.Create(gameDat))
            {
                uint offset = 0;
                for (uint i = 0; i < numFiles; i++)
                {
                    Console.Write("Adding file " + Path.GetFileName(fileList[i]) + " ... ");

                    // Go to the next file entry
                    NextFileEntry(exeStream);

                    exeStream.Position += 4;

                    using (FileStream inStream = File.OpenRead(fileList[i]))
                    {
                        if (gameVersion == GameVersion.Wii)
                        {
                            PTStream.WriteUInt32BE(exeStream, offset);
                            PTStream.WriteUInt32BE(exeStream, (uint)inStream.Length);
                        }
                        else if (gameVersion == GameVersion.PSP)
                        {
                            PTStream.WriteUInt32(exeStream, offset);
                            PTStream.WriteUInt32(exeStream, (uint)inStream.Length);
                        }

                        PTStream.CopyPartToPadded(inStream, gameDatStream, (int)inStream.Length, 2048, 0);

                        offset += (uint)PTMethods.RoundUp((int)inStream.Length, 2048);
                    }

                    exeStream.Position += 12;

                    Console.WriteLine("OK");
                }
            }
        }
    }