Why I don't like to extend or use the SDK Scene Composer

I forgot, I also stopped, because you (Normen) said that you plan to refactor SceneExplorer/SceneViewer to be more customizable, more like you whish. So I suspend my work.

At the end “the add primitives” is the only PR accepted in SDK, but it’ not the only branch I’ve got (iirc I have one about stopping infinite error loop on shader error, that nehon fixed recently (better than mine)), and having “add primitives” was so many discussion, that I keep some other localy.

1 Like

It was the only PR you made though. And its exactly as you implemented it, there wasn’t much discussion around that. Just about the use of having something like add primitives at all because no game consists of primitives and adding primitives can (as I said already) easily be done via an AssetPack or just having a model of the primitive in your project.

In response to your edit: I agree that it should be even more simple, thats why I (as I also said already, please read the thread) didn’t want to add features like rotation etc. tools in the first place.

There are no open source / free engines out there with good editors, or at least none that I have seen.
Unity3D, UDK, CryEngine, etc have excellent editors because they have 100 software developers working on it full time and tweaking and bug fixing every little thing.
Is it possible to have a quality editor? Probably, but it would take a lot of hard work to accomplish and it will still be missing some feature that somebody wants.

I guess the problem is that most people are okay with saying that. They write an editor for a game or a genre and think it might help others, but it is not about improving the engine in the first place. Of course, if you take a look at the whole picture, integrating it into the SDK would be better but it does not have any direct advantages for the one who wrote it.
Maybe you should think of a kind of system that really rewards people who contribute? I don’t know of course we don’t want to have any disadvantages for users who don’t contribute hmm…

BTW, if I integrate it into the SDK using this method, do I then have the basic SceneComposer controls like G for grab, R for rotate etc.?

And well I think the SceneComposer is quite okay. There are some features I miss (dragging and dropping spatials directly to a location, an easy way of getting the Vector at a certain location, moving lights with shortcuts like ‘G’ etc.) but as @Momoko_Fan said, it is really difficult to develop and maintain a general need 3D editor. And there are already a bunch of 3D editors out there that one can use so I don’t think it is that important to focus on a really good SceneComposer.
There are certain cases when you have to use the SceneComposer (for example when I add a weapon to a character’s attachmentNode and I want to see how the animation is looking with it), so I’d say it should be kinda easy to attach that weapon, e.g. rotate, scale and move it. But I don’t think we need a level editor for any kind of game which let’s you control the AI etc. etc. particularly because you can already do a lot with AppStates.

Thats the point, you can use the tools in the SDK for certain things that everybody needs to do at a certain point… See how a model imports, change material settings etc etc. Thats what we supplied already.

And of course its perfectly fine if people do editors for their stuff, heck, even doing a SDK plugin editor solely for their game and purposes. But why would people come to the forum and go “check out my cool editor, you can download it here”. Obviously they want to share what they did and have others use it and even help them extend it.

Thats why we did the SDK in the first place and added tools to make visual graphs from scenes, edit properties via swing in a threadsafe way, access resources in the assets folder, even load classes from the project and use them in the editor. From jME1 on there were people doing “editors” for the engine and ALL of them went the same route. The people developed them for a certain time, sometimes some people even used them, then interested waned and they went to the big graveyard of editors.

The problems with doing a generic “game editor” were already outlined but even these can be implemented in the SDK. You can supply an example project, add visual editors to make a level, place NPCs, do a whole RPG for that matter. Then you could use the existing tools, would automatically supply reusable snippets and tools for other editors, the whole thing would grow and allow doing all kinds of things (not all in the same editor mind you). But it seems it just can’t be like that :slight_smile:

Yeah it’d definetely be awesome. It’d certainly increase the lifespan of these tools :smile:
As I looked in quite a short time through the docs I didn’t find a way of extending SceneComposer in an own plugin. How would I do that? I am sure I missed something somewhere as I just had a really quick look. The most plugins will probably use a 3D view and it is awesome if you already have basic tools and could just add own buttons and listeners in a toolbar or something like that.

http://wiki.jmonkeyengine.org/doku.php/sdk:development

Well I already took a look at the docs but they don’t tell me how to build a plugin on top of the SceneComposer and its existing tools. Okay there apparently is an OffViewPanel (which is now named OffScenePanel?) but when I tried it, I simply saw a normal Swing panel. There is a SceneToolController, but is it just a controller or will it just provide the methods used by the SceneComposer? How could I get the UI of the SceneComposer to build on top of it?

This is the code I tried for just rendering a scene and all I see is an empty swing panel which is not black like it was if it showed the scene (and my jLabel):

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.softwarepage.nbplugins.cinematiceditor;

import com.jme3.gde.core.assets.ProjectAssetManager;
import com.jme3.gde.core.scene.PreviewRequest;
import com.jme3.gde.core.scene.SceneApplication;
import com.jme3.gde.core.scene.SceneListener;
import com.jme3.gde.core.scene.SceneRequest;
import com.jme3.gde.core.scene.controller.SceneToolController;
import com.jme3.gde.core.sceneexplorer.nodes.JmeNode;
import com.jme3.gde.core.sceneexplorer.nodes.NodeUtility;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.windows.TopComponent;
import org.openide.util.NbBundle.Messages;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(
        dtd = "-//net.softwarepage.nbplugins.cinematiceditor//Main//EN",
        autostore = false)
@TopComponent.Description(
        preferredID = "MainTopComponent",
        //iconBase="SET/PATH/TO/ICON/HERE", 
        persistenceType = TopComponent.PERSISTENCE_ALWAYS)
@TopComponent.Registration(mode = "editor", openAtStartup = true)
@ActionID(category = "Window", id = "net.softwarepage.nbplugins.cinematiceditor.MainTopComponent")
@ActionReference(path = "Menu/Window" /*, position = 333 */)
@TopComponent.OpenActionRegistration(
        displayName = "#CTL_MainAction",
        preferredID = "MainTopComponent")
@Messages({
    "CTL_MainAction=Main",
    "CTL_MainTopComponent=Main Window",
    "HINT_MainTopComponent=This is a Main window"
})
public final class MainTopComponent extends TopComponent implements SceneListener {

    com.jme3.scene.Node rootNode = new com.jme3.scene.Node("MyRootNode");
    private ProjectAssetManager assetManager;
    private SceneApplication app;

    public MainTopComponent() {
        initComponents();
        setName(Bundle.CTL_MainTopComponent());
        setToolTipText(Bundle.HINT_MainTopComponent());

        registerSceneListener();
        requestScene();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        offScenePanel1 = new com.jme3.gde.core.scene.OffScenePanel();

        org.openide.awt.Mnemonics.setLocalizedText(jLabel1, "jLabel1");

        javax.swing.GroupLayout offScenePanel1Layout = new javax.swing.GroupLayout(offScenePanel1);
        offScenePanel1.setLayout(offScenePanel1Layout);
        offScenePanel1Layout.setHorizontalGroup(
            offScenePanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 0, Short.MAX_VALUE)
        );
        offScenePanel1Layout.setVerticalGroup(
            offScenePanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 100, Short.MAX_VALUE)
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(offScenePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addGap(0, 346, Short.MAX_VALUE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(20, 20, 20)
                .addComponent(offScenePanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addComponent(jLabel1)
                .addContainerGap(148, Short.MAX_VALUE))
        );
    }// </editor-fold>                        
    // Variables declaration - do not modify                     
    private javax.swing.JLabel jLabel1;
    private com.jme3.gde.core.scene.OffScenePanel offScenePanel1;
    // End of variables declaration                   

    @Override
    public void componentOpened() {
    }

    private void registerSceneListener() {
        app = SceneApplication.getApplication();
        app.addSceneListener(this);
    }

    private void requestScene() {
        //create a jmeNode from the rootNode using the NodeUtility
        JmeNode jmeNode = NodeUtility.createNode(rootNode);
        assetManager = jmeNode.getLookup().lookup(ProjectAssetManager.class);
        System.out.println(assetManager);
        //create the scene request
        SceneRequest request = new SceneRequest(this, jmeNode, assetManager);
        //request the scene
        app.openScene(request);

    }

    @Override
    public void sceneOpened(SceneRequest request) {
        //check if its our request
        if (request.getRequester() == this) {
            offScenePanel1.attach(rootNode);
        }
    }

    @Override
    public void sceneClosed(SceneRequest request) {
        if (request.getRequester() == this) {
            //we have to close the scene,  any operations on the scene have to be done via Callables
        }
    }

    @Override
    public void componentClosed() {
        // TODO add custom code on component closing
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // TODO store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // TODO read your settings according to their version
    }

    @Override
    public void previewCreated(PreviewRequest pr) {
    }
}

There’s not much motiviation for creating a plugin because there’s always the option to do it as an other application, so you should make it as easy as possible. I’ve now been searching for some time, even looked in the source code and couldn’t find a way to display a scene with the exisitng camera controls without rewriting everything.
Of course I didn’t search and search and search because before doing that one would probably just create an own application, but I did spend some time on it.

You can only extend the SceneComposer by extending the scenecomposer code directly. A new plugin would use the scene by itself (like the TerrainEditor).

As I said before, most of the leading 3D game engines have an editor-first approach - whilst I like the code-first focus in JME3 I do think the lack of a full-featured editor out of the box lets the engine down somewhat. I do agree with normen’s point that it makes most sense to extend the tools within the existing SDK but personally I’d need more up to date info and examples on how to do that because as @mathiasj says it’s not obvious for the uninitiated.

1 Like

Well there has been a big effort on the documentation for this, but I guess it’s not enough
@Normen maybe we should make a step by step video tutorial on how to create a netbeans plugin extending the scene composer…
Not sure if it’s easily doable…

2 Likes

I think you really should do that because it would help a lot! It doesn’t even have to be a video if that is too much, just a step to step thing which quickly explains how to extend scene composer and add own tools and stuff like that.

No game engine has an editor-first approach…

The docs show how you can get and open an instance of the scene, see “requesting the scene” here:
http://wiki.jmonkeyengine.org/doku.php/sdk:development:scene

Heres how to add tools to the SceneExplorer (like adding spatials etc.)
http://wiki.jmonkeyengine.org/doku.php/sdk:development:sceneexplorer

The main page also contains hints to generic camera tools etc. that are used by both the Terrain Editor and the SceneComposer. And ofc your plugin can use all other features of the core SDK that both of these use.

The scene composer itself, as said, is not extensible, you can’t add buttons to its main view or anything like that. That could/would be possible for future versions of the SDK but it still wouldn’t be the way to make a plugin where you “add waypoints” or “add NPCs” as the scenecomposer will continue to be a generic editor for models and scenes. You would make your own plugin for that anyway. So request the scene and do whatever you want to do. Again, the Terrain Editor and the Vehicle editor are examples of such plugins.

You can however simply change the code of the SceneComposer and build your own SDK and/or make a PR if you think your extended SceneComposer should go into the release version.

When I said ‘on top of the SceneComposer’ I really meant including all the functions of the SceneComposer in an own plugin which offers more functionality but could use for example the rotate tools.
Once I have the instance of a scene, how should I then display it? As I said, I tried it with the OffScenePanel and didn’t get it to work. And what about all the camera stuff? Is it enough to simply attach the AbstractCameraController?

You can just copy-paste the whole SceneComposer code if you want the same and extend it. Include the SceneComposer library, then you have access to its classes for moving etc. When you have the instance of a scene the OpenGL window is already opened.