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