Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество
Главная
    Документация jMonkeyEngine
        jMonkeyEngine SDK: Документация
            Разработки для jMonkeyEngine SDK
                SceneExplorer

SceneExplorer

Опубликованно: 17.10.2017, 7:42
Последняя редакция, Andry: 17.10.2017 23:55

Добавление типов Узлов в SceneExplorer

Если ваш плагин приносит свои собственные объекты в SceneGraph, вы все равно можете с ними работать как с любым другим элементом SceneExplorer, включая их специальные свойства.

Если вы хотите поддерживать специальные свойства ваших объектов, которые не обнаруживаются SDK автоматически, вам придется создать свой собственный класс, который расширяет org.openide.nodes.Node и реализует интерфейс com.jme3.gde.core.sceneexplorer.nodes.AbstractSceneExplorerNode. Затем вы регистрируете этот класс, добавляя

@org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)

над телом вашего класса. То есть, все ваш Spatial-тип будет автоматически использоваться и отображаться в SceneExplorer. Убедитесь, что вы зарегистрировали jar с используемыми классами в настройках плагина под «wrapped libraries», иначе среда IDE не сможет получить доступ к этим классам.

AbstractSceneExplorerNode предлагает некоторые другие полезные функции, которые вы можете добавить, например, автоматическое создание корректно заданных свойств и.т.п. JmeSpatial, например, основывается на нем. Простой пример SceneExplorerNode для объекта, расширяющего Spatial, будет JmeGeometry (см. Ниже). Редакторы для специальных типов переменных могут быть добавлены с помощью интерфейса SceneExplorerPropertyEditor, который также может быть зарегистрирован как ServiceProvider.

SceneExplorerNode может использоваться для объектов типа Spatial и Control.

  • Добавьте в свой проект «Nodes API» и «Lookup API», если вы хотите использовать этот

Пример Spatial

@org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)
public class JmeGeometry extends JmeSpatial {

    private static Image smallImage =
            ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/geometry.gif");
    private Geometry geom;

    public JmeGeometry() {
    }

    public JmeGeometry(Geometry spatial, SceneExplorerChildren children) {
        super(spatial, children);
        getLookupContents().add(spatial);
        this.geom = spatial;
        setName(spatial.getName());
    }

    @Override
    public Image getIcon(int type) {
        return smallImage;
    }

    @Override
    public Image getOpenedIcon(int type) {
        return smallImage;
    }

    @Override
    protected Sheet createSheet() {
        Sheet sheet = super.createSheet();
        Sheet.Set set = Sheet.createPropertiesSet();
        set.setDisplayName("Geometry");
        set.setName(Geometry.class.getName());
        Geometry obj = geom;//getLookup().lookup(Geometry.class);
        if (obj == null) {
            return sheet;
        }

        set.put(makeProperty(obj, int.class, "getLodLevel", "setLodLevel", "Lod Level"));
        set.put(makeProperty(obj, Material.class, "getMaterial", "setMaterial", "Material"));
        set.put(makeProperty(obj, Mesh.class, "getMesh", "Mesh"));

        sheet.put(set);
        return sheet;

    }

    public Class getExplorerObjectClass() {
        return Geometry.class;
    }

    public Class getExplorerNodeClass() {
        return JmeGeometry.class;
    }

    public org.openide.nodes.Node[] createNodes(Object key, Object key2, boolean readOnly) {
        SceneExplorerChildren children=new SceneExplorerChildren((com.jme3.scene.Spatial)key);
        children.setReadOnly(readOnly);
        return new org.openide.nodes.Node[]{new JmeGeometry((Geometry) key, children).setReadOnly(readOnly)};
    }
}

Пример Control

@org.openide.util.lookup.ServiceProvider(service=SceneExplorerNode.class)
public class JmeGhostControl extends AbstractSceneExplorerNode {

    private static Image smallImage =
            ImageUtilities.loadImage("com/jme3/gde/core/sceneexplorer/nodes/icons/ghostcontrol.gif");
    private GhostControl control;

    public JmeGhostControl() {
    }

    public JmeGhostControl(GhostControl control, DataObject dataObject) {
        super(dataObject);
        getLookupContents().add(this);
        getLookupContents().add(control);
        this.control = control;
        setName("GhostControl");
    }

    @Override
    public Image getIcon(int type) {
        return smallImage;
    }

    @Override
    public Image getOpenedIcon(int type) {
        return smallImage;
    }

    protected SystemAction[] createActions() {
        return new SystemAction[]{
                    //                    SystemAction.get(CopyAction.class),
                    //                    SystemAction.get(CutAction.class),
                    //                    SystemAction.get(PasteAction.class),
                    SystemAction.get(DeleteAction.class)
                };
    }

    @Override
    public boolean canDestroy() {
        return !readOnly;
    }

    @Override
    public void destroy() throws IOException {
        super.destroy();
        final Spatial spat=getParentNode().getLookup().lookup(Spatial.class);
        try {
            SceneApplication.getApplication().enqueue(new Callable<Void>() {

                public Void call() throws Exception {
                    spat.removeControl(control);
                    return null;
                }
            }).get();
            ((AbstractSceneExplorerNode)getParentNode()).refresh(true);
        } catch (InterruptedException ex) {
            Exceptions.printStackTrace(ex);
        } catch (ExecutionException ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    @Override
    protected Sheet createSheet() {
        Sheet sheet = super.createSheet();
        Sheet.Set set = Sheet.createPropertiesSet();
        set.setDisplayName("GhostControl");
        set.setName(GhostControl.class.getName());
        GhostControl obj = control;//getLookup().lookup(Spatial.class);
        if (obj == null) {
            return sheet;
        }

        set.put(makeProperty(obj, Vector3f.class, "getPhysicsLocation", "setPhysicsLocation", "Physics Location"));
        set.put(makeProperty(obj, Quaternion.class, "getPhysicsRotation", "setPhysicsRotation", "Physics Rotation"));

        set.put(makeProperty(obj, CollisionShape.class, "getCollisionShape", "setCollisionShape", "Collision Shape"));
        set.put(makeProperty(obj, int.class, "getCollisionGroup", "setCollisionGroup", "Collision Group"));
        set.put(makeProperty(obj, int.class, "getCollideWithGroups", "setCollideWithGroups", "Collide With Groups"));

        sheet.put(set);
        return sheet;

    }

    public Class getExplorerObjectClass() {
        return GhostControl.class;
    }

    public Class getExplorerNodeClass() {
        return JmeGhostControl.class;
    }

    public org.openide.nodes.Node[] createNodes(Object key, DataObject key2, boolean cookie) {
        return new org.openide.nodes.Node[]{new JmeGhostControl((GhostControl) key, key2).setReadOnly(cookie)};
    }
}

Добавление элементов в меню добавления и инструменты

Чтобы добавить Spatials, Contols и для общих инструментов, вы можете создавать абстрактные классы, которые вы можете использовать для расширения опций. Отменить/Повторить обрабатывается абстрактным классом. AbstractNewSpatial*Wizard*Action позволяет показать мастер AWT перед созданием Spatial. Вы также можете просто реализовать базовый класс ServiceProvider и вернуть любой тип действия (например, мастер), в этом случае вам придется обрабатывать потоки самостоятельно!

Обратите внимание, что классы, которые вы создаете одноэлементны, которые используются на нескольких узлах, и вы не должны хранить любые данные в локальных переменных!

Чтобы добавить новый Инструмент(Tool), создайте новый AbstractToolAction:

@org.openide.util.lookup.ServiceProvider(service = ToolAction.class)
public class GenerateTangentsTool extends AbstractToolAction {

    public GenerateTangentsTool() {
        name = "Generate Tangents";
    }

    @Override
    protected Object doApplyTool(AbstractSceneExplorerNode rootNode) {
        Geometry geom = rootNode.getLookup().lookup(Geometry.class);
        Mesh mesh = geom.getMesh();
        if (mesh != null) {
            TangentBinormalGenerator.generate(mesh);
        }
        return geom;
    }

    @Override
    protected void doUndoTool(AbstractSceneExplorerNode rootNode, Object undoObject) {
        Geometry geom = rootNode.getLookup().lookup(Geometry.class);
        Mesh mesh = geom.getMesh();
        if (mesh != null) {
            mesh.clearBuffer(Type.Tangent);
        }
    }

    public Class<?> getNodeClass() {
        return JmeGeometry.class;
    }

}

Для нового Spatial или Control используйте AbstractNewSpatialAction

@org.openide.util.lookup.ServiceProvider(service = NewSpatialAction.class)
public class NewSpecialSpatialAction extends AbstractNewSpatialAction {

    public NewSpecialSpatialAction() {
        name = "Spatial";
    }

    @Override
    protected Spatial doCreateSpatial(Node parent) {
        Spatial spatial=new Node();
        return spatial;
    }
}

или AbstractNewControlAction:

@org.openide.util.lookup.ServiceProvider(service = NewControlAction.class)
public class NewRigidBodyAction extends AbstractNewControlAction {

    public NewRigidBodyAction() {
        name = "Static RigidBody";
    }

    @Override
    protected Control doCreateControl(Spatial spatial) {
        RigidBodyControl control = spatial.getControl(RigidBodyControl.class);
        if (control != null) {
            spatial.removeControl(control);
        }
        Node parent = spatial.getParent();
        spatial.removeFromParent();
        control = new RigidBodyControl(0);
        if (parent != null) {
            parent.attachChild(spatial);
        }
        return control;
    }
}

Добавление с помощью мастера

Вы можете создать новый мастер с помощью шаблона мастера в SDK (Создать Файл ▸ Разработка модулей ▸ Мастер). Действие, созданное шаблоном, может быть легко изменено на добавления Control или Spatial или для применения Инструмента(Tool). Обратите внимание, что здесь мы расширяем действие AbstractNewSpatial*Wizard*.

Хорошим примером является «Мастер Добавления SkyBox»:

@org.openide.util.lookup.ServiceProvider(service = NewSpatialAction.class)
public class AddSkyboxAction extends AbstractNewSpatialWizardAction {

    private WizardDescriptor.Panel[] panels;

    public AddSkyboxAction() {
        name = "Skybox..";
    }

    @Override
    protected Object showWizard(org.openide.nodes.Node node) {
        WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
        wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
        wizardDescriptor.setTitle("Skybox Wizard");
        Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
        dialog.setVisible(true);
        dialog.toFront();
        boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
        if (!cancelled) {
            return wizardDescriptor;
        }
        return null;
    }

    @Override
    protected Spatial doCreateSpatial(Node parent, Object properties) {
        if (properties != null) {
            return generateSkybox((WizardDescriptor) properties);
        }
        return null;
    }

    private Spatial generateSkybox(WizardDescriptor wiz) {
        if ((Boolean) wiz.getProperty("multipleTextures")) {
            Texture south = (Texture) wiz.getProperty("textureSouth");
            Texture north = (Texture) wiz.getProperty("textureNorth");
            Texture east = (Texture) wiz.getProperty("textureEast");
            Texture west = (Texture) wiz.getProperty("textureWest");
            Texture top = (Texture) wiz.getProperty("textureTop");
            Texture bottom = (Texture) wiz.getProperty("textureBottom");
            Vector3f normalScale = (Vector3f) wiz.getProperty("normalScale");
            return SkyFactory.createSky(pm, west, east, north, south, top, bottom, normalScale);
        } else {
            Texture textureSingle = (Texture) wiz.getProperty("textureSingle");
            Vector3f normalScale = (Vector3f) wiz.getProperty("normalScale");
            boolean useSpheremap = (Boolean) wiz.getProperty("useSpheremap");
            return SkyFactory.createSky(pm, textureSingle, normalScale, useSpheremap);
        }
    }

    /**
     * Инициализируем панели, представляющих отдельные шаги мастера, и 
     * задаём различные свойства, влияющие на внешний вид мастера.
     */
    private WizardDescriptor.Panel[] getPanels() {
        if (panels == null) {
            panels = new WizardDescriptor.Panel[]{
                        new SkyboxWizardPanel1(),
                        new SkyboxWizardPanel2()
                    };
            String[] steps = new String[panels.length];
            for (int i = 0; i < panels.length; i++) {
                Component c = panels[i].getComponent();
                // Название шага по умолчанию к названию компонента панели.
                // В основном полезно для получения названия выбранной цели в
                // списке шагов.
                steps[i] = c.getName();
                if (c instanceof JComponent) { // предположим, что компоненты Swing
                    JComponent jc = (JComponent) c;
                    // Зададим номер шага компонента
                    // TODO при использовании org.openide.dialogs >= 7.8, может использовать WizardDescriptor.PROP_*:
                    jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
                    // Зададим название шага для панели
                    jc.putClientProperty("WizardPanel_contentData", steps);
                    // Включим создание подзаголовка на каждом шаге
                    jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
                    // Покажем шаги с левой стороны с фоновым изображением
                    jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
                    // Включим нумерацию всех шагов
                    jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
                }
            }
        }
        return panels;
    }
}
Абстрактные spatial и control, реализуют действия отмены/повтора автоматически, для ToolActions, и вы должны реализовать их самостоятельно.

Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Добавить комментарий

jMonkeyEngine.ru © 2017. Все права сохранены.