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