/// <summary> /// Function to retrieve an image based on the current depth slice. /// </summary> /// <param name="sourceImage">The image to extract the depth slice from.</param> /// <param name="currentDepthSlice">The depth slice to extract.</param> /// <returns>A new image with the specified depth slice.</returns> public IGorgonImage GetDepthSliceAsImage(IGorgonImage sourceImage, int currentDepthSlice) { if (sourceImage.MipCount == 1) { return(sourceImage); } IGorgonImage result = new GorgonImage(new GorgonImageInfo(sourceImage, ImageType.Image2D) { Depth = 1 }); for (int mip = 0; mip < result.MipCount; ++mip) { int depthCount = sourceImage.GetDepthCount(mip); if (currentDepthSlice >= depthCount) { return(result); } IGorgonImageBuffer srcBuffer = sourceImage.Buffers[mip, currentDepthSlice]; IGorgonImageBuffer destBuffer = result.Buffers[mip]; srcBuffer.CopyTo(destBuffer); } return(result); }
/// <summary> /// Function to retrieve an image based on the current mip level. /// </summary> /// <param name="sourceImage">The image to extract the mip level from.</param> /// <param name="currentMipLevel">The mip level to extract.</param> /// <returns>A new image with the specified mip level.</returns> public IGorgonImage GetMipLevelAsImage(IGorgonImage sourceImage, int currentMipLevel) { if (sourceImage.MipCount == 1) { return(sourceImage); } int depthCount = 1; if (sourceImage.ImageType == ImageType.Image3D) { depthCount = sourceImage.GetDepthCount(currentMipLevel); } IGorgonImage result = new GorgonImage(new GorgonImageInfo(sourceImage) { Width = sourceImage.Buffers[currentMipLevel].Width, Height = sourceImage.Buffers[currentMipLevel].Height, Depth = depthCount, MipCount = 1 }); for (int array = 0; array < sourceImage.ArrayCount; ++array) { for (int depth = 0; depth < result.Depth; ++depth) { IGorgonImageBuffer srcBuffer = sourceImage.Buffers[currentMipLevel, sourceImage.ImageType == ImageType.Image3D ? depth : array]; IGorgonImageBuffer destBuffer = result.Buffers[0, sourceImage.ImageType == ImageType.Image3D ? depth : array]; srcBuffer.CopyTo(destBuffer); } } return(result); }
/// <summary> /// Function to convert the image to B4G4R4A4. /// </summary> /// <param name="baseImage">The base image to convert.</param> /// <param name="dithering">Dithering to apply to the converstion to B8G8R8A8.</param> /// <returns>The updated image.</returns> private static IGorgonImage ConvertToB4G4R4A4(IGorgonImage baseImage, ImageDithering dithering) { // This temporary image will be used to convert to B8G8R8A8. IGorgonImage newImage = baseImage; IGorgonImageInfo destInfo = new GorgonImageInfo(baseImage.ImageType, BufferFormat.B4G4R4A4_UNorm) { Depth = baseImage.Depth, Height = baseImage.Height, Width = baseImage.Width, ArrayCount = baseImage.ArrayCount, MipCount = baseImage.MipCount }; // This is our working buffer for B4G4R4A4. IGorgonImage destImage = new GorgonImage(destInfo); try { // If necessary, convert to B8G8R8A8. Otherwise, we'll just downsample directly. if ((newImage.Format != BufferFormat.B8G8R8A8_UNorm) && (newImage.Format != BufferFormat.R8G8B8A8_UNorm)) { newImage = baseImage.Clone(); ConvertToFormat(newImage, BufferFormat.B8G8R8A8_UNorm, dithering); } // The next step is to manually downsample to R4G4B4A4. // Because we're doing this manually, dithering won't be an option unless unless we've downsampled from a much higher bit format when converting to B8G8R8A8. for (int array = 0; array < newImage.ArrayCount; ++array) { for (int mip = 0; mip < newImage.MipCount; ++mip) { int depthCount = newImage.GetDepthCount(mip); for (int depth = 0; depth < depthCount; depth++) { IGorgonImageBuffer destBuffer = destImage.Buffers[mip, destInfo.ImageType == ImageType.Image3D ? depth : array]; IGorgonImageBuffer srcBuffer = newImage.Buffers[mip, newImage.ImageType == ImageType.Image3D ? depth : array]; ConvertPixelsToB4G4R4A4(destBuffer, srcBuffer); } } } destImage.CopyTo(baseImage); return(baseImage); } finally { destImage.Dispose(); if (newImage != baseImage) { newImage.Dispose(); } } }
/// <summary> /// Function to convert the image from B4G4R4A4. /// </summary> /// <param name="baseImage">The base image to convert.</param> /// <param name="destFormat">The destination format.</param> /// <returns>The updated image.</returns> private static IGorgonImage ConvertFromB4G4R4A4(IGorgonImage baseImage, BufferFormat destFormat) { // If we're converting to R8G8B8A8 or B8G8R8A8, then use those formats, otherwise, default to B8G8R8A8 as an intermediate buffer. BufferFormat tempFormat = ((destFormat != BufferFormat.B8G8R8A8_UNorm) && (destFormat != BufferFormat.R8G8B8A8_UNorm)) ? BufferFormat.B8G8R8A8_UNorm : destFormat; // Create an worker image in B8G8R8A8 format. IGorgonImageInfo destInfo = new GorgonImageInfo(baseImage.ImageType, tempFormat) { Depth = baseImage.Depth, Height = baseImage.Height, Width = baseImage.Width, ArrayCount = baseImage.ArrayCount, MipCount = baseImage.MipCount }; // Our destination image for B8G8R8A8 or R8G8B8A8. var destImage = new GorgonImage(destInfo); try { // We have to manually upsample from R4G4B4A4 to B8R8G8A8. // Because we're doing this manually, dithering won't be an option unless for (int array = 0; array < baseImage.ArrayCount; ++array) { for (int mip = 0; mip < baseImage.MipCount; ++mip) { int depthCount = baseImage.GetDepthCount(mip); for (int depth = 0; depth < depthCount; depth++) { IGorgonImageBuffer destBuffer = destImage.Buffers[mip, baseImage.ImageType == ImageType.Image3D ? depth : array]; IGorgonImageBuffer srcBuffer = baseImage.Buffers[mip, baseImage.ImageType == ImageType.Image3D ? depth : array]; ConvertPixelsFromB4G4R4A4(destBuffer, srcBuffer); } } } // If the destination format is not R8G8B8A8 or B8G8R8A8, then we need to do more conversion. if (destFormat != destImage.Format) { ConvertToFormat(destImage, destFormat); } // Update the base image with our worker image. destImage.CopyTo(baseImage); return(baseImage); } finally { destImage.Dispose(); } }
/// <summary> /// Function to copy an image onto another image, using the supplied alignment. /// </summary> /// <param name="srcImage">The image to copy.</param> /// <param name="destImage">The destination image.</param> /// <param name="startMip">The starting mip map level to copy.</param> /// <param name="startArrayOrDepth">The starting array index for 2D images, or depth slice for 3D images.</param> /// <param name="alignment">The alignment of the image, relative to the source image.</param> public void CopyTo(IGorgonImage srcImage, IGorgonImage destImage, int startMip, int startArrayOrDepth, Alignment alignment) { int mipCount = destImage.MipCount - startMip; int arrayCount = destImage.ArrayCount - (destImage.ImageType == ImageType.Image3D ? 0 : startArrayOrDepth); int minMipCount = mipCount.Min(srcImage.MipCount); int minArrayCount = arrayCount.Min(srcImage.ArrayCount); var size = new DX.Size2(srcImage.Width, srcImage.Height); for (int array = 0; array < minArrayCount; ++array) { for (int mip = 0; mip < minMipCount; ++mip) { int destDepthCount = destImage.GetDepthCount(mip + startMip); int minDepth = destDepthCount.Min(srcImage.GetDepthCount(mip)); for (int depth = 0; depth < minDepth; ++depth) { int destOffset; if (destImage.ImageType == ImageType.Image3D) { destOffset = depth + startArrayOrDepth; // We're at the end of the destination buffer, skip the rest of the slices. if (destOffset >= destDepthCount) { break; } } else { destOffset = array + startArrayOrDepth; } IGorgonImageBuffer srcBuffer = srcImage.Buffers[mip, srcImage.ImageType == ImageType.Image3D ? depth : array]; IGorgonImageBuffer destBuffer = destImage.Buffers[mip + startMip, destOffset]; // Clear the destination buffer before copying. destBuffer.Data.Fill(0); int minWidth = destBuffer.Width.Min(srcBuffer.Width); int minHeight = destBuffer.Height.Min(srcBuffer.Height); var copyRegion = new DX.Rectangle(0, 0, minWidth, minHeight); DX.Point startLoc = GetAnchorStart(new DX.Size2(minWidth, minHeight), ref size, alignment); srcBuffer.CopyTo(destBuffer, copyRegion, startLoc.X, startLoc.Y); } } } }
/// <summary> /// Function to update the depth slice count for a 3D image, or the array index count for a 2D/cube image. /// </summary> /// <param name="sourceImage">The image to update.</param> /// <param name="arrayOrDepthCount">The new depth or array count.</param> /// <returns>A new image with the specified depth/array count, or the same image if no changes were made.</returns> public IGorgonImage ChangeArrayOrDepthCount(IGorgonImage sourceImage, int arrayOrDepthCount) { int currentArrayOrDepth = sourceImage.ImageType == ImageType.Image3D ? sourceImage.Depth : sourceImage.ArrayCount; int depthCount = sourceImage.ImageType == ImageType.Image3D ? arrayOrDepthCount : 1; int arrayCount = sourceImage.ImageType != ImageType.Image3D ? arrayOrDepthCount : 1; if (currentArrayOrDepth == arrayOrDepthCount) { return(sourceImage); } IGorgonImage newImage = new GorgonImage(new GorgonImageInfo(sourceImage) { Depth = depthCount, ArrayCount = arrayCount }); for (int array = 0; array < arrayCount.Min(sourceImage.ArrayCount); ++array) { for (int mip = 0; mip < sourceImage.MipCount; ++mip) { for (int depth = 0; depth < depthCount.Min(sourceImage.GetDepthCount(mip)); ++depth) { IGorgonImageBuffer srcBuffer = sourceImage.Buffers[mip, sourceImage.ImageType == ImageType.Image3D ? depth : array]; IGorgonImageBuffer destBuffer = newImage.Buffers[mip, sourceImage.ImageType == ImageType.Image3D ? depth : array]; srcBuffer.CopyTo(destBuffer); } depthCount >>= 1; if (depthCount < 1) { depthCount = 1; } } } return(newImage); }