scene.adoc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. = jMonkeyEngine SDK -- The Scene
  2. :revnumber: 2.0
  3. :revdate: 2020/07/10
  4. To reduce system overhead the jMonkeyEngine SDK Core supplies one scene/jme3 application that is shared between plugins. Furthermore there's the "`SceneExplorer`" that shows a visual representation of the scenegraph and its objects properties across plugins.
  5. == How to access the Scene
  6. There are several ways for your plugin to interact with the Scene:
  7. * It listens for selected spatials / objects and offers options for those
  8. * It requests the whole scene for itself and loads/arranges the content in it (e.g. a terrain editor or model animation plugin).
  9. == Listening for Node selection
  10. In the jMonkeyEngine SDK, all objects are wrapped into NetBeans "`Nodes`" (different thing than jme Nodes!). Such nodes can have properties and icons and can be displayed and selected in the jMonkeyEngine SDK UI. The SceneExplorer shows a tree of Nodes that wrap the Spatials of the current scene and allows manipulating their properties on selection. A jME "`Spatial`" is wrapped by a "`JmeSpatial`" node, for example. One advantage of these Nodes is that one can manipulate properties of Spatials directly from the AWT thread.
  11. To listen to the current selection, implement org.openide.util.LookupListener and register like this:
  12. [source,java]
  13. ----
  14. private final Result<JmeSpatial> result;
  15. //method to register the listener;
  16. private void registerListener(){
  17. result = Utilities.actionsGlobalContext().lookupResult(JmeSpatial.class);
  18. result.addLookupListener(this);
  19. }
  20. //implements org.openide.util.LookupListener (called from AWT thread)
  21. public void resultChanged(LookupEvent ev) {
  22. Collection<JmeSpatial> items = (Collection<JmeSpatial>) result.allInstances();
  23. for (JmeSpatial jmeSpatial : items) {
  24. //Using the JmeSpatials properties you can modify the spatial directly from the AWT thread:
  25. jmeSpatial.getPropertySets()[0].setValue("Local Translation", Vector3f.ZERO);
  26. return;
  27. }
  28. }
  29. ----
  30. You can also access the "`real`" spatial but since its part of the scenegraph you will have to modify it on that thread:
  31. [source,java]
  32. ----
  33. //retrieve the "real" spatial class from the JmeNode
  34. for (JmeSpatial jmeSpatial : items) {
  35. //the spatial is stored inside the JmeSpatials "Lookup", a general container for Objects
  36. final Spatial realSpatial = jmeSpatial.getLookup().lookup(Spatial.class);
  37. //use a Callable to execute on the render thread:
  38. SceneApplication.getApplication().enqueue(new Callable() {
  39. public Object call() throws Exception {
  40. realSpatial.setLocalTranslation(Vector3f.ZERO);
  41. return null;
  42. }
  43. });
  44. return;
  45. }
  46. ----
  47. == Requesting the Scene
  48. If your plugin wants to use the scene by itself, it first has to implement SceneListener and register at the scene and then send a SceneRequest to the SceneApplication. When the SceneRequest has been approved and the current Scene has been closed, the SceneListener (your class) is called with its own SceneRequest as a parameter. When another plugin sends a SceneRequest it is also reported to you and its a hint that your RootNode has been removed from the Scene and you are no longer in control of it. You could also hook into the SceneRequests of other plugins to see if/when they are activated to display add-on plugins for that plugin.
  49. The SceneRequest object has to contain several things. A thing that you must supply is a jme "`Node`" wrapped into a "`JmeNode`" object. This is your rootNode that you use to display and build your scene. As soon as you control the scene, you will have to control the camera etc. yourself.
  50. [source,java]
  51. ----
  52. com.jme3.scene.Node rootNode = new com.jme3.scene.Node("MyRootNode");
  53. private void registerSceneListener(){
  54. SceneApplication.getApplication().addSceneListener(this);
  55. }
  56. private void requestScene(){
  57. //create a jmeNode from the rootNode using the NodeUtility
  58. JmeNode jmeNode = NodeUtility.createNode(rootNode);
  59. //create the scene request
  60. SceneRequest request=new SceneRequest(this, jmeNode, assetManager);
  61. //request the scene
  62. SceneApplication.getApplication().openScene(request);
  63. }
  64. //implements SceneListener (called from AWT thread)
  65. public void sceneOpened(SceneRequest request){
  66. //check if its our request
  67. if (request.getRequester() == this) {
  68. //we now own the scene, any operations on the scene have to be done via Callables
  69. }
  70. }
  71. public void sceneClosed(SceneRequest request) {
  72. if (request.getRequester() == this) {
  73. //we have to close the scene, any operations on the scene have to be done via Callables
  74. }
  75. }
  76. ----
  77. == Undo/Redo support
  78. The jMonkeyEngine SDK has a global undo/redo queue that activates the undo/redo buttons. To use it in your TopComponent, add the following method:
  79. [source,java]
  80. ----
  81. @Override
  82. public UndoRedo getUndoRedo() {
  83. return Lookup.getDefault().lookup(SceneUndoRedoManager.class);
  84. }
  85. ----
  86. To add a undo/redo event that modifies objects on the Scenegraph, there's a special version of AbstractUndoableEdit which executes the undo/redo calls on the scene thread. Simply implement that class and add it to the queue like this:
  87. [source,java]
  88. ----
  89. Lookup.getDefault().lookup(SceneUndoRedoManager.class).addEdit(this, new AbstractUndoableSceneEdit() {
  90. @Override
  91. public void sceneUndo() {
  92. //undo stuff in scene here
  93. }
  94. @Override
  95. public void sceneRedo() {
  96. //redo stuff in scene here
  97. }
  98. @Override
  99. public void awtUndo() {
  100. //undo stuff on awt thread here (updating of visual nodes etc, called post scene edit)
  101. }
  102. @Override
  103. public void awtRedo() {
  104. //redo stuff on awt thread here
  105. }
  106. });
  107. ----
  108. Note: Its important that you use the method addEdit(Object source, UndoableEdit edit);