00001
00002
00003
00004
00005
00006
00007
00008 package edu.tum.cs.vis.model.parser;
00009
00010 import java.awt.Color;
00011 import java.io.File;
00012 import java.io.FileNotFoundException;
00013 import java.io.IOException;
00014 import java.util.ArrayList;
00015 import java.util.HashMap;
00016 import java.util.LinkedList;
00017 import java.util.List;
00018 import java.util.Map;
00019 import java.util.regex.Matcher;
00020
00021 import javax.vecmath.Point2f;
00022 import javax.vecmath.Vector3f;
00023 import javax.xml.parsers.DocumentBuilder;
00024 import javax.xml.parsers.DocumentBuilderFactory;
00025 import javax.xml.parsers.ParserConfigurationException;
00026
00027 import org.w3c.dom.Document;
00028 import org.w3c.dom.Element;
00029 import org.w3c.dom.NodeList;
00030 import org.xml.sax.SAXException;
00031
00032 import com.dddviewr.collada.Collada;
00033 import com.dddviewr.collada.Input;
00034 import com.dddviewr.collada.Source;
00035 import com.dddviewr.collada.Unit;
00036 import com.dddviewr.collada.effects.Blinn;
00037 import com.dddviewr.collada.effects.Effect;
00038 import com.dddviewr.collada.effects.EffectAttribute;
00039 import com.dddviewr.collada.effects.Lambert;
00040 import com.dddviewr.collada.geometry.Geometry;
00041 import com.dddviewr.collada.geometry.Lines;
00042 import com.dddviewr.collada.geometry.Mesh;
00043 import com.dddviewr.collada.geometry.Primitives;
00044 import com.dddviewr.collada.geometry.Triangles;
00045 import com.dddviewr.collada.materials.Material;
00046 import com.dddviewr.collada.nodes.Node;
00047 import com.dddviewr.collada.visualscene.BaseXform;
00048 import com.dddviewr.collada.visualscene.InstanceGeometry;
00049 import com.dddviewr.collada.visualscene.InstanceMaterial;
00050 import com.dddviewr.collada.visualscene.InstanceNode;
00051 import com.dddviewr.collada.visualscene.Matrix;
00052 import com.dddviewr.collada.visualscene.VisualScene;
00053
00054 import edu.tum.cs.ias.knowrob.utils.FileUtil;
00055 import edu.tum.cs.ias.knowrob.utils.ResourceRetriever;
00056 import edu.tum.cs.vis.model.Model;
00057 import edu.tum.cs.vis.model.util.Appearance;
00058 import edu.tum.cs.vis.model.util.Group;
00059 import edu.tum.cs.vis.model.util.Line;
00060 import edu.tum.cs.vis.model.util.Triangle;
00061 import edu.tum.cs.vis.model.util.Vertex;
00062
00071 public class ColladaParser extends ModelParser {
00072
00082 private static Appearance getAppearance(Material mat, Collada collada) {
00083 Appearance appearance = new Appearance();
00084 Effect effect = collada.findEffect(mat.getInstanceEffect().getUrl().substring(1));
00085 if (effect.getEffectMaterial() instanceof Lambert) {
00086 Lambert lambert = (Lambert) effect.getEffectMaterial();
00087 EffectAttribute diffuse = lambert.getDiffuse();
00088 String texturePath = null;
00089 Color materialColor = new Color(0.5f, 0.5f, 0.5f, 1.0f);
00090 if (diffuse.getTexture() != null) {
00091 texturePath = collada.findImage(
00092 effect.findNewParam(
00093 effect.findNewParam(diffuse.getTexture().getTexture())
00094 .getSampler2D().getSource()).getSurface().getInitFrom())
00095 .getInitFrom();
00096 if (texturePath.startsWith("./images/"))
00097 texturePath = "." + texturePath;
00098 } else {
00099 float[] colors = diffuse.getData();
00100
00101 materialColor = new Color(colors[0], colors[1], colors[2], colors[3]);
00102 }
00103
00104 if (texturePath != null) {
00105 appearance.setImageFileName(texturePath);
00106 } else {
00107
00108
00109 appearance.setColorFill(materialColor);
00110 appearance.setColorLine(materialColor);
00111 }
00112 } else if (effect.getEffectMaterial() instanceof Blinn) {
00113
00114 Blinn blinn = (Blinn) effect.getEffectMaterial();
00115
00116 String texturePath = null;
00117 if (blinn.getDiffuse().getTexture() != null) {
00118 texturePath = collada.findImage(
00119 effect.findNewParam(
00120 effect.findNewParam(blinn.getDiffuse().getTexture().getTexture())
00121 .getSampler2D().getSource()).getSurface().getInitFrom())
00122 .getInitFrom();
00123 if (texturePath.startsWith("./images/"))
00124 texturePath = "." + texturePath;
00125 appearance.setImageFileName(texturePath);
00126 } else {
00127
00128 float[] emission = blinn.getEmission().getData();
00129 float[] ambient = blinn.getAmbient().getData();
00130 float[] diffuse = blinn.getDiffuse().getData();
00131 float[] specular = blinn.getSpecular().getData();
00132 float[] shininess = blinn.getShininess().getData();
00133 float[] result = new float[4];
00134 for (int i = 0; i < 4; i++) {
00135 result[i] = 0;
00136 if (emission != null)
00137 result[i] += emission[i];
00138 if (ambient != null)
00139 result[i] += ambient[i];
00140 if (diffuse != null)
00141 result[i] += diffuse[i];
00142 if (specular != null && shininess != null)
00143 result[i] += (float) Math.pow(specular[i], shininess[0]);
00144 }
00145
00146
00147 appearance.setColorFill(new Color(result[0], result[1], result[2], Math.min(
00148 result[3], 1f)));
00149 appearance.setColorLine(appearance.getColorFill());
00150 }
00151
00152 }
00153 return appearance;
00154 }
00155
00164 private static String getDaeLocation(String tmpPath) {
00165 File kmlFile = new File(tmpPath + "doc.kml");
00166 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
00167 DocumentBuilder dBuilder = null;
00168 try {
00169 dBuilder = dbFactory.newDocumentBuilder();
00170 } catch (ParserConfigurationException e) {
00171 System.err.println("Couldn't get .dae location from doc.kml: " + e.getMessage());
00172 return null;
00173 }
00174 Document doc;
00175 try {
00176 doc = dBuilder.parse(kmlFile);
00177 } catch (SAXException e) {
00178 System.err.println("Couldn't get .dae location from doc.kml: " + e.getMessage());
00179 return null;
00180 } catch (IOException e) {
00181 System.err.println("Couldn't get .dae location from doc.kml: " + e.getMessage());
00182 return null;
00183 }
00184 doc.getDocumentElement().normalize();
00185
00186 if (!doc.getDocumentElement().getNodeName().equalsIgnoreCase("kml")) {
00187 System.out.println("Invalid doc.kml file. Root node must be 'kml'");
00188 return null;
00189 }
00190
00191 LinkedList<String> nodeNames = new LinkedList<String>();
00192 nodeNames.add("Placemark");
00193 nodeNames.add("Model");
00194 nodeNames.add("Link");
00195 nodeNames.add("href");
00196
00197 NodeList nList = doc.getElementsByTagName(nodeNames.poll());
00198
00199 String loc = getNodeValue(nList, nodeNames);
00200 if (loc == null) {
00201 System.out.println("Couldn't get .dae location from doc.kml");
00202 return null;
00203 }
00204
00205 String ret = tmpPath + loc;
00206 if (File.separator.equals("\\")) {
00207 ret = ret.replaceAll("/", Matcher.quoteReplacement(File.separator));
00208 } else {
00209 ret = ret.replaceAll("\\\\", Matcher.quoteReplacement(File.separator));
00210 }
00211 return ret;
00212 }
00213
00225 private static String getNodeValue(NodeList nList, LinkedList<String> nodeNames) {
00226 if (nodeNames.isEmpty() || nList == null) {
00227 return null;
00228 }
00229 if (nodeNames.size() == 1) {
00230 for (int temp = 0; temp < nList.getLength(); temp++) {
00231 org.w3c.dom.Node nNode = nList.item(temp);
00232 if (nNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
00233 Element element = (Element) nNode;
00234 NodeList nlList = element.getElementsByTagName(nodeNames.poll());
00235 if (nlList == null)
00236 return null;
00237 nlList = nlList.item(0).getChildNodes();
00238
00239 org.w3c.dom.Node nValue = nlList.item(0);
00240 return nValue.getNodeValue();
00241
00242 }
00243 }
00244 } else {
00245 for (int temp = 0; temp < nList.getLength(); temp++) {
00246
00247 org.w3c.dom.Node nNode = nList.item(temp);
00248
00249 if (nNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
00250
00251 Element element = (Element) nNode;
00252
00253 LinkedList<String> tmpNodeNames = new LinkedList<String>();
00254 tmpNodeNames.addAll(nodeNames);
00255 String val = getNodeValue(element.getElementsByTagName(tmpNodeNames.poll()),
00256 tmpNodeNames);
00257 if (val != null)
00258 return val;
00259 }
00260 }
00261 }
00262 return null;
00263 }
00264
00276 private static ArrayList<Vertex> getVerticesOfMesh(Mesh m, List<Input> inputs, String type) {
00277 Source vertexSource = null;
00278 for (Input in : inputs) {
00279 if (in.getSemantic().compareTo(type) == 0) {
00280 vertexSource = m.getSource(in.getSource().substring(1));
00281 }
00282 }
00283
00284 if (vertexSource == null) {
00285 return null;
00286 }
00287
00288 float[][] vertPoints = SourceToFloat(vertexSource);
00289
00290 ArrayList<Vertex> vertices = new ArrayList<Vertex>();
00291 for (int i = 0; i < vertPoints.length; i++) {
00292 vertices.add(new Vertex(vertPoints[i][0], vertPoints[i][1], vertPoints[i][2]));
00293 }
00294
00295 return vertices;
00296 }
00297
00314 private static void parseGeometry(Geometry g, Group currGroup,
00315 Map<String, String> instanceMaterial, List<BaseXform> transformations, Collada collada) {
00316 Mesh m = g.getMesh();
00317 ArrayList<Vertex> vertices = getVerticesOfMesh(m, m.getVertices().getInputs(), "POSITION");
00318 ArrayList<Vertex> normals = getVerticesOfMesh(m, m.getVertices().getInputs(), "NORMAL");
00319
00320 for (int i = 0; i < vertices.size(); i++) {
00321 Vertex v = vertices.get(i);
00322 useTransformation(v, transformations, true);
00323 if (normals != null) {
00324 Vertex n = normals.get(i);
00325 useTransformation(n, transformations, false);
00326 v.setNormalVector(new Vector3f(n.x, n.y, n.z));
00327 }
00328 }
00329
00330 currGroup.getModel().getVertices().addAll(vertices);
00331
00332 for (Primitives p : m.getPrimitives()) {
00333 if (p instanceof Triangles) {
00334 Triangles t = (Triangles) p;
00335 parseGeometryTriangle(t, currGroup, instanceMaterial, collada, vertices, m);
00336 } else if (p instanceof Lines) {
00337 Lines l = (Lines) p;
00338 parseGeometryLine(l, currGroup, instanceMaterial, collada, vertices);
00339 }
00340 }
00341 }
00342
00358 private static void parseGeometryLine(Lines l, Group currGroup,
00359 Map<String, String> instanceMaterial, Collada collada, List<Vertex> vertices) {
00360 Material mat = null;
00361 if (instanceMaterial.containsKey(l.getMaterial())) {
00362 mat = collada.findMaterial(instanceMaterial.get(l.getMaterial()));
00363
00364 } else {
00365 l.dump(System.err, 5);
00366 throw new RuntimeException("No material given for Line (see above) ");
00367 }
00368
00369 int stride = l.getInputs().size();
00370 int count = l.getCount();
00371
00372 int[][] indexes = new int[count * 3][stride];
00373
00374 for (int i = 0, k = 0; i < count * 3; i++) {
00375 for (int j = 0; j < stride; j++, k++)
00376 indexes[i][j] = l.getData()[k];
00377 }
00378
00379 int vertexOffset = 0;
00380 for (Input i : l.getInputs()) {
00381 if (i.getSemantic().compareTo("VERTEX") == 0)
00382 vertexOffset = i.getOffset();
00383
00384 }
00385
00386 Appearance appearance = getAppearance(mat, collada);
00387 appearance.setColorFill(null);
00388
00389
00390 for (int i = 0; i < indexes.length && i + 2 < indexes.length; i++) {
00391 Line line = new Line();
00392 line.setAppearance(appearance);
00393
00394 for (int v = 0; v < 2; v++) {
00395
00396 line.getPosition()[v] = vertices.get(indexes[i][vertexOffset]);
00397
00398 i++;
00399 }
00400 line.updateCentroid();
00401 i -= 2;
00402
00403
00404
00405 currGroup.getMesh().getLines().add(line);
00406 currGroup.getModel().getLines().add(line);
00407 }
00408 }
00409
00427 private static void parseGeometryTriangle(Triangles t, Group currGroup,
00428 Map<String, String> instanceMaterial, Collada collada, List<Vertex> vertices, Mesh m) {
00429 Appearance appearance;
00430 if (instanceMaterial.containsKey(t.getMaterial())) {
00431 Material mat = collada.findMaterial(instanceMaterial.get(t.getMaterial()));
00432 appearance = getAppearance(mat, collada);
00433 appearance.setColorLine(null);
00434
00435 } else {
00436
00437 appearance = new Appearance();
00438 appearance.setColorFill(new Color(120, 120, 120));
00439 }
00440
00441 int stride = t.getInputs().size();
00442 int count = t.getCount();
00443
00444 int[][] indexes = new int[count * 3][stride];
00445
00446 for (int i = 0, k = 0; i < count * 3; i++) {
00447 for (int j = 0; j < stride; j++, k++)
00448 indexes[i][j] = t.getData()[k];
00449 }
00450
00451 int vertexOffset = 0, textureOffset = 0, normalOffset = 0;
00452 Source textureSource = null;
00453 Source normalSource = null;
00454 for (Input i : t.getInputs()) {
00455 if (i.getSemantic().equals("VERTEX"))
00456 vertexOffset = i.getOffset();
00457 else if (i.getSemantic().equals("TEXCOORD")) {
00458 textureOffset = i.getOffset();
00459 textureSource = m.getSource(i.getSource().substring(1));
00460 } else if (i.getSemantic().equals("NORMAL")) {
00461 normalOffset = i.getOffset();
00462 normalSource = m.getSource(i.getSource().substring(1));
00463 }
00464
00465 }
00466
00467 float[][] texturePoints = null;
00468 if (textureSource != null) {
00469
00470 texturePoints = SourceToFloat(textureSource);
00471 }
00472
00473 float[][] normalCoordinates = null;
00474 if (normalSource != null) {
00475
00476 normalCoordinates = SourceToFloat(normalSource);
00477 }
00478
00479
00480 for (int i = 0; i < indexes.length; i++) {
00481 Triangle tri = new Triangle();
00482 tri.setAppearance(appearance);
00483
00484 if (tri.getAppearance().getImageFileName() != null)
00485 tri.setTexPosition(new Point2f[3]);
00486
00487
00488 for (int v = 0; v < 3; v++) {
00489
00490 Vertex vert = vertices.get(indexes[i][vertexOffset]);
00491
00492 tri.getPosition()[v] = vert;
00493
00494
00495 if (tri.getAppearance().getImageFileName() != null) {
00496 tri.getTexPosition()[v] = new Point2f(
00497 texturePoints[indexes[i][textureOffset]][0],
00498 texturePoints[indexes[i][textureOffset]][1]);
00499 }
00500
00501 if (normalCoordinates != null) {
00502 Vector3f norm = new Vector3f(normalCoordinates[indexes[i][normalOffset]][0],
00503 normalCoordinates[indexes[i][normalOffset]][1],
00504 normalCoordinates[indexes[i][normalOffset]][2]);
00505 vert.setNormalVector(norm);
00506 }
00507
00508 i++;
00509 }
00510 i--;
00511
00512 if (!tri.calculateNormalVector()) {
00513 continue;
00514 }
00515 tri.updateCentroid();
00516
00517
00518 currGroup.addTriangle(tri);
00519 }
00520
00521 }
00522
00530 private static float[][] SourceToFloat(Source s) {
00531 float ret[][] = new float[s.getAccessor().getCount()][s.getAccessor().getStride()];
00532 for (int i = 0, k = 0; i < s.getAccessor().getCount(); i++) {
00533 for (int j = 0; j < s.getAccessor().getStride(); j++, k++)
00534 ret[i][j] = s.getFloatArray().get(k);
00535 }
00536 return ret;
00537 }
00538
00550 private static void useTransformation(Vertex vertex, List<BaseXform> transformations,
00551 boolean withTranslate) {
00552 for (int idx = transformations.size() - 1; idx >= 0; idx--) {
00553 BaseXform transform = transformations.get(idx);
00554 if (transform instanceof Matrix) {
00555 int cnt = 4;
00556 float matrix[][] = new float[cnt][cnt];
00557 int v = 0;
00558 for (int ma_y = 0; ma_y < cnt; ma_y++) {
00559 for (int ma_x = 0; ma_x < cnt; ma_x++) {
00560 if (!withTranslate && (ma_y > 2 || ma_x > 2) && ma_y != ma_x)
00561
00562
00563 matrix[ma_y][ma_x] = 0;
00564 else
00565 matrix[ma_y][ma_x] = ((Matrix) transform).getData()[v];
00566
00567 v++;
00568 }
00569 }
00570 vertex.transform(matrix);
00571 } else {
00572 System.out.println("Transformation not implemented: ");
00573 transform.dump(System.out, 4);
00574 }
00575 }
00576 }
00577
00582 private String textureBasePath = "";
00583
00584 @Override
00585 protected boolean loadModel(String filename) {
00586 Collada collada = null;
00587 textureBasePath = null;
00588 String daeFile = null;
00589
00590
00591 String extension = getExtension(filename);
00592 if (extension.equalsIgnoreCase("kmz")) {
00593 String tmpPath = ResourceRetriever.createTempDirectory();
00594 if (!tmpPath.endsWith("/") && !tmpPath.endsWith("\\"))
00595 tmpPath += File.separator;
00596 FileUtil.Unzip(filename, tmpPath);
00597
00598 daeFile = getDaeLocation(tmpPath);
00599
00600 textureBasePath = daeFile.substring(0, daeFile.lastIndexOf(File.separator));
00601
00602 if (!textureBasePath.endsWith("/") && !textureBasePath.endsWith("\\"))
00603 textureBasePath += File.separator;
00604
00605 } else if (extension.equalsIgnoreCase("dae")) {
00606 String fullPath = new File(filename).getPath();
00607 textureBasePath = fullPath.substring(0, fullPath.length()
00608 - new File(filename).getName().length());
00609 daeFile = filename;
00610 }
00611
00612
00613 try {
00614 collada = Collada.readFile(daeFile);
00615 } catch (FileNotFoundException e) {
00616 System.err.println("File doesn't exists: " + daeFile);
00617 e.printStackTrace();
00618 return false;
00619 } catch (SAXException e) {
00620 System.err.println("XML-Exception in : " + daeFile);
00621 e.printStackTrace();
00622 return false;
00623 } catch (IOException e) {
00624 System.err.println("IO-Exception in : " + daeFile);
00625 e.printStackTrace();
00626 return false;
00627 }
00628
00629 model = new Model();
00630 model.setGroup(new Group(model));
00631
00632
00633
00634
00635 VisualScene scene = collada.getLibraryVisualScenes().getScene(
00636 collada.getScene().getInstanceVisualScene().getUrl());
00637
00638 for (Node n : scene.getNodes()) {
00639 parseNode(n, model.getGroup(), new ArrayList<BaseXform>(), collada);
00640 }
00641
00642 model.setTextureBasePath(textureBasePath);
00643
00644 Unit unit = collada.getUnit();
00645 if (unit != null && unit.getMeter() != 1.0) {
00646 model.scale(unit.getMeter());
00647 }
00648
00649 model.mirrorX();
00650
00651 return true;
00652 }
00653
00667 private void parseNode(Node node, Group currGroup, ArrayList<BaseXform> transformations,
00668 Collada collada) {
00669
00670
00671 if (node.getXforms() != null)
00672 transformations.addAll(node.getXforms());
00673
00674
00675 if (node.getChildNodes() != null) {
00676 for (Node child : node.getChildNodes()) {
00677 Group g = new Group(currGroup.getModel());
00678 g.setName(child.getName());
00679 currGroup.addChild(g);
00680 parseNode(child, g, transformations, collada);
00681 }
00682 }
00683
00684
00685 InstanceNode instNode = node.getInstanceNode();
00686 if (instNode != null) {
00687 parseNode(collada.findNode(instNode.getUrl()), currGroup, transformations, collada);
00688 }
00689
00690
00691 List<InstanceGeometry> instGeoList = node.getInstanceGeometry();
00692
00693 for (InstanceGeometry instGeo : instGeoList) {
00694 HashMap<String, String> instanceMaterial = new HashMap<String, String>();
00695 for (InstanceMaterial mat : instGeo.getInstanceMaterials()) {
00696 instanceMaterial.put(mat.getSymbol(), mat.getTarget());
00697 }
00698 parseGeometry(collada.findGeometry(instGeo.getUrl()), currGroup, instanceMaterial,
00699 transformations, collada);
00700 }
00701
00702
00703 if (node.getXforms() != null)
00704 transformations.removeAll(node.getXforms());
00705 }
00706 }