OSDN Git Service

Change .gitignore.
[mikumikustudio/MikuMikuStudio.git] / engine / src / desktop / com / jme3 / system / awt / AwtPanel.java
1 package com.jme3.system.awt;
2
3 import com.jme3.post.SceneProcessor;
4 import com.jme3.renderer.RenderManager;
5 import com.jme3.renderer.ViewPort;
6 import com.jme3.renderer.queue.RenderQueue;
7 import com.jme3.texture.FrameBuffer;
8 import com.jme3.texture.Image.Format;
9 import com.jme3.util.BufferUtils;
10 import com.jme3.util.Screenshots;
11 import java.awt.AWTException;
12 import java.awt.BufferCapabilities;
13 import java.awt.Canvas;
14 import java.awt.Graphics;
15 import java.awt.Graphics2D;
16 import java.awt.ImageCapabilities;
17 import java.awt.RenderingHints;
18 import java.awt.event.ComponentAdapter;
19 import java.awt.event.ComponentEvent;
20 import java.awt.geom.AffineTransform;
21 import java.awt.image.AffineTransformOp;
22 import java.awt.image.BufferStrategy;
23 import java.awt.image.BufferedImage;
24 import java.nio.ByteBuffer;
25 import java.nio.IntBuffer;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.concurrent.atomic.AtomicBoolean;
29
30 public class AwtPanel extends Canvas implements SceneProcessor {
31
32     private boolean attachAsMain = false;
33     
34     private BufferedImage img;
35     private FrameBuffer fb;
36     private ByteBuffer byteBuf;
37     private IntBuffer intBuf;
38     private RenderManager rm;
39     private PaintMode paintMode;
40     private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>(); 
41     
42     // Visibility/drawing vars
43     private BufferStrategy strategy;
44     private AffineTransformOp transformOp;
45     private AtomicBoolean hasNativePeer = new AtomicBoolean(false);
46     private AtomicBoolean showing = new AtomicBoolean(false);
47     private AtomicBoolean repaintRequest = new AtomicBoolean(false);
48     
49     // Reshape vars
50     private int newWidth  = 1;
51     private int newHeight = 1;
52     private AtomicBoolean reshapeNeeded  = new AtomicBoolean(false);
53     private final Object lock = new Object();
54     
55     public AwtPanel(PaintMode paintMode){
56         this.paintMode = paintMode;
57         
58         if (paintMode == PaintMode.Accelerated){
59             setIgnoreRepaint(true);
60         }
61         
62         addComponentListener(new ComponentAdapter(){
63             @Override
64             public void componentResized(ComponentEvent e) {
65                 synchronized (lock){
66                     int newWidth2 = Math.max(getWidth(), 1);
67                     int newHeight2 = Math.max(getHeight(), 1);
68                     if (newWidth != newWidth2 || newHeight != newHeight2){
69                         newWidth = newWidth2;
70                         newHeight = newHeight2;
71                         reshapeNeeded.set(true);
72                         System.out.println("EDT: componentResized " + newWidth + ", " + newHeight);
73                     }
74                 }
75             }
76         });
77     }
78     
79     @Override
80     public void addNotify(){
81         super.addNotify();
82
83         synchronized (lock){
84             hasNativePeer.set(true);
85             System.out.println("EDT: addNotify");
86         }
87         
88         requestFocusInWindow();
89     }
90
91     @Override
92     public void removeNotify(){
93         synchronized (lock){
94             hasNativePeer.set(false);
95             System.out.println("EDT: removeNotify");
96         }
97         
98         super.removeNotify();
99     }
100     
101     @Override
102     public void paint(Graphics g){
103         Graphics2D g2d = (Graphics2D) g;
104         synchronized (lock){
105             g2d.drawImage(img, transformOp, 0, 0);
106         }
107     }
108     
109     public boolean checkVisibilityState(){
110         if (!hasNativePeer.get()){
111             if (strategy != null){
112                 strategy.dispose();
113                 strategy = null;
114                 System.out.println("OGL: Not visible. Destroy strategy.");
115             }
116             return false;
117         }
118         
119         boolean currentShowing = isShowing();
120         if (showing.getAndSet(currentShowing) != currentShowing){
121             if (currentShowing){
122                 System.out.println("OGL: Enter showing state.");
123             }else{
124                 System.out.println("OGL: Exit showing state.");
125             }
126         }
127         return currentShowing;
128     }
129     
130     public void repaintInThread(){
131         // Convert screenshot.
132         byteBuf.clear();
133         rm.getRenderer().readFrameBuffer(fb, byteBuf);
134         
135         synchronized (lock){
136             // All operations on img must be synchronized
137             // as it is accessed from EDT.
138             Screenshots.convertScreenShot2(intBuf, img);
139             repaint();
140         }
141     }
142     
143     public void drawFrameInThread(){
144         // Convert screenshot.
145         byteBuf.clear();
146         rm.getRenderer().readFrameBuffer(fb, byteBuf);
147         Screenshots.convertScreenShot2(intBuf, img);
148         
149         synchronized (lock){
150             // All operations on strategy should be synchronized (?)
151             if (strategy == null){
152                 try {
153                     createBufferStrategy(1, 
154                             new BufferCapabilities(
155                                 new ImageCapabilities(true), 
156                                 new ImageCapabilities(true), 
157                                 BufferCapabilities.FlipContents.UNDEFINED)
158                                         );
159                 } catch (AWTException ex) {
160                     ex.printStackTrace();
161                 }
162                 strategy = getBufferStrategy();
163                 System.out.println("OGL: Visible. Create strategy.");
164             }
165             
166             // Draw screenshot.
167             do {
168                 do {
169                     Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
170                     if (g2d == null){
171                         System.out.println("OGL: DrawGraphics was null.");
172                         return;
173                     }
174                     
175                     g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
176                                          RenderingHints.VALUE_RENDER_SPEED);
177                     
178                     g2d.drawImage(img, transformOp, 0, 0);
179                     g2d.dispose();
180                     strategy.show();
181                 } while (strategy.contentsRestored());
182             } while (strategy.contentsLost());
183         }
184     }
185     
186     public boolean isActiveDrawing(){
187         return paintMode != PaintMode.OnRequest && showing.get();
188     }
189     
190     public void attachTo(boolean overrideMainFramebuffer, ViewPort ... vps){
191         if (viewPorts.size() > 0){
192             for (ViewPort vp : viewPorts){
193                 vp.setOutputFrameBuffer(null);
194             }
195             viewPorts.get(viewPorts.size()-1).removeProcessor(this);
196         }
197         
198         viewPorts.addAll(Arrays.asList(vps));
199         viewPorts.get(viewPorts.size()-1).addProcessor(this);
200         
201         this.attachAsMain = overrideMainFramebuffer;
202     }
203     
204     public void initialize(RenderManager rm, ViewPort vp) {
205         if (this.rm == null){
206             // First time called in OGL thread
207             this.rm = rm;
208             reshapeInThread(1, 1);
209         }
210     }
211
212     private void reshapeInThread(int width, int height) {
213         byteBuf = BufferUtils.ensureLargeEnough(byteBuf, width * height * 4);
214         intBuf = byteBuf.asIntBuffer();
215         
216         fb = new FrameBuffer(width, height, 1);
217         fb.setDepthBuffer(Format.Depth);
218         fb.setColorBuffer(Format.RGB8);
219         
220         if (attachAsMain){
221             rm.getRenderer().setMainFrameBufferOverride(fb);
222         }
223         
224         synchronized (lock){
225             img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
226         }
227         
228 //        synchronized (lock){
229 //            img = (BufferedImage) getGraphicsConfiguration().createCompatibleImage(width, height);
230 //        }
231         
232         AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
233         tx.translate(0, -img.getHeight());
234         transformOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
235         
236         for (ViewPort vp : viewPorts){
237             if (!attachAsMain){
238                 vp.setOutputFrameBuffer(fb);
239             }
240             vp.getCamera().resize(width, height, true);
241             
242             // NOTE: Hack alert. This is done ONLY for custom framebuffers.
243             // Main framebuffer should use RenderManager.notifyReshape().
244             for (SceneProcessor sp : vp.getProcessors()){
245                 sp.reshape(vp, width, height);
246             }
247         }
248     }
249
250     public boolean isInitialized() {
251         return fb != null;
252     }
253
254     public void preFrame(float tpf) {
255     }
256
257     public void postQueue(RenderQueue rq) {
258     }
259     
260     @Override
261     public void invalidate(){
262         // For "PaintMode.OnDemand" only.
263         repaintRequest.set(true);
264     }
265
266     public void postFrame(FrameBuffer out) {
267         if (!attachAsMain && out != fb){
268             throw new IllegalStateException("Why did you change the output framebuffer?");
269         }
270         
271         if (reshapeNeeded.getAndSet(false)){
272             reshapeInThread(newWidth, newHeight);
273         }else{
274             if (!checkVisibilityState()){
275                 return;
276             }
277             
278             switch (paintMode){
279                 case Accelerated:
280                     drawFrameInThread();
281                     break;
282                 case Repaint:
283                     repaintInThread();
284                     break;
285                 case OnRequest:
286                     if (repaintRequest.getAndSet(false)){
287                         repaintInThread();
288                     }
289                     break;
290             }
291         }
292     }
293     
294     public void reshape(ViewPort vp, int w, int h) {
295     }
296
297     public void cleanup() {
298     }
299 }