JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
AWTAnimatorImpl.java
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (c) 2010 JogAmp Community. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * - Redistribution of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * - Redistribution in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of Sun Microsystems, Inc. or the names of
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * This software is provided "AS IS," without a warranty of any kind. ALL
21 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
22 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
23 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
24 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
25 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
26 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
27 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
28 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
29 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
30 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
31 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32 */
33
34package com.jogamp.opengl.util;
35
36import java.awt.Component;
37import java.awt.EventQueue;
38import java.awt.Rectangle;
39import java.util.ArrayList;
40import java.util.IdentityHashMap;
41import java.util.Iterator;
42import java.util.List;
43import java.util.Map;
44
45import javax.swing.JComponent;
46import javax.swing.RepaintManager;
47import javax.swing.SwingUtilities;
48import com.jogamp.opengl.GLAutoDrawable;
49
50import com.jogamp.opengl.util.AnimatorBase.UncaughtAnimatorException;
51
52/** Abstraction to factor out AWT dependencies from the Animator's
53 implementation in a way that still allows the FPSAnimator to pick
54 up this behavior if desired. */
55
56class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl {
57 // For efficient rendering of Swing components, in particular when
58 // they overlap one another
59 private final List<JComponent> lightweights = new ArrayList<JComponent>();
60 private final Map<RepaintManager,RepaintManager> repaintManagers = new IdentityHashMap<RepaintManager,RepaintManager>();
61 private final Map<JComponent,Rectangle> dirtyRegions = new IdentityHashMap<JComponent,Rectangle>();
62
63 @Override
64 public void display(final ArrayList<GLAutoDrawable> drawables,
65 final boolean ignoreExceptions,
66 final boolean printExceptions) throws UncaughtAnimatorException {
67 boolean hasException = false;
68 for (int i=0; !hasException && i<drawables.size(); i++) {
69 GLAutoDrawable drawable = null;
70 boolean catch1 = true;
71 try {
72 drawable = drawables.get(i);
73 catch1 = false;
74 if (drawable instanceof JComponent) {
75 // Lightweight components need a more efficient drawing
76 // scheme than simply forcing repainting of each one in
77 // turn since drawing one can force another one to be
78 // drawn in turn
79 lightweights.add((JComponent)drawable);
80 } else {
81 drawable.display();
82 }
83 } catch (final Throwable t) {
84 if( catch1 && t instanceof IndexOutOfBoundsException ) {
85 // concurrent pulling of GLAutoDrawables ..
86 hasException = true;
87 } else if ( ignoreExceptions ) {
88 if ( printExceptions ) {
89 t.printStackTrace();
90 }
91 } else {
92 throw new UncaughtAnimatorException(drawable, t);
93 }
94 }
95 }
96 if (lightweights.size() > 0) {
97 try {
98 SwingUtilities.invokeAndWait(drawWithRepaintManagerRunnable);
99 } catch (final Throwable t) {
100 t.printStackTrace();
101 }
102 lightweights.clear();
103 }
104 }
105
106 // Uses RepaintManager APIs to implement more efficient redrawing of
107 // the Swing widgets we're animating
108 private final Runnable drawWithRepaintManagerRunnable = new Runnable() {
109 @Override
110 public void run() {
111 for (final Iterator<JComponent> iter = lightweights.iterator(); iter.hasNext(); ) {
112 JComponent comp = iter.next();
113 RepaintManager rm = RepaintManager.currentManager(comp);
114 rm.markCompletelyDirty(comp);
115 repaintManagers.put(rm, rm);
116
117 // RepaintManagers don't currently optimize the case of
118 // overlapping sibling components. If we have two
119 // JInternalFrames in a JDesktopPane, the redraw of the
120 // bottom one will cause the top one to be redrawn as
121 // well. The top one will then be redrawn separately. In
122 // order to optimize this case we need to compute the union
123 // of all of the dirty regions on a particular JComponent if
124 // optimized drawing isn't enabled for it.
125
126 // Walk up the hierarchy trying to find a non-optimizable
127 // ancestor
128 final Rectangle visible = comp.getVisibleRect();
129 int x = visible.x;
130 int y = visible.y;
131 while (comp != null) {
132 x += comp.getX();
133 y += comp.getY();
134 final Component c = comp.getParent();
135 if ((c == null) || (!(c instanceof JComponent))) {
136 comp = null;
137 } else {
138 comp = (JComponent) c;
139 if (!comp.isOptimizedDrawingEnabled()) {
140 rm = RepaintManager.currentManager(comp);
141 repaintManagers.put(rm, rm);
142 // Need to dirty this region
143 Rectangle dirty = dirtyRegions.get(comp);
144 if (dirty == null) {
145 dirty = new Rectangle(x, y, visible.width, visible.height);
146 dirtyRegions.put(comp, dirty);
147 } else {
148 // Compute union with already dirty region
149 // Note we could compute multiple non-overlapping
150 // regions: might want to do that in the future
151 // (prob. need more complex algorithm -- dynamic
152 // programming?)
153 dirty.add(new Rectangle(x, y, visible.width, visible.height));
154 }
155 }
156 }
157 }
158 }
159
160 // Dirty any needed regions on non-optimizable components
161 for (final Iterator<JComponent> iter = dirtyRegions.keySet().iterator(); iter.hasNext(); ) {
162 final JComponent comp = iter.next();
163 final Rectangle rect = dirtyRegions.get(comp);
164 final RepaintManager rm = RepaintManager.currentManager(comp);
165 rm.addDirtyRegion(comp, rect.x, rect.y, rect.width, rect.height);
166 }
167
168 // Draw all dirty regions
169 for (final Iterator<RepaintManager> iter = repaintManagers.keySet().iterator(); iter.hasNext(); ) {
170 iter.next().paintDirtyRegions();
171 }
172 dirtyRegions.clear();
173 repaintManagers.clear();
174 }
175 };
176
177 @Override
178 public boolean blockUntilDone(final Thread thread) {
179 return Thread.currentThread() != thread && !EventQueue.isDispatchThread();
180 }
181}