mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 09:48:44 +02:00
Merge pull request #3175 from Barnold1953/OculusSDK
Two new example scripts
This commit is contained in:
commit
3dfb5030c5
4 changed files with 1017 additions and 0 deletions
637
examples/fallingSand.js
Normal file
637
examples/fallingSand.js
Normal file
|
@ -0,0 +1,637 @@
|
||||||
|
//
|
||||||
|
// fallingSand.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Ben Arnold on 7/14/14.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This sample script allows the user to place sand voxels that will undergo
|
||||||
|
// cellular automata physics.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z fighting
|
||||||
|
var previewLineWidth = 2.0;
|
||||||
|
|
||||||
|
var voxelSize = 1;
|
||||||
|
var windowDimensions = Controller.getViewportDimensions();
|
||||||
|
var toolIconUrl = "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/tools/";
|
||||||
|
|
||||||
|
var MAX_VOXEL_SCALE_POWER = 5;
|
||||||
|
var MIN_VOXEL_SCALE_POWER = -8;
|
||||||
|
var MAX_VOXEL_SCALE = Math.pow(2.0, MAX_VOXEL_SCALE_POWER);
|
||||||
|
var MIN_VOXEL_SCALE = Math.pow(2.0, MIN_VOXEL_SCALE_POWER);
|
||||||
|
|
||||||
|
|
||||||
|
var linePreviewTop = Overlays.addOverlay("line3d", {
|
||||||
|
position: { x: 0, y: 0, z: 0},
|
||||||
|
end: { x: 0, y: 0, z: 0},
|
||||||
|
color: { red: 0, green: 0, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: previewLineWidth
|
||||||
|
});
|
||||||
|
|
||||||
|
var linePreviewBottom = Overlays.addOverlay("line3d", {
|
||||||
|
position: { x: 0, y: 0, z: 0},
|
||||||
|
end: { x: 0, y: 0, z: 0},
|
||||||
|
color: { red: 0, green: 0, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: previewLineWidth
|
||||||
|
});
|
||||||
|
|
||||||
|
var linePreviewLeft = Overlays.addOverlay("line3d", {
|
||||||
|
position: { x: 0, y: 0, z: 0},
|
||||||
|
end: { x: 0, y: 0, z: 0},
|
||||||
|
color: { red: 0, green: 0, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: previewLineWidth
|
||||||
|
});
|
||||||
|
|
||||||
|
var linePreviewRight = Overlays.addOverlay("line3d", {
|
||||||
|
position: { x: 0, y: 0, z: 0},
|
||||||
|
end: { x: 0, y: 0, z: 0},
|
||||||
|
color: { red: 0, green: 0, blue: 255},
|
||||||
|
alpha: 1,
|
||||||
|
visible: false,
|
||||||
|
lineWidth: previewLineWidth
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var UIColor = { red: 119, green: 103, blue: 53};
|
||||||
|
var activeUIColor = { red: 234, green: 206, blue: 106};
|
||||||
|
|
||||||
|
var toolHeight = 50;
|
||||||
|
var toolWidth = 50;
|
||||||
|
|
||||||
|
var editToolsOn = true;
|
||||||
|
|
||||||
|
var voxelToolSelected = false;
|
||||||
|
|
||||||
|
var scaleSelectorWidth = 144;
|
||||||
|
var scaleSelectorHeight = 37;
|
||||||
|
|
||||||
|
var scaleSelectorX = windowDimensions.x / 5.0;
|
||||||
|
var scaleSelectorY = windowDimensions.y - scaleSelectorHeight;
|
||||||
|
|
||||||
|
var voxelTool = Overlays.addOverlay("image", {
|
||||||
|
x: scaleSelectorX + scaleSelectorWidth + 1, y: windowDimensions.y - toolHeight, width: toolWidth, height: toolHeight,
|
||||||
|
subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight },
|
||||||
|
imageURL: toolIconUrl + "voxel-tool.svg",
|
||||||
|
visible: editToolsOn,
|
||||||
|
color: UIColor,
|
||||||
|
alpha: 0.9
|
||||||
|
});
|
||||||
|
|
||||||
|
var copyScale = true;
|
||||||
|
function ScaleSelector() {
|
||||||
|
this.x = scaleSelectorX;
|
||||||
|
this.y = scaleSelectorY;
|
||||||
|
this.width = scaleSelectorWidth;
|
||||||
|
this.height = scaleSelectorHeight;
|
||||||
|
|
||||||
|
this.displayPower = false;
|
||||||
|
this.scale = 1.0;
|
||||||
|
this.power = 0;
|
||||||
|
|
||||||
|
this.FIRST_PART = this.width * 40.0 / 100.0;
|
||||||
|
this.SECOND_PART = this.width * 37.0 / 100.0;
|
||||||
|
|
||||||
|
this.buttonsOverlay = Overlays.addOverlay("image", {
|
||||||
|
x: this.x, y: this.y,
|
||||||
|
width: this.width, height: this.height,
|
||||||
|
//subImage: { x: 0, y: toolHeight, width: toolWidth, height: toolHeight },
|
||||||
|
imageURL: toolIconUrl + "voxel-size-selector.svg",
|
||||||
|
alpha: 0.9,
|
||||||
|
visible: editToolsOn,
|
||||||
|
color: activeUIColor
|
||||||
|
});
|
||||||
|
this.textOverlay = Overlays.addOverlay("text", {
|
||||||
|
x: this.x + this.FIRST_PART, y: this.y,
|
||||||
|
width: this.SECOND_PART, height: this.height,
|
||||||
|
topMargin: 13,
|
||||||
|
text: this.scale.toString(),
|
||||||
|
alpha: 0.0,
|
||||||
|
visible: editToolsOn,
|
||||||
|
color: activeUIColor
|
||||||
|
});
|
||||||
|
this.powerOverlay = Overlays.addOverlay("text", {
|
||||||
|
x: this.x + this.FIRST_PART, y: this.y,
|
||||||
|
width: this.SECOND_PART, height: this.height,
|
||||||
|
leftMargin: 28,
|
||||||
|
text: this.power.toString(),
|
||||||
|
alpha: 0.0,
|
||||||
|
visible: false,
|
||||||
|
color: activeUIColor
|
||||||
|
});
|
||||||
|
this.setScale = function(scale) {
|
||||||
|
if (scale > MAX_VOXEL_SCALE) {
|
||||||
|
scale = MAX_VOXEL_SCALE;
|
||||||
|
}
|
||||||
|
if (scale < MIN_VOXEL_SCALE) {
|
||||||
|
scale = MIN_VOXEL_SCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scale = scale;
|
||||||
|
this.power = Math.floor(Math.log(scale) / Math.log(2));
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.show = function(doShow) {
|
||||||
|
Overlays.editOverlay(this.buttonsOverlay, {visible: doShow});
|
||||||
|
Overlays.editOverlay(this.textOverlay, {visible: doShow});
|
||||||
|
Overlays.editOverlay(this.powerOverlay, {visible: doShow && this.displayPower});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.move = function() {
|
||||||
|
this.x = swatchesX + swatchesWidth;
|
||||||
|
this.y = swatchesY;
|
||||||
|
|
||||||
|
Overlays.editOverlay(this.buttonsOverlay, {
|
||||||
|
x: this.x, y: this.y,
|
||||||
|
});
|
||||||
|
Overlays.editOverlay(this.textOverlay, {
|
||||||
|
x: this.x + this.FIRST_PART, y: this.y,
|
||||||
|
});
|
||||||
|
Overlays.editOverlay(this.powerOverlay, {
|
||||||
|
x: this.x + this.FIRST_PART, y: this.y,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.switchDisplay = function() {
|
||||||
|
this.displayPower = !this.displayPower;
|
||||||
|
|
||||||
|
if (this.displayPower) {
|
||||||
|
Overlays.editOverlay(this.textOverlay, {
|
||||||
|
leftMargin: 18,
|
||||||
|
text: "2"
|
||||||
|
});
|
||||||
|
Overlays.editOverlay(this.powerOverlay, {
|
||||||
|
text: this.power.toString(),
|
||||||
|
visible: editToolsOn
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Overlays.editOverlay(this.textOverlay, {
|
||||||
|
leftMargin: 13,
|
||||||
|
text: this.scale.toString()
|
||||||
|
});
|
||||||
|
Overlays.editOverlay(this.powerOverlay, {
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update = function() {
|
||||||
|
if (this.displayPower) {
|
||||||
|
Overlays.editOverlay(this.powerOverlay, {text: this.power.toString()});
|
||||||
|
} else {
|
||||||
|
Overlays.editOverlay(this.textOverlay, {text: this.scale.toString()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.incrementScale = function() {
|
||||||
|
copyScale = false;
|
||||||
|
if (this.power < MAX_VOXEL_SCALE_POWER) {
|
||||||
|
++this.power;
|
||||||
|
this.scale *= 2.0;
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.decrementScale = function() {
|
||||||
|
copyScale = false;
|
||||||
|
if (MIN_VOXEL_SCALE_POWER < this.power) {
|
||||||
|
--this.power;
|
||||||
|
this.scale /= 2.0;
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.clicked = function(x, y) {
|
||||||
|
if (this.x < x && x < this.x + this.width &&
|
||||||
|
this.y < y && y < this.y + this.height) {
|
||||||
|
|
||||||
|
if (x < this.x + this.FIRST_PART) {
|
||||||
|
this.decrementScale();
|
||||||
|
} else if (x < this.x + this.FIRST_PART + this.SECOND_PART) {
|
||||||
|
this.switchDisplay();
|
||||||
|
} else {
|
||||||
|
this.incrementScale();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cleanup = function() {
|
||||||
|
Overlays.deleteOverlay(this.buttonsOverlay);
|
||||||
|
Overlays.deleteOverlay(this.textOverlay);
|
||||||
|
Overlays.deleteOverlay(this.powerOverlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
var scaleSelector = new ScaleSelector();
|
||||||
|
|
||||||
|
function calculateVoxelFromIntersection(intersection, operation) {
|
||||||
|
|
||||||
|
var resultVoxel;
|
||||||
|
|
||||||
|
var x;
|
||||||
|
var y;
|
||||||
|
var z;
|
||||||
|
|
||||||
|
// if our "target voxel size" is larger than the voxel we intersected with, then we need to find the closest
|
||||||
|
// ancestor voxel of our target size that contains our intersected voxel.
|
||||||
|
if (voxelSize > intersection.voxel.s) {
|
||||||
|
x = Math.floor(intersection.voxel.x / voxelSize) * voxelSize;
|
||||||
|
y = Math.floor(intersection.voxel.y / voxelSize) * voxelSize;
|
||||||
|
z = Math.floor(intersection.voxel.z / voxelSize) * voxelSize;
|
||||||
|
} else {
|
||||||
|
// otherwise, calculate the enclosed voxel of size voxelSize that the intersection point falls inside of.
|
||||||
|
// if you have a voxelSize that's smaller than the voxel you're intersecting, this calculation will result
|
||||||
|
// in the subvoxel that the intersection point falls in, if the target voxelSize matches the intersecting
|
||||||
|
// voxel this still works and results in returning the intersecting voxel which is what we want
|
||||||
|
var adjustToCenter = Vec3.multiply(Voxels.getFaceVector(intersection.face), (voxelSize * -0.5));
|
||||||
|
|
||||||
|
var centerOfIntersectingVoxel = Vec3.sum(intersection.intersection, adjustToCenter);
|
||||||
|
x = Math.floor(centerOfIntersectingVoxel.x / voxelSize) * voxelSize;
|
||||||
|
y = Math.floor(centerOfIntersectingVoxel.y / voxelSize) * voxelSize;
|
||||||
|
z = Math.floor(centerOfIntersectingVoxel.z / voxelSize) * voxelSize;
|
||||||
|
}
|
||||||
|
resultVoxel = { x: x, y: y, z: z, s: voxelSize };
|
||||||
|
var highlightAt = { x: x, y: y, z: z, s: voxelSize };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// we only do the "add to the face we're pointing at" adjustment, if the operation is an add
|
||||||
|
// operation, and the target voxel size is equal to or smaller than the intersecting voxel.
|
||||||
|
var wantAddAdjust = (operation == "add" && (voxelSize <= intersection.voxel.s));
|
||||||
|
|
||||||
|
// now we also want to calculate the "edge square" for the face for this voxel
|
||||||
|
if (intersection.face == "MIN_X_FACE") {
|
||||||
|
|
||||||
|
highlightAt.x = x - zFightingSizeAdjust;
|
||||||
|
if (wantAddAdjust) {
|
||||||
|
resultVoxel.x -= voxelSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust };
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust };
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
|
||||||
|
|
||||||
|
} else if (intersection.face == "MAX_X_FACE") {
|
||||||
|
|
||||||
|
highlightAt.x = x + voxelSize + zFightingSizeAdjust;
|
||||||
|
if (wantAddAdjust) {
|
||||||
|
resultVoxel.x += resultVoxel.s;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust };
|
||||||
|
resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + zFightingSizeAdjust };
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
|
||||||
|
|
||||||
|
} else if (intersection.face == "MIN_Y_FACE") {
|
||||||
|
|
||||||
|
highlightAt.y = y - zFightingSizeAdjust;
|
||||||
|
if (wantAddAdjust) {
|
||||||
|
resultVoxel.y -= voxelSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust };
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust };
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
|
||||||
|
resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust , y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust };
|
||||||
|
|
||||||
|
} else if (intersection.face == "MAX_Y_FACE") {
|
||||||
|
|
||||||
|
highlightAt.y = y + voxelSize + zFightingSizeAdjust;
|
||||||
|
if (wantAddAdjust) {
|
||||||
|
resultVoxel.y += voxelSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust };
|
||||||
|
resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + zFightingSizeAdjust};
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust};
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y, z: highlightAt.z + voxelSize - zFightingSizeAdjust};
|
||||||
|
|
||||||
|
} else if (intersection.face == "MIN_Z_FACE") {
|
||||||
|
|
||||||
|
highlightAt.z = z - zFightingSizeAdjust;
|
||||||
|
if (wantAddAdjust) {
|
||||||
|
resultVoxel.z -= voxelSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z };
|
||||||
|
resultVoxel.bottomLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z};
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z };
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z};
|
||||||
|
|
||||||
|
} else if (intersection.face == "MAX_Z_FACE") {
|
||||||
|
|
||||||
|
highlightAt.z = z + voxelSize + zFightingSizeAdjust;
|
||||||
|
if (wantAddAdjust) {
|
||||||
|
resultVoxel.z += voxelSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultVoxel.bottomLeft = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z };
|
||||||
|
resultVoxel.bottomRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + zFightingSizeAdjust, z: highlightAt.z};
|
||||||
|
resultVoxel.topLeft = {x: highlightAt.x + zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z };
|
||||||
|
resultVoxel.topRight = {x: highlightAt.x + voxelSize - zFightingSizeAdjust, y: highlightAt.y + voxelSize - zFightingSizeAdjust, z: highlightAt.z};
|
||||||
|
|
||||||
|
}
|
||||||
|
return resultVoxel;
|
||||||
|
}
|
||||||
|
|
||||||
|
var trackLastMouseX = 0;
|
||||||
|
var trackLastMouseY = 0;
|
||||||
|
|
||||||
|
function showPreviewLines() {
|
||||||
|
|
||||||
|
var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY);
|
||||||
|
|
||||||
|
var intersection = Voxels.findRayIntersection(pickRay);
|
||||||
|
|
||||||
|
if (intersection.intersects) {
|
||||||
|
var resultVoxel = calculateVoxelFromIntersection(intersection, "");
|
||||||
|
Overlays.editOverlay(linePreviewTop, { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true });
|
||||||
|
Overlays.editOverlay(linePreviewBottom, { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true });
|
||||||
|
Overlays.editOverlay(linePreviewLeft, { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true });
|
||||||
|
Overlays.editOverlay(linePreviewRight, { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true });
|
||||||
|
} else {
|
||||||
|
Overlays.editOverlay(linePreviewTop, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewBottom, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewLeft, { visible: false });
|
||||||
|
Overlays.editOverlay(linePreviewRight, { visible: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseMoveEvent(event) {
|
||||||
|
trackLastMouseX = event.x;
|
||||||
|
trackLastMouseY = event.y;
|
||||||
|
if (!voxelToolSelected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showPreviewLines();
|
||||||
|
}
|
||||||
|
|
||||||
|
var BRUSH_RADIUS = 2;
|
||||||
|
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
var mouseX = event.x;
|
||||||
|
var mouseY = event.y;
|
||||||
|
|
||||||
|
var clickedOnSomething = false;
|
||||||
|
// Check if we clicked an overlay
|
||||||
|
var clickedOverlay = Overlays.getOverlayAtPoint({x: mouseX, y: mouseY});
|
||||||
|
|
||||||
|
if (clickedOverlay == voxelTool) {
|
||||||
|
voxelToolSelected = !voxelToolSelected;
|
||||||
|
|
||||||
|
if (voxelToolSelected == true) {
|
||||||
|
Overlays.editOverlay(voxelTool, {
|
||||||
|
color: activeUIColor
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Overlays.editOverlay(voxelTool, {
|
||||||
|
color: UIColor
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedOnSomething = true;
|
||||||
|
} else if (scaleSelector.clicked(event.x, event.y)) {
|
||||||
|
clickedOnSomething = true;
|
||||||
|
voxelSize = scaleSelector.scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if we clicked on the UI or the voxel tool is disabled
|
||||||
|
if (clickedOnSomething || !voxelToolSelected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the picking ray for the click
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
var intersection = Voxels.findRayIntersection(pickRay);
|
||||||
|
var resultVoxel = calculateVoxelFromIntersection(intersection, "add");
|
||||||
|
|
||||||
|
|
||||||
|
//Add a clump of sand voxels
|
||||||
|
makeSphere(resultVoxel.x, resultVoxel.y, resultVoxel.z, voxelSize * BRUSH_RADIUS, voxelSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sandArray = [];
|
||||||
|
var numSand = 0;
|
||||||
|
|
||||||
|
|
||||||
|
//These arrays are used to buffer add/remove operations so they can be batched together
|
||||||
|
var addArray = [];
|
||||||
|
var addArraySize = 0;
|
||||||
|
var removeArray = [];
|
||||||
|
var removeArraySize = 0;
|
||||||
|
|
||||||
|
//The colors must be different
|
||||||
|
var activeSandColor = { r: 234, g: 206, b: 106};
|
||||||
|
var inactiveSandColor = { r: 233, g: 206, b: 106};
|
||||||
|
|
||||||
|
//This is used as an optimization, so that we
|
||||||
|
//will check our 6 neighbors at most once.
|
||||||
|
var adjacentVoxels = [];
|
||||||
|
var numAdjacentVoxels = 0;
|
||||||
|
//Stores a list of voxels we need to activate
|
||||||
|
var activateMap = {};
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
|
||||||
|
//Clear the activate map each frame
|
||||||
|
activateMap = {};
|
||||||
|
|
||||||
|
//Update all sand in our sandArray
|
||||||
|
var i = 0;
|
||||||
|
while (i < numSand) {
|
||||||
|
//Update the sand voxel and if it doesn't move, deactivate it
|
||||||
|
if (updateSand(i) == false) {
|
||||||
|
deactivateSand(i);
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < removeArraySize; i++) {
|
||||||
|
var voxel = removeArray[i];
|
||||||
|
Voxels.eraseVoxel(voxel.x, voxel.y, voxel.z, voxel.s);
|
||||||
|
}
|
||||||
|
removeArraySize = 0;
|
||||||
|
|
||||||
|
//Add all voxels that have moved
|
||||||
|
for (var i = 0; i < addArraySize; i++) {
|
||||||
|
var voxel = addArray[i];
|
||||||
|
Voxels.setVoxel(voxel.x, voxel.y, voxel.z, voxel.s, voxel.r, voxel.g, voxel.b);
|
||||||
|
}
|
||||||
|
addArraySize = 0;
|
||||||
|
|
||||||
|
for (var key in activateMap) {
|
||||||
|
var voxel = activateMap[key];
|
||||||
|
Voxels.setVoxel(voxel.x, voxel.y, voxel.z, voxel.s, activeSandColor.r, activeSandColor.g, activeSandColor.b);
|
||||||
|
sandArray[numSand++] = { x: voxel.x, y: voxel.y, z: voxel.z, s: voxel.s, r: activeSandColor.r, g: activeSandColor.g, b: activeSandColor.b };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Adds a sphere of sand at the center cx,cy,cz
|
||||||
|
function makeSphere(cx, cy, cz, r, voxelSize) {
|
||||||
|
|
||||||
|
var r2 = r * r;
|
||||||
|
var distance2;
|
||||||
|
var dx;
|
||||||
|
var dy;
|
||||||
|
var dz;
|
||||||
|
|
||||||
|
for (var x = cx - r; x <= cx + r; x += voxelSize) {
|
||||||
|
for (var y = cy - r; y <= cy + r; y += voxelSize) {
|
||||||
|
for (var z = cz - r; z <= cz + r; z += voxelSize) {
|
||||||
|
dx = Math.abs(x - cx);
|
||||||
|
dy = Math.abs(y - cy);
|
||||||
|
dz = Math.abs(z - cz);
|
||||||
|
distance2 = dx * dx + dy * dy + dz * dz;
|
||||||
|
if (distance2 <= r2 && isVoxelEmpty(x, y, z, voxelSize)) {
|
||||||
|
Voxels.setVoxel(x, y, z, voxelSize, activeSandColor.r, activeSandColor.g, activeSandColor.b);
|
||||||
|
sandArray[numSand++] = { x: x, y: y, z: z, s: voxelSize, r: activeSandColor.r, g: activeSandColor.g, b: activeSandColor.b };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if a given voxel is empty
|
||||||
|
function isVoxelEmpty(x, y, z, s, isAdjacent) {
|
||||||
|
var halfSize = s / 2;
|
||||||
|
var point = {x: x + halfSize, y: y + halfSize, z: z + halfSize };
|
||||||
|
|
||||||
|
var adjacent = Voxels.getVoxelEnclosingPointBlocking(point);
|
||||||
|
//If color is all 0, we assume its air.
|
||||||
|
|
||||||
|
if (adjacent.red == 0 && adjacent.green == 0 && adjacent.blue == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAdjacent) {
|
||||||
|
adjacentVoxels[numAdjacentVoxels++] = adjacent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Moves voxel to x,y,z if the space is empty
|
||||||
|
function tryMoveVoxel(voxel, x, y, z) {
|
||||||
|
//If the adjacent voxel is empty, we will move to it.
|
||||||
|
if (isVoxelEmpty(x, y, z, voxel.s, false)) {
|
||||||
|
var hsize = voxel.s / 2;
|
||||||
|
for (var i = 0; i < 5; i++) {
|
||||||
|
var point = {x: voxel.x + directionVecs[i].x * voxel.s + hsize, y: voxel.y + directionVecs[i].y * voxel.s + hsize, z: voxel.z + directionVecs[i].z * voxel.s + hsize };
|
||||||
|
adjacentVoxels[numAdjacentVoxels++] = Voxels.getVoxelEnclosingPointBlocking(point);
|
||||||
|
}
|
||||||
|
moveVoxel(voxel, x, y, z);
|
||||||
|
|
||||||
|
//Get all adjacent voxels for activation
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Moves voxel to x,y,z
|
||||||
|
function moveVoxel(voxel, x, y, z) {
|
||||||
|
activateNeighbors();
|
||||||
|
removeArray[removeArraySize++] = {x: voxel.x, y: voxel.y, z: voxel.z, s: voxel.s};
|
||||||
|
addArray[addArraySize++] = {x: x, y: y, z: z, s: voxel.s, r: activeSandColor.r, g: activeSandColor.g, b: activeSandColor.b};
|
||||||
|
voxel.x = x;
|
||||||
|
voxel.y = y;
|
||||||
|
voxel.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
var LEFT = 0;
|
||||||
|
var BACK = 1;
|
||||||
|
var RIGHT = 2;
|
||||||
|
var FRONT = 3;
|
||||||
|
var TOP = 4;
|
||||||
|
|
||||||
|
//These indicate the different directions to neighbor voxels, so we can iterate them
|
||||||
|
var directionVecs = [];
|
||||||
|
directionVecs[LEFT] = {x: -1, y: 0, z: 0}; //Left
|
||||||
|
directionVecs[BACK] = {x: 0, y: 0, z: -1}; //Back
|
||||||
|
directionVecs[RIGHT] = {x: 1, y: 0, z: 0}; //Right
|
||||||
|
directionVecs[FRONT] = {x: 0, y: 0, z: 1}; //Front
|
||||||
|
directionVecs[TOP] = {x: 0, y: 1, z: 0}; //Top
|
||||||
|
|
||||||
|
function updateSand(i) {
|
||||||
|
var voxel = sandArray[i];
|
||||||
|
var size = voxel.s;
|
||||||
|
var hsize = size / 2;
|
||||||
|
numAdjacentVoxels = 0;
|
||||||
|
|
||||||
|
//Down
|
||||||
|
if (tryMoveVoxel(voxel, voxel.x, voxel.y - size, voxel.z)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Left, back, right, front
|
||||||
|
for (var i = 0; i < 4; i++) {
|
||||||
|
if (isVoxelEmpty(voxel.x + directionVecs[i].x * size, voxel.y + directionVecs[i].y * size, voxel.z + directionVecs[i].z * size, size, true)
|
||||||
|
&& isVoxelEmpty(voxel.x + directionVecs[i].x * size, (voxel.y - size) + directionVecs[i].y * size, voxel.z + directionVecs[i].z * size, size, false)) {
|
||||||
|
//get the rest of the adjacent voxels
|
||||||
|
for (var j = i + 1; j < 5; j++) {
|
||||||
|
var point = {x: voxel.x + directionVecs[j].x * size + hsize, y: voxel.y + directionVecs[j].y * size + hsize, z: voxel.z + directionVecs[j].z * size + hsize };
|
||||||
|
adjacentVoxels[numAdjacentVoxels++] = Voxels.getVoxelEnclosingPointBlocking(point);
|
||||||
|
}
|
||||||
|
moveVoxel(voxel, voxel.x + directionVecs[i].x * size, voxel.y + directionVecs[i].y * size, voxel.z + directionVecs[i].z * size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function activateNeighbors() {
|
||||||
|
for (var i = 0; i < numAdjacentVoxels; i++) {
|
||||||
|
var voxel = adjacentVoxels[i];
|
||||||
|
//Check if this neighbor is inactive, if so, activate it
|
||||||
|
if (voxel.red == inactiveSandColor.r && voxel.green == inactiveSandColor.g && voxel.blue == inactiveSandColor.b) {
|
||||||
|
activateMap[voxel.x.toString() + "," + voxel.y.toString() + ',' + voxel.z.toString()] = voxel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Deactivates a sand voxel to save processing power
|
||||||
|
function deactivateSand(i) {
|
||||||
|
var voxel = sandArray[i];
|
||||||
|
addArray[addArraySize++] = {x: voxel.x, y: voxel.y, z: voxel.z, s: voxel.s, r: inactiveSandColor.r, g: inactiveSandColor.g, b: inactiveSandColor.b};
|
||||||
|
sandArray[i] = sandArray[numSand-1];
|
||||||
|
numSand--;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cleanup
|
||||||
|
function scriptEnding() {
|
||||||
|
for (var i = 0; i < numSand; i++) {
|
||||||
|
var voxel = sandArray[i];
|
||||||
|
Voxels.eraseVoxel(voxel.x, voxel.y, voxel.z, voxel.s);
|
||||||
|
}
|
||||||
|
Overlays.deleteOverlay(linePreviewTop);
|
||||||
|
Overlays.deleteOverlay(linePreviewBottom);
|
||||||
|
Overlays.deleteOverlay(linePreviewLeft);
|
||||||
|
Overlays.deleteOverlay(linePreviewRight);
|
||||||
|
scaleSelector.cleanup();
|
||||||
|
Overlays.deleteOverlay(voxelTool);
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||||
|
|
||||||
|
Script.update.connect(update);
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
|
||||||
|
Voxels.setMaxPacketSize(1); //this is needed or a bug occurs :(
|
||||||
|
Voxels.setPacketsPerSecond(10000);
|
358
examples/grenadeLauncher.js
Normal file
358
examples/grenadeLauncher.js
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
//
|
||||||
|
// grenadeLauncher.js
|
||||||
|
// examples
|
||||||
|
// Created by Ben Arnold on 7/11/14.
|
||||||
|
// This is a modified version of gun.js by Brad Hefta-Gaub.
|
||||||
|
//
|
||||||
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This is an example script that turns the hydra controllers and mouse into a particle gun.
|
||||||
|
// It reads the controller, watches for trigger pulls, and launches particles.
|
||||||
|
// When particles collide with voxels they blow big holes out of the voxels.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
function getRandomFloat(min, max) {
|
||||||
|
return Math.random() * (max - min) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastX = 0;
|
||||||
|
var lastY = 0;
|
||||||
|
var yawFromMouse = 0;
|
||||||
|
var pitchFromMouse = 0;
|
||||||
|
var isMouseDown = false;
|
||||||
|
|
||||||
|
var BULLET_VELOCITY = 3.0;
|
||||||
|
var MIN_THROWER_DELAY = 1000;
|
||||||
|
var MAX_THROWER_DELAY = 1000;
|
||||||
|
var LEFT_BUTTON_1 = 1;
|
||||||
|
var LEFT_BUTTON_3 = 3;
|
||||||
|
var RELOAD_INTERVAL = 5;
|
||||||
|
|
||||||
|
var showScore = false;
|
||||||
|
|
||||||
|
// Load some sound to use for loading and firing
|
||||||
|
var fireSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/GUN-SHOT2.raw");
|
||||||
|
var loadSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/Gun_Reload_Weapon22.raw");
|
||||||
|
var impactSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guns/BulletImpact2.raw");
|
||||||
|
var targetHitSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/hit.raw");
|
||||||
|
var targetLaunchSound = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Space%20Invaders/shoot.raw");
|
||||||
|
|
||||||
|
var gunModel = "http://public.highfidelity.io/models/attachments/HaloGun.fst";
|
||||||
|
|
||||||
|
var audioOptions = new AudioInjectionOptions();
|
||||||
|
audioOptions.volume = 0.9;
|
||||||
|
|
||||||
|
var shotsFired = 0;
|
||||||
|
|
||||||
|
var shotTime = new Date();
|
||||||
|
|
||||||
|
// initialize our triggers
|
||||||
|
var triggerPulled = new Array();
|
||||||
|
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||||
|
for (t = 0; t < numberOfTriggers; t++) {
|
||||||
|
triggerPulled[t] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isLaunchButtonPressed = false;
|
||||||
|
|
||||||
|
var score = 0;
|
||||||
|
|
||||||
|
// Create a reticle image in center of screen
|
||||||
|
var screenSize = Controller.getViewportDimensions();
|
||||||
|
var reticle = Overlays.addOverlay("image", {
|
||||||
|
x: screenSize.x / 2 - 16,
|
||||||
|
y: screenSize.y / 2 - 16,
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/reticle.png",
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
alpha: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
if (showScore) {
|
||||||
|
var text = Overlays.addOverlay("text", {
|
||||||
|
x: screenSize.x / 2 - 100,
|
||||||
|
y: screenSize.y / 2 - 50,
|
||||||
|
width: 150,
|
||||||
|
height: 50,
|
||||||
|
color: { red: 0, green: 0, blue: 0},
|
||||||
|
textColor: { red: 255, green: 0, blue: 0},
|
||||||
|
topMargin: 4,
|
||||||
|
leftMargin: 4,
|
||||||
|
text: "Score: " + score
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function printVector(string, vector) {
|
||||||
|
print(string + " " + vector.x + ", " + vector.y + ", " + vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shootBullet(position, velocity) {
|
||||||
|
var BULLET_SIZE = 0.1;
|
||||||
|
var BULLET_GRAVITY = -3.0;
|
||||||
|
//Creates a grenade with a reasonable lifetime so that one is less likely to accidentally blow up
|
||||||
|
//far away voxels
|
||||||
|
Particles.addParticle(
|
||||||
|
{ position: position,
|
||||||
|
radius: BULLET_SIZE,
|
||||||
|
color: { red: 10, green: 10, blue: 10 },
|
||||||
|
velocity: velocity,
|
||||||
|
gravity: { x: 0, y: BULLET_GRAVITY, z: 0 },
|
||||||
|
lifetime: 10.0,
|
||||||
|
damping: 0 });
|
||||||
|
|
||||||
|
// Play firing sounds
|
||||||
|
audioOptions.position = position;
|
||||||
|
Audio.playSound(fireSound, audioOptions);
|
||||||
|
shotsFired++;
|
||||||
|
if ((shotsFired % RELOAD_INTERVAL) == 0) {
|
||||||
|
Audio.playSound(loadSound, audioOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function shootTarget() {
|
||||||
|
var TARGET_SIZE = 0.25;
|
||||||
|
var TARGET_GRAVITY = -0.6;
|
||||||
|
var TARGET_UP_VELOCITY = 3.0;
|
||||||
|
var TARGET_FWD_VELOCITY = 5.0;
|
||||||
|
var DISTANCE_TO_LAUNCH_FROM = 3.0;
|
||||||
|
var camera = Camera.getPosition();
|
||||||
|
//printVector("camera", camera);
|
||||||
|
var targetDirection = Quat.angleAxis(getRandomFloat(-20.0, 20.0), { x:0, y:1, z:0 });
|
||||||
|
targetDirection = Quat.multiply(Camera.getOrientation(), targetDirection);
|
||||||
|
var forwardVector = Quat.getFront(targetDirection);
|
||||||
|
//printVector("forwardVector", forwardVector);
|
||||||
|
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_TO_LAUNCH_FROM));
|
||||||
|
//printVector("newPosition", newPosition);
|
||||||
|
var velocity = Vec3.multiply(forwardVector, TARGET_FWD_VELOCITY);
|
||||||
|
velocity.y += TARGET_UP_VELOCITY;
|
||||||
|
//printVector("velocity", velocity);
|
||||||
|
|
||||||
|
Particles.addParticle(
|
||||||
|
{ position: newPosition,
|
||||||
|
radius: TARGET_SIZE,
|
||||||
|
color: { red: 0, green: 200, blue: 200 },
|
||||||
|
velocity: velocity,
|
||||||
|
gravity: { x: 0, y: TARGET_GRAVITY, z: 0 },
|
||||||
|
lifetime: 1000.0,
|
||||||
|
damping: 0.99 });
|
||||||
|
|
||||||
|
// Record start time
|
||||||
|
shotTime = new Date();
|
||||||
|
|
||||||
|
// Play target shoot sound
|
||||||
|
audioOptions.position = newPosition;
|
||||||
|
Audio.playSound(targetLaunchSound, audioOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function particleCollisionWithVoxel(particle, voxel, collision) {
|
||||||
|
var VOXEL_SIZE = 0.5;
|
||||||
|
// Don't make this big. I mean it.
|
||||||
|
var CRATER_RADIUS = 5;
|
||||||
|
var particleProperties = Particles.getParticleProperties(particle);
|
||||||
|
var position = particleProperties.position;
|
||||||
|
Particles.deleteParticle(particle);
|
||||||
|
|
||||||
|
audioOptions.position = collision.contactPoint;
|
||||||
|
Audio.playSound(impactSound, audioOptions);
|
||||||
|
|
||||||
|
// Make a crater
|
||||||
|
var center = collision.contactPoint;
|
||||||
|
var RADIUS = CRATER_RADIUS * VOXEL_SIZE;
|
||||||
|
var RADIUS2 = RADIUS * RADIUS;
|
||||||
|
var distance2;
|
||||||
|
var dx;
|
||||||
|
var dy;
|
||||||
|
var dz;
|
||||||
|
for (var x = center.x - RADIUS; x <= center.x + RADIUS; x += VOXEL_SIZE) {
|
||||||
|
for (var y = center.y - RADIUS; y <= center.y + RADIUS; y += VOXEL_SIZE) {
|
||||||
|
for (var z = center.z - RADIUS; z <= center.z + RADIUS; z += VOXEL_SIZE) {
|
||||||
|
dx = Math.abs(x - center.x);
|
||||||
|
dy = Math.abs(y - center.y);
|
||||||
|
dz = Math.abs(z - center.z);
|
||||||
|
distance2 = dx * dx + dy * dy + dz * dz;
|
||||||
|
if (distance2 <= RADIUS2) {
|
||||||
|
Voxels.eraseVoxel(x, y, z, VOXEL_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function particleCollisionWithParticle(particle1, particle2, collision) {
|
||||||
|
score++;
|
||||||
|
if (showScore) {
|
||||||
|
Overlays.editOverlay(text, { text: "Score: " + score } );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record shot time
|
||||||
|
var endTime = new Date();
|
||||||
|
var msecs = endTime.valueOf() - shotTime.valueOf();
|
||||||
|
//print("hit, msecs = " + msecs);
|
||||||
|
//Vec3.print("penetration = ", collision.penetration);
|
||||||
|
//Vec3.print("contactPoint = ", collision.contactPoint);
|
||||||
|
Particles.deleteParticle(particle1);
|
||||||
|
Particles.deleteParticle(particle2);
|
||||||
|
// play the sound near the camera so the shooter can hear it
|
||||||
|
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||||
|
Audio.playSound(targetHitSound, audioOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyPressEvent(event) {
|
||||||
|
// if our tools are off, then don't do anything
|
||||||
|
if (event.text == "t") {
|
||||||
|
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
||||||
|
Script.setTimeout(shootTarget, time);
|
||||||
|
} else if (event.text == ".") {
|
||||||
|
shootFromMouse();
|
||||||
|
} else if (event.text == "r") {
|
||||||
|
playLoadSound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function playLoadSound() {
|
||||||
|
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||||
|
Audio.playSound(loadSound, audioOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
//MyAvatar.attach(gunModel, "RightHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
|
||||||
|
MyAvatar.attach(gunModel, "LeftHand", {x: -0.02, y: -.14, z: 0.07}, Quat.fromPitchYawRollDegrees(-70, -151, 72), 0.20);
|
||||||
|
|
||||||
|
// Give a bit of time to load before playing sound
|
||||||
|
Script.setTimeout(playLoadSound, 2000);
|
||||||
|
|
||||||
|
function update(deltaTime) {
|
||||||
|
|
||||||
|
// Check for mouseLook movement, update rotation
|
||||||
|
// rotate body yaw for yaw received from controller or mouse
|
||||||
|
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } ));
|
||||||
|
MyAvatar.orientation = newOrientation;
|
||||||
|
yawFromMouse = 0;
|
||||||
|
|
||||||
|
// apply pitch from controller or mouse
|
||||||
|
var newPitch = MyAvatar.headPitch + pitchFromMouse;
|
||||||
|
MyAvatar.headPitch = newPitch;
|
||||||
|
pitchFromMouse = 0;
|
||||||
|
|
||||||
|
// Check hydra controller for launch button press
|
||||||
|
if (!isLaunchButtonPressed && Controller.isButtonPressed(LEFT_BUTTON_3)) {
|
||||||
|
isLaunchButtonPressed = true;
|
||||||
|
var time = MIN_THROWER_DELAY + Math.random() * MAX_THROWER_DELAY;
|
||||||
|
Script.setTimeout(shootTarget, time);
|
||||||
|
} else if (isLaunchButtonPressed && !Controller.isButtonPressed(LEFT_BUTTON_3)) {
|
||||||
|
isLaunchButtonPressed = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check hydra controller for trigger press
|
||||||
|
|
||||||
|
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||||
|
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||||
|
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||||
|
|
||||||
|
// this is expected for hydras
|
||||||
|
if (numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
||||||
|
for (var t = 0; t < numberOfTriggers; t++) {
|
||||||
|
var shootABullet = false;
|
||||||
|
var triggerValue = Controller.getTriggerValue(t);
|
||||||
|
|
||||||
|
if (triggerPulled[t]) {
|
||||||
|
// must release to at least 0.1
|
||||||
|
if (triggerValue < 0.1) {
|
||||||
|
triggerPulled[t] = false; // unpulled
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// must pull to at least 0.9
|
||||||
|
if (triggerValue > 0.9) {
|
||||||
|
triggerPulled[t] = true; // pulled
|
||||||
|
shootABullet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shootABullet) {
|
||||||
|
|
||||||
|
var palmController = t * controllersPerTrigger;
|
||||||
|
var palmPosition = Controller.getSpatialControlPosition(palmController);
|
||||||
|
|
||||||
|
var fingerTipController = palmController + 1;
|
||||||
|
var fingerTipPosition = Controller.getSpatialControlPosition(fingerTipController);
|
||||||
|
|
||||||
|
var palmToFingerTipVector =
|
||||||
|
{ x: (fingerTipPosition.x - palmPosition.x),
|
||||||
|
y: (fingerTipPosition.y - palmPosition.y),
|
||||||
|
z: (fingerTipPosition.z - palmPosition.z) };
|
||||||
|
|
||||||
|
// just off the front of the finger tip
|
||||||
|
var position = { x: fingerTipPosition.x + palmToFingerTipVector.x/2,
|
||||||
|
y: fingerTipPosition.y + palmToFingerTipVector.y/2,
|
||||||
|
z: fingerTipPosition.z + palmToFingerTipVector.z/2};
|
||||||
|
|
||||||
|
var linearVelocity = 25;
|
||||||
|
|
||||||
|
var velocity = { x: palmToFingerTipVector.x * linearVelocity,
|
||||||
|
y: palmToFingerTipVector.y * linearVelocity,
|
||||||
|
z: palmToFingerTipVector.z * linearVelocity };
|
||||||
|
|
||||||
|
shootBullet(position, velocity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
isMouseDown = true;
|
||||||
|
lastX = event.x;
|
||||||
|
lastY = event.y;
|
||||||
|
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
|
||||||
|
//Audio.playSound(loadSound, audioOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shootFromMouse() {
|
||||||
|
var DISTANCE_FROM_CAMERA = 2.0;
|
||||||
|
var camera = Camera.getPosition();
|
||||||
|
var forwardVector = Quat.getFront(Camera.getOrientation());
|
||||||
|
var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, DISTANCE_FROM_CAMERA));
|
||||||
|
var velocity = Vec3.multiply(forwardVector, BULLET_VELOCITY);
|
||||||
|
shootBullet(newPosition, velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseReleaseEvent(event) {
|
||||||
|
// position
|
||||||
|
isMouseDown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseMoveEvent(event) {
|
||||||
|
//Move the camera if LEFT_BUTTON_1 is pressed
|
||||||
|
if (Controller.isButtonPressed(LEFT_BUTTON_1)) {
|
||||||
|
var MOUSE_YAW_SCALE = -0.25;
|
||||||
|
var MOUSE_PITCH_SCALE = -12.5;
|
||||||
|
var FIXED_MOUSE_TIMESTEP = 0.016;
|
||||||
|
yawFromMouse += ((event.x - lastX) * MOUSE_YAW_SCALE * FIXED_MOUSE_TIMESTEP);
|
||||||
|
pitchFromMouse += ((event.y - lastY) * MOUSE_PITCH_SCALE * FIXED_MOUSE_TIMESTEP);
|
||||||
|
lastX = event.x;
|
||||||
|
lastY = event.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
Overlays.deleteOverlay(reticle);
|
||||||
|
Overlays.deleteOverlay(text);
|
||||||
|
MyAvatar.detachOne(gunModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
Particles.particleCollisionWithVoxel.connect(particleCollisionWithVoxel);
|
||||||
|
Particles.particleCollisionWithParticle.connect(particleCollisionWithParticle);
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
Script.update.connect(update);
|
||||||
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
|
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||||
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||||
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -187,4 +187,21 @@ VoxelDetail VoxelsScriptingInterface::getVoxelEnclosingPoint(const glm::vec3& po
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VoxelDetail VoxelsScriptingInterface::getVoxelEnclosingPointBlocking(const glm::vec3& point) {
|
||||||
|
VoxelDetail result = { 0.0f, 0.0f, 0.0f, 0.0f, 0, 0, 0 };
|
||||||
|
if (_tree) {
|
||||||
|
OctreeElement* element = _tree->getElementEnclosingPoint(point / (float)TREE_SCALE, Octree::Lock);
|
||||||
|
if (element) {
|
||||||
|
VoxelTreeElement* voxel = static_cast<VoxelTreeElement*>(element);
|
||||||
|
result.x = voxel->getCorner().x;
|
||||||
|
result.y = voxel->getCorner().y;
|
||||||
|
result.z = voxel->getCorner().z;
|
||||||
|
result.s = voxel->getScale();
|
||||||
|
result.red = voxel->getColor()[0];
|
||||||
|
result.green = voxel->getColor()[1];
|
||||||
|
result.blue = voxel->getColor()[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,11 @@ public:
|
||||||
/// \return VoxelDetail - if no voxel encloses the point then VoxelDetail items will be 0
|
/// \return VoxelDetail - if no voxel encloses the point then VoxelDetail items will be 0
|
||||||
Q_INVOKABLE VoxelDetail getVoxelEnclosingPoint(const glm::vec3& point);
|
Q_INVOKABLE VoxelDetail getVoxelEnclosingPoint(const glm::vec3& point);
|
||||||
|
|
||||||
|
/// checks the local voxel tree for the smallest voxel enclosing the point and uses a blocking lock
|
||||||
|
/// \param point the x,y,z coordinates of the point (in meter units)
|
||||||
|
/// \return VoxelDetail - if no voxel encloses the point then VoxelDetail items will be 0
|
||||||
|
Q_INVOKABLE VoxelDetail getVoxelEnclosingPointBlocking(const glm::vec3& point);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
|
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
|
||||||
RayToVoxelIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType);
|
RayToVoxelIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType);
|
||||||
|
|
Loading…
Reference in a new issue