OSDN Git Service

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