Home | History | Annotate | Download | only in post
      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
     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 
    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 
    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 
    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 
    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
    214     public void simpleInitApp() {
    215         setupOffscreenView();
    216         createDisplayFrame();
    217     }
    218 
    219     @Override
    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 
    231     public void initialize(RenderManager rm, ViewPort vp) {
    232     }
    233 
    234     public void reshape(ViewPort vp, int w, int h) {
    235     }
    236 
    237     public boolean isInitialized() {
    238         return true;
    239     }
    240 
    241     public void preFrame(float tpf) {
    242     }
    243 
    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      */
    251     public void postFrame(FrameBuffer out) {
    252         updateImageContents();
    253     }
    254 
    255     public void cleanup() {
    256     }
    257 
    258 
    259 }
    260