org.rifidi.designer.rcp.game.DesignerGame.java Source code

Java tutorial

Introduction

Here is the source code for org.rifidi.designer.rcp.game.DesignerGame.java

Source

/*
 *  DesignerGame.java
 *
 *  Project:      RiFidi Designer - A Virtualization tool for 3D RFID environments
 *  http://www.rifidi.org
 *  http://rifidi.sourceforge.net
 *  Copyright:       Pramari LLC and the Rifidi Project
 *  License:      Lesser GNU Public License (LGPL)
 *  http://www.opensource.org/licenses/lgpl-license.html
 */
package org.rifidi.designer.rcp.game;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.lwjgl.opengl.EXTFramebufferObject;
import org.monklypse.core.SWTDefaultImplementor;
import org.monklypse.core.renderer.LWJGLOffscreenRenderer;
import org.monklypse.core.renderer.OffscreenRenderer;
import org.rifidi.designer.entities.Entity;
import org.rifidi.designer.entities.SceneData;
import org.rifidi.designer.entities.VisualEntity;
import org.rifidi.designer.rcp.GlobalProperties;
import org.rifidi.designer.rcp.views.minimapview.MiniMapView;
import org.rifidi.designer.services.core.collision.FieldService;
import org.rifidi.designer.services.core.entities.EntitiesServiceImpl;
import org.rifidi.designer.services.core.entities.SceneDataChangedListener;
import org.rifidi.designer.services.core.entities.SceneDataService;
import org.rifidi.designer.services.core.highlighting.HighlightingService;
import org.rifidi.designer.services.core.selection.SelectionService;
import org.rifidi.designer.services.core.world.CommandStateService;
import org.rifidi.designer.services.core.world.RepeatedUpdateAction;
import org.rifidi.designer.services.core.world.WorldService;
import org.rifidi.designer.services.core.world.WorldStates;
import org.rifidi.services.annotations.Inject;
import org.rifidi.services.registry.ServiceRegistry;
import org.rifidi.utilities.grid.GridNode;

import com.jme.bounding.BoundingBox;
import com.jme.light.DirectionalLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.renderer.lwjgl.LWJGLRenderer;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FragmentProgramState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.util.geom.Debugger;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameStateManager;
import com.jmex.physics.PhysicsDebugger;
import com.jmex.swt.lwjgl.LWJGLSWTCanvas;

/**
 * FIXME: Class comment.
 * 
 * @author Jochen Mader - jochen@pramari.com - May 28, 2008
 * 
 */
public class DesignerGame extends SWTDefaultImplementor implements SceneDataChangedListener,
        ISelectionChangedListener, KeyListener, WorldService, CommandStateService, HighlightingService {

    private static final Log logger = LogFactory.getLog(DesignerGame.class);
    /** Wall transparency. TODO redo trans stuff */
    private BlendState wallAlpha;
    /** Zbuffer for the rootnode. */
    private ZBufferState zbufferState;
    /** The primary lightstate. */
    private LightState ls;
    /** Currently used scenedata. */
    private SceneData sceneData;
    /** Reference to the scenedataservice. */
    private SceneDataService sceneDataService;
    /** Offscreenrenderer for the minimap. */
    private OffscreenRenderer offy;
    /** Reference to the minimap. */
    private MiniMapView miniMapView;
    /** Display minimap every nth frame. */
    private int minimapCounter = 10;
    /** ImageData for the minimap. */
    private ImageData imgData;
    /** Alpha state used for highlighting. */
    private BlendState alphaState;
    /** Fragment program used for highlighting. */
    private String fragprog = "!!ARBfp1.0" + "MOV result.color, program.local[0];"
            + "MOV result.color.a, program.local[1].a;" + "END";
    /** Action submitted to the update thread for updating the highlight state. */
    private HilitedRepeatedUpdateAction repeater;
    /** Map of highlighted entities with the highlighting color as the key. */
    private Map<ColorRGBA, List<VisualEntity>> hilited;
    /** Map of fragment programs by their color. */
    private Map<ColorRGBA, FragmentProgramState> fragmentPrograms;
    /** Reference to the field service. */
    private FieldService fieldService;
    /** The current state of the world. */
    private WorldStates worldState;
    /** Maps WorldStates to command names. */
    private Map<WorldStates, List<String>> stateMap;
    /** Boolean indicators for camera directional motion */
    private boolean[] updownleftright = new boolean[4];

    /** Scene related stuff. */

    private boolean gridEnabled = false;
    /** Node for the grid. */
    private GridNode gridNode;
    /** Grid game state. */
    private BasicGameState gridState;
    /**
     * List that contains all the spatials that should be rendered by the
     * offscreen renderer.
     */
    private List<Spatial> offscreenRenderSpatials;
    /** LOD of the main camera. */
    private int sceneLOD;
    /** Cursors for the canvas. */
    private Cursor invisibleCursor, defaultCursor;

    /**
     * @param name
     * @param width
     * @param height
     */
    public DesignerGame(String name, int width, int height) {
        super(width, height);

        hilited = new HashMap<ColorRGBA, List<VisualEntity>>();
        hilited.put(ColorRGBA.blue, new ArrayList<VisualEntity>());
        fragmentPrograms = new HashMap<ColorRGBA, FragmentProgramState>();

        logger.debug("WorldService created");
        worldState = WorldStates.NoSceneDataLoaded;
        stateMap = new HashMap<WorldStates, List<String>>();
        stateMap.put(WorldStates.NoSceneDataLoaded, new ArrayList<String>());
        stateMap.get(WorldStates.NoSceneDataLoaded).add("newscene");
        stateMap.put(WorldStates.Paused, new ArrayList<String>());
        stateMap.get(WorldStates.Paused).add("newscene");
        stateMap.get(WorldStates.Paused).add("saveas");
        stateMap.get(WorldStates.Paused).add("save");
        stateMap.get(WorldStates.Paused).add("start");
        stateMap.get(WorldStates.Paused).add("stop");
        stateMap.put(WorldStates.Stopped, new ArrayList<String>());
        stateMap.get(WorldStates.Stopped).add("newscene");
        stateMap.get(WorldStates.Stopped).add("saveas");
        stateMap.get(WorldStates.Stopped).add("save");
        stateMap.get(WorldStates.Stopped).add("start");
        stateMap.put(WorldStates.Running, new ArrayList<String>());
        stateMap.get(WorldStates.Running).add("newscene");
        stateMap.get(WorldStates.Running).add("saveas");
        stateMap.get(WorldStates.Running).add("save");
        stateMap.get(WorldStates.Running).add("stop");
        stateMap.get(WorldStates.Running).add("pause");
        ServiceRegistry.getInstance().service(this);
        offscreenRenderSpatials = new ArrayList<Spatial>();
    }

    /**
     * Overwritten to enable LOD.
     */

    /*
     * (non-Javadoc)
     * 
     * @see org.monklypse.core.SWTDefaultImplementor#doRender()
     */
    @Override
    public void doRender() {
        if (sceneLOD != ((ZoomableLWJGLCamera) getCamera()).getLod()) {
            if (sceneDataService.getCurrentSceneData() != null) {
                sceneLOD = ((ZoomableLWJGLCamera) getCamera()).getLod();
                for (Entity entity : sceneDataService.getCurrentSceneData().getEntities()) {
                    if (entity instanceof VisualEntity) {
                        ((VisualEntity) entity).setLOD(sceneLOD);
                    }
                }
            }
        }
        super.doRender();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.monklypse.core.SWTDefaultImplementor#simpleRender()
     */
    // TODO: remove!!
    private Node bu = null;

    @Override
    public void simpleRender() {
        if (sceneData != null && !getCanvas().isDisposed() && sceneData.getRootNode().getParent() != null) {
            GameStateManager.getInstance().render(0);
            if (GlobalProperties.physicsDebugging) {
                PhysicsDebugger.drawPhysics(sceneData.getPhysicsSpace(), getRenderer());
            }
            if (GlobalProperties.boundingDebugging) {
                if (bu == null) {
                    bu = ((EntitiesServiceImpl) sceneDataService).getRoomOctree().getTreeAsNode();
                }
                Debugger.drawBounds(bu, getRenderer());
                Debugger.drawBounds(sceneData.getRootNode(), getRenderer());
            }
            getRenderer().displayBackBuffer();
            // getCanvas().swapBuffers();
            if (miniMapView == null) {
                miniMapView = (MiniMapView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
                        .findView(MiniMapView.ID);
            }
            if (offy.isSupported() && miniMapView != null && minimapCounter == 10) {
                miniMapView.setMapCamera(offy.getCamera());
                minimapCounter = 0;
                sceneLOD = 3;
                for (Entity entity : sceneDataService.getCurrentSceneData().getEntities()) {
                    if (entity instanceof VisualEntity) {
                        ((VisualEntity) entity).setLOD(sceneLOD);
                    }
                }
                offscreenRenderSpatials.clear();
                offy.render(sceneData.getRootNode());
                IntBuffer buffer = offy.getImageData();
                if (imgData == null) {
                    imgData = new ImageData(200, 200, 32, new PaletteData(0xFF0000, 0x00FF00, 0x0000FF));
                }
                for (int y = 0; y < 200; y++) {
                    for (int x = 0; x < 200; x++) {
                        imgData.setPixel(x, y, buffer.get((199 - y) * 200 + x));
                    }
                }
                miniMapView.setImage(imgData, 20);
            }
            minimapCounter++;

        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.monklypse.core.SWTDefaultImplementor#simpleSetup()
     */
    @Override
    public void simpleSetup() {
        setCamera(new ZoomableLWJGLCamera(this, 754, 584));
        getCanvas().addKeyListener(this);
        // clear keylist if the canvas loses the focus
        getCanvas().addFocusListener(new FocusListener() {

            /*
             * (non-Javadoc)
             * 
             * @see
             * org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.
             * swt.events.FocusEvent)
             */
            @Override
            public void focusGained(FocusEvent e) {
            }

            /*
             * (non-Javadoc)
             * 
             * @see
             * org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt
             * .events.FocusEvent)
             */
            @Override
            public void focusLost(FocusEvent e) {
                updownleftright[0] = false;
                updownleftright[1] = false;
                updownleftright[2] = false;
                updownleftright[3] = false;
            }

        });

        offy = new LWJGLOffscreenRenderer(200, 200, (LWJGLRenderer) getRenderer());
        if (offy.isSupported()) {
            EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
        } else {
            logger.debug("Offscreen rendering is not supported!");
        }

        GameStateManager.create();
        // alphastate for transparent walls
        wallAlpha = DisplaySystem.getDisplaySystem().getRenderer().createBlendState();
        wallAlpha.setBlendEnabled(true);
        wallAlpha.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
        wallAlpha.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
        wallAlpha.setEnabled(true);
        // create ZBuffer stuff
        zbufferState = DisplaySystem.getDisplaySystem().getRenderer().createZBufferState();
        zbufferState.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
        zbufferState.setEnabled(true);

        // create cullstate for backface culling
        CullState cullState = DisplaySystem.getDisplaySystem().getRenderer().createCullState();
        cullState.setCullFace(CullState.Face.Back);

        // create alpha state for highlighting
        alphaState = DisplaySystem.getDisplaySystem().getRenderer().createBlendState();
        alphaState.setBlendEnabled(true);
        alphaState.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
        alphaState.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
        alphaState.setEnabled(true);

        fragmentPrograms.put(ColorRGBA.blue, createNewFragmentProgramState(ColorRGBA.blue));

        repeater = new HilitedRepeatedUpdateAction();

        // create a default light
        ls = DisplaySystem.getDisplaySystem().getRenderer().createLightState();
        ls.setTwoSidedLighting(false);
        ls.setEnabled(true);

        DirectionalLight light = new DirectionalLight();
        light.setAmbient(new ColorRGBA(1f, 1f, 1f, 0f));
        light.setEnabled(true);
        ls.attach(light);

        light = new DirectionalLight();
        light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 0f));
        light.setAmbient(new ColorRGBA(0f, 0f, 0f, 0f));
        light.setDirection(new Vector3f(0, -1, 0));
        light.setEnabled(true);
        ls.attach(light);

        light = new DirectionalLight();
        light.setDiffuse(new ColorRGBA(.4f, .4f, .4f, 0f));
        light.setAmbient(new ColorRGBA(0f, 0f, 0f, 0f));
        light.setDirection(new Vector3f(1, 0, 0));
        light.setEnabled(true);
        ls.attach(light);

        // light = new DirectionalLight();
        // light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 0f));
        // light.setAmbient(new ColorRGBA(0f, 0f, 0f, 0f));
        // light.setDirection(new Vector3f(0, 0, 1));
        // light.setEnabled(true);
        // ls.attach(light);

        InputStream arb = this.getClass().getClassLoader()
                .getResourceAsStream("/org/rifidi/designer/rcp/game/phong.arb");
        BufferedReader br = new BufferedReader(new InputStreamReader(arb));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try {
            while ((line = br.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        getRenderer().setBackgroundColor(ColorRGBA.gray.clone());
        // FragmentProgramState
        // phong=display.getRenderer().createFragmentProgramState();
        // phong.load(sb.toString());
        // phong.setParameter(new float[]{.5f,.5f,.5f,.5f}, 0);
        // phong.setParameter(new float[]{1f,1f,1f,1f}, 1);
        // phong.setEnabled(true);
        getRootNode().setRenderState(zbufferState);
        getRootNode().setRenderState(cullState);
        getRootNode().setRenderState(ls);
        getRootNode().updateRenderState();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.monklypse.core.SWTDefaultImplementor#simpleUpdate()
     */
    @Override
    public void simpleUpdate() {
        if (sceneData != null) {
            performCameraMotion();
            GameStateManager.getInstance().update(tpf);
            sceneData.getRootNode().updateGeometricState(tpf, true);
            if (WorldStates.Running.equals(worldState)) {
                sceneData.getCollisionHandler().update(tpf);
                sceneData.getPhysicsSpace().update(tpf);
                fieldService.checkFields();
            }
            repeater.doUpdate(tpf);
        }
    }

    private FragmentProgramState createNewFragmentProgramState(ColorRGBA color) {
        // create fragment program state for highlighting
        FragmentProgramState fragmentProgramState = DisplaySystem.getDisplaySystem().getRenderer()
                .createFragmentProgramState();
        fragmentProgramState.load(fragprog);
        fragmentProgramState.setEnabled(true);
        float[] color4f = new float[] { color.r, color.g, color.b, 0f };
        fragmentProgramState.setParameter(color4f, 0);
        return fragmentProgramState;
    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.rifidi.designer.services.core.entities.SceneDataChangedListener#
     * destroySceneData(org.rifidi.designer.entities.SceneData)
     */
    @Override
    public void destroySceneData(SceneData sceneData) {
        update(new Callable<Object>() {

            /*
             * (non-Javadoc)
             * 
             * @see java.util.concurrent.Callable#call()
             */
            @Override
            public Object call() throws Exception {
                getRootNode().detachAllChildren();
                return null;
            }

        });
    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.rifidi.designer.services.core.entities.SceneDataChangedListener#
     * sceneDataChanged(org.rifidi.designer.entities.SceneData)
     */
    @Override
    public void sceneDataChanged(SceneData sceneDataNew) {
        this.sceneData = sceneDataNew;
        worldState = WorldStates.Paused;
        update(new Callable<Object>() {

            /*
             * (non-Javadoc)
             * 
             * @see java.util.concurrent.Callable#call()
             */
            @Override
            public Object call() throws Exception {
                sceneData.getRootNode().attachChild(sceneData.getRoomNode());
                sceneData.getRootNode().setName("rootnode");
                sceneData.getRoomNode().setName("roomnode");
                getRootNode().attachChild(sceneData.getRootNode());
                // adjust main camera
                getCamera().setLocation(
                        new Vector3f((int) (((BoundingBox) sceneData.getRoomNode().getWorldBound()).xExtent / 2), 2,
                                (int) ((BoundingBox) sceneData.getRoomNode().getWorldBound()).zExtent / 2));
                getCamera().getLocation().addLocal(new Vector3f(-5, 0, -15));
                ((ZoomableLWJGLCamera) getCamera()).adjustLOD();
                getCamera().update();
                // adjust minimpa camera
                if (offy.isSupported()) {
                    offy.setBackgroundColor(new ColorRGBA(.667f, .667f, .851f, 1f));
                    offy.getCamera().setLocation(
                            new Vector3f(((BoundingBox) sceneData.getRoomNode().getWorldBound()).xExtent, 2,
                                    ((BoundingBox) sceneData.getRoomNode().getWorldBound()).zExtent));
                    offy.getCamera().setParallelProjection(true);

                    offy.getCamera().setAxes(new Vector3f(-1, 0, 0), new Vector3f(0, 0, -1),
                            new Vector3f(0, -1, 0));

                    float ratio = ((BoundingBox) sceneData.getRoomNode().getWorldBound()).xExtent
                            / ((BoundingBox) sceneData.getRoomNode().getWorldBound()).zExtent;
                    float sidelength = 0;
                    if (ratio > 1) {
                        sidelength = ((BoundingBox) sceneData.getRoomNode().getWorldBound()).xExtent;
                    } else {
                        sidelength = ((BoundingBox) sceneData.getRoomNode().getWorldBound()).zExtent;
                    }
                    offy.getCamera().setFrustum(-100.0f, 1000.0f, -.6f * sidelength * 2, .6f * sidelength * 2,
                            -.6f * sidelength * 2, .6f * sidelength * 2);

                    offy.getCamera().update();
                    offy.getCamera().apply();
                }
                createGrid();
                getRootNode().updateRenderState();
                return null;
            }

        });
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(
     * org.eclipse.jface.viewers.SelectionChangedEvent)
     */
    @SuppressWarnings("unchecked")
    @Override
    public void selectionChanged(SelectionChangedEvent event) {
        Set<VisualEntity> newHighlights = new HashSet<VisualEntity>();
        Set<VisualEntity> unlit = new HashSet<VisualEntity>();
        Iterator<VisualEntity> iter = ((IStructuredSelection) event.getSelection()).iterator();
        while (iter.hasNext()) {
            VisualEntity entity = iter.next();
            hilited.get(ColorRGBA.blue).add(entity);
            newHighlights.add(entity);
        }
        changeHighlighting(ColorRGBA.blue, newHighlights);
        hilited.get(ColorRGBA.blue).removeAll(unlit);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.
     * KeyEvent)
     */
    public void keyPressed(KeyEvent e) {
        if (e.character == 'a' || e.character == 'A' || e.keyCode == SWT.ARROW_LEFT) {
            updownleftright[2] = true;
        } else if (e.character == 'd' || e.character == 'D' || e.keyCode == SWT.ARROW_RIGHT) {
            updownleftright[3] = true;
        } else if (e.character == 'w' || e.character == 'W' || e.keyCode == SWT.ARROW_UP) {
            updownleftright[0] = true;
        } else if (e.character == 's' || e.character == 'S' || e.keyCode == SWT.ARROW_DOWN) {
            updownleftright[1] = true;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events
     * .KeyEvent)
     */
    public void keyReleased(KeyEvent e) {
        updownleftright[0] = false;
        updownleftright[1] = false;
        updownleftright[2] = false;
        updownleftright[3] = false;
    }

    /**
     * Reposition the camera if any motion keys are held down.
     */
    public void performCameraMotion() {
        ZoomableLWJGLCamera cam = (ZoomableLWJGLCamera) DisplaySystem.getDisplaySystem().getRenderer().getCamera();
        float keyspeed = 0.9f + (cam.getZoomlevel() / 20);
        if (updownleftright[2]) {
            cam.setLocation(cam.getLocation().add(new Vector3f(-keyspeed, 0, 0)));
        }
        if (updownleftright[3]) {
            cam.setLocation(cam.getLocation().add(new Vector3f(keyspeed, 0, 0)));
        }
        if (updownleftright[0]) {
            cam.setLocation(cam.getLocation().add(new Vector3f(0, 0, -keyspeed)));
        }
        if (updownleftright[1]) {
            cam.setLocation(cam.getLocation().add(new Vector3f(0, 0, keyspeed)));
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.services.registry.core.world.WorldService#pause()
     */
    @Override
    public void pause() {
        if (sceneData != null) {
            for (Entity entity : sceneData.getSearchableEntities()) {
                entity.pause();
            }
            worldState = WorldStates.Paused;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.services.registry.core.world.WorldService#run()
     */
    @Override
    public void run() {
        for (Entity entity : sceneData.getSearchableEntities()) {
            entity.start();
        }
        worldState = WorldStates.Running;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.rifidi.services.registry.core.world.WorldService#stop()
     */
    @Override
    public void stop() {
        update(new Callable<Object>() {

            /*
             * (non-Javadoc)
             * 
             * @see java.util.concurrent.Callable#call()
             */
            public Object call() throws Exception {
                synchronized (sceneData.getSyncedEntities()) {
                    for (Entity entity : new ArrayList<Entity>(sceneData.getSyncedEntities())) {
                        entity.reset();
                    }
                }
                return new Object();
            }

        });
        worldState = WorldStates.Stopped;
    }

    public void toggleGrid() {
        if (gridEnabled) {
            gridState.setActive(false);
            gridEnabled = false;
        } else {
            gridState.setActive(true);
            gridEnabled = true;
        }
    }

    /**
     * Creates the grid for displaying.
     */
    private void createGrid() {
        if (gridState != null) {
            GameStateManager.getInstance().detachChild(gridState);
        }
        // create the grid
        logger.debug("creating grid");
        int gridX = (int) ((BoundingBox) sceneDataService.getCurrentSceneData().getRoomNode()
                .getWorldBound()).xExtent * 2;
        int gridZ = (int) ((BoundingBox) sceneDataService.getCurrentSceneData().getRoomNode()
                .getWorldBound()).zExtent * 2;
        // one grid is 1 unit!!!
        gridX = Math.floor(((BoundingBox) sceneDataService.getCurrentSceneData().getRoomNode()
                .getWorldBound()).xExtent) < ((BoundingBox) sceneDataService.getCurrentSceneData().getRoomNode()
                        .getWorldBound()).xExtent ? gridX + 1 : gridX;
        gridZ = Math.floor(((BoundingBox) sceneDataService.getCurrentSceneData().getRoomNode()
                .getWorldBound()).zExtent) < ((BoundingBox) sceneDataService.getCurrentSceneData().getRoomNode()
                        .getWorldBound()).zExtent ? gridZ + 1 : gridZ;
        GridNode grid = new GridNode("griddy", gridX, gridZ, .1f);
        grid.setLocalTranslation(
                ((BoundingBox) sceneDataService.getCurrentSceneData().getRoomNode().getWorldBound()).getCenter().x,
                0.01f,
                ((BoundingBox) sceneDataService.getCurrentSceneData().getRoomNode().getWorldBound()).getCenter().z);

        MaterialState ms = DisplaySystem.getDisplaySystem().getRenderer().createMaterialState();
        ms.setDiffuse(new ColorRGBA(0.345f, 0.639f, 0.901f, 1.0f));
        grid.setRenderState(ms);

        gridNode = grid;
        gridState = new BasicGameState("GridState");
        gridState.getRootNode().attachChild(grid);
        gridState.setActive(true);
        gridNode.updateRenderState();
        gridNode.updateGeometricState(0, true);
        GameStateManager.getInstance().attachChild(gridState);
        gridEnabled = !gridEnabled;
        toggleGrid();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rifidi.services.registry.core.world.CommandStateService#isEnabled
     * (java.lang.String)
     */
    @Override
    public boolean isEnabled(String commandName) {
        return stateMap.get(worldState).contains(commandName);
    }

    /**
     * @param sceneDataService
     *            the sceneDataService to set
     */
    @Inject
    public void setSceneDataService(SceneDataService sceneDataService) {
        this.sceneDataService = sceneDataService;
        sceneDataService.addSceneDataChangedListener(this);
    }

    /**
     * @param selectionService
     *            the selectionService to set
     */
    @Inject
    public void setSelectionService(SelectionService selectionService) {
        selectionService.addSelectionChangedListener(this);
    }

    /**
     * @param fieldService
     *            the fieldService to set
     */
    @Inject
    public void setFieldService(FieldService fieldService) {
        this.fieldService = fieldService;
    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.rifidi.designer.services.core.highlighting.HighlightingService#
     * changeHighlighting(com.jme.renderer.ColorRGBA, java.util.Set)
     */
    @Override
    public void changeHighlighting(ColorRGBA color, Set<VisualEntity> highlight) {
        if (!fragmentPrograms.containsKey(color)) {
            fragmentPrograms.put(color, createNewFragmentProgramState(color));
            hilited.put(color, new ArrayList<VisualEntity>());
        }
        ArrayList<VisualEntity> unlit = new ArrayList<VisualEntity>();
        for (VisualEntity entity : hilited.get(color)) {
            if (!highlight.contains(entity)) {
                unlit.add(entity);
            }
        }
        hilited.get(color).clear();
        hilited.get(color).addAll(highlight);

        for (VisualEntity entity : highlight) {
            Node hilit = entity.getBoundingNode();
            // for those who forget to add the bounding volume
            if (hilit != null) {
                hilit.setCullHint(Spatial.CullHint.Dynamic);
                if (hilit.getChild("hiliter") != null) {
                    Spatial hilite = (Spatial) hilit.getChild("hiliter");
                    hilite.setRenderState(fragmentPrograms.get(color));
                    hilite.setRenderState(alphaState);
                    hilite.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
                } else {
                    hilit.setRenderState(fragmentPrograms.get(color));
                    hilit.setRenderState(alphaState);
                    hilit.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
                }
                hilit.updateRenderState();
            }
        }
        for (VisualEntity entity : unlit) {
            Node hilit = entity.getBoundingNode();
            // for those who forget to add the bounding volume
            if (hilit != null) {
                hilit.setCullHint(Spatial.CullHint.Always);
                if (hilit.getChild("hiliter") != null) {
                    Spatial hilite = (Spatial) hilit.getChild("hiliter");
                    hilite.clearRenderState(RenderState.RS_FRAGMENT_PROGRAM);
                } else {
                    hilit.clearRenderState(RenderState.RS_FRAGMENT_PROGRAM);
                }
                hilit.updateRenderState();
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.rifidi.designer.services.core.highlighting.HighlightingService#
     * changeHighlightColor(com.jme.renderer.ColorRGBA,
     * com.jme.renderer.ColorRGBA, java.util.Set)
     */
    @Override
    public void changeHighlightColor(ColorRGBA color, ColorRGBA newcolor, Set<VisualEntity> hilight) {
        hilited.get(color).removeAll(hilight);
        if (!fragmentPrograms.containsKey(newcolor)) {
            fragmentPrograms.put(newcolor, createNewFragmentProgramState(newcolor));
            hilited.put(newcolor, new ArrayList<VisualEntity>());
        }
        hilited.get(newcolor).addAll(hilight);
        for (VisualEntity target : hilight) {
            Node hilit = target.getBoundingNode();
            if (hilit.getChild("hiliter") != null) {
                Spatial hilite = (Spatial) hilit.getChild("hiliter");
                hilite.clearRenderState(RenderState.RS_FRAGMENT_PROGRAM);
                hilite.clearRenderState(RenderState.RS_FRAGMENT_PROGRAM);
                hilite.setRenderState(fragmentPrograms.get(newcolor));
            } else {
                hilit.clearRenderState(RenderState.RS_FRAGMENT_PROGRAM);
                hilit.clearRenderState(RenderState.RS_FRAGMENT_PROGRAM);
                hilit.setRenderState(fragmentPrograms.get(newcolor));
            }
            hilit.updateRenderState();
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.rifidi.designer.services.core.highlighting.HighlightingService#
     * clearAllHighlights()
     */
    @Override
    public void clearAllHighlights() {
        // TODO Auto-generated method stub

    }

    /*
     * (non-Javadoc)
     * 
     * @seeorg.rifidi.designer.services.core.highlighting.HighlightingService#
     * clearHighlights(java.util.Set)
     */
    @Override
    public void clearHighlights(Set<VisualEntity> hilight) {
        for (ColorRGBA color : hilited.keySet()) {
            for (VisualEntity target : hilight) {
                Node hilit = target.getBoundingNode();
                hilit.setCullHint(Spatial.CullHint.Always);
                if (hilit.getChild("hiliter") != null) {
                    Spatial hilite = (Spatial) hilit.getChild("hiliter");
                    hilite.clearRenderState(RenderState.RS_FRAGMENT_PROGRAM);
                    hilite.clearRenderState(RenderState.RS_FRAGMENT_PROGRAM);
                } else {
                    hilit.clearRenderState(RenderState.RS_FRAGMENT_PROGRAM);
                }
                hilit.updateRenderState();
            }

            hilited.get(color).removeAll(hilight);
        }
    }

    /**
     * Set the LOD for the scene. Can be undone using resetLOD.
     * 
     * @param lod
     */
    public void setLOD(int lod) {
        if (sceneDataService.getCurrentSceneData() != null) {
            for (Entity entity : sceneDataService.getCurrentSceneData().getEntities()) {
                if (entity instanceof VisualEntity) {
                    ((VisualEntity) entity).setLOD(lod);
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.monklypse.core.JMECanvasImplementor2#resizeCanvas(int, int)
     */
    @Override
    public void resizeCanvas(int width, int height) {
        // don't resize if the canvas was hidden
        if (width == 0 && height == 0) {
            return;
        }
        if (width > height) {
            getRenderer().reinit(width, (int) (width * .8));
            return;
        }
        getRenderer().reinit((int) (height * .8), height);
    }

    public void showMouse() {
        getCanvas().setCursor(defaultCursor);
    }

    public void hideMouse() {
        getCanvas().setCursor(invisibleCursor);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.monklypse.core.JMECanvasImplementor2#setCanvas(java.lang.Object)
     */
    @Override
    public void setCanvas(LWJGLSWTCanvas canvas) {
        super.setCanvas(canvas);

        Color white = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
        Color black = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK);
        PaletteData palette = new PaletteData(new RGB[] { white.getRGB(), black.getRGB() });
        ImageData sourceData = new ImageData(16, 16, 1, palette);
        sourceData.transparentPixel = 0;
        invisibleCursor = new Cursor(Display.getCurrent(), sourceData, 0, 0);
        defaultCursor = canvas.getCursor();
    }

    /**
     * Action that is submitted to the update thread to keep the highlights
     * pulsing.
     * 
     * 
     * @author Jochen Mader Feb 1, 2008
     * @tags
     * 
     */
    private class HilitedRepeatedUpdateAction implements RepeatedUpdateAction {
        /**
         * Maximum alpha value.
         */
        private Float maxAlpha = 1f;
        /**
         * Minimum alpha value.
         */
        private Float minAlpha = .25f;
        /**
         * Base alpha value
         */
        private Float alpha = 1f;
        /**
         * Signum.
         */
        private Integer sign = 1;

        /*
         * (non-Javadoc)
         * 
         * @see
         * org.rifidi.services.registry.core.world.RepeatedUpdateAction#doUpdate
         * (float)
         */
        @Override
        public void doUpdate(float timePassed) {
            timePassed *= sign;
            alpha += timePassed;
            if (alpha <= minAlpha) {
                sign = 1;
                alpha = minAlpha;
            } else if (alpha >= maxAlpha) {
                sign = -1;
                alpha = maxAlpha;
            }
            // Dynamic update
            for (FragmentProgramState fragmentProgramState : fragmentPrograms.values()) {
                fragmentProgramState.setParameter(new float[] { 0f, 0f, alpha, alpha }, 1);
                fragmentProgramState.setNeedsRefresh(true);
            }
        }

    }

}