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