From dc3bcddeb134f7a6e15d26fd3768c7e7796eab30 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 20 Jun 2006 19:36:23 +0000 Subject: [PATCH] Added basic JME import dialog to model viewer. With the latest version of LWJGL, the AWT canvas releases its OpenGL context after rendering. Rather than redesign all event handling to take place in the update method, I put in a hack to grab the context back. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4200 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- lib/LIBS | 1 + rsrc/i18n/jme/viewer.properties | 8 + src/java/com/threerings/jme/JmeCanvasApp.java | 37 ++++- .../com/threerings/jme/tools/ModelViewer.java | 149 +++++++++++++++++- 4 files changed, 186 insertions(+), 9 deletions(-) diff --git a/lib/LIBS b/lib/LIBS index 339f58471..5e1e0b9e2 100644 --- a/lib/LIBS +++ b/lib/LIBS @@ -6,6 +6,7 @@ commons-io.jar commons-lang.jar commons-logging.jar jme-awt.jar +jme-effects.jar jme-bui.jar jme-model.jar jme-sound.jar diff --git a/rsrc/i18n/jme/viewer.properties b/rsrc/i18n/jme/viewer.properties index 1656ca058..b5363738b 100644 --- a/rsrc/i18n/jme/viewer.properties +++ b/rsrc/i18n/jme/viewer.properties @@ -7,6 +7,7 @@ m.title = Three Rings Model Viewer m.file_menu = File m.file_load = Load Model... +m.file_import = Import JME File... m.file_quit = Quit m.view_menu = View @@ -25,6 +26,9 @@ m.mode_skin = Skin m.load_title = Select Model to Load m.load_filter = Model Files (*.properties, *.dat) +m.import_title = Select File to Import +m.import_filter = JME Files (*.jme) + m.anim_select = Animations: m.anim_start = Start m.anim_stop = Stop @@ -36,6 +40,10 @@ m.loaded_model = Loaded {0} m.load_error = Error loading {0}: {1} m.invalid_type = Invalid file type. +m.import = JME File: {0} +m.scale = Scale +m.respawn_particles = Respawn Particles + m.rotate_light = Rotate Light m.azimuth = Azimuth: m.elevation = Elevation: diff --git a/src/java/com/threerings/jme/JmeCanvasApp.java b/src/java/com/threerings/jme/JmeCanvasApp.java index def5a70a3..3e7faf587 100644 --- a/src/java/com/threerings/jme/JmeCanvasApp.java +++ b/src/java/com/threerings/jme/JmeCanvasApp.java @@ -22,16 +22,20 @@ package com.threerings.jme; import java.awt.Canvas; +import java.awt.Graphics; import java.awt.EventQueue; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; +import org.lwjgl.LWJGLException; + import com.jme.renderer.Renderer; import com.jme.renderer.lwjgl.LWJGLRenderer; import com.jme.scene.Node; import com.jme.system.DisplaySystem; import com.jmex.awt.JMECanvas; import com.jmex.awt.JMECanvasImplementor; +import com.jmex.awt.lwjgl.LWJGLCanvas; import com.jmex.bui.CanvasRootNode; @@ -44,7 +48,15 @@ public class JmeCanvasApp extends JmeApp public JmeCanvasApp (int width, int height) { _display = DisplaySystem.getDisplaySystem("LWJGL"); - _canvas = _display.createCanvas(width, height); + + // create a throwaway canvas so that the display system knows it's + // created, then create our custom canvas + _display.createCanvas(width, height); + try { + _canvas = createCanvas(); + } catch (LWJGLException e) { + Log.warning("Failed to create LWJGL canvas [error=" + e + "]."); + } ((JMECanvas)_canvas).setImplementor(_winimp); _canvas.setBounds(0, 0, width, height); _canvas.addComponentListener(new ComponentAdapter() { @@ -91,7 +103,28 @@ public class JmeCanvasApp extends JmeApp { return EventQueue.isDispatchThread(); } - + + /** + * Creates and returns the LWJGL canvas instance. + */ + protected Canvas createCanvas () + throws LWJGLException + { + // LWJGL's canvas releases the context after painting. we make it + // current again, because we want it valid when we process events. + return new LWJGLCanvas() { + public void update (Graphics g) { + super.update(g); + try { + makeCurrent(); + } catch (LWJGLException e) { + Log.warning("Failed to make context current [error=" + + e + "]."); + } + } + }; + } + // documentation inherited protected DisplaySystem createDisplay () { diff --git a/src/java/com/threerings/jme/tools/ModelViewer.java b/src/java/com/threerings/jme/tools/ModelViewer.java index 380e7d725..b4f45dd8f 100644 --- a/src/java/com/threerings/jme/tools/ModelViewer.java +++ b/src/java/com/threerings/jme/tools/ModelViewer.java @@ -89,7 +89,9 @@ import com.jme.scene.state.ZBufferState; import com.jme.system.JmeException; import com.jme.util.LoggingSystem; import com.jme.util.TextureManager; +import com.jme.util.export.binary.BinaryImporter; import com.jme.util.geom.Debugger; +import com.jmex.effects.particles.ParticleMesh; import com.samskivert.swing.GroupLayout; import com.samskivert.swing.Spacer; @@ -168,6 +170,16 @@ public class ModelViewer extends JmeCanvasApp KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.CTRL_MASK)); file.add(load); + Action importAction = new AbstractAction(_msg.get("m.file_import")) { + public void actionPerformed (ActionEvent e) { + showImportDialog(); + } + }; + importAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_I); + importAction.putValue(Action.ACCELERATOR_KEY, + KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_MASK)); + file.add(importAction); + file.addSeparator(); Action quit = new AbstractAction(_msg.get("m.file_quit")) { public void actionPerformed (ActionEvent e) { @@ -492,7 +504,7 @@ public class ModelViewer extends JmeCanvasApp if (file.isDirectory()) { return true; } - String path = file.toString(); + String path = file.toString().toLowerCase(); return path.endsWith(".properties") || path.endsWith(".dat"); } @@ -632,6 +644,54 @@ public class ModelViewer extends JmeCanvasApp } } + /** + * Shows the import particle system dialog. + */ + protected void showImportDialog () + { + if (_ichooser == null) { + _ichooser = new JFileChooser(); + _ichooser.setDialogTitle(_msg.get("m.import_title")); + _ichooser.setFileFilter(new FileFilter() { + public boolean accept (File file) { + if (file.isDirectory()) { + return true; + } + String path = file.toString().toLowerCase(); + return path.endsWith(".jme"); + } + public String getDescription () { + return _msg.get("m.import_filter"); + } + }); + File dir = new File(_config.getValue("import_dir", ".")); + if (dir.exists()) { + _ichooser.setCurrentDirectory(dir); + } + } + if (_ichooser.showOpenDialog(_frame) == JFileChooser.APPROVE_OPTION) { + importFile(_ichooser.getSelectedFile()); + } + _config.setValue("import_dir", + _ichooser.getCurrentDirectory().toString()); + } + + /** + * Attempts to import the specified file as a JME binary scene. + */ + protected void importFile (File file) + { + try { + new ImportDialog(file, + (Spatial)BinaryImporter.getInstance().load( + file)).setVisible(true); + + } catch (Exception e) { + e.printStackTrace(); + _status.setText(_msg.get("m.load_error", file, e)); + } + } + /** * Updates the model's animation speed based on the position of the * animation speed slider. @@ -678,6 +738,9 @@ public class ModelViewer extends JmeCanvasApp /** The model file chooser. */ protected JFileChooser _chooser; + /** The import file chooser. */ + protected JFileChooser _ichooser; + /** The desired animation mode. */ protected Model.AnimationMode _animMode; @@ -730,6 +793,84 @@ public class ModelViewer extends JmeCanvasApp } }; + /** Allows users to manipulate an imported JME file. */ + protected class ImportDialog extends JDialog + implements ChangeListener + { + public ImportDialog (File file, Spatial spatial) + { + super(_frame, _msg.get("m.import", file), false); + _spatial = spatial; + + // rotate from y-up to z-up and set initial scale + _spatial.getLocalRotation().fromAngleNormalAxis(FastMath.HALF_PI, + Vector3f.UNIT_X); + _spatial.setLocalScale(0.025f); + + JPanel cpanel = GroupLayout.makeVBox(); + getContentPane().add(cpanel, BorderLayout.CENTER); + + JPanel spanel = new JPanel(); + spanel.add(new JLabel(_msg.get("m.scale"))); + spanel.add(_scale = new JSlider(0, 1000, 250)); + _scale.addChangeListener(this); + cpanel.add(spanel); + + JPanel bpanel = new JPanel(); + bpanel.add(new JButton(new AbstractAction( + _msg.get("m.respawn_particles")) { + public void actionPerformed (ActionEvent e) { + forceRespawn(_spatial); + } + })); + bpanel.add(new JButton(new AbstractAction(_msg.get("m.close")) { + public void actionPerformed (ActionEvent e) { + setVisible(false); + } + })); + getContentPane().add(bpanel, BorderLayout.SOUTH); + pack(); + } + + // documentation inherited from interface ChangeListener + public void stateChanged (ChangeEvent e) + { + _spatial.setLocalScale(_scale.getValue() * 0.0001f); + } + + @Override // documentation inherited + public void setVisible (boolean visible) + { + super.setVisible(visible); + if (visible && _spatial.getParent() == null) { + _ctx.getGeometry().attachChild(_spatial); + } else if (!visible && _spatial.getParent() != null) { + _ctx.getGeometry().detachChild(_spatial); + } + } + + /** + * Recursively forces all particles to respawn. + */ + protected void forceRespawn (Spatial spatial) + { + if (spatial instanceof ParticleMesh) { + ((ParticleMesh)spatial).forceRespawn(); + } else if (spatial instanceof Node) { + Node node = (Node)spatial; + for (int ii = 0, nn = node.getQuantity(); ii < nn; ii++) { + forceRespawn(node.getChild(ii)); + } + } + } + + /** The imported scene. */ + protected Spatial _spatial; + + /** The scale slider. */ + protected JSlider _scale; + } + /** Allows users to move the directional light around. */ protected class RotateLightDialog extends JDialog implements ChangeListener @@ -773,12 +914,6 @@ public class ModelViewer extends JmeCanvasApp -FastMath.sin(el)); } - // documentation inherited from interface ActionListener - public void actionPerformed (ActionEvent e) - { - setVisible(false); - } - /** Azimuth and elevation sliders. */ protected JSlider _azimuth, _elevation; }