Skip to content

Commit

Permalink
added saving and loading complex scenes
Browse files Browse the repository at this point in the history
  • Loading branch information
i-make-robots committed Dec 18, 2023
1 parent bc5b821 commit 084bf55
Show file tree
Hide file tree
Showing 15 changed files with 172 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -803,20 +803,20 @@ public static double[][] createMatrix(int rows, int cols) {
public static double [] matrix4dToArray(Matrix4d m) {
return new double[] {
m.m00,
m.m10,
m.m20,
m.m30,
m.m01,
m.m11,
m.m21,
m.m31,
m.m02,
m.m12,
m.m22,
m.m32,
m.m03,
m.m10,
m.m11,
m.m12,
m.m13,
m.m20,
m.m21,
m.m22,
m.m23,
m.m30,
m.m31,
m.m32,
m.m33,
};
}
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/com/marginallyclever/ro3/Factory.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public Category(String name,Supplier<T> supplier) {
this.supplier = supplier;
}

public Category(Supplier<T> supplier) {
this.name = supplier.get().getClass().getSimpleName();
this.supplier = supplier;
}

public void add(Category<T> c) {
children.add(c);
}
Expand All @@ -51,10 +56,11 @@ public Supplier<T> getSupplierFor(String path) {
List<Category<T>> toCheck = new ArrayList<>(root.children);
while(!toCheck.isEmpty()) {
Category<T> current = toCheck.remove(0);
toCheck.addAll(current.children);

if(current.name.equals(path)) {
return current.supplier;
}
toCheck.addAll(current.children);
}

return null;
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/com/marginallyclever/ro3/RO3Frame.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
import ModernDocking.ext.ui.DockingUI;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatLightLaf;
import com.marginallyclever.ro3.actions.LoadScene;
import com.marginallyclever.ro3.actions.NewScene;
import com.marginallyclever.ro3.actions.SaveScene;
import com.marginallyclever.ro3.actions.*;
import com.marginallyclever.ro3.logpanel.LogPanel;
import com.marginallyclever.ro3.node.NodeDetailView;
import com.marginallyclever.ro3.node.nodetreeview.NodeTreeView;
Expand Down Expand Up @@ -143,8 +141,12 @@ public void actionPerformed(java.awt.event.ActionEvent e) {
private JMenu buildFileMenu() {
JMenu menuFile = new JMenu("File");
menuFile.add(new JMenuItem(new NewScene()));
menuFile.add(new JSeparator());
menuFile.add(new JMenuItem(new LoadScene()));
menuFile.add(new JMenuItem(new SaveScene()));
menuFile.add(new JSeparator());
menuFile.add(new JMenuItem(new ImportScene()));
menuFile.add(new JMenuItem(new ExportScene()));
// TODO load recent scene
menuFile.add(new JSeparator());
JMenuItem quit = new JMenuItem(new AbstractAction("Quit") {
Expand Down
16 changes: 10 additions & 6 deletions src/main/java/com/marginallyclever/ro3/Registry.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ public class Registry {
public static EventListenerList listeners = new EventListenerList();

public static void start() {
Factory.Category<Node> nodule = new Factory.Category<>("Node", null);
Factory.Category<Node> nodule = new Factory.Category<>( "Node", null );
nodeFactory.getRoot().add(nodule);
Factory.Category<Node> pose = new Factory.Category<>("Pose", Pose::new);
pose.add(new Factory.Category<>("MeshInstance", MeshInstance::new ));
pose.add(new Factory.Category<>("Camera", Camera::new ));
Factory.Category<Node> pose = new Factory.Category<>( Pose::new );
pose.add(new Factory.Category<>( MeshInstance::new ));
pose.add(new Factory.Category<>( Camera::new ));
nodule.add(pose);
nodule.add(new Factory.Category<>("Material", Material::new ));
nodule.add(new Factory.Category<>("DH Parameter", DHParameter::new ));
nodule.add(new Factory.Category<>( Material::new ));
nodule.add(new Factory.Category<>( DHParameter::new ));

cameras.add(new Camera("Camera 1"));

Expand All @@ -51,6 +51,10 @@ public static void removeSceneChangeListener(SceneChangeListener listener) {
}

public static void setScene(Node newScene) {
for (SceneChangeListener listener : listeners.getListeners(SceneChangeListener.class)) {
listener.beforeSceneChange(newScene);
}

scene = newScene;

for (SceneChangeListener listener : listeners.getListeners(SceneChangeListener.class)) {
Expand Down
58 changes: 58 additions & 0 deletions src/main/java/com/marginallyclever/ro3/actions/ExportScene.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.marginallyclever.ro3.actions;

import com.marginallyclever.robotoverlord.RobotOverlord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;

/**
* Export the scene to a file for sharing on another computer. This is not the same as saving the scene.
* Exporting the scene will save the scene and all the assets it uses to a single file.
*/
public class ExportScene extends AbstractAction {
private static final Logger logger = LoggerFactory.getLogger(SaveScene.class);
private static final JFileChooser chooser = new JFileChooser();

public ExportScene() {
super("Export Scene");
}

/**
* Invoked when an action occurs.
*
* @param e the event to be processed
*/
@Override
public void actionPerformed(ActionEvent e) {
chooser.setFileFilter(RobotOverlord.FILE_FILTER);
Component source = (Component) e.getSource();
JFrame parentFrame = (JFrame)SwingUtilities.getWindowAncestor(source);

if (chooser.showSaveDialog(parentFrame) == JFileChooser.APPROVE_OPTION) {
// check before overwriting.
File selectedFile = chooser.getSelectedFile();
if (selectedFile.exists()) {
int response = JOptionPane.showConfirmDialog(null,
"Do you want to replace the existing file?",
"Confirm Overwrite",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (response == JOptionPane.NO_OPTION) {
return;
}
}

String absolutePath = chooser.getSelectedFile().getAbsolutePath();
exportScene(absolutePath);
}
}

private void exportScene(String absolutePath) {
logger.info("Export scene to {}", absolutePath);
logger.error("Not implemented yet.");
}
}
17 changes: 9 additions & 8 deletions src/main/java/com/marginallyclever/ro3/actions/ImportScene.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.marginallyclever.ro3.Registry;
import com.marginallyclever.ro3.node.Node;
import com.marginallyclever.robotoverlord.RobotOverlord;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -12,13 +13,15 @@
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
* Load a Scene into the existing Scene.
*/
public class ImportScene extends AbstractAction {
private static final JFileChooser chooser = new JFileChooser();
private static final Logger logger = LoggerFactory.getLogger(ImportScene.class);
private static final JFileChooser chooser = new JFileChooser();

public ImportScene() {
super("Import Scene");
Expand All @@ -43,16 +46,14 @@ public void actionPerformed(ActionEvent e) {
private void loadIntoScene(File selectedFile) {
logger.info("Import scene from {}",selectedFile.getAbsolutePath());

// Create an ObjectMapper instance
ObjectMapper mapper = new ObjectMapper();

try {
// Read the JSON file and convert it into a Node object
Node loaded = mapper.readValue(selectedFile, Node.class);
String content = new String(Files.readAllBytes(Paths.get(selectedFile.getAbsolutePath())));
JSONObject json = new JSONObject(content);
Node loaded = new Node("Scene");
loaded.fromJSON(json);

// option 1: add the loaded scene to the current scene.
// Add the loaded scene to the current scene.
Registry.getScene().addChild(loaded);
// TODO option 2: copy the loaded scene into the currently selected Nodes of the NodeTreeView?
} catch (IOException e) {
logger.error("Error loading scene from JSON", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import java.nio.file.Paths;

public class LoadScene extends AbstractAction {
private static final JFileChooser chooser = new JFileChooser();
private static final Logger logger = LoggerFactory.getLogger(LoadScene.class);
private static final JFileChooser chooser = new JFileChooser();

public LoadScene() {
super("Load Scene");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import java.io.IOException;

public class SaveScene extends AbstractAction {
private static final JFileChooser chooser = new JFileChooser();
private static final Logger logger = LoggerFactory.getLogger(SaveScene.class);
private static final JFileChooser chooser = new JFileChooser();

public SaveScene() {
super("Save Scene");
Expand Down
4 changes: 0 additions & 4 deletions src/main/java/com/marginallyclever/ro3/node/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,6 @@ private void fireAttachEvent(Node child) {
for(NodeAttachListener listener : listeners.getListeners(NodeAttachListener.class)) {
listener.nodeAttached(child);
}

for(Node grandchild : child.children) {
fireAttachEvent(grandchild);
}
}

private void fireDetachEvent(Node child) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.marginallyclever.ro3.node.Node;
import com.marginallyclever.robotoverlord.swing.CollapsiblePanel;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -14,7 +15,7 @@

public class DHParameter extends Node {
private static final Logger logger = LoggerFactory.getLogger(DHParameter.class);
double d=0,r=0,alpha=0,theta=0;
private transient double d=0,r=0,alpha=0,theta=0;

public DHParameter() {
super("DH Parameter");
Expand Down Expand Up @@ -120,4 +121,14 @@ public void getComponents(List<JComponent> list) {

super.getComponents(list);
}

@Override
public JSONObject toJSON() {
return super.toJSON();
}

@Override
public void fromJSON(JSONObject from) {
super.fromJSON(from);
}
}
15 changes: 15 additions & 0 deletions src/main/java/com/marginallyclever/ro3/node/nodes/Material.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.marginallyclever.ro3.texture.TextureFactoryPanel;
import com.marginallyclever.ro3.texture.TextureWithMetadata;
import com.marginallyclever.robotoverlord.swing.CollapsiblePanel;
import org.json.JSONObject;

import javax.swing.*;
import java.awt.*;
Expand Down Expand Up @@ -72,4 +73,18 @@ private void setTextureButtonLabel(JButton button) {
public TextureWithMetadata getTexture() {
return texture;
}

@Override
public JSONObject toJSON() {
JSONObject json = super.toJSON();
json.put("texture",texture.getSource());
return json;
}

@Override
public void fromJSON(JSONObject from) {
super.fromJSON(from);
String textureSource = from.getString("texture");
texture = Registry.textureFactory.load(textureSource);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.marginallyclever.robotoverlord.swing.CollapsiblePanel;
import com.marginallyclever.robotoverlord.systems.render.mesh.Mesh;
import com.marginallyclever.robotoverlord.systems.render.mesh.MeshSmoother;
import com.marginallyclever.robotoverlord.systems.render.mesh.load.MeshFactory;
import org.json.JSONObject;

import javax.swing.*;
import java.awt.*;
Expand Down Expand Up @@ -62,4 +64,21 @@ private void setMeshButtonLabel(JButton button) {
public Mesh getMesh() {
return mesh;
}

@Override
public JSONObject toJSON() {
JSONObject json = super.toJSON();
if(mesh!=null) {
json.put("mesh", mesh.getSourceName());
}
return json;
}

@Override
public void fromJSON(JSONObject from) {
super.fromJSON(from);
if(from.has("mesh")) {
mesh = MeshFactory.load(from.getString("mesh"));
}
}
}
23 changes: 23 additions & 0 deletions src/main/java/com/marginallyclever/ro3/node/nodes/Pose.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.marginallyclever.convenience.helpers.MatrixHelper;
import com.marginallyclever.ro3.node.Node;
import com.marginallyclever.robotoverlord.swing.CollapsiblePanel;
import org.json.JSONArray;
import org.json.JSONObject;

import javax.swing.*;
import javax.swing.text.NumberFormatter;
Expand Down Expand Up @@ -142,4 +144,25 @@ public void setPosition(Vector3d p) {
local.m13 = p.y;
local.m23 = p.z;
}

@Override
public JSONObject toJSON() {
JSONObject json = super.toJSON();

double[] localArray = MatrixHelper.matrix4dToArray(local);
json.put("local", new JSONArray(localArray));
return json;
}

@Override
public void fromJSON(JSONObject from) {
super.fromJSON(from);
JSONArray localArray = from.getJSONArray("local");
double[] localData = new double[16];
for (int i = 0; i < 16; i++) {
localData[i] = localArray.getDouble(i);
}

local.set(localData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ public NodeTreeView(String tabText) {

buildMenuBar();

JScrollPane scroll = new JScrollPane();
scroll.setViewportView(tree);
add(scroll, BorderLayout.CENTER);
add(tree, BorderLayout.CENTER);
add(menuBar, BorderLayout.NORTH);
}

Expand Down Expand Up @@ -255,6 +253,7 @@ public void beforeSceneChange(Node oldScene) {
public void afterSceneChange(Node newScene) {
logger.debug("afterSceneChange");
listenTo(newScene);
treeModel.removeAllChildren();
treeModel.setUserObject(newScene);
((DefaultTreeModel) tree.getModel()).nodeStructureChanged(treeModel.getRoot());
scanTree(newScene);
Expand Down
Loading

0 comments on commit 084bf55

Please sign in to comment.