/* * 2014 SMEdit development team * http://lazygamerz.org * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser Gereral Public Licence as published by the Free * Software Foundation; either version 3 of the Licence, or (at your opinion) any * later version. * * This library is distributed in the hope that it will be usefull, but WITHOUT ANY * WARRANTY; without even the implied warranty of merchantability or fitness for a * particular purpose. See the GNU Lesser General Public Licence for more details. * * You should have received a copy of the GNU Lesser General Public Licence along * with this library; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, Ma 02111-1307 USA. * * http://www.gnu.org/licenses/lgpl.html (English) * http://gugs.sindominio.net/gnu-gpl/lgpl-es.html * */ package jo.util.jgl.logic.imp; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import jo.sm.logic.utils.FloatUtils; import jo.sm.logic.utils.IntegerUtils; import jo.sm.logic.utils.StringUtils; import jo.sm.logic.utils.XMLUtils; import jo.util.jgl.obj.JGLGroup; import jo.util.jgl.obj.JGLNode; import jo.util.jgl.obj.tri.JGLObj; import jo.vecmath.Point3f; import jo.vecmath.Point4f; import org.w3c.dom.Document; import org.w3c.dom.Node; public class DAELogic { private static final Map<String, Point4f> mGeometryMaterials = new HashMap<>(); private static final Map<String, Point4f> mLibraryMaterials = new HashMap<>(); private static final Map<String, Point4f> mLibraryEffects = new HashMap<>(); public static JGLNode readDAE(InputStream is) { JGLGroup dae = new JGLGroup(); Document doc = XMLUtils.readStream(is); System.out.println("Indexing"); indexLibraryEffects(doc); indexLibraryMaterials(doc); indexGeometryMaterials(doc); System.out.println("Looking for geometries"); for (Node g : XMLUtils.findNodes(doc, "COLLADA/library_geometries/geometry")) { System.out.println("Geometry " + XMLUtils.getAttribute(g, "id")); for (Node t : XMLUtils.findNodes(g, "mesh/triangles")) { JGLObj o = new JGLObj(); //System.out.println("Triangles"); int triCount = IntegerUtils.parseInt(XMLUtils.getAttribute(t, "count")); Point4f color = getColor(t); if (color == null) { System.out.println("no color"); color = new Point4f(.9f, .9f, .9f, .9f); } Map<Integer, String> offsetToSemantic; offsetToSemantic = new HashMap<>(); Map<String, List<Short>> semanticToTriangles; semanticToTriangles = new HashMap<>(); Map<String, List<Point3f>> semanticToFloats; semanticToFloats = new HashMap<>(); for (Node input : XMLUtils.findNodes(t, "input")) { String semantic = XMLUtils.getAttribute(input, "semantic"); int offset = IntegerUtils.parseInt(XMLUtils.getAttribute(input, "offset")); String source = XMLUtils.getAttribute(input, "source").substring(1); Node src = findNodeWithValue(t.getParentNode(), "vertices", "id", source); if (src != null) { Node i = XMLUtils.findFirstNode(src, "input"); source = XMLUtils.getAttribute(i, "source").substring(1); } List<Point3f> positions = findFloatArray(t.getParentNode(), source); if (positions == null) { System.out.println(" no position source, sematic=" + semantic + ", offset=" + offset + ", source=" + source); continue; } offsetToSemantic.put(offset, semantic); semanticToTriangles.put(semantic, new ArrayList<Short>()); semanticToFloats.put(semantic, positions); } Node p = XMLUtils.findFirstNode(t, "p"); if (p == null) { System.out.println(" no p node"); continue; } //List<Short> triangles = new ArrayList<Short>(); String triTxt = XMLUtils.getText(p); StringTokenizer st = new StringTokenizer(triTxt, " \r\n\t"); int count = st.countTokens(); if (count != triCount * 3 * offsetToSemantic.size()) { System.err.println("Odd count of triangles! Expected " + triCount + " -> " + triCount * 3 * offsetToSemantic.size() + ", got " + count); System.err.println(triTxt); System.err.println("--------------------------------------------------"); continue; } for (int i = 0; i < triCount * 3; i++) { for (int offset = 0; offset < offsetToSemantic.size(); offset++) { String sem = offsetToSemantic.get(offset); semanticToTriangles.get(sem).add(Short.parseShort(st.nextToken())); } } List<Point3f> oVerts = new ArrayList<>(); List<Point3f> oNorms = new ArrayList<>(); List<Short> oTris = new ArrayList<>(); Map<String, Integer> combos = new HashMap<>(); for (int i = 0; i < triCount * 3; i++) { int vv = semanticToTriangles.get("VERTEX").get(i); int nn = vv; if (semanticToTriangles.containsKey("NORMAL")) { nn = semanticToTriangles.get("NORMAL").get(i); } String id = vv + "-" + nn; //System.out.println(" "+id); if (combos.containsKey(id)) { oTris.add(combos.get(id).shortValue()); } else { if (vv >= semanticToFloats.get("VERTEX").size()) { System.out.println("Bad position index " + vv + " (out of " + semanticToFloats.get("VERTEX").size() + ")"); continue; } Point3f vvp = semanticToFloats.get("VERTEX").get(vv); oVerts.add(vvp); if (semanticToTriangles.containsKey("NORMAL")) { if (nn >= semanticToFloats.get("NORMAL").size()) { System.out.println("Bad normal index " + nn + " (out of " + semanticToFloats.get("NORMALS").size() + ")"); continue; } Point3f nnp = semanticToFloats.get("NORMAL").get(nn); oNorms.add(nnp); } int idx = oVerts.size(); combos.put(id, idx); oTris.add((short) idx); } } o.setVertices(oVerts); if (semanticToTriangles.containsKey("NORMAL")) { o.setNormals(oNorms); } o.setIndices(oTris); //System.out.println("Converted to verts="+oVerts.size()+", norms="+oNorms.size()+", tris="+oTris.size()); if (color == null) { } else { List<Point4f> colors = new ArrayList<>(); for (Point3f oVert : oVerts) { colors.add(color); } o.setColors(colors); } System.out.println(" added"); dae.add(o); } } System.out.println("Created " + dae.getChildren().size() + " objects"); return dae; } private static Point4f getColor(Node t) { String geomID = XMLUtils.getAttribute(t.getParentNode().getParentNode(), "id"); if (StringUtils.isTrivial(geomID)) { return null; } String material = XMLUtils.getAttribute(t, "material"); if (StringUtils.isTrivial(material)) { return null; } return mGeometryMaterials.get(geomID + "$" + material); } private static List<Point3f> findFloatArray(Node parent, String id) { Node src = findNodeWithValue(parent, "source", "id", id); if (src == null) { return null; } Node fsrc = XMLUtils.findFirstNode(src, "float_array"); if (fsrc == null) { return null; } Node asrc = XMLUtils.findFirstNode(src, "technique_common/accessor"); if (asrc == null) { return null; } int stride = IntegerUtils.parseInt(XMLUtils.getAttribute(asrc, "stride")); List<Point3f> floats = new ArrayList<>(); StringTokenizer st = new StringTokenizer(XMLUtils.getText(fsrc), " \r\n\t"); while (st.countTokens() > 0) { Point3f p = new Point3f(); p.x = FloatUtils.parseFloat(st.nextToken()); p.y = FloatUtils.parseFloat(st.nextToken()); if (stride == 3) { p.z = FloatUtils.parseFloat(st.nextToken()); } floats.add(p); } if (st.countTokens() != 0) { System.err.println("Odd numer of tokens for " + XMLUtils.getText(fsrc)); } return floats; } // private static String findInputSource(Node parent, String semantic) // { // Node i = findNodeWithValue(parent, "input", "semantic", semantic); // if (i != null) // { // String source = XMLUtils.getAttribute(i, "source"); // if (source.startsWith("#")) // source = source.substring(1); // return source; // } // return null; // } private static Node findNodeWithValue(Node parent, String nodeName, String attrName, String attrValue) { for (Node i : XMLUtils.findAllNodesRecursive(parent, nodeName)) { String s = XMLUtils.getAttribute(i, attrName); if (attrValue.equals(s)) { return i; } } return null; } private static void indexGeometryMaterials(Document doc) { mGeometryMaterials.clear(); for (Node ig : XMLUtils.findNodes(doc, "COLLADA/library_visual_scenes/visual_scene/node/instance_geometry")) { String geomID = XMLUtils.getAttribute(ig, "url"); if (StringUtils.isTrivial(geomID)) { continue; } if (geomID.startsWith("#")) { geomID = geomID.substring(1); } for (Node im : XMLUtils.findAllNodesRecursive(ig, "instance_material")) { String symbol = XMLUtils.getAttribute(im, "symbol"); String target = XMLUtils.getAttribute(im, "target"); if (target.startsWith("#")) { target = target.substring(1); } if (!mLibraryMaterials.containsKey(target)) { continue; } Point4f effect = mLibraryMaterials.get(target); if (effect == null) { continue; } mGeometryMaterials.put(geomID + "$" + symbol, effect); } } } private static void indexLibraryMaterials(Document doc) { mLibraryMaterials.clear(); for (Node e : XMLUtils.findNodes(doc, "COLLADA/library_materials/material")) { String id = XMLUtils.getAttribute(e, "id"); if (StringUtils.isTrivial(id)) { continue; } Node ie = XMLUtils.findFirstNode(e, "instance_effect"); if (ie == null) { continue; } String effectID = XMLUtils.getAttribute(ie, "url"); if (StringUtils.isTrivial(effectID)) { continue; } if (effectID.startsWith("#")) { effectID = effectID.substring(1); } Point4f effect = mLibraryEffects.get(effectID); if (effect == null) { continue; } mLibraryMaterials.put(id, effect); } } private static void indexLibraryEffects(Document doc) { mLibraryEffects.clear(); for (Node e : XMLUtils.findNodes(doc, "COLLADA/library_effects/effect")) { String id = XMLUtils.getAttribute(e, "id"); if (StringUtils.isTrivial(id)) { continue; } Node d = XMLUtils.findFirstNodeRecursive(e, "diffuse"); if (d == null) { continue; } Node c = XMLUtils.findFirstNodeRecursive(d, "color"); if (c == null) { continue; } StringTokenizer st = new StringTokenizer(XMLUtils.getText(c).trim(), " \t\r\n"); if (st.countTokens() != 4) { continue; } Point4f color = new Point4f(); color.x = FloatUtils.parseFloat(st.nextToken()); color.y = FloatUtils.parseFloat(st.nextToken()); color.z = FloatUtils.parseFloat(st.nextToken()); color.w = FloatUtils.parseFloat(st.nextToken()); mLibraryEffects.put(id, color); } } }