• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * 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  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions 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 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package jme3test.post;
34 
35 import com.jme3.app.SimpleApplication;
36 import com.jme3.material.Material;
37 import com.jme3.math.ColorRGBA;
38 import com.jme3.math.FastMath;
39 import com.jme3.math.Quaternion;
40 import com.jme3.math.Vector3f;
41 import com.jme3.post.SceneProcessor;
42 import com.jme3.renderer.Camera;
43 import com.jme3.renderer.RenderManager;
44 import com.jme3.renderer.ViewPort;
45 import com.jme3.renderer.queue.RenderQueue;
46 import com.jme3.scene.Geometry;
47 import com.jme3.scene.shape.Box;
48 import com.jme3.system.AppSettings;
49 import com.jme3.system.JmeContext.Type;
50 import com.jme3.texture.FrameBuffer;
51 import com.jme3.texture.Image.Format;
52 import com.jme3.texture.Texture2D;
53 import com.jme3.util.BufferUtils;
54 import com.jme3.util.Screenshots;
55 import java.awt.Color;
56 import java.awt.Dimension;
57 import java.awt.Graphics;
58 import java.awt.Graphics2D;
59 import java.awt.event.WindowAdapter;
60 import java.awt.event.WindowEvent;
61 import java.awt.image.BufferedImage;
62 import java.nio.ByteBuffer;
63 import javax.swing.JFrame;
64 import javax.swing.JPanel;
65 import javax.swing.SwingUtilities;
66 
67 /**
68  * This test renders a scene to an offscreen framebuffer, then copies
69  * the contents to a Swing JFrame. Note that some parts are done inefficently,
70  * this is done to make the code more readable.
71  */
72 public class TestRenderToMemory extends SimpleApplication implements SceneProcessor {
73 
74     private Geometry offBox;
75     private float angle = 0;
76 
77     private FrameBuffer offBuffer;
78     private ViewPort offView;
79     private Texture2D offTex;
80     private Camera offCamera;
81     private ImageDisplay display;
82 
83     private static final int width = 800, height = 600;
84 
85     private final ByteBuffer cpuBuf = BufferUtils.createByteBuffer(width * height * 4);
86     private final byte[] cpuArray = new byte[width * height * 4];
87     private final BufferedImage image = new BufferedImage(width, height,
88                                             BufferedImage.TYPE_4BYTE_ABGR);
89 
90     private class ImageDisplay extends JPanel {
91 
92         private long t;
93         private long total;
94         private int frames;
95         private int fps;
96 
97         @Override
paintComponent(Graphics gfx)98         public void paintComponent(Graphics gfx) {
99             super.paintComponent(gfx);
100             Graphics2D g2d = (Graphics2D) gfx;
101 
102             if (t == 0)
103                 t = timer.getTime();
104 
105 //            g2d.setBackground(Color.BLACK);
106 //            g2d.clearRect(0,0,width,height);
107 
108             synchronized (image){
109                 g2d.drawImage(image, null, 0, 0);
110             }
111 
112             long t2 = timer.getTime();
113             long dt = t2 - t;
114             total += dt;
115             frames ++;
116             t = t2;
117 
118             if (total > 1000){
119                 fps = frames;
120                 total = 0;
121                 frames = 0;
122             }
123 
124             g2d.setColor(Color.white);
125             g2d.drawString("FPS: "+fps, 0, getHeight() - 100);
126         }
127     }
128 
main(String[] args)129     public static void main(String[] args){
130         TestRenderToMemory app = new TestRenderToMemory();
131         app.setPauseOnLostFocus(false);
132         AppSettings settings = new AppSettings(true);
133         settings.setResolution(1, 1);
134         app.setSettings(settings);
135         app.start(Type.OffscreenSurface);
136     }
137 
createDisplayFrame()138     public void createDisplayFrame(){
139         SwingUtilities.invokeLater(new Runnable(){
140             public void run(){
141                 JFrame frame = new JFrame("Render Display");
142                 display = new ImageDisplay();
143                 display.setPreferredSize(new Dimension(width, height));
144                 frame.getContentPane().add(display);
145                 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
146                 frame.addWindowListener(new WindowAdapter(){
147                     public void windowClosed(WindowEvent e){
148                         stop();
149                     }
150                 });
151                 frame.pack();
152                 frame.setLocationRelativeTo(null);
153                 frame.setResizable(false);
154                 frame.setVisible(true);
155             }
156         });
157     }
158 
updateImageContents()159     public void updateImageContents(){
160         cpuBuf.clear();
161         renderer.readFrameBuffer(offBuffer, cpuBuf);
162 
163         synchronized (image) {
164             Screenshots.convertScreenShot(cpuBuf, image);
165         }
166 
167         if (display != null)
168             display.repaint();
169     }
170 
setupOffscreenView()171     public void setupOffscreenView(){
172         offCamera = new Camera(width, height);
173 
174         // create a pre-view. a view that is rendered before the main view
175         offView = renderManager.createPreView("Offscreen View", offCamera);
176         offView.setBackgroundColor(ColorRGBA.DarkGray);
177         offView.setClearFlags(true, true, true);
178 
179         // this will let us know when the scene has been rendered to the
180         // frame buffer
181         offView.addProcessor(this);
182 
183         // create offscreen framebuffer
184         offBuffer = new FrameBuffer(width, height, 1);
185 
186         //setup framebuffer's cam
187         offCamera.setFrustumPerspective(45f, 1f, 1f, 1000f);
188         offCamera.setLocation(new Vector3f(0f, 0f, -5f));
189         offCamera.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y);
190 
191         //setup framebuffer's texture
192 //        offTex = new Texture2D(width, height, Format.RGBA8);
193 
194         //setup framebuffer to use renderbuffer
195         // this is faster for gpu -> cpu copies
196         offBuffer.setDepthBuffer(Format.Depth);
197         offBuffer.setColorBuffer(Format.RGBA8);
198 //        offBuffer.setColorTexture(offTex);
199 
200         //set viewport to render to offscreen framebuffer
201         offView.setOutputFrameBuffer(offBuffer);
202 
203         // setup framebuffer's scene
204         Box boxMesh = new Box(Vector3f.ZERO, 1,1,1);
205         Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m");
206         offBox = new Geometry("box", boxMesh);
207         offBox.setMaterial(material);
208 
209         // attach the scene to the viewport to be rendered
210         offView.attachScene(offBox);
211     }
212 
213     @Override
simpleInitApp()214     public void simpleInitApp() {
215         setupOffscreenView();
216         createDisplayFrame();
217     }
218 
219     @Override
simpleUpdate(float tpf)220     public void simpleUpdate(float tpf){
221         Quaternion q = new Quaternion();
222         angle += tpf;
223         angle %= FastMath.TWO_PI;
224         q.fromAngles(angle, 0, angle);
225 
226         offBox.setLocalRotation(q);
227         offBox.updateLogicalState(tpf);
228         offBox.updateGeometricState();
229     }
230 
initialize(RenderManager rm, ViewPort vp)231     public void initialize(RenderManager rm, ViewPort vp) {
232     }
233 
reshape(ViewPort vp, int w, int h)234     public void reshape(ViewPort vp, int w, int h) {
235     }
236 
isInitialized()237     public boolean isInitialized() {
238         return true;
239     }
240 
preFrame(float tpf)241     public void preFrame(float tpf) {
242     }
243 
postQueue(RenderQueue rq)244     public void postQueue(RenderQueue rq) {
245     }
246 
247     /**
248      * Update the CPU image's contents after the scene has
249      * been rendered to the framebuffer.
250      */
postFrame(FrameBuffer out)251     public void postFrame(FrameBuffer out) {
252         updateImageContents();
253     }
254 
cleanup()255     public void cleanup() {
256     }
257 
258 
259 }
260