Skip to content

Commit

Permalink
Set mesh or texture to nothing (#232)
Browse files Browse the repository at this point in the history
Work on #225 

# New mesh selection process

1. `Add` a MeshInstance.
2. Click the MeshInstance.
3. Click the `...` selection button 
4. Click `Load Mesh` and locate a mesh in your file system. Mesh Chooser
Dialog is same as before.
5. Click to select your newly loaded mesh. Note all loaded meshes will
appear in this list.
6. Click `Clear` to set the selection to nothing.
7. Click `OK` to confirm your selection.
8. If you have selected a mesh, it will appear at the world origin. 

- If you have moved the MeshInstance it may be somewhere else.  
- If you have `3D View > Render > Meshes` turned off it may not be
visible.


![image](https://github.com/MarginallyClever/Robot-Overlord-App/assets/1464454/e88fb8ec-99f1-46c5-a538-ce4b72d6cb9d)
  • Loading branch information
i-make-robots authored Jan 7, 2024
2 parents 9350f31 + 8c3f893 commit d963707
Show file tree
Hide file tree
Showing 34 changed files with 436 additions and 85 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.marginallyclever</groupId>
<artifactId>RobotOverlord</artifactId>
<version>2.100.0</version>
<version>2.101.0</version>
<name>Robot Overlord</name>
<description>A friendly 3D user interface for controlling robots.</description>
<url>https://www.marginallyclever.com/</url>
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/marginallyclever/ro3/Registry.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.marginallyclever.ro3;

import com.marginallyclever.ro3.listwithevents.ListWithEvents;
import com.marginallyclever.ro3.mesh.MeshFactory;
import com.marginallyclever.ro3.node.nodes.*;
import com.marginallyclever.ro3.node.Node;
import com.marginallyclever.ro3.node.nodes.marlinrobotarm.MarlinRobotArm;
Expand All @@ -11,7 +12,6 @@
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
Expand All @@ -21,6 +21,7 @@ public class Registry {

public static final EventListenerList listeners = new EventListenerList();
public static final TextureFactory textureFactory = new TextureFactory();
public static final MeshFactory meshFactory = new MeshFactory();
public static final Factory<Node> nodeFactory = new Factory<>(Node.class);
private static Node scene = new Node("Scene");
public static final ListWithEvents<Camera> cameras = new ListWithEvents<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.apps.commands.ImportScene;
import com.marginallyclever.ro3.node.nodes.MeshInstance;
import com.marginallyclever.ro3.mesh.load.MeshFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -68,13 +67,13 @@ public void drop(DropTargetDropEvent event) {

private boolean importMesh(String absolutePath) {
logger.debug("drag importMesh {}",absolutePath);
if(!MeshFactory.canLoad(absolutePath)) {
if(!Registry.meshFactory.canLoad(absolutePath)) {
logger.info("can't load file.");
return false;
}

MeshInstance meshInstance = new MeshInstance(getFilenameWithoutExtensionFromPath(absolutePath));
meshInstance.setMesh(MeshFactory.load(absolutePath));
meshInstance.setMesh(Registry.meshFactory.load(absolutePath));
Registry.getScene().addChild(meshInstance);
logger.error("done.");
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.marginallyclever.convenience.helpers.FileHelper;
import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.apps.RO3Frame;
import com.marginallyclever.ro3.mesh.load.MeshFactory;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -91,7 +90,7 @@ public void commitExport(String absolutePath) {
JSONObject json = Registry.getScene().toJSON();

List<String> sources = Registry.textureFactory.getAllSourcesForExport();
sources.addAll(MeshFactory.getAllSourcesForExport());
sources.addAll(Registry.meshFactory.getAllSourcesForExport());

createZipAndAddAssets(absolutePath, json.toString(), sources);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package com.marginallyclever.ro3.apps.dialogs;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.Objects;

import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.listwithevents.ItemAddedListener;
import com.marginallyclever.ro3.listwithevents.ItemRemovedListener;
import com.marginallyclever.ro3.mesh.Mesh;
import com.marginallyclever.ro3.mesh.MeshFactory;

/**
* <p>The {@link MeshChooserDialog} class allows for selecting a {@link com.marginallyclever.ro3.mesh.Mesh}
* that has been previously loaded by the {@link MeshFactory}.
* This class also provides access to the {@link MeshFactoryDialog} for loading additional meshes.</p>
* <p>TODO In the future it would be nice to count references and unload it when no longer needed.</p>
*/
public class MeshChooserDialog extends JPanel implements ItemAddedListener<Mesh>, ItemRemovedListener<Mesh> {
private final DefaultListModel<Mesh> model = new DefaultListModel<>();
private final JList<Mesh> list = new JList<>();
private final JToolBar toolBar = new JToolBar();
private Mesh selectedItem;
private String viewType;

public MeshChooserDialog() {
super(new BorderLayout());

setupToolbar();
setupMeshList();

var clearButton = new JButton("Clear");
clearButton.addActionListener(e -> setSelectedItem(null));

add(toolBar, BorderLayout.NORTH);
add(new JScrollPane(list), BorderLayout.CENTER);
add(clearButton, BorderLayout.SOUTH);
}

public void setSelectedItem(Mesh mesh) {
selectedItem = mesh;
if(mesh==null) {
list.clearSelection();
} else {
list.setSelectedValue(mesh, true);
}
}

private void setupToolbar() {
toolBar.add(new JButton(new AbstractAction() {
{
putValue(Action.NAME, "Load Mesh");
putValue(Action.SHORT_DESCRIPTION, "Load a mesh from a file.");
putValue(Action.SMALL_ICON, new ImageIcon(Objects.requireNonNull(getClass().getResource(
"/com/marginallyclever/ro3/apps/actions/icons8-load-16.png"))));
}

@Override
public void actionPerformed(ActionEvent e) {
MeshFactoryDialog meshFactoryDialog = new MeshFactoryDialog();
int result = meshFactoryDialog.run();
if (result == JFileChooser.APPROVE_OPTION) {
Mesh mesh = meshFactoryDialog.getMesh();
setSelectedItem(mesh);
}
}
}));

/*
String[] viewTypes = {"List View", "Detail View", "Thumbnail View"};
JComboBox<String> viewTypeComboBox = new JComboBox<>(viewTypes);
viewTypeComboBox.addActionListener(e -> {
viewType = (String) viewTypeComboBox.getSelectedItem();
updateView();
});
toolbar.add(viewTypeComboBox);
*/
}

private void setupMeshList() {
list.setCellRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Mesh mesh = (Mesh) value;
String text = mesh.getSourceName() + " (" + mesh.getNumVertices() + " vertices)";
return super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus);
}
});

for (Mesh mesh : Registry.meshFactory.getPool().getList()) {
model.addElement(mesh);
}
list.setModel(model);
list.addListSelectionListener(e -> selectedItem = list.getSelectedValue());
}

@Override
public void addNotify() {
super.addNotify();
Registry.meshFactory.getPool().addItemAddedListener(this);
Registry.meshFactory.getPool().addItemRemovedListener(this);
}

@Override
public void removeNotify() {
super.removeNotify();
Registry.meshFactory.getPool().removeItemAddedListener(this);
Registry.meshFactory.getPool().removeItemRemovedListener(this);
}

private void updateView() {
// Update the list of meshes based on the selected view type
// This could involve changing the ListCellRenderer of the JList
// For example, for the "Thumbnail View", you could display a small preview of each mesh
}

public Mesh getSelectedItem() {
return selectedItem;
}

@Override
public void itemAdded(Object source, Mesh item) {
model.addElement(item);
}

@Override
public void itemRemoved(Object source, Mesh item) {
model.removeElement(item);
}

/**
* Run the selection as a dialog.
* @param parent the parent component for the dialog.
* @return JFileChooser.APPROVE_OPTION or JFileChooser.CANCEL_OPTION. return type is int because this is a
* JFileChooser replacement. It is consistent with {@link MeshFactoryDialog} and {@link TextureFactoryDialog}.
*/
public int run(JComponent parent) {
int result = JOptionPane.showOptionDialog(
parent,
this,
"Select",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE,
new ImageIcon(Objects.requireNonNull(getClass().getResource(
"/com/marginallyclever/ro3/apps/dialogs/icons8-mesh-16.png"))),
null,
null);
if(result == JOptionPane.OK_OPTION) {
return JFileChooser.APPROVE_OPTION;
}
return JFileChooser.CANCEL_OPTION;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.marginallyclever.ro3.apps.dialogs;

import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.apps.shared.PersistentJFileChooser;
import com.marginallyclever.ro3.mesh.Mesh;
import com.marginallyclever.ro3.mesh.load.MeshFactory;
import com.marginallyclever.ro3.mesh.MeshFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -16,14 +17,14 @@
*/
public class MeshFactoryDialog {
private static final Logger logger = LoggerFactory.getLogger(MeshFactoryDialog.class);
private static final JFileChooser chooser = new PersistentJFileChooser();
private final PersistentJFileChooser chooser = new PersistentJFileChooser();
private Mesh lastMeshLoaded;

public MeshFactoryDialog() {
super();

List<FileFilter> filters = MeshFactory.getAllExtensions();
if (filters.isEmpty()) throw new RuntimeException("No MeshFactory filters found?!");
List<FileFilter> filters = Registry.meshFactory.getAllExtensions();
if (filters.isEmpty()) throw new RuntimeException("No filters found?!");
if (filters.size() == 1) {
chooser.setFileFilter(filters.get(0));
} else {
Expand All @@ -34,15 +35,14 @@ public MeshFactoryDialog() {
}

/**
*
* @return JFileChooser.APPROVE_OPTION or return JFileChooser.CANCEL_OPTION
* @return JFileChooser.APPROVE_OPTION or JFileChooser.CANCEL_OPTION
*/
public int run() {
int returnVal = chooser.showDialog(SwingUtilities.getWindowAncestor(chooser), "Select");
int returnVal = chooser.showOpenDialog(SwingUtilities.getWindowAncestor(chooser));
if(returnVal == JFileChooser.APPROVE_OPTION) {
String absPath = chooser.getSelectedFile().getAbsolutePath();
try {
lastMeshLoaded = MeshFactory.load(absPath);
lastMeshLoaded = Registry.meshFactory.load(absPath);
} catch(Exception e) {
logger.error("Failed to load from "+absPath,e);
returnVal = JFileChooser.CANCEL_OPTION;
Expand Down
Loading

0 comments on commit d963707

Please sign in to comment.