public static KtxFile Load(Stream s, bool readKeyValuePairs) { using (BinaryReader br = new BinaryReader(s)) { KtxHeader header = ReadStruct <KtxHeader>(br); KtxKeyValuePair[] kvps = null; if (readKeyValuePairs) { int keyValuePairBytesRead = 0; List <KtxKeyValuePair> keyValuePairs = new List <KtxKeyValuePair>(); while (keyValuePairBytesRead < header.BytesOfKeyValueData) { int bytesRemaining = (int)(header.BytesOfKeyValueData - keyValuePairBytesRead); KtxKeyValuePair kvp = ReadNextKeyValuePair(br, out int read); keyValuePairBytesRead += read; keyValuePairs.Add(kvp); } kvps = keyValuePairs.ToArray(); } else { br.BaseStream.Seek(header.BytesOfKeyValueData, SeekOrigin.Current); // Skip over header data. } uint numberOfMipmapLevels = Math.Max(1, header.NumberOfMipmapLevels); uint numberOfArrayElements = Math.Max(1, header.NumberOfArrayElements); uint numberOfFaces = Math.Max(1, header.NumberOfFaces); uint baseWidth = Math.Max(1, header.PixelWidth); uint baseHeight = Math.Max(1, header.PixelHeight); uint baseDepth = Math.Max(1, header.PixelDepth); KtxMipmapLevel[] images = new KtxMipmapLevel[numberOfMipmapLevels]; for (int mip = 0; mip < numberOfMipmapLevels; mip++) { uint mipWidth = Math.Max(1, baseWidth / (uint)(Math.Pow(2, mip))); uint mipHeight = Math.Max(1, baseHeight / (uint)(Math.Pow(2, mip))); uint mipDepth = Math.Max(1, baseDepth / (uint)(Math.Pow(2, mip))); uint imageSize = br.ReadUInt32(); uint arrayElementSize = imageSize / numberOfArrayElements; KtxArrayElement[] arrayElements = new KtxArrayElement[numberOfArrayElements]; for (int arr = 0; arr < numberOfArrayElements; arr++) { uint faceSize = arrayElementSize / numberOfFaces; KtxFace[] faces = new KtxFace[numberOfFaces]; for (int face = 0; face < numberOfFaces; face++) { faces[face] = new KtxFace(br.ReadBytes((int)faceSize)); } arrayElements[arr] = new KtxArrayElement(faces); } images[mip] = new KtxMipmapLevel( mipWidth, mipHeight, mipDepth, imageSize, arrayElementSize, arrayElements); uint mipPaddingBytes = 3 - ((imageSize + 3) % 4); br.BaseStream.Seek(mipPaddingBytes, SeekOrigin.Current); } return(new KtxFile(header, kvps, images)); } }
public static unsafe Texture LoadTexture( GraphicsDevice gd, ResourceFactory factory, Stream assetStream, PixelFormat format) { KtxFile ktxTex2D = Load(assetStream, false); uint width = ktxTex2D.Header.PixelWidth; uint height = ktxTex2D.Header.PixelHeight; if (height == 0) { height = width; } uint arrayLayers = Math.Max(1, ktxTex2D.Header.NumberOfArrayElements); uint mipLevels = Math.Max(1, ktxTex2D.Header.NumberOfMipmapLevels); Texture ret = factory.CreateTexture(TextureDescription.Texture2D( width, height, mipLevels, arrayLayers, format, TextureUsage.Sampled)); Texture stagingTex = factory.CreateTexture(TextureDescription.Texture2D( width, height, mipLevels, arrayLayers, format, TextureUsage.Staging)); // Copy texture data into staging buffer for (uint level = 0; level < mipLevels; level++) { KtxMipmapLevel mipmap = ktxTex2D.Mipmaps[level]; for (uint layer = 0; layer < arrayLayers; layer++) { KtxArrayElement ktxLayer = mipmap.ArrayElements[layer]; Debug.Assert(ktxLayer.Faces.Length == 1); byte[] pixelData = ktxLayer.Faces[0].Data; fixed(byte *pixelDataPtr = &pixelData[0]) { gd.UpdateTexture(stagingTex, (IntPtr)pixelDataPtr, (uint)pixelData.Length, 0, 0, 0, mipmap.Width, mipmap.Height, 1, level, layer); } } } CommandList copyCL = factory.CreateCommandList(); copyCL.Begin(); for (uint level = 0; level < mipLevels; level++) { KtxMipmapLevel mipLevel = ktxTex2D.Mipmaps[level]; for (uint layer = 0; layer < arrayLayers; layer++) { copyCL.CopyTexture( stagingTex, 0, 0, 0, level, layer, ret, 0, 0, 0, level, layer, mipLevel.Width, mipLevel.Height, mipLevel.Depth, 1); } } copyCL.End(); gd.SubmitCommands(copyCL); gd.DisposeWhenIdle(copyCL); gd.DisposeWhenIdle(stagingTex); return(ret); }