diff --git a/2023-10-14.png b/2023-10-14.png deleted file mode 100644 index 567d95447..000000000 Binary files a/2023-10-14.png and /dev/null differ diff --git a/README.md b/README.md index 6b6f1ee15..d221d4fad 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![workflow](https://github.com/MarginallyClever/Robot-Overlord-App/actions/workflows/main.yml/badge.svg) -![Preview image](https://github.com/MarginallyClever/Robot-Overlord-App/blob/master/2023-10-14.png) +![Preview image](https://github.com/MarginallyClever/Robot-Overlord-App/blob/master/Screenshot 2023-12-23 120520.png) # Robot Overlord # @@ -18,10 +18,6 @@ Some of the robots it controls are: - Spidee, a 6 legged crab-style walker. - Dog Robot, a generic 4 legged walker. -# Video - -[![Click to watch](README.PNG)](https://www.youtube.com/watch?v=QGYz506W1Pk) - # Why [Our philosophy about Robot Overlord](https://github.com/MarginallyClever/Robot-Overlord-App/wiki/Why-Robot-Overlord%3F). @@ -35,20 +31,10 @@ Steps to get started: Then you should be able to run the application. -## Usage - -Camera movement: middle mouse button. Click and drag to move forward and back. shift+drag to orbit. roll the middle mouse to change the orbit distance. - -Double click any entity in the entityManager to select it, or use the entity panel in the top right. - -For robot arms, select an arm and then open the control panel. - ## More If you're reading this, make an issue ticket and we will respond to it promptly. -![Preview image](https://github.com/MarginallyClever/Robot-Overlord-App/blob/master/Screenshot%202023-05-04%20154621.png) - ## Icons Many app icons provided by http://icons8.com. \ No newline at end of file diff --git a/Screenshot 2023-05-04 154621.png b/Screenshot 2023-05-04 154621.png deleted file mode 100644 index b85f714e3..000000000 Binary files a/Screenshot 2023-05-04 154621.png and /dev/null differ diff --git a/Screenshot 2023-12-23 120520.png b/Screenshot 2023-12-23 120520.png new file mode 100644 index 000000000..aaef6ea6a Binary files /dev/null and b/Screenshot 2023-12-23 120520.png differ diff --git a/pom.xml b/pom.xml index 03a7fd03e..7a62c86d6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.marginallyclever RobotOverlord - 2.90.0 + 2.92.0 Robot Overlord A friendly 3D user interface for controlling robots. http://www.marginallyclever.com/ diff --git a/src/main/java/com/marginallyclever/ro3/Registry.java b/src/main/java/com/marginallyclever/ro3/Registry.java index 08daa3fb7..89ceaf5ac 100644 --- a/src/main/java/com/marginallyclever/ro3/Registry.java +++ b/src/main/java/com/marginallyclever/ro3/Registry.java @@ -4,11 +4,10 @@ import com.marginallyclever.ro3.node.nodes.*; import com.marginallyclever.ro3.node.Node; import com.marginallyclever.ro3.node.nodes.marlinrobotarm.MarlinRobotArm; -import com.marginallyclever.ro3.render.RenderPass; -import com.marginallyclever.ro3.render.renderpasses.*; import com.marginallyclever.ro3.texture.TextureFactory; import javax.swing.event.EventListenerList; +import javax.vecmath.Vector3d; import java.util.ArrayList; import java.util.List; @@ -20,7 +19,6 @@ public class Registry { public static EventListenerList listeners = new EventListenerList(); public static TextureFactory textureFactory = new TextureFactory(); public static final Factory nodeFactory = new Factory<>(Node.class); - public static ListWithEvents renderPasses = new ListWithEvents<>(); private static Node scene = new Node("Scene"); public static ListWithEvents cameras = new ListWithEvents<>(); private static Camera activeCamera = null; @@ -37,14 +35,6 @@ public static void start() { Factory.Category pose = nodule.add("Pose", Pose::new); pose.add("Camera", Camera::new); - renderPasses.add(new DrawBackground()); - renderPasses.add(new DrawMeshes()); - renderPasses.add(new DrawBoundingBoxes()); - renderPasses.add(new DrawCameras()); - renderPasses.add(new DrawDHParameters()); - renderPasses.add(new DrawHingeJoints()); - renderPasses.add(new DrawPoses()); - reset(); } @@ -52,7 +42,12 @@ public static void reset() { // reset camera List toRemove = new ArrayList<>(cameras.getList()); for(Camera c : toRemove) cameras.remove(c); - cameras.add(new Camera("Camera 1")); + Camera first = new Camera("Camera 1"); + cameras.add(first); + double v = Math.sqrt(Math.pow(50,2)/3d); // match the viewport default orbit distance. + first.setPosition(new Vector3d(v,v,v)); + first.lookAt(new Vector3d(0,0,0)); + // reset scene List toRemove2 = new ArrayList<>(scene.getChildren()); diff --git a/src/main/java/com/marginallyclever/ro3/apps/RO3Frame.java b/src/main/java/com/marginallyclever/ro3/apps/RO3Frame.java index 9561364a9..1c449c398 100644 --- a/src/main/java/com/marginallyclever/ro3/apps/RO3Frame.java +++ b/src/main/java/com/marginallyclever/ro3/apps/RO3Frame.java @@ -16,8 +16,8 @@ import com.marginallyclever.ro3.apps.nodedetailview.NodeDetailView; import com.marginallyclever.ro3.apps.nodetreeview.NodeTreeView; import com.marginallyclever.ro3.apps.webcampanel.WebCamPanel; -import com.marginallyclever.ro3.render.OpenGLPanel; -import com.marginallyclever.ro3.render.Viewport; +import com.marginallyclever.ro3.apps.render.OpenGLPanel; +import com.marginallyclever.ro3.apps.render.Viewport; import com.marginallyclever.robotoverlord.RobotOverlord; import com.marginallyclever.robotoverlord.swing.actions.AboutAction; import org.slf4j.Logger; diff --git a/src/main/java/com/marginallyclever/ro3/apps/RecentFilesMenu.java b/src/main/java/com/marginallyclever/ro3/apps/RecentFilesMenu.java index f95f58c2b..0aeb25850 100644 --- a/src/main/java/com/marginallyclever/ro3/apps/RecentFilesMenu.java +++ b/src/main/java/com/marginallyclever/ro3/apps/RecentFilesMenu.java @@ -91,7 +91,7 @@ private void updateRecentFilesMenu() { public void removePath(String filePath) { recentFiles.remove(filePath); - updateRecentFilesMenu(); + saveToPreferences(); } /** diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/AddNode.java b/src/main/java/com/marginallyclever/ro3/apps/actions/AddNode.java index 38d151d99..d0b685bc9 100644 --- a/src/main/java/com/marginallyclever/ro3/apps/actions/AddNode.java +++ b/src/main/java/com/marginallyclever/ro3/apps/actions/AddNode.java @@ -20,10 +20,10 @@ public class AddNode extends AbstractAction { public AddNode(NodeTreeView treeView) { super(); + this.treeView = treeView; putValue(Action.NAME,"Add"); putValue(SMALL_ICON,new ImageIcon(Objects.requireNonNull(getClass().getResource("icons8-add-16.png")))); putValue(SHORT_DESCRIPTION,"Add a new instance of a Node to every selected branches of the tree."); - this.treeView = treeView; } /** diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/ExportScene.java b/src/main/java/com/marginallyclever/ro3/apps/actions/ExportScene.java index 7b81b9015..0b431fc8d 100644 --- a/src/main/java/com/marginallyclever/ro3/apps/actions/ExportScene.java +++ b/src/main/java/com/marginallyclever/ro3/apps/actions/ExportScene.java @@ -1,28 +1,37 @@ package com.marginallyclever.ro3.apps.actions; -import com.marginallyclever.robotoverlord.RobotOverlord; +import com.marginallyclever.convenience.helpers.FileHelper; +import com.marginallyclever.ro3.Registry; +import com.marginallyclever.robotoverlord.systems.render.mesh.load.MeshFactory; +import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + +import java.io.*; +import java.util.*; import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.awt.event.ActionEvent; -import java.io.File; -import java.util.Objects; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** *

Export the scene and all the assets used to a single file for sharing on another computer. * This is not the same as saving the scene.

*/ public class ExportScene extends AbstractAction { - private static final Logger logger = LoggerFactory.getLogger(SaveScene.class); - private static final JFileChooser chooser = new JFileChooser(); + private final Logger logger = LoggerFactory.getLogger(ExportScene.class); + public static final FileNameExtensionFilter ZIP_FILTER = new FileNameExtensionFilter("ZIP files", "zip"); + private final JFileChooser chooser = new JFileChooser(); public ExportScene() { super(); putValue(Action.NAME,"Export Scene"); putValue(Action.SMALL_ICON,new ImageIcon(Objects.requireNonNull(getClass().getResource("icons8-export-16.png")))); - putValue(SHORT_DESCRIPTION,"Export the scene and all the assets used to a single file."); + putValue(SHORT_DESCRIPTION,"Export the scene and all the assets used to a ZIP file."); } /** @@ -32,15 +41,29 @@ public ExportScene() { */ @Override public void actionPerformed(ActionEvent e) { - chooser.setFileFilter(RobotOverlord.FILE_FILTER); + chooser.setFileFilter(ZIP_FILTER); Component source = (Component) e.getSource(); JFrame parentFrame = (JFrame)SwingUtilities.getWindowAncestor(source); + // make sure to add the extension if the user doesn't + chooser.addActionListener((e2) -> { + if (JFileChooser.APPROVE_SELECTION.equals(e2.getActionCommand())) { + String[] extensions = ZIP_FILTER.getExtensions(); + File f = chooser.getSelectedFile(); + String fname = f.getName().toLowerCase(); + boolean matches = Arrays.stream(extensions).anyMatch((ext) -> fname.toLowerCase().endsWith("." + ext)); + if (!matches) { + f = new File(f.getPath() + "." + extensions[0]); // append the first extension from ZIP_FILTER + chooser.setSelectedFile(f); + } + } + }); + if (chooser.showSaveDialog(parentFrame) == JFileChooser.APPROVE_OPTION) { // check before overwriting. File selectedFile = chooser.getSelectedFile(); if (selectedFile.exists()) { - int response = JOptionPane.showConfirmDialog(null, + int response = JOptionPane.showConfirmDialog(SwingUtilities.getWindowAncestor(source), "Do you want to replace the existing file?", "Confirm Overwrite", JOptionPane.YES_NO_OPTION, @@ -51,12 +74,87 @@ public void actionPerformed(ActionEvent e) { } String absolutePath = chooser.getSelectedFile().getAbsolutePath(); - exportScene(absolutePath); + commitExport(absolutePath); } } - private void exportScene(String absolutePath) { - logger.info("Export scene to {}", absolutePath); - logger.error("Not implemented yet."); + private void commitExport(String absolutePath) { + logger.info("Exporting to {}", absolutePath); + + JSONObject json = Registry.getScene().toJSON(); + + List sources = Registry.textureFactory.getAllSourcesForExport(); + sources.addAll(MeshFactory.getAllSourcesForExport()); + + createZipAndAddAssets(absolutePath, json.toString(), sources); + + logger.error("done."); + } + + private void createZipAndAddAssets(String outputZipFile, String json, List sources) { + // for remembering unique asset names + Map pathMapping = new HashMap<>(); + + String rootFolderName = nameWithoutExtension(new File(outputZipFile)); + String sceneName = rootFolderName+ ".ro"; + String newSceneName = rootFolderName+"/"+sceneName; + pathMapping.put(sceneName,newSceneName); // reserve this name + + try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outputZipFile))) { + for( String originalPath : sources ) { + String newName = rootFolderName + "/" + createUniqueName(originalPath, pathMapping); + addFileToZip(originalPath, newName, zos); + pathMapping.put(originalPath, newName); + } + + // Modify JSON string + String modifiedJson = replacePathsInJson(json, pathMapping); + // Add modified JSON string to zip + zos.putNextEntry(new ZipEntry(newSceneName)); + byte[] jsonBytes = modifiedJson.getBytes(); + zos.write(jsonBytes, 0, jsonBytes.length); + zos.closeEntry(); + } catch (FileNotFoundException e) { + logger.error("Could not open ZIP file.", e); + } catch (IOException e) { + logger.error("IO error.", e); + } + } + + private void addFileToZip(String filePath, String newName, ZipOutputStream zos) throws IOException { + zos.putNextEntry(new ZipEntry(newName)); + BufferedInputStream input = FileHelper.open(filePath); + byte[] bytes = input.readAllBytes(); + zos.write(bytes, 0, bytes.length); + zos.closeEntry(); + } + + private String createUniqueName(String originalPath, Map pathMapping) { + File file = new File(originalPath); + String name = file.getName(); + int counter = 1; + while (pathMapping.containsValue(name)) { + name = String.format("%s_%d.%s", nameWithoutExtension(file), counter++, extension(file)); + } + return name; + } + + private String nameWithoutExtension(File file) { + String fileName = file.getName(); + int dotIndex = fileName.lastIndexOf('.'); + return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex); + } + + private String extension(File file) { + String fileName = file.getName(); + int dotIndex = fileName.lastIndexOf('.'); + return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1); + } + + private String replacePathsInJson(String json, Map pathMapping) { + for (Map.Entry entry : pathMapping.entrySet()) { + json = json.replace(entry.getKey(), entry.getValue()); + } + return json; } } diff --git a/src/main/java/com/marginallyclever/ro3/apps/actions/SaveScene.java b/src/main/java/com/marginallyclever/ro3/apps/actions/SaveScene.java index f3ef2d409..5173d9bad 100644 --- a/src/main/java/com/marginallyclever/ro3/apps/actions/SaveScene.java +++ b/src/main/java/com/marginallyclever/ro3/apps/actions/SaveScene.java @@ -12,6 +12,7 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.Arrays; import java.util.Objects; /** diff --git a/src/main/java/com/marginallyclever/ro3/apps/logpanel/LogPanel.java b/src/main/java/com/marginallyclever/ro3/apps/logpanel/LogPanel.java index 5486419e2..36acb18e9 100644 --- a/src/main/java/com/marginallyclever/ro3/apps/logpanel/LogPanel.java +++ b/src/main/java/com/marginallyclever/ro3/apps/logpanel/LogPanel.java @@ -2,12 +2,22 @@ import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.FileAppender; import com.marginallyclever.ro3.apps.DockingPanel; import org.slf4j.LoggerFactory; import javax.swing.*; import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.lang.module.Configuration; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Iterator; import java.util.Locale; +import java.util.Objects; import java.util.Properties; /** @@ -15,11 +25,17 @@ * because it is created before {@link ModernDocking.app.Docking} is initialized. */ public class LogPanel extends JPanel { + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(LogPanel.class); private final JTextArea logArea = new JTextArea(); public LogPanel() { super(new BorderLayout()); + JToolBar toolbar = new JToolBar(); + toolbar.setFloatable(false); + toolbar.add(new JButton(new OpenLogFileLocation())); + add(toolbar, BorderLayout.NORTH); + logArea.setEditable(false); JScrollPane scroll = new JScrollPane(); scroll.setViewportView(logArea); @@ -27,16 +43,16 @@ public LogPanel() { // append log events to this panel LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); - Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); LogPanelAppender appender = new LogPanelAppender(this); appender.setContext(lc); - logger.addAppender(appender); + rootLogger.addAppender(appender); appender.start(); - reportSystemInfo(logger); + reportSystemInfo(); } - private void reportSystemInfo(Logger logger) { + private void reportSystemInfo() { logger.info("------------------------------------------------"); Properties p = System.getProperties(); for(String n : p.stringPropertyNames()) { diff --git a/src/main/java/com/marginallyclever/ro3/apps/logpanel/OpenLogFileLocation.java b/src/main/java/com/marginallyclever/ro3/apps/logpanel/OpenLogFileLocation.java new file mode 100644 index 000000000..6eadda805 --- /dev/null +++ b/src/main/java/com/marginallyclever/ro3/apps/logpanel/OpenLogFileLocation.java @@ -0,0 +1,57 @@ +package com.marginallyclever.ro3.apps.logpanel; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import ch.qos.logback.core.FileAppender; +import org.slf4j.LoggerFactory; + +import javax.swing.*; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.Objects; + +public class OpenLogFileLocation extends AbstractAction { + private final org.slf4j.Logger logger = LoggerFactory.getLogger(OpenLogFileLocation.class); + + public OpenLogFileLocation() { + super(); + putValue(Action.NAME,"Open Log File Location"); + putValue(Action.SMALL_ICON,new ImageIcon(Objects.requireNonNull(getClass().getResource("icons8-folder-16.png")))); + putValue(Action.SHORT_DESCRIPTION,"Open the folder containing the log file."); + } + + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + String logFileName = getLogFile(); + if(logFileName==null) { + logger.error("Failed to find log file."); + return; + } + + logger.debug("Opening log file location: "+logFileName); + try { + File file = new File(logFileName); + String absolutePath = file.getAbsolutePath(); + File parentDirectory = new File(absolutePath).getParentFile(); + Desktop.getDesktop().open(parentDirectory); + } catch(IOException ex) { + logger.error("Failed to open log file location.",ex); + } + } + + private String getLogFile() { + Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); + + for (Iterator> it = logger.iteratorForAppenders(); it.hasNext(); ) { + Appender appender = it.next(); + if (appender instanceof FileAppender) { + FileAppender fileAppender = (FileAppender) appender; + return fileAppender.getFile(); + } + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/marginallyclever/ro3/apps/nodeselector/NodeSelector.java b/src/main/java/com/marginallyclever/ro3/apps/nodeselector/NodeSelector.java index 607b61980..372451daf 100644 --- a/src/main/java/com/marginallyclever/ro3/apps/nodeselector/NodeSelector.java +++ b/src/main/java/com/marginallyclever/ro3/apps/nodeselector/NodeSelector.java @@ -19,14 +19,13 @@ public class NodeSelector extends JButton { private T subject; public NodeSelector(Class type) { - super(); - addActionListener((e)-> runSelectionDialog(type)); - setButtonLabel(); + this(type,null); } public NodeSelector(Class type, T subject) { super(); this.subject = subject; + setName("selector"); addActionListener((e)-> runSelectionDialog(type)); setButtonLabel(); } @@ -34,7 +33,7 @@ public NodeSelector(Class type, T subject) { private void runSelectionDialog(Class type) { NodeSelectionDialog panel = new NodeSelectionDialog<>(type); panel.setSubject(subject); - int result = JOptionPane.showConfirmDialog(NodeSelector.this, panel, "Select Node", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); + int result = JOptionPane.showConfirmDialog(NodeSelector.this, panel, "Select "+type.getSimpleName(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (result == JOptionPane.OK_OPTION) { T oldValue = subject; NodeSelector.this.subject = panel.getSelectedNode(); diff --git a/src/main/java/com/marginallyclever/ro3/render/OpenGLPanel.java b/src/main/java/com/marginallyclever/ro3/apps/render/OpenGLPanel.java similarity index 80% rename from src/main/java/com/marginallyclever/ro3/render/OpenGLPanel.java rename to src/main/java/com/marginallyclever/ro3/apps/render/OpenGLPanel.java index 6d4100763..2c26eb8c0 100644 --- a/src/main/java/com/marginallyclever/ro3/render/OpenGLPanel.java +++ b/src/main/java/com/marginallyclever/ro3/apps/render/OpenGLPanel.java @@ -1,4 +1,4 @@ -package com.marginallyclever.ro3.render; +package com.marginallyclever.ro3.apps.render; import com.jogamp.opengl.*; import com.jogamp.opengl.awt.GLJPanel; @@ -10,20 +10,16 @@ import org.slf4j.LoggerFactory; import java.awt.event.*; -import java.util.List; -import java.util.ArrayList; import javax.swing.*; import java.awt.*; /** * {@link OpenGLPanel} is a {@link DockingPanel} that contains a {@link GLJPanel} and an {@link FPSAnimator}. */ -public class OpenGLPanel extends JPanel implements GLEventListener, MouseListener, MouseMotionListener, MouseWheelListener, KeyListener { +public class OpenGLPanel extends JPanel implements GLEventListener, MouseListener, MouseMotionListener, MouseWheelListener { private static final Logger logger = LoggerFactory.getLogger(OpenGLPanel.class); protected GLJPanel glCanvas; - protected int canvasWidth, canvasHeight; private final FPSAnimator animator = new FPSAnimator(GraphicsPreferences.framesPerSecond.get()); - private final List listeners = new ArrayList<>(); public OpenGLPanel() { super(new BorderLayout()); @@ -48,7 +44,6 @@ public void addNotify() { glCanvas.addMouseListener(this); glCanvas.addMouseMotionListener(this); glCanvas.addMouseWheelListener(this); - glCanvas.addKeyListener(this); } @Override @@ -58,7 +53,6 @@ public void removeNotify() { glCanvas.removeMouseListener(this); glCanvas.removeMouseMotionListener(this); glCanvas.removeMouseWheelListener(this); - glCanvas.removeKeyListener(this); } private GLCapabilities getCapabilities() { @@ -80,21 +74,11 @@ private GLCapabilities getCapabilities() { } public void addGLEventListener(GLEventListener listener) { - listeners.add(listener); glCanvas.addGLEventListener(listener); } public void removeGLEventListener(GLEventListener listener) { glCanvas.removeGLEventListener(listener); - listeners.remove(listener); - } - - public int getGLEventListenersCount() { - return listeners.size(); - } - - public GLEventListener getGLEventListener(int index) { - return listeners.get(index); } public void stopAnimationSystem() { @@ -131,15 +115,12 @@ public void init(GLAutoDrawable glAutoDrawable) { @Override public void dispose(GLAutoDrawable glAutoDrawable) { logger.info("dispose"); - GL3 gl3 = glAutoDrawable.getGL().getGL3(); Registry.textureFactory.unloadAll(); } @Override public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int width, int height) { //logger.debug("reshape {}x{}",width,height); - canvasWidth = width; - canvasHeight = height; } @Override @@ -168,27 +149,4 @@ public void mouseMoved(MouseEvent e) {} @Override public void mouseWheelMoved(MouseWheelEvent e) {} - - public int getCanvasHeight() { - return canvasHeight; - } - - public int getCanvasWidth() { - return canvasWidth; - } - - @Override - public void keyTyped(KeyEvent e) { - System.out.println("keyTyped "+e); - } - - @Override - public void keyPressed(KeyEvent e) { - System.out.println("keyPressed "+e); - } - - @Override - public void keyReleased(KeyEvent e) { - System.out.println("keyReleased "+e); - } } diff --git a/src/main/java/com/marginallyclever/ro3/render/RenderPass.java b/src/main/java/com/marginallyclever/ro3/apps/render/RenderPass.java similarity index 86% rename from src/main/java/com/marginallyclever/ro3/render/RenderPass.java rename to src/main/java/com/marginallyclever/ro3/apps/render/RenderPass.java index f4fd47083..1f88b0e49 100644 --- a/src/main/java/com/marginallyclever/ro3/render/RenderPass.java +++ b/src/main/java/com/marginallyclever/ro3/apps/render/RenderPass.java @@ -1,8 +1,7 @@ -package com.marginallyclever.ro3.render; +package com.marginallyclever.ro3.apps.render; import com.jogamp.opengl.GLEventListener; import com.marginallyclever.ro3.Registry; -import com.marginallyclever.robotoverlord.systems.render.ShaderProgram; /** * Classes which implement {@link RenderPass} are drawn on top of the 3D scene. They should be registered to the diff --git a/src/main/java/com/marginallyclever/ro3/render/Viewport.java b/src/main/java/com/marginallyclever/ro3/apps/render/Viewport.java similarity index 90% rename from src/main/java/com/marginallyclever/ro3/render/Viewport.java rename to src/main/java/com/marginallyclever/ro3/apps/render/Viewport.java index c5640cfca..1c564af8a 100644 --- a/src/main/java/com/marginallyclever/ro3/render/Viewport.java +++ b/src/main/java/com/marginallyclever/ro3/apps/render/Viewport.java @@ -1,9 +1,11 @@ -package com.marginallyclever.ro3.render; +package com.marginallyclever.ro3.apps.render; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLEventListener; import com.marginallyclever.convenience.helpers.MatrixHelper; import com.marginallyclever.ro3.Registry; +import com.marginallyclever.ro3.apps.render.renderpasses.*; +import com.marginallyclever.ro3.listwithevents.ListWithEvents; import com.marginallyclever.ro3.node.nodes.Camera; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,18 +21,18 @@ import java.util.List; /** - * {@link Viewport} is an {@link OpenGLPanel} that uses {@link Registry#renderPasses} to draw the + * {@link Viewport} is an {@link OpenGLPanel} that uses a set of {@link RenderPass}es to draw the * {@link Registry#getScene()} from the perspective of a {@link Registry#getActiveCamera()}. */ public class Viewport extends OpenGLPanel implements GLEventListener { - private static final Logger logger = LoggerFactory.getLogger(Viewport.class); + public ListWithEvents renderPasses = new ListWithEvents<>(); private Camera camera; private final JToolBar toolBar = new JToolBar(); private final DefaultComboBoxModel cameraListModel = new DefaultComboBoxModel<>(); private final JPopupMenu renderPassMenu = new JPopupMenu(); private final List buttonPressed = new ArrayList<>(); private int mx, my; - private double orbitRadius = 100; + private double orbitRadius = 50; private final double orbitChangeFactor = 1.1; // must always be greater than 1 @@ -38,6 +40,7 @@ public Viewport() { super(); add(toolBar, BorderLayout.NORTH); toolBar.setLayout(new FlowLayout(FlowLayout.LEFT,5,1)); + addRenderPasses(); addCameraSelector(); addRenderPassSelection(); @@ -46,6 +49,17 @@ public Viewport() { } } + private void addRenderPasses() { + renderPasses.add(new DrawBackground()); + renderPasses.add(new DrawGroundPlane()); + renderPasses.add(new DrawMeshes()); + renderPasses.add(new DrawBoundingBoxes()); + renderPasses.add(new DrawCameras()); + renderPasses.add(new DrawDHParameters()); + renderPasses.add(new DrawHingeJoints()); + renderPasses.add(new DrawPoses()); + } + private void addRenderPassSelection() { JButton button = new JButton("Render"); toolBar.add(button); @@ -55,7 +69,7 @@ private void addRenderPassSelection() { // Add an ActionListener to the JButton to show the JPopupMenu when clicked button.addActionListener(e -> renderPassMenu.show(button, button.getWidth()/2, button.getHeight()/2)); - for(RenderPass renderPass : Registry.renderPasses.getList()) { + for(RenderPass renderPass : renderPasses.getList()) { addRenderPass(renderPass); } } @@ -65,8 +79,8 @@ public void addNotify() { super.addNotify(); Registry.cameras.addItemAddedListener(this::addCamera); Registry.cameras.addItemRemovedListener(this::removeCamera); - Registry.renderPasses.addItemAddedListener(this::addRenderPass); - Registry.renderPasses.addItemRemovedListener(this::removeRenderPass); + renderPasses.addItemAddedListener(this::addRenderPass); + renderPasses.addItemRemovedListener(this::removeRenderPass); } @Override @@ -74,8 +88,8 @@ public void removeNotify() { super.removeNotify(); Registry.cameras.removeItemAddedListener(this::addCamera); Registry.cameras.removeItemRemovedListener(this::removeCamera); - Registry.renderPasses.removeItemAddedListener(this::addRenderPass); - Registry.renderPasses.removeItemRemovedListener(this::removeRenderPass); + renderPasses.removeItemAddedListener(this::addRenderPass); + renderPasses.removeItemRemovedListener(this::removeRenderPass); } private void addRenderPass(RenderPass renderPass) { @@ -181,7 +195,7 @@ public void display(GLAutoDrawable glAutoDrawable) { private void renderAllPasses() { // renderPasses that are always on - for(RenderPass pass : Registry.renderPasses.getList()) { + for(RenderPass pass : renderPasses.getList()) { if(pass.getActiveStatus()==RenderPass.ALWAYS) { pass.draw(); } diff --git a/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/AbstractRenderPass.java b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/AbstractRenderPass.java new file mode 100644 index 000000000..0dc447d02 --- /dev/null +++ b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/AbstractRenderPass.java @@ -0,0 +1,74 @@ +package com.marginallyclever.ro3.apps.render.renderpasses; + +import com.jogamp.opengl.GLAutoDrawable; +import com.marginallyclever.ro3.apps.render.RenderPass; + +/** + * {@link AbstractRenderPass} handles common methods for all {@link RenderPass}. + */ +public abstract class AbstractRenderPass implements RenderPass { + private String name; + private int activeStatus = ALWAYS; + protected int canvasWidth, canvasHeight; + + protected AbstractRenderPass() {} + + protected AbstractRenderPass(String name) { + this(); + this.name = name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * @return the localized name of this pass. + */ + @Override + public String getName() { + return name; + } + + /** + * @return NEVER, SOMETIMES, or ALWAYS + */ + @Override + public int getActiveStatus() { + return activeStatus; + } + + /** + * @param status NEVER, SOMETIMES, or ALWAYS + */ + @Override + public void setActiveStatus(int status) { + activeStatus = status; + } + + @Override + public void draw() { + + } + + @Override + public void init(GLAutoDrawable glAutoDrawable) { + + } + + @Override + public void dispose(GLAutoDrawable glAutoDrawable) { + + } + + @Override + public void display(GLAutoDrawable glAutoDrawable) { + + } + + @Override + public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int width, int height) { + canvasWidth = width; + canvasHeight = height; + } +} diff --git a/src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawBackground.java b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawBackground.java similarity index 88% rename from src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawBackground.java rename to src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawBackground.java index fd720443d..67f713fa8 100644 --- a/src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawBackground.java +++ b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawBackground.java @@ -1,4 +1,4 @@ -package com.marginallyclever.ro3.render.renderpasses; +package com.marginallyclever.ro3.apps.render.renderpasses; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL3; @@ -9,8 +9,6 @@ import com.marginallyclever.convenience.helpers.ResourceHelper; import com.marginallyclever.ro3.Registry; import com.marginallyclever.ro3.node.nodes.Camera; -import com.marginallyclever.ro3.render.RenderPass; -import com.marginallyclever.ro3.texture.TextureFactory; import com.marginallyclever.ro3.texture.TextureWithMetadata; import com.marginallyclever.robotoverlord.systems.render.ShaderProgram; import com.marginallyclever.robotoverlord.systems.render.mesh.Mesh; @@ -24,16 +22,16 @@ *

Draw the background. This may be a skybox or a solid color.

*

TODO use the OpenGL cube map texture?

*/ -public class DrawBackground implements RenderPass { +public class DrawBackground extends AbstractRenderPass { private static final Logger logger = LoggerFactory.getLogger(DrawBackground.class); - private int activeStatus = ALWAYS; private final ColorRGB eraseColor = new ColorRGB(64,64,128); private ShaderProgram shader; private final Mesh mesh = new Mesh(); private final TextureWithMetadata texture; - private int canvasWidth, canvasHeight; public DrawBackground() { + super("Erase/Background"); + // build a box mesh.setRenderStyle(GL3.GL_QUADS); @@ -80,22 +78,7 @@ public DrawBackground() { mesh.addTexCoord(a,f); mesh.addVertex(-v, -v, -v); texture = Registry.textureFactory.load("/skybox/skybox.png"); - } - - /** - * @return NEVER, SOMETIMES, or ALWAYS - */ - @Override - public int getActiveStatus() { - return activeStatus; - } - - /** - * @param status NEVER, SOMETIMES, or ALWAYS - */ - @Override - public void setActiveStatus(int status) { - activeStatus = status; + texture.setDoNotExport(true); } /** @@ -125,15 +108,6 @@ public void dispose(GLAutoDrawable glAutoDrawable) { shader.delete(gl3); } - @Override - public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int width, int height) { - canvasWidth = width; - canvasHeight = height; - } - - @Override - public void display(GLAutoDrawable glAutoDrawable) {} - @Override public void draw() { GL3 gl3 = GLContext.getCurrentGL().getGL3(); diff --git a/src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawBoundingBoxes.java b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawBoundingBoxes.java similarity index 83% rename from src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawBoundingBoxes.java rename to src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawBoundingBoxes.java index 2acb272c2..e56bd9b31 100644 --- a/src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawBoundingBoxes.java +++ b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawBoundingBoxes.java @@ -1,4 +1,4 @@ -package com.marginallyclever.ro3.render.renderpasses; +package com.marginallyclever.ro3.apps.render.renderpasses; import com.jogamp.opengl.GL3; import com.jogamp.opengl.GLAutoDrawable; @@ -10,12 +10,7 @@ import com.marginallyclever.ro3.Registry; import com.marginallyclever.ro3.node.Node; import com.marginallyclever.ro3.node.nodes.Camera; -import com.marginallyclever.ro3.node.nodes.Material; import com.marginallyclever.ro3.node.nodes.MeshInstance; -import com.marginallyclever.ro3.node.nodes.Pose; -import com.marginallyclever.ro3.render.RenderPass; -import com.marginallyclever.ro3.texture.TextureWithMetadata; -import com.marginallyclever.robotoverlord.components.shapes.Box; import com.marginallyclever.robotoverlord.systems.render.ShaderProgram; import com.marginallyclever.robotoverlord.systems.render.mesh.Mesh; import org.slf4j.Logger; @@ -30,14 +25,14 @@ /** * Draw the bounding box of each {@link MeshInstance} in the scene. */ -public class DrawBoundingBoxes implements RenderPass { +public class DrawBoundingBoxes extends AbstractRenderPass { private static final Logger logger = LoggerFactory.getLogger(DrawBoundingBoxes.class); - private int activeStatus = ALWAYS; private ShaderProgram shader; private final Mesh mesh = new Mesh(); - private int canvasWidth, canvasHeight; public DrawBoundingBoxes() { + super("Bounding Boxes"); + mesh.setRenderStyle(GL3.GL_LINES); // add 8 points of a unit cube centered on the origin mesh.addVertex(-0.5f, 0.5f, 0.5f); @@ -65,30 +60,6 @@ public DrawBoundingBoxes() { mesh.addIndex(3); mesh.addIndex(7); } - /** - * @return NEVER, SOMETIMES, or ALWAYS - */ - @Override - public int getActiveStatus() { - return activeStatus; - } - - /** - * @param status NEVER, SOMETIMES, or ALWAYS - */ - @Override - public void setActiveStatus(int status) { - activeStatus = status; - } - - /** - * @return the localized name of this overlay - */ - @Override - public String getName() { - return "Bounding Boxes"; - } - @Override public void init(GLAutoDrawable glAutoDrawable) { GL3 gl3 = glAutoDrawable.getGL().getGL3(); @@ -108,15 +79,6 @@ public void dispose(GLAutoDrawable glAutoDrawable) { shader.delete(gl3); } - @Override - public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int width, int height) { - canvasWidth = width; - canvasHeight = height; - } - - @Override - public void display(GLAutoDrawable glAutoDrawable) {} - @Override public void draw() { Camera camera = Registry.getActiveCamera(); diff --git a/src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawCameras.java b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawCameras.java similarity index 83% rename from src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawCameras.java rename to src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawCameras.java index dbcc73c02..6963b7c3f 100644 --- a/src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawCameras.java +++ b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawCameras.java @@ -1,4 +1,4 @@ -package com.marginallyclever.ro3.render.renderpasses; +package com.marginallyclever.ro3.apps.render.renderpasses; import com.jogamp.opengl.GL3; import com.jogamp.opengl.GLAutoDrawable; @@ -7,7 +7,6 @@ import com.marginallyclever.convenience.helpers.ResourceHelper; import com.marginallyclever.ro3.Registry; import com.marginallyclever.ro3.node.nodes.Camera; -import com.marginallyclever.ro3.render.RenderPass; import com.marginallyclever.robotoverlord.systems.render.ShaderProgram; import com.marginallyclever.robotoverlord.systems.render.mesh.Mesh; import org.slf4j.Logger; @@ -19,14 +18,14 @@ /** * Draws each {@link Camera} as a pyramid approximating the perspective view frustum. */ -public class DrawCameras implements RenderPass { +public class DrawCameras extends AbstractRenderPass { private static final Logger logger = LoggerFactory.getLogger(DrawCameras.class); - private int activeStatus = ALWAYS; private final Mesh mesh = new Mesh(); private ShaderProgram shader; - private int canvasWidth,canvasHeight; public DrawCameras() { + super("Cameras"); + // add mesh to a list that can be unloaded and reloaded as needed. mesh.setRenderStyle(GL3.GL_LINES); Vector3d a = new Vector3d(-1,-1,-1); @@ -47,30 +46,6 @@ public DrawCameras() { mesh.addColor(0,0,0,1); mesh.addVertex((float)a.x, (float)a.y, (float)a.z); } - /** - * @return NEVER, SOMETIMES, or ALWAYS - */ - @Override - public int getActiveStatus() { - return activeStatus; - } - - /** - * @param status NEVER, SOMETIMES, or ALWAYS - */ - @Override - public void setActiveStatus(int status) { - activeStatus = status; - } - - /** - * @return the localized name of this overlay - */ - @Override - public String getName() { - return "Cameras"; - } - @Override public void init(GLAutoDrawable glAutoDrawable) { GL3 gl3 = glAutoDrawable.getGL().getGL3(); @@ -90,15 +65,6 @@ public void dispose(GLAutoDrawable glAutoDrawable) { shader.delete(gl3); } - @Override - public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int width, int height) { - canvasWidth = width; - canvasHeight = height; - } - - @Override - public void display(GLAutoDrawable glAutoDrawable) {} - @Override public void draw() { Camera camera = Registry.getActiveCamera(); diff --git a/src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawDHParameters.java b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawDHParameters.java similarity index 83% rename from src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawDHParameters.java rename to src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawDHParameters.java index 36e2bee9b..04b9e3ee4 100644 --- a/src/main/java/com/marginallyclever/ro3/render/renderpasses/DrawDHParameters.java +++ b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawDHParameters.java @@ -1,4 +1,4 @@ -package com.marginallyclever.ro3.render.renderpasses; +package com.marginallyclever.ro3.apps.render.renderpasses; import com.jogamp.opengl.GL3; import com.jogamp.opengl.GLAutoDrawable; @@ -11,7 +11,6 @@ import com.marginallyclever.ro3.node.nodes.Camera; import com.marginallyclever.ro3.node.nodes.DHParameter; import com.marginallyclever.ro3.node.nodes.Pose; -import com.marginallyclever.ro3.render.RenderPass; import com.marginallyclever.robotoverlord.systems.render.ShaderProgram; import com.marginallyclever.robotoverlord.systems.render.mesh.Mesh; import org.slf4j.Logger; @@ -26,14 +25,14 @@ /** * Draws each {@link DHParameter} as two lines from the previous joint to the current joint. */ -public class DrawDHParameters implements RenderPass { +public class DrawDHParameters extends AbstractRenderPass { private static final Logger logger = LoggerFactory.getLogger(DrawDHParameters.class); - private int activeStatus = ALWAYS; private final Mesh mesh = new Mesh(); private ShaderProgram shader; - private int canvasWidth,canvasHeight; public DrawDHParameters() { + super("DH Parameters"); + // add mesh to a list that can be unloaded and reloaded as needed. mesh.setRenderStyle(GL3.GL_LINES); // line d @@ -44,30 +43,6 @@ public DrawDHParameters() { mesh.addColor(1,0,0,1); mesh.addVertex(0,0,0); } - /** - * @return NEVER, SOMETIMES, or ALWAYS - */ - @Override - public int getActiveStatus() { - return activeStatus; - } - - /** - * @param status NEVER, SOMETIMES, or ALWAYS - */ - @Override - public void setActiveStatus(int status) { - activeStatus = status; - } - - /** - * @return the localized name of this overlay - */ - @Override - public String getName() { - return "DH Parameters"; - } - @Override public void init(GLAutoDrawable glAutoDrawable) { GL3 gl3 = glAutoDrawable.getGL().getGL3(); @@ -87,15 +62,6 @@ public void dispose(GLAutoDrawable glAutoDrawable) { shader.delete(gl3); } - @Override - public void reshape(GLAutoDrawable glAutoDrawable, int x, int y, int width, int height) { - canvasWidth = width; - canvasHeight = height; - } - - @Override - public void display(GLAutoDrawable glAutoDrawable) {} - @Override public void draw() { Camera camera = Registry.getActiveCamera(); diff --git a/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawGroundPlane.java b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawGroundPlane.java new file mode 100644 index 000000000..662d5ce38 --- /dev/null +++ b/src/main/java/com/marginallyclever/ro3/apps/render/renderpasses/DrawGroundPlane.java @@ -0,0 +1,87 @@ +package com.marginallyclever.ro3.apps.render.renderpasses; + +import com.jogamp.opengl.GL3; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLContext; +import com.marginallyclever.convenience.helpers.MatrixHelper; +import com.marginallyclever.convenience.helpers.ResourceHelper; +import com.marginallyclever.ro3.Registry; +import com.marginallyclever.ro3.node.nodes.Camera; +import com.marginallyclever.robotoverlord.systems.render.ShaderProgram; +import com.marginallyclever.robotoverlord.systems.render.mesh.Mesh; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.vecmath.Matrix4d; +import javax.vecmath.Vector3d; + +/** + * Draw the ground plane. + */ +public class DrawGroundPlane extends AbstractRenderPass { + private static final Logger logger = LoggerFactory.getLogger(DrawGroundPlane.class); + private final Mesh mesh = MatrixHelper.createMesh(1.0); + private ShaderProgram shader; + + public DrawGroundPlane() { + super("Ground plane"); + + mesh.setRenderStyle(GL3.GL_LINES); + int v = 1000; + int stepSize=100; + for(int s=-v;s T findFirstSibling(Class type) { * @return the JSON object. */ public JSONObject toJSON() { - logger.info("Saving {}.",getAbsolutePath()); + //logger.debug("Saving {}.",getAbsolutePath()); JSONObject json = new JSONObject(); json.put("type",getClass().getSimpleName()); json.put("name",name); diff --git a/src/main/java/com/marginallyclever/ro3/node/nodes/Camera.java b/src/main/java/com/marginallyclever/ro3/node/nodes/Camera.java index 3fe29ab7c..49cb24e3b 100644 --- a/src/main/java/com/marginallyclever/ro3/node/nodes/Camera.java +++ b/src/main/java/com/marginallyclever/ro3/node/nodes/Camera.java @@ -2,7 +2,7 @@ import com.marginallyclever.convenience.helpers.MatrixHelper; import com.marginallyclever.ro3.Registry; -import com.marginallyclever.robotoverlord.components.PoseComponent; +import com.marginallyclever.ro3.apps.render.Viewport; import com.marginallyclever.robotoverlord.swing.CollapsiblePanel; import javax.swing.*; @@ -16,7 +16,7 @@ import java.util.List; /** - *

A {@link Camera} is a {@link Pose} that can be used by a {@link com.marginallyclever.ro3.render.Viewport} to + *

A {@link Camera} is a {@link Pose} that can be used by a {@link Viewport} to * render the scene.

*

For perspective rendering it has a vertical field of view and a near and far clipping plane.

*/ @@ -25,6 +25,7 @@ public class Camera extends Pose { private double fovY = 60; private double nearZ = 1; private double farZ = 1000; + private double orbitRadius = 50; public Camera() { super("Camera"); diff --git a/src/main/java/com/marginallyclever/ro3/texture/TextureFactory.java b/src/main/java/com/marginallyclever/ro3/texture/TextureFactory.java index 4b8068d9b..684bb200a 100644 --- a/src/main/java/com/marginallyclever/ro3/texture/TextureFactory.java +++ b/src/main/java/com/marginallyclever/ro3/texture/TextureFactory.java @@ -7,7 +7,6 @@ import javax.imageio.ImageIO; import java.awt.image.BufferedImage; -import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -56,4 +55,16 @@ public void unloadAll() { t.unload(); } } + + /** + * @return a list of all the sources used to load textures. + */ + public List getAllSourcesForExport() { + List result = new ArrayList<>(); + for(TextureWithMetadata t : textures) { + if(t.isDoNotExport()) continue; + result.add(t.getSource()); + } + return result; + } } diff --git a/src/main/java/com/marginallyclever/ro3/texture/TextureWithMetadata.java b/src/main/java/com/marginallyclever/ro3/texture/TextureWithMetadata.java index e5cc601d8..365f901af 100644 --- a/src/main/java/com/marginallyclever/ro3/texture/TextureWithMetadata.java +++ b/src/main/java/com/marginallyclever/ro3/texture/TextureWithMetadata.java @@ -9,10 +9,15 @@ import java.awt.image.BufferedImage; +/** + * {@link TextureWithMetadata} is an OpenGL {@link Texture} with metadata about where it came from and the source + * image. + */ public class TextureWithMetadata { private final BufferedImage image; private Texture texture; private final String source; + private boolean doNotExport=false; public TextureWithMetadata(BufferedImage image,String source) { super(); @@ -79,4 +84,12 @@ public int getHeight() { if(image==null) return 0; return image.getHeight(); } + + public boolean isDoNotExport() { + return doNotExport; + } + + public void setDoNotExport(boolean value) { + doNotExport=value; + } } diff --git a/src/main/java/com/marginallyclever/robotoverlord/systems/render/mesh/load/MeshFactory.java b/src/main/java/com/marginallyclever/robotoverlord/systems/render/mesh/load/MeshFactory.java index 695efde12..d28f238a3 100644 --- a/src/main/java/com/marginallyclever/robotoverlord/systems/render/mesh/load/MeshFactory.java +++ b/src/main/java/com/marginallyclever/robotoverlord/systems/render/mesh/load/MeshFactory.java @@ -130,4 +130,12 @@ public static String getMaterialPath(String absolutePath) { } return null; } + + public static List getAllSourcesForExport() { + List result = new ArrayList<>(); + for( Mesh m : meshPool ) { + result.add(m.getSourceName()); + } + return result; + } } diff --git a/src/main/resources/com/marginallyclever/ro3/apps/logpanel/icons8-folder-16.png b/src/main/resources/com/marginallyclever/ro3/apps/logpanel/icons8-folder-16.png new file mode 100644 index 000000000..114747374 Binary files /dev/null and b/src/main/resources/com/marginallyclever/ro3/apps/logpanel/icons8-folder-16.png differ diff --git a/src/main/resources/com/marginallyclever/ro3/render/default_330.frag b/src/main/resources/com/marginallyclever/ro3/apps/render/default_330.frag similarity index 100% rename from src/main/resources/com/marginallyclever/ro3/render/default_330.frag rename to src/main/resources/com/marginallyclever/ro3/apps/render/default_330.frag diff --git a/src/main/resources/com/marginallyclever/ro3/render/default_330.vert b/src/main/resources/com/marginallyclever/ro3/apps/render/default_330.vert similarity index 100% rename from src/main/resources/com/marginallyclever/ro3/render/default_330.vert rename to src/main/resources/com/marginallyclever/ro3/apps/render/default_330.vert diff --git a/src/main/resources/com/marginallyclever/ro3/render/renderpasses/mesh.frag b/src/main/resources/com/marginallyclever/ro3/apps/render/renderpasses/mesh.frag similarity index 100% rename from src/main/resources/com/marginallyclever/ro3/render/renderpasses/mesh.frag rename to src/main/resources/com/marginallyclever/ro3/apps/render/renderpasses/mesh.frag diff --git a/src/main/resources/com/marginallyclever/ro3/render/renderpasses/mesh.vert b/src/main/resources/com/marginallyclever/ro3/apps/render/renderpasses/mesh.vert similarity index 100% rename from src/main/resources/com/marginallyclever/ro3/render/renderpasses/mesh.vert rename to src/main/resources/com/marginallyclever/ro3/apps/render/renderpasses/mesh.vert diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index e697a163b..c26248a6c 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -5,7 +5,7 @@ System.out - INFO + DEBUG ACCEPT DENY diff --git a/src/test/java/com/marginallyclever/ro3/render/TestViewport.java b/src/test/java/com/marginallyclever/ro3/apps/render/TestViewport.java similarity index 91% rename from src/test/java/com/marginallyclever/ro3/render/TestViewport.java rename to src/test/java/com/marginallyclever/ro3/apps/render/TestViewport.java index 7e8df34d2..22c9cad75 100644 --- a/src/test/java/com/marginallyclever/ro3/render/TestViewport.java +++ b/src/test/java/com/marginallyclever/ro3/apps/render/TestViewport.java @@ -1,6 +1,6 @@ -package com.marginallyclever.ro3.render; +package com.marginallyclever.ro3.apps.render; -import com.marginallyclever.ro3.node.nodes.Camera; +import com.marginallyclever.ro3.apps.render.Viewport; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable;