Source code: com/xerox/VTM/engine/AccViewPanel.java
1 /* FILE: AccViewPanel.java
2 * DATE OF CREATION: Jun 08 2000
3 * AUTHOR : Emmanuel Pietriga (emmanuel.pietriga@xrce.xerox.com)
4 * MODIF: Tue Aug 05 14:55:10 2003 by Emmanuel Pietriga (emmanuel@w3.org, emmanuel@claribole.net)
5 * Copyright (c) Xerox Corporation, XRCE/Contextual Computing, 2002. All Rights Reserved
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * For full terms see the file COPYING.
18 */
19
20 package com.xerox.VTM.engine;
21
22 import com.xerox.VTM.glyphs.*;
23 import javax.swing.*;
24 import java.awt.*;
25 import java.awt.geom.*;
26 import java.awt.image.*;
27 import java.awt.event.*;
28 import java.util.Vector;
29 import java.util.Date;
30 import java.util.Enumeration;
31
32 /**
33 * Each view runs in its own thread - uses double buffering -
34 * this one is hardware accelerated (at least under Win32) using VolatileImage available since JDK 1.4.0 (does not accelerate bitmaps)
35 * @author Emmanuel Pietriga
36 */
37 public class AccViewPanel extends ViewPanel implements Runnable {
38
39 /**for Double Buffering*/
40 VolatileImage vImg;
41
42 //get the BufferedImage for this view
43 protected BufferedImage getImage(){
44 return this.vImg.getSnapshot();
45 }
46
47 public AccViewPanel(Vector cameras,View v) {
48 addHierarchyListener(
49 new HierarchyListener() {
50 public void hierarchyChanged(HierarchyEvent e) {
51 if (isShowing()) {
52 start();
53 } else {
54 stop();
55 }
56 }
57 }
58 );
59 parent=v;
60 //init of camera array
61 cams=new Camera[cameras.size()]; //array of Camera
62 for (int nbcam=0;nbcam<cameras.size();nbcam++){
63 cams[nbcam]=(Camera)(cameras.get(nbcam));
64 }
65 //init other stuff
66 setBackground(Color.lightGray);
67 this.addMouseListener(this);
68 this.addMouseMotionListener(this);
69 start();
70 // for (int i=0;i<cams.length;i++){
71 // System.out.println(cams[i].toString());
72 // }
73 // BufferedImage cImage=new BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB); //create a BufferedImage with transparent background
74 // try {//this buffer represents the mouse cursor shape (it does not appear since it is transparent)
75 // Cursor custCursor=Toolkit.getDefaultToolkit().createCustomCursor(cImage,new Point(0,0),"myCursor");
76 // this.setCursor(custCursor);
77 // }
78 // catch(IndexOutOfBoundsException e){if (parent.parent.debug){System.err.println("Error while creating custom cursor "+e);setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));}}
79 setAWTCursor(Cursor.CUSTOM_CURSOR); //custom cursor means VTM cursor
80 if (parent.parent.debug){System.out.println("View refresh time set to "+frameTime+"ms");}
81 }
82
83 public void start() {
84 Dimension size = getSize();
85 runView = new Thread(this);
86 runView.setPriority(Thread.NORM_PRIORITY);
87 runView.start();
88 }
89
90 public synchronized void stop() {
91 runView = null;
92 notify();
93 }
94
95 public void run() {
96 Thread me = Thread.currentThread();
97 while (getSize().width <= 0) { //Wait until the window actually exists
98 try {
99 runView.sleep(500);
100 }
101 catch (InterruptedException e) {
102 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep "+e);}
103 return;
104 }
105 }
106 Graphics2D g2d = null;
107 Graphics2D BufferG2D = null;
108 Dimension oldSize=getSize();
109 //clipRect=new Rectangle(0,0,oldSize.width,oldSize.height);
110 while (runView == me) {
111 if (notBlank){
112 if (active){
113 if (repaintNow) {
114 repaintNow=false;//do this first as the thread can be interrupted inside this branch and we want to catch new requests for repaint
115 updateMouseOnly=false;
116 d1=System.currentTimeMillis();
117 Dimension size=getSize();
118 if (size.width != oldSize.width || size.height != oldSize.height) {
119 //each time the parent window is resized, adapt the buffer image size
120 vImg=null;
121 if (BufferG2D != null) {
122 BufferG2D.dispose();
123 BufferG2D = null;
124 }
125 //clipRect=new Rectangle(0,0,size.width,size.height);
126 if (parent.parent.debug){System.out.println("Resizing JPanel: ("+oldSize.width+"x"+oldSize.height+") -> ("+size.width+"x"+size.height+")");}
127 oldSize=size;
128 updateAntialias=true;
129 updateFont=true;
130 }
131 if (vImg==null) {
132 GraphicsConfiguration gc=getGraphicsConfiguration();
133 vImg=gc.createCompatibleVolatileImage(size.width,size.height);
134 updateAntialias=true;
135 updateFont=true;
136 }
137 if (BufferG2D == null) {
138 BufferG2D = vImg.createGraphics();
139 BufferG2D.setFont(VirtualSpaceManager.mainFont);
140 updateAntialias=true;
141 updateFont=true;
142 }
143 if (updateFont) {BufferG2D.setFont(VirtualSpaceManager.mainFont);updateFont=false;}
144 if (updateAntialias){if (antialias){BufferG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);} else {BufferG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);}updateAntialias=false;}
145 g2d = BufferG2D;
146 //g2d.setClip(clipRect);
147 GraphicsConfiguration gc=this.getGraphicsConfiguration();
148 int valCode=vImg.validate(gc);
149 if (valCode==VolatileImage.IMAGE_INCOMPATIBLE){
150 vImg=gc.createCompatibleVolatileImage(size.width,size.height);
151 }
152 standardStroke=g2d.getStroke();
153 standardTransform=g2d.getTransform();
154 //parent.parent.constMgr.updateAttribsFromMvars();
155 synchronized(this){
156 g2d.setPaintMode();
157 g2d.setBackground(backColor);
158 g2d.clearRect(0, 0, getWidth(), getHeight());
159 //begin actual drawing here
160 for (int nbcam=0;nbcam<cams.length;nbcam++){
161 if ((cams[nbcam]!=null) && (cams[nbcam].enabled) && ((cams[nbcam].eager) || (cams[nbcam].shouldRepaint()))){
162 camIndex=cams[nbcam].getIndex();
163 drawnGlyphs=cams[nbcam].parentSpace.getDrawnGlyphs(camIndex);
164 synchronized(drawnGlyphs){
165 drawnGlyphs.removeAllElements();
166 uncoef=(float)((cams[nbcam].focal+cams[nbcam].altitude)/cams[nbcam].focal);
167 viewW=this.getSize().width;//compute region's width and height
168 viewH=this.getSize().height;
169 viewWHu=(long)(cams[nbcam].posx+this.getSize().width/2*uncoef);//compute region seen from this view
170 viewHHu=(long)(cams[nbcam].posy+this.getSize().height/2*uncoef);//through camera
171 viewWLu=(long)(cams[nbcam].posx-this.getSize().width/2*uncoef);
172 viewHLu=(long)(cams[nbcam].posy-this.getSize().height/2*uncoef);
173 if (parent.detectMultipleFullFills){//if detect multiple fills option is ON
174 for (Enumeration en=cams[nbcam].parentSpace.getVisibleGlyphs().elements();en.hasMoreElements();){
175 gl=(Glyph)(en.nextElement());
176 if (gl.drawMe(viewWHu,viewHHu,viewWLu,viewHLu,camIndex)){
177 cams[nbcam].parentSpace.drewGlyph(gl,camIndex);gl.project(cams[nbcam],this);
178 }
179 }
180 //drawnGlyphs=cams[nbcam].parentSpace.getDrawnGlyphs(camIndex);
181 beginAt=0;
182 for (int j=drawnGlyphs.size()-1;j>=0;j--){//glyphs must have been projected because fillsView uses
183 if (((Glyph)drawnGlyphs.elementAt(j)).fillsView(viewW,viewH,cams[nbcam].getIndex())){//projected coords
184 beginAt=j;
185 break;
186 }
187 }
188 for (int j=beginAt;j<drawnGlyphs.size();j++){
189 gl=(Glyph)drawnGlyphs.elementAt(j);
190 if (gl.isVisible()){
191 gl.draw(g2d,size.width,size.height,cams[nbcam].getIndex(),standardStroke,standardTransform);
192 }
193 }
194 }
195 else {//if detect multiple fills option is OFF
196 for (Enumeration en=cams[nbcam].parentSpace.getVisibleGlyphs().elements();en.hasMoreElements();){
197 gl=(Glyph)(en.nextElement());
198 if (gl.drawMe(viewWHu,viewHHu,viewWLu,viewHLu,camIndex)){
199 //if glyph is al least partially visible in the reg. seen from this view, display
200 synchronized(gl){
201 gl.project(cams[nbcam],this);
202 if (gl.isVisible()){
203 gl.draw(g2d,size.width,size.height,cams[nbcam].getIndex(),standardStroke,standardTransform);
204 cams[nbcam].parentSpace.drewGlyph(gl,camIndex);
205 }
206 }
207 }
208 }
209 }
210 }
211 }
212 }
213 if (inside){//deal with mouse glyph only if mouse cursor is inside this window
214 try {
215 parent.mouse.unProject(cams[activeLayer],this); //we project the mouse cursor wrt the appropriate coord sys
216 if (computeListAtEachRepaint && parent.mouse.isSensitive()){
217 parent.mouse.computeMouseOverList(evH,cams[activeLayer]);
218 }
219 }
220 catch (NullPointerException ex) {if (parent.parent.debug){System.err.println("viewpanel.run.drawdrag "+ex);}}
221 g2d.setColor(parent.mouse.color);
222 if (drawDrag){g2d.drawLine(origDragx,origDragy,parent.mouse.mx,parent.mouse.my);}
223 if (drawRect){g2d.drawRect(Math.min(origDragx,parent.mouse.mx),Math.min(origDragy,parent.mouse.my),Math.max(origDragx,parent.mouse.mx)-Math.min(origDragx,parent.mouse.mx),Math.max(origDragy,parent.mouse.my)-Math.min(origDragy,parent.mouse.my));}
224 if (drawOval){
225 if (circleOnly){
226 g2d.drawOval(origDragx-Math.abs(origDragx-parent.mouse.mx),origDragy-Math.abs(origDragx-parent.mouse.mx),2*Math.abs(origDragx-parent.mouse.mx),2*Math.abs(origDragx-parent.mouse.mx));
227 }
228 else {
229 g2d.drawOval(origDragx-Math.abs(origDragx-parent.mouse.mx),origDragy-Math.abs(origDragy-parent.mouse.my),2*Math.abs(origDragx-parent.mouse.mx),2*Math.abs(origDragy-parent.mouse.my));
230 }
231 }
232 if (drawVTMcursor){
233 synchronized(this){
234 g2d.setXORMode(backColor);
235 parent.mouse.draw(g2d);
236 oldX=parent.mouse.mx;
237 oldY=parent.mouse.my;
238 }
239 }
240 }
241 //end drawing here
242 if (g2d == BufferG2D) {
243 repaint();
244 }
245 d2=System.currentTimeMillis();
246 timeToSleep=frameTime-d2+d1; //40-(d2-d1) = wanted refresh rate - time needed to do the actual repaint operations
247 }
248 //either we do - BETTER UNDER Win32
249 try {
250 runView.sleep((timeToSleep>10) ? timeToSleep : 10); //sleep ... ms
251 }
252 catch (InterruptedException e) {
253 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep2 "+e);}
254 return;
255 }
256 //or this both seem to work well (have to test on several config) - BETTER UNDER SOLARIS
257 //Thread.yield();
258 }
259 else if (updateMouseOnly){
260 updateMouseOnly=false;
261 d1=System.currentTimeMillis();
262 try {
263 parent.mouse.unProject(cams[activeLayer],this); //we project the mouse cursor wrt the appropriate coord sys
264 if (computeListAtEachRepaint && parent.mouse.isSensitive()){parent.mouse.computeMouseOverList(evH,cams[activeLayer]);}
265 }
266 catch (NullPointerException ex) {if (parent.parent.debug){System.err.println("viewpanel.run.drawdrag "+ex);}}
267 if (drawVTMcursor){
268 synchronized(this){
269 try {
270 g2d.setXORMode(backColor);
271 g2d.setColor(parent.mouse.color);
272 g2d.drawLine(oldX-10,oldY,oldX+10,oldY);
273 g2d.drawLine(oldX,oldY-10,oldX,oldY+10);
274 g2d.drawLine(parent.mouse.mx-10,parent.mouse.my,parent.mouse.mx+10,parent.mouse.my);
275 g2d.drawLine(parent.mouse.mx,parent.mouse.my-10,parent.mouse.mx,parent.mouse.my+10);
276 oldX=parent.mouse.mx;
277 oldY=parent.mouse.my;
278 }//a nullpointerex on g2d seems to occur from time to time when going in or exiting from blank mode - just catch it and wait for next loop until we find out what's causing this
279 catch (NullPointerException ex47){if (parent.parent.debug){System.err.println("viewpanel.run.runview.drawVTMcursor "+ex47);}}
280 }
281 }
282 repaint();
283 d2=System.currentTimeMillis();
284 timeToSleep=frameTime-d2+d1; //40-(d2-d1) = wanted refresh rate - time needed to do the actual repaint operations
285 try {
286 runView.sleep((timeToSleep>10) ? timeToSleep : 10); //sleep ... ms
287 }
288 catch (InterruptedException e){
289 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep3 "+e);}
290 return;
291 }
292 }
293 else {
294 try {
295 runView.sleep(frameTime+20); //sleep ... ms
296 }
297 catch (InterruptedException e) {
298 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep3 "+e);}
299 return;
300 }
301 }
302 }
303 else {
304 try {
305 runView.sleep(deactiveTime); //sleep ... ms
306 }
307 catch (InterruptedException e) {
308 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep4 "+e);}
309 return;
310 }
311 }
312 }
313 else {
314 Dimension size=getSize();
315 if (size.width != oldSize.width || size.height != oldSize.height) {
316 //each time the parent window is resized, adapt the buffer image size
317 vImg=null;
318 if (BufferG2D != null) {
319 BufferG2D.dispose();
320 BufferG2D = null;
321 }
322 if (parent.parent.debug){System.out.println("Resizing JPanel: ("+oldSize.width+"x"+oldSize.height+") -> ("+size.width+"x"+size.height+")");}
323 oldSize=size;
324 updateAntialias=true;
325 updateFont=true;
326 }
327 if (vImg==null) {
328 GraphicsConfiguration gc=getGraphicsConfiguration();
329 vImg=gc.createCompatibleVolatileImage(size.width,size.height);
330 updateAntialias=true;
331 updateFont=true;
332 }
333 if (BufferG2D == null) {
334 BufferG2D = vImg.createGraphics();
335 BufferG2D.setFont(VirtualSpaceManager.mainFont);
336 updateAntialias=true;
337 updateFont=true;
338 }
339 if (updateFont) {BufferG2D.setFont(VirtualSpaceManager.mainFont);updateFont=false;}
340 if (updateAntialias){if (antialias){BufferG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);} else {BufferG2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);}updateAntialias=false;}
341 g2d = BufferG2D;
342 //g2d.setClip(clipRect);
343 GraphicsConfiguration gc=this.getGraphicsConfiguration();
344 int valCode=vImg.validate(gc);
345 if (valCode==VolatileImage.IMAGE_INCOMPATIBLE){
346 vImg=gc.createCompatibleVolatileImage(size.width,size.height);
347 }
348 standardStroke=g2d.getStroke();
349 standardTransform=g2d.getTransform();
350 g2d.setPaintMode();
351 g2d.setColor(blankColor);
352 g2d.fillRect(0,0,getWidth(),getHeight());
353 repaint();
354 try {
355 runView.sleep(deactiveTime); //sleep ... ms
356 }
357 catch (InterruptedException e){
358 if (parent.parent.debug){System.err.println("viewpanel.run.runview.sleep5 "+e);}
359 return;
360 }
361 }
362 }
363 if (g2d != null) {
364 g2d.dispose();
365 }
366 }
367
368 public void paint(Graphics g) {
369 synchronized (this) {
370 g2 = (Graphics2D) g;
371 if (vImg != null) {
372 g2.drawImage(vImg, 0, 0, this);
373 }
374 }
375 }
376
377 }