source: OniSplit/Motoko/TextureImporter.cs@ 1116

Last change on this file since 1116 was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 9.3 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4using Oni.Imaging;
5
6namespace Oni.Motoko
7{
8 internal class TextureImporter : Importer
9 {
10 private static readonly int[] powersOf2 = new[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 };
11 private static readonly Dictionary<string, TextureFormat> formatNames = new Dictionary<string, TextureFormat>(StringComparer.OrdinalIgnoreCase)
12 {
13 { "bgr32", TextureFormat.BGR },
14 { "bgr", TextureFormat.BGR },
15 { "bgra32", TextureFormat.RGBA },
16 { "rgba", TextureFormat.RGBA },
17 { "bgra4444", TextureFormat.BGRA4444 },
18 { "bgr555", TextureFormat.BGR555 },
19 { "bgra5551", TextureFormat.BGRA5551 },
20 { "dxt1", TextureFormat.DXT1 }
21 };
22
23 private readonly bool allowLargeTextures;
24 private readonly bool noMipMaps;
25 private readonly TextureFlags defaultFlags;
26 private readonly TextureFormat? defaultFormat;
27 private readonly string envmapName;
28
29 public static TextureFormat ParseTextureFormat(string name)
30 {
31 TextureFormat format;
32
33 if (!formatNames.TryGetValue(name, out format))
34 throw new FormatException(string.Format("Invalid texture format '{0}'", name));
35
36 return format;
37 }
38
39 public TextureImporter(TextureImporterOptions options)
40 {
41 if (options != null)
42 {
43 defaultFormat = options.Format;
44 envmapName = options.EnvironmentMap;
45 defaultFlags = options.Flags & ~TextureFlags.HasMipMaps;
46 noMipMaps = (options.Flags & TextureFlags.HasMipMaps) == 0;
47 allowLargeTextures = true;
48 }
49 }
50
51 public TextureImporter(string[] args)
52 {
53 foreach (string arg in args)
54 {
55 if (arg.StartsWith("-format:", StringComparison.Ordinal))
56 {
57 TextureFormat formatArg;
58 string formatName = arg.Substring(8);
59
60 if (!formatNames.TryGetValue(formatName, out formatArg))
61 throw new NotSupportedException(string.Format("Unknown texture format {0}", formatName));
62
63 defaultFormat = formatArg;
64 }
65 else if (arg.StartsWith("-envmap:", StringComparison.Ordinal))
66 {
67 string envmap = arg.Substring(8);
68
69 if (envmap.Length > 0)
70 envmapName = envmap;
71 }
72 else if (arg == "-large")
73 {
74 allowLargeTextures = true;
75 }
76 else if (arg == "-nouwrap")
77 {
78 defaultFlags |= TextureFlags.NoUWrap;
79 }
80 else if (arg == "-novwrap")
81 {
82 defaultFlags |= TextureFlags.NoVWrap;
83 }
84 else if (arg == "-nomipmaps")
85 {
86 noMipMaps = true;
87 }
88 }
89 }
90
91 public override void Import(string filePath, string outputDirPath)
92 {
93 var texture = new Texture
94 {
95 Name = DecodeFileName(filePath),
96 Flags = defaultFlags
97 };
98
99 LoadImage(texture, filePath);
100
101 if (envmapName != null)
102 {
103 texture.EnvMap = new Texture();
104 texture.EnvMap.Name = envmapName;
105 }
106
107 BeginImport();
108 TextureDatWriter.Write(texture, this);
109 Write(outputDirPath);
110 }
111
112 private void LoadImage(Texture texture, string filePath)
113 {
114 var surfaces = new List<Surface>();
115
116 switch (Path.GetExtension(filePath).ToLowerInvariant())
117 {
118 case ".tga":
119 surfaces.Add(TgaReader.Read(filePath));
120 break;
121 case ".dds":
122 surfaces.AddRange(DdsReader.Read(filePath, noMipMaps));
123 break;
124 default:
125#if !NETCORE
126 surfaces.Add(SysReader.Read(filePath));
127#endif
128 break;
129 }
130
131 if (surfaces.Count == 0)
132 throw new InvalidDataException(string.Format("Could not load image '{0}'", filePath));
133
134 var mainSurface = surfaces[0];
135
136 if (Array.IndexOf(powersOf2, mainSurface.Width) == -1)
137 Console.Error.WriteLine("Warning: Texture '{0}' width is not a power of 2", filePath);
138
139 if (Array.IndexOf(powersOf2, mainSurface.Height) == -1)
140 Console.Error.WriteLine("Warning: Texture '{0}' height is not a power of 2", filePath);
141
142 if (surfaces.Count == 1)
143 {
144 mainSurface.CleanupAlpha();
145 }
146
147 if (mainSurface.Format == SurfaceFormat.DXT1 && defaultFormat != null && defaultFormat != TextureFormat.DXT1)
148 {
149 //
150 // If the source image is DXT1 but the target is not then we can convert here
151 // to a more flexible image format.
152 //
153
154 for (int i = 0; i < surfaces.Count; i++)
155 surfaces[i] = surfaces[i].Convert(SurfaceFormat.RGBA);
156
157 mainSurface = surfaces[0];
158 }
159
160 if (!allowLargeTextures && (mainSurface.Width > 256 || mainSurface.Height > 256))
161 {
162 if (surfaces.Count == 1)
163 {
164 int sx = mainSurface.Width / 256;
165 int sy = mainSurface.Height / 256;
166
167 int s = Math.Max(sx, sy);
168
169 mainSurface = mainSurface.Resize(mainSurface.Width / s, mainSurface.Height / s);
170 surfaces[0] = mainSurface;
171 }
172 else
173 {
174 while (surfaces.Count > 0 && (surfaces[0].Width > 256 || surfaces[0].Height > 256))
175 surfaces.RemoveAt(0);
176
177 mainSurface = surfaces[0];
178 }
179 }
180
181 if (surfaces.Count == 1 && !noMipMaps && mainSurface.Format != SurfaceFormat.DXT1)
182 {
183 var surface = mainSurface;
184
185 while (surface.Width > 1 || surface.Height > 1)
186 {
187 int width = Math.Max(surface.Width >> 1, 1);
188 int height = Math.Max(surface.Height >> 1, 1);
189
190 surface = surface.Resize(width, height);
191
192 surfaces.Add(surface);
193 }
194 }
195
196 var convertToFormat = mainSurface.Format;
197
198 if (defaultFormat != null)
199 {
200 texture.Format = defaultFormat.Value;
201 convertToFormat = texture.Format.ToSurfaceFormat();
202 }
203 else
204 {
205 switch (mainSurface.Format)
206 {
207 case SurfaceFormat.BGRA4444:
208 texture.Format = TextureFormat.BGRA4444;
209 break;
210
211 case SurfaceFormat.BGRX5551:
212 texture.Format = TextureFormat.BGR555;
213 break;
214
215 case SurfaceFormat.BGR565:
216 texture.Format = TextureFormat.BGR555;
217 break;
218
219 case SurfaceFormat.BGRA5551:
220 texture.Format = TextureFormat.BGRA5551;
221 break;
222
223 case SurfaceFormat.BGRX:
224 case SurfaceFormat.RGBX:
225 texture.Format = TextureFormat.BGR;
226 convertToFormat = SurfaceFormat.BGRX;
227 break;
228
229 case SurfaceFormat.BGRA:
230 case SurfaceFormat.RGBA:
231 //
232 // We don't do RGBA32 unless specifically required because
233 // Oni needs a patch to support it.
234 //
235 texture.Format = TextureFormat.BGRA4444;
236 convertToFormat = SurfaceFormat.BGRA4444;
237 break;
238
239 case SurfaceFormat.DXT1:
240 texture.Format = TextureFormat.DXT1;
241 break;
242
243 default:
244 throw new NotSupportedException(string.Format("Image format {0} cannot be imported", mainSurface.Format));
245 }
246 }
247
248 if (convertToFormat != mainSurface.Format)
249 {
250 for (int i = 0; i < surfaces.Count; i++)
251 surfaces[i] = surfaces[i].Convert(convertToFormat);
252
253 mainSurface = surfaces[0];
254 }
255
256 if (texture.Format != TextureFormat.RGBA)
257 texture.Flags |= TextureFlags.SwapBytes;
258
259 texture.Width = mainSurface.Width;
260 texture.Height = mainSurface.Height;
261 texture.Surfaces.AddRange(surfaces);
262 }
263 }
264}
Note: See TracBrowser for help on using the repository browser.