210 lines
9.6 KiB
C#
210 lines
9.6 KiB
C#
// MonoGame - Copyright (C) The MonoGame Team
|
|
// This file is subject to the terms and conditions defined in
|
|
// file 'LICENSE.txt', which is part of this source code package.
|
|
|
|
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
|
|
using Microsoft.Xna.Framework.Graphics.PackedVector;
|
|
using FreeImageAPI;
|
|
using System.IO;
|
|
using MonoGame.Utilities;
|
|
|
|
namespace Microsoft.Xna.Framework.Content.Pipeline
|
|
{
|
|
/// <summary>
|
|
/// Provides methods for reading texture files for use in the Content Pipeline.
|
|
/// </summary>
|
|
[ContentImporter(".bmp", // Bitmap Image File
|
|
".cut", // Dr Halo CUT
|
|
".dds", // Direct Draw Surface
|
|
".g3", // Raw Fax G3
|
|
".hdr", // RGBE
|
|
".gif", // Graphcis Interchange Format
|
|
".ico", // Microsoft Windows Icon
|
|
".iff", // Interchange File Format
|
|
".jbg", ".jbig", // JBIG
|
|
".jng", ".jpg", ".jpeg", ".jpe", ".jif", ".jfif", ".jfi", // JPEG
|
|
".jp2", ".j2k", ".jpf", ".jpx", ".jpm", ".mj2", // JPEG 2000
|
|
".jxr", ".hdp", ".wdp", // JPEG XR
|
|
".koa", ".gg", // Koala
|
|
".pcd", // Kodak PhotoCD
|
|
".mng", // Multiple-Image Network Graphics
|
|
".pcx", //Personal Computer Exchange
|
|
".pbm", ".pgm", ".ppm", ".pnm", // Netpbm
|
|
".pfm", // Printer Font Metrics
|
|
".png", //Portable Network Graphics
|
|
".pict", ".pct", ".pic", // PICT
|
|
".psd", // Photoshop
|
|
".3fr", ".ari", ".arw", ".bay", ".crw", ".cr2", ".cap", ".dcs", // RAW
|
|
".dcr", ".dng", ".drf", ".eip", ".erf", ".fff", ".iiq", ".k25", // RAW
|
|
".kdc", ".mdc", ".mef", ".mos", ".mrw", ".nef", ".nrw", ".obm", // RAW
|
|
".orf", ".pef", ".ptx", ".pxn", ".r3d", ".raf", ".raw", ".rwl", // RAW
|
|
".rw2", ".rwz", ".sr2", ".srf", ".srw", ".x3f", // RAW
|
|
".ras", ".sun", // Sun RAS
|
|
".sgi", ".rgba", ".bw", ".int", ".inta", // Silicon Graphics Image
|
|
".tga", // Truevision TGA/TARGA
|
|
".tiff", ".tif", // Tagged Image File Format
|
|
".wbmp", // Wireless Application Protocol Bitmap Format
|
|
".webp", // WebP
|
|
".xbm", // X BitMap
|
|
".xpm", // X PixMap
|
|
DisplayName = "Texture Importer - MonoGame", DefaultProcessor = "TextureProcessor")]
|
|
public class TextureImporter : ContentImporter<TextureContent>
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of TextureImporter.
|
|
/// </summary>
|
|
public TextureImporter( )
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called by the XNA Framework when importing a texture file to be used as a game asset. This is the method called by the XNA Framework when an asset is to be imported into an object that can be recognized by the Content Pipeline.
|
|
/// </summary>
|
|
/// <param name="filename">Name of a game asset file.</param>
|
|
/// <param name="context">Contains information for importing a game asset, such as a logger interface.</param>
|
|
/// <returns>Resulting game asset.</returns>
|
|
public override TextureContent Import(string filename, ContentImporterContext context)
|
|
{
|
|
var ext = Path.GetExtension(filename).ToLower();
|
|
|
|
// Special case for loading some formats
|
|
switch (ext)
|
|
{
|
|
case ".dds":
|
|
return DdsLoader.Import(filename, context);
|
|
case ".bmp":
|
|
return LoadImage(filename);
|
|
}
|
|
|
|
var output = new Texture2DContent { Identity = new ContentIdentity(filename) };
|
|
|
|
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
|
|
var fBitmap = FreeImage.LoadEx(filename, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
|
|
//if freeimage can not recognize the image type
|
|
if(format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
|
|
throw new ContentLoadException("TextureImporter failed to load '" + filename + "'");
|
|
//if freeimage can recognize the file headers but can't read its contents
|
|
else if(fBitmap.IsNull)
|
|
throw new InvalidContentException("TextureImporter couldn't understand the contents of '" + filename + "'", output.Identity);
|
|
BitmapContent face = null;
|
|
var height = (int) FreeImage.GetHeight(fBitmap);
|
|
var width = (int) FreeImage.GetWidth(fBitmap);
|
|
//uint bpp = FreeImage.GetBPP(fBitmap);
|
|
var imageType = FreeImage.GetImageType(fBitmap);
|
|
|
|
// Swizzle channels and expand to include an alpha channel
|
|
fBitmap = ConvertAndSwapChannels(fBitmap, imageType);
|
|
|
|
// The bits per pixel and image type may have changed
|
|
uint bpp = FreeImage.GetBPP(fBitmap);
|
|
imageType = FreeImage.GetImageType(fBitmap);
|
|
var pitch = (int) FreeImage.GetPitch(fBitmap);
|
|
var redMask = FreeImage.GetRedMask(fBitmap);
|
|
var greenMask = FreeImage.GetGreenMask(fBitmap);
|
|
var blueMask = FreeImage.GetBlueMask(fBitmap);
|
|
|
|
// Create the byte array for the data
|
|
byte[] bytes = new byte[((width * height * bpp - 1) / 8) + 1];
|
|
|
|
//Converts the pixel data to bytes, do not try to use this call to switch the color channels because that only works for 16bpp bitmaps
|
|
FreeImage.ConvertToRawBits(bytes, fBitmap, pitch, bpp, redMask, greenMask, blueMask, true);
|
|
// Create the Pixel bitmap content depending on the image type
|
|
switch(imageType)
|
|
{
|
|
//case FREE_IMAGE_TYPE.FIT_BITMAP:
|
|
default:
|
|
face = new PixelBitmapContent<Color>(width, height);
|
|
break;
|
|
case FREE_IMAGE_TYPE.FIT_RGBA16:
|
|
face = new PixelBitmapContent<Rgba64>(width, height);
|
|
break;
|
|
case FREE_IMAGE_TYPE.FIT_RGBAF:
|
|
face = new PixelBitmapContent<Vector4>(width, height);
|
|
break;
|
|
}
|
|
FreeImage.UnloadEx(ref fBitmap);
|
|
|
|
face.SetPixelData(bytes);
|
|
output.Faces[0].Add(face);
|
|
return output;
|
|
}
|
|
/// <summary>
|
|
/// Expands images to have an alpha channel and swaps red and blue channels
|
|
/// </summary>
|
|
/// <param name="fBitmap">Image to process</param>
|
|
/// <param name="imageType">Type of the image for the procedure</param>
|
|
/// <returns></returns>
|
|
private static FIBITMAP ConvertAndSwapChannels(FIBITMAP fBitmap, FREE_IMAGE_TYPE imageType)
|
|
{
|
|
FIBITMAP bgra;
|
|
switch (imageType)
|
|
{
|
|
// Return BGRA images as is
|
|
|
|
case FREE_IMAGE_TYPE.FIT_RGBAF:
|
|
case FREE_IMAGE_TYPE.FIT_RGBA16:
|
|
break;
|
|
|
|
// Add an alpha channel to BGRA images without one
|
|
|
|
case FREE_IMAGE_TYPE.FIT_RGBF:
|
|
bgra = FreeImage.ConvertToType(fBitmap, FREE_IMAGE_TYPE.FIT_RGBAF, true);
|
|
FreeImage.UnloadEx(ref fBitmap);
|
|
fBitmap = bgra;
|
|
break;
|
|
|
|
case FREE_IMAGE_TYPE.FIT_RGB16:
|
|
bgra = FreeImage.ConvertToType(fBitmap, FREE_IMAGE_TYPE.FIT_RGBA16, true);
|
|
FreeImage.UnloadEx(ref fBitmap);
|
|
fBitmap = bgra;
|
|
break;
|
|
|
|
|
|
// Add an alpha channel to RGB images
|
|
// Swap the red and blue channels of RGBA images
|
|
|
|
default:
|
|
// Bitmap and other formats are converted to 32-bit by default
|
|
bgra = FreeImage.ConvertTo32Bits(fBitmap);
|
|
SwitchRedAndBlueChannels(bgra);
|
|
FreeImage.UnloadEx(ref fBitmap);
|
|
fBitmap = bgra;
|
|
break;
|
|
}
|
|
|
|
return fBitmap;
|
|
}
|
|
/// <summary>
|
|
/// Switches the red and blue channels
|
|
/// </summary>
|
|
/// <param name="fBitmap">image</param>
|
|
private static void SwitchRedAndBlueChannels(FIBITMAP fBitmap)
|
|
{
|
|
var r = FreeImage.GetChannel(fBitmap, FREE_IMAGE_COLOR_CHANNEL.FICC_RED);
|
|
var b = FreeImage.GetChannel(fBitmap, FREE_IMAGE_COLOR_CHANNEL.FICC_BLUE);
|
|
FreeImage.SetChannel(fBitmap, b, FREE_IMAGE_COLOR_CHANNEL.FICC_RED);
|
|
FreeImage.SetChannel(fBitmap, r, FREE_IMAGE_COLOR_CHANNEL.FICC_BLUE);
|
|
FreeImage.UnloadEx(ref r);
|
|
FreeImage.UnloadEx(ref b);
|
|
}
|
|
|
|
// Loads BMP using StbSharp. This allows us to load BMP files containing BITMAPV4HEADER and BITMAPV5HEADER
|
|
// structures, which FreeImage does not support.
|
|
TextureContent LoadImage(string filename)
|
|
{
|
|
var output = new Texture2DContent { Identity = new ContentIdentity(filename) };
|
|
|
|
int width, height, comp;
|
|
byte[] data = null;
|
|
using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
|
|
data = ImageReader.Read(stream, out width, out height, out comp, Imaging.STBI_rgb_alpha);
|
|
|
|
var face = new PixelBitmapContent<Color>(width, height);
|
|
face.SetPixelData(data);
|
|
output.Faces[0].Add(face);
|
|
|
|
return output;
|
|
}
|
|
}
|
|
}
|