sceneexplorer.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width,initial-scale=1">
  6. <title>The SceneExplorer :: jMonkeyEngine Docs</title>
  7. <link rel="canonical" href="https://wiki.jmonkeyengine.org/docs/sdk/development/sceneexplorer.html">
  8. <meta name="generator" content="Antora 2.3.3">
  9. <link rel="stylesheet" href="../../../_/css/site.css">
  10. <meta property="og:image" content="https://wiki.jmonkeyengine.org/_/img/iconx128.png">
  11. <meta property="og:description" content="The SceneExplorer">
  12. <meta property="og:title" content="jMonkeyEngine Docs">
  13. <link rel="stylesheet" href="../../../_/css/site-extra.css">
  14. <link rel="stylesheet" href="../../../_/css/vendor/docsearch.min.css">
  15. <!-- fetched from https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css -->
  16. <link rel="icon" href="../../../_/img/favicon.ico" type="image/x-icon">
  17. </head>
  18. <body class="article">
  19. <header class="header">
  20. <nav class="navbar">
  21. <div class="navbar-brand">
  22. <a class="navbar-item" href="https://wiki.jmonkeyengine.org">
  23. <img alt="" src="../../../_/img/jme-logo.png" height="32" type="image/x-icon">
  24. </a>
  25. <div class="navbar-item hide-for-print">
  26. <input id="search-input" type="text" placeholder="Search docs">
  27. </div>
  28. <button class="navbar-burger" data-target="topbar-nav">
  29. <span></span>
  30. <span></span>
  31. <span></span>
  32. </button>
  33. </div>
  34. <div id="topbar-nav" class="navbar-menu">
  35. <div class="navbar-end">
  36. <div class="navbar-item theme-switch-wrapper">
  37. <label class="theme-switch" for="checkbox">
  38. <input type="checkbox" id="checkbox" />
  39. <div class="slider round"></div>
  40. </label>
  41. </div>
  42. <a class="navbar-item" href="https://github.com/jmonkeyengine/wiki">Github</a>
  43. </div>
  44. </div>
  45. </nav>
  46. </header>
  47. <div class="body">
  48. <div class="nav-container" data-component="docs" data-version="master">
  49. <aside class="nav">
  50. <div class="panels">
  51. <div class="nav-panel-menu is-active" data-panel="menu">
  52. <nav class="nav-menu">
  53. <h3 class="title"><a href="../../documentation.html">Docs</a></h3>
  54. <ul class="nav-list">
  55. <li class="nav-item" data-depth="0">
  56. <ul class="nav-list">
  57. <li class="nav-item" data-depth="1">
  58. <a class="nav-link" href="../../documentation.html">Getting Started</a>
  59. </li>
  60. <li class="nav-item" data-depth="1">
  61. <a class="nav-link" href="https://javadoc.jmonkeyengine.org/v3.3.2-stable">JavaDoc</a>
  62. </li>
  63. <li class="nav-item" data-depth="1">
  64. <button class="nav-item-toggle"></button>
  65. <a class="nav-link" href="../../jme3.html">jMonkeyEngine 3</a>
  66. <ul class="nav-list">
  67. <li class="nav-item" data-depth="2">
  68. <button class="nav-item-toggle"></button>
  69. <span class="nav-text">Beginner Tutorials</span>
  70. <ul class="nav-list">
  71. <li class="nav-item" data-depth="3">
  72. <a class="nav-link" href="../../jme3/beginner/hello_simpleapplication.html">Hello SimpleApplication</a>
  73. </li>
  74. <li class="nav-item" data-depth="3">
  75. <a class="nav-link" href="../../jme3/beginner/hello_node.html">Hello Node</a>
  76. </li>
  77. <li class="nav-item" data-depth="3">
  78. <a class="nav-link" href="../../jme3/beginner/hello_asset.html">Hello Asset</a>
  79. </li>
  80. <li class="nav-item" data-depth="3">
  81. <a class="nav-link" href="../../jme3/beginner/hello_main_event_loop.html">Hello Main Event Loop</a>
  82. </li>
  83. <li class="nav-item" data-depth="3">
  84. <a class="nav-link" href="../../jme3/beginner/hello_input_system.html">Hello Input System</a>
  85. </li>
  86. <li class="nav-item" data-depth="3">
  87. <a class="nav-link" href="../../jme3/beginner/hello_material.html">Hello Material</a>
  88. </li>
  89. <li class="nav-item" data-depth="3">
  90. <a class="nav-link" href="../../jme3/beginner/hello_animation.html">Hello Animation</a>
  91. </li>
  92. <li class="nav-item" data-depth="3">
  93. <a class="nav-link" href="../../jme3/beginner/hello_picking.html">Hello Picking</a>
  94. </li>
  95. <li class="nav-item" data-depth="3">
  96. <a class="nav-link" href="../../jme3/beginner/hello_collision.html">Hello Collision</a>
  97. </li>
  98. <li class="nav-item" data-depth="3">
  99. <a class="nav-link" href="../../jme3/beginner/hello_terrain.html">Hello Terrain</a>
  100. </li>
  101. <li class="nav-item" data-depth="3">
  102. <a class="nav-link" href="../../jme3/beginner/hello_audio.html">Hello Audio</a>
  103. </li>
  104. <li class="nav-item" data-depth="3">
  105. <a class="nav-link" href="../../jme3/beginner/hello_effects.html">Hello Effects</a>
  106. </li>
  107. <li class="nav-item" data-depth="3">
  108. <a class="nav-link" href="../../jme3/beginner/hello_physics.html">Hello Physics</a>
  109. </li>
  110. </ul>
  111. </li>
  112. <li class="nav-item" data-depth="2">
  113. <button class="nav-item-toggle"></button>
  114. <span class="nav-text">Intermediate Tutorials</span>
  115. <ul class="nav-list">
  116. <li class="nav-item" data-depth="3">
  117. <button class="nav-item-toggle"></button>
  118. <span class="nav-text">Concepts</span>
  119. <ul class="nav-list">
  120. <li class="nav-item" data-depth="4">
  121. <a class="nav-link" href="../../jme3/intermediate/best_practices.html">Best Practices</a>
  122. </li>
  123. <li class="nav-item" data-depth="4">
  124. <a class="nav-link" href="../../jme3/intermediate/simpleapplication.html">Simple Application</a>
  125. </li>
  126. <li class="nav-item" data-depth="4">
  127. <a class="nav-link" href="../../jme3/features.html">Features</a>
  128. </li>
  129. <li class="nav-item" data-depth="4">
  130. <a class="nav-link" href="../../jme3/intermediate/optimization.html">Optimization</a>
  131. </li>
  132. <li class="nav-item" data-depth="4">
  133. <a class="nav-link" href="../../jme3/faq.html">FAQ</a>
  134. </li>
  135. </ul>
  136. </li>
  137. <li class="nav-item" data-depth="3">
  138. <button class="nav-item-toggle"></button>
  139. <span class="nav-text">Math Concepts</span>
  140. <ul class="nav-list">
  141. <li class="nav-item" data-depth="4">
  142. <a class="nav-link" href="../../jme3/math_for_dummies.html">Math For Dummies</a>
  143. </li>
  144. <li class="nav-item" data-depth="4">
  145. <a class="nav-link" href="../../jme3/intermediate/math.html">Math</a>
  146. </li>
  147. <li class="nav-item" data-depth="4">
  148. <a class="nav-link" href="../../jme3/math.html">More Math</a>
  149. </li>
  150. <li class="nav-item" data-depth="4">
  151. <a class="nav-link" href="../../jme3/rotate.html">Rotate</a>
  152. </li>
  153. <li class="nav-item" data-depth="4">
  154. <a class="nav-link" href="../../jme3/math_video_tutorials.html">Math Video Tutorials</a>
  155. </li>
  156. </ul>
  157. </li>
  158. <li class="nav-item" data-depth="3">
  159. <button class="nav-item-toggle"></button>
  160. <span class="nav-text">3D Graphics Concepts</span>
  161. <ul class="nav-list">
  162. <li class="nav-item" data-depth="4">
  163. <a class="nav-link" href="../../jme3/intermediate/multi-media_asset_pipeline.html">Multi-Media Asset Pipeline</a>
  164. </li>
  165. <li class="nav-item" data-depth="4">
  166. <a class="nav-link" href="../../jme3/scenegraph_for_dummies.html">Scenegraph for Dummies</a>
  167. </li>
  168. <li class="nav-item" data-depth="4">
  169. <a class="nav-link" href="../../jme3/beginner/hellovector.html">Hello Vector</a>
  170. </li>
  171. <li class="nav-item" data-depth="4">
  172. <a class="nav-link" href="../../jme3/terminology.html">Terminology</a>
  173. </li>
  174. <li class="nav-item" data-depth="4">
  175. <a class="nav-link" href="../../jme3/intermediate/how_to_use_materials.html">How to Use Materials</a>
  176. </li>
  177. <li class="nav-item" data-depth="4">
  178. <a class="nav-link" href="../../jme3/intermediate/transparency_sorting.html">Transparency and Sorting</a>
  179. </li>
  180. <li class="nav-item" data-depth="4">
  181. <a class="nav-link" href="../../jme3/external/blender.html">Importing from Blender</a>
  182. </li>
  183. <li class="nav-item" data-depth="4">
  184. <a class="nav-link" href="../../jme3/external/3dsmax.html">Importing from 3DS Max</a>
  185. </li>
  186. </ul>
  187. </li>
  188. </ul>
  189. </li>
  190. </ul>
  191. </li>
  192. <li class="nav-item" data-depth="1">
  193. <a class="nav-link" href="../../logo.html">Logo Usage</a>
  194. </li>
  195. <li class="nav-item" data-depth="1">
  196. <a class="nav-link" href="../../bsd_license.html">License</a>
  197. </li>
  198. <li class="nav-item" data-depth="1">
  199. <a class="nav-link" href="../../github_tips.html">Github Tips</a>
  200. </li>
  201. </ul>
  202. </li>
  203. <li class="nav-item" data-depth="0">
  204. <button class="nav-item-toggle"></button>
  205. <span class="nav-text">SDK</span>
  206. <ul class="nav-list">
  207. <li class="nav-item" data-depth="1">
  208. <a class="nav-link" href="../../sdk.html">jMonkeyEngine SDK</a>
  209. </li>
  210. </ul>
  211. </li>
  212. </ul>
  213. </nav>
  214. </div>
  215. <div class="nav-panel-explore" data-panel="explore">
  216. <div class="context">
  217. <span class="title">Docs</span>
  218. <span class="version">master</span>
  219. </div>
  220. <ul class="components">
  221. <li class="component is-current">
  222. <span class="title">Docs</span>
  223. <ul class="versions">
  224. <li class="version is-current is-latest">
  225. <a href="../../documentation.html">master</a>
  226. </li>
  227. </ul>
  228. </li>
  229. <li class="component">
  230. <span class="title">Wiki UI</span>
  231. <ul class="versions">
  232. <li class="version is-latest">
  233. <a href="../../../wiki-ui/index.html">master</a>
  234. </li>
  235. </ul>
  236. </li>
  237. </ul>
  238. </div>
  239. </div>
  240. </aside>
  241. </div>
  242. <main class="article">
  243. <div class="toolbar" role="navigation">
  244. <button class="nav-toggle"></button>
  245. <nav class="breadcrumbs" aria-label="breadcrumbs">
  246. <ul>
  247. <li><a href="../../documentation.html">Docs</a></li>
  248. <li><a href="sceneexplorer.html">The SceneExplorer</a></li>
  249. </ul>
  250. </nav>
  251. <div class="edit-this-page"><a href="https://github.com/jMonkeyEngine/wiki/edit/master/docs/modules/ROOT/pages/sdk/development/sceneexplorer.adoc">Edit this Page</a></div>
  252. </div>
  253. <div class="content">
  254. <article class="doc">
  255. <h1 class="page">The SceneExplorer</h1>
  256. <div class="sect1">
  257. <h2 id="adding-node-types-to-sceneexplorer"><a class="anchor" href="#adding-node-types-to-sceneexplorer"></a>Adding Node types to SceneExplorer</h2>
  258. <div class="sectionbody">
  259. <div class="paragraph">
  260. <p>If your plugin brings in its own SceneGraph objects you can still have them work like any other SceneExplorer item, including its special properties.</p>
  261. </div>
  262. <div class="paragraph">
  263. <p>If you want to support special properties of your objects that are not exposed by the SDK automatically, you will have to create your own class that extends org.openide.nodes.Node and implement the interface com.jme3.gde.core.sceneexplorer.nodes.AbstractSceneExplorerNode. Then you register that class by adding</p>
  264. </div>
  265. <div class="listingblock">
  266. <div class="content">
  267. <pre class="highlightjs highlight"><code>@org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)</code></pre>
  268. </div>
  269. </div>
  270. <div class="literalblock">
  271. <div class="content">
  272. <pre>above the body of your class. Thats all, your Spatial type will automatically be used and displayed in the SceneExplorer. Make sure you register a jar with the used classes in the plugin preferences under “wrapped libraries, otherwise the IDE cannot access those classes.</pre>
  273. </div>
  274. </div>
  275. <div class="paragraph">
  276. <p>AbstractSceneExplorerNode brings some other useful features you might want to include like automatic creation of properly threaded properties etc. JmeSpatial for example bases on it. A simple SceneExplorerNode example for an object extending Spatial would be JmeGeometry (see below). Editors for special variable types can be added using the SceneExplorerPropertyEditor interface, which can be registered as a ServiceProvider as well.</p>
  277. </div>
  278. <div class="paragraph">
  279. <p>The SceneExplorerNode can be used for Spatial and Control type objects.</p>
  280. </div>
  281. <div class="ulist">
  282. <ul>
  283. <li>
  284. <p><em>Add the “Nodes <abbr title="Application Programming Interface">API</abbr> and “Lookup <abbr title="Application Programming Interface">API</abbr> libraries to your project when you want to use this</em></p>
  285. </li>
  286. </ul>
  287. </div>
  288. <div class="sect2">
  289. <h3 id="spatial-example"><a class="anchor" href="#spatial-example"></a>Spatial Example</h3>
  290. <div class="listingblock">
  291. <div class="content">
  292. <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)
  293. public class JmeGeometry extends JmeSpatial {
  294. private static Image smallImage =
  295. ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/geometry.gif");
  296. private Geometry geom;
  297. public JmeGeometry() {
  298. }
  299. public JmeGeometry(Geometry spatial, SceneExplorerChildren children) {
  300. super(spatial, children);
  301. getLookupContents().add(spatial);
  302. this.geom = spatial;
  303. setName(spatial.getName());
  304. }
  305. @Override
  306. public Image getIcon(int type) {
  307. return smallImage;
  308. }
  309. @Override
  310. public Image getOpenedIcon(int type) {
  311. return smallImage;
  312. }
  313. @Override
  314. protected Sheet createSheet() {
  315. Sheet sheet = super.createSheet();
  316. Sheet.Set set = Sheet.createPropertiesSet();
  317. set.setDisplayName("Geometry");
  318. set.setName(Geometry.class.getName());
  319. Geometry obj = geom;//getLookup().lookup(Geometry.class);
  320. if (obj == null) {
  321. return sheet;
  322. }
  323. set.put(makeProperty(obj, int.class, "getLodLevel", "setLodLevel", "Lod Level"));
  324. set.put(makeProperty(obj, Material.class, "getMaterial", "setMaterial", "Material"));
  325. set.put(makeProperty(obj, Mesh.class, "getMesh", "Mesh"));
  326. sheet.put(set);
  327. return sheet;
  328. }
  329. public Class getExplorerObjectClass() {
  330. return Geometry.class;
  331. }
  332. public Class getExplorerNodeClass() {
  333. return JmeGeometry.class;
  334. }
  335. public org.openide.nodes.Node[] createNodes(Object key, Object key2, boolean readOnly) {
  336. SceneExplorerChildren children=new SceneExplorerChildren((com.jme3.scene.Spatial)key);
  337. children.setReadOnly(readOnly);
  338. return new org.openide.nodes.Node[]{new JmeGeometry((Geometry) key, children).setReadOnly(readOnly)};
  339. }
  340. }</code></pre>
  341. </div>
  342. </div>
  343. </div>
  344. <div class="sect2">
  345. <h3 id="control-example"><a class="anchor" href="#control-example"></a>Control Example</h3>
  346. <div class="listingblock">
  347. <div class="content">
  348. <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)
  349. public class JmeGhostControl extends AbstractSceneExplorerNode {
  350. private static Image smallImage =
  351. ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/ghostcontrol.gif");
  352. private GhostControl control;
  353. public JmeGhostControl() {
  354. }
  355. public JmeGhostControl(GhostControl control, DataObject dataObject) {
  356. super(dataObject);
  357. getLookupContents().add(this);
  358. getLookupContents().add(control);
  359. this.control = control;
  360. setName("GhostControl");
  361. }
  362. @Override
  363. public Image getIcon(int type) {
  364. return smallImage;
  365. }
  366. @Override
  367. public Image getOpenedIcon(int type) {
  368. return smallImage;
  369. }
  370. protected SystemAction[] createActions() {
  371. return new SystemAction[]{
  372. // SystemAction.get(CopyAction.class),
  373. // SystemAction.get(CutAction.class),
  374. // SystemAction.get(PasteAction.class),
  375. SystemAction.get(DeleteAction.class)
  376. };
  377. }
  378. @Override
  379. public boolean canDestroy() {
  380. return !readOnly;
  381. }
  382. @Override
  383. public void destroy() throws IOException {
  384. super.destroy();
  385. final Spatial spat=getParentNode().getLookup().lookup(Spatial.class);
  386. try {
  387. SceneApplication.getApplication().enqueue(new Callable&lt;Void&gt;() {
  388. public Void call() throws Exception {
  389. spat.removeControl(control);
  390. return null;
  391. }
  392. }).get();
  393. ((AbstractSceneExplorerNode)getParentNode()).refresh(true);
  394. } catch (InterruptedException ex) {
  395. Exceptions.printStackTrace(ex);
  396. } catch (ExecutionException ex) {
  397. Exceptions.printStackTrace(ex);
  398. }
  399. }
  400. @Override
  401. protected Sheet createSheet() {
  402. Sheet sheet = super.createSheet();
  403. Sheet.Set set = Sheet.createPropertiesSet();
  404. set.setDisplayName("GhostControl");
  405. set.setName(GhostControl.class.getName());
  406. GhostControl obj = control;//getLookup().lookup(Spatial.class);
  407. if (obj == null) {
  408. return sheet;
  409. }
  410. set.put(makeProperty(obj, Vector3f.class, "getPhysicsLocation", "setPhysicsLocation", "Physics Location"));
  411. set.put(makeProperty(obj, Quaternion.class, "getPhysicsRotation", "setPhysicsRotation", "Physics Rotation"));
  412. set.put(makeProperty(obj, CollisionShape.class, "getCollisionShape", "setCollisionShape", "Collision Shape"));
  413. set.put(makeProperty(obj, int.class, "getCollisionGroup", "setCollisionGroup", "Collision Group"));
  414. set.put(makeProperty(obj, int.class, "getCollideWithGroups", "setCollideWithGroups", "Collide With Groups"));
  415. sheet.put(set);
  416. return sheet;
  417. }
  418. public Class getExplorerObjectClass() {
  419. return GhostControl.class;
  420. }
  421. public Class getExplorerNodeClass() {
  422. return JmeGhostControl.class;
  423. }
  424. public org.openide.nodes.Node[] createNodes(Object key, DataObject key2, boolean cookie) {
  425. return new org.openide.nodes.Node[]{new JmeGhostControl((GhostControl) key, key2).setReadOnly(cookie)};
  426. }
  427. }</code></pre>
  428. </div>
  429. </div>
  430. </div>
  431. </div>
  432. </div>
  433. <div class="sect1">
  434. <h2 id="adding-items-to-the-add-and-tools-menus"><a class="anchor" href="#adding-items-to-the-add-and-tools-menus"></a>Adding items to the add and tools menus</h2>
  435. <div class="sectionbody">
  436. <div class="paragraph">
  437. <p>For adding Spatials, Contols and for general tools theres premade abstract classes that you can use to extend the options. Undo/Redo is handled by the abstract class. AbstractNewSpatial*Wizard*Action allows you to show an AWT wizard before creating the Spatial. You can also just implement the base ServiceProvider class and return any kind of action (such as a wizard), in this case you have to handle the threading yourself!</p>
  438. </div>
  439. <div class="admonitionblock important">
  440. <table>
  441. <tr>
  442. <td class="icon">
  443. <i class="fa icon-important" title="Important"></i>
  444. </td>
  445. <td class="content">
  446. <div class="paragraph">
  447. <p>Note that the classes you create are singletons which are used across multiple nodes and you should not store any data in local variables!</p>
  448. </div>
  449. </td>
  450. </tr>
  451. </table>
  452. </div>
  453. <div class="paragraph">
  454. <p>To add a new Tool, create a new AbstractToolAction:</p>
  455. </div>
  456. <div class="listingblock">
  457. <div class="content">
  458. <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@org.openide.util.lookup.ServiceProvider(service = ToolAction.class)
  459. public class GenerateTangentsTool extends AbstractToolAction {
  460. public GenerateTangentsTool() {
  461. name = "Generate Tangents";
  462. }
  463. @Override
  464. protected Object doApplyTool(AbstractSceneExplorerNode rootNode) {
  465. Geometry geom = rootNode.getLookup().lookup(Geometry.class);
  466. Mesh mesh = geom.getMesh();
  467. if (mesh != null) {
  468. TangentBinormalGenerator.generate(mesh);
  469. }
  470. return geom;
  471. }
  472. @Override
  473. protected void doUndoTool(AbstractSceneExplorerNode rootNode, Object undoObject) {
  474. Geometry geom = rootNode.getLookup().lookup(Geometry.class);
  475. Mesh mesh = geom.getMesh();
  476. if (mesh != null) {
  477. mesh.clearBuffer(Type.Tangent);
  478. }
  479. }
  480. public Class&lt;?&gt; getNodeClass() {
  481. return JmeGeometry.class;
  482. }
  483. }</code></pre>
  484. </div>
  485. </div>
  486. <div class="paragraph">
  487. <p>For a new Spatial or Control, use AbstractNewSpatialAction</p>
  488. </div>
  489. <div class="listingblock">
  490. <div class="content">
  491. <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@org.openide.util.lookup.ServiceProvider(service = NewSpatialAction.class)
  492. public class NewSpecialSpatialAction extends AbstractNewSpatialAction {
  493. public NewSpecialSpatialAction() {
  494. name = "Spatial";
  495. }
  496. @Override
  497. protected Spatial doCreateSpatial(Node parent) {
  498. Spatial spatial=new Node();
  499. return spatial;
  500. }
  501. }</code></pre>
  502. </div>
  503. </div>
  504. <div class="paragraph">
  505. <p>or AbstractNewControlAction:</p>
  506. </div>
  507. <div class="listingblock">
  508. <div class="content">
  509. <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@org.openide.util.lookup.ServiceProvider(service = NewControlAction.class)
  510. public class NewRigidBodyAction extends AbstractNewControlAction {
  511. public NewRigidBodyAction() {
  512. name = "Static RigidBody";
  513. }
  514. @Override
  515. protected Control doCreateControl(Spatial spatial) {
  516. RigidBodyControl control = spatial.getControl(RigidBodyControl.class);
  517. if (control != null) {
  518. spatial.removeControl(control);
  519. }
  520. Node parent = spatial.getParent();
  521. spatial.removeFromParent();
  522. control = new RigidBodyControl(0);
  523. if (parent != null) {
  524. parent.attachChild(spatial);
  525. }
  526. return control;
  527. }
  528. }</code></pre>
  529. </div>
  530. </div>
  531. <div class="sect2">
  532. <h3 id="adding-using-a-wizard"><a class="anchor" href="#adding-using-a-wizard"></a>Adding using a Wizard</h3>
  533. <div class="paragraph">
  534. <p>You can create a new wizard using the wizard template in the SDK (New File→Module Development→Wizard). The Action that the template creates can easily be changed to one for adding a Control or Spatial or for applying a Tool. Note that we extend AbstractNewSpatial*Wizard*Action here.</p>
  535. </div>
  536. <div class="paragraph">
  537. <p>A good example is the “Add SkyBox Wizard:</p>
  538. </div>
  539. <div class="listingblock">
  540. <div class="content">
  541. <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@org.openide.util.lookup.ServiceProvider(service = NewSpatialAction.class)
  542. public class AddSkyboxAction extends AbstractNewSpatialWizardAction {
  543. private WizardDescriptor.Panel[] panels;
  544. public AddSkyboxAction() {
  545. name = "Skybox..";
  546. }
  547. @Override
  548. protected Object showWizard(org.openide.nodes.Node node) {
  549. WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
  550. wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
  551. wizardDescriptor.setTitle("Skybox Wizard");
  552. Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
  553. dialog.setVisible(true);
  554. dialog.toFront();
  555. boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
  556. if (!cancelled) {
  557. return wizardDescriptor;
  558. }
  559. return null;
  560. }
  561. @Override
  562. protected Spatial doCreateSpatial(Node parent, Object properties) {
  563. if (properties != null) {
  564. return generateSkybox((WizardDescriptor) properties);
  565. }
  566. return null;
  567. }
  568. private Spatial generateSkybox(WizardDescriptor wiz) {
  569. if ((Boolean) wiz.getProperty("multipleTextures")) {
  570. Texture south = (Texture) wiz.getProperty("textureSouth");
  571. Texture north = (Texture) wiz.getProperty("textureNorth");
  572. Texture east = (Texture) wiz.getProperty("textureEast");
  573. Texture west = (Texture) wiz.getProperty("textureWest");
  574. Texture top = (Texture) wiz.getProperty("textureTop");
  575. Texture bottom = (Texture) wiz.getProperty("textureBottom");
  576. Vector3f normalScale = (Vector3f) wiz.getProperty("normalScale");
  577. return SkyFactory.createSky(pm, west, east, north, south, top, bottom, normalScale);
  578. } else {
  579. Texture textureSingle = (Texture) wiz.getProperty("textureSingle");
  580. Vector3f normalScale = (Vector3f) wiz.getProperty("normalScale");
  581. boolean useSpheremap = (Boolean) wiz.getProperty("useSpheremap");
  582. return SkyFactory.createSky(pm, textureSingle, normalScale, useSpheremap);
  583. }
  584. }
  585. /**
  586. * Initialize panels representing individual wizard's steps and sets
  587. * various properties for them influencing wizard appearance.
  588. */
  589. private WizardDescriptor.Panel[] getPanels() {
  590. if (panels == null) {
  591. panels = new WizardDescriptor.Panel[]{
  592. new SkyboxWizardPanel1(),
  593. new SkyboxWizardPanel2()
  594. };
  595. String[] steps = new String[panels.length];
  596. for (int i = 0; i &lt; panels.length; i++) {
  597. Component c = panels[i].getComponent();
  598. // Default step name to component name of panel. Mainly useful
  599. // for getting the name of the target chooser to appear in the
  600. // list of steps.
  601. steps[i] = c.getName();
  602. if (c instanceof JComponent) { // assume Swing components
  603. JComponent jc = (JComponent) c;
  604. // Sets step number of a component
  605. // TODO if using org.openide.dialogs &gt;= 7.8, can use WizardDescriptor.PROP_*:
  606. jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
  607. // Sets steps names for a panel
  608. jc.putClientProperty("WizardPanel_contentData", steps);
  609. // Turn on subtitle creation on each step
  610. jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
  611. // Show steps on the left side with the image on the background
  612. jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
  613. // Turn on numbering of all steps
  614. jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
  615. }
  616. }
  617. }
  618. return panels;
  619. }
  620. }</code></pre>
  621. </div>
  622. </div>
  623. <div class="admonitionblock tip">
  624. <table>
  625. <tr>
  626. <td class="icon">
  627. <i class="fa icon-tip" title="Tip"></i>
  628. </td>
  629. <td class="content">
  630. <div class="paragraph">
  631. <p>The abstract spatial and control actions implement undo/redo automatically, for the ToolActions you have to implement it yourself.</p>
  632. </div>
  633. </td>
  634. </tr>
  635. </table>
  636. </div>
  637. </div>
  638. </div>
  639. </div>
  640. </article>
  641. <aside class="toc sidebar" data-title="Contents" data-levels="2">
  642. <div class="toc-menu"></div>
  643. </aside>
  644. </div>
  645. </main>
  646. </div>
  647. <footer class="footer">
  648. <p>Copyright 2020 jMonkeyEngine Wiki Contributors. Licensed BSD-3.</p>
  649. </footer>
  650. <script src="../../../_/js/vendor/docsearch.min.js"></script>
  651. <!-- fetched from https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js -->
  652. <script>
  653. var search = docsearch({
  654. apiKey: 'a736b6d93de805e26ec2f49b55013fbd',
  655. indexName: 'jmonkeyengine',
  656. inputSelector: '#search-input',
  657. autocompleteOptions: { hint: false, keyboardShortcuts: ['s'] },
  658. algoliaOptions: { hitsPerPage: 10 }
  659. }).autocomplete
  660. search.on('autocomplete:closed', function () { search.autocomplete.setVal() })
  661. function focusSearchInput () { document.querySelector('#search-input').focus() }
  662. if (document.querySelector('.home-link.is-current')) window.addEventListener('load', focusSearchInput)
  663. </script>
  664. <script src="../../../_/js/site.js"></script>
  665. <script async src="../../../_/js/vendor/highlight.js"></script>
  666. </body>
  667. </html>