source: OniSplit/Motoko/TextureXmlImporter.cs

Last change on this file 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: 7.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Globalization;
4using System.IO;
5using System.Xml;
6using Oni.Imaging;
7using Oni.Metadata;
8using Oni.Xml;
9
10namespace Oni.Motoko
11{
12 internal class TextureXmlImporter
13 {
14 private readonly XmlImporter importer;
15 private readonly XmlReader xml;
16 private readonly string filePath;
17
18 public TextureXmlImporter(XmlImporter importer, XmlReader xml, string filePath)
19 {
20 this.importer = importer;
21 this.xml = xml;
22 this.filePath = filePath;
23 }
24
25 public void Import()
26 {
27 xml.ReadStartElement();
28
29 var name = Importer.DecodeFileName(Path.GetFileNameWithoutExtension(filePath));
30 var flags = MetaEnum.Parse<InstanceMetadata.TXMPFlags>(xml.ReadElementContentAsString("Flags", ""));
31 var format = MetaEnum.Parse<InstanceMetadata.TXMPFormat>(xml.ReadElementContentAsString("Format", ""));
32
33 int width = 0;
34 int height = 0;
35 int speed = 1;
36
37 if (xml.IsStartElement("Width"))
38 width = xml.ReadElementContentAsInt();
39
40 if (xml.IsStartElement("Height"))
41 height = xml.ReadElementContentAsInt();
42
43 string envMapName = null;
44
45 if (xml.IsStartElement("EnvMap"))
46 {
47 envMapName = xml.ReadElementContentAsString();
48
49 if (envMapName != null && envMapName.Length == 0)
50 envMapName = null;
51 }
52
53 if (xml.IsStartElement("Speed"))
54 speed = xml.ReadElementContentAsInt();
55
56 var imageFilePaths = new List<string>();
57 var inputDirPath = Path.GetDirectoryName(filePath);
58
59 while (xml.IsStartElement("Image"))
60 {
61 string imageFilePath = xml.ReadElementContentAsString();
62
63 if (!Path.IsPathRooted(imageFilePath))
64 imageFilePath = Path.Combine(inputDirPath, imageFilePath);
65
66 if (!File.Exists(imageFilePath))
67 throw new IOException(string.Format("Could not find image file '{0}'", imageFilePath));
68
69 imageFilePaths.Add(imageFilePath);
70 }
71
72 xml.ReadEndElement();
73
74 var surfaces = new List<Surface>();
75
76 foreach (string imageFilePath in imageFilePaths)
77 surfaces.Add(TgaReader.Read(imageFilePath));
78
79 if (surfaces.Count == 0)
80 throw new InvalidDataException("No images found. A texture must have at least one image.");
81
82 int imageWidth = 0;
83 int imageHeight = 0;
84
85 foreach (Surface surface in surfaces)
86 {
87 if (imageWidth == 0)
88 imageWidth = surface.Width;
89 else if (imageWidth != surface.Width)
90 throw new NotSupportedException("All animation frames must have the same size.");
91
92 if (imageHeight == 0)
93 imageHeight = surface.Height;
94 else if (imageHeight != surface.Height)
95 throw new NotSupportedException("All animation frames must have the same size.");
96 }
97
98 if (width == 0)
99 width = imageWidth;
100 else if (width > imageWidth)
101 throw new NotSupportedException("Cannot upscale images.");
102
103 if (height == 0)
104 height = imageHeight;
105 else if (height > imageHeight)
106 throw new NotSupportedException("Cannot upscale images.");
107
108 //if (envMapName != null && surfaces.Count > 1)
109 // throw new NotSupportedException("Animated textures cannot have an environment map.");
110
111 if (width != imageWidth || height != imageHeight)
112 {
113 for (int i = 0; i < surfaces.Count; i++)
114 surfaces[i] = surfaces[i].Resize(width, height);
115 }
116
117 flags |= InstanceMetadata.TXMPFlags.SwapBytes;
118
119 if (envMapName != null)
120 flags |= InstanceMetadata.TXMPFlags.HasEnvMap;
121
122 for (int i = 0; i < surfaces.Count; i++)
123 {
124 BinaryWriter writer;
125
126 if (i == 0)
127 writer = importer.BeginXmlInstance(TemplateTag.TXMP, name, i.ToString(CultureInfo.InvariantCulture));
128 else
129 writer = importer.BeginXmlInstance(TemplateTag.TXMP, null, i.ToString(CultureInfo.InvariantCulture));
130
131 writer.Skip(128);
132 writer.Write((int)flags);
133 writer.WriteUInt16(width);
134 writer.WriteUInt16(height);
135 writer.Write((int)format);
136
137 if (i == 0 && surfaces.Count > 1)
138 writer.WriteInstanceId(surfaces.Count);
139 else
140 writer.Write(0);
141
142 if (envMapName != null)
143 writer.WriteInstanceId(surfaces.Count + ((surfaces.Count > 1) ? 1 : 0));
144 else
145 writer.Write(0);
146
147 writer.Write(importer.RawWriter.Align32());
148 writer.Skip(12);
149
150 var mainSurface = surfaces[i];
151
152 var levels = new List<Surface> { mainSurface };
153
154 if ((flags & InstanceMetadata.TXMPFlags.HasMipMaps) != 0)
155 {
156 int mipWidth = width;
157 int mipHeight = height;
158
159 while (mipWidth > 1 || mipHeight > 1)
160 {
161 mipWidth = Math.Max(mipWidth >> 1, 1);
162 mipHeight = Math.Max(mipHeight >> 1, 1);
163
164 levels.Add(mainSurface.Resize(mipWidth, mipHeight));
165 }
166 }
167
168 foreach (var level in levels)
169 {
170 var surface = level.Convert(TextureFormatToSurfaceFormat(format));
171 importer.RawWriter.Write(surface.Data);
172 }
173
174 importer.EndXmlInstance();
175 }
176
177 if (surfaces.Count > 1)
178 {
179 var txan = importer.CreateInstance(TemplateTag.TXAN);
180
181 using (var writer = txan.OpenWrite(12))
182 {
183 writer.WriteInt16(speed);
184 writer.WriteInt16(speed);
185 writer.Write(0);
186 writer.Write(surfaces.Count);
187 writer.Write(0);
188
189 for (int i = 1; i < surfaces.Count; i++)
190 writer.WriteInstanceId(i);
191 }
192 }
193
194 if (envMapName != null)
195 {
196 importer.CreateInstance(TemplateTag.TXMP, envMapName);
197 }
198 }
199
200 private static SurfaceFormat TextureFormatToSurfaceFormat(InstanceMetadata.TXMPFormat format)
201 {
202 switch (format)
203 {
204 case InstanceMetadata.TXMPFormat.BGRA4444:
205 return SurfaceFormat.BGRA4444;
206
207 case InstanceMetadata.TXMPFormat.BGR555:
208 return SurfaceFormat.BGRX5551;
209
210 case InstanceMetadata.TXMPFormat.BGRA5551:
211 return SurfaceFormat.BGRA5551;
212
213 case InstanceMetadata.TXMPFormat.RGBA:
214 return SurfaceFormat.RGBA;
215
216 case InstanceMetadata.TXMPFormat.BGR:
217 return SurfaceFormat.BGRX;
218
219 case InstanceMetadata.TXMPFormat.DXT1:
220 return SurfaceFormat.DXT1;
221
222 default:
223 throw new NotSupportedException(string.Format("Texture format {0} is not supported", format));
224 }
225 }
226 }
227}
Note: See TracBrowser for help on using the repository browser.