//////////////////////////////////////////////////////////////////////// // Global variables //////////////////////////////////////////////////// MouseGesture MG; // The mouse gesture integrator. Thing THING; // The thing to be commanded. // Global functions //////////////////////////////////////////////////// // // Initializations. // void setup() { // Set the applet size. size(400, 400); // Create the thing to be commanded. THING = new Thing(); // Create the mouse gesture integrator. MG = new MouseGesture(); // Register commands. MG.addCommand("[]", new ActionHit()); MG.addCommand("[D]", new ActionRotateStop()); MG.addCommand("[L]", new ActionRotateLeft()); MG.addCommand("[R]", new ActionRotateRight()); MG.addCommand("[U]", new ActionDrift()); MG.addCommand("[DU]", new ActionShapeCircle()); MG.addCommand("[DL]", new ActionShapeRectangle()); MG.addCommand("[DR]", new ActionShapeTriangle()); MG.addCommand("[DUD]", new ActionShapeStar()); MG.addCommand("[UDU]", new ActionColor(color(255, 255, 255))); MG.addCommand("[UR]", new ActionColor(color(255, 0, 0))); MG.addCommand("[UL]", new ActionColor(color( 0, 0, 255))); MG.addCommand("[UD]", new ActionColor(color( 0, 255, 0))); MG.addCommand("[URD]", new ActionColor(color(255, 255, 0))); MG.addCommand("[URU]", new ActionColor(color(255, 0, 255))); MG.addCommand("[UDL]", new ActionColor(color( 0, 255, 255))); } // // The main loop. // void loop() { background(0); THING.onLoop(); MG.onLoop(); } // Event handlers ////////////////////////////////////////////////////// void mousePressed() { MG.onPressed(); } void mouseDragged() { MG.onDragged(); } void mouseReleased() { MG.onReleased(); } // Class definitions /////////////////////////////////////////////////// // // Mouse gesture integration class. // // The object of this class integrates components of mouse gesture // interpretation. // class MouseGesture { // Constructor. MouseGesture() { _drawColor = 0; _maxNrVectors = 100; // Create and initialize components for mouse gesture interpretation. _vectorizer = new MGVectorizer(this); _sequencer = new MGSequencer(this); _commander = new MGCommander(this); _vectors = new MGVector[_maxNrVectors]; for (int i = 0; i < _maxNrVectors; i++) { _vectors[i] = new MGVector(i == _maxNrVectors - 1); // The last vector becomes the sentinel. } } // Event handlers. void onPressed() { _vectorizer.onPressed(); } void onDragged() { _vectorizer.onDragged(); } void onReleased() { _vectorizer.onReleased(); } // Add a command. void addCommand(String command, MGAction action) { _commander.addCommand(command, action); } // Main process. void onLoop() { // Set the stroke color and weight. if ((_drawColor += 10) > 100) _drawColor = -100; stroke(155 + abs(_drawColor)); strokeWeight(2); // Process all vectors. for (int i = 0; i < _maxNrVectors; i++) _vectors[i].onLoop(); // Process the mouse motion vectorizer. _vectorizer.onLoop(); } // Energize a vector. void energizeVector(char type) { // Repeat request for energization until a vector accept it. int i = 0; while (!_vectors[i++].energize(this, type)); // This loop is assured to be terminated because the sentinel stored at // the tail of _vectors[] always returns true from energize(). } // Data members int _drawColor; // Drawing color. MGVectorizer _vectorizer; // The mouse motion vectorizer. MGSequencer _sequencer; // The vector sequencer. MGCommander _commander; // The commander. int _maxNrVectors; // The maximum number of vectors. MGVector[] _vectors; // The mouse motion vectors. } // // Mouse motion vector class. // // This class is a visualization of mouse motion vector. The mouse // motion sequencer class MGSequencer analyzes mouse drag motions and // create objects of this class. // class MGVector { // Constructor. MGVector(boolean isSentinel) { _isSentinel = isSentinel; _energized = false; } // Energize. boolean energize(MouseGesture observer, char type) { // If it is the sentinel, pretend to be energized but do nothing. if (_isSentinel) return true; // If it has been already energized, reject the request. if (_energized) return false; // Initialize the vector with 'Fall' behavior. _energized = true; _observer = observer; _type = type; _x = mouseX; _y = mouseY; _behavior = new MGFall(this); // Request acknowledged. return true; } // Process the vector. void onLoop() { // If it has not been energized yet, do nothing. if (!_energized) return; // Draw it. drawShape(); // Behave. _behavior.behave(); } // Draw the vector shape. void drawShape() { push(); translate(_x, _y); switch (_type) { case ']': // Rotate 180 degrees. rotate(PI); /* Fall through */ case '[': // Draw a bracket. beginShape(LINE_STRIP); vertex(0, -10); vertex(-10, -10); vertex(-10, 10); vertex(0, 10); endShape(); break; case 'L': // Rotate 90 degrees. rotate(HALF_PI); /* Fall through */ case 'D': // Rotate 90 degrees. rotate(HALF_PI); /* Fall through */ case 'R': // Rotate 90 degrees. rotate(HALF_PI); /* Fall through */ case 'U': // Draw an arrow. beginShape(LINE_STRIP); vertex(0, 10); vertex(0, 0); vertex(-10, 0); vertex(0, -10); vertex(10, 0); vertex(0, 0); endShape(); break; } pop(); } // Change behavior to 'Enqueue'. void enqueue() { _behavior = new MGEnqueue(this); _x = width; _y = height - 10; } // Change behavior to 'Align'. void align(int x, int y) { _behavior = new MGAlign(this); _x = x; _y = y; } // Change behavior to 'Reject'. void reject() { _behavior = new MGReject(this); } // Change behavior to 'Launch'. void launch(String command) { _behavior = new MGLaunch(this, command); } // Suppress the vector; ready for next energization. void sleep() { _behavior = null; _energized = false; } // Data members. boolean _isSentinel; // Is this vector the sentinel? boolean _energized; // Is this vector eneregized? MouseGesture _observer; // The observer to be notified events. char _type; // The vector type. float _x; // X component of the vector location. float _y; // Y component of the vector location. MGBehavior _behavior; // Current vector behavior. } // // Abstract behavior class of mouse motion vector. // abstract class MGBehavior { // Constructor. MGBehavior(MGVector vector) { _vector = vector; } // Behave. abstract void behave(); // Data members. MGVector _vector; // The vector behaves. } // // 'Fall' behavior class. // // 'Free fall' from the mouse motion vectorizer. // class MGFall extends MGBehavior { MGFall(MGVector vector) { super(vector); _dx = random(-3, 3); _dy = -10; _life = 50; } public void behave() { _dy += 1.0; _vector._x += _dx; _vector._y += _dy; if (--_life <= 0) _vector.enqueue(); } float _dx; float _dy; int _life; } // // 'Enqueue' behavior class. // // After free fall from the vectorizer, the vector is enqueued toward // the sequencer, moving from right to left at the bottom of screen. // class MGEnqueue extends MGBehavior { MGEnqueue(MGVector vector) { super(vector); } public void behave() { _vector._x -= 5; MG._sequencer.tryAccept(_vector); } } // // 'Align' behavior class. // // If the sequencer accept the vector, it waits the completion of // a command sequence by arrival of a termination vector. // class MGAlign extends MGBehavior { MGAlign(MGVector vector) { super(vector); } public void behave() { /* Do nothing. */ } } // // 'Reject' behavior class. // // If the sequencer rejected the vector, it is thrown away. // class MGReject extends MGBehavior { MGReject(MGVector vector) { super(vector); _dx = random(10, 15); _dy = random(-25, -20); _life = 50; } public void behave() { _dy += 1.0; _vector._x += _dx; _vector._y += _dy; if (--_life <= 0) _vector.sleep(); } float _dx; float _dy; int _life; } // // 'Launch' behavior class. // // Once a command sequence is completed, the sequence of vectors are // launched upward. // class MGLaunch extends MGBehavior { MGLaunch(MGVector vector, String command) { super(vector); _command = command; _dy = 0; } public void behave() { _vector._y += _dy--; if (_vector._y < 0) { MG._commander.command(_command); _vector.sleep(); } } String _command; int _dy; } // // Mouse motion vectorizer class. // class MGVectorizer { MGVectorizer(MouseGesture owner) { _owner = owner; _radius = 30; _dragging = false; } void onPressed() { _anchorX = mouseX; _anchorY = mouseY; _dragging = true; _owner.energizeVector('['); } void onDragged() { if (dist(_anchorX, _anchorY, mouseX, mouseY) < _radius) return; int dx = mouseX - _anchorX; int dy = mouseY - _anchorY; _anchorX = mouseX; _anchorY = mouseY; _owner.energizeVector((abs(dx) >= abs(dy)) ? ((dx > 0) ? 'R' : 'L') : ((dy > 0) ? 'D' : 'U')); } void onReleased() { _owner.energizeVector(']'); _dragging = false; } void onLoop() { if (_dragging) { noFill(); ellipseMode(CENTER_DIAMETER); push(); translate(_anchorX, _anchorY); ellipse(0, 0, _radius * 2, _radius * 2); line(-_radius, -_radius, _radius, _radius); line(-_radius, _radius, _radius, -_radius); pop(); } } boolean _dragging; int _radius; int _anchorX; int _anchorY; MouseGesture _owner; } // // Mouse motion sequencer class. // class MGSequencer { MGSequencer(MouseGesture owner) { _owner = owner; _maxLenSequence = 10 + 2; _sequence = new MGVector[_maxLenSequence]; _index = 0; } void tryAccept(MGVector vector) { if (vector._x > _index * 20) return; if (vector._type == ']') { vector.align(_index * 20 + 10, height - 10); addVector(vector); launchSequence(); return; } if (_index < _maxLenSequence - 1) { if (((_index == 0) && (vector._type == '[')) || ((_index > 0) && (_sequence[_index - 1]._type != vector._type))) { vector.align(_index * 20 + 10, height - 10); addVector(vector); return; } } vector.reject(); } void addVector(MGVector vector){ _sequence[_index++] = vector; } void launchSequence() { String command = new String(""); for (int i = 0; i < _index; i++) { command += _sequence[i]._type; } _sequence[0].launch(command); for (int i = 1; i < _index; i++) { _sequence[i].launch(""); } _index = 0; } MouseGesture _owner; int _maxLenSequence; MGVector _sequence[]; int _index; } class MGCommander { MGCommander(MouseGesture owner) { _owner = owner; _actionMap = new Hashtable(); } void addCommand(String command, MGAction action) { _actionMap.put(command, action); } void command(String command) { MGAction action = (MGAction) (_actionMap.get(command)); if (action != null) { action.execute(); }; } MouseGesture _owner; Hashtable _actionMap; } interface MGAction { abstract void execute(); } class ActionShapeCircle implements MGAction { public void execute() { THING.shapeCircle(); } } class ActionRotateStop implements MGAction { public void execute() { THING.rotateStop(); } } class ActionRotateRight implements MGAction { public void execute() { THING.rotateRight(); } } class ActionRotateLeft implements MGAction { public void execute() { THING.rotateLeft(); } } class ActionDrift implements MGAction { public void execute() { THING.drift(); } } class ActionHit implements MGAction { public void execute() { THING.hit(); } } class ActionShapeRectangle implements MGAction { public void execute() { THING.shapeRectangle(); } } class ActionShapeTriangle implements MGAction { public void execute() { THING.shapeTriangle(); } } class ActionShapeStar implements MGAction { public void execute() { THING.shapeStar(); } } class ActionColor implements MGAction { ActionColor(color c) { _color = c; } public void execute() { THING.setColor(_color); } color _color; } class Thing { Thing() { _shape = new ShapeTriangle(); _color = color(255, 255, 255); _scale = 0.3; _angle = 0.0; _rotate = 0.0; _drift = 0.0; } void hit() { _scale = 1.0; } void rotateStop() { _rotate = 0.0; } void rotateRight() { if (_rotate < 0.3) _rotate += 0.01; } void rotateLeft() { if (_rotate > -0.3) _rotate -= 0.01; } void drift() { _drift = height / 2; } void shapeCircle() { _shape = new ShapeCircle(); } void shapeRectangle() { _shape = new ShapeRectangle(); } void shapeTriangle() { _shape = new ShapeTriangle(); } void shapeStar() { _shape = new ShapeStar(); } void setColor(color c) { _color = c; } void onLoop() { stroke(_color); strokeWeight(4); noFill(); push(); translate(width / 2, height / 2); rotate(_angle); translate(0.0, -_drift); scale(_scale); _shape.drawShape(); if (_scale > 0.3) _scale -= 0.01; if (_drift > 0.0) _drift -= 1; _angle += _rotate; pop(); } Shape _shape; color _color; float _scale; float _angle; float _rotate; float _drift; } interface Shape { abstract void drawShape(); } class ShapeCircle implements Shape { public void drawShape() { ellipseMode(CENTER_DIAMETER); ellipse(0, 0, width, height); } } class ShapeRectangle implements Shape { public void drawShape() { rectMode(CENTER_DIAMETER); rect(0, 0, width, height); } } class ShapeTriangle implements Shape { ShapeTriangle() { X0 = 0.0; Y0 = -height / 2.0; X1 = cos(PI / 6.0) * width / 2.0; Y1 = sin(PI / 6.0) * height / 2.0; } public void drawShape() { triangle(X0, Y0, X1, Y1, -X1, Y1); } float X0; float Y0; float X1; float Y1; } class ShapeStar implements Shape { float X = cos(PI / 10) * width / 2.0; float Y = -sin(PI / 10) * height / 2.0; public void drawShape() { for (int i = 0; i < 5; i++) { line(X, Y, -X, Y); rotate(PI * 0.4); } } }