1 package com.jme3.system.awt;
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;
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;
25 public class AwtPanel extends Canvas implements SceneProcessor {
27 private boolean attachAsMain = false;
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>();
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);
45 private int newWidth = 1;
46 private int newHeight = 1;
47 private AtomicBoolean reshapeNeeded = new AtomicBoolean(false);
48 private final Object lock = new Object();
50 public AwtPanel(PaintMode paintMode){
51 this.paintMode = paintMode;
53 if (paintMode == PaintMode.Accelerated){
54 setIgnoreRepaint(true);
57 addComponentListener(new ComponentAdapter(){
59 public void componentResized(ComponentEvent e) {
61 int newWidth2 = Math.max(getWidth(), 1);
62 int newHeight2 = Math.max(getHeight(), 1);
63 if (newWidth != newWidth2 || newHeight != newHeight2){
65 newHeight = newHeight2;
66 reshapeNeeded.set(true);
67 System.out.println("EDT: componentResized " + newWidth + ", " + newHeight);
75 public void addNotify(){
79 hasNativePeer.set(true);
80 System.out.println("EDT: addNotify");
83 requestFocusInWindow();
87 public void removeNotify(){
89 hasNativePeer.set(false);
90 System.out.println("EDT: removeNotify");
97 public void paint(Graphics g){
98 Graphics2D g2d = (Graphics2D) g;
100 g2d.drawImage(img, transformOp, 0, 0);
104 public boolean checkVisibilityState(){
105 if (!hasNativePeer.get()){
106 if (strategy != null){
109 System.out.println("OGL: Not visible. Destroy strategy.");
114 boolean currentShowing = isShowing();
115 if (showing.getAndSet(currentShowing) != currentShowing){
117 System.out.println("OGL: Enter showing state.");
119 System.out.println("OGL: Exit showing state.");
122 return currentShowing;
125 public void repaintInThread(){
126 // Convert screenshot.
128 rm.getRenderer().readFrameBuffer(fb, byteBuf);
131 // All operations on img must be synchronized
132 // as it is accessed from EDT.
133 Screenshots.convertScreenShot2(intBuf, img);
138 public void drawFrameInThread(){
139 // Convert screenshot.
141 rm.getRenderer().readFrameBuffer(fb, byteBuf);
142 Screenshots.convertScreenShot2(intBuf, img);
145 // All operations on strategy should be synchronized (?)
146 if (strategy == null){
148 createBufferStrategy(1,
149 new BufferCapabilities(
150 new ImageCapabilities(true),
151 new ImageCapabilities(true),
152 BufferCapabilities.FlipContents.UNDEFINED)
154 } catch (AWTException ex) {
155 ex.printStackTrace();
157 strategy = getBufferStrategy();
158 System.out.println("OGL: Visible. Create strategy.");
164 Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
166 System.out.println("OGL: DrawGraphics was null.");
170 g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
171 RenderingHints.VALUE_RENDER_SPEED);
173 g2d.drawImage(img, transformOp, 0, 0);
176 } while (strategy.contentsRestored());
177 } while (strategy.contentsLost());
181 public boolean isActiveDrawing(){
182 return paintMode != PaintMode.OnRequest && showing.get();
185 public void attachTo(boolean overrideMainFramebuffer, ViewPort ... vps){
186 if (viewPorts.size() > 0){
187 for (ViewPort vp : viewPorts){
188 vp.setOutputFrameBuffer(null);
190 viewPorts.get(viewPorts.size()-1).removeProcessor(this);
193 viewPorts.addAll(Arrays.asList(vps));
194 viewPorts.get(viewPorts.size()-1).addProcessor(this);
196 this.attachAsMain = overrideMainFramebuffer;
199 public void initialize(RenderManager rm, ViewPort vp) {
200 if (this.rm == null){
201 // First time called in OGL thread
203 reshapeInThread(1, 1);
207 private void reshapeInThread(int width, int height) {
208 byteBuf = BufferUtils.ensureLargeEnough(byteBuf, width * height * 4);
209 intBuf = byteBuf.asIntBuffer();
211 fb = new FrameBuffer(width, height, 1);
212 fb.setDepthBuffer(Format.Depth);
213 fb.setColorBuffer(Format.RGB8);
216 rm.getRenderer().setMainFrameBufferOverride(fb);
220 img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
223 // synchronized (lock){
224 // img = (BufferedImage) getGraphicsConfiguration().createCompatibleImage(width, height);
227 AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
228 tx.translate(0, -img.getHeight());
229 transformOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
231 for (ViewPort vp : viewPorts){
233 vp.setOutputFrameBuffer(fb);
235 vp.getCamera().resize(width, height, true);
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);
245 public boolean isInitialized() {
249 public void preFrame(float tpf) {
252 public void postQueue(RenderQueue rq) {
256 public void invalidate(){
257 // For "PaintMode.OnDemand" only.
258 repaintRequest.set(true);
261 public void postFrame(FrameBuffer out) {
262 if (!attachAsMain && out != fb){
263 throw new IllegalStateException("Why did you change the output framebuffer?");
266 if (reshapeNeeded.getAndSet(false)){
267 reshapeInThread(newWidth, newHeight);
269 if (!checkVisibilityState()){
281 if (repaintRequest.getAndSet(false)){
289 public void reshape(ViewPort vp, int w, int h) {
292 public void cleanup() {