Needs a lot of cleanup. Data has been de-duplicated, and where identical copies existed, one of them has been replaced with a symlink. Some files have been excluded, such as binaries, installers and debug dumps. Some of that may still be present.
470 lines
15 KiB
JavaScript
470 lines
15 KiB
JavaScript
var controlHeld = false;
|
|
var shiftHeld = false;
|
|
|
|
Script.include([
|
|
"libraries/toolBars.js",
|
|
"libraries/utils.js",
|
|
]);
|
|
|
|
var isActive = false;
|
|
var toolIconUrl = "https://s3-us-west-1.amazonaws.com/hifi-content/seth/production/icons/"
|
|
|
|
var toolHeight = 50;
|
|
var toolWidth = 50;
|
|
|
|
var addingVoxels = false;
|
|
var deletingVoxels = false;
|
|
var addingSpheres = false;
|
|
var deletingSpheres = false;
|
|
|
|
var offAlpha = 0.8;
|
|
var onAlpha = 1.0;
|
|
var editSphereRadius = 4;
|
|
|
|
function floorVector(v) {
|
|
return {x: Math.floor(v.x), y: Math.floor(v.y), z: Math.floor(v.z)};
|
|
}
|
|
|
|
var toolBar = (function () {
|
|
var that = {},
|
|
toolBar,
|
|
activeButton,
|
|
addVoxelButton,
|
|
deleteVoxelButton,
|
|
addSphereButton,
|
|
deleteSphereButton,
|
|
addTerrainButton;
|
|
|
|
function initialize() {
|
|
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.voxel.toolbar", function (windowDimensions, toolbar) {
|
|
return {
|
|
x: windowDimensions.x - 8*2 - toolbar.width * 2,
|
|
y: (windowDimensions.y - toolbar.height) / 2
|
|
};
|
|
});
|
|
|
|
activeButton = toolBar.addTool({
|
|
imageURL: "http://s3.amazonaws.com/hifi-public/images/tools/polyvox.svg",
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: onAlpha,
|
|
visible: true,
|
|
}, false);
|
|
|
|
addVoxelButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "voxel-add.svg",
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: offAlpha,
|
|
visible: false
|
|
}, false);
|
|
|
|
deleteVoxelButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "voxel-delete.svg",
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: offAlpha,
|
|
visible: false
|
|
}, false);
|
|
|
|
addSphereButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "sphere-add.svg",
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: offAlpha,
|
|
visible: false
|
|
}, false);
|
|
|
|
deleteSphereButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "sphere-delete.svg",
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: offAlpha,
|
|
visible: false
|
|
}, false);
|
|
|
|
addTerrainButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "voxel-terrain.svg",
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: onAlpha,
|
|
visible: false
|
|
}, false);
|
|
|
|
that.setActive(false);
|
|
}
|
|
|
|
function disableAllButtons() {
|
|
addingVoxels = false;
|
|
deletingVoxels = false;
|
|
addingSpheres = false;
|
|
deletingSpheres = false;
|
|
|
|
toolBar.setAlpha(offAlpha, addVoxelButton);
|
|
toolBar.setAlpha(offAlpha, deleteVoxelButton);
|
|
toolBar.setAlpha(offAlpha, addSphereButton);
|
|
toolBar.setAlpha(offAlpha, deleteSphereButton);
|
|
|
|
toolBar.selectTool(addVoxelButton, false);
|
|
toolBar.selectTool(deleteVoxelButton, false);
|
|
toolBar.selectTool(addSphereButton, false);
|
|
toolBar.selectTool(deleteSphereButton, false);
|
|
}
|
|
|
|
that.setActive = function(active) {
|
|
if (active != isActive) {
|
|
isActive = active;
|
|
that.showTools(isActive);
|
|
}
|
|
toolBar.selectTool(activeButton, isActive);
|
|
};
|
|
|
|
// Sets visibility of tool buttons, excluding the power button
|
|
that.showTools = function(doShow) {
|
|
toolBar.showTool(addVoxelButton, doShow);
|
|
toolBar.showTool(deleteVoxelButton, doShow);
|
|
toolBar.showTool(addSphereButton, doShow);
|
|
toolBar.showTool(deleteSphereButton, doShow);
|
|
toolBar.showTool(addTerrainButton, doShow);
|
|
};
|
|
|
|
that.mousePressEvent = function (event) {
|
|
var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
|
|
|
if (activeButton === toolBar.clicked(clickedOverlay)) {
|
|
that.setActive(!isActive);
|
|
return true;
|
|
}
|
|
|
|
if (addVoxelButton === toolBar.clicked(clickedOverlay)) {
|
|
var wasAddingVoxels = addingVoxels;
|
|
disableAllButtons()
|
|
if (!wasAddingVoxels) {
|
|
addingVoxels = true;
|
|
toolBar.setAlpha(onAlpha, addVoxelButton);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (deleteVoxelButton === toolBar.clicked(clickedOverlay)) {
|
|
var wasDeletingVoxels = deletingVoxels;
|
|
disableAllButtons()
|
|
if (!wasDeletingVoxels) {
|
|
deletingVoxels = true;
|
|
toolBar.setAlpha(onAlpha, deleteVoxelButton);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (addSphereButton === toolBar.clicked(clickedOverlay)) {
|
|
var wasAddingSpheres = addingSpheres
|
|
disableAllButtons()
|
|
if (!wasAddingSpheres) {
|
|
addingSpheres = true;
|
|
toolBar.setAlpha(onAlpha, addSphereButton);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (deleteSphereButton === toolBar.clicked(clickedOverlay)) {
|
|
var wasDeletingSpheres = deletingSpheres;
|
|
disableAllButtons()
|
|
if (!wasDeletingSpheres) {
|
|
deletingSpheres = true;
|
|
toolBar.setAlpha(onAlpha, deleteSphereButton);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
if (addTerrainButton === toolBar.clicked(clickedOverlay)) {
|
|
addTerrainBlock();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Window.domainChanged.connect(function() {
|
|
that.setActive(false);
|
|
});
|
|
|
|
that.cleanup = function () {
|
|
toolBar.cleanup();
|
|
};
|
|
|
|
|
|
initialize();
|
|
return that;
|
|
}());
|
|
|
|
|
|
|
|
function getTerrainAlignedLocation(pos) {
|
|
var posDiv16 = Vec3.multiply(pos, 1.0 / 16.0);
|
|
var posDiv16Floored = floorVector(posDiv16);
|
|
return Vec3.multiply(posDiv16Floored, 16.0);
|
|
}
|
|
|
|
|
|
function lookupTerrainForLocation(pos) {
|
|
var baseLocation = getTerrainAlignedLocation(pos);
|
|
entitiesAtLoc = Entities.findEntities(baseLocation, 1.0);
|
|
for (var i = 0; i < entitiesAtLoc.length; i++) {
|
|
var id = entitiesAtLoc[i];
|
|
var properties = Entities.getEntityProperties(id);
|
|
if (properties.name == "terrain") {
|
|
return id;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
function grabLowestJointY() {
|
|
var jointNames = MyAvatar.getJointNames();
|
|
var floorY = MyAvatar.position.y;
|
|
for (var jointName in jointNames) {
|
|
if (MyAvatar.getJointPosition(jointNames[jointName]).y < floorY) {
|
|
floorY = MyAvatar.getJointPosition(jointNames[jointName]).y;
|
|
}
|
|
}
|
|
return floorY;
|
|
}
|
|
|
|
|
|
function addTerrainBlock() {
|
|
var baseLocation = getTerrainAlignedLocation(Vec3.sum(MyAvatar.position, {x:8, y:8, z:8}));
|
|
if (baseLocation.y > MyAvatar.position.y) {
|
|
baseLocation.y -= 16;
|
|
}
|
|
|
|
var alreadyThere = lookupTerrainForLocation(baseLocation);
|
|
if (alreadyThere) {
|
|
// there is already a terrain block under MyAvatar.
|
|
// try in front of the avatar.
|
|
facingPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(8.0, Quat.getFront(Camera.getOrientation())));
|
|
facingPosition = Vec3.sum(facingPosition, {x:8, y:8, z:8});
|
|
baseLocation = getTerrainAlignedLocation(facingPosition);
|
|
alreadyThere = lookupTerrainForLocation(baseLocation);
|
|
if (alreadyThere) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
var polyVoxID = addTerrainBlockNearLocation(baseLocation);
|
|
|
|
if (polyVoxID) {
|
|
var AvatarPositionInVoxelCoords = Entities.worldCoordsToVoxelCoords(polyVoxID, MyAvatar.position);
|
|
// TODO -- how to find the avatar's feet?
|
|
var topY = Math.round(AvatarPositionInVoxelCoords.y) - 4;
|
|
Entities.setVoxelsInCuboid(polyVoxID, {x:0, y:0, z:0}, {x:16, y:topY, z:16}, 255);
|
|
}
|
|
}
|
|
|
|
function addTerrainBlockNearLocation(baseLocation) {
|
|
var alreadyThere = lookupTerrainForLocation(baseLocation);
|
|
if (alreadyThere) {
|
|
return null;
|
|
}
|
|
|
|
var polyVoxID = Entities.addEntity({
|
|
type: "PolyVox",
|
|
name: "terrain",
|
|
position: baseLocation,
|
|
dimensions: { x:16, y:16, z:16 },
|
|
voxelVolumeSize: {x:16, y:64, z:16},
|
|
voxelSurfaceStyle: 0,
|
|
xTextureURL: "http://headache.hungry.com/~seth/hifi/dirt.jpeg",
|
|
yTextureURL: "http://headache.hungry.com/~seth/hifi/grass.png",
|
|
zTextureURL: "http://headache.hungry.com/~seth/hifi/dirt.jpeg"
|
|
});
|
|
|
|
//////////
|
|
// stitch together the terrain with x/y/z NeighorID properties
|
|
//////////
|
|
|
|
// link neighbors to this plot
|
|
imXNNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:16, y:0, z:0}));
|
|
imYNNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:16, z:0}));
|
|
imZNNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:16}));
|
|
imXPNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:-16, y:0, z:0}));
|
|
imYPNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:-16, z:0}));
|
|
imZPNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:-16}));
|
|
|
|
if (imXNNeighborFor) {
|
|
var properties = Entities.getEntityProperties(imXNNeighborFor);
|
|
properties.xNNeighborID = polyVoxID;
|
|
Entities.editEntity(imXNNeighborFor, properties);
|
|
}
|
|
if (imYNNeighborFor) {
|
|
var properties = Entities.getEntityProperties(imYNNeighborFor);
|
|
properties.yNNeighborID = polyVoxID;
|
|
Entities.editEntity(imYNNeighborFor, properties);
|
|
}
|
|
if (imZNNeighborFor) {
|
|
var properties = Entities.getEntityProperties(imZNNeighborFor);
|
|
properties.zNNeighborID = polyVoxID;
|
|
Entities.editEntity(imZNNeighborFor, properties);
|
|
}
|
|
|
|
if (imXPNeighborFor) {
|
|
var properties = Entities.getEntityProperties(imXPNeighborFor);
|
|
properties.xPNeighborID = polyVoxID;
|
|
Entities.editEntity(imXPNeighborFor, properties);
|
|
}
|
|
if (imYPNeighborFor) {
|
|
var properties = Entities.getEntityProperties(imYPNeighborFor);
|
|
properties.yPNeighborID = polyVoxID;
|
|
Entities.editEntity(imYPNeighborFor, properties);
|
|
}
|
|
if (imZPNeighborFor) {
|
|
var properties = Entities.getEntityProperties(imZPNeighborFor);
|
|
properties.zPNeighborID = polyVoxID;
|
|
Entities.editEntity(imZPNeighborFor, properties);
|
|
}
|
|
|
|
|
|
// link this plot to its neighbors
|
|
var properties = Entities.getEntityProperties(polyVoxID);
|
|
properties.xNNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:-16, y:0, z:0}));
|
|
properties.yNNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:-16, z:0}));
|
|
properties.zNNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:-16}));
|
|
properties.xPNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:16, y:0, z:0}));
|
|
properties.yPNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:16, z:0}));
|
|
properties.zPNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:16}));
|
|
Entities.editEntity(polyVoxID, properties);
|
|
|
|
return polyVoxID;
|
|
}
|
|
|
|
|
|
function attemptVoxelChangeForEntity(entityID, pickRayDir, intersectionLocation) {
|
|
|
|
var properties = Entities.getEntityProperties(entityID);
|
|
if (properties.type != "PolyVox") {
|
|
return false;
|
|
}
|
|
|
|
if (addingVoxels == false && deletingVoxels == false && addingSpheres == false && deletingSpheres == false) {
|
|
return false;
|
|
}
|
|
|
|
var voxelOrigin = Entities.worldCoordsToVoxelCoords(entityID, Vec3.subtract(intersectionLocation, pickRayDir));
|
|
var voxelPosition = Entities.worldCoordsToVoxelCoords(entityID, intersectionLocation);
|
|
var pickRayDirInVoxelSpace = Vec3.subtract(voxelPosition, voxelOrigin);
|
|
pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace);
|
|
|
|
var doAdd = addingVoxels;
|
|
var doDelete = deletingVoxels;
|
|
var doAddSphere = addingSpheres;
|
|
var doDeleteSphere = deletingSpheres;
|
|
|
|
if (controlHeld) {
|
|
if (doAdd) {
|
|
doAdd = false;
|
|
doDelete = true;
|
|
} else if (doDelete) {
|
|
doDelete = false;
|
|
doAdd = true;
|
|
} else if (doAddSphere) {
|
|
doAddSphere = false;
|
|
doDeleteSphere = true;
|
|
} else if (doDeleteSphere) {
|
|
doDeleteSphere = false;
|
|
doAddSphere = true;
|
|
}
|
|
}
|
|
|
|
if (doDelete) {
|
|
var toErasePosition = Vec3.sum(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
|
|
return Entities.setVoxel(entityID, floorVector(toErasePosition), 0);
|
|
}
|
|
if (doAdd) {
|
|
var toDrawPosition = Vec3.subtract(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
|
|
return Entities.setVoxel(entityID, floorVector(toDrawPosition), 255);
|
|
}
|
|
if (doDeleteSphere) {
|
|
var toErasePosition = intersectionLocation;
|
|
return Entities.setVoxelSphere(entityID, floorVector(toErasePosition), editSphereRadius, 0);
|
|
}
|
|
if (doAddSphere) {
|
|
var toDrawPosition = intersectionLocation;
|
|
return Entities.setVoxelSphere(entityID, floorVector(toDrawPosition), editSphereRadius, 255);
|
|
}
|
|
}
|
|
|
|
|
|
function attemptVoxelChange(pickRayDir, intersection) {
|
|
|
|
var ids;
|
|
|
|
ids = Entities.findEntities(intersection.intersection, editSphereRadius + 1.0);
|
|
if (ids.indexOf(intersection.entityID) < 0) {
|
|
ids.push(intersection.entityID);
|
|
}
|
|
|
|
var success = false;
|
|
for (var i = 0; i < ids.length; i++) {
|
|
var entityID = ids[i];
|
|
success |= attemptVoxelChangeForEntity(entityID, pickRayDir, intersection.intersection)
|
|
}
|
|
return success;
|
|
}
|
|
|
|
|
|
function mousePressEvent(event) {
|
|
if (!event.isLeftButton) {
|
|
return;
|
|
}
|
|
|
|
if (toolBar.mousePressEvent(event)) {
|
|
return;
|
|
}
|
|
|
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
|
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
|
|
|
|
if (intersection.intersects) {
|
|
if (attemptVoxelChange(pickRay.direction, intersection)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if the PolyVox entity is empty, we can't pick against its "on" voxels. try picking against its
|
|
// bounding box, instead.
|
|
intersection = Entities.findRayIntersection(pickRay, false); // bounding box picking
|
|
if (intersection.intersects) {
|
|
attemptVoxelChange(pickRay.direction, intersection);
|
|
}
|
|
}
|
|
|
|
|
|
function keyPressEvent(event) {
|
|
if (event.text == "CONTROL") {
|
|
controlHeld = true;
|
|
}
|
|
if (event.text == "SHIFT") {
|
|
shiftHeld = true;
|
|
}
|
|
}
|
|
|
|
|
|
function keyReleaseEvent(event) {
|
|
if (event.text == "CONTROL") {
|
|
controlHeld = false;
|
|
}
|
|
if (event.text == "SHIFT") {
|
|
shiftHeld = false;
|
|
}
|
|
}
|
|
|
|
|
|
function cleanup() {
|
|
toolBar.cleanup();
|
|
}
|
|
|
|
|
|
Controller.mousePressEvent.connect(mousePressEvent);
|
|
Controller.keyPressEvent.connect(keyPressEvent);
|
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
|
Script.scriptEnding.connect(cleanup);
|