package com.badlogic.gdx.tools.flame;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import com.badlogic.gdx.graphics.g3d.particles.ParticleController;
import com.badlogic.gdx.graphics.g3d.particles.influencers.DynamicsInfluencer;
import com.badlogic.gdx.graphics.g3d.particles.influencers.DynamicsModifier;
import com.badlogic.gdx.graphics.g3d.particles.influencers.DynamicsModifier.BrownianAcceleration;
import com.badlogic.gdx.graphics.g3d.particles.influencers.DynamicsModifier.CentripetalAcceleration;
import com.badlogic.gdx.graphics.g3d.particles.influencers.DynamicsModifier.FaceDirection;
import com.badlogic.gdx.graphics.g3d.particles.influencers.DynamicsModifier.PolarAcceleration;
import com.badlogic.gdx.graphics.g3d.particles.influencers.DynamicsModifier.Rotational3D;
import com.badlogic.gdx.graphics.g3d.particles.influencers.DynamicsModifier.TangentialAcceleration;
import com.badlogic.gdx.tools.flame.FlameMain.ControllerType;
import com.badlogic.gdx.utils.Array;
/** @author Inferno */
public class DynamicsInfluencerPanel extends InfluencerPanel<DynamicsInfluencer> {
private static final String VEL_TYPE_ROTATIONAL_2D = "Angular Velocity 2D",
VEL_TYPE_ROTATIONAL_3D = "Angular Velocity 3D",
VEL_TYPE_CENTRIPETAL = "Centripetal",
VEL_TYPE_TANGENTIAL = "Tangential",
VEL_TYPE_POLAR = "Polar",
VEL_TYPE_BROWNIAN = "Brownian",
VEL_TYPE_FACE = "Face";
protected class VelocityWrapper{
public DynamicsModifier velocityValue;
public boolean isActive;
public VelocityWrapper(DynamicsModifier value, boolean isActive){
this.velocityValue = value;
this.isActive = isActive;
}
}
JComboBox velocityBox;
JTable velocityTable;
DefaultTableModel velocityTableModel;
JPanel selectedVelocityPanel;
AngularVelocityPanel angularVelocityPanel;
StrengthVelocityPanel strengthVelocityPanel;
ParticleValuePanel emptyPanel;
Array<VelocityWrapper> velocities;
public DynamicsInfluencerPanel (FlameMain editor, DynamicsInfluencer influencer) {
super(editor, influencer, "Dynamics Influencer",
"Defines how the particles dynamics (acceleration, angular velocity).");
velocities = new Array<VelocityWrapper>();
setValue(value);
set(influencer);
}
private void set (DynamicsInfluencer influencer) {
//Clear
for (int i = velocityTableModel.getRowCount() - 1; i >= 0; i--) {
velocityTableModel.removeRow(i);
}
velocities.clear();
//Add
for(int i=0, c = influencer.velocities.size; i < c; ++i){
velocities.add(new VelocityWrapper((DynamicsModifier)influencer.velocities.items[i], true));
velocityTableModel.addRow(new Object[] {"Velocity "+i, true});
}
DefaultComboBoxModel model = (DefaultComboBoxModel) velocityBox.getModel();
model.removeAllElements();
for(Object velocityObject : getAvailableVelocities(editor.getControllerType())){
model.addElement(velocityObject);
}
}
private Object[] getAvailableVelocities (ControllerType type) {
if(type == ControllerType.Billboard || type == ControllerType.PointSprite) {
return new String[]{ VEL_TYPE_ROTATIONAL_2D, VEL_TYPE_CENTRIPETAL, VEL_TYPE_TANGENTIAL,
VEL_TYPE_POLAR, VEL_TYPE_BROWNIAN};
}
else if(type == ControllerType.ModelInstance|| type == ControllerType.ParticleController) {
return new String[]{ VEL_TYPE_ROTATIONAL_3D, VEL_TYPE_CENTRIPETAL, VEL_TYPE_TANGENTIAL,
VEL_TYPE_POLAR, VEL_TYPE_BROWNIAN, VEL_TYPE_FACE};
}
return null;
}
protected void initializeComponents () {
super.initializeComponents();
JPanel velocitiesPanel = new JPanel();
velocitiesPanel.setLayout(new GridBagLayout());
{
JPanel sideButtons = new JPanel(new GridBagLayout());
velocitiesPanel.add(sideButtons, new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0));
{
sideButtons.add(velocityBox = new JComboBox(new DefaultComboBoxModel()),
new GridBagConstraints(0, -1, 1, 1, 0, 0, GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 6, 0), 0, 0));
}
{
JButton newButton = new JButton("New");
sideButtons.add(newButton, new GridBagConstraints(0, -1, 1, 1, 0, 0, GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 6, 0), 0, 0));
newButton.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent event) {
createVelocity(velocityBox.getSelectedItem());
}
});
}
{
JButton deleteButton = new JButton("Delete");
sideButtons.add(deleteButton, new GridBagConstraints(0, -1, 1, 1, 0, 0, GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL, new Insets(0, 0, 6, 0), 0, 0));
deleteButton.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent event) {
deleteVelocity();
}
});
}
}
JScrollPane scroll = new JScrollPane();
velocitiesPanel.add(scroll, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,
0, 0, 6), 0, 0));
velocityTable = new JTable() {
public Class getColumnClass (int column) {
return column == 1 ? Boolean.class : super.getColumnClass(column);
}
@Override
public Dimension getPreferredScrollableViewportSize () {
Dimension dim = super.getPreferredScrollableViewportSize();
dim.height = getPreferredSize().height;
return dim;
}
};
velocityTable.getTableHeader().setReorderingAllowed(false);
velocityTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
scroll.setViewportView(velocityTable);
velocityTableModel = new DefaultTableModel(new String[0][0], new String[] {"Velocity", "Active"});
velocityTable.setModel(velocityTableModel);
velocityTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged (ListSelectionEvent event) {
if (event.getValueIsAdjusting()) return;
velocitySelected();
}
});
velocityTableModel.addTableModelListener(new TableModelListener() {
public void tableChanged (TableModelEvent event) {
if (event.getColumn() != 1) return;
velocityChecked(event.getFirstRow(), (Boolean)velocityTable.getValueAt(event.getFirstRow(), 1));
}
});
//Velocity values
emptyPanel = new ParticleValuePanel(editor, "", "",true, false);
strengthVelocityPanel = new StrengthVelocityPanel(editor, null, "Life", "", "");
angularVelocityPanel = new AngularVelocityPanel(editor, null, "Life", "", "");
strengthVelocityPanel.setVisible(false);
angularVelocityPanel.setVisible(false);
emptyPanel.setVisible(false);
strengthVelocityPanel.setIsAlwayShown(true);
angularVelocityPanel.setIsAlwayShown(true);
emptyPanel.setIsAlwayShown(true);
emptyPanel.setValue(null);
//Assemble
int i=0;
addContent(i++, 0, velocitiesPanel);
addContent(i++, 0, strengthVelocityPanel);
addContent(i++, 0, angularVelocityPanel);
addContent(i++, 0, emptyPanel);
}
protected void velocityChecked (int index, boolean isChecked) {
ParticleController controller = editor.getEmitter();
DynamicsInfluencer influencer = (DynamicsInfluencer)controller.findInfluencer(DynamicsInfluencer.class);
influencer.velocities.clear();
velocities.get(index).isActive = isChecked;
for(VelocityWrapper wrapper : velocities){
if(wrapper.isActive)
influencer.velocities.add(wrapper.velocityValue);
}
//Restart the effect and reinit the controller
editor.restart();
}
protected void velocitySelected () {
//Show the velocity value panel
int index = velocityTable.getSelectedRow();
if(index == -1) return;
DynamicsModifier velocityValue = velocities.get(index).velocityValue;
EditorPanel velocityPanel = getVelocityPanel(velocityValue);
//Show the selected velocity
if(selectedVelocityPanel != null && selectedVelocityPanel != velocityPanel)
selectedVelocityPanel.setVisible(false);
velocityPanel.setVisible(true);
velocityPanel.showContent(true);
selectedVelocityPanel = velocityPanel;
}
private EditorPanel getVelocityPanel (DynamicsModifier velocityValue) {
EditorPanel panel = null;
//Billboards
if(velocityValue instanceof DynamicsModifier.Rotational2D ){
strengthVelocityPanel.setValue((DynamicsModifier.Strength) velocityValue);
strengthVelocityPanel.setName("Angular Velocity");
strengthVelocityPanel.setDescription("The angular speed around the billboard facing direction, in degrees/sec .");
panel = strengthVelocityPanel;
}
else if( velocityValue instanceof CentripetalAcceleration){
strengthVelocityPanel.setValue((DynamicsModifier.CentripetalAcceleration) velocityValue);
strengthVelocityPanel.setName("Centripetal Acceleration");
strengthVelocityPanel.setDescription("A directional acceleration, the direction is towards the origin (global), or towards the emitter position (local), in world units/sec2 .");
panel = strengthVelocityPanel;
}
else if( velocityValue instanceof TangentialAcceleration){
angularVelocityPanel.setValue((DynamicsModifier.Angular) velocityValue);
angularVelocityPanel.setName("Tangetial Velocity");
angularVelocityPanel.setDescription("A directional acceleration (axis and magnitude), the final direction is the cross product between particle position and the axis, in world units/sec2 .");
panel = angularVelocityPanel;
}
else if( velocityValue instanceof PolarAcceleration){
angularVelocityPanel.setValue((DynamicsModifier.Angular) velocityValue);
angularVelocityPanel.setName("Polar Velocity");
angularVelocityPanel.setDescription("A directional acceleration (axis and magnitude), in world units/sec2 .");
panel = angularVelocityPanel;
}
else if( velocityValue instanceof BrownianAcceleration){
strengthVelocityPanel.setValue((DynamicsModifier.Strength) velocityValue);
strengthVelocityPanel.setName("Brownian Velocity");
strengthVelocityPanel.setDescription("A directional acceleration which has random direction at each update, in world units/sec2.");
panel = strengthVelocityPanel;
}
else if(velocityValue instanceof Rotational3D ){
angularVelocityPanel.setValue((DynamicsModifier.Angular) velocityValue);
angularVelocityPanel.setName("Angular Velocity");
angularVelocityPanel.setDescription("An angular velocity (axis and magnitude), in degree/sec2.");
panel = angularVelocityPanel;
}
else if( velocityValue instanceof FaceDirection){
emptyPanel.setName("Face");
emptyPanel.setDescription("Rotates the model to face its current velocity (Do not add any other angular velocity when using this).");
panel = emptyPanel;
}
return panel;
}
private DynamicsModifier createVelocityValue (Object selectedItem) {
DynamicsModifier velocityValue = null;
if(selectedItem == VEL_TYPE_ROTATIONAL_2D) velocityValue = new DynamicsModifier.Rotational2D();
else if(selectedItem == VEL_TYPE_ROTATIONAL_3D) velocityValue = new DynamicsModifier.Rotational3D();
else if(selectedItem == VEL_TYPE_CENTRIPETAL) velocityValue = new DynamicsModifier.CentripetalAcceleration();
else if(selectedItem == VEL_TYPE_TANGENTIAL) velocityValue = new DynamicsModifier.TangentialAcceleration();
else if(selectedItem == VEL_TYPE_POLAR) velocityValue = new DynamicsModifier.PolarAcceleration();
else if(selectedItem == VEL_TYPE_BROWNIAN) velocityValue = new DynamicsModifier.BrownianAcceleration();
else if(selectedItem == VEL_TYPE_FACE) velocityValue = new DynamicsModifier.FaceDirection();
return velocityValue;
}
protected void deleteVelocity () {
int row = velocityTable.getSelectedRow();
if (row == -1) return;
//Remove the velocity from the table
ParticleController controller = editor.getEmitter();
DynamicsInfluencer influencer = (DynamicsInfluencer)controller.findInfluencer(DynamicsInfluencer.class);
influencer.velocities.removeValue(velocities.removeIndex(row).velocityValue, true);
velocityTableModel.removeRow(row);
//Restart the effect and reinit the controller
editor.restart();
selectedVelocityPanel.setVisible(false);
selectedVelocityPanel = null;
}
protected void createVelocity (Object selectedItem) {
//Add the velocity to the table and to the influencer
ParticleController controller = editor.getEmitter();
DynamicsInfluencer influencer = (DynamicsInfluencer)controller.findInfluencer(DynamicsInfluencer.class);
VelocityWrapper wrapper = new VelocityWrapper(createVelocityValue(selectedItem), true);
velocities.add(wrapper);
influencer.velocities.add(wrapper.velocityValue);
int index = velocities.size-1;
velocityTableModel.addRow(new Object[] {"Velocity "+index, true});
//Reinit
editor.restart();
//Select new velocity
velocityTable.getSelectionModel().setSelectionInterval(index, index);
revalidate();
repaint();
}
}