package org.newdawn.slick.tools.peditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import org.lwjgl.LWJGLException;
import org.newdawn.slick.CanvasGameContainer;
import org.newdawn.slick.InputListener;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.particles.ConfigurableEmitter;
import org.newdawn.slick.particles.ParticleIO;
import org.newdawn.slick.particles.ParticleSystem;
import org.newdawn.slick.util.InputAdapter;
import org.newdawn.slick.util.Log;
/**
* The bootstrap and main frame for the particle editor Pedigree.
*
* @author kevin
*/
public class ParticleEditor extends JFrame {
/** The canvas displaying the particles */
private ParticleGame game;
/** Create a new system */
private JMenuItem newSystem = new JMenuItem("New System");
/** Load a complete particle system */
private JMenuItem load = new JMenuItem("Load System");
/** Save a complete particle system */
private JMenuItem save = new JMenuItem("Save System");
/** Load a single particle emitter */
private JMenuItem imp = new JMenuItem("Import Emitter");
/** Clone a single particle emitter */
private JMenuItem clone = new JMenuItem("Clone Emitter");
/** Save a single particle emitter */
private JMenuItem exp = new JMenuItem("Export Emitter");
/** Toggle the HUD */
private JMenuItem hud = new JMenuItem("Toggle Overlay");
/** Toggle the HUD */
private JMenuItem loadBackground = new JMenuItem("Load Background Image");
/** Toggle the HUD */
private JMenuItem clearBackground = new JMenuItem("Clear Background Image");
/** Toggle the graphice editor */
private JMenuItem whiskas = new JMenuItem("Show/Hide Graph Editor");
/** Exit the editor */
private JMenuItem quit = new JMenuItem("Exit");
/** The visual list of emitters */
private EmitterList emitters;
/** The controls for the initial emission settings */
private EmissionControls emissionControls;
/** The positional controls for spawnng particles */
private PositionControls positionControls;
/** The global settings for the emitter */
private SettingsPanel settingsPanel;
/** The color controls for particles */
private ColorPanel colorPanel;
/** The limiting controls for particles */
private LimitPanel limitPanel;
/** The whiskas panel */
private WhiskasPanel whiskasPanel;
/** Control for the type of particle system blending */
private JCheckBox additive = new JCheckBox("Additive Blending");
/** Control for the type of particle point usage */
private JCheckBox pointsEnabled = new JCheckBox("Use Points");
/** The currently selected particle emitter */
private ConfigurableEmitter selected;
/** Chooser used to load/save/import/export */
private JFileChooser chooser = new JFileChooser(new File("."));
/** Reset the particle counts on the canvas */
private JButton reset = new JButton("Reset Max");
/** Play or Pause the current rendering */
private JButton pause = new JButton("Play/Pause");
/** The slider defining the movement of the system */
private JSlider systemMove = new JSlider(-100,100,0);
/** The graph editor frame **/
private JFrame graphEditorFrame;
/** The filter in use */
private FileFilter xmlFileFilter;
/**
* Create a new editor
*
* @throws LWJGLException Indicates a failure to create an OpenGL context
* @throws SlickException
*/
public ParticleEditor() throws LWJGLException, SlickException {
super("Pedigree - Whiskas flavoured");
xmlFileFilter = new FileFilter() {
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
if (f.getName().endsWith(".xml")) {
return true;
}
return false;
}
public String getDescription() {
return "XML Files";
}
};
chooser.setFileFilter(xmlFileFilter);
// try {
// InputStream in = ParticleEditor.class.getClassLoader().getResourceAsStream("org/newdawn/slick/tools/peditor/data/icon.gif");
//
// setIconImage(ImageIO.read(in));
// } catch (IOException e) {
// e.printStackTrace();
// }
emitters = new EmitterList(this);
emissionControls = new EmissionControls();
positionControls = new PositionControls();
settingsPanel = new SettingsPanel(emitters);
colorPanel = new ColorPanel();
limitPanel = new LimitPanel(emitters);
whiskasPanel= new WhiskasPanel( emitters, colorPanel, emissionControls );
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
JMenu file = new JMenu("File");
file.add(newSystem);
file.addSeparator();
file.add(load);
file.add(save);
file.addSeparator();
file.add(imp);
file.add(clone);
file.add(exp);
file.addSeparator();
file.add(hud);
file.add(whiskas);
file.addSeparator();
file.add(loadBackground);
file.add(clearBackground);
file.addSeparator();
file.add(quit);
loadBackground.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
loadBackground();
}
});
clearBackground.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
clearBackground();
}
});
newSystem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
createNewSystem();
}
});
hud.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
game.setHud(!game.isHudOn());
}
});
load.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
loadSystem();
}
});
save.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
saveSystem();
}
});
clone.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cloneEmitter();
}
});
exp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
exportEmitter();
}
});
imp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
importEmitter();
}
});
quit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
whiskas.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
graphEditorFrame.setVisible(!graphEditorFrame.isVisible());
}
});
JMenuBar bar = new JMenuBar();
bar.add(file);
setJMenuBar(bar);
game = new ParticleGame(this);
final CanvasGameContainer container = new CanvasGameContainer(game);
container.setSize(500,600);
JPanel controls = new JPanel();
controls.setLayout(null);
emitters.setBounds(0,0,300,150);
emitters.setBorder(BorderFactory.createTitledBorder("Emitters"));
controls.add(emitters);
JTabbedPane tabs = new JTabbedPane();
tabs.setBounds(0,150,300,350);
controls.add(tabs);
tabs.add("Settings", settingsPanel);
tabs.add("Emission", emissionControls);
tabs.add("Position", positionControls);
tabs.add("Rendering", colorPanel);
tabs.add("Limit", limitPanel);
tabs.add("Whiskas", whiskasPanel);
JPanel panel = new JPanel();
panel.setLayout(null);
container.setBounds(0,0,500,600);
controls.setBounds(500,20,300,575);
reset.setBounds(90,500,90,25);
controls.add(reset);
systemMove.setBounds(180,500,120,25);
controls.add(systemMove);
pause.setBounds(0,500,90,25);
controls.add(pause);
additive.setBounds(500,0,150,25);
panel.add(additive);
pointsEnabled.setBounds(650,0,150,25);
panel.add(pointsEnabled);
panel.add(container);
panel.add(controls);
systemMove.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
game.setSystemMove(systemMove.getValue(),false);
}
});
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
additive.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateBlendMode();
}
});
pointsEnabled.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
game.getSystem().setUsePoints(pointsEnabled.isSelected());
}
});
reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
game.resetCounts();
}
});
pause.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
game.setPaused(!game.isPaused());
}
});
ConfigurableEmitter test = new ConfigurableEmitter("Default");
emitters.add(test);
game.addEmitter(test);
additive.setSelected(true);
setContentPane(panel);
setSize(800,600);
setResizable(false);
setVisible(true);
InputListener listener = new InputAdapter() {
public void mousePressed(int x, int y, int button) {
if (button != 0) {
positionControls.setPosition(0,0);
}
systemMove.setValue(0);
game.setSystemMove(0,true);
}
public void mouseMoved(int x, int y, int nx, int ny) {
if (container.getContainer().getInput().isMouseButtonDown(0)) {
int xp = nx - 250;
int yp = ny - 300;
positionControls.setPosition(xp,yp);
systemMove.setValue(0);
game.setSystemMove(0,true);
}
}
};
game.setListener(listener);
// init graph window
initGraphEditorWindow();
emitters.setSelected(0);
try {
container.start();
} catch (SlickException e1) {
Log.error(e1);
}
}
/**
* Load a background image to display behind the particle system
*/
private void loadBackground() {
JFileChooser chooser = new JFileChooser(".");
chooser.setDialogTitle("Open");
int resp = chooser.showOpenDialog(this);
if (resp == JFileChooser.APPROVE_OPTION) {
game.setBackgroundImage(chooser.getSelectedFile());
}
}
/**
* Clear the background image in use
*/
private void clearBackground() {
game.setBackgroundImage(null);
}
/**
* init the graph editor window
*/
private void initGraphEditorWindow()
{
// create the window
GraphEditorWindow editor = new GraphEditorWindow();
whiskasPanel.setEditor(editor);
graphEditorFrame= new JFrame("Whiskas Gradient Editor");
graphEditorFrame.getContentPane().add(editor);
graphEditorFrame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
graphEditorFrame.pack();
graphEditorFrame.setSize(600, 300);
graphEditorFrame.setLocation(this.getX(), this.getY()+this.getHeight());
graphEditorFrame.setVisible(true);
// try {
// InputStream in = ParticleEditor.class.getClassLoader().getResourceAsStream("org/newdawn/slick/tools/peditor/data/icon.gif");
//
// //graphEditorFrame.setIconImage(ImageIO.read(in));
// } catch (IOException e) {
// e.printStackTrace();
// }
}
/**
* Set the movement of the system
*
* @param move The movement of the system
*/
public void setSystemMove(int move) {
systemMove.setValue(move);
}
/**
* Import an emitter XML file
*/
public void importEmitter() {
chooser.setDialogTitle("Open");
int resp = chooser.showOpenDialog(this);
if (resp == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
File path = file.getParentFile();
try {
final ConfigurableEmitter emitter = ParticleIO.loadEmitter(file);
if (emitter.getImageName() != null) {
File possible = new File(path, emitter.getImageName());
if (possible.exists()) {
emitter.setImageName(possible.getAbsolutePath());
} else {
chooser.setDialogTitle("Locate the image: "+emitter.getImageName());
resp = chooser.showOpenDialog(this);
FileFilter filter = new FileFilter() {
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
return (f.getName().equals(emitter.getImageName()));
}
public String getDescription() {
return emitter.getImageName();
}
};
chooser.addChoosableFileFilter(filter);
if (resp == JFileChooser.APPROVE_OPTION) {
File image = chooser.getSelectedFile();
emitter.setImageName(image.getAbsolutePath());
path = image.getParentFile();
}
chooser.resetChoosableFileFilters();
chooser.addChoosableFileFilter(xmlFileFilter);
}
}
addEmitter(emitter);
emitters.setSelected(emitter);
} catch (IOException e) {
Log.error(e);
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
}
/**
* Clone the selected emitter
*/
public void cloneEmitter() {
if (selected == null) {
return;
}
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ParticleIO.saveEmitter(bout, selected);
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ConfigurableEmitter emitter = ParticleIO.loadEmitter(bin);
emitter.name = emitter.name + "_clone";
addEmitter(emitter);
emitters.setSelected(emitter);
} catch (IOException e) {
Log.error(e);
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
/**
* Export an emitter XML file
*/
public void exportEmitter() {
if (selected == null) {
return;
}
chooser.setDialogTitle("Save");
int resp = chooser.showSaveDialog(this);
if (resp == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
if (!file.getName().endsWith(".xml")) {
file = new File(file.getAbsolutePath()+".xml");
}
try {
ParticleIO.saveEmitter(file, selected);
} catch (IOException e) {
Log.error(e);
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
}
/**
* Create a completely new particle system
*/
public void createNewSystem() {
game.clearSystem(additive.isSelected());
pointsEnabled.setSelected(false);
emitters.clear();
}
/**
* Load a complete particle system XML description
*/
public void loadSystem() {
chooser.setDialogTitle("Open");
int resp = chooser.showOpenDialog(this);
if (resp == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
File path = file.getParentFile();
try {
ParticleSystem system = ParticleIO.loadConfiguredSystem(file);
game.setSystem(system);
emitters.clear();
for (int i=0;i<system.getEmitterCount();i++) {
final ConfigurableEmitter emitter = (ConfigurableEmitter) system.getEmitter(i);
if (emitter.getImageName() != null) {
File possible = new File(path, emitter.getImageName());
if (possible.exists()) {
emitter.setImageName(possible.getAbsolutePath());
} else {
chooser.setDialogTitle("Locate the image: "+emitter.getImageName());
FileFilter filter = new FileFilter() {
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
return (f.getName().equals(emitter.getImageName()));
}
public String getDescription() {
return emitter.getImageName();
}
};
chooser.addChoosableFileFilter(filter);
resp = chooser.showOpenDialog(this);
if (resp == JFileChooser.APPROVE_OPTION) {
File image = chooser.getSelectedFile();
emitter.setImageName(image.getAbsolutePath());
path = image.getParentFile();
}
chooser.setDialogTitle("Open");
chooser.resetChoosableFileFilters();
chooser.addChoosableFileFilter(xmlFileFilter);
}
}
emitters.add(emitter);
}
additive.setSelected(system.getBlendingMode() == ParticleSystem.BLEND_ADDITIVE);
pointsEnabled.setSelected(system.usePoints());
emitters.setSelected(0);
} catch (IOException e) {
Log.error(e);
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
}
/**
* Save a complete particle system XML description
*/
public void saveSystem() {
int resp = chooser.showSaveDialog(this);
if (resp == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
if (!file.getName().endsWith(".xml")) {
file = new File(file.getAbsolutePath()+".xml");
}
try {
ParticleIO.saveConfiguredSystem(file, game.getSystem());
} catch (IOException e) {
Log.error(e);
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
}
/**
* Add a new emitter to the editor
*
* @param emitter The emitter to add
*/
public void addEmitter(ConfigurableEmitter emitter) {
emitters.add(emitter);
game.addEmitter(emitter);
}
/**
* Remove a particle emitter from the editor
*
* @param emitter The emitter to be removed
*/
public void removeEmitter(ConfigurableEmitter emitter) {
emitters.remove(emitter);
game.removeEmitter(emitter);
}
/**
* Set the currently selected and edited particle emitter
*
* @param emitter The emitter that should be selected or null for none
*/
public void setCurrentEmitter(ConfigurableEmitter emitter) {
this.selected = emitter;
if (emitter == null) {
emissionControls.setEnabled(false);
settingsPanel.setEnabled(false);
positionControls.setEnabled(false);
colorPanel.setEnabled(false);
limitPanel.setEnabled(false);
whiskasPanel.setEnabled(false);
} else {
emissionControls.setEnabled(true);
settingsPanel.setEnabled(true);
positionControls.setEnabled(true);
colorPanel.setEnabled(true);
limitPanel.setEnabled(true);
whiskasPanel.setEnabled(true);
emissionControls.setTarget(emitter);
settingsPanel.setTarget(emitter);
positionControls.setTarget(emitter);
settingsPanel.setTarget(emitter);
colorPanel.setTarget(emitter);
limitPanel.setTarget(emitter);
whiskasPanel.setTarget(emitter);
}
}
/**
* Change the visual indicator for the current particle system
* blend mode
*/
public void updateBlendMode() {
if (additive.isSelected()) {
game.getSystem().setBlendingMode(ParticleSystem.BLEND_ADDITIVE);
} else {
game.getSystem().setBlendingMode(ParticleSystem.BLEND_COMBINE);
}
}
/**
* Entry point in the editor
*
* @param argv The arguments passed on the command line
*/
public static void main(String[] argv) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
new ParticleEditor();
} catch (Exception e) {
Log.error(e);
}
}
}