public static BitmapTextureInteropDefinition CreateBitmapTextureInteropDefinition(DDSHeader header) { var result = new BitmapTextureInteropDefinition { Width = (short)header.Width, Height = (short)header.Height, Depth = (byte)Math.Max(1, header.Depth), MipmapCount = (byte)Math.Max(1, header.MipMapCount), HighResInSecondaryResource = 0, }; result.BitmapType = BitmapDdsFormatDetection.DetectType(header); result.Format = BitmapDdsFormatDetection.DetectFormat(header); result.D3DFormat = (int)header.PixelFormat.FourCC; result.Curve = BitmapImageCurve.xRGB; // find a way to properly determine that if (IsCompressedFormat(result.Format)) { result.Flags |= BitmapFlags.Compressed; } if (IsPowerOfTwo(header.Width) && IsPowerOfTwo(header.Height)) { result.Flags |= BitmapFlags.PowerOfTwoDimensions; } return(result); }
public XboxBitmap(BitmapTextureInteropDefinition definition, Bitmap.Image image) : base(definition, image) { UpdateFormat(image.Format); MultipleOfBlockDimension = Width % BlockDimension == 0 && Height % BlockDimension == 0; NotExact = Width != VirtualWidth || Height != VirtualHeight; InTile = Width <= MinimalBitmapSize / 2 && Height <= MinimalBitmapSize / 2; Offset = 0; }
public BaseBitmap(BitmapTextureInteropDefinition definition, Bitmap.Image image) { Height = definition.Height; Width = definition.Width; Depth = definition.Depth; MipMapCount = definition.MipmapCount != 0 ? definition.MipmapCount - 1 : 0; Type = definition.BitmapType; Flags = image.Flags; Curve = image.Curve; MipMapOffset = image.MipMapOffset; UpdateFormat(image.Format); }
public static BitmapTextureInteropDefinition CreateBitmapTextureInteropDefinition(BaseBitmap bitmap) { var result = new BitmapTextureInteropDefinition { Width = (short)bitmap.Width, Height = (short)bitmap.Height, Depth = (byte)bitmap.Depth, MipmapCount = (byte)(bitmap.MipMapCount + 1), HighResInSecondaryResource = 0, }; result.BitmapType = bitmap.Type; result.Format = bitmap.Format; switch (result.Format) { case BitmapFormat.Dxt1: result.D3DFormat = (int)D3DFormat.D3DFMT_DXT1; result.Flags |= BitmapFlags.Compressed; break; case BitmapFormat.Dxt3: result.D3DFormat = (int)D3DFormat.D3DFMT_DXT3; result.Flags |= BitmapFlags.Compressed; break; case BitmapFormat.Dxt5: result.D3DFormat = (int)D3DFormat.D3DFMT_DXT5; result.Flags |= BitmapFlags.Compressed; break; case BitmapFormat.Dxn: result.D3DFormat = (int)D3DFormat.D3DFMT_ATI2; result.Flags |= BitmapFlags.Compressed; break; default: result.D3DFormat = (int)D3DFormat.D3DFMT_UNKNOWN; break; } result.Curve = bitmap.Curve; if (IsPowerOfTwo(bitmap.Width) && IsPowerOfTwo(bitmap.Height)) { result.Flags |= BitmapFlags.PowerOfTwoDimensions; } return(result); }
public static Bitmap.Image CreateBitmapImageFromResourceDefinition(BitmapTextureInteropDefinition definition) { var result = new Bitmap.Image() { Signature = "mtib", Width = definition.Width, Height = definition.Height, Depth = (sbyte)definition.Depth, Format = definition.Format, Type = definition.BitmapType, MipmapCount = (sbyte)(definition.MipmapCount != 0 ? definition.MipmapCount - 1 : 0), Flags = definition.Flags, Curve = definition.Curve }; return(result); }
public static uint GetXboxBitmapD3DTextureType(BitmapTextureInteropDefinition bitmapResource) { switch (bitmapResource.BitmapType) { case BitmapType.Texture2D: case BitmapType.Array: return(1); case BitmapType.Texture3D: return(2); case BitmapType.CubeMap: return(3); default: throw new NotSupportedException(); } }
private static BaseBitmap ConvertGen3Bitmap(byte[] primaryData, byte[] secondaryData, BitmapTextureInteropDefinition definition, Bitmap bitmap, int imageIndex, bool isPaired, int pairIndex, BitmapTextureInteropDefinition otherDefinition, bool forDDS) { if (primaryData == null && secondaryData == null) { return(null); } using (var result = new MemoryStream()) { int mipLevelCount = definition.MipmapCount; int layerCount = definition.BitmapType == BitmapType.CubeMap ? 6 : definition.Depth; if (definition.BitmapType == BitmapType.Array && mipLevelCount > 1) { mipLevelCount = 1; definition.MipmapCount = 1; } if (!forDDS) { // order for d3d9, all faces first, then mipmaps for (int mipLevel = 0; mipLevel < mipLevelCount; mipLevel++) { for (int layerIndex = 0; layerIndex < layerCount; layerIndex++) { if (definition.BitmapType == BitmapType.CubeMap) // swap cubemap faces { if (layerIndex == 2) { layerIndex = 3; } else if (layerIndex == 3) { layerIndex = 2; } } ConvertGen3BitmapData(result, primaryData, secondaryData, definition, bitmap, imageIndex, mipLevel, layerIndex, isPaired, pairIndex, otherDefinition); if (definition.BitmapType == BitmapType.CubeMap) { if (layerIndex == 3) { layerIndex = 2; } else if (layerIndex == 2) { layerIndex = 3; } } } } } else { for (int layerIndex = 0; layerIndex < layerCount; layerIndex++) { if (definition.BitmapType == BitmapType.CubeMap) // swap cubemap faces { if (layerIndex == 2) { layerIndex = 3; } else if (layerIndex == 3) { layerIndex = 2; } } for (int mipLevel = 0; mipLevel < mipLevelCount; mipLevel++) { ConvertGen3BitmapData(result, primaryData, secondaryData, definition, bitmap, imageIndex, mipLevel, layerIndex, isPaired, pairIndex, otherDefinition); } if (definition.BitmapType == BitmapType.CubeMap) { if (layerIndex == 3) { layerIndex = 2; } else if (layerIndex == 2) { layerIndex = 3; } } } } var resultData = result.ToArray(); BaseBitmap resultBitmap = new BaseBitmap(bitmap.Images[imageIndex]); var newFormat = BitmapUtils.GetEquivalentBitmapFormat(bitmap.Images[imageIndex].Format); resultBitmap.UpdateFormat(newFormat); if (BitmapUtils.RequiresDecompression(resultBitmap.Format, (uint)resultBitmap.Width, (uint)resultBitmap.Height)) { resultBitmap.Format = BitmapFormat.A8R8G8B8; } if (!BitmapUtils.IsCompressedFormat(resultBitmap.Format)) { resultBitmap.Flags &= ~BitmapFlags.Compressed; } else { resultBitmap.Flags |= BitmapFlags.Compressed; } // // Update resource definition/image, truncate DXN to level 4x4 // resultBitmap.Data = resultData; if (resultBitmap.Format == BitmapFormat.Dxn) // wouldn't be required if d3d9 supported non power of two DXN and with mips less than 8x8 { GenerateCompressedMipMaps(resultBitmap); } if (resultBitmap.Type == BitmapType.Array) // for HO, arrays use the index of Texture3D { resultBitmap.Type = BitmapType.Texture3D; } return(resultBitmap); } }
private static void ConvertGen3BitmapData(Stream resultStream, byte[] primaryData, byte[] secondaryData, BitmapTextureInteropDefinition definition, Bitmap bitmap, int imageIndex, int level, int layerIndex, bool isPaired, int pairIndex, BitmapTextureInteropDefinition otherDefinition) { byte[] data; uint levelOffset; var d3dFormat = definition.D3DFormat; var isTiled = Direct3D.D3D9x.D3D.IsTiled(d3dFormat); uint blockWidth; uint blockHeight; uint alignedWidth = (uint)definition.Width >> level; uint alignedHeight = (uint)definition.Height >> level; if (alignedWidth < 1) { alignedWidth = 1; } if (alignedHeight < 1) { alignedHeight = 1; } uint alignedDepth = definition.Depth; var gpuFormat = XboxGraphics.XGGetGpuFormat(d3dFormat); uint bitsPerPixel = XboxGraphics.XGBitsPerPixelFromGpuFormat(gpuFormat); XboxGraphics.XGGetBlockDimensions(gpuFormat, out blockWidth, out blockHeight); XboxGraphics.XGPOINT point = new XboxGraphics.XGPOINT(); if (definition.MipmapCount > 1) { XboxGraphics.GetMipTailLevelOffsetCoords((uint)definition.Width, (uint)definition.Height, definition.Depth, (uint)level, gpuFormat, false, false, point); } var textureType = BitmapUtils.GetXboxBitmapD3DTextureType(definition); Direct3D.D3D9x.D3D.AlignTextureDimensions(ref alignedWidth, ref alignedHeight, ref alignedDepth, bitsPerPixel, gpuFormat, textureType, isTiled); if (level > 0) { // align to next power of two if (!Direct3D.D3D9x.D3D.IsPowerOfTwo((int)alignedWidth)) { alignedWidth = Direct3D.D3D9x.D3D.Log2Ceiling((int)alignedWidth); if (alignedWidth < 0) { alignedWidth = 0; } alignedWidth = 1u << (int)alignedWidth; } if (!Direct3D.D3D9x.D3D.IsPowerOfTwo((int)alignedHeight)) { alignedHeight = Direct3D.D3D9x.D3D.Log2Ceiling((int)alignedHeight); if (alignedHeight < 0) { alignedHeight = 0; } alignedHeight = 1u << (int)alignedHeight; } } // hacks when the point is outside of the first aligned texture, compute how many tiles you need and extract them (non-square only) if (point.X >= 32) { alignedWidth *= (uint)(1 + point.X / 32); } if (point.Y >= 32) { alignedHeight *= (uint)(1 + point.Y / 32); } uint texelPitch = blockWidth * blockHeight * bitsPerPixel / 8; uint size = alignedWidth * alignedHeight * bitsPerPixel / 8; // documentation says that each packed mip level should be aligned to 4KB, required to make untiling work smoothly size = (uint)((size + 0xFFF) & ~0xFFF); int tileOffset = 0; if (!isPaired) { bool useHighResBuffer = definition.HighResInSecondaryResource > 0; if ((level == 0 && useHighResBuffer) || primaryData == null) { levelOffset = BitmapUtils.GetXboxBitmapLevelOffset(definition, layerIndex, level); uint alignedSecondaryLength = (uint)((secondaryData.Length + 0x3FFF) & ~0x3FFF); data = new byte[alignedSecondaryLength]; Array.Copy(secondaryData, 0, data, 0, secondaryData.Length); } else { levelOffset = BitmapUtils.GetXboxBitmapLevelOffset(definition, layerIndex, level, useHighResBuffer); uint alignedPrimaryLength = (uint)((primaryData.Length + 0x3FFF) & ~0x3FFF); data = new byte[alignedPrimaryLength]; Array.Copy(primaryData, 0, data, 0, primaryData.Length); } } else { bool useHighResBuffer = definition.HighResInSecondaryResource > 0; var bitmap1 = pairIndex == 0 ? definition : otherDefinition; var bitmap2 = pairIndex == 0 ? otherDefinition : definition; if (level == 0 && useHighResBuffer) { levelOffset = BitmapUtils.GetXboxInterleavedBitmapOffset(bitmap1, bitmap2, layerIndex, level, pairIndex); uint alignedSecondaryLength = (uint)((secondaryData.Length + 0x3FFF) & ~0x3FFF); data = new byte[alignedSecondaryLength]; Array.Copy(secondaryData, 0, data, 0, secondaryData.Length); } else { levelOffset = BitmapUtils.GetXboxInterleavedBitmapOffset(bitmap1, bitmap2, layerIndex, level, pairIndex, useHighResBuffer); uint alignedPrimaryLength = (uint)((primaryData.Length + 0x3FFF) & ~0x3FFF); data = new byte[alignedPrimaryLength]; Array.Copy(primaryData, 0, data, 0, primaryData.Length); } } tileOffset += (int)levelOffset; byte[] tempResult = new byte[size]; // check if data has enough memory for the requested, size, sometimes it does not (truncated to save memory) uint copySize = size; if (size + tileOffset >= data.Length) { copySize = (uint)(data.Length - tileOffset); } Array.Copy(data, tileOffset, tempResult, 0, copySize); data = tempResult; uint nBlockWidth; uint nBlockHeight; if (isTiled) { // // Untile texture // byte[] result = new byte[size]; nBlockWidth = alignedWidth / blockWidth; nBlockHeight = alignedHeight / blockHeight; for (int i = 0; i < nBlockHeight; i++) { for (int j = 0; j < nBlockWidth; j++) { int destinationIndex = (int)(i * nBlockWidth + j); // offset in terms block int destinationOffset = (int)(destinationIndex * texelPitch); uint tiledIndex = XboxGraphics.XGAddress2DTiledOffset((uint)j, (uint)i, nBlockWidth, texelPitch); // returns offset in terms of block uint tiledOffset = tiledIndex * texelPitch; Array.Copy(data, tiledOffset, result, destinationOffset, texelPitch); } } data = result; } // find level size aligned to block size int levelWidth = definition.Width >> level; int levelHeight = definition.Height >> level; if (levelWidth < 1) { levelWidth = 1; } if (levelHeight < 1) { levelHeight = 1; } if (levelWidth % blockWidth != 0) { levelWidth = (int)(levelWidth + blockWidth - levelWidth % blockWidth); } if (levelHeight % blockHeight != 0) { levelHeight = (int)(levelHeight + blockHeight - levelHeight % blockHeight); } byte[] finalData = new byte[levelWidth * levelHeight * bitsPerPixel >> 3]; nBlockWidth = (uint)(levelWidth / blockWidth); nBlockHeight = (uint)(levelHeight / blockHeight); uint sliceBlockWidth = alignedWidth / blockWidth; // skip these loops if the bitmap is already the proper format if (point.X != 0 || point.Y != 0 || finalData.Length != data.Length) { for (int i = 0; i < nBlockHeight; i++) { for (int j = 0; j < nBlockWidth; j++) { uint offset = (uint)(((i + point.Y) * sliceBlockWidth) + j + point.X) * texelPitch; uint destOffset = (uint)((i * nBlockWidth) + j) * texelPitch; Array.Copy(data, offset, finalData, destOffset, texelPitch); } } } else { Array.Copy(data, 0, finalData, 0, data.Length); } XboxGraphics.XGEndianSwapSurface(d3dFormat, finalData); uint actualWidth = (uint)definition.Width >> level; uint actualHeight = (uint)definition.Height >> level; if (actualWidth < 1) { actualWidth = 1; } if (actualHeight < 1) { actualHeight = 1; } bool requireDecompression = BitmapUtils.RequiresDecompression(BitmapUtils.GetEquivalentBitmapFormat(bitmap.Images[imageIndex].Format), (uint)definition.Width, (uint)definition.Height); finalData = BitmapUtils.ConvertXboxFormats(finalData, actualWidth, actualHeight, bitmap.Images[imageIndex].Format, requireDecompression); resultStream.Write(finalData, 0, finalData.Length); }
public DDSHeader(BitmapTextureInteropDefinition definition) { CreateHeaderFromType(definition.Height, definition.Width, definition.Depth, definition.MipmapCount, definition.Format, definition.BitmapType); }
public static uint GetXboxBitmapLevelOffset(BitmapTextureInteropDefinition bitmapResource, int ArrayIndex, int Level, bool hasHighResData = false) { uint blockWidth, blockHeight; uint layerSize; uint offset = 0; uint levelSizeBytes; uint unknownType = GetXboxBitmapD3DTextureType(bitmapResource); var format = XboxGraphics.XGGetGpuFormat(bitmapResource.D3DFormat); uint bitsPerPixel = XboxGraphics.XGBitsPerPixelFromGpuFormat(format); bool isTiled = Direct3D.D3D9x.D3D.IsTiled(bitmapResource.D3DFormat); XboxGraphics.XGGetBlockDimensions(format, out blockWidth, out blockHeight); int levels = bitmapResource.MipmapCount == 0 ? Direct3D.D3D9x.D3D.GetMaxMipLevels(bitmapResource.Width, bitmapResource.Height, bitmapResource.Depth, 0) : bitmapResource.MipmapCount; bool isPacked = levels > 1; uint width = (uint)bitmapResource.Width; uint height = (uint)bitmapResource.Height; uint depth = (uint)bitmapResource.Depth; uint levelWidth = width; uint levelHeight = height; uint levelDepth = depth; if (Level > 0 || (isPacked && (levelWidth <= 16 || levelHeight <= 16))) { uint arrayStride = 1; if (bitmapResource.BitmapType == BitmapType.CubeMap || bitmapResource.BitmapType == BitmapType.Array) { int arrayFactor = bitmapResource.BitmapType == BitmapType.Array ? 2 : 0; uint actualDepth = (uint)(bitmapResource.BitmapType == BitmapType.CubeMap ? 6 : bitmapResource.Depth); arrayStride = Direct3D.D3D9x.D3D.NextMultipleOf(actualDepth, 1u << arrayFactor); } uint alignedWidth = 0; uint alignedHeight = 0; uint alignedDepth = 0; for (int i = 0; i < Level; i++) { levelWidth = width >> i; levelHeight = height >> i; if (levelWidth < 1) { levelWidth = 1; } if (levelHeight < 1) { levelHeight = 1; } alignedDepth = levelDepth; alignedWidth = levelWidth; alignedHeight = levelHeight; Direct3D.D3D9x.D3D.AlignTextureDimensions(ref alignedWidth, ref alignedHeight, ref alignedDepth, bitsPerPixel, format, unknownType, isTiled); // if not first mip level, align to next power of two if (i > 0) { if (!Direct3D.D3D9x.D3D.IsPowerOfTwo((int)alignedWidth)) { alignedWidth = Direct3D.D3D9x.D3D.Log2Ceiling((int)alignedWidth); if (alignedWidth < 0) { alignedWidth = 0; } alignedWidth = 1u << (int)alignedWidth; } if (!Direct3D.D3D9x.D3D.IsPowerOfTwo((int)alignedHeight)) { alignedHeight = Direct3D.D3D9x.D3D.Log2Ceiling((int)alignedHeight); if (alignedHeight < 0) { alignedHeight = 0; } alignedHeight = 1u << (int)alignedHeight; } } layerSize = (bitsPerPixel * alignedWidth * alignedHeight) / 8; // if the bitmap uses the high resolution buffer, the first level is stored there so no need to add it to the running offset if (hasHighResData && i == 0) { if (Level == 1) { levelWidth = width >> 1; levelHeight = height >> 1; if (levelWidth < 1) { levelWidth = 1; } if (levelHeight < 1) { levelHeight = 1; } alignedDepth = levelDepth; alignedWidth = levelWidth; alignedHeight = levelHeight; Direct3D.D3D9x.D3D.AlignTextureDimensions(ref alignedWidth, ref alignedHeight, ref alignedDepth, bitsPerPixel, format, unknownType, isTiled); } continue; } if ((levelWidth <= 16 || levelHeight <= 16) && isPacked) { break; } else { if (unknownType == 2) { levelSizeBytes = Direct3D.D3D9x.D3D.NextMultipleOf(alignedDepth * layerSize, 0x1000); } else { levelSizeBytes = alignedDepth * Direct3D.D3D9x.D3D.NextMultipleOf(layerSize, 0x1000); } offset += arrayStride * levelSizeBytes; } } // when array index is > 0, we need to add an offset into the right array layer, outside of the loop since the loop computes the offset for all layers if (ArrayIndex > 0) { alignedDepth = depth; alignedWidth = width >> Level; alignedHeight = height >> Level; if (alignedWidth < 1) { alignedWidth = 1; } if (alignedHeight < 1) { alignedHeight = 1; } Direct3D.D3D9x.D3D.AlignTextureDimensions(ref alignedWidth, ref alignedHeight, ref alignedDepth, bitsPerPixel, format, unknownType, isTiled); // if not first mip level, align to next power of two if (Level > 0) { if (!Direct3D.D3D9x.D3D.IsPowerOfTwo((int)alignedWidth)) { alignedWidth = Direct3D.D3D9x.D3D.Log2Ceiling((int)alignedWidth); if (alignedWidth < 0) { alignedWidth = 0; } alignedWidth = 1u << (int)alignedWidth; } if (!Direct3D.D3D9x.D3D.IsPowerOfTwo((int)alignedHeight)) { alignedHeight = Direct3D.D3D9x.D3D.Log2Ceiling((int)alignedHeight); if (alignedHeight < 0) { alignedHeight = 0; } alignedHeight = 1u << (int)alignedHeight; } } uint size = alignedWidth * alignedHeight * bitsPerPixel / 8; uint nextLevelSize = Direct3D.D3D9x.D3D.NextMultipleOf(size, 0x1000); offset += (uint)(ArrayIndex * nextLevelSize); } } else { levelWidth = width; levelHeight = height; levelDepth = depth; Direct3D.D3D9x.D3D.AlignTextureDimensions( ref levelWidth, ref levelHeight, ref levelDepth, bitsPerPixel, format, unknownType, isTiled); if (!isTiled && !(bitmapResource.BitmapType == BitmapType.Array) && !(isPacked) && unknownType == 1 && bitmapResource.MipmapCount < 1) { levelHeight = Direct3D.D3D9x.D3D.NextMultipleOf(height, blockHeight); } layerSize = (bitsPerPixel * levelWidth * levelHeight) >> 3; levelSizeBytes = Direct3D.D3D9x.D3D.NextMultipleOf(layerSize, 0x1000); offset += levelSizeBytes * (uint)ArrayIndex; } return(offset); }
public static uint GetXboxInterleavedBitmapOffset(BitmapTextureInteropDefinition bitmap1, BitmapTextureInteropDefinition bitmap2, int arrayIndex, int level, int currentBitmapIndex, bool hasHighResData = false) { /* * Block size, bits per pixel, tiling and formats are the same, also texture must be square. */ uint offset = 0; var format = XboxGraphics.XGGetGpuFormat(bitmap1.D3DFormat); uint bitsPerPixel = XboxGraphics.XGBitsPerPixelFromGpuFormat(format); bool isTiled = Direct3D.D3D9x.D3D.IsTiled(bitmap1.D3DFormat); XboxGraphics.XGGetBlockDimensions(format, out uint blockWidth, out blockWidth); BitmapTextureInteropDefinition currentBitmap = currentBitmapIndex == 0 ? bitmap1 : bitmap2; BitmapTextureInteropDefinition otherBitmap = currentBitmapIndex == 0 ? bitmap2 : bitmap1; uint dimension = (uint)currentBitmap.Width; uint depth = (uint)currentBitmap.Depth; uint levelDimension = dimension; uint levelDepth = depth; uint tileSize = (blockWidth * blockWidth * 32 * 32 * bitsPerPixel) >> 3; uint arrayStride = 1; if (currentBitmap.BitmapType == BitmapType.CubeMap || currentBitmap.BitmapType == BitmapType.Array) { int arrayFactor = currentBitmap.BitmapType == BitmapType.Array ? 2 : 0; uint actualDepth = (uint)(currentBitmap.BitmapType == BitmapType.CubeMap ? 6 : currentBitmap.Depth); arrayStride = Direct3D.D3D9x.D3D.NextMultipleOf(actualDepth, 1u << arrayFactor); } // assume power of two for now bool useInterleavedOffset; if (currentBitmap.Width == otherBitmap.Width) { useInterleavedOffset = currentBitmapIndex != 0; } else { useInterleavedOffset = currentBitmap.Width < otherBitmap.Width; } if (useInterleavedOffset) { if ((levelDimension >> level) <= 64) { offset += tileSize / 2; } } if (bitmap1.Width > bitmap2.Width) { if (useInterleavedOffset) { // compute used data from the other image if (currentBitmap.HighResInSecondaryResource > 0) { if (level == 0) { offset += (uint)(arrayStride * otherBitmap.Width * otherBitmap.Width * bitsPerPixel) / 8; } } if (currentBitmap.Width >> level <= 64) { // compute first level that can fit mips int lowerBound = currentBitmap.Width > 16 ? 64 : 16; int targetLevel = 0; uint tempWidth = (uint)bitmap1.Width; do { targetLevel++; tempWidth >>= 1; if (tempWidth < 1) { tempWidth = 1; } }while (tempWidth > lowerBound && targetLevel <= bitmap1.MipmapCount); if (targetLevel > 0) { offset += GetXboxBitmapLevelOffset(bitmap1, 0, targetLevel, bitmap1.HighResInSecondaryResource > 0); } } else { if (bitmap2.Width >> level <= 64) { // compute first level that can fit mips int targetLevel = 0; uint tempWidth = (uint)bitmap1.Width; do { targetLevel++; tempWidth >>= 1; if (tempWidth < 1) { tempWidth = 1; } }while (tempWidth > (bitmap2.Width >> level) && targetLevel <= bitmap1.MipmapCount); if (targetLevel > 0) { offset += GetXboxBitmapLevelOffset(bitmap1, 0, targetLevel, bitmap1.HighResInSecondaryResource > 0); } } } } else { offset = 0; } } else if (bitmap1.Width == bitmap2.Width) { if (bitmap1.Width > 64 && level == 0 && useInterleavedOffset) { offset += arrayStride * tileSize; } if (bitmap1.Width > 128) { throw new Exception("FIX ME"); } } else { if (useInterleavedOffset) { // compute used data from the other image if (currentBitmap.HighResInSecondaryResource > 0) { if (level == 0) { offset += (uint)(arrayStride * otherBitmap.Width * otherBitmap.Width * bitsPerPixel) / 8; } } if (currentBitmap.Width >> level <= 64) { // compute first level that can fit mips int lowerBound = currentBitmap.Width > 16 ? 64 : 16; int targetLevel = 0; uint tempWidth = (uint)bitmap2.Width; do { targetLevel++; tempWidth >>= 1; if (tempWidth < 1) { tempWidth = 1; } }while (tempWidth > lowerBound && targetLevel <= bitmap2.MipmapCount); if (targetLevel > 0) { offset += GetXboxBitmapLevelOffset(bitmap2, 0, targetLevel, bitmap2.HighResInSecondaryResource > 0); } } else { if (bitmap1.Width >> level <= 64) { // compute first level that can fit mips int targetLevel = 0; uint tempWidth = (uint)bitmap2.Width; do { targetLevel++; tempWidth >>= 1; if (tempWidth < 1) { tempWidth = 1; } }while (tempWidth > (bitmap1.Width >> level) && targetLevel <= bitmap2.MipmapCount); if (targetLevel > 0) { offset += GetXboxBitmapLevelOffset(bitmap2, 0, targetLevel, bitmap2.HighResInSecondaryResource > 0); } } } } else { offset = 0; } } offset += GetXboxBitmapLevelOffset(currentBitmap, arrayIndex, level, hasHighResData); return(offset); }