/**
* *****************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
* ****************************************************************************
*/
package sg.atom2d.tools.fx.particle.app;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.CompoundBorder;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import com.jme3.renderer.Camera;
import java.awt.Canvas;
import sg.atom2d.game2d.graphics.fx.particle.ParticleEffect;
import sg.atom2d.game2d.graphics.fx.particle.ParticleEmitter;
import sg.atom2d.game2d.graphics.fx.particle.values.NumericValue;
import sg.atom2d.tools.fx.particle.components.CountPanel;
import sg.atom2d.tools.fx.particle.components.EditorPanel;
import sg.atom2d.tools.fx.particle.components.EffectPanel;
import sg.atom2d.tools.fx.particle.components.GradientPanel;
import sg.atom2d.tools.fx.particle.components.ImagePanel;
import sg.atom2d.tools.fx.particle.components.NumericPanel;
import sg.atom2d.tools.fx.particle.components.OptionsPanel;
import sg.atom2d.tools.fx.particle.components.PercentagePanel;
import sg.atom2d.tools.fx.particle.components.RangedNumericPanel;
import sg.atom2d.tools.fx.particle.components.ScaledNumericPanel;
import sg.atom2d.tools.fx.particle.components.SpawnPanel;
public class ParticleEditor extends JFrame {
public Canvas lwjglCanvas;
public JPanel rowsPanel;
public JPanel editRowsPanel;
public EffectPanel effectPanel;
private JSplitPane splitPane;
public Camera worldCamera;
public Camera textCamera;
public NumericValue pixelsPerMeter;
public NumericValue zoomLevel;
public float pixelsPerMeterPrev;
public float zoomLevelPrev;
public ParticleEffect effect = new ParticleEffect();
public final HashMap<ParticleEmitter, ParticleData> particleData = new HashMap();
private final ParticleRenderer particleRenderer;
public ParticleEditor() {
super("Particle Editor");
particleRenderer = new ParticleRenderer();
lwjglCanvas = particleRenderer.createAndStartCanvas(600, 400);
addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent event) {
System.exit(0);
// Gdx.app.quit();
}
});
initializeComponents();
setSize(1000, 950);
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
create();
}
public void create() {
pixelsPerMeter = new NumericValue();
pixelsPerMeter.setValue(1.0f);
pixelsPerMeter.setAlwaysActive(true);
zoomLevel = new NumericValue();
zoomLevel.setValue(1.0f);
zoomLevel.setAlwaysActive(true);
effectPanel.newEmitter("Untitled", true);
}
public void reloadRows() {
EventQueue.invokeLater(new Runnable() {
public void run() {
editRowsPanel.removeAll();
addEditorRow(new NumericPanel(pixelsPerMeter, "Pixels per meter", ""));
addEditorRow(new NumericPanel(zoomLevel, "Zoom level", ""));
rowsPanel.removeAll();
ParticleEmitter emitter = getEmitter();
addRow(new ImagePanel(ParticleEditor.this, "Image", ""));
addRow(new CountPanel(ParticleEditor.this, "Count",
"Min number of particles at all times, max number of particles allowed."));
addRow(new RangedNumericPanel(emitter.getDelay(), "Delay",
"Time from beginning of effect to emission start, in milliseconds."));
addRow(new RangedNumericPanel(emitter.getDuration(), "Duration", "Time particles will be emitted, in milliseconds."));
addRow(new ScaledNumericPanel(emitter.getEmission(), "Duration", "Emission",
"Number of particles emitted per second."));
addRow(new ScaledNumericPanel(emitter.getLife(), "Duration", "Life", "Time particles will live, in milliseconds."));
addRow(new ScaledNumericPanel(emitter.getLifeOffset(), "Duration", "Life Offset",
"Particle starting life consumed, in milliseconds."));
addRow(new RangedNumericPanel(emitter.getXOffsetValue(), "X Offset",
"Amount to offset a particle's starting X location, in world units."));
addRow(new RangedNumericPanel(emitter.getYOffsetValue(), "Y Offset",
"Amount to offset a particle's starting Y location, in world units."));
addRow(new SpawnPanel(ParticleEditor.this, emitter.getSpawnShape(), "Spawn", "Shape used to spawn particles."));
addRow(new ScaledNumericPanel(emitter.getSpawnWidth(), "Duration", "Spawn Width",
"Width of the spawn shape, in world units."));
addRow(new ScaledNumericPanel(emitter.getSpawnHeight(), "Duration", "Spawn Height",
"Height of the spawn shape, in world units."));
addRow(new ScaledNumericPanel(emitter.getScale(), "Life", "Size", "Particle size, in world units."));
addRow(new ScaledNumericPanel(emitter.getVelocity(), "Life", "Velocity", "Particle speed, in world units per second."));
addRow(new ScaledNumericPanel(emitter.getAngle(), "Life", "Angle", "Particle emission angle, in degrees."));
addRow(new ScaledNumericPanel(emitter.getRotation(), "Life", "Rotation", "Particle rotation, in degrees."));
addRow(new ScaledNumericPanel(emitter.getWind(), "Life", "Wind", "Wind strength, in world units per second."));
addRow(new ScaledNumericPanel(emitter.getGravity(), "Life", "Gravity", "Gravity strength, in world units per second."));
addRow(new GradientPanel(emitter.getTint(), "Tint", ""));
addRow(new PercentagePanel(emitter.getTransparency(), "Life", "Transparency", ""));
addRow(new OptionsPanel(ParticleEditor.this, "Options", ""));
for (Component component : rowsPanel.getComponents()) {
if (component instanceof EditorPanel) {
((EditorPanel) component).update(ParticleEditor.this);
}
}
rowsPanel.repaint();
}
});
}
void addEditorRow(JPanel row) {
row.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, java.awt.Color.black));
editRowsPanel.add(row, new GridBagConstraints(0, -1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0));
}
void addRow(JPanel row) {
row.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, java.awt.Color.black));
rowsPanel.add(row, new GridBagConstraints(0, -1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0));
}
public void setVisible(String name, boolean visible) {
for (Component component : rowsPanel.getComponents()) {
if (component instanceof EditorPanel && ((EditorPanel) component).getName().equals(name)) {
component.setVisible(visible);
}
}
}
public ParticleEmitter getEmitter() {
return effect.getEmitters().get(effectPanel.editIndex);
}
public ImageIcon getIcon(ParticleEmitter emitter) {
ParticleData data = particleData.get(emitter);
if (data == null) {
particleData.put(emitter, data = new ParticleData());
}
String imagePath = emitter.getImagePath();
if (data.icon == null && imagePath != null) {
try {
URL url;
File file = new File(imagePath);
if (file.exists()) {
url = file.toURI().toURL();
} else {
url = ParticleEditor.class.getResource(imagePath);
if (url == null) {
return null;
}
}
data.icon = new ImageIcon(url);
} catch (MalformedURLException ex) {
ex.printStackTrace();
}
}
return data.icon;
}
public void setIcon(ParticleEmitter emitters, ImageIcon icon) {
ParticleData data = particleData.get(emitters);
if (data == null) {
particleData.put(emitters, data = new ParticleData());
}
data.icon = icon;
}
public void setEnabled(ParticleEmitter emitter, boolean enabled) {
ParticleData data = particleData.get(emitter);
if (data == null) {
particleData.put(emitter, data = new ParticleData());
}
data.enabled = enabled;
emitter.reset();
}
public boolean isEnabled(ParticleEmitter emitter) {
ParticleData data = particleData.get(emitter);
if (data == null) {
return true;
}
return data.enabled;
}
private void initializeComponents() {
// {
// JMenuBar menuBar = new JMenuBar();
// setJMenuBar(menuBar);
// JPopupMenu.setDefaultLightWeightPopupEnabled(false);
// JMenu fileMenu = new JMenu("File");
// menuBar.add(fileMenu);
// }
splitPane = new JSplitPane();
splitPane.setUI(new BasicSplitPaneUI() {
public void paint(Graphics g, JComponent jc) {
}
});
splitPane.setDividerSize(4);
getContentPane().add(splitPane, BorderLayout.CENTER);
{
JSplitPane rightSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
rightSplit.setUI(new BasicSplitPaneUI() {
public void paint(Graphics g, JComponent jc) {
}
});
rightSplit.setDividerSize(4);
splitPane.add(rightSplit, JSplitPane.RIGHT);
{
JPanel propertiesPanel = new JPanel(new GridBagLayout());
rightSplit.add(propertiesPanel, JSplitPane.TOP);
propertiesPanel.setBorder(new CompoundBorder(BorderFactory.createEmptyBorder(3, 0, 6, 6), BorderFactory
.createTitledBorder("Editor Properties")));
{
JScrollPane scroll = new JScrollPane();
propertiesPanel.add(scroll, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTH,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
scroll.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
{
editRowsPanel = new JPanel(new GridBagLayout());
scroll.setViewportView(editRowsPanel);
scroll.getVerticalScrollBar().setUnitIncrement(70);
}
}
}
{
JPanel propertiesPanel = new JPanel(new GridBagLayout());
rightSplit.add(propertiesPanel, JSplitPane.BOTTOM);
propertiesPanel.setBorder(new CompoundBorder(BorderFactory.createEmptyBorder(3, 0, 6, 6), BorderFactory
.createTitledBorder("Emitter Properties")));
{
JScrollPane scroll = new JScrollPane();
propertiesPanel.add(scroll, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTH,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
scroll.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
{
rowsPanel = new JPanel(new GridBagLayout());
scroll.setViewportView(rowsPanel);
scroll.getVerticalScrollBar().setUnitIncrement(70);
}
}
}
rightSplit.setDividerLocation(200);
}
{
JSplitPane leftSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
leftSplit.setUI(new BasicSplitPaneUI() {
public void paint(Graphics g, JComponent jc) {
}
});
leftSplit.setDividerSize(4);
splitPane.add(leftSplit, JSplitPane.LEFT);
{
JPanel spacer = new JPanel(new BorderLayout());
leftSplit.add(spacer, JSplitPane.TOP);
spacer.add(lwjglCanvas);
spacer.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 4));
}
{
JPanel emittersPanel = new JPanel(new BorderLayout());
leftSplit.add(emittersPanel, JSplitPane.BOTTOM);
emittersPanel.setBorder(new CompoundBorder(BorderFactory.createEmptyBorder(0, 6, 6, 0), BorderFactory
.createTitledBorder("Effect Emitters")));
{
effectPanel = new EffectPanel(this);
emittersPanel.add(effectPanel);
}
}
leftSplit.setDividerLocation(625);
}
splitPane.setDividerLocation(325);
}
static class ParticleData {
public ImageIcon icon;
public String imagePath;
public boolean enabled = true;
}
public static void main(String[] args) {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
try {
UIManager.setLookAndFeel(info.getClassName());
} catch (Throwable ignored) {
}
break;
}
}
EventQueue.invokeLater(new Runnable() {
public void run() {
new ParticleEditor();
}
});
}
}