mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 16:32:38 +02:00
469 lines
15 KiB
JavaScript
469 lines
15 KiB
JavaScript
var controlHeld = false;
|
|
var shiftHeld = false;
|
|
|
|
Script.include([
|
|
"libraries/toolBars.js",
|
|
"libraries/utils.js",
|
|
]);
|
|
|
|
var isActive = false;
|
|
var toolIconUrl = "http://headache.hungry.com/~seth/hifi/";
|
|
var toolHeight = 50;
|
|
var toolWidth = 50;
|
|
|
|
var addingVoxels = false;
|
|
var deletingVoxels = false;
|
|
var addingSpheres = false;
|
|
var deletingSpheres = false;
|
|
|
|
var offAlpha = 0.5;
|
|
var onAlpha = 0.9;
|
|
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,
|
|
});
|
|
|
|
addVoxelButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "voxel-add.svg",
|
|
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: offAlpha,
|
|
visible: false
|
|
});
|
|
|
|
deleteVoxelButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "voxel-delete.svg",
|
|
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: offAlpha,
|
|
visible: false
|
|
});
|
|
|
|
addSphereButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "sphere-add.svg",
|
|
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: offAlpha,
|
|
visible: false
|
|
});
|
|
|
|
deleteSphereButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "sphere-delete.svg",
|
|
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: offAlpha,
|
|
visible: false
|
|
});
|
|
|
|
addTerrainButton = toolBar.addTool({
|
|
imageURL: toolIconUrl + "voxel-terrain.svg",
|
|
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
|
width: toolWidth,
|
|
height: toolHeight,
|
|
alpha: onAlpha,
|
|
visible: 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();
|
|
// Overlays.deleteOverlay(activeButton);
|
|
};
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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"
|
|
});
|
|
|
|
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);
|
|
|
|
|
|
//////////
|
|
// 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 true;
|
|
}
|
|
|
|
|
|
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() {
|
|
for (var i = 0; i < overlays.length; i++) {
|
|
Overlays.deleteOverlay(overlays[i]);
|
|
}
|
|
toolBar.cleanup();
|
|
}
|
|
|
|
|
|
Controller.mousePressEvent.connect(mousePressEvent);
|
|
Controller.keyPressEvent.connect(keyPressEvent);
|
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
|
Script.scriptEnding.connect(cleanup);
|