1 /* $RCSfile$ 2 * $Author: aherraez $ 3 * $Date: 2009-01-15 21:00:00 +0100 (Thu, 15 Jan 2009) $ 4 * $Revision: 7752 $ 5 6 * 7 * Copyright (C) 2003-2009 The Jmol Development Team 8 * 9 * Contact: jmol-developers@lists.sf.net 10 * 11 * This library is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU Lesser General Public 13 * License as published by the Free Software Foundation; either 14 * version 2.1 of the License, or (at your option) any later version. 15 * 16 * This library is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * Lesser General Public License for more details. 20 * 21 * You should have received a copy of the GNU Lesser General Public 22 * License along with this library; if not, write to the Free Software 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 24 */ 25 26 /* Based on _VrmlExporter by rhanson 27 and Help from http://x3dgraphics.com/examples/X3dForWebAuthors/index.html 28 */ 29 30 package org.jmol.export; 31 32 33 import java.util.Map; 34 35 import javajs.util.A4; 36 import javajs.util.Lst; 37 import javajs.util.P3; 38 import javajs.util.PT; 39 import javajs.util.T3; 40 41 import javajs.util.BS; 42 43 import org.jmol.util.Font; 44 import org.jmol.util.GData; 45 import org.jmol.viewer.Viewer; 46 47 public class _X3dExporter extends _VrmlExporter { 48 _X3dExporter()49 public _X3dExporter() { 50 super(); 51 useTable = new UseTable("USE='"); 52 } 53 54 55 @Override outputHeader()56 protected void outputHeader() { 57 output("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"); 58 output("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.1//EN\" \"http://www.web3d.org/specifications/x3d-3.1.dtd\">\n"); 59 output("<X3D profile='Immersive' version='3.1' " 60 + "xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' " 61 + "xsd:noNamespaceSchemaLocation=' http://www.web3d.org/specifications/x3d-3.1.xsd '>" 62 + "\n"); 63 output("<head>\n"); 64 output("<meta name='title' content=" 65 + PT.esc(vwr.ms.modelSetName).replace('<', ' ').replace('>', 66 ' ').replace('&', ' ') + "/>\n"); 67 output("<meta name='description' content='Jmol rendering'/>\n"); 68 output("<meta name='creator' content=' '/>\n"); 69 output("<meta name='created' content='" + getExportDate() + "'/>\n"); 70 output("<meta name='generator' content='Jmol " + Viewer.getJmolVersion() 71 + ", http://www.jmol.org'/>\n"); 72 output("<meta name='license' content='http://www.gnu.org/licenses/licenses.html#LGPL'/>\n"); 73 output("</head>\n"); 74 output("<Scene>\n"); 75 76 output("<NavigationInfo type='EXAMINE'/>\n"); 77 // puts the vwr into model-rotation mode 78 output("<Background skyColor='" + rgbFractionalFromColix(backgroundColix) 79 + "'/>\n"); 80 // next is an approximation only 81 float angle = getViewpoint(); 82 output("<Viewpoint fieldOfView='" + angle); 83 output("' position='"); 84 // remove export scaling for from Viewpoint so on-screen version is good. 85 cameraPosition.z *= exportScale; 86 output(cameraPosition); 87 output("' orientation='"); 88 output(tempP1); 89 output(" " + -viewpoint.angle + "'\n jump='true' description='v1'/>\n"); 90 output("\n <!-- \n"); 91 output(getJmolPerspective()); 92 output("\n -->\n\n"); 93 commentChar = null; 94 outputInitialTransform(); 95 } 96 97 @Override outputAttrPt(String attr, T3 pt)98 protected void outputAttrPt(String attr, T3 pt) { 99 output(" " + attr + "='" + pt.x + " " + pt.y + " " + pt.z + "'"); 100 } 101 102 @Override pushMatrix()103 protected void pushMatrix() { 104 output("<Transform "); 105 } 106 107 @Override popMatrix()108 protected void popMatrix() { 109 output("</Transform>\n"); 110 } 111 112 @Override outputAttr(String attr, float x, float y, float z)113 protected void outputAttr(String attr, float x, float y, float z) { 114 output(" " + attr + "='" + round(x) + " " + round(y) + " " + round(z) + "'"); 115 } 116 117 @Override outputRotation(A4 a)118 protected void outputRotation(A4 a) { 119 output(" rotation='" + a.x + " " + a.y + " " + a.z + " " + a.angle + "'"); 120 } 121 122 123 @Override outputFooter()124 protected void outputFooter() { 125 useTable = null; 126 popMatrix(); 127 popMatrix(); 128 output("</Scene>\n"); 129 output("</X3D>\n"); 130 } 131 132 @Override outputAppearance(short colix, boolean isText)133 protected void outputAppearance(short colix, boolean isText) { 134 String def = getDef((isText ? "T" : "") + colix); 135 output("<Appearance "); 136 if (def.charAt(0) == '_') { 137 String color = rgbFractionalFromColix(colix); 138 output("DEF='" + def + "'><Material diffuseColor='"); 139 if (isText) 140 output("0 0 0' specularColor='0 0 0' ambientIntensity='0.0' shininess='0.0' emissiveColor='" 141 + color + "'/>"); 142 else 143 output(color + "' transparency='" + translucencyFractionalFromColix(colix) + "'/>" ); 144 } 145 else 146 output(def +">"); 147 output("</Appearance>"); 148 } 149 150 @Override outputChildShapeStart()151 protected void outputChildShapeStart() { 152 outputShapeStart(); 153 } 154 155 @Override outputShapeStart()156 protected void outputShapeStart() { 157 output("<Shape>"); 158 outputFaceSetStart(); 159 } 160 161 @Override outputChildStart()162 protected void outputChildStart() { 163 // not used! 164 } 165 166 @Override outputChildClose()167 protected void outputChildClose() { 168 // not used! 169 } 170 171 @Override outputDefChildFaceSet(String child)172 protected void outputDefChildFaceSet(String child) { 173 if (child != null) 174 output("DEF='" + child + "'"); 175 } 176 177 @Override outputFaceSetStart()178 protected void outputFaceSetStart() { 179 output("<IndexedFaceSet "); 180 } 181 182 @Override outputFaceSetClose()183 protected void outputFaceSetClose() { 184 output("</IndexedFaceSet>\n"); 185 } 186 187 @Override outputUseChildClose(String child)188 protected void outputUseChildClose(String child) { 189 output(child + "/>"); 190 } 191 192 @Override outputChildShapeClose()193 protected void outputChildShapeClose() { 194 outputShapeClose(); 195 } 196 197 @Override outputShapeClose()198 protected void outputShapeClose() { 199 output("</Shape>\n"); 200 } 201 202 @Override outputCloseTag()203 protected void outputCloseTag() { 204 output(">\n"); 205 } 206 207 208 @Override outputTriangle(T3 pt1, T3 pt2, T3 pt3, short colix)209 protected void outputTriangle(T3 pt1, T3 pt2, T3 pt3, short colix) { 210 // nucleic base 211 // cartoons 212 output("<Shape>\n"); 213 output("<IndexedFaceSet solid='false' "); 214 output("coordIndex='0 1 2 -1'>"); 215 output("<Coordinate point='"); 216 output(pt1); 217 output(" "); 218 output(pt2); 219 output(" "); 220 output(pt3); 221 output("'/>"); 222 output("</IndexedFaceSet>\n"); 223 outputAppearance(colix, false); 224 output("\n</Shape>\n"); 225 } 226 227 228 @Override outputCircle(P3 pt1, P3 pt2, float radius, short colix, boolean doFill)229 protected void outputCircle(P3 pt1, P3 pt2, float radius, short colix, 230 boolean doFill) { 231 232 // not fixed -- still duplicated in X3d 233 if (doFill) { 234 235 // draw filled circle 236 pushMatrix(); 237 output("translation='"); 238 tempV1.ave(tempP3, pt1); 239 output(tempV1); 240 output("'><Billboard axisOfRotation='0 0 0'>"); 241 pushMatrix(); 242 output ("rotation='1 0 0 1.5708'"); 243 float height = pt1.distance(pt2); 244 outputAttr("scale", radius, height, radius); 245 output(">"); 246 outputCylinderChildScaled(colix, GData.ENDCAPS_FLAT); 247 popMatrix(); 248 output("</Billboard>"); 249 popMatrix(); 250 251 return; 252 } 253 254 // draw a thin torus 255 256 String child = getDef("C" + colix + "_" + radius); 257 pushMatrix(); 258 outputTransRot(tempP3, pt1, 0, 0, 1); 259 tempP3.set(1, 1, 1); 260 tempP3.scale(radius); 261 outputAttr("scale", tempP3.x, tempP3.y, tempP3.z); 262 output(">\n<Billboard "); 263 if (child.charAt(0) == '_') { 264 output("DEF='" + child + "'"); 265 output(" axisOfRotation='0 0 0'>"); 266 pushMatrix(); 267 output("<Shape><Extrusion beginCap='false' convex='false' endCap='false' creaseAngle='1.57'"); 268 output(" crossSection='"); 269 float rpd = 3.1415926f / 180; 270 float scale = 0.02f / radius; 271 for (int i = 0; i <= 360; i += 10) { 272 output(round(Math.cos(i * rpd) * scale) + " "); 273 output(round(Math.sin(i * rpd) * scale) + " "); 274 } 275 output("' spine='"); 276 for (int i = 0; i <= 360; i += 10) { 277 output(round(Math.cos(i * rpd)) + " "); 278 output(round(Math.sin(i * rpd)) + " 0 "); 279 } 280 output("'/>"); 281 outputAppearance(colix, false); 282 output("</Shape>"); 283 popMatrix(); 284 } else { 285 output(child + ">"); 286 } 287 output("</Billboard>\n"); 288 popMatrix(); 289 } 290 291 @Override outputGeometry(T3[] vertices, T3[] normals, short[] colixes, int[][] indices, short[] polygonColixes, int nVertices, int nPolygons, BS bsPolygons, int faceVertexMax, Lst<Short> colorList, Map<Short, Integer> htColixes, P3 offset)292 protected void outputGeometry(T3[] vertices, T3[] normals, 293 short[] colixes, int[][] indices, 294 short[] polygonColixes, 295 int nVertices, int nPolygons, 296 BS bsPolygons, 297 int faceVertexMax, Lst<Short> colorList, Map<Short, Integer> htColixes, P3 offset) { 298 299 output(" creaseAngle='0.5'\n"); 300 301 if (polygonColixes != null) 302 output(" colorPerVertex='false'\n"); 303 304 // coordinates, part 1 305 306 output("coordIndex='\n"); 307 int[] map = new int[nVertices]; 308 getCoordinateMap(vertices, map, null); 309 outputIndices(indices, map, nPolygons, bsPolygons, faceVertexMax); 310 output("'\n"); 311 312 // normals, part 1 313 314 Lst<String> vNormals = null; 315 if (normals != null) { 316 vNormals = new Lst<String>(); 317 map = getNormalMap(normals, nVertices, null, vNormals); 318 output(" solid='false'\n normalPerVertex='true'\n normalIndex='\n"); 319 outputIndices(indices, map, nPolygons, bsPolygons, faceVertexMax); 320 output("'\n"); 321 } 322 323 map = null; 324 325 // colors, part 1 326 327 if (colorList != null) { 328 output(" colorIndex='\n"); 329 outputColorIndices(indices, nPolygons, bsPolygons, faceVertexMax, htColixes, colixes, polygonColixes); 330 output("'\n"); 331 } 332 333 output(">\n"); // closes IndexedFaceSet opening tag 334 335 // coordinates, part 2 336 337 output("<Coordinate point='\n"); 338 outputVertices(vertices, nVertices, offset); 339 output("'/>\n"); 340 341 // normals, part 2 342 343 if (normals != null) { 344 output("<Normal vector='\n"); 345 outputNormals(vNormals); 346 vNormals = null; 347 output("'/>\n"); 348 } 349 350 // colors, part 2 351 352 if (colorList != null) { 353 output("<Color color='\n"); 354 outputColors(colorList); 355 output("'/>\n"); 356 } 357 } 358 359 @Override outputTextPixel(P3 pt, int argb)360 protected void outputTextPixel(P3 pt, int argb) { 361 // // text only 362 // String color = rgbFractionalFromArgb(argb); 363 // output("<Transform translation='"); 364 // output(pt); 365 // output("'>\n<Shape "); 366 // String child = getDef("p" + argb); 367 // if (child.charAt(0) == '_') { 368 // output("DEF='" + child + "'>"); 369 // output("<Sphere radius='0.01'/>"); 370 // output("<Appearance><Material diffuseColor='0 0 0' specularColor='0 0 0'" 371 // + " ambientIntensity='0.0' shininess='0.0' emissiveColor='" 372 // + color + "'/></Appearance>'"); 373 // } else { 374 // output(child + ">"); 375 // } 376 // output("</Shape>\n"); 377 // output("</Transform>\n"); 378 } 379 380 @Override plotText(int x, int y, int z, short colix, String text, Font font3d)381 void plotText(int x, int y, int z, short colix, String text, Font font3d) { 382 // output("<Transform translation='"); 383 // output(setFont(x, y, z, colix, text, font3d)); 384 // output("'>"); 385 // // These x y z are 3D coordinates of echo or the atom the label is attached 386 // // to. 387 // output("<Billboard "); 388 // if (fontChild.charAt(0) == '_') { 389 // output("DEF='" + fontChild + "' axisOfRotation='0 0 0'>" 390 // + "<Transform translation='0.0 0.0 0.0'>" 391 // + "<Shape>"); 392 // outputAppearance(colix, true); 393 // output("<Text string=" + PT.esc(text) + ">"); 394 // output("<FontStyle "); 395 // String fontstyle = getDef("F" + fontFace + fontStyle); 396 // if (fontstyle.charAt(0) == '_') { 397 // output("DEF='" + fontstyle + "' size='"+fontSize+"' family='" + fontFace 398 // + "' style='" + fontStyle + "'/>"); 399 // } else { 400 // output(fontstyle + "/>"); 401 // } 402 // output("</Text>"); 403 // output("</Shape>"); 404 // output("</Transform>"); 405 // } else { 406 // output(fontChild + ">"); 407 // } 408 // output("</Billboard>\n"); 409 // output("</Transform>\n"); 410 // 411 // /* 412 // * Unsolved issues: # Non-label texts: echos, measurements :: need to get 413 // * space coordinates, not screen coord. # Font size: not implemented; 0.4A 414 // * is hardcoded (resizes with zoom) Java VRML font3d.fontSize = 13.0 size 415 // * (numeric), but in angstroms, not pixels font3d.fontSizeNominal = 13.0 # 416 // * Label offsets: not implemented; hardcoded to 0.25A in each x,y,z # 417 // * Multi-line labels: only the first line is received # Sub/superscripts not 418 // * interpreted 419 // */ 420 } 421 422 // @Override 423 // protected void outputCone(P3 ptBase, P3 ptTip, float radius, 424 // short colix) { 425 // float height = ptBase.distance(ptTip); 426 // pushMatrix(); 427 // outputTransRot(ptBase, ptTip, 0, 1, 0); 428 // outputAttr("scale", radius, height, radius); 429 // outputCloseTag(); 430 // outputShapeStart(); 431 // String child = getDef("c"); 432 // if (child.charAt(0) == '_') { 433 // outputDefChildFaceSet(child); 434 // outputConeGeometry(true); 435 // outputCloseFaceSet(); 436 // } else { 437 // outputChildClose(child); 438 // } 439 // outputAppearance(colix, false); 440 // outputShapeClose(); 441 // popMatrix(); 442 // } 443 // 444 // @Override 445 // protected boolean outputCylinder(P3 ptCenter, P3 pt1, P3 pt2, 446 // short colix, byte endcaps, float radius, P3 ptX, P3 ptY, boolean checkRadius) { 447 // float height = pt1.distance(pt2); 448 // pushMatrix(); 449 // if (ptX == null) { 450 // outputTransRot(pt1, pt2, 0, 1, 0); 451 // outputAttr("scale", radius, height, radius); 452 // } else { 453 // outputAttrPt("translation", ptCenter); 454 // outputQuaternionFrame(ptCenter, ptY, pt1, ptX, 2, 2, 2); 455 // pt1.set(0, 0, -0.5f); 456 // pt2.set(0, 0, 0.5f); 457 // } 458 // outputCloseTag(); 459 // outputCylinderChildScaled(colix, endcaps); 460 // popMatrix(); 461 //// if (endcaps == GData.ENDCAPS_SPHERICAL) { 462 //// outputSphere(pt1, radius * 1.01f, colix, true); 463 //// outputSphere(pt2, radius * 1.01f, colix, true); 464 //// } 465 // return true; 466 // } 467 // 468 // @Override 469 // protected void outputCylinderChildScaled(short colix, 470 // byte endcaps) { 471 // outputShapeStart(); 472 // String child = getDef("C" + "_" + endcaps); 473 // if (child.charAt(0) == '_') { 474 // outputDefChildFaceSet(child); 475 // outputCylinderGeometry(endcaps); 476 // outputCloseFaceSet(); 477 // } else { 478 // outputUseChildClose(child); 479 // } 480 // outputAppearance(colix, false); 481 // outputShapeClose(); 482 // } 483 484 // @Override 485 // protected void outputSurface(T3[] vertices, T3[] normals, 486 // short[] colixes, int[][] indices, 487 // short[] polygonColixes, 488 // int nVertices, int nPolygons, int nTriangles, BS bsPolygons, 489 // int faceVertexMax, short colix, 490 // Lst<Short> colorList, Map<Short, Integer> htColixes, P3 offset) { 491 // output("<Shape><IndexedFaceSet \n"); 492 // outputGeometry(vertices, normals, colixes, indices, polygonColixes, 493 // nVertices, nPolygons, bsPolygons, faceVertexMax, colorList, 494 // htColixes, offset); 495 // output("</IndexedFaceSet>"); 496 // outputAppearance(colix, false); 497 // output("</Shape>\n"); 498 // } 499 500 501 } 502