JME 2 Integration with FengGUI

My apologies on deleting my previous post.  There didn't seem much of an interest, and I improved the code since then.



There exists an older style of integrating FengGUI with JME 2.  This style works fine when applied to FengGUI SVN revision 638 or below.  Above that, the internal structure of FengGUI applies a different technique for handling data.  I have placed attention into an integration that works with FengGUI SVN 653 and JME 2 SVN revision 4570.  I foresee such code going into a portion of the JME wiki in the future.



Until that happens, I would like to host some example code on a web site I am constructing.  I see a problem in that I plan to put up a bit of advertising on the site, and that may offend someone.  However, everything in life has a price whether in time or money, and I'm not asking for payments.



Thanks.

shatterblast said:
(...)
Until that happens, I would like to host some example code on a web site I am constructing.  I see a problem in that I plan to put up a bit of advertising on the site, and that may offend someone.  However, everything in life has a price whether in time or money, and I'm not asking for payments.

Thanks.

I don't see any problem with that, as long as your advertisement isn't intrusive and you can vouch for its security (I've been to some sites where their automated advertisements actually caused a lot of malicious warnings without them knowing). There are other sites around that do the same as you. It's always nice if the end product finds its way into our or some common open source repo in the end though, like SF or google code.

I've got not problem with that, but it would be super appreciated if you could post the code here as well (with a link saying that the external site is the most up-to-date or something)…  The reason for this is that searching for a bit of that code won't turn up any results if it's on an external site



I, for one, will search the name of the method I'm having trouble with rather than the actual problem I'm trying to solve…  If the code is hosted elsewhere, it won't show up :frowning:



Either way, code snippets are code snippets… anyone donating their time to teach others is definitely in sync with jME :smiley:

I thought of making self-executing jar files with class files, resources, and source code inside.  I might produce a variety of jar files for a couple of different examples.  I have two ready to go anyhow.

Thank you for your opinions.  I will begin to put up the code.  Hopefully, it will be up sometime tomorrow.

I have finished what I can.  I spent the day merging two of my java packages into a single one.  While the source code has become available, a delay has occurred for any self-executing jar file.  I must advise usage of full-screen LWJGL mode due to the experimental nature of both the code from myself and SVN.  For this reason, you should place a copy of the LWJGL “native” folder in a shared space with the source code’s package folder in your development environment.  Check “findNatives” in the source for further investigation.



My link:

http://shatterblast.getenjoyment.net/

I have obtained third-party file hosting.  I should have available a self-executable jar file in a day or two.

I have removed advertisements temporarily.  A larger ZIP file without the source code is available from the link "Download Integration Examples".  All notes are updated.



I'm ceasing efforts for now to resume my own project.  Please leave comments, and I will handle them as possible.  Thanks.

And finally, here are the most necessary files with nothing else attached.  IExample.java will need to be taken from the FengGUI code and placed into the same package folder.  The Everything.java code provided here will need modifying on your part if you want certain examples added or taken away.  Testing confirms compatibility with JME 2 SVN 4596.  I borrowed the "findNatives" code from the LWJGL forums.  It helped keep code consistent with their releases.



JOGL has been untested, but my previous session produced a "missing mouse" error.


/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package jME2_and_FengGUI_Integration;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

import org.fenggui.Display;
import org.fenggui.binding.render.lwjgl.LWJGLBinding;

import com.jme.app.SimpleGame;
import com.jme.image.Texture;
import com.jme.input.MouseInput;
import com.jme.math.Vector3f;
import com.jme.scene.state.TextureState;

/**
 * AppStart_Edit
 *
 * @author Original author: Unknown
 * @author Modification by Wesley Lange, " shatterblast "
 */

public class AppStart_Edit extends SimpleGame {
   public static void main(String[] args) {
      AppStart_Edit app = new AppStart_Edit();
      app.setConfigShowMode(ConfigShowMode.AlwaysShow);
      app.findNatives();
      app.start();
   }

   Display disp;

   TextureState defaultTextureState;

   public void findNatives() {

      /*
       * Set lwjgl library path so that LWJGL finds the natives depending on
       * the OS.
       */
      String osName = System.getProperty("os.name");
      // Get .jar dir. new File(".") and property "user.dir" will not work if
      // .jar is called from
      // a different directory, e.g. java -jar /someOtherDirectory/myApp.jar
      String nativeDir = "";
      try {
         nativeDir = new File(this.getClass().getProtectionDomain()
               .getCodeSource().getLocation().toURI()).getParent();
      } catch (URISyntaxException uriEx) {
         try {
            // Try to resort to current dir. May still fail later due to bad
            // start dir.
            uriEx.printStackTrace();
            nativeDir = new File(".").getCanonicalPath();
         } catch (IOException ioEx) {
            // Completely failed
            System.out
                  .println("Failed to locate native library directory. Error:n"
                        + ioEx.toString());
            ioEx.printStackTrace();
            System.exit(-1);
         }
      }

      // Append library subdir
      nativeDir += File.separator + "native" + File.separator;
      if (osName.startsWith("Windows")) {
         nativeDir += "windows";
      } else if (osName.startsWith("Linux") || osName.startsWith("FreeBSD")) {
         nativeDir += "linux";
      } else if (osName.startsWith("Mac OS X")) {
         nativeDir += "macosx";
      } else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) {
         nativeDir += "solaris";
      } else {
         System.out.println("Unsupported OS: " + osName + ". Exiting.");
         System.exit(-1);
      }
      System.setProperty("org.lwjgl.librarypath", nativeDir);
   }

   // Pieces together the beginnings of FengGUI.
   protected void initGUI() {
      disp = new org.fenggui.Display(
            new org.fenggui.binding.render.lwjgl.LWJGLBinding());

      input = new FengJMEInputHandler(disp);

      Everything everything = new Everything();
      everything.buildGUI(disp);

      disp.layout();

   }

   @Override
   protected void simpleInitGame() {
      Texture defTex = TextureState.getDefaultTexture().createSimpleClone();
      defaultTextureState = display.getRenderer().createTextureState();
      defTex.setScale(new Vector3f(1, 1, 1));
      defaultTextureState.setTexture(defTex);

      disp = new Display(new LWJGLBinding());
      input = new FengJMEInputHandler(disp);

      initGUI();

      MouseInput.get().setCursorVisible(true);
   }

   // Seems necessary for sending the texture verification to the OpenGL
   // rendering thread.
   // Otherwise, the GUI will not show.
   @Override
   protected void simpleRender() {
      defaultTextureState.apply();

      disp.display();
   }
}



/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * FengGUI - Java GUIs in OpenGL (http://www.fenggui.org)
 *
 * Copyright (C) 2005-2009 FengGUI Project
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details:
 * http://www.gnu.org/copyleft/lesser.html#TOC3
 */

package jME2_and_FengGUI_Integration;

import org.fenggui.event.key.Key;
import org.fenggui.event.mouse.MouseButton;
import org.lwjgl.input.Keyboard;

import com.jme.input.InputHandler;
import com.jme.input.MouseInput;
import com.jme.input.MouseInputListener;
import com.jme.input.action.InputActionEvent;
import com.jme.input.action.KeyInputAction;

/**
 *
 * @author Johannes Schaback
 * @author Modification by Wesley Lange, " shatterblast "
 *
 */

public class FengJMEInputHandler extends InputHandler {

   private class KeyAction extends KeyInputAction {

      /**
       * Helper method that maps LWJGL key events to FengGUI.
       *
       * @return The Key enumeration of the last key pressed.
       */
      private Key mapKeyEvent() {
         Key keyClass;

         switch (Keyboard.getEventKey()) {
         case Keyboard.KEY_BACK:
            keyClass = Key.BACKSPACE;
            break;
         case Keyboard.KEY_RETURN:
            keyClass = Key.ENTER;
            break;
         case Keyboard.KEY_DELETE:
            keyClass = Key.DELETE;
            break;
         case Keyboard.KEY_UP:
            keyClass = Key.UP;
            break;
         case Keyboard.KEY_RIGHT:
            keyClass = Key.RIGHT;
            break;
         case Keyboard.KEY_LEFT:
            keyClass = Key.LEFT;
            break;
         case Keyboard.KEY_DOWN:
            keyClass = Key.DOWN;
            break;
         case Keyboard.KEY_SCROLL:
            keyClass = Key.SHIFT;
            break;
         case Keyboard.KEY_LMENU:
            keyClass = Key.ALT;
            break;
         case Keyboard.KEY_RMENU:
            keyClass = Key.ALT;
            break;
         case Keyboard.KEY_LCONTROL:
            keyClass = Key.CTRL;
            break;
         case Keyboard.KEY_RSHIFT:
            keyClass = Key.SHIFT;
            break;
         case Keyboard.KEY_LSHIFT:
            keyClass = Key.SHIFT;
            break;
         case Keyboard.KEY_RCONTROL:
            keyClass = Key.CTRL;
            break;
         case Keyboard.KEY_INSERT:
            keyClass = Key.INSERT;
            break;
         case Keyboard.KEY_F12:
            keyClass = Key.F12;
            break;
         case Keyboard.KEY_F11:
            keyClass = Key.F11;
            break;
         case Keyboard.KEY_F10:
            keyClass = Key.F10;
            break;
         case Keyboard.KEY_F9:
            keyClass = Key.F9;
            break;
         case Keyboard.KEY_F8:
            keyClass = Key.F8;
            break;
         case Keyboard.KEY_F7:
            keyClass = Key.F7;
            break;
         case Keyboard.KEY_F6:
            keyClass = Key.F6;
            break;
         case Keyboard.KEY_F5:
            keyClass = Key.F5;
            break;
         case Keyboard.KEY_F4:
            keyClass = Key.F4;
            break;
         case Keyboard.KEY_F3:
            keyClass = Key.F3;
            break;
         case Keyboard.KEY_F2:
            keyClass = Key.F2;
            break;
         case Keyboard.KEY_F1:
            keyClass = Key.F1;
            break;
         default:
            if ("1234567890".indexOf(Keyboard.getEventCharacter()) != -1) {
               keyClass = Key.DIGIT;
            } else {
               // @todo must not necessarily be a letter!! #
               keyClass = Key.LETTER;
            }
            break;
         }

         return keyClass;
      }

      public void performAction(InputActionEvent evt) {
         char character = evt.getTriggerCharacter();
         Key key = mapKeyEvent();
         if (evt.getTriggerPressed()) {

            keyHandled = disp.fireKeyPressedEvent(character, key)
                  .isPressed(key);
         } else
            keyHandled = disp.fireKeyReleasedEvent(character, key)
                  .isPressed(key);
      }

   }

   private class MouseListener implements MouseInputListener {
      private Key keyboardKey1;
      private Key keyboardKey2;
      private Key mouseKey1;
      private Key mouseKey2;
      private Key mouseWheelKey1;
      private Key mouseWheelKey2;
      private boolean down;
      private int lastButton;

      /**
       * Helper method that maps the mouse button to the equivalent FengGUI
       * MouseButton enumeration.
       *
       * @param button
       *            The button pressed or released.
       * @return The FengGUI MouseButton enumeration matching the button.
       */
      private MouseButton getMouseButton(int button) {
         switch (button) {
         case 0:
            return MouseButton.LEFT;
         case 1:
            return MouseButton.RIGHT;
         case 2:
            return MouseButton.MIDDLE;
         default:
            return MouseButton.LEFT;
         }
      }

      public void onButton(int button, boolean pressed, int x, int y) {
         down = pressed;
         lastButton = button;
         if (pressed)
            mouseHandled = disp.fireMousePressedEvent(x, y,
                  getMouseButton(button)).isPressed(keyboardKey1);
         else
            mouseHandled = disp.fireMouseReleasedEvent(x, y,
                  getMouseButton(button)).isPressed(keyboardKey2);
      }

      // Dragging with the mouse might not work correctly because of how
      // "clickCount" trails to nothing.
      public void onMove(int xDelta, int yDelta, int newX, int newY) {
         // If the button is down, the mouse is being dragged
         if (down)
            mouseHandled = disp.fireMouseDraggedEvent(newX, newY,
                  getMouseButton(lastButton)).isPressed(mouseKey1);
         else
            mouseHandled = disp.fireMouseMovedEvent(newX, newY).isPressed(
                  mouseKey2);
      }

      // from Shatterblast: Scrolling with a mouse wheel does not work
      // correctly in my tests.
      // It might relate to how "scrollingAmount" trails to nothing.
      public void onWheel(int wheelDelta, int x, int y) {
         int scrollingAmount = 0;

         // wheelDelta is positive if the mouse wheel rolls up
         if (wheelDelta > 0)
            mouseHandled = disp.fireMouseWheel(x, y, true, wheelDelta,
                  scrollingAmount).isPressed(mouseWheelKey1);
         else
            mouseHandled = disp.fireMouseWheel(x, y, false, wheelDelta,
                  scrollingAmount).isPressed(mouseWheelKey2);

         // note (johannes): wheeling code not tested on jME, please report
         // problems on www.fenggui.org/forum/
      }

   }

   private org.fenggui.Display disp;
   private KeyInputAction keyAction;

   private boolean keyHandled;

   private boolean mouseHandled;

   public FengJMEInputHandler(org.fenggui.Display disp) {
      this.disp = disp;

      keyAction = new KeyAction();
      addAction(keyAction, DEVICE_KEYBOARD, BUTTON_ALL, AXIS_NONE, false);

      MouseInput.get().addListener(new MouseListener());
   }

   @Override
   public void update(float time) {
      keyHandled = false;
      mouseHandled = false;
      super.update(time);
   }

   public boolean wasKeyHandled() {
      return keyHandled;
   }

   public boolean wasMouseHandled() {
      return mouseHandled;
   }

}




/*

 * FengGUI - Java GUIs in OpenGL (http://www.fenggui.org)

 *

 * Copyright (C) 2005-2009 FengGUI Project

 *

 * This library is free software; you can redistribute it and/or

 * modify it under the terms of the GNU Lesser General Public

 * License as published by the Free Software Foundation; either

 * version 2.1 of the License, or (at your option) any later version.

 *

 * This library is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

 * Lesser General Public License for more details:

 * http://www.gnu.org/copyleft/lesser.html#TOC3

 */



package jME2_and_FengGUI_Integration;



import org.fenggui.Display;

import org.fenggui.FengGUI;

import org.fenggui.Widget;

import org.fenggui.binding.render.Binding;

import org.fenggui.binding.render.Graphics;

import org.fenggui.composite.menu.Menu;

import org.fenggui.composite.menu.MenuBar;

import org.fenggui.composite.menu.MenuItem;

import org.fenggui.event.IMenuItemPressedListener;

import org.fenggui.event.MenuItemPressedEvent;

import org.fenggui.theme.ITheme;

import org.fenggui.theme.XMLTheme;



/**

 *

 * @author Johannes Schaback

 * @author edited by marcmenghin

 * @author Modification by Wesley Lange, " shatterblast "

 *

 */



public class Everything {

   // This variable seems to define the rendered window's area.

   private Display display = null;



   // This portion seems necessary for displaying the widget window.

   private void buildExampleGUIinRenderThread(final IExample gameMenuExample) {

      Widget w = new Widget() {

         @Override

         public void paint(Graphics g) {

            display.removeWidget(this);

            gameMenuExample.buildGUI(display);

         }

      };

      display.addWidget(w);

   }



   // This part registers the "Examples" menu and the primary example in its

   // list.

   private void buildExamplesMenu(MenuBar menuBar) {

      Menu examplesMenu = createMenu(menuBar, "Examples", false);

      registerExample(new TextViewExample(), examplesMenu, true);

      registerExample(new GameMenuExample(), examplesMenu, true);

      registerExample(new TextAreaExample(), examplesMenu, true);

      MenuItem exitItem = new MenuItem("Exit", examplesMenu.getAppearance());

      examplesMenu.addItem(exitItem);



      // register "Exit" item to quit the app

      exitItem.addMenuItemPressedListener(new IMenuItemPressedListener() {



         public void menuItemPressed(

               MenuItemPressedEvent menuItemPressedEvent) {

            System.exit(0);

         }



      });

   }



   // This seems like the basic structure for building the window's contents.

   // It inherits from IExample's buildGUI.

   public void buildGUI(Display g) {

      display = g;

      loadThemeDirect("x_software_data/QtCurve/QtCurve.xml");

      buildMenuBar();

   }



   // Menu bars position and initiation

   private void buildMenuBar() {



      // Puts the menu bars across the top of the window.

      final MenuBar menuBar = FengGUI.createWidget(MenuBar.class);

      display.addWidget(menuBar);

      buildExamplesMenu(menuBar);



      // position MenuBar in Display

      menuBar.updateMinSize();

      menuBar.setX(0);

      menuBar.setY(display.getHeight() - menuBar.getMinHeight());

      menuBar.setSize(display.getWidth(), menuBar.getMinHeight());

   }



   // This part defines a menu. It allows the creation of the "Examples" menu

   // in this code.

   private Menu createMenu(MenuBar bar, String text, boolean isParent) {

      Menu menu = FengGUI.createWidget(Menu.class);

      bar.registerSubMenu(menu, text);

      return menu;

   }



   // Necessary in the basic structure.

   public String getExampleDescription() {

      return "";

   }



   // Necessary in the basic structure.

   public String getExampleName() {

      return "";

   }



   // This part sets the window theme.

   // I need to somehow provide links in a more direct manner to the

   // "image resources."

   private void loadThemeDirect(final String filename) {



      // The below line can cause a bit of lag.

      Binding.getInstance().setUseClassLoader(true);

      ITheme theme = null;

      // Need to figure a way of getting rid of this and setting it directly.

      try {

         theme = new XMLTheme(filename);

      } catch (Exception e) {

         e.printStackTrace();

      }

      FengGUI.setTheme(theme);

   }



   // This portion appears to define the example so that it can be created.

   public void registerExample(final IExample fengGUI_Example,

         Menu examplesMenu, boolean activate) {

      MenuItem item = new MenuItem(fengGUI_Example.getExampleName(),

            examplesMenu.getAppearance());

      examplesMenu.addItem(item);



      item.setEnabled(activate);

      item.addMenuItemPressedListener(new IMenuItemPressedListener() {



         public void menuItemPressed(

               MenuItemPressedEvent menuItemPressedEvent) {

            buildExampleGUIinRenderThread(fengGUI_Example);

         }

      });



   }

}

Bug fix applied to FengJMEInputHandler.  Keyboard input was producing duplicate output characters.  Now only 1 character will display per a key press.  The fix has not yet been applied to the web site repository so please take care.

Excellent, thanks so much for sharing!

erlend_sh said:

Excellent, thanks so much for sharing!


You're welcome.

I did not observe enough popularity with the integration on my own web site to see it worth keeping it there.  All code in this forum thread remains still confirmed as compatible with FengGUI - SVN revision 656 and JME 2 - SVN revision 4657.  As such, I am keeping the integration code separate from my own project.  It will no longer become available on my project's site for now.



Since I've taken an interest in applets, here is the TestIsland class put into the context of SimplePass Applet.  I have split it into two halves to fit the forum space.



[code]
/*
 * Copyright (c) 2003-2009 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package jmetest.awt.applet;

import com.jme.math.Vector3f;
import com.jmex.awt.applet.SimplePassApplet;

import java.nio.FloatBuffer;

import com.jme.image.Texture;
import com.jme.math.Plane;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.pass.RenderPass;
import com.jme.scene.PassNode;
import com.jme.scene.PassNodeState;
import com.jme.scene.Skybox;
import com.jme.scene.Spatial;
import com.jme.scene.Spatial.TextureCombineMode;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FogState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.util.TextureManager;
import com.jmex.effects.water.WaterRenderPass;
import com.jmex.terrain.TerrainPage;
import com.jmex.terrain.util.RawHeightMap;

/********************************************************************************************
 * This test case takes advantage of SimplePassApplet for using the RenderPass way to OpenGL.
 * 
 * @author Modification by Wesley Lange, " shatterblast "
 ********************************************************************************************
 */

public class TestSimplePassApplet extends SimplePassApplet {
   private static final long serialVersionUID = 1L;
   

    private WaterRenderPass waterEffectRenderPass;
    private Quad waterQuad;
    private Spatial splatTerrain;
    private Spatial reflectionTerrain;
    private Skybox skybox;

    private float farPlane = 10000.0f;
    private float textureScale = 0.07f;
    private float globalSplatScale = 90.0f;

   /**
    * sets the desired size of the applet.
    */
   @Override
   public void init() {
      System.setProperty("jme.stats", "set");
      setSize(640, 480);
      super.init();
   }
   /**
    * create a simple Box.
    */
   @Override
    protected void simpleInitGame() {
      display.setTitle("Test Island");

        setupEnvironment();

        createTerrain();
        createReflectionTerrain();

        buildSkyBox();

        rootNode.attachChild(skybox);
        rootNode.attachChild(splatTerrain);

        waterEffectRenderPass = new WaterRenderPass(cam, 6, false, true);
        waterEffectRenderPass.setWaterPlane(new Plane(new Vector3f(0.0f, 1.0f,
                0.0f), 0.0f));
        waterEffectRenderPass.setClipBias(-1.0f);
        waterEffectRenderPass.setReflectionThrottle(0.0f);
        waterEffectRenderPass.setRefractionThrottle(0.0f);

        waterQuad = new Quad("waterQuad", 1, 1);
        FloatBuffer normBuf = waterQuad.getNormalBuffer();
        normBuf.clear();
        normBuf.put(0).put(1).put(0);
        normBuf.put(0).put(1).put(0);
        normBuf.put(0).put(1).put(0);
        normBuf.put(0).put(1).put(0);

        waterEffectRenderPass.setWaterEffectOnSpatial(waterQuad);
        rootNode.attachChild(waterQuad);

        waterEffectRenderPass.setReflectedScene(skybox);
        waterEffectRenderPass.addReflectedScene(reflectionTerrain);
        waterEffectRenderPass.setSkybox(skybox);
        pManager.add(waterEffectRenderPass);

        RenderPass rootPass = new RenderPass();
        rootPass.add(rootNode);
        pManager.add(rootPass);

        // BloomRenderPass bloomRenderPass = new BloomRenderPass(cam, 4);
        // if (!bloomRenderPass.isSupported()) {
        // Text t = new Text("Text", "GLSL Not supported on this computer.");
        // t.setRenderQueueMode(Renderer.QUEUE_ORTHO);
        // t.setLightCombineMode(Spatial.LightCombineMode.Off);
        // t.setLocalTranslation(new Vector3f(0, 20, 0));
        // fpsNode.attachChild(t);
        // } else {
        // bloomRenderPass.setExposurePow(2.0f);
        // bloomRenderPass.setBlurIntensityMultiplier(0.5f);
        //           
        // bloomRenderPass.add(rootNode);
        // bloomRenderPass.setUseCurrentScene(true);
        // pManager.add(bloomRenderPass);
        // }

        RenderPass statPass = new RenderPass();
        statPass.add(statNode);
        pManager.add(statPass);

        rootNode.setCullHint(Spatial.CullHint.Never);
        rootNode.setCullHint(Spatial.CullHint.Never);
    }
[/code]


   
      @Override
   protected void simpleUpdate() {
        skybox.getLocalTranslation().set(cam.getLocation());
        skybox.updateGeometricState(0.0f, true);

        Vector3f transVec = new Vector3f(cam.getLocation().x,
                waterEffectRenderPass.getWaterHeight(), cam.getLocation().z);
        setTextureCoords(0, transVec.x, -transVec.z, textureScale);
        setVertexCoords(transVec.x, transVec.y, transVec.z);
      super.simpleUpdate();
   }
      
      private void createTerrain() {
           RawHeightMap heightMap = new RawHeightMap(TestSimplePassApplet.class
                   .getClassLoader().getResource(
                           "jmetest/data/texture/terrain/heights.raw"),
                   129, RawHeightMap.FORMAT_16BITLE, false);

           Vector3f terrainScale = new Vector3f(5, 0.003f, 6);
           heightMap.setHeightScale(0.001f);
           TerrainPage page = new TerrainPage("Terrain", 33, heightMap.getSize(),
                   terrainScale, heightMap.getHeightMap());
           page.getLocalTranslation().set(0, -9.5f, 0);
           page.setDetailTexture(1, 1);

           // create some interesting texturestates for splatting
           TextureState ts1 = createSplatTextureState(
                   "jmetest/data/texture/terrain/baserock.jpg", null);

           TextureState ts2 = createSplatTextureState(
                   "jmetest/data/texture/terrain/darkrock.jpg",
                   "jmetest/data/texture/terrain/darkrockalpha.png");

           TextureState ts3 = createSplatTextureState(
                   "jmetest/data/texture/terrain/deadgrass.jpg",
                   "jmetest/data/texture/terrain/deadalpha.png");

           TextureState ts4 = createSplatTextureState(
                   "jmetest/data/texture/terrain/nicegrass.jpg",
                   "jmetest/data/texture/terrain/grassalpha.png");

           TextureState ts5 = createSplatTextureState(
                   "jmetest/data/texture/terrain/road.jpg",
                   "jmetest/data/texture/terrain/roadalpha.png");

           TextureState ts6 = createLightmapTextureState("jmetest/data/texture/terrain/lightmap.jpg");

           // alpha used for blending the passnodestates together
           BlendState as = display.getRenderer().createBlendState();
           as.setBlendEnabled(true);
           as.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
           as.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
           as.setTestEnabled(true);
           as.setTestFunction(BlendState.TestFunction.GreaterThan);
           as.setEnabled(true);

           // alpha used for blending the lightmap
           BlendState as2 = display.getRenderer().createBlendState();
           as2.setBlendEnabled(true);
           as2.setSourceFunction(BlendState.SourceFunction.DestinationColor);
           as2.setDestinationFunction(BlendState.DestinationFunction.SourceColor);
           as2.setTestEnabled(true);
           as2.setTestFunction(BlendState.TestFunction.GreaterThan);
           as2.setEnabled(true);

           // //////////////////// PASS STUFF START
           // try out a passnode to use for splatting
           PassNode splattingPassNode = new PassNode("SplatPassNode");
           splattingPassNode.attachChild(page);

           PassNodeState passNodeState = new PassNodeState();
           passNodeState.setPassState(ts1);
           splattingPassNode.addPass(passNodeState);

           passNodeState = new PassNodeState();
           passNodeState.setPassState(ts2);
           passNodeState.setPassState(as);
           splattingPassNode.addPass(passNodeState);

           passNodeState = new PassNodeState();
           passNodeState.setPassState(ts3);
           passNodeState.setPassState(as);
           splattingPassNode.addPass(passNodeState);

           passNodeState = new PassNodeState();
           passNodeState.setPassState(ts4);
           passNodeState.setPassState(as);
           splattingPassNode.addPass(passNodeState);

           passNodeState = new PassNodeState();
           passNodeState.setPassState(ts5);
           passNodeState.setPassState(as);
           splattingPassNode.addPass(passNodeState);

           passNodeState = new PassNodeState();
           passNodeState.setPassState(ts6);
           passNodeState.setPassState(as2);
           splattingPassNode.addPass(passNodeState);
           // //////////////////// PASS STUFF END

           // lock some things to increase the performance
           splattingPassNode.lockBounds();
           splattingPassNode.lockTransforms();
           splattingPassNode.lockShadows();

           splatTerrain = splattingPassNode;
           splatTerrain.setCullHint(Spatial.CullHint.Dynamic);

       }
      
      private void createReflectionTerrain() {
           RawHeightMap heightMap = new RawHeightMap(TestSimplePassApplet.class
                   .getClassLoader().getResource(
                           "jmetest/data/texture/terrain/heights.raw"),
                   129, RawHeightMap.FORMAT_16BITLE, false);

           Vector3f terrainScale = new Vector3f(5, 0.003f, 6);
           heightMap.setHeightScale(0.001f);
           TerrainPage page = new TerrainPage("Terrain", 33, heightMap.getSize(),
                   terrainScale, heightMap.getHeightMap());
           page.getLocalTranslation().set(0, -9.5f, 0);
           page.setDetailTexture(1, 1);

           // create some interesting texturestates for splatting
           TextureState ts1 = display.getRenderer().createTextureState();
           Texture t0 = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(
                           "jmetest/data/texture/terrain/terrainlod.jpg"),
                   Texture.MinificationFilter.Trilinear,
                   Texture.MagnificationFilter.Bilinear);
           t0.setWrap(Texture.WrapMode.Repeat);
           t0.setApply(Texture.ApplyMode.Modulate);
           t0.setScale(new Vector3f(1.0f, 1.0f, 1.0f));
           ts1.setTexture(t0, 0);

           // //////////////////// PASS STUFF START
           // try out a passnode to use for splatting
           PassNode splattingPassNode = new PassNode("SplatPassNode");
           splattingPassNode.attachChild(page);

           PassNodeState passNodeState = new PassNodeState();
           passNodeState.setPassState(ts1);
           splattingPassNode.addPass(passNodeState);
           // //////////////////// PASS STUFF END

           // lock some things to increase the performance
           splattingPassNode.lockBounds();
           splattingPassNode.lockTransforms();
           splattingPassNode.lockShadows();

           reflectionTerrain = splattingPassNode;

           initSpatial(reflectionTerrain);
       }
      
      private void setupEnvironment() {
           cam.setFrustumPerspective(45.0f, (float) display.getWidth()
                   / (float) display.getHeight(), 1f, farPlane);
           cam.setLocation(new Vector3f(-320, 80, -270));
           cam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
           cam.update();

           CullState cs = display.getRenderer().createCullState();
           cs.setCullFace(CullState.Face.Back);
           rootNode.setRenderState(cs);

           lightState.detachAll();
           rootNode.setLightCombineMode(Spatial.LightCombineMode.Off);

           FogState fogState = display.getRenderer().createFogState();
           fogState.setDensity(1.0f);
           fogState.setEnabled(true);
           fogState.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
           fogState.setEnd(farPlane);
           fogState.setStart(farPlane / 10.0f);
           fogState.setDensityFunction(FogState.DensityFunction.Linear);
           fogState.setQuality(FogState.Quality.PerVertex);
           rootNode.setRenderState(fogState);
       }
      
      private void addAlphaSplat(TextureState ts, String alpha) {
           Texture t1 = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(alpha),
                   Texture.MinificationFilter.Trilinear,
                   Texture.MagnificationFilter.Bilinear);
           t1.setWrap(Texture.WrapMode.Repeat);
           t1.setApply(Texture.ApplyMode.Combine);
           t1.setCombineFuncRGB(Texture.CombinerFunctionRGB.Replace);
           t1.setCombineSrc0RGB(Texture.CombinerSource.Previous);
           t1.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
           t1.setCombineFuncAlpha(Texture.CombinerFunctionAlpha.Replace);
           ts.setTexture(t1, ts.getNumberOfSetTextures());
       }
      
      private TextureState createSplatTextureState(String texture, String alpha) {
           TextureState ts = display.getRenderer().createTextureState();

           Texture t0 = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(texture),
                   Texture.MinificationFilter.Trilinear,
                   Texture.MagnificationFilter.Bilinear);
           t0.setWrap(Texture.WrapMode.Repeat);
           t0.setApply(Texture.ApplyMode.Modulate);
           t0.setScale(new Vector3f(globalSplatScale, globalSplatScale, 1.0f));
           ts.setTexture(t0, 0);

           if (alpha != null) {
               addAlphaSplat(ts, alpha);
           }

           return ts;
       }
      
      private TextureState createLightmapTextureState(String texture) {
           TextureState ts = display.getRenderer().createTextureState();

           Texture t0 = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(texture),
                   Texture.MinificationFilter.Trilinear,
                   Texture.MagnificationFilter.Bilinear);
           t0.setWrap(Texture.WrapMode.Repeat);
           ts.setTexture(t0, 0);

           return ts;
       }
      
      private void buildSkyBox() {
           skybox = new Skybox("skybox", 10, 10, 10);

           String dir = "jmetest/data/skybox1/";
           Texture north = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(dir + "1.jpg"),
                   Texture.MinificationFilter.BilinearNearestMipMap,
                   Texture.MagnificationFilter.Bilinear);
           Texture south = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(dir + "3.jpg"),
                   Texture.MinificationFilter.BilinearNearestMipMap,
                   Texture.MagnificationFilter.Bilinear);
           Texture east = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(dir + "2.jpg"),
                   Texture.MinificationFilter.BilinearNearestMipMap,
                   Texture.MagnificationFilter.Bilinear);
           Texture west = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(dir + "4.jpg"),
                   Texture.MinificationFilter.BilinearNearestMipMap,
                   Texture.MagnificationFilter.Bilinear);
           Texture up = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(dir + "6.jpg"),
                   Texture.MinificationFilter.BilinearNearestMipMap,
                   Texture.MagnificationFilter.Bilinear);
           Texture down = TextureManager.loadTexture(TestSimplePassApplet.class
                   .getClassLoader().getResource(dir + "5.jpg"),
                   Texture.MinificationFilter.BilinearNearestMipMap,
                   Texture.MagnificationFilter.Bilinear);

           skybox.setTexture(Skybox.Face.North, north);
           skybox.setTexture(Skybox.Face.West, west);
           skybox.setTexture(Skybox.Face.South, south);
           skybox.setTexture(Skybox.Face.East, east);
           skybox.setTexture(Skybox.Face.Up, up);
           skybox.setTexture(Skybox.Face.Down, down);
           skybox.preloadTextures();

           CullState cullState = display.getRenderer().createCullState();
           cullState.setCullFace(CullState.Face.None);
           cullState.setEnabled(true);
           skybox.setRenderState(cullState);

           ZBufferState zState = display.getRenderer().createZBufferState();
           zState.setEnabled(false);
           skybox.setRenderState(zState);

           FogState fs = display.getRenderer().createFogState();
           fs.setEnabled(false);
           skybox.setRenderState(fs);

           skybox.setLightCombineMode(Spatial.LightCombineMode.Off);
           skybox.setCullHint(Spatial.CullHint.Never);
           skybox.setTextureCombineMode(TextureCombineMode.Replace);
           skybox.updateRenderState();

           skybox.lockBounds();
           skybox.lockMeshes();
       }
      
       private void setVertexCoords(float x, float y, float z) {
           FloatBuffer vertBuf = waterQuad.getVertexBuffer();
           vertBuf.clear();

           vertBuf.put(x - farPlane).put(y).put(z - farPlane);
           vertBuf.put(x - farPlane).put(y).put(z + farPlane);
           vertBuf.put(x + farPlane).put(y).put(z + farPlane);
           vertBuf.put(x + farPlane).put(y).put(z - farPlane);
       }
       
       private void setTextureCoords(int buffer, float x, float y,
               float textureScale) {
           x *= textureScale * 0.5f;
           y *= textureScale * 0.5f;
           textureScale = farPlane * textureScale;
           FloatBuffer texBuf;
           texBuf = waterQuad.getTextureCoords(buffer).coords;
           texBuf.clear();
           texBuf.put(x).put(textureScale + y);
           texBuf.put(x).put(y);
           texBuf.put(textureScale + x).put(y);
           texBuf.put(textureScale + x).put(textureScale + y);
       }
       
       private void initSpatial(Spatial spatial) {
           ZBufferState buf = display.getRenderer().createZBufferState();
           buf.setEnabled(true);
           buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
           spatial.setRenderState(buf);

           CullState cs = display.getRenderer().createCullState();
           cs.setCullFace(CullState.Face.Back);
           spatial.setRenderState(cs);

           spatial.setCullHint(Spatial.CullHint.Never);

           spatial.updateGeometricState(0.0f, true);
           spatial.updateRenderState();
       }
}



Download the attached file for the purpose of convenience if it helps you.  It is the same code.
shatterblast said:

JOGL has been untested, but my previous session produced a "missing mouse" error.

Is it fixed?