forked from MonoGame/MonoGame
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TextureImporter.cs
212 lines (189 loc) · 9.61 KB
/
TextureImporter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// 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 System;
using System.IO;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Graphics.PackedVector;
using FreeImageAPI;
using MonoGame.Framework.Utilities;
using StbImageSharp;
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) };
var format = FreeImage.GetFileType(filename, 0);
var fBitmap = FreeImage.Load(format, filename, 0);
//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 == IntPtr.Zero)
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.Unload(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 IntPtr ConvertAndSwapChannels(IntPtr fBitmap, FREE_IMAGE_TYPE imageType)
{
IntPtr 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.Unload(fBitmap);
fBitmap = bgra;
break;
case FREE_IMAGE_TYPE.FIT_RGB16:
bgra = FreeImage.ConvertToType(fBitmap, FREE_IMAGE_TYPE.FIT_RGBA16, true);
FreeImage.Unload(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.Unload(fBitmap);
fBitmap = bgra;
break;
}
return fBitmap;
}
/// <summary>
/// Switches the red and blue channels
/// </summary>
/// <param name="fBitmap">image</param>
private static void SwitchRedAndBlueChannels(IntPtr 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.Unload(r);
FreeImage.Unload(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) };
ImageResult result;
using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
result = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha);
}
var face = new PixelBitmapContent<Color>(result.Width, result.Height);
face.SetPixelData(result.Data);
output.Faces[0].Add(face);
return output;
}
}
}