Stardust in a Klein Bottle
Draws Klein Bottle using Stardust Particle Engine.
see also: http://en.wikipedia.org/wiki/Klein_bottle
/**
* Copyright wellflat ( http://wonderfl.net/user/wellflat )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/6RzY
*/
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.filters.GlowFilter;
import idv.cjcat.stardust.common.clocks.SteadyClock;
import idv.cjcat.stardust.threeD.renderers.DisplayObjectRenderer3D;
[SWF(width = 465, height = 465, backgroundColor = 0x00, frameRate = 30)]
/**
* Draws Klein Bottle using Stardust Particle Engine.
* see also: http://en.wikipedia.org/wiki/Klein_bottle
*/
public class Main extends Sprite {
private var size:int;
private var container:Sprite;
private var emitter:KleinBottleEmitter;
private var renderer:DisplayObjectRenderer3D;
public function Main():void {
Wonderfl.capture_delay(20);
stage.scaleMode = "noScale";
stage.align = "TL";
size = stage.stageWidth; // required square stage
graphics.beginFill(0);
graphics.drawRect(0, 0, size, size);
container = new Sprite();
container.x = container.y = size/2;
container.filters = [new GlowFilter(0x0099ff), new BlurFilter(2, 2, 1)];
addChild(container);
emitter = new KleinBottleEmitter(new SteadyClock(1), size);
renderer = new DisplayObjectRenderer3D(container);
renderer.addEmitter(emitter);
addEventListener(Event.ENTER_FRAME, draw, false, 0, true);
}
// control camera and plot point.
private function draw(e:Event):void {
rotate();
emitter.plot();
}
private function rotate():void {
var pi:Number = Math.PI;
var theta:Number = 1.00 * (mouseX - size/2)*pi/180;
var phy:Number = 0.80 * (mouseY - size/2)*pi/180;
var lb:Number = -0.45*pi, ub:Number = 0.45*pi;
if(phy < lb) phy = lb;
if(phy > ub) phy = ub;
var r:Number = 800;
var cp:Number = Math.cos(phy);
var x:Number = r*Math.sin(theta)*cp;
var y:Number = r*Math.sin(phy);
var z:Number = -r*Math.cos(theta)*cp;
renderer.camera.position.x = x;
renderer.camera.position.y = y;
renderer.camera.position.z = z;
renderer.camera.direction.set(-x, -y, -z);
}
}
}
import idv.cjcat.stardust.common.actions.*;
import idv.cjcat.stardust.common.actions.triggers.DeathTrigger;
import idv.cjcat.stardust.common.clocks.Clock;
import idv.cjcat.stardust.common.initializers.*;
import idv.cjcat.stardust.common.math.UniformRandom;
import idv.cjcat.stardust.threeD.actions.*;
import idv.cjcat.stardust.threeD.emitters.Emitter3D;
import idv.cjcat.stardust.threeD.initializers.*;
import idv.cjcat.stardust.threeD.zones.*;
class KleinBottleEmitter extends Emitter3D {
private const SCALE:int = 25;
private var size:int;
private var point:SinglePoint3D;
// have a increase in speed of vertex access, without using Vec3D Class.
// < x0, y0, z0, x1, y1, z1, ... >
private var vertices:Vector.<Number>;
private var pos:int;
public function KleinBottleEmitter(clock:Clock, size:int) {
super(clock);
this.size = size;
point = new SinglePoint3D();
addInitializer(new DisplayObjectClass3D(MaterialSeed));
addInitializer(new Life(new UniformRandom(550, 0)));
addInitializer(new Mask(1 | 2));
addInitializer(new Position3D(point));
var actions:CompositeAction = new CompositeAction();
actions.mask = 1 | 2 | 4;
actions.addAction(new Age());
actions.addAction(new DeathLife());
actions.addAction(new Move3D());
addAction(actions);
var spawn:Spawn3D = new Spawn3D(new UniformRandom(1, 0));
spawn.addInitializer(new Mask(1 | 4));
spawn.addInitializer(new DisplayObjectClass3D(MaterialSeed));
spawn.addInitializer(new Life(new UniformRandom(20, 10)));
spawn.addInitializer(new Velocity3D(new SphereShell(0, 0, 0, 10, 30)));
var trigger:DeathTrigger = new DeathTrigger();
trigger.mask = 2;
trigger.addAction(spawn);
addAction(trigger);
var scaleCurve:ScaleCurve = new ScaleCurve(0, 10);
scaleCurve.mask = 4;
addAction(scaleCurve);
// make verteces
vertices = new Vector.<Number>();
pos = 0;
var pi:Number = Math.PI;
var u:Number, v:Number, r:Number;
var step:int = 8;
for(var i:int = 0; i <= 2*pi*step; i++) {
for(var j:int = 0; j <= 2*pi*1.6; j++) {
u = i/step; v = j/1.6;
r = 4*(1 - Math.cos(u)/2);
if(u < pi) {
vertices[pos++] = (6*Math.cos(u)*(1 + Math.sin(u)) + r*Math.cos(u)*Math.cos(v))*SCALE;
vertices[pos++] = (16*Math.sin(u) + r*Math.sin(u)*Math.cos(v))*SCALE;
}else if(u > pi) {
vertices[pos++] = (6*Math.cos(u)*(1 + Math.sin(u)) + r*Math.cos(v + Math.PI))*SCALE;
vertices[pos++] = (16*Math.sin(u))*SCALE;
}
vertices[pos++] = r*Math.sin(v)*SCALE;
}
}
pos = 0;
}
public function plot():void {
try {
point.x = vertices[pos++];
point.y = vertices[pos++];
point.z = vertices[pos++];
this.step();
}catch(e:RangeError) {
pos = 0;
}
}
}
import flash.display.Shape;
class MaterialSeed extends Shape {
public function MaterialSeed() {
graphics.beginFill(0xffffff);
graphics.drawCircle(0, 0, 10);
}
}