text: var controlHeld = false;
  var shiftHeld = false;
  
  Script.include([
      "./libraries/toolBars.js",
      "./libraries/utils.js",
  ]);
  
  var isActive = false;
  var toolIconUrl = Script.resolvePath("assets/images/tools/");
  
  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: toolIconUrl+"voxels.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.getForward(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: Script.resolvePath("assets/images/textures/dirt.jpeg"),
          yTextureURL: Script.resolvePath("assets/images/textures/grass.png"),
          zTextureURL: Script.resolvePath("assets/images/textures/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);