OSDN Git Service

Remove the / in the beginning of the texture's filename while loading a model
[mikumikustudio/libgdx-mikumikustudio.git] / gdx / src / com / badlogic / gdx / graphics / g3d / loader / G3dModelLoader.java
1 package com.badlogic.gdx.graphics.g3d.loader;
2
3 import com.badlogic.gdx.assets.AssetLoaderParameters;
4 import com.badlogic.gdx.assets.loaders.FileHandleResolver;
5 import com.badlogic.gdx.assets.loaders.ModelLoader;
6 import com.badlogic.gdx.files.FileHandle;
7 import com.badlogic.gdx.graphics.Color;
8 import com.badlogic.gdx.graphics.GL10;
9 import com.badlogic.gdx.graphics.VertexAttribute;
10 import com.badlogic.gdx.graphics.g3d.Model;
11 import com.badlogic.gdx.graphics.g3d.model.data.ModelAnimation;
12 import com.badlogic.gdx.graphics.g3d.model.data.ModelData;
13 import com.badlogic.gdx.graphics.g3d.model.data.ModelMaterial;
14 import com.badlogic.gdx.graphics.g3d.model.data.ModelMesh;
15 import com.badlogic.gdx.graphics.g3d.model.data.ModelMeshPart;
16 import com.badlogic.gdx.graphics.g3d.model.data.ModelNode;
17 import com.badlogic.gdx.graphics.g3d.model.data.ModelNodeAnimation;
18 import com.badlogic.gdx.graphics.g3d.model.data.ModelNodeKeyframe;
19 import com.badlogic.gdx.graphics.g3d.model.data.ModelNodePart;
20 import com.badlogic.gdx.graphics.g3d.model.data.ModelTexture;
21 import com.badlogic.gdx.math.Matrix4;
22 import com.badlogic.gdx.math.Quaternion;
23 import com.badlogic.gdx.math.Vector2;
24 import com.badlogic.gdx.math.Vector3;
25 import com.badlogic.gdx.utils.Array;
26 import com.badlogic.gdx.utils.ArrayMap;
27 import com.badlogic.gdx.utils.BaseJsonReader;
28 import com.badlogic.gdx.utils.GdxRuntimeException;
29 import com.badlogic.gdx.utils.JsonValue;
30 import com.badlogic.gdx.utils.UBJsonReader;
31
32 public class G3dModelLoader extends ModelLoader<AssetLoaderParameters<Model>> {
33         public static final short VERSION_HI = 0;
34         public static final short VERSION_LO = 1;
35         protected final BaseJsonReader reader;
36         
37         public G3dModelLoader(final BaseJsonReader reader) {
38                 this(reader, null);
39         }
40         
41         public G3dModelLoader(BaseJsonReader reader, FileHandleResolver resolver) {
42                 super(resolver);
43                 this.reader = reader;
44         }
45         
46         @Override
47         public ModelData loadModelData (FileHandle fileHandle, AssetLoaderParameters<Model> parameters) {
48                 return parseModel(fileHandle);
49         }
50
51         public ModelData parseModel (FileHandle handle) {
52                 JsonValue json = reader.parse(handle);
53                 ModelData model = new ModelData();
54                 JsonValue version = json.require("version");
55                 model.version[0] = (short)version.getInt(0);
56                 model.version[1] = (short)version.getInt(1);
57                 if (model.version[0] != VERSION_HI || model.version[1] != VERSION_LO)
58                         throw new GdxRuntimeException("Model version not supported");
59
60                 model.id = json.getString("id", "");
61                 parseMeshes(model, json);
62                 parseMaterials(model, json, handle.parent().path());
63                 parseNodes(model, json);
64                 parseAnimations(model, json);
65                 return model;
66         }
67
68         
69         private void parseMeshes (ModelData model, JsonValue json) {
70                 JsonValue meshes = json.require("meshes");
71                 
72                 model.meshes.ensureCapacity(meshes.size());
73                 for (JsonValue mesh = meshes.child(); mesh != null; mesh = mesh.next()) {
74                         ModelMesh jsonMesh = new ModelMesh();
75                         
76                         String id = mesh.getString("id", "");
77                         jsonMesh.id = id;
78                         
79                         JsonValue attributes = mesh.require("attributes");
80                         jsonMesh.attributes = parseAttributes(attributes);
81                         
82                         JsonValue vertices = mesh.require("vertices");
83                         float[] verts = new float[vertices.size()];
84                         int j = 0;
85                         for (JsonValue value = vertices.child(); value != null; value = value.next(), j++) {
86                                 verts[j] = value.asFloat();
87                         }
88                         jsonMesh.vertices = verts;
89                         
90                         JsonValue meshParts = mesh.require("parts");
91                         Array<ModelMeshPart> parts = new Array<ModelMeshPart>();
92                         for (JsonValue meshPart = meshParts.child(); meshPart != null; meshPart = meshPart.next()) {
93                                 ModelMeshPart jsonPart = new ModelMeshPart();
94                                 String partId = meshPart.getString("id", null);
95                                 if(id == null) {
96                                         throw new GdxRuntimeException("Not id given for mesh part");
97                                 }
98                                 for(ModelMeshPart other: parts) {
99                                         if(other.id.equals(partId)) {
100                                                 throw new GdxRuntimeException("Mesh part with id '" + partId + "' already in defined");
101                                         }
102                                 }
103                                 jsonPart.id = partId;
104                                 
105                                 String type = meshPart.getString("type", null);
106                                 if(type == null) {
107                                         throw new GdxRuntimeException("No primitive type given for mesh part '" + partId + "'");
108                                 }
109                                 jsonPart.primitiveType = parseType(type);
110                                 
111                                 JsonValue indices = meshPart.require("indices");
112                                 short[] partIndices = new short[indices.size()];
113                                 int k = 0;
114                                 for (JsonValue value = indices.child(); value != null; value = value.next(), k++) {
115                                         partIndices[k] = (short)value.asInt();
116                                 }
117                                 jsonPart.indices = partIndices;
118                                 parts.add(jsonPart);
119                         }
120                         jsonMesh.parts = parts.toArray(ModelMeshPart.class);
121                         model.meshes.add(jsonMesh);
122                 }
123         }
124         
125         private int parseType (String type) {
126                 if(type.equals("TRIANGLES")) {
127                         return GL10.GL_TRIANGLES;
128                 } else if(type.equals("LINES")) {
129                         return GL10.GL_LINES;
130                 } else if(type.equals("POINTS")) {
131                         return GL10.GL_POINTS;
132                 } else if(type.equals("TRIANGLE_STRIP")) {
133                         return GL10.GL_TRIANGLE_STRIP;
134                 } else if(type.equals("LINE_STRIP")) {
135                         return GL10.GL_LINE_STRIP;
136                 } else { 
137                         throw new GdxRuntimeException("Unknown primitive type '" + type + "', should be one of triangle, trianglestrip, line, linestrip, lineloop or point");
138                 }
139         }
140
141         private VertexAttribute[] parseAttributes (JsonValue attributes) {
142                 Array<VertexAttribute> vertexAttributes = new Array<VertexAttribute>();
143                 int unit = 0;
144                 int blendWeightCount = 0;
145                 for (JsonValue value = attributes.child(); value != null; value = value.next()) {
146                         String attribute = value.asString();
147                         String attr = (String)attribute;
148                         if(attr.equals("POSITION")) {
149                                 vertexAttributes.add(VertexAttribute.Position());
150                         } else if(attr.equals("NORMAL")) {
151                                 vertexAttributes.add(VertexAttribute.Normal());
152                         } else if(attr.equals("COLOR")) {
153                                 vertexAttributes.add(VertexAttribute.ColorUnpacked());
154                         } else if(attr.equals("COLORPACKED")) {
155                                 vertexAttributes.add(VertexAttribute.Color());
156                         } else if(attr.equals("TANGENT")) {
157                                 vertexAttributes.add(VertexAttribute.Tangent());
158                         } else if(attr.equals("BINORMAL")) {
159                                 vertexAttributes.add(VertexAttribute.Binormal());
160                         } else if(attr.startsWith("TEXCOORD")) {
161                                 vertexAttributes.add(VertexAttribute.TexCoords(unit++));
162                         } else if(attr.startsWith("BLENDWEIGHT")) {
163                                 vertexAttributes.add(VertexAttribute.BoneWeight(blendWeightCount++));
164                         } else {
165                                 throw new GdxRuntimeException("Unknown vertex attribute '" + attr + "', should be one of position, normal, uv, tangent or binormal");
166                         }
167                 }
168                 return vertexAttributes.toArray(VertexAttribute.class);
169         }
170
171         private void parseMaterials (ModelData model, JsonValue json, String materialDir) {
172                 JsonValue materials = json.get("materials");
173                 if(materials == null) {
174                         // we should probably create some default material in this case
175                 }
176                 else {
177                         model.materials.ensureCapacity(materials.size());
178                         for (JsonValue material = materials.child(); material != null; material = material.next()) {
179                                 ModelMaterial jsonMaterial = new ModelMaterial();
180                                 
181                                 String id = material.getString("id", null);
182                                 if(id == null)
183                                         throw new GdxRuntimeException("Material needs an id.");
184
185                                 jsonMaterial.id = id;
186                                                         
187                                 // Read material colors
188                                 jsonMaterial.diffuse = parseColor(material.get("diffuse"), Color.WHITE);
189                                 jsonMaterial.ambient = parseColor(material.get("ambient"), Color.BLACK);
190                                 jsonMaterial.emissive = parseColor(material.get("emissive"), Color.BLACK);
191                                 
192                            // Read specular
193                                 jsonMaterial.specular = parseColor(material.get("specular"), Color.BLACK);
194                                 // Read shininess
195                                 jsonMaterial.shininess = material.getFloat("shininess", 0.0f);
196                                 // Read opacity
197                                 jsonMaterial.opacity = material.getFloat("opacity", 1.0f);
198                                 
199                                 // Read textures
200                                 JsonValue textures = material.get("textures");
201                                 if(textures != null){
202                                         for (JsonValue texture = textures.child(); texture != null; texture = texture.next()) {
203                                                 ModelTexture jsonTexture = new ModelTexture();
204                                                 
205                                                 String textureId = texture.getString("id", null);
206                                                 if(textureId == null)
207                                                         throw new GdxRuntimeException("Texture has no id.");
208                                                 jsonTexture.id = textureId;
209                                                 
210                                                 String fileName = texture.getString("filename", null);
211                                                 if(fileName == null)
212                                                         throw new GdxRuntimeException("Texture needs filename.");
213                                                 jsonTexture.fileName = materialDir + (materialDir.length() == 0 || materialDir.endsWith("/") ? "" : "/") + fileName;
214                                                 
215                                                 jsonTexture.uvTranslation = readVector2(texture.get("uvTranslation"), 0f, 0f);
216                                                 jsonTexture.uvScaling = readVector2(texture.get("uvScaling"), 1f, 1f);
217                                                 
218                                                 String textureType = texture.getString("type", null);
219                                                 if(textureType == null)
220                                                         throw new GdxRuntimeException("Texture needs type.");
221                                                 
222                                                 jsonTexture.usage = parseTextureUsage(textureType);
223                                                 
224                                                 if(jsonMaterial.textures == null)
225                                                         jsonMaterial.textures = new Array<ModelTexture>();
226                                                 jsonMaterial.textures.add(jsonTexture);
227                                         }
228                                 }
229
230                                 model.materials.add(jsonMaterial);
231                         }
232                 }
233         }
234         
235         private int parseTextureUsage(final String value) {
236                 if (value.equalsIgnoreCase("AMBIENT"))
237                         return ModelTexture.USAGE_AMBIENT;
238                 else if (value.equalsIgnoreCase("BUMP"))
239                         return ModelTexture.USAGE_BUMP;
240                 else if (value.equalsIgnoreCase("DIFFUSE"))
241                         return ModelTexture.USAGE_DIFFUSE;
242                 else if (value.equalsIgnoreCase("EMISSIVE"))
243                         return ModelTexture.USAGE_EMISSIVE;
244                 else if (value.equalsIgnoreCase("NONE"))
245                         return ModelTexture.USAGE_NONE;
246                 else if (value.equalsIgnoreCase("NORMAL"))
247                         return ModelTexture.USAGE_NORMAL;
248                 else if (value.equalsIgnoreCase("REFLECTION"))
249                         return ModelTexture.USAGE_REFLECTION;
250                 else if (value.equalsIgnoreCase("SHININESS"))
251                         return ModelTexture.USAGE_SHININESS;
252                 else if (value.equalsIgnoreCase("SPECULAR"))
253                         return ModelTexture.USAGE_SPECULAR;
254                 else if (value.equalsIgnoreCase("TRANSPARENCY"))
255                         return ModelTexture.USAGE_TRANSPARENCY;
256                 return ModelTexture.USAGE_UNKNOWN;
257         }
258
259         private Color parseColor (JsonValue colorArray, Color defaultColor) {
260                 if(colorArray == null) {
261                         return defaultColor;
262                 }
263                 else if(colorArray.size() == 3)
264                         return new Color(colorArray.getFloat(0), colorArray.getFloat(1), colorArray.getFloat(2), 1.0f);
265                 else
266                         throw new GdxRuntimeException("Expected Color values <> than three.");
267         }
268
269         private Vector2 readVector2 (JsonValue vectorArray, float x, float y) {
270                 if(vectorArray == null)
271                         return new Vector2(x, y);
272                 else if(vectorArray.size() == 2)
273                         return new Vector2(vectorArray.getFloat(0), vectorArray.getFloat(1));
274                 else
275                         throw new GdxRuntimeException("Expected Vector2 values <> than two.");
276         }
277
278         private Array<ModelNode> parseNodes (ModelData model, JsonValue json) {
279                 JsonValue nodes = json.get("nodes");
280                 if(nodes == null) {
281                         throw new GdxRuntimeException("At least one node is required.");
282                 }
283                 
284                 model.nodes.ensureCapacity(nodes.size());
285                 for (JsonValue node = nodes.child(); node != null; node = node.next()) {
286                         model.nodes.add(parseNodesRecursively(node));
287                 }
288                 return model.nodes;
289         }
290         
291         private final Quaternion tempQ = new Quaternion(); 
292         private ModelNode parseNodesRecursively(JsonValue json){
293                 ModelNode jsonNode = new ModelNode();
294                 
295                 String id = json.getString("id", null);
296                 if(id == null)
297                         throw new GdxRuntimeException("Node id missing.");
298                 jsonNode.id = id;
299                 
300                 JsonValue translation = json.get("translation");
301                 if (translation != null && translation.size() != 3)
302                         throw new GdxRuntimeException("Node translation incomplete");
303                 jsonNode.translation = translation == null ? null : new Vector3(translation.getFloat(0), translation.getFloat(1), translation.getFloat(2));
304                 
305                 JsonValue rotation = json.get("rotation");
306                 if(rotation != null && rotation.size() != 4)
307                         throw new GdxRuntimeException("Node rotation incomplete");
308                 jsonNode.rotation = rotation == null ? null : new Quaternion(rotation.getFloat(0), rotation.getFloat(1), rotation.getFloat(2), rotation.getFloat(3));
309                 
310                 JsonValue scale = json.get("scale");
311                 if(scale != null && scale.size() != 3)
312                         throw new GdxRuntimeException("Node scale incomplete");
313                 jsonNode.scale = scale == null ? null : new Vector3(scale.getFloat(0), scale.getFloat(1), scale.getFloat(2));
314                 
315                 String meshId = json.getString("mesh", null);
316                 if(meshId != null)
317                         jsonNode.meshId = meshId;
318                 
319                 JsonValue materials = json.get("parts");
320                 if(materials != null){
321                         jsonNode.parts = new ModelNodePart[materials.size()];
322                         int i = 0;
323                         for (JsonValue material = materials.child(); material != null; material = material.next(), i++) {
324                                 ModelNodePart nodePart = new ModelNodePart();
325                                 
326                                 String meshPartId = material.getString("meshpartid", null);
327                                 String materialId = material.getString("materialid", null);
328                                 if(meshPartId == null || materialId == null){
329                                         throw new GdxRuntimeException("Node "+id+" part is missing meshPartId or materialId");
330                                 }
331                                 nodePart.materialId = materialId;
332                                 nodePart.meshPartId = meshPartId;
333                                 
334                                 JsonValue bones = material.get("bones");
335                                 if (bones != null) {
336                                         nodePart.bones = new ArrayMap<String, Matrix4>(true, bones.size(), String.class, Matrix4.class);
337                                         int j = 0;
338                                         for (JsonValue bone = bones.child(); bone != null; bone = bone.next(), j++) {
339                                                 String nodeId = bone.getString("node", null);
340                                                 if (nodeId == null)
341                                                         throw new GdxRuntimeException("Bone node ID missing");
342                                                 
343                                                 Matrix4 transform = new Matrix4();
344                                                 
345                                                 JsonValue val = bone.get("translation");
346                                                 if (val != null && val.size() >= 3)
347                                                         transform.translate(val.getFloat(0), val.getFloat(1), val.getFloat(2));
348                                                 
349                                                 val = bone.get("rotation");
350                                                 if(val != null && val.size() >= 4)
351                                                         transform.rotate(tempQ.set(val.getFloat(0), val.getFloat(1), val.getFloat(2), val.getFloat(3)));
352                                                 
353                                                 val = bone.get("scale");
354                                                 if(val != null && val.size() >= 3)
355                                                         transform.scale(val.getFloat(0), val.getFloat(1), val.getFloat(2));
356                                                 
357                                                 nodePart.bones.put(nodeId, transform);
358                                         }
359                                 }
360                                 
361                                 jsonNode.parts[i] = nodePart;
362                         }
363                 }
364                 
365                 JsonValue children = json.get("children");
366                 if(children != null){
367                         jsonNode.children = new ModelNode[children.size()];
368
369                         int i = 0;
370                         for (JsonValue child = children.child(); child != null; child = child.next(), i++) {
371                                 jsonNode.children[i] = parseNodesRecursively(child);
372                         }
373                 }
374                 
375                 return jsonNode;
376         }
377         
378         private void parseAnimations (ModelData model, JsonValue json) {
379                 JsonValue animations = json.get("animations");
380                 if(animations == null)
381                         return;
382                 
383                 model.animations.ensureCapacity(animations.size());
384                 
385                 for (JsonValue anim = animations.child(); anim != null; anim = anim.next()) {
386                         JsonValue nodes = anim.get("bones");
387                         if (nodes == null)
388                                 continue;
389                         ModelAnimation animation = new ModelAnimation();
390                         model.animations.add(animation);
391                         animation.nodeAnimations.ensureCapacity(nodes.size());
392                         animation.id = anim.getString("id");
393                         for (JsonValue node = nodes.child(); node != null; node = node.next()) {
394                                 JsonValue keyframes = node.get("keyframes");
395
396                                 ModelNodeAnimation nodeAnim = new ModelNodeAnimation();
397                                 animation.nodeAnimations.add(nodeAnim);
398                                 nodeAnim.nodeId = node.getString("boneId");
399                                 nodeAnim.keyframes.ensureCapacity(keyframes.size());
400
401                                 for (JsonValue keyframe = keyframes.child(); keyframe != null; keyframe = keyframe.next()) {
402                                         ModelNodeKeyframe kf = new ModelNodeKeyframe();
403                                         nodeAnim.keyframes.add(kf);
404                                         kf.keytime = keyframe.getFloat("keytime") / 1000.f;
405                                         JsonValue translation = keyframe.get("translation");
406                                         if (translation != null && translation.size() == 3)
407                                                 kf.translation = new Vector3(translation.getFloat(0), translation.getFloat(1), translation.getFloat(2));
408                                         JsonValue rotation = keyframe.get("rotation");
409                                         if (rotation != null && rotation.size() == 4)
410                                                 kf.rotation = new Quaternion(rotation.getFloat(0), rotation.getFloat(1), rotation.getFloat(2), rotation.getFloat(3));
411                                         JsonValue scale = keyframe.get("scale");
412                                         if (scale != null && scale.size() == 3)
413                                                 kf.scale = new Vector3(scale.getFloat(0), scale.getFloat(1), scale.getFloat(2));
414                                 }
415                         }
416                 }
417         }
418 }