source: OniSplit/DaeExporter.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: 11.9 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4
5namespace Oni
6{
7 internal class DaeExporter : Exporter
8 {
9 private readonly bool noAnimation;
10 private readonly List<string> animationNames = new List<string>();
11 private readonly string geometryName;
12 private readonly string fileType;
13
14 public DaeExporter(string[] args, InstanceFileManager fileManager, string outputDirPath, string fileType)
15 : base(fileManager, outputDirPath)
16 {
17 foreach (string arg in args)
18 {
19 if (arg == "-noanim")
20 noAnimation = true;
21 else if (arg.StartsWith("-anim:", StringComparison.Ordinal))
22 animationNames.Add(arg.Substring(6));
23 else if (arg.StartsWith("-geom:", StringComparison.Ordinal))
24 geometryName = arg.Substring(6);
25 }
26
27 this.fileType = fileType;
28 }
29
30 protected override void ExportFile(string sourceFilePath)
31 {
32 string extension = Path.GetExtension(sourceFilePath);
33
34 if (string.Equals(extension, ".xml", StringComparison.OrdinalIgnoreCase))
35 {
36 var sceneExporter = new SceneExporter(InstanceFileManager, OutputDirPath);
37 sceneExporter.ExportScene(sourceFilePath);
38 return;
39 }
40
41 base.ExportFile(sourceFilePath);
42 }
43
44 protected override List<InstanceDescriptor> GetSupportedDescriptors(InstanceFile file)
45 {
46 var descriptors = new List<InstanceDescriptor>();
47 descriptors.AddRange(file.GetNamedDescriptors(TemplateTag.ONCC));
48 descriptors.AddRange(file.GetNamedDescriptors(TemplateTag.TRBS));
49 descriptors.AddRange(file.GetNamedDescriptors(TemplateTag.M3GM));
50 descriptors.AddRange(file.GetNamedDescriptors(TemplateTag.AKEV));
51 descriptors.AddRange(file.GetNamedDescriptors(TemplateTag.OBAN));
52 descriptors.AddRange(file.GetNamedDescriptors(TemplateTag.OFGA));
53 descriptors.AddRange(file.GetNamedDescriptors(TemplateTag.ONWC));
54 return descriptors;
55 }
56
57 protected override void ExportInstance(InstanceDescriptor descriptor)
58 {
59 var tag = descriptor.Template.Tag;
60
61 if (tag == TemplateTag.AKEV)
62 {
63 var mesh = Akira.AkiraDatReader.Read(descriptor);
64 Akira.AkiraDaeWriter.Write(mesh, descriptor.Name, OutputDirPath, fileType);
65 return;
66 }
67
68 var scene = new Dae.Scene();
69 scene.Name = descriptor.Name;
70
71 var textureWriter = new Motoko.TextureDaeWriter(OutputDirPath);
72 var geometryWriter = new Motoko.GeometryDaeWriter(textureWriter);
73 var bodyWriter = new Totoro.BodyDaeWriter(geometryWriter);
74
75 if (tag == TemplateTag.OFGA)
76 ExportObjectGeometry(descriptor, scene, geometryWriter);
77 else if (tag == TemplateTag.OBAN)
78 ExportObjectAnimation(descriptor, scene, geometryWriter);
79 else if (tag == TemplateTag.ONCC)
80 ExportCharacterBody(descriptor, scene, bodyWriter);
81 else if (tag == TemplateTag.TRBS)
82 ExportCharacterBodySet(descriptor, scene, bodyWriter);
83 else if (tag == TemplateTag.M3GM)
84 ExportGeometry(descriptor, scene, geometryWriter);
85 else if (tag == TemplateTag.ONWC)
86 ExportWeaponGeometry(descriptor, scene, geometryWriter);
87
88 if (scene.Nodes.Count > 0)
89 {
90 string filePath = Path.Combine(OutputDirPath, descriptor.Name + "." + fileType);
91
92 Dae.Writer.WriteFile(filePath, scene);
93 }
94 }
95
96 private void ExportObjectGeometry(InstanceDescriptor descriptor, Dae.Scene scene, Motoko.GeometryDaeWriter geometryWriter)
97 {
98 var geometry = Physics.ObjectDatReader.ReadObjectGeometry(descriptor);
99 var root = new Dae.Node();
100
101 foreach (var objNode in geometry.Geometries)
102 root.Nodes.Add(geometryWriter.WriteNode(objNode.Geometry, objNode.Geometry.Name));
103
104 scene.Nodes.Add(root);
105 }
106
107 private void ExportObjectAnimation(InstanceDescriptor descriptor, Dae.Scene scene, Motoko.GeometryDaeWriter geometryWriter)
108 {
109 var animation = Physics.ObjectDatReader.ReadAnimation(descriptor);
110 Dae.Node node;
111
112 if (geometryName == "camera")
113 {
114 node = new Dae.Node
115 {
116 Name = descriptor.Name + "_camera",
117 Instances = {
118 new Dae.CameraInstance {
119 Target = new Dae.Camera {
120 XFov = 45.0f,
121 AspectRatio = 4.0f / 3.0f,
122 ZNear = 1.0f,
123 ZFar = 10000.0f
124 }
125 }}
126 };
127 }
128 else if (geometryName != null)
129 {
130 var file = InstanceFileManager.OpenFile(geometryName);
131
132 if (file == null)
133 {
134 Console.Error.WriteLine("Cannot fine file {0}", geometryName);
135 node = new Dae.Node();
136 }
137 else
138 {
139 var geom = Motoko.GeometryDatReader.Read(file.Descriptors[0]);
140 node = geometryWriter.WriteNode(geom, geom.Name);
141 }
142 }
143 else
144 {
145 node = new Dae.Node();
146 }
147
148 scene.Nodes.Add(node);
149
150 ExportAnimation(node, new List<Physics.ObjectAnimationKey>(animation.Keys));
151 }
152
153 private void ExportGeometry(InstanceDescriptor descriptor, Dae.Scene scene, Motoko.GeometryDaeWriter geometryWriter)
154 {
155 var animations = new List<Physics.ObjectAnimation>(animationNames.Count);
156
157 foreach (string animationFilePath in animationNames)
158 {
159 var file = InstanceFileManager.OpenFile(animationFilePath);
160
161 if (file == null)
162 {
163 Console.Error.WriteLine("Cannot find animation {0}", animationFilePath);
164 continue;
165 }
166
167 animations.Add(Physics.ObjectDatReader.ReadAnimation(file.Descriptors[0]));
168 }
169
170 ExportGeometry(scene, geometryWriter, descriptor, animations);
171 }
172
173 private void ExportCharacterBodySet(InstanceDescriptor descriptor, Dae.Scene scene, Totoro.BodyDaeWriter bodyWriter)
174 {
175 var body = Totoro.BodyDatReader.Read(descriptor);
176 var node = bodyWriter.Write(body, noAnimation, null);
177
178 scene.Nodes.Add(node);
179 }
180
181 private void ExportCharacterBody(InstanceDescriptor descriptor, Dae.Scene scene, Totoro.BodyDaeWriter bodyWriter)
182 {
183 var animationName = animationNames.Count > 0 ? animationNames[0] : null;
184 var characterClass = Game.CharacterClass.Read(descriptor, animationName);
185
186 var body = Totoro.BodyDatReader.Read(characterClass.Body);
187 var textures = characterClass.Textures;
188 var pelvis = bodyWriter.Write(body, noAnimation, textures);
189
190 scene.Nodes.Add(pelvis);
191
192 var animation = noAnimation ? null : characterClass.Animation;
193
194 if (animation != null)
195 {
196 var anim = Totoro.AnimationDatReader.Read(animation);
197
198 Totoro.AnimationDaeWriter.Write(pelvis, anim);
199 }
200 }
201
202 private void ExportWeaponGeometry(InstanceDescriptor descriptor, Dae.Scene scene, Motoko.GeometryDaeWriter geometryWriter)
203 {
204 var weaponClass = Game.WeaponClass.Read(descriptor);
205
206 if (weaponClass.Geometry != null)
207 ExportGeometry(weaponClass.Geometry, scene, geometryWriter);
208 }
209
210 private static void ExportGeometry(Dae.Scene scene, Motoko.GeometryDaeWriter geometryWriter, InstanceDescriptor m3gm, List<Physics.ObjectAnimation> animations)
211 {
212 var geometry = Motoko.GeometryDatReader.Read(m3gm);
213
214 if (animations != null && animations.Count > 0)
215 {
216 geometry.HasTransform = true;
217 geometry.Transform = Matrix.CreateScale(animations[0].Keys[0].Scale);
218 }
219
220 var node = geometryWriter.WriteNode(geometry, m3gm.Name);
221 scene.Nodes.Add(node);
222
223 if (animations != null && animations.Count > 0)
224 {
225 var frames = new List<Physics.ObjectAnimationKey>();
226 int offset = 0;
227
228 foreach (var animation in animations)
229 {
230 foreach (var key in animation.Keys)
231 {
232 frames.Add(new Physics.ObjectAnimationKey
233 {
234 Translation = key.Translation,
235 Rotation = key.Rotation,
236 Time = key.Time + offset
237 });
238 }
239
240 offset += animation.Length;
241 }
242
243 ExportAnimation(node, frames);
244 }
245 }
246
247 private static void ExportAnimation(Dae.Node node, List<Physics.ObjectAnimationKey> frames)
248 {
249 var times = new float[frames.Count];
250 var interpolations = new string[times.Length];
251 var positions = new Vector3[frames.Count];
252 var angles = new Vector3[frames.Count];
253
254 for (int i = 0; i < times.Length; ++i)
255 times[i] = frames[i].Time / 60.0f;
256
257 for (int i = 0; i < interpolations.Length; i++)
258 interpolations[i] = "LINEAR";
259
260 for (int i = 0; i < frames.Count; i++)
261 positions[i] = frames[i].Translation;
262
263 for (int i = 0; i < frames.Count; i++)
264 angles[i] = frames[i].Rotation.ToEulerXYZ();
265
266 var translate = node.Transforms.Translate("translate", positions[0]);
267 var rotateX = node.Transforms.Rotate("rotX", Vector3.UnitX, angles[0].X);
268 var rotateY = node.Transforms.Rotate("rotY", Vector3.UnitY, angles[0].Y);
269 var rotateZ = node.Transforms.Rotate("rotZ", Vector3.UnitZ, angles[0].Z);
270
271 WriteSampler(times, interpolations, i => positions[i].X, translate, "X");
272 WriteSampler(times, interpolations, i => positions[i].Y, translate, "Y");
273 WriteSampler(times, interpolations, i => positions[i].Z, translate, "Z");
274 WriteSampler(times, interpolations, i => angles[i].X, rotateX, "ANGLE");
275 WriteSampler(times, interpolations, i => angles[i].Y, rotateY, "ANGLE");
276 WriteSampler(times, interpolations, i => angles[i].Z, rotateZ, "ANGLE");
277 }
278
279 private static void WriteSampler(float[] times, string[] interpolations, Func<int, float> getValue, Dae.Transform transform, string targetName)
280 {
281 var values = new float[times.Length];
282
283 for (int i = 0; i < values.Length; ++i)
284 values[i] = getValue(i);
285
286 transform.BindAnimation(targetName, new Dae.Sampler
287 {
288 Inputs = {
289 new Dae.Input(Dae.Semantic.Input, new Dae.Source(times, 1)),
290 new Dae.Input(Dae.Semantic.Output, new Dae.Source(values, 1)),
291 new Dae.Input(Dae.Semantic.Interpolation, new Dae.Source(interpolations, 1))
292 }
293 });
294 }
295 }
296}
Note: See TracBrowser for help on using the repository browser.