three.quarks-editor
Version:
A Editor for three.quarks
194 lines (174 loc) • 8.88 kB
text/typescript
import {Object3D, Vector4} from "three";
import {
Behavior,
Bezier,
ColorGenerator, ColorRange, ConeEmitter, ConstantColor, ConstantValue, DonutEmitter, EmitterShape,
FunctionColorGenerator,
FunctionValueGenerator, Gradient, IntervalValue,
ParticleEmitter, PiecewiseBezier, PointEmitter, RandomColor,
RenderMode, SphereEmitter,
ValueGenerator,
ColorOverLife, FrameOverLife, OrbitOverLife,
RotationOverLife, SizeOverLife, SpeedOverLife, ApplyForce,
} from "three.quarks";
export class CodeExporter {
/*static traverseObject(parent: Object3D): string {
for (let i = 0; i < parent.children.length; i ++) {
}
}*/
static camelize(str: string): string {
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(word, index) {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
}).replace(/\s+/g, '');
}
static camelizeClass(str: string): string {
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(word, index) {
return word.toUpperCase();
}).replace(/\s+/g, '');
}
static exportBezier(func: Bezier) {
return `new Bezier(${func.p[0]}, ${func.p[1]}, ${func.p[2]}, ${func.p[3]})`;
}
static exportColor(color: Vector4) {
return `new Vector4(${color.x}, ${color.y}, ${color.z}, ${color.w})`;
}
static exportFunction(func: ValueGenerator | ColorGenerator | FunctionValueGenerator | FunctionColorGenerator, indent = 0): string {
if (func instanceof ConstantValue) {
return `new ConstantValue(${func.value})`;
} else if (func instanceof ConstantColor) {
return `new ConstantColor(${CodeExporter.exportColor(func.color)})`;
} else if (func instanceof IntervalValue) {
return `new IntervalValue(${func.a}, ${func.b})`;
} else if (func instanceof ColorRange) {
return `new ColorRange(${CodeExporter.exportColor(func.a)}, ${CodeExporter.exportColor(func.b)})`;
} else if (func instanceof RandomColor) {
return `new RandomColor(${CodeExporter.exportColor(func.a)}, ${CodeExporter.exportColor(func.b)})`;
} else if (func instanceof Gradient) {
let code = `new Gradient(\n`;
for (let i = 0; i < func.functions.length - 1; i ++) {
code += ' '.repeat(indent + 4) + `[${CodeExporter.exportFunction(func.functions[i][0])}, ${func.functions[i][1]}], `;
}
code += ' '.repeat(indent + 4) + `[${CodeExporter.exportFunction(func.functions[func.functions.length - 1][0])}, ${func.functions[func.functions.length - 1][1]}]`;
code += ' '.repeat(indent) + `)`;
return code;
} else if (func instanceof PiecewiseBezier) {
let code = `new PiecewiseBezier(\n`;
for (let i = 0; i < func.functions.length - 1; i ++) {
code += ' '.repeat(indent + 4) + `[${CodeExporter.exportBezier(func.functions[i][0])}, ${func.functions[i][1]}], `;
}
code += ' '.repeat(indent + 4) + `[${CodeExporter.exportBezier(func.functions[func.functions.length - 1][0])}, ${func.functions[func.functions.length - 1][1]}]`;
code += ' '.repeat(indent) + `)`;
return code;
}
throw new Error();
}
static exportParticleEmitter(emitter: ParticleEmitter): string {
const name = CodeExporter.camelize(emitter.name);
const system = emitter.system;
let code = ` this.${name} = new ParticleSystem(renderer, {\n`;
code += ` duration: ${system.duration},\n`;
code += ` looping: ${system.looping},\n`;
code += ` startLife: ${CodeExporter.exportFunction(system.startLife)},\n`;
code += ` startSpeed: ${CodeExporter.exportFunction(system.startSpeed)},\n`;
code += ` startSize: ${CodeExporter.exportFunction(system.startSize)},\n`;
code += ` startColor: ${CodeExporter.exportFunction(system.startColor)},\n`;
code += ` worldSpace: ${system.worldSpace},\n`;
code += ` emissionOverTime: ${CodeExporter.exportFunction(system.emissionOverTime)},\n`;
code += ` emissionBursts: ${system.emissionBursts},\n`;
code += ` shape: ${CodeExporter.exportShape(system.emitterShape)},\n`;
code += ` texture: texture,\n`;
code += ` blending: ${system.blending},\n`;
code += ` startTileIndex: ${system.startTileIndex},\n`;
code += ` uTileCount: ${system.uTileCount},\n`;
code += ` vTileCount: ${system.vTileCount},\n`;
code += ` renderMode: ${system.renderMode},\n`;
if (system.renderMode === RenderMode.StretchedBillBoard) {
code += ` speedFactor: ${system.speedFactor},\n`;
}
code += ' });\n';
for (let i = 0; i < system.behaviors.length; i ++) {
code += ` this.${name}.addBehavior(${CodeExporter.exportBehavior(system.behaviors[i])});\n`;
}
code += ` this.${name}.emitter.renderOrder = ${system.emitter.renderOrder};\n`
code += ` this.${name}.emitter.name = '${name}';\n`
code += ` this.${name}.emitter.rotation.set(${system.emitter.rotation.x}, ${system.emitter.rotation.y}, ${system.emitter.rotation.z});\n`;
code += ` this.add(this.${name}.emitter);\n`
code += '\n';
return code;
}
static exportShape(shape: EmitterShape) {
const json = shape.toJSON();
//@ts-ignore
delete json.type;
const params = JSON.stringify(json);
const unquoted = params.replace(/"([^"]+)":/g, '$1:');
if (shape instanceof PointEmitter) {
return "new PointEmitter()";
}if (shape instanceof SphereEmitter) {
return "new SphereEmitter(" + unquoted + ")";
}if (shape instanceof ConeEmitter) {
return "new ConeEmitter(" + unquoted + ")";
}if (shape instanceof DonutEmitter) {
return "new DonutEmitter(" + unquoted + ")";
}
}
static exportBehavior(behavior: Behavior) {
let func;
switch (behavior.type) {
case 'ApplyForce':
func = CodeExporter.exportFunction((behavior as ApplyForce).force);
break;
case 'ColorOverLife':
func = CodeExporter.exportFunction((behavior as ColorOverLife).color);
break;
case 'RotationOverLife':
func = CodeExporter.exportFunction((behavior as RotationOverLife).angularVelocity);
break;
case 'SizeOverLife':
func = CodeExporter.exportFunction((behavior as SizeOverLife).size);
break;
case 'SpeedOverLife':
func = CodeExporter.exportFunction((behavior as SpeedOverLife).speed);
break;
case 'FrameOverLife':
func = CodeExporter.exportFunction((behavior as FrameOverLife).frame);
break;
case 'OrbitOverLife':
func = CodeExporter.exportFunction((behavior as OrbitOverLife).orbitSpeed);
break;
default:
func = behavior;
}
return "new " + behavior.type + "(" + func + ")";
}
static exportCode(root: Object3D): string {
let code = `export class ${CodeExporter.camelizeClass(root.name)} extends Group {\n`;
for (let i = 0; i < root.children.length; i ++) {
if (root.children[i] instanceof ParticleEmitter) {
code += ` private ${CodeExporter.camelize(root.children[i].name)}: ParticleSystem;\n`
}
}
code += '\n';
code += ` constructor() {\n`;
code += ` super();\n`;
code += ` this.name = '${root.name}';\n`;
code += ` let texture = new TextureLoader().load( "textures/texture1.png");\n`;
code += ` texture.name = "textures/texture1.png";\n`;
for (let i = 0; i < root.children.length; i ++) {
if (root.children[i] instanceof ParticleEmitter) {
code += CodeExporter.exportParticleEmitter(root.children[i] as ParticleEmitter);
}
}
code += ' }\n';
code += '\n';
code += ' update(delta: number) {\n';
for (let i = 0; i < root.children.length; i ++) {
if (root.children[i] instanceof ParticleEmitter) {
code += ` this.${CodeExporter.camelize(root.children[i].name)}.update(delta);\n`
}
}
code += ' }\n';
code += '}';
return code;
}
}