1 |
using System.Collections.Generic; |
2 |
using System.Globalization; |
3 |
using System.IO; |
4 |
using System.Xml; |
5 |
|
6 |
namespace Oni.Level |
7 |
{ |
8 |
using Akira; |
9 |
using Metadata; |
10 |
using Motoko; |
11 |
using Physics; |
12 |
using Xml; |
13 |
|
14 |
partial class LevelImporter |
15 |
{ |
16 |
private void ReadPhysics(XmlReader xml, string basePath) |
17 |
{ |
18 |
if (xml.SkipEmpty()) |
19 |
return; |
20 |
|
21 |
xml.ReadStartElement("Physics"); |
22 |
|
23 |
while (xml.IsStartElement()) |
24 |
ReadObjectSetup(xml, basePath); |
25 |
|
26 |
xml.ReadEndElement(); |
27 |
} |
28 |
|
29 |
private void ReadObjectSetup(XmlReader xml, string basePath) |
30 |
{ |
31 |
var scriptId = -1; |
32 |
var name = xml.GetAttribute("Name"); |
33 |
var position = Vector3.Zero; |
34 |
var rotation = Quaternion.Identity; |
35 |
var scale = 1.0f; |
36 |
var flags = ObjectSetupFlags.None; |
37 |
var physicsType = ObjectPhysicsType.None; |
38 |
var particles = new List<ObjectParticle>(); |
39 |
var nodes = new List<ObjectNode>(); |
40 |
string geometryName = null; |
41 |
string animationName = null; |
42 |
|
43 |
xml.ReadStartElement("Object"); |
44 |
|
45 |
while (xml.IsStartElement()) |
46 |
{ |
47 |
switch (xml.LocalName) |
48 |
{ |
49 |
case "Name": |
50 |
name = xml.ReadElementContentAsString(); |
51 |
break; |
52 |
case "ScriptId": |
53 |
scriptId = xml.ReadElementContentAsInt(); |
54 |
break; |
55 |
case "Flags": |
56 |
flags = xml.ReadElementContentAsEnum<ObjectSetupFlags>() & ~ObjectSetupFlags.InUse; |
57 |
break; |
58 |
case "Position": |
59 |
position = xml.ReadElementContentAsVector3(); |
60 |
break; |
61 |
case "Rotation": |
62 |
rotation = xml.ReadElementContentAsEulerXYZ(); |
63 |
break; |
64 |
case "Scale": |
65 |
scale = xml.ReadElementContentAsFloat(); |
66 |
break; |
67 |
case "Physics": |
68 |
physicsType = xml.ReadElementContentAsEnum<ObjectPhysicsType>(); |
69 |
break; |
70 |
case "Particles": |
71 |
particles.AddRange(ReadParticles(xml, basePath)); |
72 |
break; |
73 |
|
74 |
case "Geometry": |
75 |
geometryName = xml.ReadElementContentAsString(); |
76 |
if (nodes.Count > 0) |
77 |
{ |
78 |
error.WriteLine("Geometry cannot be used together with Import, ignoring"); |
79 |
break; |
80 |
} |
81 |
break; |
82 |
|
83 |
case "Animation": |
84 |
animationName = xml.ReadElementContentAsString(); |
85 |
if (nodes.Count > 0) |
86 |
{ |
87 |
error.WriteLine("Animation cannot be used together with Import, ignoring"); |
88 |
break; |
89 |
} |
90 |
break; |
91 |
|
92 |
case "Import": |
93 |
if (geometryName != null || animationName != null) |
94 |
{ |
95 |
error.WriteLine("Import cannot be used together with Geometry and Animation, ignoring"); |
96 |
break; |
97 |
} |
98 |
nodes.AddRange(ImportObjectGeometry(xml, basePath)); |
99 |
break; |
100 |
|
101 |
default: |
102 |
error.WriteLine("Unknown physics object element {0}", xml.LocalName); |
103 |
xml.Skip(); |
104 |
break; |
105 |
} |
106 |
} |
107 |
|
108 |
xml.ReadEndElement(); |
109 |
|
110 |
if (geometryName != null) |
111 |
{ |
112 |
var m3gm = FindSharedInstance(TemplateTag.M3GM, geometryName, objectLoadContext); |
113 |
var geometry = GeometryDatReader.Read(m3gm); |
114 |
var animation = new ObjectAnimation[0]; |
115 |
|
116 |
if (animationName != null) |
117 |
{ |
118 |
var oban = FindSharedInstance(TemplateTag.OBAN, animationName, objectLoadContext); |
119 |
animation = new[] { ObjectDatReader.ReadAnimation(oban) }; |
120 |
} |
121 |
|
122 |
nodes.Add(new ObjectNode(new[] { new ObjectGeometry(geometry) }) { |
123 |
FileName = Path.GetFileName(geometryName), |
124 |
Name = m3gm.Name, |
125 |
ScriptId = scriptId, |
126 |
Flags = flags, |
127 |
Animations = animation |
128 |
}); |
129 |
} |
130 |
|
131 |
for (int i = 0; i < nodes.Count; i++) |
132 |
{ |
133 |
var node = nodes[i]; |
134 |
|
135 |
var setup = new ObjectSetup { |
136 |
Name = node.Name, |
137 |
FileName = node.FileName, |
138 |
ScriptId = scriptId++, |
139 |
Flags = flags, |
140 |
PhysicsType = physicsType, |
141 |
}; |
142 |
|
143 |
setup.Particles.AddRange(particles); |
144 |
|
145 |
setup.Geometries = node.Geometries |
146 |
.Where(n => (n.Flags & GunkFlags.Invisible) == 0) |
147 |
.Select(n => n.Geometry.Name).ToArray(); |
148 |
|
149 |
foreach (var nodeGeometry in node.Geometries.Where(g => (g.Flags & GunkFlags.Invisible) == 0)) |
150 |
{ |
151 |
var writer = new DatWriter(); |
152 |
GeometryDatWriter.Write(nodeGeometry.Geometry, writer.ImporterFile); |
153 |
writer.Write(outputDirPath); |
154 |
} |
155 |
|
156 |
setup.Position = position; |
157 |
setup.Orientation = rotation; |
158 |
setup.Scale = scale; |
159 |
setup.Origin = Matrix.CreateFromQuaternion(setup.Orientation) |
160 |
* Matrix.CreateScale(setup.Scale) |
161 |
* Matrix.CreateTranslation(setup.Position); |
162 |
|
163 |
foreach (var animation in node.Animations) |
164 |
{ |
165 |
if (nodes.Count > 1) |
166 |
animation.Name += i.ToString("d2", CultureInfo.InvariantCulture); |
167 |
|
168 |
if ((animation.Flags & ObjectAnimationFlags.Local) != 0) |
169 |
{ |
170 |
//animation.Scale = Matrix.CreateScale(setup.Scale); |
171 |
|
172 |
foreach (var key in animation.Keys) |
173 |
{ |
174 |
key.Rotation = setup.Orientation * key.Rotation; |
175 |
key.Translation += setup.Position; |
176 |
} |
177 |
} |
178 |
|
179 |
if ((animation.Flags & ObjectAnimationFlags.AutoStart) != 0) |
180 |
{ |
181 |
setup.Animation = animation; |
182 |
setup.PhysicsType = ObjectPhysicsType.Animated; |
183 |
} |
184 |
|
185 |
var writer = new DatWriter(); |
186 |
ObjectDatWriter.WriteAnimation(animation, writer); |
187 |
writer.Write(outputDirPath); |
188 |
} |
189 |
|
190 |
if (setup.Animation == null && node.Animations.Length > 0) |
191 |
{ |
192 |
setup.Animation = node.Animations[0]; |
193 |
} |
194 |
|
195 |
if (setup.Animation != null) |
196 |
{ |
197 |
var frame0 = setup.Animation.Keys[0]; |
198 |
|
199 |
setup.Scale = frame0.Scale.X; |
200 |
setup.Orientation = frame0.Rotation; |
201 |
setup.Position = frame0.Translation; |
202 |
} |
203 |
|
204 |
level.physics.Add(setup); |
205 |
} |
206 |
} |
207 |
|
208 |
private IEnumerable<ObjectNode> ImportObjectGeometry(XmlReader xml, string basePath) |
209 |
{ |
210 |
var filePath = xml.GetAttribute("Path"); |
211 |
|
212 |
if (filePath == null) |
213 |
filePath = xml.GetAttribute("Url"); |
214 |
|
215 |
var scene = LoadScene(Path.Combine(basePath, filePath)); |
216 |
var animClips = new List<ObjectAnimationClip>(); |
217 |
|
218 |
if (!xml.SkipEmpty()) |
219 |
{ |
220 |
xml.ReadStartElement(); |
221 |
|
222 |
while (xml.IsStartElement()) |
223 |
{ |
224 |
switch (xml.LocalName) |
225 |
{ |
226 |
case "Animation": |
227 |
animClips.Add(ReadAnimationClip(xml)); |
228 |
break; |
229 |
|
230 |
default: |
231 |
error.WriteLine("Unknown element {0}", xml.LocalName); |
232 |
xml.Skip(); |
233 |
break; |
234 |
} |
235 |
} |
236 |
|
237 |
xml.ReadEndElement(); |
238 |
} |
239 |
|
240 |
var importer = new ObjectDaeImporter(textureImporter, null); |
241 |
importer.Import(scene); |
242 |
return importer.Nodes; |
243 |
} |
244 |
} |
245 |
} |