ShadowEditor/ShadowEditor.Web/src/editor/component/ParticleEmitterComponent.jsx
2019-08-17 22:59:19 +08:00

467 lines
17 KiB
JavaScript

import { PropertyGrid, PropertyGroup, TextProperty, DisplayProperty, CheckBoxProperty, ButtonProperty, NumberProperty, SelectProperty, ColorProperty, TextureProperty, ButtonsProperty, Button, IntegerProperty } from '../../third_party';
import SetValueCommand from '../../command/SetValueCommand';
import Converter from '../../utils/Converter';
import Ajax from '../../utils/Ajax';
/**
* 粒子发射器组件
* @author tengge / https://github.com/tengge1
*/
class ParticleEmitterComponent extends React.Component {
constructor(props) {
super(props);
this.selected = null;
this.isPlaying = false;
this.state = {
show: false,
expanded: true,
positionX: 0,
positionY: 0,
positionZ: 0,
positionSpreadX: 0,
positionSpreadY: 0,
positionSpreadZ: 0,
velocityX: 0,
velocityY: 0,
velocityZ: 0,
velocitySpreadX: 0,
velocitySpreadY: 0,
velocitySpreadZ: 0,
accelerationX: 0,
accelerationY: 0,
accelerationZ: 0,
accelerationSpreadX: 0,
accelerationSpreadY: 0,
accelerationSpreadZ: 0,
color1: null,
color2: null,
color3: null,
color4: null,
size: 1,
sizeSpread: 0,
texture: null,
particleCount: 1000,
maxAge: 5,
maxAgeSpread: 2,
previewText: _t('Preview'),
};
this.handleExpand = this.handleExpand.bind(this);
this.handleUpdate = this.handleUpdate.bind(this);
this.handleChangePosition = this.handleChangePosition.bind(this);
this.handleChangeVelocity = this.handleChangeVelocity.bind(this);
this.handleChangeAcceleration = this.handleChangeAcceleration.bind(this);
this.handleChangeColor = this.handleChangeColor.bind(this);
this.handleChangeSize = this.handleChangeSize.bind(this);
this.handleChangeTexture = this.handleChangeTexture.bind(this);
this.handleChangeParticleCount = this.handleChangeParticleCount.bind(this);
this.handleChangeMaxAge = this.handleChangeMaxAge.bind(this);
this.handleChangeMaxAgeSpread = this.handleChangeMaxAgeSpread.bind(this);
this.handlePreview = this.handlePreview.bind(this);
this.startPreview = this.startPreview.bind(this);
this.stopPreview = this.stopPreview.bind(this);
this.onAnimate = this.onAnimate.bind(this);
}
render() {
const {
show, expanded, positionX, positionY, positionZ, positionSpreadX, positionSpreadY, positionSpreadZ, velocityX, velocityY, velocityZ,
velocitySpreadX, velocitySpreadY, velocitySpreadZ, accelerationX, accelerationY, accelerationZ, accelerationSpreadX, accelerationSpreadY,
accelerationSpreadZ, color1, color2, color3, color4, size, sizeSpread, texture, particleCount, maxAge, maxAgeSpread, previewText
} = this.state;
if (!show) {
return null;
}
return <PropertyGroup title={_t('ParticleEmitter')} show={show} expanded={expanded} onExpand={this.handleExpand}>
<NumberProperty label={`${_t('Position')}X`} name={'positionX'} value={positionX} onChange={this.handleChangePosition}></NumberProperty>
<NumberProperty label={`${_t('Position')}Y`} name={'positionY'} value={positionY} onChange={this.handleChangePosition}></NumberProperty>
<NumberProperty label={`${_t('Position')}Z`} name={'positionZ'} value={positionZ} onChange={this.handleChangePosition}></NumberProperty>
<NumberProperty label={`${_t('PositionSpread')}X`} name={'positionSpreadX'} value={positionSpreadX} onChange={this.handleChangePosition}></NumberProperty>
<NumberProperty label={`${_t('PositionSpread')}Y`} name={'positionSpreadY'} value={positionSpreadY} onChange={this.handleChangePosition}></NumberProperty>
<NumberProperty label={`${_t('PositionSpread')}Z`} name={'positionSpreadZ'} value={positionSpreadZ} onChange={this.handleChangePosition}></NumberProperty>
<NumberProperty label={`${_t('Velocity')}X`} name={'velocityX'} value={velocityX} onChange={this.handleChangeVelocity}></NumberProperty>
<NumberProperty label={`${_t('Velocity')}Y`} name={'velocityY'} value={velocityY} onChange={this.handleChangeVelocity}></NumberProperty>
<NumberProperty label={`${_t('Velocity')}Z`} name={'velocityZ'} value={velocityZ} onChange={this.handleChangeVelocity}></NumberProperty>
<NumberProperty label={`${_t('VelocitySpread')}X`} name={'velocitySpreadX'} value={velocitySpreadX} onChange={this.handleChangeVelocity}></NumberProperty>
<NumberProperty label={`${_t('VelocitySpread')}Y`} name={'velocitySpreadY'} value={velocitySpreadY} onChange={this.handleChangeVelocity}></NumberProperty>
<NumberProperty label={`${_t('VelocitySpread')}Z`} name={'velocitySpreadZ'} value={velocitySpreadZ} onChange={this.handleChangeVelocity}></NumberProperty>
<NumberProperty label={`${_t('Acceleration')}X`} name={'accelerationX'} value={accelerationX} onChange={this.handleChangeAcceleration}></NumberProperty>
<NumberProperty label={`${_t('Acceleration')}Y`} name={'accelerationY'} value={accelerationY} onChange={this.handleChangeAcceleration}></NumberProperty>
<NumberProperty label={`${_t('Acceleration')}Z`} name={'accelerationZ'} value={accelerationZ} onChange={this.handleChangeAcceleration}></NumberProperty>
<NumberProperty label={`${_t('AccelerationSpread')}X`} name={'accelerationSpreadX'} value={accelerationSpreadX} onChange={this.handleChangeAcceleration}></NumberProperty>
<NumberProperty label={`${_t('AccelerationSpread')}Y`} name={'accelerationSpreadY'} value={accelerationSpreadY} onChange={this.handleChangeAcceleration}></NumberProperty>
<NumberProperty label={`${_t('AccelerationSpread')}Z`} name={'accelerationSpreadZ'} value={accelerationSpreadZ} onChange={this.handleChangeAcceleration}></NumberProperty>
<ColorProperty label={`${_t('Color')}1`} name={'color1'} value={color1} onChange={this.handleChangeColor}></ColorProperty>
<ColorProperty label={`${_t('Color')}2`} name={'color2'} value={color2} onChange={this.handleChangeColor}></ColorProperty>
<ColorProperty label={`${_t('Color')}3`} name={'color3'} value={color3} onChange={this.handleChangeColor}></ColorProperty>
<ColorProperty label={`${_t('Color')}4`} name={'color4'} value={color4} onChange={this.handleChangeColor}></ColorProperty>
<NumberProperty label={`${_t('Size')}`} name={'size'} value={size} onChange={this.handleChangeSize}></NumberProperty>
<NumberProperty label={`${_t('SizeSpread')}`} name={'sizeSpread'} value={sizeSpread} onChange={this.handleChangeSize}></NumberProperty>
<TextureProperty label={`${_t('Texture')}`} name={'texture'} value={texture} onChange={this.handleChangeTexture}></TextureProperty>
<IntegerProperty label={`${_t('ParticleCount')}`} name={'particleCount'} value={particleCount} onChange={this.handleChangeParticleCount}></IntegerProperty>
<NumberProperty label={`${_t('MaxAge')}`} name={'maxAge'} value={maxAge} onChange={this.handleChangeMaxAge}></NumberProperty>
<NumberProperty label={`${_t('maxAgeSpread')}`} name={'maxAgeSpread'} value={maxAgeSpread} onChange={this.maxAgeSpread}></NumberProperty>
<ButtonProperty text={previewText} onChange={this.handlePreview}></ButtonProperty>
</PropertyGroup>;
}
componentDidMount() {
app.on(`objectSelected.ParticleEmitterComponent`, this.handleUpdate);
app.on(`objectChanged.ParticleEmitterComponent`, this.handleUpdate);
}
handleExpand(expanded) {
this.setState({
expanded,
});
}
handleUpdate() {
const editor = app.editor;
if (!editor.selected || !(editor.selected.userData.type === 'ParticleEmitter')) {
this.setState({
show: false,
});
return;
}
this.selected = editor.selected;
let group = this.selected.userData.group;
let emitter = group.emitters[0];
let state = {
show: true,
positionX: emitter.position.value.x,
positionY: emitter.position.value.y,
positionZ: emitter.position.value.z,
positionSpreadX: emitter.position.spread.x,
positionSpreadY: emitter.position.spread.y,
positionSpreadZ: emitter.position.spread.z,
velocityX: emitter.velocity.value.x,
velocityY: emitter.velocity.value.y,
velocityZ: emitter.velocity.value.z,
velocitySpreadX: emitter.velocity.spread.x,
velocitySpreadY: emitter.velocity.spread.y,
velocitySpreadZ: emitter.velocity.spread.z,
accelerationX: emitter.acceleration.value.x,
accelerationY: emitter.acceleration.value.y,
accelerationZ: emitter.acceleration.value.z,
accelerationSpreadX: emitter.acceleration.spread.x,
accelerationSpreadY: emitter.acceleration.spread.y,
accelerationSpreadZ: emitter.acceleration.spread.z,
color1: `#${emitter.color.value[0].getHexString()}`,
color2: `#${emitter.color.value[1].getHexString()}`,
color3: `#${emitter.color.value[2].getHexString()}`,
color4: `#${emitter.color.value[3].getHexString()}`,
size: emitter.size.value[0],
sizeSpread: emitter.size.spread[0],
texture: group.texture,
particleCount: emitter.particleCount,
maxAge: emitter.maxAge.value,
maxAgeSpread: emitter.maxAge.spread,
previewText: this.isPlaying ? _t('Cancel') : _t('Preview')
};
this.setState(state);
}
handleChangePosition(value, name) {
this.setState({
[name]: value,
});
if (value === null) {
return;
}
const { positionX, positionY, positionZ, positionSpreadX, positionSpreadY, positionSpreadZ } = Object.assign({}, this.state, {
[name]: value,
});
let group = this.selected.userData.group;
let emitter = group.emitters[0];
emitter.position.value.x = positionX;
emitter.position.value.y = positionY;
emitter.position.value.z = positionZ;
emitter.position.spread.x = positionSpreadX;
emitter.position.spread.y = positionSpreadY;
emitter.position.spread.z = positionSpreadZ;
emitter.updateFlags.position = true;
app.call(`objectChanged`, this, this.selected);
}
handleChangeVelocity(value, name) {
this.setState({
[name]: value,
});
if (value === null) {
return;
}
const { velocityX, velocityY, velocityZ, velocitySpreadX, velocitySpreadY, velocitySpreadZ } = Object.assign({}, this.selected, {
[name]: value,
});
let group = this.selected.userData.group;
let emitter = group.emitters[0];
emitter.velocity.value.x = velocityX;
emitter.velocity.value.y = velocityY;
emitter.velocity.value.z = velocityZ;
emitter.velocity.spread.x = velocitySpreadX;
emitter.velocity.spread.y = velocitySpreadY;
emitter.velocity.spread.z = velocitySpreadZ;
emitter.updateFlags.velocity = true;
app.call(`objectChanged`, this, this.selected);
}
handleChangeAcceleration(value, name) {
if (value === null) {
this.setState({
[name]: value,
});
return;
}
const { accelerationX, accelerationY, accelerationZ, accelerationSpreadX, accelerationSpreadY, accelerationSpreadZ } = Object.assign({}, this.state, {
[name]: value,
});
let group = this.selected.userData.group;
let emitter = group.emitters[0];
emitter.acceleration.value.x = accelerationX;
emitter.acceleration.value.y = accelerationY;
emitter.acceleration.value.z = accelerationZ;
emitter.acceleration.spread.x = accelerationSpreadX;
emitter.acceleration.spread.y = accelerationSpreadY;
emitter.acceleration.spread.z = accelerationSpreadZ;
emitter.updateFlags.acceleration = true;
app.call(`objectChanged`, this, this.selected);
}
handleChangeColor(value, name) {
if (value === null) {
this.setState({
[name]: value,
});
return;
}
const { color1, color2, color3, color4 } = Object.assign({}, this.state, {
[name]: value,
});
let group = this.selected.userData.group;
let emitter = group.emitters[0];
emitter.color.value[0] = new THREE.Color(color1);
emitter.color.value[1] = new THREE.Color(color2);
emitter.color.value[2] = new THREE.Color(color3);
emitter.color.value[3] = new THREE.Color(color4);
emitter.updateFlags.color = true;
app.call(`objectChanged`, this, this.selected);
}
handleChangeSize(value, name) {
if (value === null) {
this.setState({
[name]: value,
});
return;
}
const { size, sizeSpread } = Object.assign({}, this.state, {
[name]: value,
});
let group = this.selected.userData.group;
let emitter = group.emitters[0];
for (var i = 0; i < emitter.size.value.length; i++) {
emitter.size.value[i] = size;
emitter.size.spread[i] = sizeSpread;
}
emitter.updateFlags.size = true;
app.call(`objectChanged`, this, this.selected);
}
handleChangeTexture(value, name) {
if (value === null) {
this.setState({
[name]: value,
});
return;
}
const { texture } = Object.assign({}, this.state, {
[name]: value,
});
let group = this.selected.userData.group;
let emitter = group.emitters[0];
texture.needsUpdate = true;
group.texture = texture;
group.material.uniforms.texture.value = texture;
app.call(`objectChanged`, this, this.selected);
}
handleChangeParticleCount(value, name) {
if (value === null) {
this.setState({
[name]: value,
});
return;
}
const { particleCount } = Object.assign({}, this.state, {
[name]: value,
});
let group = this.selected.userData.group;
let emitter = group.emitters[0];
emitter.particleCount = particleCount;
emitter.updateFlags.params = true;
app.call(`objectChanged`, this, this.selected);
}
handleChangeMaxAge(value, name) {
if (value === null) {
this.setState({
[name]: value,
});
return;
}
const { maxAge } = Object.assign({}, this.state, {
[name]: value,
});
let group = this.selected.userData.group;
let emitter = group.emitters[0];
emitter.maxAge.value = maxAge;
emitter.updateFlags.params = true;
app.call(`objectChanged`, this, this.selected);
}
handleChangeMaxAgeSpread(value, name) {
if (value === null) {
this.setState({
[name]: value,
});
return;
}
const { maxAgeSpread } = Object.assign({}, this.state, {
[name]: value,
});
let group = this.selected.userData.group;
let emitter = group.emitters[0];
emitter.maxAge.spread = maxAgeSpread;
emitter.updateFlags.params = true;
app.call(`objectChanged`, this, this.selected);
}
handlePreview() {
if (this.isPlaying) {
this.stopPreview();
} else {
this.startPreview();
}
}
startPreview() {
this.isPlaying = true;
this.setState({
previewText: _t('Cancel'),
});
app.on(`animate.ParticleEmitterComponent`, this.onAnimate);
}
stopPreview() {
this.isPlaying = false;
this.setState({
previewText: _t('Preview'),
});
let group = this.selected.userData.group;
let emitter = this.selected.userData.emitter;
group.removeEmitter(emitter);
group.addEmitter(emitter);
group.tick(0);
app.on(`animate.ParticleEmitterComponent`, null);
}
onAnimate(clock, deltaTime) {
let group = this.selected.userData.group;
group.tick(deltaTime);
}
}
export default ParticleEmitterComponent;