From f52d9c12936129c6407325fc69a4b414fb680b26 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Thu, 2 Jul 2015 14:54:09 -0700 Subject: [PATCH] added paint scripts for polylines --- examples/hydraPolyLinePaint.js | 233 +++++++++++++++++++++++++++++++ examples/mousePolyLinePaint.js | 248 +++++++++++++++++++++++++++++++++ 2 files changed, 481 insertions(+) create mode 100644 examples/hydraPolyLinePaint.js create mode 100644 examples/mousePolyLinePaint.js diff --git a/examples/hydraPolyLinePaint.js b/examples/hydraPolyLinePaint.js new file mode 100644 index 0000000000..b0336a48da --- /dev/null +++ b/examples/hydraPolyLinePaint.js @@ -0,0 +1,233 @@ +// +// hydraPaint.js +// examples +// +// Created by Eric Levin on 5/14/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to paint with the hydra! +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +var LEFT = 0; +var RIGHT = 1; +var LASER_WIDTH = 3; +var LASER_COLOR = { + red: 50, + green: 150, + blue: 200 +}; +var TRIGGER_THRESHOLD = .02; + +var MAX_POINTS_PER_LINE = 50; + +var LIFETIME = 6000; +var DRAWING_DEPTH = 2; +var LINE_DIMENSIONS = 100; + + +var DISTANCE_FROM_HAND = 5; +var MIN_POINT_DISTANCE = 0.01; + +var MIN_BRUSH_RADIUS = 0.04; +var MAX_BRUSH_RADIUS = 0.08; + +var RIGHT_BUTTON_1 = 7 +var RIGHT_BUTTON_2 = 8 +var RIGHT_BUTTON_3 = 9; +var RIGHT_BUTTON_4 = 10 +var LEFT_BUTTON_1 = 1; +var LEFT_BUTTON_2 = 2; +var LEFT_BUTTON_3 = 3; +var LEFT_BUTTON_4 = 4; + +var colorPalette = [{ + red: 10, + green: 208, + blue: 60 +}, { + red: 214, + green: 91, + blue: 67 +}, { + red: 192, + green: 41, + blue: 66 +}, { + red: 84, + green: 36, + blue: 55 +}, { + red: 83, + green: 119, + blue: 122 +}]; + +var MIN_STROKE_WIDTH = 0.002; +var MAX_STROKE_WIDTH = 0.05; + +function controller(side, cycleColorButton) { + this.triggerHeld = false; + this.triggerThreshold = 0.9; + this.side = side; + this.palm = 2 * side; + this.tip = 2 * side + 1; + this.trigger = side; + this.cycleColorButton = cycleColorButton; + + this.points = []; + this.normals = []; + this.strokeWidths = []; + + this.currentColorIndex = 0; + this.currentColor = colorPalette[this.currentColorIndex]; + + + this.brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: this.currentColor, + dimensions: { + x: MIN_BRUSH_RADIUS, + y: MIN_BRUSH_RADIUS, + z: MIN_BRUSH_RADIUS + } + }); + + this.cycleColor = function() { + this.currentColor = colorPalette[++this.currentColorIndex]; + if (this.currentColorIndex === colorPalette.length - 1) { + this.currentColorIndex = -1; + } + } + this.newLine = function(position) { + print("NEW LINE") + this.linePosition = position; + this.line = Entities.addEntity({ + position: position, + type: "PolyLine", + color: this.currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + lineWidth: 0.1, + lifetime: LIFETIME + }); + this.points = []; + this.normals = [] + this.strokeWidths = []; + } + + this.update = function(deltaTime) { + this.updateControllerState(); + + var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); + var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); + var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) + Entities.editEntity(this.brush, { + position: newBrushPos, + color: this.currentColor, + dimensions: { + x: brushRadius, + y: brushRadius, + z: brushRadius + } + }); + + + if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { + this.newLine(this.palmPosition); + this.drawing = true; + } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { + this.drawing = false; + } + + if (this.drawing) { + var localPoint = Vec3.subtract(newBrushPos, this.linePosition); + if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + // print("NOT ENOUGH DISTANCE BETWEEN POINTS!!"); + return; + } + + this.points.push(localPoint); + var normal = computeNormal(newBrushPos, Camera.getPosition()); + + this.normals.push(normal); + var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); + this.strokeWidths.push(strokeWidth); + Entities.editEntity(this.line, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + color: this.currentColor + }); + + if (this.points.length > MAX_POINTS_PER_LINE) { + this.newLine(newBrushPos); + this.points.push(Vec3.subtract(newBrushPos, this.linePosition)); + this.normals.push(computeNormal(newBrushPos, Camera.getPosition())); + this.strokeWidths.push(MIN_STROKE_WIDTH); + } + } + } + + + this.updateControllerState = function() { + this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton); + this.palmPosition = Controller.getSpatialControlPosition(this.palm); + this.tipPosition = Controller.getSpatialControlPosition(this.tip); + this.palmNormal = Controller.getSpatialControlNormal(this.palm); + this.triggerValue = Controller.getTriggerValue(this.trigger); + + + if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { + this.cycleColor(); + Entities.editEntity(this.brush, { + // color: this.currentColor + }); + } + + this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; + + } + + this.cleanup = function() { + Entities.deleteEntity(this.brush); + } +} + +function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); +} + +function update(deltaTime) { + leftController.update(deltaTime); + rightController.update(deltaTime); +} + +function scriptEnding() { + leftController.cleanup(); + rightController.cleanup(); +} + +function vectorIsZero(v) { + return v.x === 0 && v.y === 0 && v.z === 0; +} + + +var rightController = new controller(RIGHT, RIGHT_BUTTON_4); +var leftController = new controller(LEFT, LEFT_BUTTON_4); +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} \ No newline at end of file diff --git a/examples/mousePolyLinePaint.js b/examples/mousePolyLinePaint.js new file mode 100644 index 0000000000..14949c6c5c --- /dev/null +++ b/examples/mousePolyLinePaint.js @@ -0,0 +1,248 @@ +// +// paint.js +// examples +// +// Created by Eric Levin on 6/4/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to paint with the hydra or mouse! +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +var LINE_DIMENSIONS = 5; +var LIFETIME = 6000; +var EVENT_CHANGE_THRESHOLD = 200; +var LINE_WIDTH = .05; +var MAX_POINTS = 10; +var points = []; +var normals = []; +var strokeWidths = []; +var count = 0; +var prevEvent = null; + +var MIN_POINT_DISTANCE = .01; + +var colorPalette = [{ + red: 236, + green: 208, + blue: 120 +}, { + red: 214, + green: 91, + blue: 67 +}, { + red: 192, + green: 41, + blue: 66 +}, { + red: 84, + green: 36, + blue: 55 +}, { + red: 83, + green: 119, + blue: 122 +}]; + +var currentColorIndex = 0; +var currentColor = colorPalette[currentColorIndex]; + +function cycleColor() { + currentColor = colorPalette[++currentColorIndex]; + if (currentColorIndex === colorPalette.length - 1) { + currentColorIndex = -1; + } + +} + +MousePaint(); + +function MousePaint() { + var DRAWING_DISTANCE = 5; + var lines = []; + var isDrawing = false; + + var line, linePosition; + + var BRUSH_SIZE = .05; + + var brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: currentColor, + dimensions: { + x: BRUSH_SIZE, + y: BRUSH_SIZE, + z: BRUSH_SIZE + } + }); + + + function newLine(position) { + linePosition = position; + line = Entities.addEntity({ + position: position, + type: "PolyLine", + color: currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + linePoints: [], + lineWidth: LINE_WIDTH, + lifetime: LIFETIME + }); + points = []; + normals = [] + strokeWidths = []; + } + + + + function mouseMoveEvent(event) { + + var pickRay = Camera.computePickRay(event.x, event.y); + count++; + var worldPoint = computeWorldPoint(pickRay); + Entities.editEntity(brush, { + position: worldPoint + }); + + + if (!isDrawing) { + return; + } + var eventChange = Math.sqrt(Math.pow(event.x - prevEvent.x, 2) + Math.pow(event.y - prevEvent.y, 2)); + //print("EVENT CHANGE " + eventChange) + if (eventChange > EVENT_CHANGE_THRESHOLD) { + print("PAST THRESHOLD!") + return; + } + + + var localPoint = computeLocalPoint(worldPoint); + if (Vec3.distance(points[points.length - 1], localPoint) < MIN_POINT_DISTANCE) { + print("NOT ENOUGH DISTANCE BETWEEN MOUSE MOVES") + return; + } + var width = (Math.sin(count / 100) + 1.1) / 10; + points.push(localPoint) + normals.push(computeNormal(worldPoint, pickRay.origin)); + strokeWidths.push(.07); + Entities.editEntity(line, { + strokeWidths: strokeWidths, + linePoints: points, + normals: normals, + }); + if (points.length > MAX_POINTS) { + newLine(worldPoint); + var localPoint = computeLocalPoint(worldPoint); + points.push(localPoint); + normals.push(computeNormal(worldPoint, pickRay.origin)); + strokeWidths.push(.07); + + } + prevEvent = event; + } + + function undoStroke() { + var deletedLine = lines.pop(); + var deletedLineProps = Entities.getEntityProperties(deletedLine); + deletedLines.push(deletedLineProps); + Entities.deleteEntity(deletedLine); + } + + function redoStroke() { + var restoredLine = Entities.addEntity(deletedLines.pop()); + Entities.addEntity(restoredLine); + lines.push(restoredLine); + } + + function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); + } + + function computeWorldPoint(pickRay) { + var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE); + return Vec3.sum(pickRay.origin, addVector); + } + + function computeLocalPoint(worldPoint) { + + var localPoint = Vec3.subtract(worldPoint, linePosition); + return localPoint; + } + + function mousePressEvent(event) { + if (!event.isLeftButton) { + isDrawing = false; + return; + } + var pickRay = Camera.computePickRay(event.x, event.y); + prevEvent = {x: event.x, y:event.y}; + var worldPoint = computeWorldPoint(pickRay); + newLine(worldPoint); + var localPoint = computeLocalPoint(worldPoint); + points.push(localPoint); + normals.push(computeNormal(worldPoint, pickRay.origin)); + strokeWidths.push(0.07); + isDrawing = true; + + } + + function mouseReleaseEvent() { + isDrawing = false; + } + + function keyPressEvent(event) { + if (event.text === "SPACE") { + cycleColor(); + Entities.editEntity(brush, { + color: currentColor + }); + } + if (event.text === "z") { + undoStroke(); + } + if (event.text === "x") { + redoStroke(); + } + } + + + + function cleanup() { + lines.forEach(function(line) { + // Entities.deleteEntity(line); + }); + Entities.deleteEntity(brush); + + } + + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Script.scriptEnding.connect(cleanup); + + Controller.keyPressEvent.connect(keyPressEvent); +} + + +function randFloat(low, high) { + return low + Math.random() * (high - low); +} + + +function randInt(low, high) { + return Math.floor(randFloat(low, high)); +} + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} \ No newline at end of file