mirror of
https://github.com/lubosz/overte.git
synced 2025-04-11 09:35:32 +02:00
496 lines
No EOL
12 KiB
JavaScript
496 lines
No EOL
12 KiB
JavaScript
//
|
|
// 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
|
|
//
|
|
Script.include('lineRider.js')
|
|
var MAX_POINTS_PER_LINE = 30;
|
|
var LINE_LIFETIME = 60 * 5 //5 minute lifetime
|
|
|
|
var colorPalette = [{
|
|
red: 236,
|
|
green: 208,
|
|
blue: 120
|
|
}, {
|
|
red: 217,
|
|
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];
|
|
|
|
|
|
|
|
if (hydraCheck() === true) {
|
|
HydraPaint();
|
|
} else {
|
|
MousePaint();
|
|
}
|
|
|
|
|
|
function cycleColor() {
|
|
currentColor = colorPalette[++currentColorIndex];
|
|
if (currentColorIndex === colorPalette.length - 1) {
|
|
currentColorIndex = -1;
|
|
}
|
|
|
|
}
|
|
|
|
function hydraCheck() {
|
|
var numberOfButtons = Controller.getNumberOfButtons();
|
|
var numberOfTriggers = Controller.getNumberOfTriggers();
|
|
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
|
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
|
hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2);
|
|
return hydrasConnected; //hydrasConnected;
|
|
}
|
|
|
|
//************ Mouse Paint **************************
|
|
|
|
function MousePaint() {
|
|
var DRAWING_DISTANCE = 2;
|
|
var lines = [];
|
|
var deletedLines = [];
|
|
var isDrawing = false;
|
|
var path = [];
|
|
|
|
var lineRider = new LineRider();
|
|
lineRider.addStartHandler(function() {
|
|
var points = [];
|
|
//create points array from list of all points in path
|
|
path.forEach(function(point) {
|
|
points.push(point);
|
|
});
|
|
lineRider.setPath(points);
|
|
});
|
|
|
|
|
|
|
|
var LINE_WIDTH = 7;
|
|
var line;
|
|
var points = [];
|
|
|
|
|
|
var BRUSH_SIZE = 0.02;
|
|
|
|
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(point) {
|
|
line = Entities.addEntity({
|
|
position: MyAvatar.position,
|
|
type: "Line",
|
|
color: currentColor,
|
|
dimensions: {
|
|
x: 10,
|
|
y: 10,
|
|
z: 10
|
|
},
|
|
lineWidth: LINE_WIDTH,
|
|
lifetime: LINE_LIFETIME
|
|
});
|
|
points = [];
|
|
if (point) {
|
|
|
|
points.push(point);
|
|
path.push(point);
|
|
}
|
|
lines.push(line);
|
|
}
|
|
|
|
|
|
function mouseMoveEvent(event) {
|
|
|
|
if (!isDrawing) {
|
|
return;
|
|
}
|
|
|
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
|
var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE);
|
|
var point = Vec3.sum(Camera.getPosition(), addVector);
|
|
points.push(point);
|
|
path.push(point);
|
|
Entities.editEntity(line, {
|
|
linePoints: points
|
|
});
|
|
Entities.editEntity(brush, {
|
|
position: point
|
|
});
|
|
|
|
|
|
if (points.length === MAX_POINTS_PER_LINE) {
|
|
//We need to start a new line!
|
|
newLine(point);
|
|
}
|
|
}
|
|
|
|
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 mousePressEvent(event) {
|
|
if(!event.isLeftButton) {
|
|
isDrawing = false;
|
|
return;
|
|
}
|
|
lineRider.mousePressEvent(event);
|
|
path = [];
|
|
newLine();
|
|
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);
|
|
lineRider.cleanup();
|
|
|
|
}
|
|
|
|
|
|
Controller.mousePressEvent.connect(mousePressEvent);
|
|
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
|
Script.scriptEnding.connect(cleanup);
|
|
|
|
Controller.keyPressEvent.connect(keyPressEvent);
|
|
}
|
|
|
|
|
|
|
|
//*****************HYDRA PAINT *******************************************
|
|
|
|
|
|
|
|
function HydraPaint() {
|
|
|
|
|
|
|
|
var lineRider = new LineRider();
|
|
lineRider.addStartHandler(function() {
|
|
var points = [];
|
|
//create points array from list of all points in path
|
|
rightController.path.forEach(function(point) {
|
|
points.push(point);
|
|
});
|
|
lineRider.setPath(points);
|
|
});
|
|
|
|
var LEFT = 0;
|
|
var RIGHT = 1;
|
|
|
|
var currentTime = 0;
|
|
|
|
|
|
var minBrushSize = .02;
|
|
var maxBrushSize = .04
|
|
|
|
|
|
var minLineWidth = 5;
|
|
var maxLineWidth = 10;
|
|
var currentLineWidth = minLineWidth;
|
|
var MIN_PAINT_TRIGGER_THRESHOLD = .01;
|
|
var COLOR_CHANGE_TIME_FACTOR = 0.1;
|
|
|
|
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 STROKE_SMOOTH_FACTOR = 1;
|
|
|
|
var MIN_DRAW_DISTANCE = 0.2;
|
|
var MAX_DRAW_DISTANCE = 0.4;
|
|
|
|
function controller(side, undoButton, redoButton, cycleColorButton, startRideButton) {
|
|
this.triggerHeld = false;
|
|
this.triggerThreshold = 0.9;
|
|
this.side = side;
|
|
this.palm = 2 * side;
|
|
this.tip = 2 * side + 1;
|
|
this.trigger = side;
|
|
this.lines = [];
|
|
this.deletedLines = [] //just an array of properties objects
|
|
this.isPainting = false;
|
|
|
|
this.undoButton = undoButton;
|
|
this.undoButtonPressed = false;
|
|
this.prevUndoButtonPressed = false;
|
|
|
|
this.redoButton = redoButton;
|
|
this.redoButtonPressed = false;
|
|
this.prevRedoButtonPressed = false;
|
|
|
|
this.cycleColorButton = cycleColorButton;
|
|
this.cycleColorButtonPressed = false;
|
|
this.prevColorCycleButtonPressed = false;
|
|
|
|
this.startRideButton = startRideButton;
|
|
this.startRideButtonPressed = false;
|
|
this.prevStartRideButtonPressed = false;
|
|
|
|
this.strokeCount = 0;
|
|
this.currentBrushSize = minBrushSize;
|
|
this.points = [];
|
|
this.path = [];
|
|
|
|
this.brush = Entities.addEntity({
|
|
type: 'Sphere',
|
|
position: {
|
|
x: 0,
|
|
y: 0,
|
|
z: 0
|
|
},
|
|
color: currentColor,
|
|
dimensions: {
|
|
x: minBrushSize,
|
|
y: minBrushSize,
|
|
z: minBrushSize
|
|
}
|
|
});
|
|
|
|
|
|
this.newLine = function(point) {
|
|
this.line = Entities.addEntity({
|
|
position: MyAvatar.position,
|
|
type: "Line",
|
|
color: currentColor,
|
|
dimensions: {
|
|
x: 10,
|
|
y: 10,
|
|
z: 10
|
|
},
|
|
lineWidth: 5,
|
|
lifetime: LINE_LIFETIME
|
|
});
|
|
this.points = [];
|
|
if (point) {
|
|
this.points.push(point);
|
|
this.path.push(point);
|
|
}
|
|
this.lines.push(this.line);
|
|
}
|
|
|
|
this.update = function(deltaTime) {
|
|
this.updateControllerState();
|
|
this.avatarPalmOffset = Vec3.subtract(this.palmPosition, MyAvatar.position);
|
|
this.projectedForwardDistance = Vec3.dot(Quat.getFront(Camera.getOrientation()), this.avatarPalmOffset);
|
|
this.mappedPalmOffset = map(this.projectedForwardDistance, -.5, .5, MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE);
|
|
this.tipDirection = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition));
|
|
this.offsetVector = Vec3.multiply(this.mappedPalmOffset, this.tipDirection);
|
|
this.drawPoint = Vec3.sum(this.palmPosition, this.offsetVector);
|
|
this.currentBrushSize = map(this.triggerValue, 0, 1, minBrushSize, maxBrushSize);
|
|
Entities.editEntity(this.brush, {
|
|
position: this.drawPoint,
|
|
dimensions: {
|
|
x: this.currentBrushSize,
|
|
y: this.currentBrushSize,
|
|
z: this.currentBrushSize
|
|
},
|
|
color: currentColor
|
|
});
|
|
if (this.triggerValue > MIN_PAINT_TRIGGER_THRESHOLD) {
|
|
if (!this.isPainting) {
|
|
this.isPainting = true;
|
|
this.newLine();
|
|
this.path = [];
|
|
}
|
|
if (this.strokeCount % STROKE_SMOOTH_FACTOR === 0) {
|
|
this.paint(this.drawPoint);
|
|
}
|
|
this.strokeCount++;
|
|
} else if (this.triggerValue < MIN_PAINT_TRIGGER_THRESHOLD && this.isPainting) {
|
|
this.releaseTrigger();
|
|
}
|
|
|
|
this.oldPalmPosition = this.palmPosition;
|
|
this.oldTipPosition = this.tipPosition;
|
|
}
|
|
|
|
this.releaseTrigger = function() {
|
|
this.isPainting = false;
|
|
|
|
}
|
|
|
|
|
|
this.updateControllerState = function() {
|
|
this.undoButtonPressed = Controller.isButtonPressed(this.undoButton);
|
|
this.redoButtonPressed = Controller.isButtonPressed(this.redoButton);
|
|
this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton);
|
|
this.startRideButtonPressed = Controller.isButtonPressed(this.startRideButton);
|
|
|
|
//This logic gives us button release
|
|
if (this.prevUndoButtonPressed === true && this.undoButtonPressed === false) {
|
|
//User released undo button, so undo
|
|
this.undoStroke();
|
|
}
|
|
if (this.prevRedoButtonPressed === true && this.redoButtonPressed === false) {
|
|
this.redoStroke();
|
|
}
|
|
|
|
if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) {
|
|
cycleColor();
|
|
Entities.editEntity(this.brush, {
|
|
color: currentColor
|
|
});
|
|
}
|
|
if (this.prevStartRideButtonPressed === true && this.startRideButtonPressed === false) {
|
|
lineRider.toggleRide();
|
|
}
|
|
this.prevRedoButtonPressed = this.redoButtonPressed;
|
|
this.prevUndoButtonPressed = this.undoButtonPressed;
|
|
this.prevCycleColorButtonPressed = this.cycleColorButtonPressed;
|
|
this.prevStartRideButtonPressed = this.startRideButtonPressed;
|
|
|
|
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
|
|
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
|
|
this.triggerValue = Controller.getTriggerValue(this.trigger);
|
|
}
|
|
|
|
this.undoStroke = function() {
|
|
var deletedLine = this.lines.pop();
|
|
var deletedLineProps = Entities.getEntityProperties(deletedLine);
|
|
this.deletedLines.push(deletedLineProps);
|
|
Entities.deleteEntity(deletedLine);
|
|
}
|
|
|
|
this.redoStroke = function() {
|
|
var restoredLine = Entities.addEntity(this.deletedLines.pop());
|
|
Entities.addEntity(restoredLine);
|
|
this.lines.push(restoredLine);
|
|
}
|
|
|
|
this.paint = function(point) {
|
|
|
|
currentLineWidth = map(this.triggerValue, 0, 1, minLineWidth, maxLineWidth);
|
|
this.points.push(point);
|
|
this.path.push(point);
|
|
Entities.editEntity(this.line, {
|
|
linePoints: this.points,
|
|
lineWidth: currentLineWidth,
|
|
});
|
|
if (this.points.length > MAX_POINTS_PER_LINE) {
|
|
this.newLine(point);
|
|
}
|
|
}
|
|
|
|
this.cleanup = function() {
|
|
Entities.deleteEntity(this.brush);
|
|
this.lines.forEach(function(line) {
|
|
Entities.deleteEntity(line);
|
|
});
|
|
}
|
|
}
|
|
|
|
function update(deltaTime) {
|
|
rightController.update(deltaTime);
|
|
leftController.update(deltaTime);
|
|
currentTime += deltaTime;
|
|
}
|
|
|
|
function cleanup() {
|
|
rightController.cleanup();
|
|
leftController.cleanup();
|
|
lineRider.cleanup();
|
|
}
|
|
|
|
function mousePressEvent(event) {
|
|
lineRider.mousePressEvent(event);
|
|
}
|
|
|
|
function vectorIsZero(v) {
|
|
return v.x === 0 && v.y === 0 && v.z === 0;
|
|
}
|
|
|
|
|
|
var rightController = new controller(RIGHT, RIGHT_BUTTON_3, RIGHT_BUTTON_4, RIGHT_BUTTON_1, RIGHT_BUTTON_2);
|
|
var leftController = new controller(LEFT, LEFT_BUTTON_3, LEFT_BUTTON_4, LEFT_BUTTON_1, LEFT_BUTTON_2);
|
|
|
|
Script.update.connect(update);
|
|
Script.scriptEnding.connect(cleanup);
|
|
Controller.mousePressEvent.connect(mousePressEvent);
|
|
|
|
}
|
|
|
|
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));
|
|
} |