Texture cloning

Hi,



I want to clone the Texture of a JMEDesktop and attatch it to a quad, but with one exception. Changes on the JMEDesktop will have no effect on the cloned Texture. So I wrote the folling test state, to show you my problem.



public class TextureCopyTest extends DebugGameState {

   private JMEDesktop jmeDesktop;
   private Quad testQuad1;
   private Quad testQuad2;

   public TextureCopyTest() {
      super();
      initKeyBindings();

      // create the test Quads
      testQuad1 = new Quad("testQuad1", 10.24f, 20.48f);
      testQuad2 = new Quad("testQuad2", 10.24f, 20.48f);

      testQuad1.setLocalTranslation(new Vector3f(10.0f, 0.0f, 0.0f));
      testQuad2.setLocalTranslation(new Vector3f(20.0f, 0.0f, 0.0f));

      testQuad1.setLightCombineMode(LightState.OFF);
      testQuad2.setLightCombineMode(LightState.OFF);
      
      // create the desktop Quad
      Callable<?> preload = new Callable() {
         public Object call() throws Exception {
            initJMEDesktop();
            jmeDesktop.setLocalScale(0.01f);
            jmeDesktop.updateRenderState();
            copyTexture();
            testQuad1.updateRenderState();
            testQuad2.updateRenderState();
            return null;
         }
      };
      GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(preload);

      rootNode.attachChild(testQuad1);
      rootNode.attachChild(testQuad2);

//      SceneMonitor.getMonitor().registerNode(rootNode, "Root Node");
//      SceneMonitor.getMonitor().showViewer(true);
   }

   private void initKeyBindings() {
      KeyBindingManager.getKeyBindingManager().set("copyTexFinal", KeyInput.KEY_X);
   }

   @Override
   public void update(float tpf) {
      super.update(tpf);
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("copyTexFinal", false)) {
         copyTextureFinal(jmeDesktop, testQuad1);
         this.getRootNode().updateRenderState();
      }
      
      SceneMonitor.getMonitor().updateViewer(tpf);
   }
   
   @Override
   public void render(float tpf) {
      super.render(tpf);
//      SceneMonitor.getMonitor().renderViewer(DisplaySystem.getDisplaySystem().getRenderer());
   }

   @Override
   public void cleanup() {
      super.cleanup();
//      SceneMonitor.getMonitor().unregisterNode(rootNode);
   }

   private void copyTexture() {
      TextureState state = (TextureState) jmeDesktop.getRenderState(RenderState.RS_TEXTURE);      
      TextureState state2 = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
      state2.setTexture(state.getTexture());
      testQuad1.setRenderState(state2);
      testQuad2.setRenderState(state);
   }

   private void initJMEDesktop() {
      jmeDesktop = new JMEDesktop("test internalFrame");
      jmeDesktop.setup(800, 1185, false, input);

      jmeDesktop.setLightCombineMode(LightState.OFF);
      rootNode.attachChild(jmeDesktop);

      jmeDesktop.getJDesktop().setBackground(new Color(1, 1, 1, 0.2f));

      // No Alpha State
      AlphaState alpha = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
      jmeDesktop.setRenderState(alpha);

      createSwingStuff();
   }

   protected void createSwingStuff() {
      final JDesktopPane desktopPane = jmeDesktop.getJDesktop();
      desktopPane.removeAll();

      createSwingInternalFrame(desktopPane, "My Frame 1", 10, 150);
      createSwingInternalFrame(desktopPane, "My Frame 2", 20, 300);
      createSwingInternalFrame(desktopPane, null, 400, 350);

      final JButton button3 = new JButton("more stuff");
      button3.setLocation(300, 100);
      button3.setSize(button3.getPreferredSize());
      desktopPane.add(button3);

      final JButton buttonToggleMouse = new JButton("toggle system/custom cursor");
      buttonToggleMouse.setLocation(300, 70);
      buttonToggleMouse.setSize(buttonToggleMouse.getPreferredSize());
      desktopPane.add(buttonToggleMouse);

      buttonToggleMouse.setMnemonic('m');

      final JLabel label = new JLabel("click scene to steer view (WASD+Arrows)");
      label.setSize(label.getPreferredSize());
      desktopPane.add(label);

      final JButton themeButton = new JButton("change l&f");
      themeButton.setLocation(10, 400);
      themeButton.setSize(themeButton.getPreferredSize());
      desktopPane.add(themeButton);

      JButton fullScreenButton = new JButton("<html><big>toggle fullscreen</big></html>");
      fullScreenButton.setSize(fullScreenButton.getPreferredSize());

      desktopPane.repaint();
      desktopPane.revalidate();
   }

   private void createSwingInternalFrame(final JDesktopPane desktopPane, final String title, int x, int y) {
      final JInternalFrame internalFrame = new JInternalFrame(title);
      if (title == null) {
         internalFrame.putClientProperty("JInternalFrame.isPalette", Boolean.TRUE);
      }
      internalFrame.setLocation(x, y);
      internalFrame.setResizable(true);

      internalFrame.getContentPane().setLayout(new FlowLayout());
      JButton button1 = new JButton("button in " + title);
      button1.setMnemonic('u');
      internalFrame.getContentPane().add(button1);
      internalFrame.getContentPane().add(new JButton("<html><i>test</i> <big>2</big></html>"));
      internalFrame.setVisible(true);
      internalFrame.pack();

      final JTextField textField = new JTextField("type in here");
      internalFrame.getContentPane().add(textField);
      internalFrame.pack();
      desktopPane.add(internalFrame);
   }

   private void copyTextureFinal(SceneElement source, SceneElement target) {
      TextureState ts = (TextureState) source.getRenderState(RenderState.RS_TEXTURE);

      // clone image
      CloneImportExport ie = new CloneImportExport();
      ie.saveClone(ts.getTexture().getImage());
      Image clonedImage = (Image) ie.loadClone();

      // create new texture
      Texture newT = new Texture();
      // clone the buffer? (no effect)
//      ByteBuffer bb = BufferUtils.clone(clonedImage.getData());
//      clonedImage.setData(bb);
      newT.setImage(clonedImage);
      newT.setScale(new Vector3f(1, -1, 1));
      newT.setFilter(Texture.FM_LINEAR);
      newT.setWrap(Texture.WM_WRAP_S_WRAP_T);   

      // apply texture to texture state
      TextureState newState = (TextureState) target.getRenderState(RenderState.RS_TEXTURE);
      newState.setTexture(newT);
      newState.apply();
      target.updateRenderState();
   }

   public static void main(String args[]) {
      StandardGame game = new StandardGame("JMEDesktop Test");
      game.start();

      GameStateManager.create();
      TextureCopyTest state = new TextureCopyTest();
      GameStateManager.getInstance().attachChild(state);
      state.setActive(true);

      state.getRootNode().updateRenderState();
   }
}



If you push 'x' the Methode "copyTextureFinal" is called. But as you see,  the quad in the middle will be complete black and thats the problem :). I want a cloned texture wich is not connected to changes on the JMEDesktop. I tried to solve this some months ago, but up till now I found no solution to this. Maybe someone have an idea.


      // clone the buffer? (no effect)
//      ByteBuffer bb = BufferUtils.clone(clonedImage.getData());
//      clonedImage.setData(bb);



has no effect because you cloned clonedImage.getData(). Not sure why it doesn't work though...

Thats right, it was an old test and I doenst change the var :).

And thanks that you tried the code, I thought nobody looked at it.

But I have still no solution for this problem :/.

Not sure about how JMEDesktop works, but it might be that the texture is generated on the GPU using RTT, in that case you can't just copy the texture data. You have to use a call like glCopyTexImage to get it from the FBO or add your texture as another render target.

Thanks Momoko, I will give it a try. That are all new things to me, but maybe I can figure it out :).

where do we stand on this topic? someone figured it out?

Took a quick look at jME-desktop today… JMEDesktop uses ImageGraphics to paint it's stuff. After JMEDesktop updates, it's ImageGraphics object will contain the data which was painted on it by swing. If you can control when JMEDesktop updates and have access to it's graphics instance, you will be able to create a unique texture from that data (e.g take a snapshot).