View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2025.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.potential.bonded;
39  
40  import org.jogamp.java3d.Appearance;
41  import org.jogamp.java3d.BranchGroup;
42  import org.jogamp.java3d.Canvas3D;
43  import org.jogamp.java3d.ColoringAttributes;
44  import org.jogamp.java3d.Geometry;
45  import org.jogamp.java3d.GeometryArray;
46  import org.jogamp.java3d.LineAttributes;
47  import org.jogamp.java3d.Material;
48  import org.jogamp.java3d.Node;
49  import org.jogamp.java3d.PointAttributes;
50  import org.jogamp.java3d.PolygonAttributes;
51  import org.jogamp.java3d.RenderingAttributes;
52  import org.jogamp.java3d.ShaderAppearance;
53  import org.jogamp.java3d.ShaderProgram;
54  import org.jogamp.java3d.Shape3D;
55  import org.jogamp.java3d.Transform3D;
56  import org.jogamp.java3d.TransformGroup;
57  import org.jogamp.java3d.TransparencyAttributes;
58  import org.jogamp.java3d.utils.geometry.Cone;
59  import org.jogamp.java3d.utils.geometry.Cylinder;
60  import org.jogamp.java3d.utils.geometry.Sphere;
61  import org.jogamp.vecmath.Color3f;
62  import org.jogamp.vecmath.Point2d;
63  import org.jogamp.vecmath.Point3d;
64  import org.jogamp.vecmath.Vector3d;
65  
66  import java.awt.Color;
67  import java.util.ArrayList;
68  import java.util.Collections;
69  import java.util.Hashtable;
70  import java.util.List;
71  
72  /**
73   * The RendererCache class defines constants related to rendering modes and caches primitives for
74   * the Renderer.
75   *
76   * @author Michael J. Schnieders
77   * @since 1.0
78   */
79  public class RendererCache {
80  
81    /** Constant <code>BLACK</code> */
82    public static final Color3f BLACK = new Color3f(Color.black.getRGBColorComponents(new float[3]));
83    /** Constant <code>viewModelHash</code> */
84    public static final Hashtable<String, ViewModel> viewModelHash = new Hashtable<>();
85    /** Constant <code>colorModelHash</code> */
86    public static final Hashtable<String, ColorModel> colorModelHash = new Hashtable<>();
87    /** Constant <code>ORANGE</code> */
88    static final Color3f ORANGE = new Color3f(Color.orange.getRGBColorComponents(new float[3]));
89    /** Constant <code>RED</code> */
90    static final Color3f RED = new Color3f(Color.red.getRGBColorComponents(new float[3]));
91    /** Constant <code>BLUE</code> */
92    static final Color3f BLUE = new Color3f(Color.blue.getRGBColorComponents(new float[3]));
93    /** Constant <code>GRAY</code> */
94    static final Color3f GRAY = new Color3f(Color.lightGray.getRGBColorComponents(new float[3]));
95    /** Constant <code>YELLOW</code> */
96    static final Color3f YELLOW = new Color3f(Color.yellow.getRGBColorComponents(new float[3]));
97    /** Constant <code>CYAN</code> */
98    static final Color3f CYAN = new Color3f(Color.cyan.getRGBColorComponents(new float[3]));
99    /** Constant <code>GREEN</code> */
100   static final Color3f GREEN = new Color3f(Color.green.getRGBColorComponents(new float[3]));
101   /** Constant <code>WHITE</code> */
102   static final Color3f WHITE = new Color3f(Color.white.getRGBColorComponents(new float[3]));
103   /** Constant <code>PINK</code> */
104   static final Color3f PINK = new Color3f(Color.pink.getRGBColorComponents(new float[3]));
105   /** Constant <code>MAGENTA</code> */
106   static final Color3f MAGENTA = new Color3f(Color.magenta.getRGBColorComponents(new float[3]));
107   /** Constant <code>nullAp</code> */
108   static final Appearance nullAp;
109 
110   private static final Transform3D localToVworld = new Transform3D();
111   private static final Transform3D worldToImagePlate = new Transform3D();
112   private static final Hashtable<Color3f, Material> materials = new Hashtable<>();
113   private static final Geometry[] sphereGeom = new Geometry[11];
114   private static final Geometry[][] cylgeom = new Geometry[3][11];
115   private static final Geometry[][] conegeom = new Geometry[2][4];
116   private static final Hashtable<Color3f, Appearance> pointAppearances = new Hashtable<>();
117   private static final Hashtable<Color3f, Appearance> lineAppearances = new Hashtable<>();
118   private static final Hashtable<Color3f, Appearance> fillAppearances = new Hashtable<>();
119   private static final Color3f[] negCharge = new Color3f[1000];
120   private static final Color3f[] posCharge = new Color3f[1000];
121   /** Constant <code>NULLColor</code> */
122   private static final Color3f NULLColor =
123       new Color3f(Color.darkGray.getRGBColorComponents(new float[3]));
124   /** Constant <code>lineAttributes</code> */
125   private static final LineAttributes lineAttributes = new LineAttributes();
126   /** Constant <code>pointAttributes</code> */
127   private static final PointAttributes pointAttributes = new PointAttributes();
128   /** Constant <code>coloringAttributes</code> */
129   private static final ColoringAttributes coloringAttributes = new ColoringAttributes();
130   /** Constant <code>renderingAttributes</code> */
131   private static final RenderingAttributes renderingAttributes = new RenderingAttributes();
132   /** Constant <code>transparencyAttributes</code> */
133   private static final TransparencyAttributes transparencyAttributes = new TransparencyAttributes();
134   /** Constant <code>fillPolygonAttributes</code> */
135   private static final PolygonAttributes fillPolygonAttributes = new PolygonAttributes();
136   /** Constant <code>pointPolygonAttributes</code> */
137   private static final PolygonAttributes pointPolygonAttributes = new PolygonAttributes();
138   /** Constant <code>linePolygonAttributes</code> */
139   private static final PolygonAttributes linePolygonAttributes = new PolygonAttributes();
140   /** Constant <code>detail=3</code> */
141   public static int detail = 3;
142   /** Constant <code>radius=1.0d</code> */
143   public static double radius = 1.0d;
144   /** Constant <code>bondwidth=3</code> */
145   public static int bondwidth = 3;
146   /** Constant <code>highlightSelections=false</code> */
147   public static boolean highlightSelections = false;
148   /** Constant <code>labelAtoms=false</code> */
149   public static boolean labelAtoms = false;
150   /** Constant <code>labelResidues=false</code> */
151   public static boolean labelResidues = false;
152   /** Constant <code>pickingColor</code> */
153   public static Color3f pickingColor = MAGENTA;
154   /** Constant <code>selectionColor</code> */
155   public static Color3f selectionColor = YELLOW;
156   /** Constant <code>userColor</code> */
157   public static Color3f userColor = WHITE;
158 
159   private static final List<Transform3D> transform3DPool = Collections.synchronizedList(new ArrayList<>());
160   private static final List<BranchGroup> spherePool = Collections.synchronizedList(new ArrayList<>());
161   private static final List<BranchGroup> doubleCylinderPool = Collections.synchronizedList(new ArrayList<>());
162   private static ShaderProgram shaderProgram = null;
163 
164   static {
165     coloringAttributes.setShadeModel(ColoringAttributes.NICEST);
166     coloringAttributes.setColor(new Color3f(0, 0, 0));
167     lineAttributes.setLineAntialiasingEnable(true);
168     lineAttributes.setLinePattern(LineAttributes.PATTERN_SOLID);
169     lineAttributes.setLineWidth(1.0f);
170     pointAttributes.setPointAntialiasingEnable(true);
171     pointAttributes.setPointSize(1.0f);
172     fillPolygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_FILL);
173     fillPolygonAttributes.setCullFace(PolygonAttributes.CULL_BACK);
174     linePolygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_LINE);
175     pointPolygonAttributes.setPolygonMode(PolygonAttributes.POLYGON_POINT);
176     renderingAttributes.setVisible(true);
177     renderingAttributes.setDepthBufferEnable(true);
178     renderingAttributes.setDepthBufferWriteEnable(true);
179     renderingAttributes.setIgnoreVertexColors(true);
180     transparencyAttributes.setTransparencyMode(TransparencyAttributes.NONE);
181 
182     ViewModel[] values = ViewModel.values();
183     for (ViewModel value : values) {
184       viewModelHash.put(value.toString(), value);
185     }
186 
187     ColorModel[] colorModelValues = ColorModel.values();
188     for (ColorModel value : colorModelValues) {
189       colorModelHash.put(value.toString(), value);
190     }
191 
192     nullAp = new Appearance();
193     RenderingAttributes ra = new RenderingAttributes();
194     ra.setVisible(false);
195     nullAp.setRenderingAttributes(ra);
196   }
197 
198   /** Constructor for RendererCache. */
199   public RendererCache() {}
200 
201   /**
202    * appearanceFactory
203    *
204    * @param col a {@link org.jogamp.vecmath.Color3f} object.
205    * @param polygonType a {@link ffx.potential.bonded.RendererCache.ViewModel} object.
206    * @return a {@link org.jogamp.java3d.Appearance} object.
207    */
208   static Appearance appearanceFactory(Color3f col, ViewModel polygonType) {
209     if (col == null) {
210       return null;
211     }
212     Appearance ap;
213     if (polygonType == RendererCache.ViewModel.FILL) {
214       ap = fillAppearances.get(col);
215     } else if (polygonType == RendererCache.ViewModel.POINTS) {
216       ap = pointAppearances.get(col);
217     } else {
218       ap = lineAppearances.get(col);
219     }
220     if (ap == null) {
221       ap = createAppearance(col, polygonType);
222     }
223     return ap;
224   }
225 
226   /**
227    * coneFactory
228    *
229    * @param ap a {@link org.jogamp.java3d.Appearance} object.
230    * @param res a int.
231    * @return a {@link org.jogamp.java3d.Shape3D} object.
232    */
233   protected static Shape3D coneFactory(Appearance ap, int res) {
234     if (res > 3) {
235       res = 3;
236     }
237     Shape3D cone = new Shape3D();
238     cone.setAppearance(ap);
239     cone.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
240     cone.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
241     cone.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
242     cone.setCapability(Shape3D.ALLOW_PICKABLE_WRITE);
243     cone.addGeometry(getConeGeom(0, res));
244     cone.addGeometry(getConeGeom(1, res));
245     return cone;
246   }
247 
248   private static Appearance createAppearance(Color3f col, ViewModel polygonType) {
249     Appearance ap = null;
250     if (shaderProgram != null) {
251       ShaderAppearance sap = new ShaderAppearance();
252       sap.setShaderProgram(shaderProgram);
253       ap = sap;
254     }
255     if (ap == null) {
256       ap = new Appearance();
257     }
258     Material mat = materialFactory(col);
259     ap.setMaterial(mat);
260     ap.setRenderingAttributes(renderingAttributes);
261     ap.setColoringAttributes(coloringAttributes);
262     ap.setLineAttributes(lineAttributes);
263     ap.setPointAttributes(pointAttributes);
264     if (polygonType == RendererCache.ViewModel.FILL) {
265       ap.setPolygonAttributes(fillPolygonAttributes);
266       fillAppearances.put(col, ap);
267     } else if (polygonType == RendererCache.ViewModel.POINTS) {
268       ap.setPolygonAttributes(pointPolygonAttributes);
269       pointAppearances.put(col, ap);
270     } else {
271       ap.setPolygonAttributes(linePolygonAttributes);
272       lineAppearances.put(col, ap);
273     }
274     return ap;
275   }
276 
277   /**
278    * This method creates a Cylinder
279    *
280    * @param ap a {@link org.jogamp.java3d.Appearance} object.
281    * @param res a int.
282    * @return a {@link org.jogamp.java3d.Shape3D} object.
283    */
284   private static Shape3D createCylinder(Appearance ap, int res) {
285     if (res < 0) {
286       res = 0;
287     }
288     if (res > 10) {
289       res = 10;
290     }
291     final Shape3D cyl = new Shape3D();
292     cyl.setAppearance(ap);
293     cyl.addGeometry(getCylinderGeom(0, res));
294     cyl.addGeometry(getCylinderGeom(1, res));
295     cyl.addGeometry(getCylinderGeom(2, res));
296     cyl.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
297     cyl.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
298     cyl.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
299     cyl.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
300     cyl.setCapability(Shape3D.ENABLE_PICK_REPORTING);
301     cyl.setCapability(Shape3D.ALLOW_PICKABLE_WRITE);
302     return cyl;
303   }
304 
305   /** This method creates a single Sphere from the given appearance */
306   private static Shape3D createSphere(Appearance ap, int div) {
307     Shape3D shape3d = new Shape3D();
308     shape3d.setAppearance(ap);
309     shape3d.addGeometry(getSphereGeom(div));
310     shape3d.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
311     shape3d.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
312     shape3d.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
313     shape3d.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
314     shape3d.setCapability(Shape3D.ENABLE_PICK_REPORTING);
315     shape3d.setCapability(Shape3D.ALLOW_PICKABLE_WRITE);
316     return shape3d;
317   }
318 
319   private static TransformGroup createTransformGroup(Transform3D transform3D) {
320     TransformGroup transformGroup;
321     if (transform3D == null) {
322       transformGroup = new TransformGroup();
323     } else {
324       transformGroup = new TransformGroup(transform3D);
325     }
326     transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
327     transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
328     transformGroup.setCapability(TransformGroup.ALLOW_CHILDREN_READ);
329     return transformGroup;
330   }
331 
332   /**
333    * doubleCylinderFactory
334    *
335    * @param a1 a {@link ffx.potential.bonded.Atom} object.
336    * @param a2 a {@link ffx.potential.bonded.Atom} object.
337    * @param div a int.
338    * @return a {@link org.jogamp.java3d.BranchGroup} object.
339    */
340   static BranchGroup doubleCylinderFactory(Atom a1, Atom a2, int div) {
341     BranchGroup branchGroup;
342     if (!doubleCylinderPool.isEmpty()) {
343       branchGroup = doubleCylinderPool.remove(0);
344       if (branchGroup != null) {
345         TransformGroup cy1tg = (TransformGroup) branchGroup.getChild(0);
346         Shape3D cy1 = (Shape3D) cy1tg.getChild(0);
347         cy1.setAppearance(a1.getAtomAppearance());
348         cy1.setUserData(a1);
349         TransformGroup cy2tg = (TransformGroup) branchGroup.getChild(1);
350         Shape3D cy2 = (Shape3D) cy2tg.getChild(0);
351         cy2.setUserData(a2);
352         cy2.setAppearance(a2.getAtomAppearance());
353         return branchGroup;
354       }
355     }
356     branchGroup = new BranchGroup();
357     branchGroup.setCapability(BranchGroup.ALLOW_DETACH);
358     branchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
359     branchGroup.setCapability(BranchGroup.ENABLE_PICK_REPORTING);
360     TransformGroup cy1tg = createTransformGroup(null);
361     Shape3D cy1 = createCylinder(a1.getAtomAppearance(), div);
362     cy1.setUserData(a1);
363     cy1tg.addChild(cy1);
364     branchGroup.addChild(cy1tg);
365     TransformGroup cy2tg = createTransformGroup(null);
366     Shape3D cy2 = createCylinder(a2.getAtomAppearance(), div);
367     cy2.setUserData(a2);
368     cy2tg.addChild(cy2);
369     branchGroup.addChild(cy2tg);
370     branchGroup.compile();
371     return branchGroup;
372   }
373 
374   /**
375    * getColor
376    *
377    * @param a a {@link ffx.potential.bonded.Atom} object.
378    * @param mode a {@link ffx.potential.bonded.RendererCache.ColorModel} object.
379    * @return a {@link org.jogamp.vecmath.Color3f} object.
380    */
381   static Color3f getColor(Atom a, ColorModel mode) {
382     switch (mode) {
383       case CPK:
384         return Atom.AtomColor.get(a.getAtomicNumber());
385       case PICK:
386         return pickingColor;
387       case SELECT:
388         return selectionColor;
389       case PARTIALCHARGE:
390         int index;
391         double charge = a.getCharge();
392         if (charge < 0.0d) {
393           float c = (float) (charge * 1000.0);
394           index = -1 * Math.round(c);
395           if (index > 999) {
396             index = 999;
397           }
398           if (negCharge[index] == null) {
399             float value = index * 0.001f;
400             negCharge[index] = new Color3f(1.0f, 1.0f - value, 1.0f - value);
401           }
402           return negCharge[index];
403         } else if (charge == 0) {
404           return WHITE;
405         } else {
406           float c = (float) (charge * 1000.0);
407           index = Math.round(c);
408           if (index > 999) {
409             index = 999;
410           }
411           if (posCharge[index] == null) {
412             float value = index * 0.001f;
413             posCharge[index] = new Color3f(1.0f - value, 1.0f - value, 1.0f);
414           }
415           return posCharge[index];
416         }
417       default:
418         return NULLColor;
419     }
420   }
421 
422   /**
423    * getConeGeom
424    *
425    * @param num a int.
426    * @param res a int.
427    * @return a {@link org.jogamp.java3d.Geometry} object.
428    */
429   private static Geometry getConeGeom(int num, int res) {
430     if (res > 3) {
431       res = 3;
432     }
433     if (conegeom[num][res] == null) {
434       initConeGeom(res);
435     }
436     return conegeom[num][res];
437   }
438 
439   /**
440    * getCylinderGeom
441    *
442    * @param num a int.
443    * @param res a int.
444    * @return a {@link org.jogamp.java3d.Geometry} object.
445    */
446   static Geometry getCylinderGeom(int num, int res) {
447     if (res < 0) {
448       res = 0;
449     }
450     if (res > 10) {
451       res = 10;
452     }
453     if (cylgeom[num][res] == null) {
454       initCylinderGeom(res);
455     }
456     return cylgeom[num][res];
457   }
458 
459   /**
460    * getPolarGeom
461    *
462    * @param res a int.
463    * @return a {@link org.jogamp.java3d.Geometry} object.
464    */
465   protected static Geometry getPolarGeom(int res) {
466     return getSphereGeom(res);
467   }
468 
469   /**
470    * getScreenCoordinate
471    *
472    * @param canvas a {@link org.jogamp.java3d.Canvas3D} object.
473    * @param node a {@link org.jogamp.java3d.Node} object.
474    * @param point3d a {@link org.jogamp.vecmath.Point3d} object.
475    * @param point a {@link org.jogamp.vecmath.Point2d} object.
476    */
477   static void getScreenCoordinate(
478       Canvas3D canvas, Node node, Point3d point3d, final Point2d point) {
479     if (point == null) {
480       return;
481     }
482     // Get the transform to put the node in the world coordinate system
483     node.getLocalToVworld(localToVworld);
484     // Get the image plate transform
485     canvas.getVworldToImagePlate(worldToImagePlate);
486     // Transform into world coordinates
487     localToVworld.transform(point3d);
488     // Transform into imageplate coordinates
489     worldToImagePlate.transform(point3d);
490     // Final step to the 2D Screen.
491     canvas.getPixelLocationFromImagePlate(point3d, point);
492     /*
493      Now we have the location where the point will be rendered on the
494      screen depending on resize, placement, size, and eye point policies.
495      This should only be called on points that reside within the clipping
496      planes.
497     */
498   }
499 
500   /**
501    * Getter for the field <code>sphereGeom</code>.
502    *
503    * @param res a int.
504    * @return a {@link org.jogamp.java3d.Geometry} object.
505    */
506   static Geometry getSphereGeom(int res) {
507     if (res < 0) {
508       res = 0;
509     }
510     if (res > 10) {
511       res = 10;
512     }
513     if (sphereGeom[res] == null) {
514       initSphereGeom(res);
515     }
516     return sphereGeom[res];
517   }
518 
519   private static void initConeGeom(int res) {
520     Cone cone =
521         new Cone(
522             1.0f,
523             1.0f,
524             Cone.GENERATE_NORMALS | Cone.ENABLE_GEOMETRY_PICKING | Cone.ENABLE_APPEARANCE_MODIFY,
525             (res + 1) * 4,
526             1,
527             nullAp);
528     for (int i = 0; i < 2; i++) {
529       conegeom[i][res] = cone.getShape(i).getGeometry();
530       /*
531        * conegeom[i][res].setCapability(Geometry.ALLOW_INTERSECT);
532        * conegeom[i][res].setCapability(GeometryArray.ALLOW_FORMAT_READ);
533        * conegeom[i][res].setCapability(GeometryArray.ALLOW_COUNT_READ);
534        * conegeom
535        * [i][res].setCapability(GeometryArray.ALLOW_COORDINATE_READ);
536        */
537     }
538   }
539 
540   private static void initCylinderGeom(int res) {
541     Appearance ap = new Appearance();
542     Cylinder cyl =
543         new Cylinder(
544             1.0f,
545             1.0f,
546             Cylinder.GENERATE_NORMALS
547                 | Cylinder.ENABLE_APPEARANCE_MODIFY
548                 | Cylinder.ENABLE_GEOMETRY_PICKING,
549             2 + res,
550             1,
551             ap);
552     for (int i = 0; i < 3; i++) {
553       cylgeom[i][res] = cyl.getShape(i).getGeometry();
554       try {
555         cylgeom[i][res].setCapability(Geometry.ALLOW_INTERSECT);
556         cylgeom[i][res].setCapability(GeometryArray.ALLOW_FORMAT_READ);
557         cylgeom[i][res].setCapability(GeometryArray.ALLOW_COUNT_READ);
558         cylgeom[i][res].setCapability(GeometryArray.ALLOW_COORDINATE_READ);
559       } catch (Exception e) {
560         return;
561       }
562     }
563   }
564 
565   private static void initSphereGeom(int res) {
566     Appearance ap = new Appearance();
567     Sphere sphere;
568     sphere =
569         new Sphere(
570             1.0f,
571             Sphere.GENERATE_NORMALS
572                 | Sphere.ENABLE_APPEARANCE_MODIFY
573                 | Sphere.ENABLE_GEOMETRY_PICKING,
574             4 + 3 * res,
575             ap);
576     sphereGeom[res] = sphere.getShape().getGeometry();
577     // GeometryArray g = (GeometryArray) sphereGeom[res];
578     /*
579      * if (!g.isLive()) { g.setCapability(g.ALLOW_FORMAT_READ);
580      * g.setCapability(g.ALLOW_COUNT_READ);
581      * g.setCapability(g.ALLOW_COORDINATE_READ); }
582      */
583   }
584 
585   /**
586    * materialFactory
587    *
588    * @param col a {@link org.jogamp.vecmath.Color3f} object.
589    * @return a {@link org.jogamp.java3d.Material} object.
590    */
591   static Material materialFactory(Color3f col) {
592     if (col == null) {
593       return null;
594     }
595     Material mat = materials.get(col);
596     if (mat == null) {
597       mat = new Material(col, BLACK, col, WHITE, 75.0f);
598       mat.setLightingEnable(true);
599       materials.put(col, mat);
600     }
601     return mat;
602   }
603 
604   /**
605    * poolDoubleCylinder
606    *
607    * @param branchGroup a {@link org.jogamp.java3d.BranchGroup} object.
608    */
609   static void poolDoubleCylinder(BranchGroup branchGroup) {
610     if (branchGroup != null) {
611       doubleCylinderPool.add(branchGroup);
612     }
613   }
614 
615   /**
616    * poolSphere
617    *
618    * @param tg a {@link org.jogamp.java3d.BranchGroup} object.
619    */
620   static void poolSphere(BranchGroup tg) {
621     if (tg != null) {
622       spherePool.add(tg);
623     }
624   }
625 
626   /**
627    * poolTransform3D
628    *
629    * @param transform3D a {@link org.jogamp.java3d.Transform3D} object.
630    */
631   static void poolTransform3D(Transform3D transform3D) {
632     if (transform3D != null) {
633       transform3DPool.add(transform3D);
634     }
635   }
636 
637   /**
638    * sphereFactory
639    *
640    * @param ap a {@link org.jogamp.java3d.Appearance} object.
641    * @param div a int.
642    * @param transform3D a {@link org.jogamp.java3d.Transform3D} object.
643    * @return a {@link org.jogamp.java3d.BranchGroup} object.
644    */
645   static BranchGroup sphereFactory(Appearance ap, int div, Transform3D transform3D) {
646     BranchGroup branchGroup;
647     if (!spherePool.isEmpty()) {
648       branchGroup = spherePool.remove(0);
649       if (branchGroup != null) {
650         TransformGroup transformGroup = (TransformGroup) branchGroup.getChild(0);
651         transformGroup.setTransform(transform3D);
652         Shape3D sphere = (Shape3D) transformGroup.getChild(0);
653         sphere.setAppearance(ap);
654         return branchGroup;
655       }
656     }
657     branchGroup = new BranchGroup();
658     branchGroup.setCapability(BranchGroup.ALLOW_DETACH);
659     branchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
660     branchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
661     TransformGroup transformGroup = createTransformGroup(transform3D);
662     Shape3D sphere = createSphere(ap, div);
663     transformGroup.addChild(sphere);
664     branchGroup.addChild(transformGroup);
665     branchGroup.compile();
666     return branchGroup;
667   }
668 
669   /**
670    * toAtomColor
671    *
672    * @param s a {@link java.lang.String} object.
673    * @return a {@link org.jogamp.vecmath.Color3f} object.
674    */
675   static Color3f toAtomColor(String s) {
676     String c = s.toLowerCase();
677     if (c.startsWith("h")) {
678       return WHITE;
679     }
680     if (c.startsWith("c")) {
681       return GRAY;
682     }
683     if (c.startsWith("n")) {
684       return BLUE;
685     }
686     if (c.startsWith("o")) {
687       return RED;
688     }
689     if (c.startsWith("p")) {
690       return GREEN;
691     }
692     if (c.startsWith("s")) {
693       return YELLOW;
694     }
695     return NULLColor;
696   }
697 
698   /**
699    * transform3DFactory
700    *
701    * @return a {@link org.jogamp.java3d.Transform3D} object.
702    */
703   static Transform3D transform3DFactory() {
704     Transform3D transform3D;
705     if (!transform3DPool.isEmpty()) {
706       transform3D = transform3DPool.get(0);
707       if (transform3D != null) {
708         return transform3D;
709       }
710     }
711     transform3D = new Transform3D();
712     return transform3D;
713   }
714 
715   /**
716    * transform3DFactory
717    *
718    * @param position a {@link org.jogamp.vecmath.Vector3d} object.
719    * @param scale a double.
720    * @return a {@link org.jogamp.java3d.Transform3D} object.
721    */
722   static Transform3D transform3DFactory(Vector3d position, double scale) {
723     Transform3D transform3D;
724     if (!transform3DPool.isEmpty()) {
725       transform3D = transform3DPool.get(0);
726       if (transform3D != null) {
727         transform3D.setTranslation(position);
728         transform3D.setScale(scale);
729         return transform3D;
730       }
731     }
732     transform3D = new Transform3D();
733     transform3D.setTranslation(position);
734     transform3D.setScale(scale);
735     return transform3D;
736   }
737 
738   public enum ColorModel {
739     CPK,
740     GROUP,
741     RESIDUE,
742     POLYMER,
743     MOLECULE,
744     MONOCHROME,
745     USERCOLOR,
746     PARTIALCHARGE,
747     PICK,
748     SELECT,
749     REVERT,
750     STRUCTURE,
751     APPLYUSERCOLOR
752   }
753 
754   public enum ViewModel {
755     WIREFRAME,
756     BALLANDSTICK,
757     SPACEFILL,
758     RMIN,
759     TUBE,
760     INVISIBLE,
761     RESTRICT,
762     SHOWHYDROGEN,
763     HIDEHYDROGEN,
764     DETAIL,
765     RIBBON,
766     SHOWVRML,
767     HIDEVRML,
768     INDUCEDDIPOLE,
769     FORCE,
770     VELOCITY,
771     ACCELERATION,
772     HIDEVECTORS,
773     UNIT,
774     RELATIVE,
775     ABSOLUTE,
776     POINTS,
777     LINES,
778     FILL,
779     DESTROY
780   }
781 }