Example #1
0
        /// <summary>
        /// Create new 2d KtxStructure from existing data
        /// </summary>
        /// <param name="glDataType">GlDataType</param>
        /// <param name="glPixelFormat">GlPixelFormat</param>
        /// <param name="glInternalFormat">GlInternalFormat</param>
        /// <param name="width">Width</param>
        /// <param name="height">Height</param>
        /// <param name="textureDatas">Texture datas</param>
        /// <param name="metadata">metadata</param>
        /// <returns>KtxStructure</returns>
        public static KtxStructure Create(GlDataType glDataType, GlPixelFormat glPixelFormat, GlInternalFormat glInternalFormat, uint width, uint height, List <byte[]> textureDatas, Dictionary <string, MetadataValue> metadata)
        {
            KtxHeader      header      = new KtxHeader(glDataType, glPixelFormat, glInternalFormat, width, height, (uint)textureDatas.Count, metadata);
            KtxTextureData textureData = new KtxTextureData(textureDatas);

            return(new KtxStructure(header, textureData));
        }
Example #2
0
        public static (bool isValid, string possibleError) CheckIfInputIsValid(MemoryStream memoryStream)
        {
            // Currently only header and metadata are validated properly, so texture data can still contain invalid values
            (bool isStreamValid, string possibleStreamError) = KtxValidators.GenericStreamValidation(memoryStream);
            if (!isStreamValid)
            {
                return(isValid : false, possibleError : possibleStreamError);
            }

            // We have to duplicate the data, since we have to both validate it and keep it for texture data validation step
            long memoryStreamPos = memoryStream.Position;

            (bool isHeaderValid, string possibleHeaderError) = KtxValidators.ValidateHeaderData(memoryStream);
            if (!isHeaderValid)
            {
                return(isValid : false, possibleError : possibleHeaderError);
            }

            memoryStream.Position = memoryStreamPos;
            KtxHeader tempHeader = new KtxHeader(memoryStream);

            (bool isTextureDataValid, string possibleTextureDataError) = KtxValidators.ValidateTextureData(memoryStream, tempHeader, (uint)(memoryStream.Length - memoryStream.Position));

            return(isValid : isTextureDataValid, possibleError : possibleTextureDataError);
        }
Example #3
0
        public static KtxStructure LoadInput(MemoryStream memoryStream)
        {
            // First we read the header
            KtxHeader header = new KtxHeader(memoryStream);
            // Then texture data
            KtxTextureData textureData = new KtxTextureData(header, memoryStream);

            // And combine those to one structure
            return(new KtxStructure(header, textureData));
        }
Example #4
0
        private static void GenericWrite(KtxHeader header, Action <uint> writeUint, Action <byte> writeByte, Action <byte[]> writeByteArray)
        {
            writeUint(Common.expectedEndianValue);
            writeUint(header.glTypeAsUint);
            writeUint(header.glTypeSizeAsUint);
            writeUint(header.glFormatAsUint);
            writeUint(header.glInternalFormatAsUint);
            writeUint(header.glBaseInternalFormatAsUint);
            writeUint(header.pixelWidth);
            writeUint(header.pixelHeight);
            writeUint(header.pixelDepth);
            writeUint(header.numberOfArrayElements);
            writeUint(header.numberOfFaces);
            writeUint(header.numberOfMipmapLevels);
            writeUint(GetTotalSizeOfMetadata(header.metadataDictionary));
            foreach (var pair in header.metadataDictionary)
            {
                uint keyLenght   = Common.GetLengthOfUtf8StringAsBytes(pair.Key) + 1;
                uint valueLength = pair.Value.GetSizeInBytes();
                uint totalLength = keyLenght + valueLength;
                writeUint(totalLength);
                writeByteArray(Common.GetUtf8StringAsBytes(pair.Key));
                writeByte(Common.nulByte);
                writeByteArray(pair.Value.GetAsBytes());
                if (pair.Value.isString)
                {
                    writeByte(Common.nulByte);
                }

                // Write padding if needed
                while (totalLength % 4 != 0)
                {
                    writeByte(Common.nulByte);
                    totalLength++;
                }
            }
        }
Example #5
0
        /// <summary>
        /// Constructor for texture data
        /// </summary>
        /// <param name="header">Header</param>
        /// <param name="stream">Stream for reading</param>
        public KtxTextureData(KtxHeader header, Stream stream)
        {
            //this.totalTextureDataLength = (uint)stream.Length;

            // Try to figure out texture type basic
            bool containsMipmaps = header.numberOfMipmapLevels > 1;

            if (header.numberOfArrayElements == 0 || header.numberOfArrayElements == 1)
            {
                // Is NOT texture array

                if (header.numberOfFaces == 0 || header.numberOfFaces == 1)
                {
                    // Is NOT cube texture

                    if (header.pixelDepth == 0 || header.pixelDepth == 1)
                    {
                        // Is not 3D texture

                        if (header.pixelHeight == 0 || header.pixelHeight == 1)
                        {
                            // 1D texture
                            this.textureType = containsMipmaps ? TextureTypeBasic.Basic1DWithMipmaps : TextureTypeBasic.Basic1DNoMipmaps;
                        }
                        else
                        {
                            // 2D texture
                            this.textureType = containsMipmaps ? TextureTypeBasic.Basic2DWithMipmaps : TextureTypeBasic.Basic2DNoMipmaps;
                        }
                    }
                    else
                    {
                        // Is 3D texture
                        this.textureType = containsMipmaps ? TextureTypeBasic.Basic3DWithMipmaps : TextureTypeBasic.Basic3DNoMipmaps;
                    }
                }
                else
                {
                    // Is cube texture
                }
            }
            else
            {
                // Is Texture array
            }

            uint mipmapLevels = header.numberOfMipmapLevels;

            if (mipmapLevels == 0)
            {
                mipmapLevels = 1;
            }

            // Since we know how many mipmap levels there are, allocate the capacity
            this.textureDataOfMipmapLevel = new List <byte[]>((int)mipmapLevels);

            // Check if length reads should be endian swapped
            bool shouldSwapEndianness = (header.endiannessValue != Common.expectedEndianValue);

            using (BinaryReader reader = new BinaryReader(stream, Encoding.UTF8, leaveOpen: true))
            {
                for (int i = 0; i < mipmapLevels; i++)
                {
                    uint amountOfDataInThisMipmapLevel = shouldSwapEndianness ? KtxBitFiddling.SwapEndian(reader.ReadUInt32()) : reader.ReadUInt32();
                    this.textureDataOfMipmapLevel.Add(reader.ReadBytes((int)amountOfDataInThisMipmapLevel));

                    // Skip possible padding bytes
                    while (amountOfDataInThisMipmapLevel % 4 != 0)
                    {
                        amountOfDataInThisMipmapLevel++;
                        // Read but ignore values
                        reader.ReadByte();
                    }
                }
            }
        }
Example #6
0
        public static (bool isValid, string possibleError) ValidateTextureData(MemoryStream memoryStream, KtxHeader header, uint expectedTextureDataSize)
        {
            // Use the memory stream in a binary reader.
            try
            {
                using (BinaryReader reader = new BinaryReader(memoryStream, Encoding.UTF8, leaveOpen: true))
                {
                    // Specs say that if value of certain things is zero (0) then it should be used as one (1)
                    uint mipmapLevels = (header.numberOfMipmapLevels == 0) ? 1 : header.numberOfMipmapLevels;

                    uint numberOfArrayElements = (header.numberOfArrayElements == 0) ? 1 : header.numberOfArrayElements;

                    uint pixelDepth = (header.pixelDepth == 0) ? 1 : header.pixelDepth;

                    uint pixelHeight = (header.pixelHeight == 0) ? 1 : header.pixelHeight;

                    uint totalLengthOfTextureDataSection = 0;

                    // Check if length reads should be endian swapped
                    bool shouldSwapEndianness = (header.endiannessValue != Common.expectedEndianValue);

                    // Check each mipmap level separately
                    for (uint u = 0; u < mipmapLevels; u++)
                    {
                        uint imageSize = shouldSwapEndianness ? KtxBitFiddling.SwapEndian(reader.ReadUInt32()) : reader.ReadUInt32();
                        totalLengthOfTextureDataSection += (imageSize + (uint)Common.sizeOfUint);
                        if (imageSize > expectedTextureDataSize || totalLengthOfTextureDataSection > expectedTextureDataSize)
                        {
                            return(isValid : false, "Texture data: More data than expected!");
                        }

                        // TODO: More checks!

                        // Read but do not use data for anything
                        reader.ReadBytes((int)imageSize);

                        // Skip possible padding bytes
                        while (imageSize % 4 != 0)
                        {
                            imageSize++;
                            // Read but ignore values
                            reader.ReadByte();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                return(isValid : false, e.ToString());
            }

            return(isValid : true, possibleError : "");
        }