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 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
74
75
76
77
78
79 public class RendererCache {
80
81
82 public static final Color3f BLACK = new Color3f(Color.black.getRGBColorComponents(new float[3]));
83
84 public static final Hashtable<String, ViewModel> viewModelHash = new Hashtable<>();
85
86 public static final Hashtable<String, ColorModel> colorModelHash = new Hashtable<>();
87
88 static final Color3f ORANGE = new Color3f(Color.orange.getRGBColorComponents(new float[3]));
89
90 static final Color3f RED = new Color3f(Color.red.getRGBColorComponents(new float[3]));
91
92 static final Color3f BLUE = new Color3f(Color.blue.getRGBColorComponents(new float[3]));
93
94 static final Color3f GRAY = new Color3f(Color.lightGray.getRGBColorComponents(new float[3]));
95
96 static final Color3f YELLOW = new Color3f(Color.yellow.getRGBColorComponents(new float[3]));
97
98 static final Color3f CYAN = new Color3f(Color.cyan.getRGBColorComponents(new float[3]));
99
100 static final Color3f GREEN = new Color3f(Color.green.getRGBColorComponents(new float[3]));
101
102 static final Color3f WHITE = new Color3f(Color.white.getRGBColorComponents(new float[3]));
103
104 static final Color3f PINK = new Color3f(Color.pink.getRGBColorComponents(new float[3]));
105
106 static final Color3f MAGENTA = new Color3f(Color.magenta.getRGBColorComponents(new float[3]));
107
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
122 private static final Color3f NULLColor =
123 new Color3f(Color.darkGray.getRGBColorComponents(new float[3]));
124
125 private static final LineAttributes lineAttributes = new LineAttributes();
126
127 private static final PointAttributes pointAttributes = new PointAttributes();
128
129 private static final ColoringAttributes coloringAttributes = new ColoringAttributes();
130
131 private static final RenderingAttributes renderingAttributes = new RenderingAttributes();
132
133 private static final TransparencyAttributes transparencyAttributes = new TransparencyAttributes();
134
135 private static final PolygonAttributes fillPolygonAttributes = new PolygonAttributes();
136
137 private static final PolygonAttributes pointPolygonAttributes = new PolygonAttributes();
138
139 private static final PolygonAttributes linePolygonAttributes = new PolygonAttributes();
140
141 public static int detail = 3;
142
143 public static double radius = 1.0d;
144
145 public static int bondwidth = 3;
146
147 public static boolean highlightSelections = false;
148
149 public static boolean labelAtoms = false;
150
151 public static boolean labelResidues = false;
152
153 public static Color3f pickingColor = MAGENTA;
154
155 public static Color3f selectionColor = YELLOW;
156
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
199 public RendererCache() {}
200
201
202
203
204
205
206
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
228
229
230
231
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
279
280
281
282
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
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
334
335
336
337
338
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
376
377
378
379
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
424
425
426
427
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
441
442
443
444
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
461
462
463
464
465 protected static Geometry getPolarGeom(int res) {
466 return getSphereGeom(res);
467 }
468
469
470
471
472
473
474
475
476
477 static void getScreenCoordinate(
478 Canvas3D canvas, Node node, Point3d point3d, final Point2d point) {
479 if (point == null) {
480 return;
481 }
482
483 node.getLocalToVworld(localToVworld);
484
485 canvas.getVworldToImagePlate(worldToImagePlate);
486
487 localToVworld.transform(point3d);
488
489 worldToImagePlate.transform(point3d);
490
491 canvas.getPixelLocationFromImagePlate(point3d, point);
492
493
494
495
496
497
498 }
499
500
501
502
503
504
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
532
533
534
535
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
578
579
580
581
582
583 }
584
585
586
587
588
589
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
606
607
608
609 static void poolDoubleCylinder(BranchGroup branchGroup) {
610 if (branchGroup != null) {
611 doubleCylinderPool.add(branchGroup);
612 }
613 }
614
615
616
617
618
619
620 static void poolSphere(BranchGroup tg) {
621 if (tg != null) {
622 spherePool.add(tg);
623 }
624 }
625
626
627
628
629
630
631 static void poolTransform3D(Transform3D transform3D) {
632 if (transform3D != null) {
633 transform3DPool.add(transform3D);
634 }
635 }
636
637
638
639
640
641
642
643
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
671
672
673
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
700
701
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
717
718
719
720
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 }