org.cleanlogic.cesiumjs4gwt.showcase.examples.ParticleSystem.java Source code

Java tutorial

Introduction

Here is the source code for org.cleanlogic.cesiumjs4gwt.showcase.examples.ParticleSystem.java

Source

/*
 * Copyright 2017 iserge.
 *
 * 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 org.cleanlogic.cesiumjs4gwt.showcase.examples;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.*;
import org.cesiumjs.cs.Cesium;
import org.cesiumjs.cs.collections.TimeIntervalCollection;
import org.cesiumjs.cs.core.*;
import org.cesiumjs.cs.core.Math;
import org.cesiumjs.cs.core.enums.ClockRange;
import org.cesiumjs.cs.core.options.TimeIntervalOptions;
import org.cesiumjs.cs.datasources.Entity;
import org.cesiumjs.cs.datasources.graphics.ModelGraphics;
import org.cesiumjs.cs.datasources.graphics.options.ModelGraphicsOptions;
import org.cesiumjs.cs.datasources.options.EntityOptions;
import org.cesiumjs.cs.datasources.properties.*;
import org.cesiumjs.cs.js.JsDate;
import org.cesiumjs.cs.js.JsObject;
import org.cesiumjs.cs.scene.Scene;
import org.cesiumjs.cs.scene.emitters.BoxEmitter;
import org.cesiumjs.cs.scene.emitters.CircleEmitter;
import org.cesiumjs.cs.scene.emitters.ConeEmitter;
import org.cesiumjs.cs.scene.emitters.SphereEmitter;
import org.cesiumjs.cs.scene.particle.Particle;
import org.cesiumjs.cs.scene.particle.ParticleBurst;
import org.cesiumjs.cs.scene.particle.options.ParticleSystemOptions;
import org.cesiumjs.cs.widgets.ViewerPanel;
import org.cleanlogic.cesiumjs4gwt.showcase.basic.AbstractExample;
import org.cleanlogic.cesiumjs4gwt.showcase.components.store.ShowcaseExampleStore;
import org.cleanlogic.cesiumjs4gwt.showcase.examples.slider.Slider;
import org.cleanlogic.cesiumjs4gwt.showcase.examples.slider.SliderEvent;
import org.cleanlogic.cesiumjs4gwt.showcase.examples.slider.SliderListener;

import javax.inject.Inject;

/**
 * @author Serge Silaev aka iSergio <s.serge.b@gmail.com>
 */
public class ParticleSystem extends AbstractExample {
    private ViewModel viewModel = new ViewModel();

    private Slider rateSlider;
    private TextBox rateTBox;

    private Slider sizeSlider;
    private TextBox sizeTBox;

    private Slider minLifeSlider;
    private TextBox minLifeTBox;

    private Slider maxLifeSlider;
    private TextBox maxLifeTBox;

    private Slider minSpeedSlider;
    private TextBox minSpeedTBox;

    private Slider maxSpeedSlider;
    private TextBox maxSpeedTBox;

    private Slider startScaleSlider;
    private TextBox startScaleTBox;

    private Slider endScaleSlider;
    private TextBox endScaleTBox;

    private Slider gravitySlider;
    private TextBox gravityTBox;

    private TextBox translationXTBox;
    private TextBox translationYTBox;
    private TextBox translationZTBox;

    private TextBox rotationHTBox;
    private TextBox rotationPTBox;
    private TextBox rotationRTBox;

    private CheckBox spinCBox;
    private CheckBox flyCBox;
    private CheckBox showCBox;

    private SampledPositionProperty circularPosition;
    private Cartesian3 staticPosition;

    //Set bounds of our simulation time
    private JulianDate start = JulianDate.fromDate(new JsDate(2015, 2, 25, 16));
    private JulianDate stop = JulianDate.addSeconds(start, 360, new JulianDate());

    private Cartesian3 entityPosition = new Cartesian3();
    private Quaternion entityOrientation = new Quaternion();
    private Matrix3 rotationMatrix = new Matrix3();
    private Matrix4 modelMatrix = new Matrix4();

    private Matrix4 emitterModelMatrix = new Matrix4();
    private Cartesian3 translation = new Cartesian3();
    private Quaternion rotation = new Quaternion();
    private org.cesiumjs.cs.core.HeadingPitchRoll hpr = new org.cesiumjs.cs.core.HeadingPitchRoll();
    private TranslationRotationScale trs = new TranslationRotationScale();

    private Cartesian3 gravityScratch = new Cartesian3();

    private Entity entity;
    private org.cesiumjs.cs.scene.particle.ParticleSystem particleSystem;

    @Inject
    public ParticleSystem(ShowcaseExampleStore store) {
        super("Particle System", "Particle systems.",
                new String[] { "Showcase", "Cesium", "3d", "Viewer", "Particle" }, store);
    }

    @Override
    public void buildPanel() {
        ViewerPanel csVPanel = new ViewerPanel();

        //Set the random number seed for consistent results.
        Math.setRandomNumberSeed(3);

        //Make sure viewer is at the desired time.
        csVPanel.getViewer().clock().startTime = start.clone();
        csVPanel.getViewer().clock().stopTime = stop.clone();
        csVPanel.getViewer().clock().currentTime = start.clone();
        csVPanel.getViewer().clock().clockRange = ClockRange.LOOP_STOP(); //Loop at the end
        csVPanel.getViewer().clock().multiplier = 1;
        csVPanel.getViewer().clock().shouldAnimate = true;

        //Set timeline to simulation bounds
        csVPanel.getViewer().timeline().zoomTo(start, stop);

        //Compute the entity position property.
        circularPosition = computeCirclularFlight(-112.110693, 36.0994841, 0.03);
        staticPosition = Cartesian3.fromDegrees(-112.110693, 36.0994841, 1000);

        TimeIntervalOptions timeIntervalOptions = new TimeIntervalOptions();
        timeIntervalOptions.start = start;
        timeIntervalOptions.stop = stop;

        ModelGraphicsOptions modelGraphicsOptions = new ModelGraphicsOptions();
        modelGraphicsOptions.uri = new ConstantProperty<>(
                GWT.getModuleBaseURL() + "SampleData/models/CesiumAir/Cesium_Air.gltf");
        modelGraphicsOptions.minimumPixelSize = new ConstantProperty<>(64);

        EntityOptions entityOptions = new EntityOptions();
        entityOptions.availability = new TimeIntervalCollection(
                new TimeInterval[] { new TimeInterval(timeIntervalOptions) });
        entityOptions.model = new ModelGraphics(modelGraphicsOptions);
        entityOptions.position = new ConstantPositionProperty(staticPosition);
        entity = csVPanel.getViewer().entities().add(entityOptions);
        csVPanel.getViewer().trackedEntity = entity;

        ParticleSystemOptions particleSystemOptions = new ParticleSystemOptions();
        particleSystemOptions.image = GWT.getModuleBaseURL() + "SampleData/fire.png";

        particleSystemOptions.startColor = Color.RED().withAlpha(0.7f);
        particleSystemOptions.endColor = Color.YELLOW().withAlpha(0.3f);

        particleSystemOptions.startScale = viewModel.startScale;
        particleSystemOptions.endScale = viewModel.endScale;

        particleSystemOptions.minimumParticleLife = viewModel.minimumParticleLife;
        particleSystemOptions.maximumParticleLife = viewModel.maximumParticleLife;

        particleSystemOptions.minimumSpeed = viewModel.minimumSpeed;
        particleSystemOptions.maximumSpeed = viewModel.maximumSpeed;

        particleSystemOptions.imageSize = new Cartesian2(viewModel.particleSize, viewModel.particleSize);

        particleSystemOptions.emissionRate = viewModel.emissionRate;

        particleSystemOptions.bursts = new ParticleBurst[] { ParticleBurst.create(5.0, 300, 500),
                ParticleBurst.create(10.0, 50, 100), ParticleBurst.create(15.0, 200, 300) };

        particleSystemOptions.lifetime = 16.0;

        particleSystemOptions.emitter = new CircleEmitter(2.0);

        particleSystemOptions.emitterModelMatrix = computeEmitterModelMatrix();

        particleSystemOptions.updateCallback = new org.cesiumjs.cs.scene.particle.ParticleSystem.UpdateCallback() {
            @Override
            public void function(Particle particle, double dt) {
                Cartesian3 position = particle.position;

                Cartesian3.normalize(position, gravityScratch);
                Cartesian3.multiplyByScalar(gravityScratch, viewModel.gravity * dt, gravityScratch);

                particle.velocity = Cartesian3.add(particle.velocity, gravityScratch, particle.velocity);
            }
        };

        particleSystem = (org.cesiumjs.cs.scene.particle.ParticleSystem) csVPanel.getViewer().scene().primitives()
                .add(new org.cesiumjs.cs.scene.particle.ParticleSystem(particleSystemOptions));

        csVPanel.getViewer().scene().preRender().addEventListener(new Event.Listener() {
            @Override
            public void function(Object... o) {
                Scene scene = (Scene) o[0];
                JulianDate time = (JulianDate) o[1];
                particleSystem.modelMatrix = computeModelMatrix(entity, time);

                // Account for any changes to the emitter model matrix.
                particleSystem.emitterModelMatrix = computeEmitterModelMatrix();

                // Spin the emitter if enabled.
                if (viewModel.spin) {
                    viewModel.heading += 1.0;
                    viewModel.pitch += 1.0;
                    viewModel.roll += 1.0;

                    rotationHTBox.setValue(viewModel.heading + "");
                    rotationPTBox.setValue(viewModel.pitch + "");
                    rotationRTBox.setValue(viewModel.roll + "");
                }
            }
        });

        AbsolutePanel aPanel = new AbsolutePanel();
        aPanel.add(csVPanel);
        aPanel.add(createWidget(), 20, 20);

        contentPanel.add(new HTML("<p>Particle systems.</p>"));
        contentPanel.add(aPanel);

        initWidget(contentPanel);
    }

    public FlexTable createWidget() {
        MSliderListener sliderListener = new MSliderListener();
        MChangeHandler tboxListener = new MChangeHandler();

        rateSlider = new Slider("rate", 0, 100, (int) viewModel.emissionRate);
        rateSlider.setStep(1);
        rateSlider.setWidth("150px");
        rateSlider.addListener(sliderListener);
        rateTBox = new TextBox();
        rateTBox.setValue("" + (int) viewModel.emissionRate);
        rateTBox.setSize("30px", "12px");
        rateTBox.addChangeHandler(tboxListener);

        sizeSlider = new Slider("size", 2, 60, (int) viewModel.particleSize);
        sizeSlider.setStep(1);
        sizeSlider.setWidth("150px");
        sizeSlider.addListener(sliderListener);
        sizeTBox = new TextBox();
        sizeTBox.setValue("" + (int) viewModel.particleSize);
        sizeTBox.setSize("30px", "12px");
        sizeTBox.addChangeHandler(tboxListener);

        minLifeSlider = new Slider("minLife", 1, 30, (int) viewModel.minimumParticleLife);
        minLifeSlider.setStep(1);
        minLifeSlider.setWidth("150px");
        minLifeSlider.addListener(sliderListener);
        minLifeTBox = new TextBox();
        minLifeTBox.setValue("" + (int) viewModel.minimumParticleLife);
        minLifeTBox.setSize("30px", "12px");
        minLifeTBox.addChangeHandler(tboxListener);

        maxLifeSlider = new Slider("maxLife", 1, 30, (int) viewModel.maximumParticleLife);
        maxLifeSlider.setStep(1);
        maxLifeSlider.setWidth("150px");
        maxLifeSlider.addListener(sliderListener);
        maxLifeTBox = new TextBox();
        maxLifeTBox.setValue("" + (int) viewModel.maximumParticleLife);
        maxLifeTBox.setSize("30px", "12px");
        maxLifeTBox.addChangeHandler(tboxListener);

        minSpeedSlider = new Slider("minSpeed", 0, 30, (int) viewModel.minimumSpeed);
        minSpeedSlider.setStep(1);
        minSpeedSlider.setWidth("150px");
        minSpeedSlider.addListener(sliderListener);
        minSpeedTBox = new TextBox();
        minSpeedTBox.setValue("" + (int) viewModel.minimumSpeed);
        minSpeedTBox.setSize("30px", "12px");
        minSpeedTBox.addChangeHandler(tboxListener);

        maxSpeedSlider = new Slider("maxSpeed", 0, 30, (int) viewModel.maximumSpeed);
        maxSpeedSlider.setStep(1);
        maxSpeedSlider.setWidth("150px");
        maxSpeedSlider.addListener(sliderListener);
        maxSpeedTBox = new TextBox();
        maxSpeedTBox.setValue("" + (int) viewModel.maximumSpeed);
        maxSpeedTBox.setSize("30px", "12px");
        maxSpeedTBox.addChangeHandler(tboxListener);

        startScaleSlider = new Slider("startScale", 0, 10, (int) viewModel.startScale);
        startScaleSlider.setStep(1);
        startScaleSlider.setWidth("150px");
        startScaleSlider.addListener(sliderListener);
        startScaleTBox = new TextBox();
        startScaleTBox.setValue("" + (int) viewModel.startScale);
        startScaleTBox.setSize("30px", "12px");
        startScaleTBox.addChangeHandler(tboxListener);

        endScaleSlider = new Slider("endScale", 0, 10, (int) viewModel.endScale);
        endScaleSlider.setStep(1);
        endScaleSlider.setWidth("150px");
        endScaleSlider.addListener(sliderListener);
        endScaleTBox = new TextBox();
        endScaleTBox.setValue("" + (int) viewModel.endScale);
        endScaleTBox.setSize("30px", "12px");
        endScaleTBox.addChangeHandler(tboxListener);

        gravitySlider = new Slider("gravity", -20, 20, (int) viewModel.gravity);
        gravitySlider.setStep(1);
        gravitySlider.setWidth("150px");
        gravitySlider.addListener(sliderListener);
        gravityTBox = new TextBox();
        gravityTBox.setValue("" + (int) viewModel.gravity);
        gravityTBox.setSize("30px", "12px");
        gravityTBox.addChangeHandler(tboxListener);

        translationXTBox = new TextBox();
        translationXTBox.setSize("30px", "12px");
        translationXTBox.setValue(viewModel.transX + "");
        translationXTBox.addChangeHandler(tboxListener);
        translationYTBox = new TextBox();
        translationYTBox.setSize("30px", "12px");
        translationYTBox.setValue(viewModel.transY + "");
        translationYTBox.addChangeHandler(tboxListener);
        translationZTBox = new TextBox();
        translationZTBox.setSize("30px", "12px");
        translationZTBox.setValue(viewModel.transZ + "");
        translationZTBox.addChangeHandler(tboxListener);

        rotationHTBox = new TextBox();
        rotationHTBox.setSize("30px", "12px");
        rotationHTBox.setValue(viewModel.heading + "");
        rotationHTBox.addChangeHandler(tboxListener);
        rotationPTBox = new TextBox();
        rotationPTBox.setSize("30px", "12px");
        rotationPTBox.setValue(viewModel.pitch + "");
        rotationPTBox.addChangeHandler(tboxListener);
        rotationRTBox = new TextBox();
        rotationRTBox.setSize("30px", "12px");
        rotationRTBox.setValue(viewModel.roll + "");
        rotationRTBox.addChangeHandler(tboxListener);

        spinCBox = new CheckBox();
        spinCBox.setHTML("<font color=\"white\">Spin</font>");
        spinCBox.addValueChangeHandler(new MValueChangeHandler());

        flyCBox = new CheckBox();
        flyCBox.setHTML("<font color=\"white\">Fly</font>");
        flyCBox.addValueChangeHandler(new MValueChangeHandler());

        showCBox = new CheckBox();
        showCBox.setHTML("<font color=\"white\">Show</font>");
        showCBox.setValue(true);
        showCBox.addValueChangeHandler(new MValueChangeHandler());

        ListBox emitterLBox = new ListBox();
        emitterLBox.addItem("Circle", "Circle");
        emitterLBox.addItem("Cone", "Cone");
        emitterLBox.addItem("Box", "Box");
        emitterLBox.addItem("Sphere", "Sphere");
        emitterLBox.addChangeHandler(new ChangeHandler() {
            @Override
            public void onChange(ChangeEvent changeEvent) {
                ListBox source = (ListBox) changeEvent.getSource();
                switch (source.getSelectedValue()) {
                case "Circle":
                    particleSystem.emitter = new CircleEmitter(0.5);
                    break;
                case "Cone":
                    particleSystem.emitter = new ConeEmitter(Math.toRadians(45.0));
                    break;
                case "Box":
                    particleSystem.emitter = new BoxEmitter(new Cartesian3(10.0, 10.0, 10.0));
                    break;
                case "Sphere":
                    particleSystem.emitter = new SphereEmitter(5.0);
                    break;
                default:
                    break;
                }
            }
        });

        FlexTable flexTable = new FlexTable();
        flexTable.getElement().getStyle().setBackgroundColor("rgba(0, 0, 0, 0.5)");
        flexTable.setCellSpacing(2);
        flexTable.setCellPadding(2);

        flexTable.setHTML(0, 0, "<font color=\"white\">Rate</font>");
        flexTable.setWidget(0, 1, rateSlider);
        flexTable.setWidget(0, 2, rateTBox);

        flexTable.setHTML(1, 0, "<font color=\"white\">Size</font>");
        flexTable.setWidget(1, 1, sizeSlider);
        flexTable.setWidget(1, 2, sizeTBox);

        flexTable.setHTML(2, 0, "<font color=\"white\">Min Life</font>");
        flexTable.setWidget(2, 1, minLifeSlider);
        flexTable.setWidget(2, 2, minLifeTBox);

        flexTable.setHTML(3, 0, "<font color=\"white\">Max Life</font>");
        flexTable.setWidget(3, 1, maxLifeSlider);
        flexTable.setWidget(3, 2, maxLifeTBox);

        flexTable.setHTML(4, 0, "<font color=\"white\">Min Speed</font>");
        flexTable.setWidget(4, 1, minSpeedSlider);
        flexTable.setWidget(4, 2, minSpeedTBox);

        flexTable.setHTML(5, 0, "<font color=\"white\">Max Speed</font>");
        flexTable.setWidget(5, 1, maxSpeedSlider);
        flexTable.setWidget(5, 2, maxSpeedTBox);

        flexTable.setHTML(6, 0, "<font color=\"white\">Start Scale</font>");
        flexTable.setWidget(6, 1, startScaleSlider);
        flexTable.setWidget(6, 2, startScaleTBox);

        flexTable.setHTML(7, 0, "<font color=\"white\">End Scale</font>");
        flexTable.setWidget(7, 1, endScaleSlider);
        flexTable.setWidget(7, 2, endScaleTBox);

        flexTable.setHTML(8, 0, "<font color=\"white\">Gravity</font>");
        flexTable.setWidget(8, 1, gravitySlider);
        flexTable.setWidget(8, 2, gravityTBox);

        FlexTable transactionFTable = new FlexTable();
        transactionFTable.setHTML(0, 0, "<font color=\"white\">X</font>");
        transactionFTable.setWidget(0, 1, translationXTBox);
        transactionFTable.setHTML(0, 2, "<font color=\"white\">Y</font>");
        transactionFTable.setWidget(0, 3, translationYTBox);
        transactionFTable.setHTML(0, 4, "<font color=\"white\">Z</font>");
        transactionFTable.setWidget(0, 5, translationZTBox);

        flexTable.setHTML(9, 0, "<font color=\"white\">Translation</font>");
        flexTable.setWidget(9, 1, transactionFTable);

        FlexTable rotationFTable = new FlexTable();
        rotationFTable.setHTML(0, 0, "<font color=\"white\">H</font>");
        rotationFTable.setWidget(0, 1, rotationHTBox);
        rotationFTable.setHTML(0, 2, "<font color=\"white\">P</font>");
        rotationFTable.setWidget(0, 3, rotationPTBox);
        rotationFTable.setHTML(0, 4, "<font color=\"white\">R</font>");
        rotationFTable.setWidget(0, 5, rotationRTBox);

        flexTable.setHTML(10, 0, "<font color=\"white\">Rotation</font>");
        flexTable.setWidget(10, 1, rotationFTable);

        FlexTable btnFTable = new FlexTable();
        btnFTable.setWidget(0, 0, spinCBox);
        btnFTable.setWidget(0, 1, flyCBox);
        btnFTable.setWidget(0, 2, showCBox);
        btnFTable.setWidget(0, 3, emitterLBox);

        flexTable.setWidget(11, 1, btnFTable);

        return flexTable;
    }

    @Override
    public String[] getSourceCodeURLs() {
        String[] sourceCodeURLs = new String[1];
        sourceCodeURLs[0] = GWT.getModuleBaseURL() + "examples/" + "ParticleSystem.txt";
        return sourceCodeURLs;
    }

    public static class ViewModel {
        double emissionRate = 5.0;
        double gravity = 0.0;
        double minimumParticleLife = 1.0;
        double maximumParticleLife = 1.0;
        double minimumSpeed = 1.0;
        double maximumSpeed = 4.0;
        double startScale = 1.0;
        double endScale = 5.0;
        double particleSize = 25.0;
        double transX = 2.5;
        double transY = 4.0;
        double transZ = 1.0;
        double heading = 0.0;
        double pitch = 0.0;
        double roll = 0.0;
        boolean fly = true;
        boolean spin = true;
        boolean show = true;
    }

    private Matrix4 computeModelMatrix(Entity entity, JulianDate time) {
        Cartesian3 position = Property.getValueOrUndefined(entity.position, time, entityPosition);
        if (!Cesium.defined(position)) {
            return (Matrix4) JsObject.undefined();
        }

        Quaternion orientation = Property.getValueOrUndefined(entity.orientation, time, entityOrientation);
        if (!Cesium.defined(orientation)) {
            modelMatrix = Transforms.eastNorthUpToFixedFrame(position, (Ellipsoid) JsObject.undefined(),
                    modelMatrix);
        } else {
            modelMatrix = Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation, rotationMatrix),
                    position, modelMatrix);
        }
        return modelMatrix;
    }

    private Matrix4 computeEmitterModelMatrix() {
        hpr = org.cesiumjs.cs.core.HeadingPitchRoll.fromDegrees(viewModel.heading, viewModel.pitch, viewModel.roll,
                hpr);

        trs.translation = Cartesian3.fromElements(viewModel.transX, viewModel.transY, viewModel.transZ,
                translation);
        trs.rotation = Quaternion.fromHeadingPitchRoll(hpr, rotation);

        return Matrix4.fromTranslationRotationScale(trs, emitterModelMatrix);
    }

    //Generate a random circular pattern with varying heights.
    private SampledPositionProperty computeCirclularFlight(double lon, double lat, double radius) {
        SampledPositionProperty property = new SampledPositionProperty();
        for (int i = 0; i <= 360; i += 45) {
            double radians = Math.toRadians(i);
            JulianDate time = JulianDate.addSeconds(start, i, new JulianDate());
            Cartesian3 position = Cartesian3.fromDegrees(lon + (radius * 1.5 * java.lang.Math.cos(radians)),
                    lat + (radius * java.lang.Math.sin(radians)), Math.nextRandomNumber() * 500 + 1750);
            property.addSample(time, position);
        }
        return property;
    }

    private class MSliderListener implements SliderListener {

        @Override
        public void onStart(SliderEvent e) {

        }

        @Override
        public boolean onSlide(SliderEvent e) {
            Slider source = e.getSource();
            int value = source.getValue();
            if (source == rateSlider) {
                particleSystem.emissionRate = value;
                rateTBox.setValue("" + value);
            } else if (source == sizeSlider) {
                particleSystem.minimumImageSize.x = value;
                particleSystem.minimumImageSize.y = value;
                particleSystem.maximumImageSize.x = value;
                particleSystem.maximumImageSize.y = value;
                sizeTBox.setValue("" + value);
            } else if (source == minLifeSlider) {
                particleSystem.minimumParticleLife = value;
                minLifeTBox.setValue("" + value);
            } else if (source == maxLifeSlider) {
                particleSystem.maximumParticleLife = value;
                maxLifeTBox.setValue("" + value);
            } else if (source == minSpeedSlider) {
                particleSystem.minimumSpeed = value;
                minSpeedTBox.setValue("" + value);
            } else if (source == maxSpeedSlider) {
                particleSystem.maximumSpeed = value;
                maxSpeedTBox.setValue("" + value);
            } else if (source == startScaleSlider) {
                particleSystem.startScale = value;
                startScaleTBox.setValue("" + value);
            } else if (source == endScaleSlider) {
                particleSystem.endScale = value;
                endScaleTBox.setValue("" + value);
            } else if (source == gravitySlider) {
                viewModel.gravity = value;
                gravityTBox.setValue("" + value);
            }
            return true;
        }

        @Override
        public void onChange(SliderEvent e) {

        }

        @Override
        public void onStop(SliderEvent e) {

        }
    }

    private class MChangeHandler implements ChangeHandler {
        @Override
        public void onChange(ChangeEvent changeEvent) {
            TextBox source = (TextBox) changeEvent.getSource();
            int value = Integer.parseInt(source.getValue());
            if (source == rateTBox) {
                rateSlider.setValue(value);
                particleSystem.emissionRate = value;
            } else if (source == sizeTBox) {
                particleSystem.minimumImageSize.x = value;
                particleSystem.minimumImageSize.y = value;
                particleSystem.maximumImageSize.x = value;
                particleSystem.maximumImageSize.y = value;
                sizeSlider.setValue(value);
            } else if (source == minLifeTBox) {
                particleSystem.minimumParticleLife = value;
                minLifeSlider.setValue(value);
            } else if (source == maxLifeTBox) {
                particleSystem.maximumParticleLife = value;
                maxLifeSlider.setValue(value);
            } else if (source == minSpeedTBox) {
                particleSystem.minimumSpeed = value;
                minSpeedSlider.setValue(value);
            } else if (source == maxSpeedTBox) {
                particleSystem.maximumSpeed = value;
                maxSpeedSlider.setValue(value);
            } else if (source == startScaleTBox) {
                particleSystem.startScale = value;
                startScaleSlider.setValue(value);
            } else if (source == endScaleTBox) {
                particleSystem.endScale = value;
                endScaleSlider.setValue(value);
            } else if (source == gravityTBox) {
                viewModel.gravity = value;
                gravitySlider.setValue(value);
            } else if (source == translationXTBox) {
                viewModel.transX = value;
            } else if (source == translationYTBox) {
                viewModel.transY = value;
            } else if (source == translationZTBox) {
                viewModel.transZ = value;
            } else if (source == rotationHTBox) {
                viewModel.heading = value;
            } else if (source == rotationPTBox) {
                viewModel.pitch = value;
            } else if (source == rotationRTBox) {
                viewModel.roll = value;
            }
        }
    }

    private class MValueChangeHandler implements ValueChangeHandler<Boolean> {
        @Override
        public void onValueChange(ValueChangeEvent<Boolean> valueChangeEvent) {
            CheckBox source = (CheckBox) valueChangeEvent.getSource();
            boolean value = valueChangeEvent.getValue();
            if (source == spinCBox) {
                viewModel.spin = value;
            } else if (source == flyCBox) {
                if (value) {
                    entity.position = circularPosition;
                    entity.orientation = new VelocityOrientationProperty(circularPosition);
                } else {
                    entity.position = new ConstantPositionProperty(staticPosition);
                    entity.orientation = (Property) JsObject.undefined();
                }
            } else if (source == showCBox) {
                viewModel.show = value;
                entity.show = value;
                particleSystem.show = value;
            }
        }
    }
}